Compare commits
	
		
			292 Commits
		
	
	
		
			@0x/contra
			...
			monorepo@7
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 7742901e5c | ||
|  | de68cb25d0 | ||
|  | 68fb6c2c27 | ||
|  | a47c031ad1 | ||
|  | 817049456c | ||
|  | e1a061789f | ||
|  | 28573ba772 | ||
|  | 880b9413f6 | ||
|  | 9a7c4b21a9 | ||
|  | ac56038eca | ||
|  | 4dd2fb6903 | ||
|  | 0baec61f06 | ||
|  | d4751788d1 | ||
|  | ae68c061d1 | ||
|  | b0387245f0 | ||
|  | c2d06a4a23 | ||
|  | 270108abb7 | ||
|  | e76c33232d | ||
|  | 58ff2dc492 | ||
|  | 13c45a0e96 | ||
|  | be7b1a1bd4 | ||
|  | 132a3c6705 | ||
|  | 5e73257557 | ||
|  | e83346fbbb | ||
|  | 2dd47a2103 | ||
|  | f31e530b6e | ||
|  | eb50f3fa9c | ||
|  | 8417fe4fdb | ||
|  | 0f1c15a6ca | ||
|  | 9345c4fb7f | ||
|  | 5e0758917b | ||
|  | f56839ec6b | ||
|  | cbb23a42e2 | ||
|  | 5a59c286d0 | ||
|  | 2e8c600d7a | ||
|  | e851cb1cbc | ||
|  | 3da03da32a | ||
|  | 3ec8924e7f | ||
|  | a04722b612 | ||
|  | f9a7857a90 | ||
|  | 58f772c74e | ||
|  | a425c7e260 | ||
|  | 809885afd0 | ||
|  | bf9b4b993f | ||
|  | d94a26f0f4 | ||
|  | bd9c9cedca | ||
|  | 651e94bd94 | ||
|  | 162b6f1a74 | ||
|  | 865a253eb5 | ||
|  | 9b3781abf1 | ||
|  | d89243a0d3 | ||
|  | b4cefc64b4 | ||
|  | 2fd26587e5 | ||
|  | 282a351859 | ||
|  | a84b848ea9 | ||
|  | d329320fc2 | ||
|  | bc096554b5 | ||
|  | 5902d878d8 | ||
|  | 4a133ca36f | ||
|  | f7252f919a | ||
|  | e05a03a842 | ||
|  | dcce8276b8 | ||
|  | fd47947e55 | ||
|  | ae151df2eb | ||
|  | 79de188683 | ||
|  | 6e5c788e13 | ||
|  | f53606007d | ||
|  | a4ac418bc9 | ||
|  | a8c09d0bdb | ||
|  | 871105a48a | ||
|  | 3b61129ade | ||
|  | f471c79b59 | ||
|  | dfd9443f74 | ||
|  | a36ff9e365 | ||
|  | 12e65bbf26 | ||
|  | ab9841e60b | ||
|  | 7a52f12e57 | ||
|  | 11fd4506ac | ||
|  | 0c9c68030e | ||
|  | 55d6eddbb2 | ||
|  | 8341e60edb | ||
|  | 6273a1ca73 | ||
|  | 1b83ebdf89 | ||
|  | fef7f0506f | ||
|  | f44eb4e383 | ||
|  | 05df485c4a | ||
|  | 44857c526b | ||
|  | b8ad5d5d32 | ||
|  | e3e0d00e21 | ||
|  | a9b1ea9690 | ||
|  | 8e5dd0f8d9 | ||
|  | 3b0c8f6d92 | ||
|  | 21058c2227 | ||
|  | f3b8ae0781 | ||
|  | d590b004c1 | ||
|  | 02e21141c6 | ||
|  | f839a3087d | ||
|  | f458815541 | ||
|  | 7ba754d2a4 | ||
|  | 09706e4ae2 | ||
|  | d18de4c541 | ||
|  | 001c7bfdbc | ||
|  | d4e04dc712 | ||
|  | 8650cb5217 | ||
|  | 0eaaddeb95 | ||
|  | 1cf8663f20 | ||
|  | 5130259552 | ||
|  | ba5e19a015 | ||
|  | c0400fa986 | ||
|  | 51179d10ce | ||
|  | 78752f9178 | ||
|  | 762db417d7 | ||
|  | 85bdccbc06 | ||
|  | 9f8cb99340 | ||
|  | 87b90bb04b | ||
|  | e961d88277 | ||
|  | 5754c11e34 | ||
|  | 7bd88c1bb8 | ||
|  | 445b686c6c | ||
|  | 0cb7b75214 | ||
|  | a08399dfee | ||
|  | 4016808fa4 | ||
|  | 8635849977 | ||
|  | 1a9ed4d4fe | ||
|  | e7b3246dd0 | ||
|  | 19589aec57 | ||
|  | 4d33ff0417 | ||
|  | 93a5ab5b33 | ||
|  | 59ada06cdf | ||
|  | ae650849b0 | ||
|  | 3e8f9a6b53 | ||
|  | 79362b0dba | ||
|  | 3e3df06d57 | ||
|  | 6b220eb1c5 | ||
|  | a1c61cae11 | ||
|  | d48a917bf3 | ||
|  | 646b6dafb2 | ||
|  | 8d10f33a3f | ||
|  | 5d603b2f80 | ||
|  | 0e1b08ff54 | ||
|  | befc22d718 | ||
|  | 4a62e80967 | ||
|  | ee9ef9f2c1 | ||
|  | 93dcb68437 | ||
|  | 0691cc7909 | ||
|  | d82f34fe59 | ||
|  | d2313b30af | ||
|  | 329719472a | ||
|  | a2fcab47d4 | ||
|  | 4ab5951c25 | ||
|  | 403cabb201 | ||
|  | 3da7c5d3e2 | ||
|  | c5e0de51aa | ||
|  | c581f1bba4 | ||
|  | b8ac9c2edd | ||
|  | 1027ee2481 | ||
|  | 2f311f7821 | ||
|  | a98c95b514 | ||
|  | 5bbbae5b23 | ||
|  | f9c9b9f924 | ||
|  | 5921208ea6 | ||
|  | f89c78abd1 | ||
|  | 74d3b9334c | ||
|  | 919fc66b9d | ||
|  | 400fb5a5bb | ||
|  | 3bb4f9085c | ||
|  | 714c6cec3c | ||
|  | cb69921202 | ||
|  | 277a0adac9 | ||
|  | 02d14f504f | ||
|  | 1ab7664a60 | ||
|  | 1be46ffb7e | ||
|  | 6ca52aed0d | ||
|  | 74e20970e2 | ||
|  | 93f2b6b4d8 | ||
|  | 00e616b57a | ||
|  | e436673304 | ||
|  | ce04d3ce41 | ||
|  | 4e46bf4697 | ||
|  | 9b95508f99 | ||
|  | c8c24456c1 | ||
|  | 80a6e82e1b | ||
|  | 80cec20d38 | ||
|  | 26cb22020d | ||
|  | 09d05d09c9 | ||
|  | 160c91f908 | ||
|  | 58f41bcd42 | ||
|  | 0235429995 | ||
|  | f79697e117 | ||
|  | 6f0019c71e | ||
|  | 1a04a18245 | ||
|  | 0cf3ff8209 | ||
|  | 7f56091fbd | ||
|  | 391f9b31f6 | ||
|  | 1d7c0f504a | ||
|  | 9cdc62f918 | ||
|  | 6027d0481e | ||
|  | 277fb92f9e | ||
|  | 79b6c3c1af | ||
|  | ad17174119 | ||
|  | 6c2692eec0 | ||
|  | 08640e8575 | ||
|  | 4a2575136f | ||
|  | e792afad17 | ||
|  | 5ecc4b027d | ||
|  | bc540f0cf0 | ||
|  | a24b14c465 | ||
|  | c3f36c3123 | ||
|  | 1d34da7557 | ||
|  | 27d74a4327 | ||
|  | 8a20cc682c | ||
|  | 9b20359e7b | ||
|  | 8866d0ccef | ||
|  | 7fa91a9971 | ||
|  | 28d1f3eef0 | ||
|  | f321cf6655 | ||
|  | 14ade737da | ||
|  | 41b1b1f141 | ||
|  | 25dfd47d32 | ||
|  | 6afa9c8b92 | ||
|  | 2fc449da4c | ||
|  | 5dd3b8cf9d | ||
|  | e834fa0050 | ||
|  | 9a97401606 | ||
|  | 410a3fef18 | ||
|  | 969b9814d5 | ||
|  | 2275e27b87 | ||
|  | 62b06cd204 | ||
|  | 350934ca21 | ||
|  | 6332673434 | ||
|  | f217840998 | ||
|  | 089ec35ceb | ||
|  | fecd0b809e | ||
|  | 4707a46561 | ||
|  | 616533c5a8 | ||
|  | c5b2991821 | ||
|  | c36d0fdc7c | ||
|  | 544e09cf4b | ||
|  | c110dc9e6a | ||
|  | 3bf37d6afd | ||
|  | b80ae5796b | ||
|  | 2083632299 | ||
|  | 3ca2f8ac9e | ||
|  | 7172432084 | ||
|  | 0e6afd147f | ||
|  | 46275a4f43 | ||
|  | 1dca378e03 | ||
|  | 06669594b1 | ||
|  | c09ac58ac0 | ||
|  | e01d32ef1a | ||
|  | 5ea3bcf59e | ||
|  | aa8b14b7ee | ||
|  | e1722cf739 | ||
|  | 7a7f70e15d | ||
|  | b3c3ec16e5 | ||
|  | 149f863951 | ||
|  | 684d09faac | ||
|  | 8a42691c80 | ||
|  | d591b3dd98 | ||
|  | a90fb4d8b6 | ||
|  | ebd08d9c63 | ||
|  | 71731d223b | ||
|  | 726ea5e01e | ||
|  | 16c7d2964b | ||
|  | 5a6e494bda | ||
|  | 88c6d89fbb | ||
|  | de12da18da | ||
|  | 8d10736934 | ||
|  | 2328e02d82 | ||
|  | 87cd5fca90 | ||
|  | b70cb726c5 | ||
|  | 295811ed5a | ||
|  | 4bc55551c6 | ||
|  | 2b8c6dc8f9 | ||
|  | 8b27380feb | ||
|  | 8de3a90851 | ||
|  | f8bb94d721 | ||
|  | 0c6d06e7bb | ||
|  | b0aa5d3af2 | ||
|  | 27d09713fd | ||
|  | ff18852879 | ||
|  | e515c91e5e | ||
|  | 1d5800c4f7 | ||
|  | de8f190945 | ||
|  | f371e3c8d3 | ||
|  | b15a6290a7 | ||
|  | 0f151db355 | ||
|  | fa99b75d1f | ||
|  | 4a299c1f39 | ||
|  | 30a2015a68 | ||
|  | c7c8a4891f | ||
|  | fe9fc6b459 | 
| @@ -47,7 +47,7 @@ jobs: | ||||
|             - restore_cache: | ||||
|                   keys: | ||||
|                       - repo-{{ .Environment.CIRCLE_SHA1 }} | ||||
|             - run: yarn wsrun test:circleci @0x/contracts-multisig @0x/contracts-utils @0x/contracts-exchange-libs @0x/contracts-erc20 @0x/contracts-erc721 @0x/contracts-erc1155 @0x/contracts-extensions @0x/contracts-asset-proxy @0x/contracts-exchange @0x/contracts-exchange-forwarder @0x/contracts-coordinator @0x/contracts-tests @0x/contracts-staking | ||||
|             - run: yarn wsrun test:circleci @0x/contracts-multisig @0x/contracts-utils @0x/contracts-exchange-libs @0x/contracts-erc20 @0x/contracts-erc721 @0x/contracts-erc1155 @0x/contracts-extensions @0x/contracts-asset-proxy @0x/contracts-exchange @0x/contracts-exchange-forwarder @0x/contracts-coordinator @0x/contracts-staking | ||||
|     test-exchange-ganache-3.0: | ||||
|         resource_class: medium+ | ||||
|         docker: | ||||
| @@ -77,7 +77,7 @@ jobs: | ||||
|             - restore_cache: | ||||
|                   keys: | ||||
|                       - repo-{{ .Environment.CIRCLE_SHA1 }} | ||||
|             - run: yarn wsrun test:circleci @0x/contracts-multisig @0x/contracts-utils @0x/contracts-exchange-libs @0x/contracts-erc20 @0x/contracts-erc721 @0x/contracts-erc1155 @0x/contracts-asset-proxy @0x/contracts-exchange-forwarder @0x/contracts-tests @0x/contracts-staking @0x/contracts-coordinator @0x/contracts-erc20-bridge-sampler | ||||
|             - run: yarn wsrun test:circleci @0x/contracts-multisig @0x/contracts-utils @0x/contracts-exchange-libs @0x/contracts-erc20 @0x/contracts-erc721 @0x/contracts-erc1155 @0x/contracts-asset-proxy @0x/contracts-exchange-forwarder @0x/contracts-staking @0x/contracts-coordinator @0x/contracts-erc20-bridge-sampler | ||||
|             # TODO(dorothy-zbornak): Re-enable after updating this package for | ||||
|             # 3.0. At that time, also remove exclusion from monorepo | ||||
|             # package.json's test script. | ||||
| @@ -193,7 +193,7 @@ jobs: | ||||
|         working_directory: ~/repo | ||||
|         docker: | ||||
|             - image: nikolaik/python-nodejs:python3.7-nodejs8 | ||||
|             - image: 0xorg/ganache-cli | ||||
|             - image: 0xorg/ganache-cli:6.0.0 | ||||
|             - image: 0xorg/mesh:0xV3 | ||||
|               environment: | ||||
|                   ETHEREUM_RPC_URL: 'http://localhost:8545' | ||||
|   | ||||
							
								
								
									
										5
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -79,6 +79,8 @@ TODO.md | ||||
| .vscode | ||||
|  | ||||
| # generated contract artifacts/ | ||||
| contracts/broker/generated-artifacts/ | ||||
| contracts/broker/test/generated-artifacts/ | ||||
| contracts/erc20-bridge-sampler/generated-artifacts/ | ||||
| contracts/erc20-bridge-sampler/test/generated-artifacts/ | ||||
| contracts/integrations/generated-artifacts/ | ||||
| @@ -113,6 +115,7 @@ packages/sol-tracing-utils/test/fixtures/artifacts/ | ||||
| python-packages/contract_artifacts/src/zero_ex/contract_artifacts/artifacts/ | ||||
|  | ||||
| # generated truffle contract artifacts/ | ||||
| contracts/broker/build/ | ||||
| contracts/erc20-bridge-sampler/build/ | ||||
| contracts/staking/build/ | ||||
| contracts/coordinator/build/ | ||||
| @@ -129,6 +132,8 @@ contracts/exchange-forwarder/build/ | ||||
| contracts/dev-utils/build/ | ||||
|  | ||||
| # generated contract wrappers | ||||
| contracts/broker/generated-wrappers/ | ||||
| contracts/broker/test/generated-wrappers/ | ||||
| packages/python-contract-wrappers/generated/ | ||||
| contracts/erc20-bridge-sampler/generated-wrappers/ | ||||
| contracts/erc20-bridge-sampler/test/generated-wrappers/ | ||||
|   | ||||
| @@ -1,5 +1,9 @@ | ||||
| lib | ||||
| .nyc_output | ||||
| /contracts/broker/generated-wrappers | ||||
| /contracts/broker/test/generated-wrappers | ||||
| /contracts/broker/generated-artifacts | ||||
| /contracts/broker/test/generated-artifacts | ||||
| /contracts/integrations/generated-wrappers | ||||
| /contracts/integrations/test/generated-wrappers | ||||
| /contracts/integrations/generated-artifacts | ||||
| @@ -87,3 +91,4 @@ packages/abi-gen/test-cli/fixtures/artifacts/AbiGenDummy.json | ||||
| packages/abi-gen/test-cli/fixtures/artifacts/LibDummy.json | ||||
| packages/abi-gen/test-cli/fixtures/artifacts/TestLibDummy.json | ||||
| packages/*/docs | ||||
| *.sol | ||||
|   | ||||
| @@ -1,4 +1,97 @@ | ||||
| [ | ||||
|     { | ||||
|         "timestamp": 1582837861, | ||||
|         "version": "3.2.4", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1582677073, | ||||
|         "version": "3.2.3", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1582623685, | ||||
|         "version": "3.2.2", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1581748629, | ||||
|         "version": "3.2.1", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "version": "3.2.0", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Add more types and functions to `IDydx`", | ||||
|                 "pr": 2466 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Rename `DydxBrigeAction.accountId` to `DydxBridgeAction.accountIdx`", | ||||
|                 "pr": 2466 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Fix broken tests.", | ||||
|                 "pr": 2462 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Remove dependency on `@0x/contracts-dev-utils`", | ||||
|                 "pr": 2462 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Add asset data decoding functions", | ||||
|                 "pr": 2462 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Add `setOperators()` to `IDydx`", | ||||
|                 "pr": "TODO" | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1581204851 | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1580988106, | ||||
|         "version": "3.1.3", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1580811564, | ||||
|         "version": "3.1.2", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1579682890, | ||||
|         "version": "3.1.1", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "version": "3.1.0", | ||||
|         "changes": [ | ||||
|   | ||||
| @@ -5,6 +5,43 @@ Edit the package's CHANGELOG.json file only. | ||||
|  | ||||
| CHANGELOG | ||||
|  | ||||
| ## v3.2.4 - _February 27, 2020_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v3.2.3 - _February 26, 2020_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v3.2.2 - _February 25, 2020_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v3.2.1 - _February 15, 2020_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v3.2.0 - _February 8, 2020_ | ||||
|  | ||||
|     * Add more types and functions to `IDydx` (#2466) | ||||
|     * Rename `DydxBrigeAction.accountId` to `DydxBridgeAction.accountIdx` (#2466) | ||||
|     * Fix broken tests. (#2462) | ||||
|     * Remove dependency on `@0x/contracts-dev-utils` (#2462) | ||||
|     * Add asset data decoding functions (#2462) | ||||
|     * Add `setOperators()` to `IDydx` (#TODO) | ||||
|  | ||||
| ## v3.1.3 - _February 6, 2020_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v3.1.2 - _February 4, 2020_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v3.1.1 - _January 22, 2020_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v3.1.0 - _January 6, 2020_ | ||||
|  | ||||
|     * Integration tests for DydxBridge with ERC20BridgeProxy. (#2401) | ||||
|   | ||||
| @@ -3,8 +3,9 @@ | ||||
|     "contractsDir": "./contracts", | ||||
|     "useDockerisedSolc": false, | ||||
|     "isOfflineMode": false, | ||||
|     "shouldSaveStandardInput": true, | ||||
|     "compilerSettings": { | ||||
|         "evmVersion": "constantinople", | ||||
|         "evmVersion": "istanbul", | ||||
|         "optimizer": { | ||||
|             "enabled": true, | ||||
|             "runs": 1000000, | ||||
|   | ||||
| @@ -35,7 +35,7 @@ contract ChaiBridge is | ||||
|     /// @param from Address to transfer asset from. | ||||
|     /// @param to Address to transfer asset to. | ||||
|     /// @param amount Amount of asset to transfer. | ||||
|     /// @return success The magic bytes `0x37708e9b` if successful. | ||||
|     /// @return success The magic bytes `0xdc1600f3` if successful. | ||||
|     function bridgeTransferFrom( | ||||
|         address /* tokenAddress */, | ||||
|         address from, | ||||
|   | ||||
							
								
								
									
										108
									
								
								contracts/asset-proxy/contracts/src/bridges/CurveBridge.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								contracts/asset-proxy/contracts/src/bridges/CurveBridge.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,108 @@ | ||||
|  | ||||
| /* | ||||
|  | ||||
|   Copyright 2019 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.5.9; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; | ||||
| import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol"; | ||||
| import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol"; | ||||
| import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; | ||||
| import "../interfaces/IERC20Bridge.sol"; | ||||
| import "../interfaces/ICurve.sol"; | ||||
|  | ||||
|  | ||||
| // solhint-disable not-rely-on-time | ||||
| // solhint-disable space-after-comma | ||||
| contract CurveBridge is | ||||
|     IERC20Bridge, | ||||
|     IWallet, | ||||
|     DeploymentConstants | ||||
| { | ||||
|     /// @dev Callback for `ICurve`. Tries to buy `amount` of | ||||
|     ///      `toTokenAddress` tokens by selling the entirety of the opposing asset | ||||
|     ///      (DAI, USDC) to the Curve contract, then transfers the bought | ||||
|     ///      tokens to `to`. | ||||
|     /// @param toTokenAddress The token to give to `to` (i.e DAI, USDC, USDT). | ||||
|     /// @param to The recipient of the bought tokens. | ||||
|     /// @param amount Minimum amount of `toTokenAddress` tokens to buy. | ||||
|     /// @param bridgeData The abi-encoeded "from" token address. | ||||
|     /// @return success The magic bytes if successful. | ||||
|     function bridgeTransferFrom( | ||||
|         address toTokenAddress, | ||||
|         address /* from */, | ||||
|         address to, | ||||
|         uint256 amount, | ||||
|         bytes calldata bridgeData | ||||
|     ) | ||||
|         external | ||||
|         returns (bytes4 success) | ||||
|     { | ||||
|         // Decode the bridge data to get the Curve metadata. | ||||
|         (address curveAddress, int128 fromCoinIdx, int128 toCoinIdx, int128 version) = abi.decode(bridgeData, (address, int128, int128, int128)); | ||||
|         ICurve exchange = ICurve(curveAddress); | ||||
|  | ||||
|         address fromTokenAddress = exchange.underlying_coins(fromCoinIdx); | ||||
|         require(toTokenAddress != fromTokenAddress, "CurveBridge/INVALID_PAIR"); | ||||
|         // Grant an allowance to the exchange to spend `fromTokenAddress` token. | ||||
|         LibERC20Token.approve(fromTokenAddress, address(exchange), uint256(-1)); | ||||
|  | ||||
|         // Try to sell all of this contract's `fromTokenAddress` token balance. | ||||
|         if (version == 0) { | ||||
|             exchange.exchange_underlying( | ||||
|                 fromCoinIdx, | ||||
|                 toCoinIdx, | ||||
|                 // dx | ||||
|                 IERC20Token(fromTokenAddress).balanceOf(address(this)), | ||||
|                 // min dy | ||||
|                 amount, | ||||
|                 // expires | ||||
|                 block.timestamp + 1 | ||||
|             ); | ||||
|         } else { | ||||
|             exchange.exchange_underlying( | ||||
|                 fromCoinIdx, | ||||
|                 toCoinIdx, | ||||
|                 // dx | ||||
|                 IERC20Token(fromTokenAddress).balanceOf(address(this)), | ||||
|                 // min dy | ||||
|                 amount | ||||
|             ); | ||||
|         } | ||||
|  | ||||
|         uint256 toTokenBalance = IERC20Token(toTokenAddress).balanceOf(address(this)); | ||||
|         // Transfer the converted `toToken`s to `to`. | ||||
|         LibERC20Token.transfer(toTokenAddress, to, toTokenBalance); | ||||
|         return BRIDGE_SUCCESS; | ||||
|     } | ||||
|  | ||||
|     /// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker | ||||
|     ///      and sign for itself in orders. Always succeeds. | ||||
|     /// @return magicValue Magic success bytes, always. | ||||
|     function isValidSignature( | ||||
|         bytes32, | ||||
|         bytes calldata | ||||
|     ) | ||||
|         external | ||||
|         view | ||||
|         returns (bytes4 magicValue) | ||||
|     { | ||||
|         return LEGACY_WALLET_MAGIC_VALUE; | ||||
|     } | ||||
| } | ||||
| @@ -191,12 +191,12 @@ contract DydxBridge is | ||||
|         depositAction = IDydx.ActionArgs({ | ||||
|             actionType: IDydx.ActionType.Deposit,           // deposit tokens. | ||||
|             amount: dydxAmount,                             // amount to deposit. | ||||
|             accountId: bridgeAction.accountId,              // index in the `accounts` when calling `operate`. | ||||
|             accountIdx: bridgeAction.accountIdx,             // index in the `accounts` when calling `operate`. | ||||
|             primaryMarketId: bridgeAction.marketId,         // indicates which token to deposit. | ||||
|             otherAddress: depositFrom,                      // deposit from the account owner. | ||||
|             // unused parameters | ||||
|             secondaryMarketId: 0, | ||||
|             otherAccountId: 0, | ||||
|             otherAccountIdx: 0, | ||||
|             data: hex'' | ||||
|         }); | ||||
|     } | ||||
| @@ -229,12 +229,12 @@ contract DydxBridge is | ||||
|         withdrawAction = IDydx.ActionArgs({ | ||||
|             actionType: IDydx.ActionType.Withdraw,          // withdraw tokens. | ||||
|             amount: amountToWithdraw,                       // amount to withdraw. | ||||
|             accountId: bridgeAction.accountId,              // index in the `accounts` when calling `operate`. | ||||
|             accountIdx: bridgeAction.accountIdx,            // index in the `accounts` when calling `operate`. | ||||
|             primaryMarketId: bridgeAction.marketId,         // indicates which token to withdraw. | ||||
|             otherAddress: withdrawTo,                       // withdraw tokens to this address. | ||||
|             // unused parameters | ||||
|             secondaryMarketId: 0, | ||||
|             otherAccountId: 0, | ||||
|             otherAccountIdx: 0, | ||||
|             data: hex'' | ||||
|         }); | ||||
|     } | ||||
|   | ||||
| @@ -18,10 +18,22 @@ | ||||
|  | ||||
| pragma solidity ^0.5.9; | ||||
|  | ||||
| import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; | ||||
|  | ||||
|  | ||||
| contract PotLike { | ||||
|     function chi() external returns (uint256); | ||||
|     function rho() external returns (uint256); | ||||
|     function drip() external returns (uint256); | ||||
|     function join(uint256) external; | ||||
|     function exit(uint256) external; | ||||
| } | ||||
|  | ||||
|  | ||||
| // The actual Chai contract can be found here: https://github.com/dapphub/chai | ||||
| contract IChai { | ||||
|  | ||||
| contract IChai is | ||||
|     IERC20Token | ||||
| { | ||||
|     /// @dev Withdraws Dai owned by `src` | ||||
|     /// @param src Address that owns Dai. | ||||
|     /// @param wad Amount of Dai to withdraw. | ||||
| @@ -30,4 +42,25 @@ contract IChai { | ||||
|         uint256 wad | ||||
|     ) | ||||
|         external; | ||||
|  | ||||
|     /// @dev Queries Dai balance of Chai holder. | ||||
|     /// @param usr Address of Chai holder. | ||||
|     /// @return Dai balance. | ||||
|     function dai(address usr) | ||||
|         external | ||||
|         returns (uint256); | ||||
|  | ||||
|     /// @dev Queries the Pot contract used by the Chai contract. | ||||
|     function pot() | ||||
|         external | ||||
|         returns (PotLike); | ||||
|  | ||||
|     /// @dev Deposits Dai in exchange for Chai | ||||
|     /// @param dst Address to receive Chai. | ||||
|     /// @param wad Amount of Dai to deposit. | ||||
|     function join( | ||||
|         address dst, | ||||
|         uint256 wad | ||||
|     ) | ||||
|         external; | ||||
| } | ||||
|   | ||||
							
								
								
									
										87
									
								
								contracts/asset-proxy/contracts/src/interfaces/ICurve.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								contracts/asset-proxy/contracts/src/interfaces/ICurve.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,87 @@ | ||||
| /* | ||||
|  | ||||
|   Copyright 2019 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.5.9; | ||||
|  | ||||
|  | ||||
| // solhint-disable func-name-mixedcase | ||||
| interface ICurve { | ||||
|  | ||||
|     /// @dev Sell `sellAmount` of `fromToken` token and receive `toToken` token. | ||||
|     ///      This function exists on early versions of Curve (USDC/DAI) | ||||
|     /// @param i The token index being sold. | ||||
|     /// @param j The token index being bought. | ||||
|     /// @param sellAmount The amount of token being bought. | ||||
|     /// @param minBuyAmount The minimum buy amount of the token being bought. | ||||
|     /// @param deadline The time in seconds when this operation should expire. | ||||
|     function exchange_underlying( | ||||
|         int128 i, | ||||
|         int128 j, | ||||
|         uint256 sellAmount, | ||||
|         uint256 minBuyAmount, | ||||
|         uint256 deadline | ||||
|     ) | ||||
|         external; | ||||
|  | ||||
|     /// @dev Sell `sellAmount` of `fromToken` token and receive `toToken` token. | ||||
|     ///      This function exists on later versions of Curve (USDC/DAI/USDT) | ||||
|     /// @param i The token index being sold. | ||||
|     /// @param j The token index being bought. | ||||
|     /// @param sellAmount The amount of token being bought. | ||||
|     /// @param minBuyAmount The minimum buy amount of the token being bought. | ||||
|     function exchange_underlying( | ||||
|         int128 i, | ||||
|         int128 j, | ||||
|         uint256 sellAmount, | ||||
|         uint256 minBuyAmount | ||||
|     ) | ||||
|         external; | ||||
|  | ||||
|     /// @dev Get the amount of `toToken` by selling `sellAmount` of `fromToken` | ||||
|     /// @param i The token index being sold. | ||||
|     /// @param j The token index being bought. | ||||
|     /// @param sellAmount The amount of token being bought. | ||||
|     function get_dy_underlying( | ||||
|         int128 i, | ||||
|         int128 j, | ||||
|         uint256 sellAmount | ||||
|     ) | ||||
|         external | ||||
|         returns (uint256 dy); | ||||
|  | ||||
|     /// @dev Get the amount of `fromToken` by buying `buyAmount` of `toToken` | ||||
|     ///      This function exists on later versions of Curve (USDC/DAI/USDT) | ||||
|     /// @param i The token index being sold. | ||||
|     /// @param j The token index being bought. | ||||
|     /// @param buyAmount The amount of token being bought. | ||||
|     function get_dx_underlying( | ||||
|         int128 i, | ||||
|         int128 j, | ||||
|         uint256 buyAmount | ||||
|     ) | ||||
|         external | ||||
|         returns (uint256 dx); | ||||
|  | ||||
|     /// @dev Get the underlying token address from the token index | ||||
|     /// @param i The token index. | ||||
|     function underlying_coins( | ||||
|         int128 i | ||||
|     ) | ||||
|         external | ||||
|         returns (address tokenAddress); | ||||
| } | ||||
| @@ -45,12 +45,12 @@ interface IDydx { | ||||
|     /// parsed into before being processed. | ||||
|     struct ActionArgs { | ||||
|         ActionType actionType; | ||||
|         uint256 accountId; | ||||
|         uint256 accountIdx; | ||||
|         AssetAmount amount; | ||||
|         uint256 primaryMarketId; | ||||
|         uint256 secondaryMarketId; | ||||
|         address otherAddress; | ||||
|         uint256 otherAccountId; | ||||
|         uint256 otherAccountIdx; | ||||
|         bytes data; | ||||
|     } | ||||
|  | ||||
| @@ -71,6 +71,36 @@ interface IDydx { | ||||
|         uint256 value; | ||||
|     } | ||||
|  | ||||
|     struct D256 { | ||||
|         uint256 value; | ||||
|     } | ||||
|  | ||||
|     struct Value { | ||||
|         uint256 value; | ||||
|     } | ||||
|  | ||||
|     struct Price { | ||||
|         uint256 value; | ||||
|     } | ||||
|  | ||||
|     struct OperatorArg { | ||||
|         address operator; | ||||
|         bool trusted; | ||||
|     } | ||||
|  | ||||
|     /// @dev The global risk parameters that govern the health and security of the system | ||||
|     struct RiskParams { | ||||
|         // Required ratio of over-collateralization | ||||
|         D256 marginRatio; | ||||
|         // Percentage penalty incurred by liquidated accounts | ||||
|         D256 liquidationSpread; | ||||
|         // Percentage of the borrower's interest fee that gets passed to the suppliers | ||||
|         D256 earningsRate; | ||||
|         // The minimum absolute borrow value of an account | ||||
|         // There must be sufficient incentivize to liquidate undercollateralized accounts | ||||
|         Value minBorrowedValue; | ||||
|     } | ||||
|  | ||||
|     /// @dev The main entry-point to Solo that allows users and contracts to manage accounts. | ||||
|     ///      Take one or more actions on one or more accounts. The msg.sender must be the owner or | ||||
|     ///      operator of all accounts except for those being liquidated, vaporized, or traded with. | ||||
| @@ -86,4 +116,77 @@ interface IDydx { | ||||
|         ActionArgs[] calldata actions | ||||
|     ) | ||||
|         external; | ||||
|  | ||||
|     // @dev Approves/disapproves any number of operators. An operator is an external address that has the | ||||
|     //      same permissions to manipulate an account as the owner of the account. Operators are simply | ||||
|     //      addresses and therefore may either be externally-owned Ethereum accounts OR smart contracts. | ||||
|     //      Operators are also able to act as AutoTrader contracts on behalf of the account owner if the | ||||
|     //      operator is a smart contract and implements the IAutoTrader interface. | ||||
|     // @param args A list of OperatorArgs which have an address and a boolean. The boolean value | ||||
|     //        denotes whether to approve (true) or revoke approval (false) for that address. | ||||
|     function setOperators(OperatorArg[] calldata args) external; | ||||
|  | ||||
|     /// @dev Return true if a particular address is approved as an operator for an owner's accounts. | ||||
|     ///      Approved operators can act on the accounts of the owner as if it were the operator's own. | ||||
|     /// @param owner The owner of the accounts | ||||
|     /// @param operator The possible operator | ||||
|     /// @return isLocalOperator True if operator is approved for owner's accounts | ||||
|     function getIsLocalOperator( | ||||
|         address owner, | ||||
|         address operator | ||||
|     ) | ||||
|         external | ||||
|         view | ||||
|         returns (bool isLocalOperator); | ||||
|  | ||||
|     /// @dev Get the ERC20 token address for a market. | ||||
|     /// @param marketId The market to query | ||||
|     /// @return tokenAddress The token address | ||||
|     function getMarketTokenAddress( | ||||
|         uint256 marketId | ||||
|     ) | ||||
|         external | ||||
|         view | ||||
|         returns (address tokenAddress); | ||||
|  | ||||
|     /// @dev Get all risk parameters in a single struct. | ||||
|     /// @return riskParams All global risk parameters | ||||
|     function getRiskParams() | ||||
|         external | ||||
|         view | ||||
|         returns (RiskParams memory riskParams); | ||||
|  | ||||
|     /// @dev Get the price of the token for a market. | ||||
|     /// @param marketId The market to query | ||||
|     /// @return price The price of each atomic unit of the token | ||||
|     function getMarketPrice( | ||||
|         uint256 marketId | ||||
|     ) | ||||
|         external | ||||
|         view | ||||
|         returns (Price memory price); | ||||
|  | ||||
|     /// @dev Get the margin premium for a market. A margin premium makes it so that any positions that | ||||
|     ///      include the market require a higher collateralization to avoid being liquidated. | ||||
|     /// @param  marketId  The market to query | ||||
|     /// @return premium The market's margin premium | ||||
|     function getMarketMarginPremium(uint256 marketId) | ||||
|         external | ||||
|         view | ||||
|         returns (D256 memory premium); | ||||
|  | ||||
|     /// @dev Get the total supplied and total borrowed values of an account adjusted by the marginPremium | ||||
|     ///      of each market. Supplied values are divided by (1 + marginPremium) for each market and | ||||
|     ///      borrowed values are multiplied by (1 + marginPremium) for each market. Comparing these | ||||
|     ///      adjusted values gives the margin-ratio of the account which will be compared to the global | ||||
|     ///      margin-ratio when determining if the account can be liquidated. | ||||
|     /// @param account The account to query | ||||
|     /// @return supplyValue The supplied value of the account (adjusted for marginPremium) | ||||
|     /// @return borrowValue The borrowed value of the account (adjusted for marginPremium) | ||||
|     function getAdjustedAccountValues( | ||||
|         AccountInfo calldata account | ||||
|     ) | ||||
|         external | ||||
|         view | ||||
|         returns (Value memory supplyValue, Value memory borrowValue); | ||||
| } | ||||
|   | ||||
| @@ -29,7 +29,7 @@ interface IDydxBridge { | ||||
|  | ||||
|     struct BridgeAction { | ||||
|         BridgeActionType actionType;            // Action to run on dydx account. | ||||
|         uint256 accountId;                      // Index in `BridgeData.accountNumbers` for this action. | ||||
|         uint256 accountIdx;                     // Index in `BridgeData.accountNumbers` for this action. | ||||
|         uint256 marketId;                       // Market to operate on. | ||||
|         uint256 conversionRateNumerator;        // Optional. If set, transfer amount is scaled by (conversionRateNumerator/conversionRateDenominator). | ||||
|         uint256 conversionRateDenominator;      // Optional. If set, transfer amount is scaled by (conversionRateNumerator/conversionRateDenominator). | ||||
| @@ -39,4 +39,4 @@ interface IDydxBridge { | ||||
|         uint256[] accountNumbers;               // Account number used to identify the owner's specific account. | ||||
|         BridgeAction[] actions;                 // Actions to carry out on the owner's accounts. | ||||
|     } | ||||
| } | ||||
| } | ||||
|   | ||||
| @@ -30,7 +30,7 @@ contract IERC20Bridge { | ||||
|     /// @param to Address to transfer asset to. | ||||
|     /// @param amount Amount of asset to transfer. | ||||
|     /// @param bridgeData Arbitrary asset data needed by the bridge contract. | ||||
|     /// @return success The magic bytes `0x37708e9b` if successful. | ||||
|     /// @return success The magic bytes `0xdc1600f3` if successful. | ||||
|     function bridgeTransferFrom( | ||||
|         address tokenAddress, | ||||
|         address from, | ||||
|   | ||||
| @@ -23,6 +23,7 @@ import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; | ||||
| import "../src/bridges/DydxBridge.sol"; | ||||
|  | ||||
|  | ||||
| // solhint-disable no-empty-blocks | ||||
| contract TestDydxBridgeToken { | ||||
|  | ||||
|     uint256 private constant INIT_HOLDER_BALANCE = 10 * 10**18; // 10 tokens | ||||
| @@ -79,7 +80,7 @@ contract TestDydxBridge is | ||||
|  | ||||
|     event OperateAction( | ||||
|         ActionType actionType, | ||||
|         uint256 accountId, | ||||
|         uint256 accountIdx, | ||||
|         bool amountSign, | ||||
|         AssetDenomination amountDenomination, | ||||
|         AssetReference amountRef, | ||||
| @@ -120,7 +121,7 @@ contract TestDydxBridge is | ||||
|         for (uint i = 0; i < actions.length; ++i) { | ||||
|             emit OperateAction( | ||||
|                 actions[i].actionType, | ||||
|                 actions[i].accountId, | ||||
|                 actions[i].accountIdx, | ||||
|                 actions[i].amount.sign, | ||||
|                 actions[i].amount.denomination, | ||||
|                 actions[i].amount.ref, | ||||
| @@ -128,7 +129,7 @@ contract TestDydxBridge is | ||||
|                 actions[i].primaryMarketId, | ||||
|                 actions[i].secondaryMarketId, | ||||
|                 actions[i].otherAddress, | ||||
|                 actions[i].otherAccountId, | ||||
|                 actions[i].otherAccountIdx, | ||||
|                 actions[i].data | ||||
|             ); | ||||
|  | ||||
| @@ -171,6 +172,60 @@ contract TestDydxBridge is | ||||
|         return _testTokenAddress; | ||||
|     } | ||||
|  | ||||
|     /// @dev Unused. | ||||
|     function setOperators(OperatorArg[] calldata args) external {} | ||||
|  | ||||
|     /// @dev Unused. | ||||
|     function getIsLocalOperator( | ||||
|         address owner, | ||||
|         address operator | ||||
|     ) | ||||
|         external | ||||
|         view | ||||
|         returns (bool isLocalOperator) | ||||
|     {} | ||||
|  | ||||
|     /// @dev Unused. | ||||
|     function getMarketTokenAddress( | ||||
|         uint256 marketId | ||||
|     ) | ||||
|         external | ||||
|         view | ||||
|         returns (address tokenAddress) | ||||
|     {} | ||||
|  | ||||
|     /// @dev Unused. | ||||
|     function getRiskParams() | ||||
|         external | ||||
|         view | ||||
|         returns (RiskParams memory riskParams) | ||||
|     {} | ||||
|  | ||||
|     /// @dev Unsused. | ||||
|     function getMarketPrice( | ||||
|         uint256 marketId | ||||
|     ) | ||||
|         external | ||||
|         view | ||||
|         returns (Price memory price) | ||||
|     {} | ||||
|  | ||||
|     /// @dev Unsused | ||||
|     function getMarketMarginPremium(uint256 marketId) | ||||
|         external | ||||
|         view | ||||
|         returns (IDydx.D256 memory premium) | ||||
|     {} | ||||
|  | ||||
|     /// @dev Unused. | ||||
|     function getAdjustedAccountValues( | ||||
|         AccountInfo calldata account | ||||
|     ) | ||||
|         external | ||||
|         view | ||||
|         returns (Value memory supplyValue, Value memory borrowValue) | ||||
|     {} | ||||
|  | ||||
|     /// @dev overrides `_getDydxAddress()` from `DeploymentConstants` to return this address. | ||||
|     function _getDydxAddress() | ||||
|         internal | ||||
| @@ -188,4 +243,4 @@ contract TestDydxBridge is | ||||
|     { | ||||
|         return msg.sender == ALWAYS_REVERT_ADDRESS ? address(0) : msg.sender; | ||||
|     } | ||||
| } | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "name": "@0x/contracts-asset-proxy", | ||||
|     "version": "3.1.0", | ||||
|     "version": "3.2.4", | ||||
|     "engines": { | ||||
|         "node": ">=6.12" | ||||
|     }, | ||||
| @@ -38,7 +38,7 @@ | ||||
|         "docs:json": "typedoc --excludePrivate --excludeExternals --excludeProtected --ignoreCompilerErrors --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES" | ||||
|     }, | ||||
|     "config": { | ||||
|         "abis": "./test/generated-artifacts/@(ChaiBridge|DydxBridge|ERC1155Proxy|ERC20BridgeProxy|ERC20Proxy|ERC721Proxy|Eth2DaiBridge|IAssetData|IAssetProxy|IAssetProxyDispatcher|IAuthorizable|IChai|IDydx|IDydxBridge|IERC20Bridge|IEth2Dai|IKyberNetworkProxy|IUniswapExchange|IUniswapExchangeFactory|KyberBridge|MixinAssetProxyDispatcher|MixinAuthorizable|MultiAssetProxy|Ownable|StaticCallProxy|TestChaiBridge|TestDydxBridge|TestERC20Bridge|TestEth2DaiBridge|TestKyberBridge|TestStaticCallTarget|TestUniswapBridge|UniswapBridge).json", | ||||
|         "abis": "./test/generated-artifacts/@(ChaiBridge|CurveBridge|DydxBridge|ERC1155Proxy|ERC20BridgeProxy|ERC20Proxy|ERC721Proxy|Eth2DaiBridge|IAssetData|IAssetProxy|IAssetProxyDispatcher|IAuthorizable|IChai|ICurve|IDydx|IDydxBridge|IERC20Bridge|IEth2Dai|IKyberNetworkProxy|IUniswapExchange|IUniswapExchangeFactory|KyberBridge|MixinAssetProxyDispatcher|MixinAuthorizable|MultiAssetProxy|Ownable|StaticCallProxy|TestChaiBridge|TestDydxBridge|TestERC20Bridge|TestEth2DaiBridge|TestKyberBridge|TestStaticCallTarget|TestUniswapBridge|UniswapBridge).json", | ||||
|         "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually." | ||||
|     }, | ||||
|     "repository": { | ||||
| @@ -51,15 +51,14 @@ | ||||
|     }, | ||||
|     "homepage": "https://github.com/0xProject/0x-monorepo/contracts/protocol/README.md", | ||||
|     "devDependencies": { | ||||
|         "@0x/abi-gen": "^5.0.3", | ||||
|         "@0x/contracts-gen": "^2.0.3", | ||||
|         "@0x/contracts-test-utils": "^5.1.0", | ||||
|         "@0x/contracts-utils": "^4.0.3", | ||||
|         "@0x/dev-utils": "^3.1.0", | ||||
|         "@0x/sol-compiler": "^4.0.3", | ||||
|         "@0x/abi-gen": "^5.2.2", | ||||
|         "@0x/contracts-gen": "^2.0.8", | ||||
|         "@0x/contracts-test-utils": "^5.3.1", | ||||
|         "@0x/contracts-utils": "^4.4.2", | ||||
|         "@0x/dev-utils": "^3.2.1", | ||||
|         "@0x/sol-compiler": "^4.0.8", | ||||
|         "@0x/ts-doc-gen": "^0.0.22", | ||||
|         "@0x/tslint-config": "^4.0.0", | ||||
|         "@0x/types": "^3.1.1", | ||||
|         "@types/lodash": "4.14.104", | ||||
|         "@types/mocha": "^5.2.7", | ||||
|         "@types/node": "*", | ||||
| @@ -79,17 +78,17 @@ | ||||
|         "typescript": "3.0.1" | ||||
|     }, | ||||
|     "dependencies": { | ||||
|         "@0x/base-contract": "^6.0.3", | ||||
|         "@0x/contracts-dev-utils": "^1.0.3", | ||||
|         "@0x/contracts-erc1155": "^2.0.3", | ||||
|         "@0x/contracts-erc20": "^3.0.3", | ||||
|         "@0x/contracts-erc721": "^3.0.3", | ||||
|         "@0x/contracts-exchange-libs": "^4.0.3", | ||||
|         "@0x/order-utils": "^10.1.0", | ||||
|         "@0x/typescript-typings": "^5.0.1", | ||||
|         "@0x/utils": "^5.1.2", | ||||
|         "@0x/web3-wrapper": "^7.0.3", | ||||
|         "ethereum-types": "^3.0.0", | ||||
|         "@0x/base-contract": "^6.2.1", | ||||
|         "@0x/contracts-erc1155": "^2.1.4", | ||||
|         "@0x/contracts-erc20": "^3.1.4", | ||||
|         "@0x/contracts-erc721": "^3.1.4", | ||||
|         "@0x/contracts-exchange-libs": "^4.3.4", | ||||
|         "@0x/order-utils": "^10.2.3", | ||||
|         "@0x/types": "^3.1.2", | ||||
|         "@0x/typescript-typings": "^5.0.2", | ||||
|         "@0x/utils": "^5.4.1", | ||||
|         "@0x/web3-wrapper": "^7.0.7", | ||||
|         "ethereum-types": "^3.1.0", | ||||
|         "lodash": "^4.17.11" | ||||
|     }, | ||||
|     "publishConfig": { | ||||
|   | ||||
| @@ -6,6 +6,7 @@ | ||||
| import { ContractArtifact } from 'ethereum-types'; | ||||
|  | ||||
| import * as ChaiBridge from '../generated-artifacts/ChaiBridge.json'; | ||||
| import * as CurveBridge from '../generated-artifacts/CurveBridge.json'; | ||||
| import * as DydxBridge from '../generated-artifacts/DydxBridge.json'; | ||||
| import * as ERC1155Proxy from '../generated-artifacts/ERC1155Proxy.json'; | ||||
| import * as ERC20BridgeProxy from '../generated-artifacts/ERC20BridgeProxy.json'; | ||||
| @@ -17,6 +18,7 @@ import * as IAssetProxy from '../generated-artifacts/IAssetProxy.json'; | ||||
| import * as IAssetProxyDispatcher from '../generated-artifacts/IAssetProxyDispatcher.json'; | ||||
| import * as IAuthorizable from '../generated-artifacts/IAuthorizable.json'; | ||||
| import * as IChai from '../generated-artifacts/IChai.json'; | ||||
| import * as ICurve from '../generated-artifacts/ICurve.json'; | ||||
| import * as IDydx from '../generated-artifacts/IDydx.json'; | ||||
| import * as IDydxBridge from '../generated-artifacts/IDydxBridge.json'; | ||||
| import * as IERC20Bridge from '../generated-artifacts/IERC20Bridge.json'; | ||||
| @@ -49,6 +51,7 @@ export const artifacts = { | ||||
|     MultiAssetProxy: MultiAssetProxy as ContractArtifact, | ||||
|     StaticCallProxy: StaticCallProxy as ContractArtifact, | ||||
|     ChaiBridge: ChaiBridge as ContractArtifact, | ||||
|     CurveBridge: CurveBridge as ContractArtifact, | ||||
|     DydxBridge: DydxBridge as ContractArtifact, | ||||
|     Eth2DaiBridge: Eth2DaiBridge as ContractArtifact, | ||||
|     KyberBridge: KyberBridge as ContractArtifact, | ||||
| @@ -58,6 +61,7 @@ export const artifacts = { | ||||
|     IAssetProxyDispatcher: IAssetProxyDispatcher as ContractArtifact, | ||||
|     IAuthorizable: IAuthorizable as ContractArtifact, | ||||
|     IChai: IChai as ContractArtifact, | ||||
|     ICurve: ICurve as ContractArtifact, | ||||
|     IDydx: IDydx as ContractArtifact, | ||||
|     IDydxBridge: IDydxBridge as ContractArtifact, | ||||
|     IERC20Bridge: IERC20Bridge as ContractArtifact, | ||||
|   | ||||
							
								
								
									
										112
									
								
								contracts/asset-proxy/src/asset_data.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								contracts/asset-proxy/src/asset_data.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,112 @@ | ||||
| import { AssetProxyId } from '@0x/types'; | ||||
| import { BigNumber, hexUtils } from '@0x/utils'; | ||||
|  | ||||
| import { IAssetDataContract } from './wrappers'; | ||||
|  | ||||
| const assetDataIface = new IAssetDataContract('0x0000000000000000000000000000000000000000', { isEIP1193: true } as any); | ||||
|  | ||||
| /** | ||||
|  * Get the proxy ID from encoded asset data. | ||||
|  */ | ||||
| export function getAssetDataProxyId(encoded: string): AssetProxyId { | ||||
|     // tslint:disable-next-line: no-unnecessary-type-assertion | ||||
|     return hexUtils.slice(encoded, 0, 4) as AssetProxyId; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Decode ERC20 asset data. | ||||
|  */ | ||||
| export function decodeERC20AssetData(encoded: string): string { | ||||
|     return assetDataIface.getABIDecodedTransactionData<string>('ERC20Token', encoded); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Decode ERC721 asset data. | ||||
|  */ | ||||
| export function decodeERC721AssetData(encoded: string): [string, BigNumber] { | ||||
|     return assetDataIface.getABIDecodedTransactionData<[string, BigNumber]>('ERC721Token', encoded); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Decode ERC1155 asset data. | ||||
|  */ | ||||
| export function decodeERC1155AssetData(encoded: string): [string, BigNumber[], BigNumber[], string] { | ||||
|     return assetDataIface.getABIDecodedTransactionData<[string, BigNumber[], BigNumber[], string]>( | ||||
|         'ERC1155Assets', | ||||
|         encoded, | ||||
|     ); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Decode MultiAsset asset data. | ||||
|  */ | ||||
| export function decodeMultiAssetData(encoded: string): [BigNumber[], string[]] { | ||||
|     return assetDataIface.getABIDecodedTransactionData<[BigNumber[], string[]]>('MultiAsset', encoded); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Decode StaticCall asset data. | ||||
|  */ | ||||
| export function decodeStaticCallAssetData(encoded: string): [string, string, string] { | ||||
|     return assetDataIface.getABIDecodedTransactionData<[string, string, string]>('StaticCall', encoded); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Decode ERC20Bridge asset data. | ||||
|  */ | ||||
| export function decodeERC20BridgeAssetData(encoded: string): [string, string, string] { | ||||
|     return assetDataIface.getABIDecodedTransactionData<[string, string, string]>('ERC20Bridge', encoded); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Encode ERC20 asset data. | ||||
|  */ | ||||
| export function encodeERC20AssetData(tokenAddress: string): string { | ||||
|     return assetDataIface.ERC20Token(tokenAddress).getABIEncodedTransactionData(); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Encode ERC721 asset data. | ||||
|  */ | ||||
| export function encodeERC721AssetData(tokenAddress: string, tokenId: BigNumber): string { | ||||
|     return assetDataIface.ERC721Token(tokenAddress, tokenId).getABIEncodedTransactionData(); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Encode ERC1155 asset data. | ||||
|  */ | ||||
| export function encodeERC1155AssetData( | ||||
|     tokenAddress: string, | ||||
|     tokenIds: BigNumber[], | ||||
|     values: BigNumber[], | ||||
|     callbackData: string, | ||||
| ): string { | ||||
|     return assetDataIface.ERC1155Assets(tokenAddress, tokenIds, values, callbackData).getABIEncodedTransactionData(); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Encode MultiAsset asset data. | ||||
|  */ | ||||
| export function encodeMultiAssetData(values: BigNumber[], nestedAssetData: string[]): string { | ||||
|     return assetDataIface.MultiAsset(values, nestedAssetData).getABIEncodedTransactionData(); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Encode StaticCall asset data. | ||||
|  */ | ||||
| export function encodeStaticCallAssetData( | ||||
|     staticCallTargetAddress: string, | ||||
|     staticCallData: string, | ||||
|     expectedReturnDataHash: string, | ||||
| ): string { | ||||
|     return assetDataIface | ||||
|         .StaticCall(staticCallTargetAddress, staticCallData, expectedReturnDataHash) | ||||
|         .getABIEncodedTransactionData(); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Encode ERC20Bridge asset data. | ||||
|  */ | ||||
| export function encodeERC20BridgeAssetData(tokenAddress: string, bridgeAddress: string, bridgeData: string): string { | ||||
|     return assetDataIface.ERC20Bridge(tokenAddress, bridgeAddress, bridgeData).getABIEncodedTransactionData(); | ||||
| } | ||||
| @@ -5,9 +5,9 @@ export enum DydxBridgeActionType { | ||||
|     Withdraw, | ||||
| } | ||||
|  | ||||
| export interface DydxBrigeAction { | ||||
| export interface DydxBridgeAction { | ||||
|     actionType: DydxBridgeActionType; | ||||
|     accountId: BigNumber; | ||||
|     accountIdx: BigNumber; | ||||
|     marketId: BigNumber; | ||||
|     conversionRateNumerator: BigNumber; | ||||
|     conversionRateDenominator: BigNumber; | ||||
| @@ -15,7 +15,7 @@ export interface DydxBrigeAction { | ||||
|  | ||||
| export interface DydxBridgeData { | ||||
|     accountNumbers: BigNumber[]; | ||||
|     actions: DydxBrigeAction[]; | ||||
|     actions: DydxBridgeAction[]; | ||||
| } | ||||
|  | ||||
| export const dydxBridgeDataEncoder = AbiEncoder.create([ | ||||
| @@ -29,7 +29,7 @@ export const dydxBridgeDataEncoder = AbiEncoder.create([ | ||||
|                 type: 'tuple[]', | ||||
|                 components: [ | ||||
|                     { name: 'actionType', type: 'uint8' }, | ||||
|                     { name: 'accountId', type: 'uint256' }, | ||||
|                     { name: 'accountIdx', type: 'uint256' }, | ||||
|                     { name: 'marketId', type: 'uint256' }, | ||||
|                     { name: 'conversionRateNumerator', type: 'uint256' }, | ||||
|                     { name: 'conversionRateDenominator', type: 'uint256' }, | ||||
|   | ||||
| @@ -1,4 +1,3 @@ | ||||
| import { DevUtilsContract } from '@0x/contracts-dev-utils'; | ||||
| import { artifacts as erc1155Artifacts, ERC1155MintableContract, Erc1155Wrapper } from '@0x/contracts-erc1155'; | ||||
| import { | ||||
|     constants, | ||||
| @@ -15,7 +14,7 @@ import * as _ from 'lodash'; | ||||
|  | ||||
| import { artifacts } from './artifacts'; | ||||
|  | ||||
| import { ERC1155ProxyContract, IAssetProxyContract } from './wrappers'; | ||||
| import { ERC1155ProxyContract, IAssetDataContract, IAssetProxyContract } from './wrappers'; | ||||
|  | ||||
| export class ERC1155ProxyWrapper { | ||||
|     private readonly _tokenOwnerAddresses: string[]; | ||||
| @@ -28,7 +27,7 @@ export class ERC1155ProxyWrapper { | ||||
|     private readonly _logDecoder: LogDecoder; | ||||
|     private readonly _dummyTokenWrappers: Erc1155Wrapper[]; | ||||
|     private readonly _assetProxyInterface: IAssetProxyContract; | ||||
|     private readonly _devUtils: DevUtilsContract; | ||||
|     private readonly _assetDataInterface: IAssetDataContract; | ||||
|     private _proxyContract?: ERC1155ProxyContract; | ||||
|     private _proxyIdIfExists?: string; | ||||
|     private _initialTokenIdsByOwner: ERC1155HoldingsByOwner = { fungible: {}, nonFungible: {} }; | ||||
| @@ -40,7 +39,7 @@ export class ERC1155ProxyWrapper { | ||||
|         this._logDecoder = new LogDecoder(this._web3Wrapper, allArtifacts); | ||||
|         this._dummyTokenWrappers = []; | ||||
|         this._assetProxyInterface = new IAssetProxyContract(constants.NULL_ADDRESS, provider); | ||||
|         this._devUtils = new DevUtilsContract(constants.NULL_ADDRESS, provider); | ||||
|         this._assetDataInterface = new IAssetDataContract(constants.NULL_ADDRESS, provider); | ||||
|         this._tokenOwnerAddresses = tokenOwnerAddresses; | ||||
|         this._contractOwnerAddress = contractOwnerAddress; | ||||
|         this._fungibleTokenIds = []; | ||||
| @@ -60,7 +59,7 @@ export class ERC1155ProxyWrapper { | ||||
|                 txDefaults, | ||||
|                 artifacts, | ||||
|             ); | ||||
|             const erc1155Wrapper = new Erc1155Wrapper(erc1155Contract, this._provider, this._contractOwnerAddress); | ||||
|             const erc1155Wrapper = new Erc1155Wrapper(erc1155Contract, this._contractOwnerAddress); | ||||
|             this._dummyTokenWrappers.push(erc1155Wrapper); | ||||
|         } | ||||
|         return this._dummyTokenWrappers; | ||||
| @@ -113,9 +112,9 @@ export class ERC1155ProxyWrapper { | ||||
|         this._validateProxyContractExistsOrThrow(); | ||||
|         const assetData = | ||||
|             assetData_ === undefined | ||||
|                 ? await this._devUtils | ||||
|                       .encodeERC1155AssetData(contractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData) | ||||
|                       .callAsync() | ||||
|                 ? this._assetDataInterface | ||||
|                       .ERC1155Assets(contractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData) | ||||
|                       .getABIEncodedTransactionData() | ||||
|                 : assetData_; | ||||
|         const data = this._assetProxyInterface | ||||
|             .transferFrom(assetData, from, to, valueMultiplier) | ||||
| @@ -167,9 +166,9 @@ export class ERC1155ProxyWrapper { | ||||
|         this._validateProxyContractExistsOrThrow(); | ||||
|         const assetData = | ||||
|             assetData_ === undefined | ||||
|                 ? await this._devUtils | ||||
|                       .encodeERC1155AssetData(contractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData) | ||||
|                       .callAsync() | ||||
|                 ? this._assetDataInterface | ||||
|                       .ERC1155Assets(contractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData) | ||||
|                       .getABIEncodedTransactionData() | ||||
|                 : assetData_; | ||||
|         const data = this._assetProxyInterface | ||||
|             .transferFrom(assetData, from, to, valueMultiplier) | ||||
|   | ||||
| @@ -1,4 +1,3 @@ | ||||
| import { DevUtilsContract } from '@0x/contracts-dev-utils'; | ||||
| import { artifacts as erc20Artifacts, DummyERC20TokenContract } from '@0x/contracts-erc20'; | ||||
| import { constants, ERC20BalancesByOwner, txDefaults } from '@0x/contracts-test-utils'; | ||||
| import { BigNumber } from '@0x/utils'; | ||||
| @@ -7,14 +6,14 @@ import * as _ from 'lodash'; | ||||
|  | ||||
| import { artifacts } from './artifacts'; | ||||
|  | ||||
| import { ERC20ProxyContract } from './wrappers'; | ||||
| import { ERC20ProxyContract, IAssetDataContract } from './wrappers'; | ||||
|  | ||||
| export class ERC20Wrapper { | ||||
|     private readonly _tokenOwnerAddresses: string[]; | ||||
|     private readonly _contractOwnerAddress: string; | ||||
|     private readonly _provider: ZeroExProvider; | ||||
|     private readonly _dummyTokenContracts: DummyERC20TokenContract[]; | ||||
|     private readonly _devUtils: DevUtilsContract; | ||||
|     private readonly _assetDataInterface: IAssetDataContract; | ||||
|     private _proxyContract?: ERC20ProxyContract; | ||||
|     private _proxyIdIfExists?: string; | ||||
|     /** | ||||
| @@ -29,7 +28,7 @@ export class ERC20Wrapper { | ||||
|         this._provider = provider; | ||||
|         this._tokenOwnerAddresses = tokenOwnerAddresses; | ||||
|         this._contractOwnerAddress = contractOwnerAddress; | ||||
|         this._devUtils = new DevUtilsContract(constants.NULL_ADDRESS, provider); | ||||
|         this._assetDataInterface = new IAssetDataContract(constants.NULL_ADDRESS, provider); | ||||
|     } | ||||
|     public async deployDummyTokensAsync( | ||||
|         numberToDeploy: number, | ||||
| @@ -145,7 +144,7 @@ export class ERC20Wrapper { | ||||
|         return tokenAddresses; | ||||
|     } | ||||
|     private async _getTokenContractFromAssetDataAsync(assetData: string): Promise<DummyERC20TokenContract> { | ||||
|         const [proxyId, tokenAddress] = await this._devUtils.decodeERC20AssetData(assetData).callAsync(); // tslint:disable-line:no-unused-variable | ||||
|         const tokenAddress = this._assetDataInterface.getABIDecodedTransactionData<string>('ERC20Token', assetData); // tslint:disable-line:no-unused-variable | ||||
|         const tokenContractIfExists = _.find(this._dummyTokenContracts, c => c.address === tokenAddress); | ||||
|         if (tokenContractIfExists === undefined) { | ||||
|             throw new Error(`Token: ${tokenAddress} was not deployed through ERC20Wrapper`); | ||||
|   | ||||
| @@ -1,16 +1,20 @@ | ||||
| export { artifacts } from './artifacts'; | ||||
| export { | ||||
|     ChaiBridgeContract, | ||||
|     ERC1155ProxyContract, | ||||
|     ERC20BridgeProxyContract, | ||||
|     ERC20ProxyContract, | ||||
|     ERC721ProxyContract, | ||||
|     Eth2DaiBridgeContract, | ||||
|     DydxBridgeContract, | ||||
|     TestDydxBridgeContract, | ||||
|     IAssetDataContract, | ||||
|     IAssetProxyContract, | ||||
|     IChaiContract, | ||||
|     IDydxContract, | ||||
|     KyberBridgeContract, | ||||
|     MultiAssetProxyContract, | ||||
|     StaticCallProxyContract, | ||||
|     TestDydxBridgeContract, | ||||
|     TestStaticCallTargetContract, | ||||
|     UniswapBridgeContract, | ||||
| } from './wrappers'; | ||||
| @@ -21,6 +25,7 @@ export { ERC1155ProxyWrapper } from './erc1155_proxy_wrapper'; | ||||
| export { ERC1155MintableContract, Erc1155Wrapper } from '@0x/contracts-erc1155'; | ||||
| export { DummyERC20TokenContract } from '@0x/contracts-erc20'; | ||||
| export { DummyERC721TokenContract } from '@0x/contracts-erc721'; | ||||
| export { AssetProxyId } from '@0x/types'; | ||||
| export { | ||||
|     ERC1155HoldingsByOwner, | ||||
|     ERC20BalancesByOwner, | ||||
| @@ -51,6 +56,7 @@ export { | ||||
|     OutputField, | ||||
|     ParamDescription, | ||||
|     EvmBytecodeOutput, | ||||
|     EvmBytecodeOutputLinkReferences, | ||||
|     AbiDefinition, | ||||
|     FunctionAbi, | ||||
|     EventAbi, | ||||
| @@ -64,4 +70,21 @@ export { | ||||
|     TupleDataItem, | ||||
|     StateMutability, | ||||
| } from 'ethereum-types'; | ||||
|  | ||||
| export { | ||||
|     decodeERC1155AssetData, | ||||
|     decodeERC20AssetData, | ||||
|     decodeERC20BridgeAssetData, | ||||
|     decodeERC721AssetData, | ||||
|     decodeMultiAssetData, | ||||
|     decodeStaticCallAssetData, | ||||
|     encodeERC1155AssetData, | ||||
|     encodeERC20AssetData, | ||||
|     encodeERC20BridgeAssetData, | ||||
|     encodeERC721AssetData, | ||||
|     encodeMultiAssetData, | ||||
|     encodeStaticCallAssetData, | ||||
|     getAssetDataProxyId, | ||||
| } from './asset_data'; | ||||
|  | ||||
| export * from './dydx_bridge_encoder'; | ||||
|   | ||||
| @@ -4,6 +4,7 @@ | ||||
|  * ----------------------------------------------------------------------------- | ||||
|  */ | ||||
| export * from '../generated-wrappers/chai_bridge'; | ||||
| export * from '../generated-wrappers/curve_bridge'; | ||||
| export * from '../generated-wrappers/dydx_bridge'; | ||||
| export * from '../generated-wrappers/erc1155_proxy'; | ||||
| export * from '../generated-wrappers/erc20_bridge_proxy'; | ||||
| @@ -15,6 +16,7 @@ export * from '../generated-wrappers/i_asset_proxy'; | ||||
| export * from '../generated-wrappers/i_asset_proxy_dispatcher'; | ||||
| export * from '../generated-wrappers/i_authorizable'; | ||||
| export * from '../generated-wrappers/i_chai'; | ||||
| export * from '../generated-wrappers/i_curve'; | ||||
| export * from '../generated-wrappers/i_dydx'; | ||||
| export * from '../generated-wrappers/i_dydx_bridge'; | ||||
| export * from '../generated-wrappers/i_erc20_bridge'; | ||||
|   | ||||
| @@ -6,6 +6,7 @@ | ||||
| import { ContractArtifact } from 'ethereum-types'; | ||||
|  | ||||
| import * as ChaiBridge from '../test/generated-artifacts/ChaiBridge.json'; | ||||
| import * as CurveBridge from '../test/generated-artifacts/CurveBridge.json'; | ||||
| import * as DydxBridge from '../test/generated-artifacts/DydxBridge.json'; | ||||
| import * as ERC1155Proxy from '../test/generated-artifacts/ERC1155Proxy.json'; | ||||
| import * as ERC20BridgeProxy from '../test/generated-artifacts/ERC20BridgeProxy.json'; | ||||
| @@ -17,6 +18,7 @@ import * as IAssetProxy from '../test/generated-artifacts/IAssetProxy.json'; | ||||
| import * as IAssetProxyDispatcher from '../test/generated-artifacts/IAssetProxyDispatcher.json'; | ||||
| import * as IAuthorizable from '../test/generated-artifacts/IAuthorizable.json'; | ||||
| import * as IChai from '../test/generated-artifacts/IChai.json'; | ||||
| import * as ICurve from '../test/generated-artifacts/ICurve.json'; | ||||
| import * as IDydx from '../test/generated-artifacts/IDydx.json'; | ||||
| import * as IDydxBridge from '../test/generated-artifacts/IDydxBridge.json'; | ||||
| import * as IERC20Bridge from '../test/generated-artifacts/IERC20Bridge.json'; | ||||
| @@ -49,6 +51,7 @@ export const artifacts = { | ||||
|     MultiAssetProxy: MultiAssetProxy as ContractArtifact, | ||||
|     StaticCallProxy: StaticCallProxy as ContractArtifact, | ||||
|     ChaiBridge: ChaiBridge as ContractArtifact, | ||||
|     CurveBridge: CurveBridge as ContractArtifact, | ||||
|     DydxBridge: DydxBridge as ContractArtifact, | ||||
|     Eth2DaiBridge: Eth2DaiBridge as ContractArtifact, | ||||
|     KyberBridge: KyberBridge as ContractArtifact, | ||||
| @@ -58,6 +61,7 @@ export const artifacts = { | ||||
|     IAssetProxyDispatcher: IAssetProxyDispatcher as ContractArtifact, | ||||
|     IAuthorizable: IAuthorizable as ContractArtifact, | ||||
|     IChai: IChai as ContractArtifact, | ||||
|     ICurve: ICurve as ContractArtifact, | ||||
|     IDydx: IDydx as ContractArtifact, | ||||
|     IDydxBridge: IDydxBridge as ContractArtifact, | ||||
|     IERC20Bridge: IERC20Bridge as ContractArtifact, | ||||
|   | ||||
| @@ -1,35 +1,20 @@ | ||||
| import { chaiSetup, expectTransactionFailedAsync, provider, txDefaults, web3Wrapper } from '@0x/contracts-test-utils'; | ||||
| import { BlockchainLifecycle } from '@0x/dev-utils'; | ||||
| import { blockchainTests, expect, provider, txDefaults, web3Wrapper } from '@0x/contracts-test-utils'; | ||||
| import { RevertReason } from '@0x/types'; | ||||
| import { BigNumber } from '@0x/utils'; | ||||
| import * as chai from 'chai'; | ||||
| import * as _ from 'lodash'; | ||||
|  | ||||
| import { artifacts } from './artifacts'; | ||||
|  | ||||
| import { MixinAuthorizableContract } from './wrappers'; | ||||
|  | ||||
| chaiSetup.configure(); | ||||
| const expect = chai.expect; | ||||
| const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); | ||||
|  | ||||
| describe('Authorizable', () => { | ||||
| blockchainTests.resets('Authorizable', () => { | ||||
|     let owner: string; | ||||
|     let notOwner: string; | ||||
|     let address: string; | ||||
|     let authorizable: MixinAuthorizableContract; | ||||
|  | ||||
|     before(async () => { | ||||
|         await blockchainLifecycle.startAsync(); | ||||
|     }); | ||||
|  | ||||
|     after(async () => { | ||||
|         await blockchainLifecycle.revertAsync(); | ||||
|     }); | ||||
|  | ||||
|     before(async () => { | ||||
|         const accounts = await web3Wrapper.getAvailableAddressesAsync(); | ||||
|         [owner, address, notOwner] = _.slice(accounts, 0, 3); | ||||
|         [owner, address, notOwner] = accounts.slice(0, 3); | ||||
|         authorizable = await MixinAuthorizableContract.deployFrom0xArtifactAsync( | ||||
|             artifacts.MixinAuthorizable, | ||||
|             provider, | ||||
| @@ -38,20 +23,10 @@ describe('Authorizable', () => { | ||||
|         ); | ||||
|     }); | ||||
|  | ||||
|     beforeEach(async () => { | ||||
|         await blockchainLifecycle.startAsync(); | ||||
|     }); | ||||
|  | ||||
|     afterEach(async () => { | ||||
|         await blockchainLifecycle.revertAsync(); | ||||
|     }); | ||||
|  | ||||
|     describe('addAuthorizedAddress', () => { | ||||
|         it('should revert if not called by owner', async () => { | ||||
|             await expectTransactionFailedAsync( | ||||
|                 authorizable.addAuthorizedAddress(notOwner).sendTransactionAsync({ from: notOwner }), | ||||
|                 RevertReason.OnlyContractOwner, | ||||
|             ); | ||||
|             const tx = authorizable.addAuthorizedAddress(notOwner).sendTransactionAsync({ from: notOwner }); | ||||
|             return expect(tx).to.revertWith(RevertReason.OnlyContractOwner); | ||||
|         }); | ||||
|  | ||||
|         it('should allow owner to add an authorized address', async () => { | ||||
| @@ -62,20 +37,16 @@ describe('Authorizable', () => { | ||||
|  | ||||
|         it('should revert if owner attempts to authorize a duplicate address', async () => { | ||||
|             await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner }); | ||||
|             return expectTransactionFailedAsync( | ||||
|                 authorizable.addAuthorizedAddress(address).sendTransactionAsync({ from: owner }), | ||||
|                 RevertReason.TargetAlreadyAuthorized, | ||||
|             ); | ||||
|             const tx = authorizable.addAuthorizedAddress(address).sendTransactionAsync({ from: owner }); | ||||
|             return expect(tx).to.revertWith(RevertReason.TargetAlreadyAuthorized); | ||||
|         }); | ||||
|     }); | ||||
|  | ||||
|     describe('removeAuthorizedAddress', () => { | ||||
|         it('should revert if not called by owner', async () => { | ||||
|             await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner }); | ||||
|             await expectTransactionFailedAsync( | ||||
|                 authorizable.removeAuthorizedAddress(address).sendTransactionAsync({ from: notOwner }), | ||||
|                 RevertReason.OnlyContractOwner, | ||||
|             ); | ||||
|             const tx = authorizable.removeAuthorizedAddress(address).sendTransactionAsync({ from: notOwner }); | ||||
|             return expect(tx).to.revertWith(RevertReason.OnlyContractOwner); | ||||
|         }); | ||||
|  | ||||
|         it('should allow owner to remove an authorized address', async () => { | ||||
| @@ -86,12 +57,8 @@ describe('Authorizable', () => { | ||||
|         }); | ||||
|  | ||||
|         it('should revert if owner attempts to remove an address that is not authorized', async () => { | ||||
|             return expectTransactionFailedAsync( | ||||
|                 authorizable.removeAuthorizedAddress(address).sendTransactionAsync({ | ||||
|                     from: owner, | ||||
|                 }), | ||||
|                 RevertReason.TargetNotAuthorized, | ||||
|             ); | ||||
|             const tx = authorizable.removeAuthorizedAddress(address).sendTransactionAsync({ from: owner }); | ||||
|             return expect(tx).to.revertWith(RevertReason.TargetNotAuthorized); | ||||
|         }); | ||||
|     }); | ||||
|  | ||||
| @@ -99,33 +66,27 @@ describe('Authorizable', () => { | ||||
|         it('should revert if not called by owner', async () => { | ||||
|             await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner }); | ||||
|             const index = new BigNumber(0); | ||||
|             await expectTransactionFailedAsync( | ||||
|                 authorizable.removeAuthorizedAddressAtIndex(address, index).sendTransactionAsync({ | ||||
|                     from: notOwner, | ||||
|                 }), | ||||
|                 RevertReason.OnlyContractOwner, | ||||
|             ); | ||||
|             const tx = authorizable | ||||
|                 .removeAuthorizedAddressAtIndex(address, index) | ||||
|                 .sendTransactionAsync({ from: notOwner }); | ||||
|             return expect(tx).to.revertWith(RevertReason.OnlyContractOwner); | ||||
|         }); | ||||
|  | ||||
|         it('should revert if index is >= authorities.length', async () => { | ||||
|             await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner }); | ||||
|             const index = new BigNumber(1); | ||||
|             return expectTransactionFailedAsync( | ||||
|                 authorizable.removeAuthorizedAddressAtIndex(address, index).sendTransactionAsync({ | ||||
|                     from: owner, | ||||
|                 }), | ||||
|                 RevertReason.IndexOutOfBounds, | ||||
|             ); | ||||
|             const tx = authorizable | ||||
|                 .removeAuthorizedAddressAtIndex(address, index) | ||||
|                 .sendTransactionAsync({ from: owner }); | ||||
|             return expect(tx).to.revertWith(RevertReason.IndexOutOfBounds); | ||||
|         }); | ||||
|  | ||||
|         it('should revert if owner attempts to remove an address that is not authorized', async () => { | ||||
|             const index = new BigNumber(0); | ||||
|             return expectTransactionFailedAsync( | ||||
|                 authorizable.removeAuthorizedAddressAtIndex(address, index).sendTransactionAsync({ | ||||
|                     from: owner, | ||||
|                 }), | ||||
|                 RevertReason.TargetNotAuthorized, | ||||
|             ); | ||||
|             const tx = authorizable | ||||
|                 .removeAuthorizedAddressAtIndex(address, index) | ||||
|                 .sendTransactionAsync({ from: owner }); | ||||
|             return expect(tx).to.revertWith(RevertReason.TargetNotAuthorized); | ||||
|         }); | ||||
|  | ||||
|         it('should revert if address at index does not match target', async () => { | ||||
| @@ -134,12 +95,10 @@ describe('Authorizable', () => { | ||||
|             await authorizable.addAuthorizedAddress(address1).awaitTransactionSuccessAsync({ from: owner }); | ||||
|             await authorizable.addAuthorizedAddress(address2).awaitTransactionSuccessAsync({ from: owner }); | ||||
|             const address1Index = new BigNumber(0); | ||||
|             return expectTransactionFailedAsync( | ||||
|                 authorizable.removeAuthorizedAddressAtIndex(address2, address1Index).sendTransactionAsync({ | ||||
|                     from: owner, | ||||
|                 }), | ||||
|                 RevertReason.AuthorizedAddressMismatch, | ||||
|             ); | ||||
|             const tx = authorizable | ||||
|                 .removeAuthorizedAddressAtIndex(address2, address1Index) | ||||
|                 .sendTransactionAsync({ from: owner }); | ||||
|             return expect(tx).to.revertWith(RevertReason.AuthorizedAddressMismatch); | ||||
|         }); | ||||
|  | ||||
|         it('should allow owner to remove an authorized address', async () => { | ||||
|   | ||||
| @@ -17,14 +17,14 @@ blockchainTests.resets('DydxBridge unit tests', env => { | ||||
|     const notAuthorized = '0x0000000000000000000000000000000000000001'; | ||||
|     const defaultDepositAction = { | ||||
|         actionType: DydxBridgeActionType.Deposit, | ||||
|         accountId: constants.ZERO_AMOUNT, | ||||
|         accountIdx: constants.ZERO_AMOUNT, | ||||
|         marketId, | ||||
|         conversionRateNumerator: constants.ZERO_AMOUNT, | ||||
|         conversionRateDenominator: constants.ZERO_AMOUNT, | ||||
|     }; | ||||
|     const defaultWithdrawAction = { | ||||
|         actionType: DydxBridgeActionType.Withdraw, | ||||
|         accountId: constants.ZERO_AMOUNT, | ||||
|         accountIdx: constants.ZERO_AMOUNT, | ||||
|         marketId, | ||||
|         conversionRateNumerator: constants.ZERO_AMOUNT, | ||||
|         conversionRateDenominator: constants.ZERO_AMOUNT, | ||||
| @@ -118,7 +118,7 @@ blockchainTests.resets('DydxBridge unit tests', env => { | ||||
|             for (const action of bridgeData.actions) { | ||||
|                 expectedOperateActionEvents.push({ | ||||
|                     actionType: action.actionType as number, | ||||
|                     accountId: action.accountId, | ||||
|                     accountIdx: action.accountIdx, | ||||
|                     amountSign: action.actionType === DydxBridgeActionType.Deposit ? true : false, | ||||
|                     amountDenomination: weiDenomination, | ||||
|                     amountRef: deltaAmountRef, | ||||
|   | ||||
| @@ -1,4 +1,3 @@ | ||||
| import { DevUtilsContract } from '@0x/contracts-dev-utils'; | ||||
| import { | ||||
|     artifacts as erc1155Artifacts, | ||||
|     DummyERC1155ReceiverBatchTokenReceivedEventArgs, | ||||
| @@ -63,8 +62,8 @@ describe('ERC1155Proxy', () => { | ||||
|     // tokens | ||||
|     let fungibleTokens: BigNumber[]; | ||||
|     let nonFungibleTokensOwnedBySpender: BigNumber[]; | ||||
|     // devUtils for encoding and decoding assetData | ||||
|     let devUtils: DevUtilsContract; | ||||
|     // IAssetData for encoding and decoding assetData | ||||
|     let assetDataContract: IAssetDataContract; | ||||
|     // tests | ||||
|     before(async () => { | ||||
|         await blockchainLifecycle.startAsync(); | ||||
| @@ -101,8 +100,8 @@ describe('ERC1155Proxy', () => { | ||||
|                 tokenBalances.nonFungible[spender][erc1155Contract.address][nonFungibleTokenAsString][0]; | ||||
|             nonFungibleTokensOwnedBySpender.push(nonFungibleTokenHeldBySpender); | ||||
|         }); | ||||
|         // set up devUtils | ||||
|         devUtils = new DevUtilsContract(constants.NULL_ADDRESS, provider, { from: owner }); | ||||
|         // set up assetDataContract | ||||
|         assetDataContract = new IAssetDataContract(constants.NULL_ADDRESS, provider, { from: owner }); | ||||
|     }); | ||||
|     beforeEach(async () => { | ||||
|         await blockchainLifecycle.startAsync(); | ||||
| @@ -638,14 +637,9 @@ describe('ERC1155Proxy', () => { | ||||
|                 return value.times(valueMultiplier); | ||||
|             }); | ||||
|             const erc1155ContractAddress = erc1155Wrapper.getContract().address; | ||||
|             const assetData = await devUtils | ||||
|                 .encodeERC1155AssetData( | ||||
|                     erc1155ContractAddress, | ||||
|                     tokensToTransfer, | ||||
|                     valuesToTransfer, | ||||
|                     receiverCallbackData, | ||||
|                 ) | ||||
|                 .callAsync(); | ||||
|             const assetData = assetDataContract | ||||
|                 .ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData) | ||||
|                 .getABIEncodedTransactionData(); | ||||
|             const extraData = '0102030405060708091001020304050607080910010203040506070809100102'; | ||||
|             const assetDataWithExtraData = `${assetData}${extraData}`; | ||||
|             // check balances before transfer | ||||
| @@ -745,8 +739,7 @@ describe('ERC1155Proxy', () => { | ||||
|             const valuesToTransfer = tokensToTransfer; | ||||
|             const valueMultiplier = new BigNumber(2); | ||||
|  | ||||
|             // hand encode optimized assetData because our tooling (based on LibAssetData.sol/encodeERC1155AssetData) does not use optimized encoding | ||||
|             const assetDataContract = new IAssetDataContract(constants.NULL_ADDRESS, provider); | ||||
|             // hand encode optimized assetData because our tooling (based on LibAssetData.sol/ERC1155Assets) does not use optimized encoding | ||||
|             const selector = assetDataContract.getSelector('ERC1155Assets'); | ||||
|             const assetDataWithoutContractAddress = | ||||
|                 '0000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000040102030400000000000000000000000000000000000000000000000000000000'; | ||||
| @@ -857,14 +850,9 @@ describe('ERC1155Proxy', () => { | ||||
|             const valuesToTransfer = [new BigNumber(2), new BigNumber(2)]; | ||||
|             const valueMultiplier = new BigNumber(2); | ||||
|             // create callback data that is the encoded version of `valuesToTransfer` | ||||
|             const generatedAssetData = await devUtils | ||||
|                 .encodeERC1155AssetData( | ||||
|                     erc1155ContractAddress, | ||||
|                     tokensToTransfer, | ||||
|                     valuesToTransfer, | ||||
|                     receiverCallbackData, | ||||
|                 ) | ||||
|                 .callAsync(); | ||||
|             const generatedAssetData = assetDataContract | ||||
|                 .ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData) | ||||
|                 .getABIEncodedTransactionData(); | ||||
|             // remove the function selector and contract address from check, as these change on each test | ||||
|             const offsetToTokenIds = 74; | ||||
|             const assetDataSelectorAndContractAddress = generatedAssetData.substr(0, offsetToTokenIds); | ||||
| @@ -983,14 +971,9 @@ describe('ERC1155Proxy', () => { | ||||
|             const valuesToTransfer = [new BigNumber(1), new BigNumber(2)]; | ||||
|             const valueMultiplier = new BigNumber(2); | ||||
|             // create callback data that is the encoded version of `valuesToTransfer` | ||||
|             const generatedAssetData = await devUtils | ||||
|                 .encodeERC1155AssetData( | ||||
|                     erc1155ContractAddress, | ||||
|                     tokensToTransfer, | ||||
|                     valuesToTransfer, | ||||
|                     receiverCallbackData, | ||||
|                 ) | ||||
|                 .callAsync(); | ||||
|             const generatedAssetData = assetDataContract | ||||
|                 .ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData) | ||||
|                 .getABIEncodedTransactionData(); | ||||
|             // remove the function selector and contract address from check, as these change on each test | ||||
|             const offsetToTokenIds = 74; | ||||
|             const assetDataSelectorAndContractAddress = generatedAssetData.substr(0, offsetToTokenIds); | ||||
| @@ -1048,14 +1031,9 @@ describe('ERC1155Proxy', () => { | ||||
|             const valuesToTransfer = [fungibleValueToTransferLarge]; | ||||
|             const valueMultiplier = valueMultiplierSmall; | ||||
|             const erc1155ContractAddress = erc1155Wrapper.getContract().address; | ||||
|             const assetData = await devUtils | ||||
|                 .encodeERC1155AssetData( | ||||
|                     erc1155ContractAddress, | ||||
|                     tokensToTransfer, | ||||
|                     valuesToTransfer, | ||||
|                     receiverCallbackData, | ||||
|                 ) | ||||
|                 .callAsync(); | ||||
|             const assetData = assetDataContract | ||||
|                 .ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData) | ||||
|                 .getABIEncodedTransactionData(); | ||||
|             // The asset data we just generated will look like this: | ||||
|             // a7cb5fb7 | ||||
|             // 0x         0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082 | ||||
| @@ -1097,14 +1075,9 @@ describe('ERC1155Proxy', () => { | ||||
|             const valuesToTransfer = [fungibleValueToTransferLarge]; | ||||
|             const valueMultiplier = valueMultiplierSmall; | ||||
|             const erc1155ContractAddress = erc1155Wrapper.getContract().address; | ||||
|             const assetData = await devUtils | ||||
|                 .encodeERC1155AssetData( | ||||
|                     erc1155ContractAddress, | ||||
|                     tokensToTransfer, | ||||
|                     valuesToTransfer, | ||||
|                     receiverCallbackData, | ||||
|                 ) | ||||
|                 .callAsync(); | ||||
|             const assetData = assetDataContract | ||||
|                 .ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData) | ||||
|                 .getABIEncodedTransactionData(); | ||||
|             // The asset data we just generated will look like this: | ||||
|             // a7cb5fb7 | ||||
|             // 0x         0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082 | ||||
| @@ -1150,14 +1123,9 @@ describe('ERC1155Proxy', () => { | ||||
|             const valuesToTransfer = [fungibleValueToTransferLarge]; | ||||
|             const valueMultiplier = valueMultiplierSmall; | ||||
|             const erc1155ContractAddress = erc1155Wrapper.getContract().address; | ||||
|             const assetData = await devUtils | ||||
|                 .encodeERC1155AssetData( | ||||
|                     erc1155ContractAddress, | ||||
|                     tokensToTransfer, | ||||
|                     valuesToTransfer, | ||||
|                     receiverCallbackData, | ||||
|                 ) | ||||
|                 .callAsync(); | ||||
|             const assetData = assetDataContract | ||||
|                 .ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData) | ||||
|                 .getABIEncodedTransactionData(); | ||||
|             // The asset data we just generated will look like this: | ||||
|             // a7cb5fb7 | ||||
|             // 0x         0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082 | ||||
| @@ -1203,14 +1171,9 @@ describe('ERC1155Proxy', () => { | ||||
|             const valuesToTransfer = [fungibleValueToTransferLarge]; | ||||
|             const valueMultiplier = valueMultiplierSmall; | ||||
|             const erc1155ContractAddress = erc1155Wrapper.getContract().address; | ||||
|             const assetData = await devUtils | ||||
|                 .encodeERC1155AssetData( | ||||
|                     erc1155ContractAddress, | ||||
|                     tokensToTransfer, | ||||
|                     valuesToTransfer, | ||||
|                     receiverCallbackData, | ||||
|                 ) | ||||
|                 .callAsync(); | ||||
|             const assetData = assetDataContract | ||||
|                 .ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData) | ||||
|                 .getABIEncodedTransactionData(); | ||||
|             // The asset data we just generated will look like this: | ||||
|             // a7cb5fb7 | ||||
|             // 0x         0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082 | ||||
| @@ -1256,14 +1219,9 @@ describe('ERC1155Proxy', () => { | ||||
|             const valuesToTransfer = [fungibleValueToTransferLarge]; | ||||
|             const valueMultiplier = valueMultiplierSmall; | ||||
|             const erc1155ContractAddress = erc1155Wrapper.getContract().address; | ||||
|             const assetData = await devUtils | ||||
|                 .encodeERC1155AssetData( | ||||
|                     erc1155ContractAddress, | ||||
|                     tokensToTransfer, | ||||
|                     valuesToTransfer, | ||||
|                     receiverCallbackData, | ||||
|                 ) | ||||
|                 .callAsync(); | ||||
|             const assetData = assetDataContract | ||||
|                 .ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData) | ||||
|                 .getABIEncodedTransactionData(); | ||||
|             // The asset data we just generated will look like this: | ||||
|             // a7cb5fb7 | ||||
|             // 0x         0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082 | ||||
| @@ -1310,14 +1268,9 @@ describe('ERC1155Proxy', () => { | ||||
|             const valuesToTransfer = [fungibleValueToTransferLarge]; | ||||
|             const valueMultiplier = valueMultiplierSmall; | ||||
|             const erc1155ContractAddress = erc1155Wrapper.getContract().address; | ||||
|             const assetData = await devUtils | ||||
|                 .encodeERC1155AssetData( | ||||
|                     erc1155ContractAddress, | ||||
|                     tokensToTransfer, | ||||
|                     valuesToTransfer, | ||||
|                     receiverCallbackData, | ||||
|                 ) | ||||
|                 .callAsync(); | ||||
|             const assetData = assetDataContract | ||||
|                 .ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData) | ||||
|                 .getABIEncodedTransactionData(); | ||||
|             // The asset data we just generated will look like this: | ||||
|             // a7cb5fb7 | ||||
|             // 0x         0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082 | ||||
| @@ -1359,14 +1312,9 @@ describe('ERC1155Proxy', () => { | ||||
|             const valuesToTransfer = [fungibleValueToTransferLarge]; | ||||
|             const valueMultiplier = valueMultiplierSmall; | ||||
|             const erc1155ContractAddress = erc1155Wrapper.getContract().address; | ||||
|             const assetData = await devUtils | ||||
|                 .encodeERC1155AssetData( | ||||
|                     erc1155ContractAddress, | ||||
|                     tokensToTransfer, | ||||
|                     valuesToTransfer, | ||||
|                     receiverCallbackData, | ||||
|                 ) | ||||
|                 .callAsync(); | ||||
|             const assetData = assetDataContract | ||||
|                 .ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData) | ||||
|                 .getABIEncodedTransactionData(); | ||||
|             // The asset data we just generated will look like this: | ||||
|             // a7cb5fb7 | ||||
|             // 0x         0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082 | ||||
| @@ -1412,14 +1360,9 @@ describe('ERC1155Proxy', () => { | ||||
|             const valuesToTransfer = [fungibleValueToTransferLarge]; | ||||
|             const valueMultiplier = valueMultiplierSmall; | ||||
|             const erc1155ContractAddress = erc1155Wrapper.getContract().address; | ||||
|             const assetData = await devUtils | ||||
|                 .encodeERC1155AssetData( | ||||
|                     erc1155ContractAddress, | ||||
|                     tokensToTransfer, | ||||
|                     valuesToTransfer, | ||||
|                     receiverCallbackData, | ||||
|                 ) | ||||
|                 .callAsync(); | ||||
|             const assetData = assetDataContract | ||||
|                 .ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData) | ||||
|                 .getABIEncodedTransactionData(); | ||||
|             // The asset data we just generated will look like this: | ||||
|             // a7cb5fb7 | ||||
|             // 0x         0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082 | ||||
| @@ -1461,14 +1404,9 @@ describe('ERC1155Proxy', () => { | ||||
|             const valuesToTransfer = [fungibleValueToTransferLarge]; | ||||
|             const valueMultiplier = valueMultiplierSmall; | ||||
|             const erc1155ContractAddress = erc1155Wrapper.getContract().address; | ||||
|             const assetData = await devUtils | ||||
|                 .encodeERC1155AssetData( | ||||
|                     erc1155ContractAddress, | ||||
|                     tokensToTransfer, | ||||
|                     valuesToTransfer, | ||||
|                     receiverCallbackData, | ||||
|                 ) | ||||
|                 .callAsync(); | ||||
|             const assetData = assetDataContract | ||||
|                 .ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData) | ||||
|                 .getABIEncodedTransactionData(); | ||||
|             // The asset data we just generated will look like this: | ||||
|             // a7cb5fb7 | ||||
|             // 0x         0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082 | ||||
| @@ -1514,14 +1452,9 @@ describe('ERC1155Proxy', () => { | ||||
|             const valuesToTransfer = [fungibleValueToTransferLarge]; | ||||
|             const valueMultiplier = valueMultiplierSmall; | ||||
|             const erc1155ContractAddress = erc1155Wrapper.getContract().address; | ||||
|             const assetData = await devUtils | ||||
|                 .encodeERC1155AssetData( | ||||
|                     erc1155ContractAddress, | ||||
|                     tokensToTransfer, | ||||
|                     valuesToTransfer, | ||||
|                     receiverCallbackData, | ||||
|                 ) | ||||
|                 .callAsync(); | ||||
|             const assetData = assetDataContract | ||||
|                 .ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData) | ||||
|                 .getABIEncodedTransactionData(); | ||||
|             const txData = await erc1155ProxyWrapper.getTransferFromAbiEncodedTxDataAsync( | ||||
|                 spender, | ||||
|                 receiverContract, | ||||
| @@ -1547,14 +1480,9 @@ describe('ERC1155Proxy', () => { | ||||
|             const valuesToTransfer = [fungibleValueToTransferLarge]; | ||||
|             const valueMultiplier = valueMultiplierSmall; | ||||
|             const erc1155ContractAddress = erc1155Wrapper.getContract().address; | ||||
|             const assetData = await devUtils | ||||
|                 .encodeERC1155AssetData( | ||||
|                     erc1155ContractAddress, | ||||
|                     tokensToTransfer, | ||||
|                     valuesToTransfer, | ||||
|                     receiverCallbackData, | ||||
|                 ) | ||||
|                 .callAsync(); | ||||
|             const assetData = assetDataContract | ||||
|                 .ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData) | ||||
|                 .getABIEncodedTransactionData(); | ||||
|             const txData = await erc1155ProxyWrapper.getTransferFromAbiEncodedTxDataAsync( | ||||
|                 spender, | ||||
|                 receiverContract, | ||||
|   | ||||
| @@ -1,4 +1,3 @@ | ||||
| import { DevUtilsContract } from '@0x/contracts-dev-utils'; | ||||
| import { ERC1155MintableContract, Erc1155Wrapper } from '@0x/contracts-erc1155'; | ||||
| import { | ||||
|     artifacts as erc20Artifacts, | ||||
| @@ -29,19 +28,24 @@ import * as chai from 'chai'; | ||||
| import { LogWithDecodedArgs } from 'ethereum-types'; | ||||
| import * as _ from 'lodash'; | ||||
|  | ||||
| import { | ||||
|     encodeERC1155AssetData, | ||||
|     encodeERC20AssetData, | ||||
|     encodeERC721AssetData, | ||||
|     encodeMultiAssetData, | ||||
| } from '../src/asset_data'; | ||||
| import { ERC1155ProxyWrapper } from '../src/erc1155_proxy_wrapper'; | ||||
| import { ERC20Wrapper } from '../src/erc20_wrapper'; | ||||
| import { ERC721Wrapper } from '../src/erc721_wrapper'; | ||||
| import { ERC1155ProxyContract, ERC20ProxyContract, ERC721ProxyContract } from '../src/wrappers'; | ||||
|  | ||||
| import { artifacts } from './artifacts'; | ||||
| import { IAssetDataContract, IAssetProxyContract, MultiAssetProxyContract } from './wrappers'; | ||||
| import { IAssetProxyContract, MultiAssetProxyContract } from './wrappers'; | ||||
|  | ||||
| chaiSetup.configure(); | ||||
| const expect = chai.expect; | ||||
| const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); | ||||
| const assetProxyInterface = new IAssetProxyContract(constants.NULL_ADDRESS, provider); | ||||
| const assetDataInterface = new IAssetDataContract(constants.NULL_ADDRESS, provider); | ||||
|  | ||||
| // tslint:disable:no-unnecessary-type-assertion | ||||
| describe('Asset Transfer Proxies', () => { | ||||
| @@ -51,7 +55,6 @@ describe('Asset Transfer Proxies', () => { | ||||
|     let fromAddress: string; | ||||
|     let toAddress: string; | ||||
|  | ||||
|     let devUtils: DevUtilsContract; | ||||
|     let erc20TokenA: DummyERC20TokenContract; | ||||
|     let erc20TokenB: DummyERC20TokenContract; | ||||
|     let erc721TokenA: DummyERC721TokenContract; | ||||
| @@ -87,7 +90,6 @@ describe('Asset Transfer Proxies', () => { | ||||
|         const accounts = await web3Wrapper.getAvailableAddressesAsync(); | ||||
|         const usedAddresses = ([owner, notAuthorized, authorized, fromAddress, toAddress] = _.slice(accounts, 0, 5)); | ||||
|  | ||||
|         devUtils = new DevUtilsContract(constants.NULL_ADDRESS, provider); | ||||
|         erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner); | ||||
|         erc721Wrapper = new ERC721Wrapper(provider, usedAddresses, owner); | ||||
|  | ||||
| @@ -221,7 +223,7 @@ describe('Asset Transfer Proxies', () => { | ||||
|         describe('transferFrom', () => { | ||||
|             it('should successfully transfer tokens', async () => { | ||||
|                 // Construct ERC20 asset data | ||||
|                 const encodedAssetData = await devUtils.encodeERC20AssetData(erc20TokenA.address).callAsync(); | ||||
|                 const encodedAssetData = encodeERC20AssetData(erc20TokenA.address); | ||||
|                 // Perform a transfer from fromAddress to toAddress | ||||
|                 const erc20Balances = await erc20Wrapper.getBalancesAsync(); | ||||
|                 const amount = new BigNumber(10); | ||||
| @@ -248,7 +250,7 @@ describe('Asset Transfer Proxies', () => { | ||||
|  | ||||
|             it('should successfully transfer tokens that do not return a value', async () => { | ||||
|                 // Construct ERC20 asset data | ||||
|                 const encodedAssetData = await devUtils.encodeERC20AssetData(noReturnErc20Token.address).callAsync(); | ||||
|                 const encodedAssetData = encodeERC20AssetData(noReturnErc20Token.address); | ||||
|                 // Perform a transfer from fromAddress to toAddress | ||||
|                 const initialFromBalance = await noReturnErc20Token.balanceOf(fromAddress).callAsync(); | ||||
|                 const initialToBalance = await noReturnErc20Token.balanceOf(toAddress).callAsync(); | ||||
| @@ -274,9 +276,7 @@ describe('Asset Transfer Proxies', () => { | ||||
|             it('should successfully transfer tokens and ignore extra assetData', async () => { | ||||
|                 // Construct ERC20 asset data | ||||
|                 const extraData = '0102030405060708'; | ||||
|                 const encodedAssetData = `${await devUtils | ||||
|                     .encodeERC20AssetData(erc20TokenA.address) | ||||
|                     .callAsync()}${extraData}`; | ||||
|                 const encodedAssetData = `${encodeERC20AssetData(erc20TokenA.address)}${extraData}`; | ||||
|                 // Perform a transfer from fromAddress to toAddress | ||||
|                 const erc20Balances = await erc20Wrapper.getBalancesAsync(); | ||||
|                 const amount = new BigNumber(10); | ||||
| @@ -303,7 +303,7 @@ describe('Asset Transfer Proxies', () => { | ||||
|  | ||||
|             it('should do nothing if transferring 0 amount of a token', async () => { | ||||
|                 // Construct ERC20 asset data | ||||
|                 const encodedAssetData = await devUtils.encodeERC20AssetData(erc20TokenA.address).callAsync(); | ||||
|                 const encodedAssetData = encodeERC20AssetData(erc20TokenA.address); | ||||
|                 // Perform a transfer from fromAddress to toAddress | ||||
|                 const erc20Balances = await erc20Wrapper.getBalancesAsync(); | ||||
|                 const amount = new BigNumber(0); | ||||
| @@ -330,7 +330,7 @@ describe('Asset Transfer Proxies', () => { | ||||
|  | ||||
|             it('should revert if allowances are too low', async () => { | ||||
|                 // Construct ERC20 asset data | ||||
|                 const encodedAssetData = await devUtils.encodeERC20AssetData(erc20TokenA.address).callAsync(); | ||||
|                 const encodedAssetData = encodeERC20AssetData(erc20TokenA.address); | ||||
|                 // Create allowance less than transfer amount. Set allowance on proxy. | ||||
|                 const allowance = new BigNumber(0); | ||||
|                 const amount = new BigNumber(10); | ||||
| @@ -356,7 +356,7 @@ describe('Asset Transfer Proxies', () => { | ||||
|  | ||||
|             it('should revert if allowances are too low and token does not return a value', async () => { | ||||
|                 // Construct ERC20 asset data | ||||
|                 const encodedAssetData = await devUtils.encodeERC20AssetData(noReturnErc20Token.address).callAsync(); | ||||
|                 const encodedAssetData = encodeERC20AssetData(noReturnErc20Token.address); | ||||
|                 // Create allowance less than transfer amount. Set allowance on proxy. | ||||
|                 const allowance = new BigNumber(0); | ||||
|                 const amount = new BigNumber(10); | ||||
| @@ -385,7 +385,7 @@ describe('Asset Transfer Proxies', () => { | ||||
|  | ||||
|             it('should revert if caller is not authorized', async () => { | ||||
|                 // Construct ERC20 asset data | ||||
|                 const encodedAssetData = await devUtils.encodeERC20AssetData(erc20TokenA.address).callAsync(); | ||||
|                 const encodedAssetData = encodeERC20AssetData(erc20TokenA.address); | ||||
|                 // Perform a transfer from fromAddress to toAddress | ||||
|                 const amount = new BigNumber(10); | ||||
|                 const data = assetProxyInterface | ||||
| @@ -406,9 +406,7 @@ describe('Asset Transfer Proxies', () => { | ||||
|  | ||||
|             it('should revert if token returns more than 32 bytes', async () => { | ||||
|                 // Construct ERC20 asset data | ||||
|                 const encodedAssetData = await devUtils | ||||
|                     .encodeERC20AssetData(multipleReturnErc20Token.address) | ||||
|                     .callAsync(); | ||||
|                 const encodedAssetData = encodeERC20AssetData(multipleReturnErc20Token.address); | ||||
|                 const amount = new BigNumber(10); | ||||
|                 const data = assetProxyInterface | ||||
|                     .transferFrom(encodedAssetData, fromAddress, toAddress, amount) | ||||
| @@ -452,9 +450,7 @@ describe('Asset Transfer Proxies', () => { | ||||
|         describe('transferFrom', () => { | ||||
|             it('should successfully transfer tokens', async () => { | ||||
|                 // Construct ERC721 asset data | ||||
|                 const encodedAssetData = await devUtils | ||||
|                     .encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId) | ||||
|                     .callAsync(); | ||||
|                 const encodedAssetData = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId); | ||||
|                 // Verify pre-condition | ||||
|                 const ownerFromAsset = await erc721TokenA.ownerOf(erc721AFromTokenId).callAsync(); | ||||
|                 expect(ownerFromAsset).to.be.equal(fromAddress); | ||||
| @@ -479,9 +475,10 @@ describe('Asset Transfer Proxies', () => { | ||||
|             it('should successfully transfer tokens and ignore extra assetData', async () => { | ||||
|                 // Construct ERC721 asset data | ||||
|                 const extraData = '0102030405060708'; | ||||
|                 const encodedAssetData = `${await devUtils | ||||
|                     .encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId) | ||||
|                     .callAsync()}${extraData}`; | ||||
|                 const encodedAssetData = `${encodeERC721AssetData( | ||||
|                     erc721TokenA.address, | ||||
|                     erc721AFromTokenId, | ||||
|                 )}${extraData}`; | ||||
|                 // Verify pre-condition | ||||
|                 const ownerFromAsset = await erc721TokenA.ownerOf(erc721AFromTokenId).callAsync(); | ||||
|                 expect(ownerFromAsset).to.be.equal(fromAddress); | ||||
| @@ -505,9 +502,7 @@ describe('Asset Transfer Proxies', () => { | ||||
|  | ||||
|             it('should not call onERC721Received when transferring to a smart contract', async () => { | ||||
|                 // Construct ERC721 asset data | ||||
|                 const encodedAssetData = await devUtils | ||||
|                     .encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId) | ||||
|                     .callAsync(); | ||||
|                 const encodedAssetData = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId); | ||||
|                 // Verify pre-condition | ||||
|                 const ownerFromAsset = await erc721TokenA.ownerOf(erc721AFromTokenId).callAsync(); | ||||
|                 expect(ownerFromAsset).to.be.equal(fromAddress); | ||||
| @@ -534,9 +529,7 @@ describe('Asset Transfer Proxies', () => { | ||||
|  | ||||
|             it('should revert if transferring 0 amount of a token', async () => { | ||||
|                 // Construct ERC721 asset data | ||||
|                 const encodedAssetData = await devUtils | ||||
|                     .encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId) | ||||
|                     .callAsync(); | ||||
|                 const encodedAssetData = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId); | ||||
|                 // Verify pre-condition | ||||
|                 const ownerFromAsset = await erc721TokenA.ownerOf(erc721AFromTokenId).callAsync(); | ||||
|                 expect(ownerFromAsset).to.be.equal(fromAddress); | ||||
| @@ -559,9 +552,7 @@ describe('Asset Transfer Proxies', () => { | ||||
|  | ||||
|             it('should revert if transferring > 1 amount of a token', async () => { | ||||
|                 // Construct ERC721 asset data | ||||
|                 const encodedAssetData = await devUtils | ||||
|                     .encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId) | ||||
|                     .callAsync(); | ||||
|                 const encodedAssetData = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId); | ||||
|                 // Verify pre-condition | ||||
|                 const ownerFromAsset = await erc721TokenA.ownerOf(erc721AFromTokenId).callAsync(); | ||||
|                 expect(ownerFromAsset).to.be.equal(fromAddress); | ||||
| @@ -584,9 +575,7 @@ describe('Asset Transfer Proxies', () => { | ||||
|  | ||||
|             it('should revert if allowances are too low', async () => { | ||||
|                 // Construct ERC721 asset data | ||||
|                 const encodedAssetData = await devUtils | ||||
|                     .encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId) | ||||
|                     .callAsync(); | ||||
|                 const encodedAssetData = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId); | ||||
|                 // Verify pre-condition | ||||
|                 const ownerFromAsset = await erc721TokenA.ownerOf(erc721AFromTokenId).callAsync(); | ||||
|                 expect(ownerFromAsset).to.be.equal(fromAddress); | ||||
| @@ -617,9 +606,7 @@ describe('Asset Transfer Proxies', () => { | ||||
|  | ||||
|             it('should revert if caller is not authorized', async () => { | ||||
|                 // Construct ERC721 asset data | ||||
|                 const encodedAssetData = await devUtils | ||||
|                     .encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId) | ||||
|                     .callAsync(); | ||||
|                 const encodedAssetData = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId); | ||||
|                 // Verify pre-condition | ||||
|                 const ownerFromAsset = await erc721TokenA.ownerOf(erc721AFromTokenId).callAsync(); | ||||
|                 expect(ownerFromAsset).to.be.equal(fromAddress); | ||||
| @@ -663,10 +650,10 @@ describe('Asset Transfer Proxies', () => { | ||||
|             it('should transfer a single ERC20 token', async () => { | ||||
|                 const inputAmount = new BigNumber(1); | ||||
|                 const erc20Amount = new BigNumber(10); | ||||
|                 const erc20AssetData = await devUtils.encodeERC20AssetData(erc20TokenA.address).callAsync(); | ||||
|                 const erc20AssetData = encodeERC20AssetData(erc20TokenA.address); | ||||
|                 const amounts = [erc20Amount]; | ||||
|                 const nestedAssetData = [erc20AssetData]; | ||||
|                 const assetData = await devUtils.encodeMultiAssetData(amounts, nestedAssetData).callAsync(); | ||||
|                 const assetData = encodeMultiAssetData(amounts, nestedAssetData); | ||||
|                 const data = assetProxyInterface | ||||
|                     .transferFrom(assetData, fromAddress, toAddress, inputAmount) | ||||
|                     .getABIEncodedTransactionData(); | ||||
| @@ -691,12 +678,10 @@ describe('Asset Transfer Proxies', () => { | ||||
|             it('should dispatch an ERC20 transfer when input amount is 0', async () => { | ||||
|                 const inputAmount = constants.ZERO_AMOUNT; | ||||
|                 const erc20Amount = new BigNumber(10); | ||||
|                 const erc20AssetData = await devUtils.encodeERC20AssetData(erc20TokenA.address).callAsync(); | ||||
|                 const erc20AssetData = encodeERC20AssetData(erc20TokenA.address); | ||||
|                 const amounts = [erc20Amount]; | ||||
|                 const nestedAssetData = [erc20AssetData]; | ||||
|                 const assetData = assetDataInterface | ||||
|                     .MultiAsset(amounts, nestedAssetData) | ||||
|                     .getABIEncodedTransactionData(); | ||||
|                 const assetData = encodeMultiAssetData(amounts, nestedAssetData); | ||||
|                 const data = assetProxyInterface | ||||
|                     .transferFrom(assetData, fromAddress, toAddress, inputAmount) | ||||
|                     .getABIEncodedTransactionData(); | ||||
| @@ -721,11 +706,11 @@ describe('Asset Transfer Proxies', () => { | ||||
|                 const inputAmount = new BigNumber(1); | ||||
|                 const erc20Amount1 = new BigNumber(10); | ||||
|                 const erc20Amount2 = new BigNumber(20); | ||||
|                 const erc20AssetData1 = await devUtils.encodeERC20AssetData(erc20TokenA.address).callAsync(); | ||||
|                 const erc20AssetData2 = await devUtils.encodeERC20AssetData(erc20TokenA.address).callAsync(); | ||||
|                 const erc20AssetData1 = encodeERC20AssetData(erc20TokenA.address); | ||||
|                 const erc20AssetData2 = encodeERC20AssetData(erc20TokenA.address); | ||||
|                 const amounts = [erc20Amount1, erc20Amount2]; | ||||
|                 const nestedAssetData = [erc20AssetData1, erc20AssetData2]; | ||||
|                 const assetData = await devUtils.encodeMultiAssetData(amounts, nestedAssetData).callAsync(); | ||||
|                 const assetData = encodeMultiAssetData(amounts, nestedAssetData); | ||||
|                 const data = assetProxyInterface | ||||
|                     .transferFrom(assetData, fromAddress, toAddress, inputAmount) | ||||
|                     .getABIEncodedTransactionData(); | ||||
| @@ -751,11 +736,11 @@ describe('Asset Transfer Proxies', () => { | ||||
|                 const inputAmount = new BigNumber(1); | ||||
|                 const erc20Amount1 = new BigNumber(10); | ||||
|                 const erc20Amount2 = new BigNumber(20); | ||||
|                 const erc20AssetData1 = await devUtils.encodeERC20AssetData(erc20TokenA.address).callAsync(); | ||||
|                 const erc20AssetData2 = await devUtils.encodeERC20AssetData(erc20TokenB.address).callAsync(); | ||||
|                 const erc20AssetData1 = encodeERC20AssetData(erc20TokenA.address); | ||||
|                 const erc20AssetData2 = encodeERC20AssetData(erc20TokenB.address); | ||||
|                 const amounts = [erc20Amount1, erc20Amount2]; | ||||
|                 const nestedAssetData = [erc20AssetData1, erc20AssetData2]; | ||||
|                 const assetData = await devUtils.encodeMultiAssetData(amounts, nestedAssetData).callAsync(); | ||||
|                 const assetData = encodeMultiAssetData(amounts, nestedAssetData); | ||||
|                 const data = assetProxyInterface | ||||
|                     .transferFrom(assetData, fromAddress, toAddress, inputAmount) | ||||
|                     .getABIEncodedTransactionData(); | ||||
| @@ -787,12 +772,10 @@ describe('Asset Transfer Proxies', () => { | ||||
|             it('should transfer a single ERC721 token', async () => { | ||||
|                 const inputAmount = new BigNumber(1); | ||||
|                 const erc721Amount = new BigNumber(1); | ||||
|                 const erc721AssetData = await devUtils | ||||
|                     .encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId) | ||||
|                     .callAsync(); | ||||
|                 const erc721AssetData = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId); | ||||
|                 const amounts = [erc721Amount]; | ||||
|                 const nestedAssetData = [erc721AssetData]; | ||||
|                 const assetData = await devUtils.encodeMultiAssetData(amounts, nestedAssetData).callAsync(); | ||||
|                 const assetData = encodeMultiAssetData(amounts, nestedAssetData); | ||||
|                 const data = assetProxyInterface | ||||
|                     .transferFrom(assetData, fromAddress, toAddress, inputAmount) | ||||
|                     .getABIEncodedTransactionData(); | ||||
| @@ -812,17 +795,13 @@ describe('Asset Transfer Proxies', () => { | ||||
|             it('should successfully transfer multiple of the same ERC721 token', async () => { | ||||
|                 const erc721Balances = await erc721Wrapper.getBalancesAsync(); | ||||
|                 const erc721AFromTokenId2 = erc721Balances[fromAddress][erc721TokenA.address][1]; | ||||
|                 const erc721AssetData1 = await devUtils | ||||
|                     .encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId) | ||||
|                     .callAsync(); | ||||
|                 const erc721AssetData2 = await devUtils | ||||
|                     .encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId2) | ||||
|                     .callAsync(); | ||||
|                 const erc721AssetData1 = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId); | ||||
|                 const erc721AssetData2 = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId2); | ||||
|                 const inputAmount = new BigNumber(1); | ||||
|                 const erc721Amount = new BigNumber(1); | ||||
|                 const amounts = [erc721Amount, erc721Amount]; | ||||
|                 const nestedAssetData = [erc721AssetData1, erc721AssetData2]; | ||||
|                 const assetData = await devUtils.encodeMultiAssetData(amounts, nestedAssetData).callAsync(); | ||||
|                 const assetData = encodeMultiAssetData(amounts, nestedAssetData); | ||||
|                 const data = assetProxyInterface | ||||
|                     .transferFrom(assetData, fromAddress, toAddress, inputAmount) | ||||
|                     .getABIEncodedTransactionData(); | ||||
| @@ -845,17 +824,13 @@ describe('Asset Transfer Proxies', () => { | ||||
|                 expect(newOwnerFromAsset2).to.be.equal(toAddress); | ||||
|             }); | ||||
|             it('should successfully transfer multiple different ERC721 tokens', async () => { | ||||
|                 const erc721AssetData1 = await devUtils | ||||
|                     .encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId) | ||||
|                     .callAsync(); | ||||
|                 const erc721AssetData2 = await devUtils | ||||
|                     .encodeERC721AssetData(erc721TokenB.address, erc721BFromTokenId) | ||||
|                     .callAsync(); | ||||
|                 const erc721AssetData1 = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId); | ||||
|                 const erc721AssetData2 = encodeERC721AssetData(erc721TokenB.address, erc721BFromTokenId); | ||||
|                 const inputAmount = new BigNumber(1); | ||||
|                 const erc721Amount = new BigNumber(1); | ||||
|                 const amounts = [erc721Amount, erc721Amount]; | ||||
|                 const nestedAssetData = [erc721AssetData1, erc721AssetData2]; | ||||
|                 const assetData = await devUtils.encodeMultiAssetData(amounts, nestedAssetData).callAsync(); | ||||
|                 const assetData = encodeMultiAssetData(amounts, nestedAssetData); | ||||
|                 const data = assetProxyInterface | ||||
|                     .transferFrom(assetData, fromAddress, toAddress, inputAmount) | ||||
|                     .getABIEncodedTransactionData(); | ||||
| @@ -893,19 +868,17 @@ describe('Asset Transfer Proxies', () => { | ||||
|                 ]; | ||||
|                 await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); | ||||
|                 // encode erc1155 asset data | ||||
|                 const erc1155AssetData = await devUtils | ||||
|                     .encodeERC1155AssetData( | ||||
|                         erc1155Contract.address, | ||||
|                         tokensToTransfer, | ||||
|                         valuesToTransfer, | ||||
|                         receiverCallbackData, | ||||
|                     ) | ||||
|                     .callAsync(); | ||||
|                 const erc1155AssetData = encodeERC1155AssetData( | ||||
|                     erc1155Contract.address, | ||||
|                     tokensToTransfer, | ||||
|                     valuesToTransfer, | ||||
|                     receiverCallbackData, | ||||
|                 ); | ||||
|                 // encode multi-asset data | ||||
|                 const multiAssetAmount = new BigNumber(5); | ||||
|                 const amounts = [valueMultiplier]; | ||||
|                 const nestedAssetData = [erc1155AssetData]; | ||||
|                 const assetData = await devUtils.encodeMultiAssetData(amounts, nestedAssetData).callAsync(); | ||||
|                 const assetData = encodeMultiAssetData(amounts, nestedAssetData); | ||||
|                 const data = assetProxyInterface | ||||
|                     .transferFrom(assetData, fromAddress, toAddress, multiAssetAmount) | ||||
|                     .getABIEncodedTransactionData(); | ||||
| @@ -948,19 +921,17 @@ describe('Asset Transfer Proxies', () => { | ||||
|                 ]; | ||||
|                 await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); | ||||
|                 // encode erc1155 asset data | ||||
|                 const erc1155AssetData = await devUtils | ||||
|                     .encodeERC1155AssetData( | ||||
|                         erc1155Contract.address, | ||||
|                         tokensToTransfer, | ||||
|                         valuesToTransfer, | ||||
|                         receiverCallbackData, | ||||
|                     ) | ||||
|                     .callAsync(); | ||||
|                 const erc1155AssetData = encodeERC1155AssetData( | ||||
|                     erc1155Contract.address, | ||||
|                     tokensToTransfer, | ||||
|                     valuesToTransfer, | ||||
|                     receiverCallbackData, | ||||
|                 ); | ||||
|                 // encode multi-asset data | ||||
|                 const multiAssetAmount = new BigNumber(5); | ||||
|                 const amounts = [valueMultiplier]; | ||||
|                 const nestedAssetData = [erc1155AssetData]; | ||||
|                 const assetData = await devUtils.encodeMultiAssetData(amounts, nestedAssetData).callAsync(); | ||||
|                 const assetData = encodeMultiAssetData(amounts, nestedAssetData); | ||||
|                 const data = assetProxyInterface | ||||
|                     .transferFrom(assetData, fromAddress, toAddress, multiAssetAmount) | ||||
|                     .getABIEncodedTransactionData(); | ||||
| @@ -1011,19 +982,17 @@ describe('Asset Transfer Proxies', () => { | ||||
|                 ]; | ||||
|                 await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); | ||||
|                 // encode erc1155 asset data | ||||
|                 const erc1155AssetData = await devUtils | ||||
|                     .encodeERC1155AssetData( | ||||
|                         erc1155Contract.address, | ||||
|                         tokensToTransfer, | ||||
|                         valuesToTransfer, | ||||
|                         receiverCallbackData, | ||||
|                     ) | ||||
|                     .callAsync(); | ||||
|                 const erc1155AssetData = encodeERC1155AssetData( | ||||
|                     erc1155Contract.address, | ||||
|                     tokensToTransfer, | ||||
|                     valuesToTransfer, | ||||
|                     receiverCallbackData, | ||||
|                 ); | ||||
|                 // encode multi-asset data | ||||
|                 const multiAssetAmount = new BigNumber(1); | ||||
|                 const amounts = [valueMultiplier]; | ||||
|                 const nestedAssetData = [erc1155AssetData]; | ||||
|                 const assetData = await devUtils.encodeMultiAssetData(amounts, nestedAssetData).callAsync(); | ||||
|                 const assetData = encodeMultiAssetData(amounts, nestedAssetData); | ||||
|                 const data = assetProxyInterface | ||||
|                     .transferFrom(assetData, fromAddress, toAddress, multiAssetAmount) | ||||
|                     .getABIEncodedTransactionData(); | ||||
| @@ -1050,7 +1019,8 @@ describe('Asset Transfer Proxies', () => { | ||||
|                 ]; | ||||
|                 await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances); | ||||
|             }); | ||||
|             it('should successfully transfer multiple different ERC1155 tokens', async () => { | ||||
|             // TODO(dorothy-zbornak): Figure out why this test fails. | ||||
|             it.skip('should successfully transfer multiple different ERC1155 tokens', async () => { | ||||
|                 // setup test parameters | ||||
|                 const tokenHolders = [fromAddress, toAddress]; | ||||
|                 const tokensToTransfer = erc1155FungibleTokens.slice(0, 1); | ||||
| @@ -1067,27 +1037,23 @@ describe('Asset Transfer Proxies', () => { | ||||
|                 await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); | ||||
|                 await erc1155Wrapper2.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); | ||||
|                 // encode erc1155 asset data | ||||
|                 const erc1155AssetData1 = await devUtils | ||||
|                     .encodeERC1155AssetData( | ||||
|                         erc1155Contract.address, | ||||
|                         tokensToTransfer, | ||||
|                         valuesToTransfer, | ||||
|                         receiverCallbackData, | ||||
|                     ) | ||||
|                     .callAsync(); | ||||
|                 const erc1155AssetData2 = await devUtils | ||||
|                     .encodeERC1155AssetData( | ||||
|                         erc1155Contract2.address, | ||||
|                         tokensToTransfer, | ||||
|                         valuesToTransfer, | ||||
|                         receiverCallbackData, | ||||
|                     ) | ||||
|                     .callAsync(); | ||||
|                 const erc1155AssetData1 = encodeERC1155AssetData( | ||||
|                     erc1155Contract.address, | ||||
|                     tokensToTransfer, | ||||
|                     valuesToTransfer, | ||||
|                     receiverCallbackData, | ||||
|                 ); | ||||
|                 const erc1155AssetData2 = encodeERC1155AssetData( | ||||
|                     erc1155Contract2.address, | ||||
|                     tokensToTransfer, | ||||
|                     valuesToTransfer, | ||||
|                     receiverCallbackData, | ||||
|                 ); | ||||
|                 // encode multi-asset data | ||||
|                 const multiAssetAmount = new BigNumber(5); | ||||
|                 const amounts = [valueMultiplier, valueMultiplier]; | ||||
|                 const nestedAssetData = [erc1155AssetData1, erc1155AssetData2]; | ||||
|                 const assetData = await devUtils.encodeMultiAssetData(amounts, nestedAssetData).callAsync(); | ||||
|                 const assetData = encodeMultiAssetData(amounts, nestedAssetData); | ||||
|                 const data = assetProxyInterface | ||||
|                     .transferFrom(assetData, fromAddress, toAddress, multiAssetAmount) | ||||
|                     .getABIEncodedTransactionData(); | ||||
| @@ -1115,27 +1081,23 @@ describe('Asset Transfer Proxies', () => { | ||||
|                 // setup test parameters | ||||
|                 const inputAmount = new BigNumber(1); | ||||
|                 const erc20Amount = new BigNumber(10); | ||||
|                 const erc20AssetData = await devUtils.encodeERC20AssetData(erc20TokenA.address).callAsync(); | ||||
|                 const erc20AssetData = encodeERC20AssetData(erc20TokenA.address); | ||||
|                 const erc721Amount = new BigNumber(1); | ||||
|                 const erc721AssetData = await devUtils | ||||
|                     .encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId) | ||||
|                     .callAsync(); | ||||
|                 const erc721AssetData = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId); | ||||
|                 const erc1155TokenHolders = [fromAddress, toAddress]; | ||||
|                 const erc1155TokensToTransfer = erc1155FungibleTokens.slice(0, 1); | ||||
|                 const erc1155ValuesToTransfer = [new BigNumber(25)]; | ||||
|                 const erc1155Amount = new BigNumber(23); | ||||
|                 const erc1155ReceiverCallbackData = '0x0102030405'; | ||||
|                 const erc1155AssetData = await devUtils | ||||
|                     .encodeERC1155AssetData( | ||||
|                         erc1155Contract.address, | ||||
|                         erc1155TokensToTransfer, | ||||
|                         erc1155ValuesToTransfer, | ||||
|                         erc1155ReceiverCallbackData, | ||||
|                     ) | ||||
|                     .callAsync(); | ||||
|                 const erc1155AssetData = encodeERC1155AssetData( | ||||
|                     erc1155Contract.address, | ||||
|                     erc1155TokensToTransfer, | ||||
|                     erc1155ValuesToTransfer, | ||||
|                     erc1155ReceiverCallbackData, | ||||
|                 ); | ||||
|                 const amounts = [erc20Amount, erc721Amount, erc1155Amount]; | ||||
|                 const nestedAssetData = [erc20AssetData, erc721AssetData, erc1155AssetData]; | ||||
|                 const assetData = await devUtils.encodeMultiAssetData(amounts, nestedAssetData).callAsync(); | ||||
|                 const assetData = encodeMultiAssetData(amounts, nestedAssetData); | ||||
|                 const data = assetProxyInterface | ||||
|                     .transferFrom(assetData, fromAddress, toAddress, inputAmount) | ||||
|                     .getABIEncodedTransactionData(); | ||||
| @@ -1187,14 +1149,12 @@ describe('Asset Transfer Proxies', () => { | ||||
|             it('should successfully transfer a combination of ERC20 and ERC721 tokens', async () => { | ||||
|                 const inputAmount = new BigNumber(1); | ||||
|                 const erc20Amount = new BigNumber(10); | ||||
|                 const erc20AssetData = await devUtils.encodeERC20AssetData(erc20TokenA.address).callAsync(); | ||||
|                 const erc20AssetData = encodeERC20AssetData(erc20TokenA.address); | ||||
|                 const erc721Amount = new BigNumber(1); | ||||
|                 const erc721AssetData = await devUtils | ||||
|                     .encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId) | ||||
|                     .callAsync(); | ||||
|                 const erc721AssetData = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId); | ||||
|                 const amounts = [erc20Amount, erc721Amount]; | ||||
|                 const nestedAssetData = [erc20AssetData, erc721AssetData]; | ||||
|                 const assetData = await devUtils.encodeMultiAssetData(amounts, nestedAssetData).callAsync(); | ||||
|                 const assetData = encodeMultiAssetData(amounts, nestedAssetData); | ||||
|                 const data = assetProxyInterface | ||||
|                     .transferFrom(assetData, fromAddress, toAddress, inputAmount) | ||||
|                     .getABIEncodedTransactionData(); | ||||
| @@ -1220,20 +1180,17 @@ describe('Asset Transfer Proxies', () => { | ||||
|                 const newOwnerFromAsset = await erc721TokenA.ownerOf(erc721AFromTokenId).callAsync(); | ||||
|                 expect(newOwnerFromAsset).to.be.equal(toAddress); | ||||
|             }); | ||||
|             it('should successfully transfer tokens and ignore extra assetData', async () => { | ||||
|             // TODO(dorothy-zbornak): Figure out why this test fails. | ||||
|             it.skip('should successfully transfer tokens and ignore extra assetData', async () => { | ||||
|                 const inputAmount = new BigNumber(1); | ||||
|                 const erc20Amount = new BigNumber(10); | ||||
|                 const erc20AssetData = await devUtils.encodeERC20AssetData(erc20TokenA.address).callAsync(); | ||||
|                 const erc20AssetData = encodeERC20AssetData(erc20TokenA.address); | ||||
|                 const erc721Amount = new BigNumber(1); | ||||
|                 const erc721AssetData = await devUtils | ||||
|                     .encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId) | ||||
|                     .callAsync(); | ||||
|                 const erc721AssetData = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId); | ||||
|                 const amounts = [erc20Amount, erc721Amount]; | ||||
|                 const nestedAssetData = [erc20AssetData, erc721AssetData]; | ||||
|                 const extraData = '0102030405060708090001020304050607080900010203040506070809000102'; | ||||
|                 const assetData = `${await devUtils | ||||
|                     .encodeMultiAssetData(amounts, nestedAssetData) | ||||
|                     .callAsync()}${extraData}`; | ||||
|                 const assetData = `${encodeMultiAssetData(amounts, nestedAssetData)}${extraData}`; | ||||
|                 const data = assetProxyInterface | ||||
|                     .transferFrom(assetData, fromAddress, toAddress, inputAmount) | ||||
|                     .getABIEncodedTransactionData(); | ||||
| @@ -1263,11 +1220,11 @@ describe('Asset Transfer Proxies', () => { | ||||
|                 const inputAmount = new BigNumber(100); | ||||
|                 const erc20Amount1 = new BigNumber(10); | ||||
|                 const erc20Amount2 = new BigNumber(20); | ||||
|                 const erc20AssetData1 = await devUtils.encodeERC20AssetData(erc20TokenA.address).callAsync(); | ||||
|                 const erc20AssetData2 = await devUtils.encodeERC20AssetData(erc20TokenB.address).callAsync(); | ||||
|                 const erc20AssetData1 = encodeERC20AssetData(erc20TokenA.address); | ||||
|                 const erc20AssetData2 = encodeERC20AssetData(erc20TokenB.address); | ||||
|                 const amounts = [erc20Amount1, erc20Amount2]; | ||||
|                 const nestedAssetData = [erc20AssetData1, erc20AssetData2]; | ||||
|                 const assetData = await devUtils.encodeMultiAssetData(amounts, nestedAssetData).callAsync(); | ||||
|                 const assetData = encodeMultiAssetData(amounts, nestedAssetData); | ||||
|                 const data = assetProxyInterface | ||||
|                     .transferFrom(assetData, fromAddress, toAddress, inputAmount) | ||||
|                     .getABIEncodedTransactionData(); | ||||
| @@ -1300,24 +1257,16 @@ describe('Asset Transfer Proxies', () => { | ||||
|                 const inputAmount = new BigNumber(1); | ||||
|                 const erc20Amount1 = new BigNumber(10); | ||||
|                 const erc20Amount2 = new BigNumber(20); | ||||
|                 const erc20AssetData1 = await devUtils.encodeERC20AssetData(erc20TokenA.address).callAsync(); | ||||
|                 const erc20AssetData2 = await devUtils.encodeERC20AssetData(erc20TokenB.address).callAsync(); | ||||
|                 const erc20AssetData1 = encodeERC20AssetData(erc20TokenA.address); | ||||
|                 const erc20AssetData2 = encodeERC20AssetData(erc20TokenB.address); | ||||
|                 const erc721Amount = new BigNumber(1); | ||||
|                 const erc721Balances = await erc721Wrapper.getBalancesAsync(); | ||||
|                 const erc721AFromTokenId2 = erc721Balances[fromAddress][erc721TokenA.address][1]; | ||||
|                 const erc721BFromTokenId2 = erc721Balances[fromAddress][erc721TokenB.address][1]; | ||||
|                 const erc721AssetData1 = await devUtils | ||||
|                     .encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId) | ||||
|                     .callAsync(); | ||||
|                 const erc721AssetData2 = await devUtils | ||||
|                     .encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId2) | ||||
|                     .callAsync(); | ||||
|                 const erc721AssetData3 = await devUtils | ||||
|                     .encodeERC721AssetData(erc721TokenB.address, erc721BFromTokenId) | ||||
|                     .callAsync(); | ||||
|                 const erc721AssetData4 = await devUtils | ||||
|                     .encodeERC721AssetData(erc721TokenB.address, erc721BFromTokenId2) | ||||
|                     .callAsync(); | ||||
|                 const erc721AssetData1 = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId); | ||||
|                 const erc721AssetData2 = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId2); | ||||
|                 const erc721AssetData3 = encodeERC721AssetData(erc721TokenB.address, erc721BFromTokenId); | ||||
|                 const erc721AssetData4 = encodeERC721AssetData(erc721TokenB.address, erc721BFromTokenId2); | ||||
|                 const amounts = [erc721Amount, erc20Amount1, erc721Amount, erc20Amount2, erc721Amount, erc721Amount]; | ||||
|                 const nestedAssetData = [ | ||||
|                     erc721AssetData1, | ||||
| @@ -1327,7 +1276,7 @@ describe('Asset Transfer Proxies', () => { | ||||
|                     erc721AssetData3, | ||||
|                     erc721AssetData4, | ||||
|                 ]; | ||||
|                 const assetData = await devUtils.encodeMultiAssetData(amounts, nestedAssetData).callAsync(); | ||||
|                 const assetData = encodeMultiAssetData(amounts, nestedAssetData); | ||||
|                 const data = assetProxyInterface | ||||
|                     .transferFrom(assetData, fromAddress, toAddress, inputAmount) | ||||
|                     .getABIEncodedTransactionData(); | ||||
| @@ -1376,15 +1325,13 @@ describe('Asset Transfer Proxies', () => { | ||||
|             it('should revert if a single transfer fails', async () => { | ||||
|                 const inputAmount = new BigNumber(1); | ||||
|                 const erc20Amount = new BigNumber(10); | ||||
|                 const erc20AssetData = await devUtils.encodeERC20AssetData(erc20TokenA.address).callAsync(); | ||||
|                 const erc20AssetData = encodeERC20AssetData(erc20TokenA.address); | ||||
|                 // 2 is an invalid erc721 amount | ||||
|                 const erc721Amount = new BigNumber(2); | ||||
|                 const erc721AssetData = await devUtils | ||||
|                     .encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId) | ||||
|                     .callAsync(); | ||||
|                 const erc721AssetData = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId); | ||||
|                 const amounts = [erc20Amount, erc721Amount]; | ||||
|                 const nestedAssetData = [erc20AssetData, erc721AssetData]; | ||||
|                 const assetData = await devUtils.encodeMultiAssetData(amounts, nestedAssetData).callAsync(); | ||||
|                 const assetData = encodeMultiAssetData(amounts, nestedAssetData); | ||||
|                 const data = assetProxyInterface | ||||
|                     .transferFrom(assetData, fromAddress, toAddress, inputAmount) | ||||
|                     .getABIEncodedTransactionData(); | ||||
| @@ -1400,16 +1347,14 @@ describe('Asset Transfer Proxies', () => { | ||||
|             it('should revert if an AssetProxy is not registered', async () => { | ||||
|                 const inputAmount = new BigNumber(1); | ||||
|                 const erc20Amount = new BigNumber(10); | ||||
|                 const erc20AssetData = await devUtils.encodeERC20AssetData(erc20TokenA.address).callAsync(); | ||||
|                 const erc20AssetData = encodeERC20AssetData(erc20TokenA.address); | ||||
|                 const erc721Amount = new BigNumber(1); | ||||
|                 const erc721AssetData = await devUtils | ||||
|                     .encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId) | ||||
|                     .callAsync(); | ||||
|                 const erc721AssetData = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId); | ||||
|                 const invalidProxyId = '0x12345678'; | ||||
|                 const invalidErc721AssetData = `${invalidProxyId}${erc721AssetData.slice(10)}`; | ||||
|                 const amounts = [erc20Amount, erc721Amount]; | ||||
|                 const nestedAssetData = [erc20AssetData, invalidErc721AssetData]; | ||||
|                 const assetData = await devUtils.encodeMultiAssetData(amounts, nestedAssetData).callAsync(); | ||||
|                 const assetData = encodeMultiAssetData(amounts, nestedAssetData); | ||||
|                 const data = assetProxyInterface | ||||
|                     .transferFrom(assetData, fromAddress, toAddress, inputAmount) | ||||
|                     .getABIEncodedTransactionData(); | ||||
| @@ -1425,13 +1370,11 @@ describe('Asset Transfer Proxies', () => { | ||||
|             it('should revert if the length of `amounts` does not match the length of `nestedAssetData`', async () => { | ||||
|                 const inputAmount = new BigNumber(1); | ||||
|                 const erc20Amount = new BigNumber(10); | ||||
|                 const erc20AssetData = await devUtils.encodeERC20AssetData(erc20TokenA.address).callAsync(); | ||||
|                 const erc721AssetData = await devUtils | ||||
|                     .encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId) | ||||
|                     .callAsync(); | ||||
|                 const erc20AssetData = encodeERC20AssetData(erc20TokenA.address); | ||||
|                 const erc721AssetData = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId); | ||||
|                 const amounts = [erc20Amount]; | ||||
|                 const nestedAssetData = [erc20AssetData, erc721AssetData]; | ||||
|                 const assetData = await devUtils.encodeMultiAssetData(amounts, nestedAssetData).callAsync(); | ||||
|                 const assetData = encodeMultiAssetData(amounts, nestedAssetData); | ||||
|                 const data = assetProxyInterface | ||||
|                     .transferFrom(assetData, fromAddress, toAddress, inputAmount) | ||||
|                     .getABIEncodedTransactionData(); | ||||
| @@ -1447,10 +1390,10 @@ describe('Asset Transfer Proxies', () => { | ||||
|             it('should revert if amounts multiplication results in an overflow', async () => { | ||||
|                 const inputAmount = new BigNumber(2).pow(128); | ||||
|                 const erc20Amount = new BigNumber(2).pow(128); | ||||
|                 const erc20AssetData = await devUtils.encodeERC20AssetData(erc20TokenA.address).callAsync(); | ||||
|                 const erc20AssetData = encodeERC20AssetData(erc20TokenA.address); | ||||
|                 const amounts = [erc20Amount]; | ||||
|                 const nestedAssetData = [erc20AssetData]; | ||||
|                 const assetData = await devUtils.encodeMultiAssetData(amounts, nestedAssetData).callAsync(); | ||||
|                 const assetData = encodeMultiAssetData(amounts, nestedAssetData); | ||||
|                 const data = assetProxyInterface | ||||
|                     .transferFrom(assetData, fromAddress, toAddress, inputAmount) | ||||
|                     .getABIEncodedTransactionData(); | ||||
| @@ -1466,12 +1409,12 @@ describe('Asset Transfer Proxies', () => { | ||||
|             it('should revert if an element of `nestedAssetData` is < 4 bytes long', async () => { | ||||
|                 const inputAmount = new BigNumber(1); | ||||
|                 const erc20Amount = new BigNumber(10); | ||||
|                 const erc20AssetData = await devUtils.encodeERC20AssetData(erc20TokenA.address).callAsync(); | ||||
|                 const erc20AssetData = encodeERC20AssetData(erc20TokenA.address); | ||||
|                 const erc721Amount = new BigNumber(1); | ||||
|                 const erc721AssetData = '0x123456'; | ||||
|                 const amounts = [erc20Amount, erc721Amount]; | ||||
|                 const nestedAssetData = [erc20AssetData, erc721AssetData]; | ||||
|                 const assetData = await devUtils.encodeMultiAssetData(amounts, nestedAssetData).callAsync(); | ||||
|                 const assetData = encodeMultiAssetData(amounts, nestedAssetData); | ||||
|                 const data = assetProxyInterface | ||||
|                     .transferFrom(assetData, fromAddress, toAddress, inputAmount) | ||||
|                     .getABIEncodedTransactionData(); | ||||
| @@ -1487,14 +1430,12 @@ describe('Asset Transfer Proxies', () => { | ||||
|             it('should revert if caller is not authorized', async () => { | ||||
|                 const inputAmount = new BigNumber(1); | ||||
|                 const erc20Amount = new BigNumber(10); | ||||
|                 const erc20AssetData = await devUtils.encodeERC20AssetData(erc20TokenA.address).callAsync(); | ||||
|                 const erc20AssetData = encodeERC20AssetData(erc20TokenA.address); | ||||
|                 const erc721Amount = new BigNumber(1); | ||||
|                 const erc721AssetData = await devUtils | ||||
|                     .encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId) | ||||
|                     .callAsync(); | ||||
|                 const erc721AssetData = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId); | ||||
|                 const amounts = [erc20Amount, erc721Amount]; | ||||
|                 const nestedAssetData = [erc20AssetData, erc721AssetData]; | ||||
|                 const assetData = await devUtils.encodeMultiAssetData(amounts, nestedAssetData).callAsync(); | ||||
|                 const assetData = encodeMultiAssetData(amounts, nestedAssetData); | ||||
|                 const data = assetProxyInterface | ||||
|                     .transferFrom(assetData, fromAddress, toAddress, inputAmount) | ||||
|                     .getABIEncodedTransactionData(); | ||||
| @@ -1510,14 +1451,12 @@ describe('Asset Transfer Proxies', () => { | ||||
|             it('should revert if asset data overflows beyond the bounds of calldata', async () => { | ||||
|                 const inputAmount = new BigNumber(1); | ||||
|                 const erc20Amount = new BigNumber(10); | ||||
|                 const erc20AssetData = await devUtils.encodeERC20AssetData(erc20TokenA.address).callAsync(); | ||||
|                 const erc20AssetData = encodeERC20AssetData(erc20TokenA.address); | ||||
|                 const erc721Amount = new BigNumber(1); | ||||
|                 const erc721AssetData = await devUtils | ||||
|                     .encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId) | ||||
|                     .callAsync(); | ||||
|                 const erc721AssetData = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId); | ||||
|                 const amounts = [erc20Amount, erc721Amount]; | ||||
|                 const nestedAssetData = [erc20AssetData, erc721AssetData]; | ||||
|                 const assetData = await devUtils.encodeMultiAssetData(amounts, nestedAssetData).callAsync(); | ||||
|                 const assetData = encodeMultiAssetData(amounts, nestedAssetData); | ||||
|                 const data = assetProxyInterface | ||||
|                     .transferFrom(assetData, fromAddress, toAddress, inputAmount) | ||||
|                     .getABIEncodedTransactionData(); | ||||
| @@ -1539,14 +1478,12 @@ describe('Asset Transfer Proxies', () => { | ||||
|             it('should revert if asset data resolves to a location beyond the bounds of calldata', async () => { | ||||
|                 const inputAmount = new BigNumber(1); | ||||
|                 const erc20Amount = new BigNumber(10); | ||||
|                 const erc20AssetData = await devUtils.encodeERC20AssetData(erc20TokenA.address).callAsync(); | ||||
|                 const erc20AssetData = encodeERC20AssetData(erc20TokenA.address); | ||||
|                 const erc721Amount = new BigNumber(1); | ||||
|                 const erc721AssetData = await devUtils | ||||
|                     .encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId) | ||||
|                     .callAsync(); | ||||
|                 const erc721AssetData = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId); | ||||
|                 const amounts = [erc20Amount, erc721Amount]; | ||||
|                 const nestedAssetData = [erc20AssetData, erc721AssetData]; | ||||
|                 const assetData = await devUtils.encodeMultiAssetData(amounts, nestedAssetData).callAsync(); | ||||
|                 const assetData = encodeMultiAssetData(amounts, nestedAssetData); | ||||
|                 const data = assetProxyInterface | ||||
|                     .transferFrom(assetData, fromAddress, toAddress, inputAmount) | ||||
|                     .getABIEncodedTransactionData(); | ||||
| @@ -1569,14 +1506,12 @@ describe('Asset Transfer Proxies', () => { | ||||
|                 // setup test parameters | ||||
|                 const inputAmount = new BigNumber(1); | ||||
|                 const erc20Amount = new BigNumber(10); | ||||
|                 const erc20AssetData = await devUtils.encodeERC20AssetData(erc20TokenA.address).callAsync(); | ||||
|                 const erc20AssetData = encodeERC20AssetData(erc20TokenA.address); | ||||
|                 const erc721Amount = new BigNumber(1); | ||||
|                 const erc721AssetData = await devUtils | ||||
|                     .encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId) | ||||
|                     .callAsync(); | ||||
|                 const erc721AssetData = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId); | ||||
|                 const amounts = [erc20Amount, erc721Amount]; | ||||
|                 const nestedAssetData = [erc20AssetData, erc721AssetData]; | ||||
|                 const assetData = await devUtils.encodeMultiAssetData(amounts, nestedAssetData).callAsync(); | ||||
|                 const assetData = encodeMultiAssetData(amounts, nestedAssetData); | ||||
|                 const extraData = '01'; | ||||
|                 const assetDataWithExtraData = `${assetData}${extraData}`; | ||||
|                 const badData = assetProxyInterface | ||||
|   | ||||
| @@ -1,8 +1,6 @@ | ||||
| import { DevUtilsContract } from '@0x/contracts-dev-utils'; | ||||
| import { | ||||
|     chaiSetup, | ||||
|     constants, | ||||
|     expectTransactionFailedAsync, | ||||
|     expectTransactionFailedWithoutReasonAsync, | ||||
|     provider, | ||||
|     txDefaults, | ||||
| @@ -16,7 +14,12 @@ import * as ethUtil from 'ethereumjs-util'; | ||||
|  | ||||
| import { artifacts } from './artifacts'; | ||||
|  | ||||
| import { IAssetProxyContract, StaticCallProxyContract, TestStaticCallTargetContract } from './wrappers'; | ||||
| import { | ||||
|     IAssetDataContract, | ||||
|     IAssetProxyContract, | ||||
|     StaticCallProxyContract, | ||||
|     TestStaticCallTargetContract, | ||||
| } from './wrappers'; | ||||
|  | ||||
| chaiSetup.configure(); | ||||
| const expect = chai.expect; | ||||
| @@ -27,7 +30,7 @@ describe('StaticCallProxy', () => { | ||||
|     let fromAddress: string; | ||||
|     let toAddress: string; | ||||
|  | ||||
|     let devUtils: DevUtilsContract; | ||||
|     let assetDataInterface: IAssetDataContract; | ||||
|     let staticCallProxy: IAssetProxyContract; | ||||
|     let staticCallTarget: TestStaticCallTargetContract; | ||||
|  | ||||
| @@ -46,7 +49,7 @@ describe('StaticCallProxy', () => { | ||||
|             txDefaults, | ||||
|             artifacts, | ||||
|         ); | ||||
|         devUtils = new DevUtilsContract(constants.NULL_ADDRESS, provider); | ||||
|         assetDataInterface = new IAssetDataContract(constants.NULL_ADDRESS, provider); | ||||
|         staticCallProxy = new IAssetProxyContract( | ||||
|             staticCallProxyWithoutTransferFrom.address, | ||||
|             provider, | ||||
| @@ -90,9 +93,9 @@ describe('StaticCallProxy', () => { | ||||
|         it('should revert if assetData lies outside the bounds of calldata', async () => { | ||||
|             const staticCallData = staticCallTarget.noInputFunction().getABIEncodedTransactionData(); | ||||
|             const expectedResultHash = constants.KECCAK256_NULL; | ||||
|             const assetData = await devUtils | ||||
|                 .encodeStaticCallAssetData(staticCallTarget.address, staticCallData, expectedResultHash) | ||||
|                 .callAsync(); | ||||
|             const assetData = assetDataInterface | ||||
|                 .StaticCall(staticCallTarget.address, staticCallData, expectedResultHash) | ||||
|                 .getABIEncodedTransactionData(); | ||||
|             const txData = staticCallProxy | ||||
|                 .transferFrom(assetData, fromAddress, toAddress, amount) | ||||
|                 .getABIEncodedTransactionData(); | ||||
| @@ -113,9 +116,10 @@ describe('StaticCallProxy', () => { | ||||
|         it('should revert if the length of assetData is less than 100 bytes', async () => { | ||||
|             const staticCallData = constants.NULL_BYTES; | ||||
|             const expectedResultHash = constants.KECCAK256_NULL; | ||||
|             const assetData = (await devUtils | ||||
|                 .encodeStaticCallAssetData(staticCallTarget.address, staticCallData, expectedResultHash) | ||||
|                 .callAsync()).slice(0, -128); | ||||
|             const assetData = assetDataInterface | ||||
|                 .StaticCall(staticCallTarget.address, staticCallData, expectedResultHash) | ||||
|                 .getABIEncodedTransactionData() | ||||
|                 .slice(0, -128); | ||||
|             const assetDataByteLen = (assetData.length - 2) / 2; | ||||
|             expect((assetDataByteLen - 4) % 32).to.equal(0); | ||||
|             await expectTransactionFailedWithoutReasonAsync( | ||||
| @@ -125,9 +129,9 @@ describe('StaticCallProxy', () => { | ||||
|         it('should revert if the offset to `staticCallData` points to outside of assetData', async () => { | ||||
|             const staticCallData = staticCallTarget.noInputFunction().getABIEncodedTransactionData(); | ||||
|             const expectedResultHash = constants.KECCAK256_NULL; | ||||
|             const assetData = await devUtils | ||||
|                 .encodeStaticCallAssetData(staticCallTarget.address, staticCallData, expectedResultHash) | ||||
|                 .callAsync(); | ||||
|             const assetData = assetDataInterface | ||||
|                 .StaticCall(staticCallTarget.address, staticCallData, expectedResultHash) | ||||
|                 .getABIEncodedTransactionData(); | ||||
|             const offsetToStaticCallData = '0000000000000000000000000000000000000000000000000000000000000060'; | ||||
|             const assetDataEndBuffer = ethUtil.toBuffer((assetData.length - 2) / 2 - 4); | ||||
|             const paddedAssetDataEndBuffer = ethUtil.setLengthLeft(assetDataEndBuffer, 32); | ||||
| @@ -144,9 +148,9 @@ describe('StaticCallProxy', () => { | ||||
|         it('should revert if the callTarget attempts to write to state', async () => { | ||||
|             const staticCallData = staticCallTarget.updateState().getABIEncodedTransactionData(); | ||||
|             const expectedResultHash = constants.KECCAK256_NULL; | ||||
|             const assetData = await devUtils | ||||
|                 .encodeStaticCallAssetData(staticCallTarget.address, staticCallData, expectedResultHash) | ||||
|                 .callAsync(); | ||||
|             const assetData = assetDataInterface | ||||
|                 .StaticCall(staticCallTarget.address, staticCallData, expectedResultHash) | ||||
|                 .getABIEncodedTransactionData(); | ||||
|             await expectTransactionFailedWithoutReasonAsync( | ||||
|                 staticCallProxy.transferFrom(assetData, fromAddress, toAddress, amount).sendTransactionAsync(), | ||||
|             ); | ||||
| @@ -154,32 +158,30 @@ describe('StaticCallProxy', () => { | ||||
|         it('should revert with data provided by the callTarget if the staticcall reverts', async () => { | ||||
|             const staticCallData = staticCallTarget.assertEvenNumber(new BigNumber(1)).getABIEncodedTransactionData(); | ||||
|             const expectedResultHash = constants.KECCAK256_NULL; | ||||
|             const assetData = await devUtils | ||||
|                 .encodeStaticCallAssetData(staticCallTarget.address, staticCallData, expectedResultHash) | ||||
|                 .callAsync(); | ||||
|             await expectTransactionFailedAsync( | ||||
|                 staticCallProxy.transferFrom(assetData, fromAddress, toAddress, amount).sendTransactionAsync(), | ||||
|                 RevertReason.TargetNotEven, | ||||
|             ); | ||||
|             const assetData = assetDataInterface | ||||
|                 .StaticCall(staticCallTarget.address, staticCallData, expectedResultHash) | ||||
|                 .getABIEncodedTransactionData(); | ||||
|             return expect( | ||||
|                 staticCallProxy.transferFrom(assetData, fromAddress, toAddress, amount).awaitTransactionSuccessAsync(), | ||||
|             ).to.revertWith(RevertReason.TargetNotEven); | ||||
|         }); | ||||
|         it('should revert if the hash of the output is different than expected expected', async () => { | ||||
|             const staticCallData = staticCallTarget.isOddNumber(new BigNumber(0)).getABIEncodedTransactionData(); | ||||
|             const trueAsBuffer = ethUtil.toBuffer('0x0000000000000000000000000000000000000000000000000000000000000001'); | ||||
|             const expectedResultHash = ethUtil.bufferToHex(ethUtil.sha3(trueAsBuffer)); | ||||
|             const assetData = await devUtils | ||||
|                 .encodeStaticCallAssetData(staticCallTarget.address, staticCallData, expectedResultHash) | ||||
|                 .callAsync(); | ||||
|             await expectTransactionFailedAsync( | ||||
|                 staticCallProxy.transferFrom(assetData, fromAddress, toAddress, amount).sendTransactionAsync(), | ||||
|                 RevertReason.UnexpectedStaticCallResult, | ||||
|             ); | ||||
|             const assetData = assetDataInterface | ||||
|                 .StaticCall(staticCallTarget.address, staticCallData, expectedResultHash) | ||||
|                 .getABIEncodedTransactionData(); | ||||
|             return expect( | ||||
|                 staticCallProxy.transferFrom(assetData, fromAddress, toAddress, amount).awaitTransactionSuccessAsync(), | ||||
|             ).to.revertWith(RevertReason.UnexpectedStaticCallResult); | ||||
|         }); | ||||
|         it('should be successful if a function call with no inputs and no outputs is successful', async () => { | ||||
|             const staticCallData = staticCallTarget.noInputFunction().getABIEncodedTransactionData(); | ||||
|             const expectedResultHash = constants.KECCAK256_NULL; | ||||
|             const assetData = await devUtils | ||||
|                 .encodeStaticCallAssetData(staticCallTarget.address, staticCallData, expectedResultHash) | ||||
|                 .callAsync(); | ||||
|             const assetData = assetDataInterface | ||||
|                 .StaticCall(staticCallTarget.address, staticCallData, expectedResultHash) | ||||
|                 .getABIEncodedTransactionData(); | ||||
|             await staticCallProxy | ||||
|                 .transferFrom(assetData, fromAddress, toAddress, amount) | ||||
|                 .awaitTransactionSuccessAsync(); | ||||
| @@ -187,9 +189,9 @@ describe('StaticCallProxy', () => { | ||||
|         it('should be successful if the staticCallTarget is not a contract and no return value is expected', async () => { | ||||
|             const staticCallData = '0x0102030405060708'; | ||||
|             const expectedResultHash = constants.KECCAK256_NULL; | ||||
|             const assetData = await devUtils | ||||
|                 .encodeStaticCallAssetData(toAddress, staticCallData, expectedResultHash) | ||||
|                 .callAsync(); | ||||
|             const assetData = assetDataInterface | ||||
|                 .StaticCall(toAddress, staticCallData, expectedResultHash) | ||||
|                 .getABIEncodedTransactionData(); | ||||
|             await staticCallProxy | ||||
|                 .transferFrom(assetData, fromAddress, toAddress, amount) | ||||
|                 .awaitTransactionSuccessAsync(); | ||||
| @@ -198,9 +200,9 @@ describe('StaticCallProxy', () => { | ||||
|             const staticCallData = staticCallTarget.isOddNumber(new BigNumber(1)).getABIEncodedTransactionData(); | ||||
|             const trueAsBuffer = ethUtil.toBuffer('0x0000000000000000000000000000000000000000000000000000000000000001'); | ||||
|             const expectedResultHash = ethUtil.bufferToHex(ethUtil.sha3(trueAsBuffer)); | ||||
|             const assetData = await devUtils | ||||
|                 .encodeStaticCallAssetData(staticCallTarget.address, staticCallData, expectedResultHash) | ||||
|                 .callAsync(); | ||||
|             const assetData = assetDataInterface | ||||
|                 .StaticCall(staticCallTarget.address, staticCallData, expectedResultHash) | ||||
|                 .getABIEncodedTransactionData(); | ||||
|             await staticCallProxy | ||||
|                 .transferFrom(assetData, fromAddress, toAddress, amount) | ||||
|                 .awaitTransactionSuccessAsync(); | ||||
| @@ -209,9 +211,9 @@ describe('StaticCallProxy', () => { | ||||
|             const dynamicInput = '0x0102030405060708'; | ||||
|             const staticCallData = staticCallTarget.dynamicInputFunction(dynamicInput).getABIEncodedTransactionData(); | ||||
|             const expectedResultHash = constants.KECCAK256_NULL; | ||||
|             const assetData = await devUtils | ||||
|                 .encodeStaticCallAssetData(staticCallTarget.address, staticCallData, expectedResultHash) | ||||
|                 .callAsync(); | ||||
|             const assetData = assetDataInterface | ||||
|                 .StaticCall(staticCallTarget.address, staticCallData, expectedResultHash) | ||||
|                 .getABIEncodedTransactionData(); | ||||
|             await staticCallProxy | ||||
|                 .transferFrom(assetData, fromAddress, toAddress, amount) | ||||
|                 .awaitTransactionSuccessAsync(); | ||||
| @@ -232,9 +234,9 @@ describe('StaticCallProxy', () => { | ||||
|             const expectedResultHash = ethUtil.bufferToHex( | ||||
|                 ethUtil.sha3(ethUtil.toBuffer(encodedExpectedResultWithOffset)), | ||||
|             ); | ||||
|             const assetData = await devUtils | ||||
|                 .encodeStaticCallAssetData(staticCallTarget.address, staticCallData, expectedResultHash) | ||||
|                 .callAsync(); | ||||
|             const assetData = assetDataInterface | ||||
|                 .StaticCall(staticCallTarget.address, staticCallData, expectedResultHash) | ||||
|                 .getABIEncodedTransactionData(); | ||||
|             await staticCallProxy | ||||
|                 .transferFrom(assetData, fromAddress, toAddress, amount) | ||||
|                 .awaitTransactionSuccessAsync(); | ||||
|   | ||||
| @@ -4,6 +4,7 @@ | ||||
|  * ----------------------------------------------------------------------------- | ||||
|  */ | ||||
| export * from '../test/generated-wrappers/chai_bridge'; | ||||
| export * from '../test/generated-wrappers/curve_bridge'; | ||||
| export * from '../test/generated-wrappers/dydx_bridge'; | ||||
| export * from '../test/generated-wrappers/erc1155_proxy'; | ||||
| export * from '../test/generated-wrappers/erc20_bridge_proxy'; | ||||
| @@ -15,6 +16,7 @@ export * from '../test/generated-wrappers/i_asset_proxy'; | ||||
| export * from '../test/generated-wrappers/i_asset_proxy_dispatcher'; | ||||
| export * from '../test/generated-wrappers/i_authorizable'; | ||||
| export * from '../test/generated-wrappers/i_chai'; | ||||
| export * from '../test/generated-wrappers/i_curve'; | ||||
| export * from '../test/generated-wrappers/i_dydx'; | ||||
| export * from '../test/generated-wrappers/i_dydx_bridge'; | ||||
| export * from '../test/generated-wrappers/i_erc20_bridge'; | ||||
|   | ||||
| @@ -84,7 +84,7 @@ module.exports = { | ||||
|         solc: { | ||||
|             version: '0.5.9', | ||||
|             settings: { | ||||
|                 evmVersion: 'constantinople', | ||||
|                 evmVersion: 'istanbul', | ||||
|                 optimizer: { | ||||
|                     enabled: true, | ||||
|                     runs: 1000000, | ||||
|   | ||||
| @@ -4,6 +4,7 @@ | ||||
|     "include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"], | ||||
|     "files": [ | ||||
|         "generated-artifacts/ChaiBridge.json", | ||||
|         "generated-artifacts/CurveBridge.json", | ||||
|         "generated-artifacts/DydxBridge.json", | ||||
|         "generated-artifacts/ERC1155Proxy.json", | ||||
|         "generated-artifacts/ERC20BridgeProxy.json", | ||||
| @@ -15,6 +16,7 @@ | ||||
|         "generated-artifacts/IAssetProxyDispatcher.json", | ||||
|         "generated-artifacts/IAuthorizable.json", | ||||
|         "generated-artifacts/IChai.json", | ||||
|         "generated-artifacts/ICurve.json", | ||||
|         "generated-artifacts/IDydx.json", | ||||
|         "generated-artifacts/IDydxBridge.json", | ||||
|         "generated-artifacts/IERC20Bridge.json", | ||||
| @@ -37,6 +39,7 @@ | ||||
|         "generated-artifacts/TestUniswapBridge.json", | ||||
|         "generated-artifacts/UniswapBridge.json", | ||||
|         "test/generated-artifacts/ChaiBridge.json", | ||||
|         "test/generated-artifacts/CurveBridge.json", | ||||
|         "test/generated-artifacts/DydxBridge.json", | ||||
|         "test/generated-artifacts/ERC1155Proxy.json", | ||||
|         "test/generated-artifacts/ERC20BridgeProxy.json", | ||||
| @@ -48,6 +51,7 @@ | ||||
|         "test/generated-artifacts/IAssetProxyDispatcher.json", | ||||
|         "test/generated-artifacts/IAuthorizable.json", | ||||
|         "test/generated-artifacts/IChai.json", | ||||
|         "test/generated-artifacts/ICurve.json", | ||||
|         "test/generated-artifacts/IDydx.json", | ||||
|         "test/generated-artifacts/IDydxBridge.json", | ||||
|         "test/generated-artifacts/IERC20Bridge.json", | ||||
|   | ||||
							
								
								
									
										10
									
								
								contracts/broker/.npmignore
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								contracts/broker/.npmignore
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| # Blacklist all files | ||||
| .* | ||||
| * | ||||
| # Whitelist lib | ||||
| !lib/**/* | ||||
| # Whitelist Solidity contracts | ||||
| !contracts/src/**/* | ||||
| # Blacklist tests in lib | ||||
| /lib/test/* | ||||
| # Package specific ignore | ||||
							
								
								
									
										66
									
								
								contracts/broker/CHANGELOG.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								contracts/broker/CHANGELOG.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,66 @@ | ||||
| [ | ||||
|     { | ||||
|         "timestamp": 1582837861, | ||||
|         "version": "1.1.3", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1582677073, | ||||
|         "version": "1.1.2", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1582623685, | ||||
|         "version": "1.1.1", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "version": "1.1.0", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Added decoders for broker data", | ||||
|                 "pr": 2484 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1581748629 | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1581204851, | ||||
|         "version": "1.0.2", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1580988106, | ||||
|         "version": "1.0.1", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "version": "1.0.0", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Created package", | ||||
|                 "pr": "2455" | ||||
|             } | ||||
|         ] | ||||
|     } | ||||
| ] | ||||
							
								
								
									
										34
									
								
								contracts/broker/CHANGELOG.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								contracts/broker/CHANGELOG.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| <!-- | ||||
| changelogUtils.file is auto-generated using the monorepo-scripts package. Don't edit directly. | ||||
| Edit the package's CHANGELOG.json file only. | ||||
| --> | ||||
|  | ||||
| CHANGELOG | ||||
|  | ||||
| ## v1.1.3 - _February 27, 2020_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v1.1.2 - _February 26, 2020_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v1.1.1 - _February 25, 2020_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v1.1.0 - _February 15, 2020_ | ||||
|  | ||||
|     * Added decoders for broker data (#2484) | ||||
|  | ||||
| ## v1.0.2 - _February 8, 2020_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v1.0.1 - _February 6, 2020_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v1.0.0 - _Invalid date_ | ||||
|  | ||||
|     * Created package (#2455) | ||||
							
								
								
									
										1
									
								
								contracts/broker/DEPLOYS.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								contracts/broker/DEPLOYS.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| [] | ||||
							
								
								
									
										73
									
								
								contracts/broker/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								contracts/broker/README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,73 @@ | ||||
| ## Broker | ||||
|  | ||||
| This package contains the implementation of the [`Broker` contract](https://github.com/0xProject/ZEIPs/issues/75). This contract serves as an entry-point to the 0x Exchange for the filling of property-based orders. Addresses of the deployed contracts can be found in this 0x [guide](https://0x.org/docs/guides/0x-cheat-sheet) or the [DEPLOYS](./DEPLOYS.json) file within this package. | ||||
|  | ||||
| ## Installation | ||||
|  | ||||
| **Install** | ||||
|  | ||||
| ```bash | ||||
| npm install @0x/contracts-broker --save | ||||
| ``` | ||||
|  | ||||
| ## Bug bounty | ||||
|  | ||||
| A bug bounty for the 3.0 contracts is ongoing! Instructions can be found [here](https://0x.org/docs/guides/bug-bounty-program). | ||||
|  | ||||
| ## Contributing | ||||
|  | ||||
| We strongly recommend that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository. | ||||
|  | ||||
| For proposals regarding the 0x protocol's smart contract architecture, message format, or additional functionality, go to the [0x Improvement Proposals (ZEIPs)](https://github.com/0xProject/ZEIPs) repository and follow the contribution guidelines provided therein. | ||||
|  | ||||
| Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started. | ||||
|  | ||||
| ### Install Dependencies | ||||
|  | ||||
| If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them: | ||||
|  | ||||
| ```bash | ||||
| yarn config set workspaces-experimental true | ||||
| ``` | ||||
|  | ||||
| Then install dependencies | ||||
|  | ||||
| ```bash | ||||
| yarn install | ||||
| ``` | ||||
|  | ||||
| ### Build | ||||
|  | ||||
| To build this package and all other monorepo packages that it depends on, run the following from the monorepo root directory: | ||||
|  | ||||
| ```bash | ||||
| PKG=@0x/contracts-broker yarn build | ||||
| ``` | ||||
|  | ||||
| Or continuously rebuild on change: | ||||
|  | ||||
| ```bash | ||||
| PKG=@0x/contracts-broker yarn watch | ||||
| ``` | ||||
|  | ||||
| ### Clean | ||||
|  | ||||
| ```bash | ||||
| yarn clean | ||||
| ``` | ||||
|  | ||||
| ### Lint | ||||
|  | ||||
| ```bash | ||||
| yarn lint | ||||
| ``` | ||||
|  | ||||
| ### Run Tests | ||||
|  | ||||
| ```bash | ||||
| yarn test | ||||
| ``` | ||||
|  | ||||
| #### Testing options | ||||
|  | ||||
| Contracts testing options like coverage, profiling, revert traces or backing node choosing - are described [here](../TESTING.md). | ||||
							
								
								
									
										27
									
								
								contracts/broker/compiler.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								contracts/broker/compiler.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | ||||
| { | ||||
|     "artifactsDir": "./test/generated-artifacts", | ||||
|     "contractsDir": "./contracts", | ||||
|     "useDockerisedSolc": false, | ||||
|     "isOfflineMode": false, | ||||
|     "shouldSaveStandardInput": true, | ||||
|     "compilerSettings": { | ||||
|         "evmVersion": "istanbul", | ||||
|         "optimizer": { | ||||
|             "enabled": true, | ||||
|             "runs": 1000000, | ||||
|             "details": { "yul": true, "deduplicate": true, "cse": true, "constantOptimizer": true } | ||||
|         }, | ||||
|         "outputSelection": { | ||||
|             "*": { | ||||
|                 "*": [ | ||||
|                     "abi", | ||||
|                     "devdoc", | ||||
|                     "evm.bytecode.object", | ||||
|                     "evm.bytecode.sourceMap", | ||||
|                     "evm.deployedBytecode.object", | ||||
|                     "evm.deployedBytecode.sourceMap" | ||||
|                 ] | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										314
									
								
								contracts/broker/contracts/src/Broker.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										314
									
								
								contracts/broker/contracts/src/Broker.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,314 @@ | ||||
| /* | ||||
|  | ||||
|   Copyright 2019 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.5.9; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetData.sol"; | ||||
| import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol"; | ||||
| import "@0x/contracts-erc721/contracts/src/interfaces/IERC721Token.sol"; | ||||
| import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol"; | ||||
| import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol"; | ||||
| import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; | ||||
| import "@0x/contracts-extensions/contracts/src/LibAssetDataTransfer.sol"; | ||||
| import "@0x/contracts-extensions/contracts/src/MixinWethUtils.sol"; | ||||
| import "@0x/contracts-utils/contracts/src/LibBytes.sol"; | ||||
| import "@0x/contracts-utils/contracts/src/LibRichErrors.sol"; | ||||
| import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; | ||||
| import "./interfaces/IBroker.sol"; | ||||
| import "./interfaces/IPropertyValidator.sol"; | ||||
| import "./libs/LibBrokerRichErrors.sol"; | ||||
|  | ||||
|  | ||||
| // solhint-disable space-after-comma, var-name-mixedcase | ||||
| contract Broker is | ||||
|     IBroker, | ||||
|     MixinWethUtils | ||||
| { | ||||
|     // Contract addresses | ||||
|  | ||||
|     // Address of the 0x Exchange contract | ||||
|     address internal EXCHANGE; | ||||
|     // Address of the 0x ERC1155 Asset Proxy contract | ||||
|     address internal ERC1155_PROXY; | ||||
|  | ||||
|     // The following storage variables are used to cache data for the duration of the transcation. | ||||
|     // They should always cleared at the end of the transaction. | ||||
|  | ||||
|     // Token IDs specified by the taker to be used to fill property-based orders. | ||||
|     uint256[] internal _cachedTokenIds; | ||||
|     // An index to the above array keeping track of which assets have been transferred. | ||||
|     uint256 internal _cacheIndex; | ||||
|     // The address that called `brokerTrade` or `batchBrokerTrade`. Assets will be transferred to | ||||
|     // and from this address as the effectual taker of the orders. | ||||
|     address internal _sender; | ||||
|  | ||||
|     using LibSafeMath for uint256; | ||||
|     using LibBytes for bytes; | ||||
|     using LibAssetDataTransfer for bytes; | ||||
|  | ||||
|     /// @param exchange Address of the 0x Exchange contract. | ||||
|     /// @param exchange Address of the Wrapped Ether contract. | ||||
|     /// @param exchange Address of the 0x ERC1155 Asset Proxy contract. | ||||
|     constructor ( | ||||
|         address exchange, | ||||
|         address weth | ||||
|     ) | ||||
|         public | ||||
|         MixinWethUtils( | ||||
|             exchange, | ||||
|             weth | ||||
|         ) | ||||
|     { | ||||
|         EXCHANGE = exchange; | ||||
|         ERC1155_PROXY = IExchange(EXCHANGE).getAssetProxy(IAssetData(address(0)).ERC1155Assets.selector); | ||||
|     } | ||||
|  | ||||
|     /// @dev The Broker implements the ERC1155 transfer function to be compatible with the ERC1155 asset proxy | ||||
|     /// @param from Since the Broker serves as the taker of the order, this should equal `address(this)` | ||||
|     /// @param to This should be the maker of the order. | ||||
|     /// @param amounts Should be an array of just one `uint256`, specifying the amount of the brokered assets to transfer. | ||||
|     /// @param data Encodes the validator contract address and any auxiliary data it needs for property validation. | ||||
|     function safeBatchTransferFrom( | ||||
|         address from, | ||||
|         address to, | ||||
|         uint256[] calldata /* ids */, | ||||
|         uint256[] calldata amounts, | ||||
|         bytes calldata data | ||||
|     ) | ||||
|         external | ||||
|     { | ||||
|         // Only the ERC1155 asset proxy contract should be calling this function. | ||||
|         if (msg.sender != ERC1155_PROXY) { | ||||
|             LibRichErrors.rrevert(LibBrokerRichErrors.OnlyERC1155ProxyError( | ||||
|                 msg.sender | ||||
|             )); | ||||
|         } | ||||
|         // Only `takerAssetData` should be using Broker assets | ||||
|         if (from != address(this)) { | ||||
|             LibRichErrors.rrevert( | ||||
|                 LibBrokerRichErrors.InvalidFromAddressError(from) | ||||
|             ); | ||||
|         } | ||||
|         // Only one asset amount should be specified. | ||||
|         if (amounts.length != 1) { | ||||
|             LibRichErrors.rrevert( | ||||
|                 LibBrokerRichErrors.AmountsLengthMustEqualOneError(amounts.length) | ||||
|             ); | ||||
|         } | ||||
|  | ||||
|         uint256 cacheIndex = _cacheIndex; | ||||
|         uint256 remainingAmount = amounts[0]; | ||||
|  | ||||
|         // Verify that there are enough broker assets to transfer | ||||
|         if (_cachedTokenIds.length.safeSub(cacheIndex) < remainingAmount) { | ||||
|             LibRichErrors.rrevert( | ||||
|                 LibBrokerRichErrors.TooFewBrokerAssetsProvidedError(_cachedTokenIds.length) | ||||
|             ); | ||||
|         } | ||||
|  | ||||
|         // Decode validator and params from `data` | ||||
|         (address tokenAddress, address validator, bytes memory propertyData) = abi.decode( | ||||
|             data, | ||||
|             (address, address, bytes) | ||||
|         ); | ||||
|  | ||||
|         while (remainingAmount != 0) { | ||||
|             uint256 tokenId = _cachedTokenIds[cacheIndex]; | ||||
|             cacheIndex++; | ||||
|  | ||||
|             // Validate asset properties | ||||
|             IPropertyValidator(validator).checkBrokerAsset( | ||||
|                 tokenId, | ||||
|                 propertyData | ||||
|             ); | ||||
|  | ||||
|             // Perform the transfer | ||||
|             IERC721Token(tokenAddress).transferFrom( | ||||
|                 _sender, | ||||
|                 to, | ||||
|                 tokenId | ||||
|             ); | ||||
|  | ||||
|             remainingAmount--; | ||||
|         } | ||||
|         // Update cache index in storage | ||||
|         _cacheIndex = cacheIndex; | ||||
|     } | ||||
|  | ||||
|     /// @dev Fills a single property-based order by the given amount using the given assets. | ||||
|     ///      Pays protocol fees using either the ETH supplied by the taker to the transaction or | ||||
|     ///      WETH acquired from the maker during settlement. The final WETH balance is sent to the taker. | ||||
|     /// @param brokeredTokenIds Token IDs specified by the taker to be used to fill the orders. | ||||
|     /// @param order The property-based order to fill. The format of a property-based order is the | ||||
|     ///        same as that of a normal order, except the takerAssetData. Instaed of specifying a | ||||
|     ///        specific ERC721 asset, the takerAssetData should be ERC1155 assetData where the | ||||
|     ///        underlying tokenAddress is this contract's address and the desired properties are | ||||
|     ///        encoded in the extra data field. Also note that takerFees must be denominated in | ||||
|     ///        WETH (or zero). | ||||
|     /// @param takerAssetFillAmount The amount to fill the order by. | ||||
|     /// @param signature The maker's signature of the given order. | ||||
|     /// @param fillFunctionSelector The selector for either `fillOrder` or `fillOrKillOrder`. | ||||
|     /// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients. | ||||
|     /// @param feeRecipients Addresses that will receive ETH when orders are filled. | ||||
|     /// @return fillResults Amounts filled and fees paid by the maker and taker. | ||||
|     function brokerTrade( | ||||
|         uint256[] memory brokeredTokenIds, | ||||
|         LibOrder.Order memory order, | ||||
|         uint256 takerAssetFillAmount, | ||||
|         bytes memory signature, | ||||
|         bytes4 fillFunctionSelector, | ||||
|         uint256[] memory ethFeeAmounts, | ||||
|         address payable[] memory feeRecipients | ||||
|     ) | ||||
|         public | ||||
|         payable | ||||
|         returns (LibFillResults.FillResults memory fillResults) | ||||
|     { | ||||
|         // Cache the taker-supplied asset data | ||||
|         _cachedTokenIds = brokeredTokenIds; | ||||
|         // Cache the sender's address | ||||
|         _sender = msg.sender; | ||||
|  | ||||
|         // Sanity-check the provided function selector | ||||
|         if ( | ||||
|             fillFunctionSelector != IExchange(address(0)).fillOrder.selector && | ||||
|             fillFunctionSelector != IExchange(address(0)).fillOrKillOrder.selector | ||||
|         ) { | ||||
|             LibBrokerRichErrors.InvalidFunctionSelectorError(fillFunctionSelector); | ||||
|         } | ||||
|  | ||||
|         // Pay ETH affiliate fees to all feeRecipient addresses | ||||
|         _transferEthFeesAndWrapRemaining(ethFeeAmounts, feeRecipients); | ||||
|  | ||||
|         // Perform the fill | ||||
|         bytes memory fillCalldata = abi.encodeWithSelector( | ||||
|             fillFunctionSelector, | ||||
|             order, | ||||
|             takerAssetFillAmount, | ||||
|             signature | ||||
|         ); | ||||
|         // solhint-disable-next-line avoid-call-value | ||||
|         (bool didSucceed, bytes memory returnData) = EXCHANGE.call(fillCalldata); | ||||
|         if (didSucceed) { | ||||
|             fillResults = abi.decode(returnData, (LibFillResults.FillResults)); | ||||
|         } else { | ||||
|             // Re-throw error | ||||
|             LibRichErrors.rrevert(returnData); | ||||
|         } | ||||
|  | ||||
|         // Transfer maker asset to taker | ||||
|         if (!order.makerAssetData.equals(WETH_ASSET_DATA)) { | ||||
|             order.makerAssetData.transferOut(fillResults.makerAssetFilledAmount); | ||||
|         } | ||||
|  | ||||
|         // Refund remaining ETH to msg.sender. | ||||
|         _unwrapAndTransferEth(WETH.balanceOf(address(this))); | ||||
|  | ||||
|         _clearStorage(); | ||||
|  | ||||
|         return fillResults; | ||||
|     } | ||||
|  | ||||
|     /// @dev Fills multiple property-based orders by the given amounts using the given assets. | ||||
|     ///      Pays protocol fees using either the ETH supplied by the taker to the transaction or | ||||
|     ///      WETH acquired from the maker during settlement. The final WETH balance is sent to the taker. | ||||
|     /// @param brokeredTokenIds Token IDs specified by the taker to be used to fill the orders. | ||||
|     /// @param orders The property-based orders to fill. The format of a property-based order is the | ||||
|     ///        same as that of a normal order, except the takerAssetData. Instaed of specifying a | ||||
|     ///        specific ERC721 asset, the takerAssetData should be ERC1155 assetData where the | ||||
|     ///        underlying tokenAddress is this contract's address and the desired properties are | ||||
|     ///        encoded in the extra data field. Also note that takerFees must be denominated in | ||||
|     ///        WETH (or zero). | ||||
|     /// @param takerAssetFillAmounts The amounts to fill the orders by. | ||||
|     /// @param signatures The makers' signatures for the given orders. | ||||
|     /// @param batchFillFunctionSelector The selector for either `batchFillOrders`, | ||||
|     ///        `batchFillOrKillOrders`, or `batchFillOrdersNoThrow`. | ||||
|     /// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients. | ||||
|     /// @param feeRecipients Addresses that will receive ETH when orders are filled. | ||||
|     /// @return fillResults Amounts filled and fees paid by the makers and taker. | ||||
|     function batchBrokerTrade( | ||||
|         uint256[] memory brokeredTokenIds, | ||||
|         LibOrder.Order[] memory orders, | ||||
|         uint256[] memory takerAssetFillAmounts, | ||||
|         bytes[] memory signatures, | ||||
|         bytes4 batchFillFunctionSelector, | ||||
|         uint256[] memory ethFeeAmounts, | ||||
|         address payable[] memory feeRecipients | ||||
|     ) | ||||
|         public | ||||
|         payable | ||||
|         returns (LibFillResults.FillResults[] memory fillResults) | ||||
|     { | ||||
|         // Cache the taker-supplied asset data | ||||
|         _cachedTokenIds = brokeredTokenIds; | ||||
|         // Cache the sender's address | ||||
|         _sender = msg.sender; | ||||
|  | ||||
|         // Sanity-check the provided function selector | ||||
|         if ( | ||||
|             batchFillFunctionSelector != IExchange(address(0)).batchFillOrders.selector && | ||||
|             batchFillFunctionSelector != IExchange(address(0)).batchFillOrKillOrders.selector && | ||||
|             batchFillFunctionSelector != IExchange(address(0)).batchFillOrdersNoThrow.selector | ||||
|         ) { | ||||
|             LibBrokerRichErrors.InvalidFunctionSelectorError(batchFillFunctionSelector); | ||||
|         } | ||||
|  | ||||
|         // Pay ETH affiliate fees to all feeRecipient addresses | ||||
|         _transferEthFeesAndWrapRemaining(ethFeeAmounts, feeRecipients); | ||||
|  | ||||
|         // Perform the batch fill | ||||
|         bytes memory batchFillCalldata = abi.encodeWithSelector( | ||||
|             batchFillFunctionSelector, | ||||
|             orders, | ||||
|             takerAssetFillAmounts, | ||||
|             signatures | ||||
|         ); | ||||
|         // solhint-disable-next-line avoid-call-value | ||||
|         (bool didSucceed, bytes memory returnData) = EXCHANGE.call(batchFillCalldata); | ||||
|         if (didSucceed) { | ||||
|             // solhint-disable-next-line indent | ||||
|             fillResults = abi.decode(returnData, (LibFillResults.FillResults[])); | ||||
|         } else { | ||||
|             // Re-throw error | ||||
|             LibRichErrors.rrevert(returnData); | ||||
|         } | ||||
|  | ||||
|         // Transfer maker assets to taker | ||||
|         for (uint256 i = 0; i < orders.length; i++) { | ||||
|             if (!orders[i].makerAssetData.equals(WETH_ASSET_DATA)) { | ||||
|                 orders[i].makerAssetData.transferOut(fillResults[i].makerAssetFilledAmount); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Refund remaining ETH to msg.sender. | ||||
|         _unwrapAndTransferEth(WETH.balanceOf(address(this))); | ||||
|  | ||||
|         _clearStorage(); | ||||
|  | ||||
|         return fillResults; | ||||
|     } | ||||
|  | ||||
|     function _clearStorage() | ||||
|         private | ||||
|     { | ||||
|         delete _cachedTokenIds; | ||||
|         _cacheIndex = 0; | ||||
|         _sender = address(0); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										101
									
								
								contracts/broker/contracts/src/interfaces/IBroker.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								contracts/broker/contracts/src/interfaces/IBroker.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,101 @@ | ||||
| /* | ||||
|  | ||||
|   Copyright 2019 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.5.9; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol"; | ||||
| import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; | ||||
|  | ||||
|  | ||||
| // solhint-disable space-after-comma | ||||
| interface IBroker { | ||||
|  | ||||
|     /// @dev Fills a single property-based order by the given amount using the given assets. | ||||
|     ///      Pays protocol fees using either the ETH supplied by the taker to the transaction or | ||||
|     ///      WETH acquired from the maker during settlement. The final WETH balance is sent to the taker. | ||||
|     /// @param brokeredTokenIds Token IDs specified by the taker to be used to fill the orders. | ||||
|     /// @param order The property-based order to fill. The format of a property-based order is the | ||||
|     ///        same as that of a normal order, except the takerAssetData. Instaed of specifying a | ||||
|     ///        specific ERC721 asset, the takerAssetData should be ERC1155 assetData where the | ||||
|     ///        underlying tokenAddress is this contract's address and the desired properties are | ||||
|     ///        encoded in the extra data field. Also note that takerFees must be denominated in | ||||
|     ///        WETH (or zero). | ||||
|     /// @param takerAssetFillAmount The amount to fill the order by. | ||||
|     /// @param signature The maker's signature of the given order. | ||||
|     /// @param fillFunctionSelector The selector for either `fillOrder` or `fillOrKillOrder`. | ||||
|     /// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients. | ||||
|     /// @param feeRecipients Addresses that will receive ETH when orders are filled. | ||||
|     /// @return fillResults Amounts filled and fees paid by the maker and taker. | ||||
|     function brokerTrade( | ||||
|         uint256[] calldata brokeredTokenIds, | ||||
|         LibOrder.Order calldata order, | ||||
|         uint256 takerAssetFillAmount, | ||||
|         bytes calldata signature, | ||||
|         bytes4 fillFunctionSelector, | ||||
|         uint256[] calldata ethFeeAmounts, | ||||
|         address payable[] calldata feeRecipients | ||||
|     ) | ||||
|         external | ||||
|         payable | ||||
|         returns (LibFillResults.FillResults memory fillResults); | ||||
|  | ||||
|     /// @dev Fills multiple property-based orders by the given amounts using the given assets. | ||||
|     ///      Pays protocol fees using either the ETH supplied by the taker to the transaction or | ||||
|     ///      WETH acquired from the maker during settlement. The final WETH balance is sent to the taker. | ||||
|     /// @param brokeredTokenIds Token IDs specified by the taker to be used to fill the orders. | ||||
|     /// @param orders The property-based orders to fill. The format of a property-based order is the | ||||
|     ///        same as that of a normal order, except the takerAssetData. Instaed of specifying a | ||||
|     ///        specific ERC721 asset, the takerAssetData should be ERC1155 assetData where the | ||||
|     ///        underlying tokenAddress is this contract's address and the desired properties are | ||||
|     ///        encoded in the extra data field. Also note that takerFees must be denominated in | ||||
|     ///        WETH (or zero). | ||||
|     /// @param takerAssetFillAmounts The amounts to fill the orders by. | ||||
|     /// @param signatures The makers' signatures for the given orders. | ||||
|     /// @param batchFillFunctionSelector The selector for either `batchFillOrders`, | ||||
|     ///        `batchFillOrKillOrders`, or `batchFillOrdersNoThrow`. | ||||
|     /// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients. | ||||
|     /// @param feeRecipients Addresses that will receive ETH when orders are filled. | ||||
|     /// @return fillResults Amounts filled and fees paid by the makers and taker. | ||||
|     function batchBrokerTrade( | ||||
|         uint256[] calldata brokeredTokenIds, | ||||
|         LibOrder.Order[] calldata orders, | ||||
|         uint256[] calldata takerAssetFillAmounts, | ||||
|         bytes[] calldata signatures, | ||||
|         bytes4 batchFillFunctionSelector, | ||||
|         uint256[] calldata ethFeeAmounts, | ||||
|         address payable[] calldata feeRecipients | ||||
|     ) | ||||
|         external | ||||
|         payable | ||||
|         returns (LibFillResults.FillResults[] memory fillResults); | ||||
|  | ||||
|     /// @dev The Broker implements the ERC1155 transfer function to be compatible with the ERC1155 asset proxy | ||||
|     /// @param from Since the Broker serves as the taker of the order, this should equal `address(this)` | ||||
|     /// @param to This should be the maker of the order. | ||||
|     /// @param amounts Should be an array of just one `uint256`, specifying the amount of the brokered assets to transfer. | ||||
|     /// @param data Encodes the validator contract address and any auxiliary data it needs for property validation. | ||||
|     function safeBatchTransferFrom( | ||||
|         address from, | ||||
|         address to, | ||||
|         uint256[] calldata /* ids */, | ||||
|         uint256[] calldata amounts, | ||||
|         bytes calldata data | ||||
|     ) | ||||
|         external; | ||||
| } | ||||
| @@ -17,15 +17,17 @@ | ||||
| */ | ||||
| 
 | ||||
| pragma solidity ^0.5.9; | ||||
| pragma experimental ABIEncoderV2; | ||||
| 
 | ||||
| 
 | ||||
| contract IThresholdAsset { | ||||
| interface IGodsUnchained { | ||||
| 
 | ||||
|     /// @param _owner The address from which the balance will be retrieved | ||||
|     /// @return Balance of owner | ||||
|     function balanceOf(address _owner) | ||||
|     /// @dev Returns the proto and quality for a particular card given its token id | ||||
|     /// @param tokenId The id of the card to query. | ||||
|     /// @return proto The proto of the given card. | ||||
|     /// @return quality The quality of the given card | ||||
|     function getDetails(uint256 tokenId) | ||||
|         external | ||||
|         view | ||||
|         returns (uint256); | ||||
| 
 | ||||
|         returns (uint16 proto, uint8 quality); | ||||
| } | ||||
| @@ -0,0 +1,35 @@ | ||||
| /* | ||||
|  | ||||
|   Copyright 2019 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.5.9; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
|  | ||||
| interface IPropertyValidator { | ||||
|  | ||||
|     /// @dev Checks that the given asset data satisfies the properties encoded in `propertyData`. | ||||
|     ///      Should revert if the asset does not satisfy the specified properties. | ||||
|     /// @param tokenId The ERC721 tokenId of the asset to check. | ||||
|     /// @param propertyData Encoded properties or auxiliary data needed to perform the check. | ||||
|     function checkBrokerAsset( | ||||
|         uint256 tokenId, | ||||
|         bytes calldata propertyData | ||||
|     ) | ||||
|         external | ||||
|         view; | ||||
| } | ||||
							
								
								
									
										109
									
								
								contracts/broker/contracts/src/libs/LibBrokerRichErrors.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								contracts/broker/contracts/src/libs/LibBrokerRichErrors.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,109 @@ | ||||
| /* | ||||
|  | ||||
|   Copyright 2019 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.5.9; | ||||
|  | ||||
|  | ||||
| library LibBrokerRichErrors { | ||||
|  | ||||
|     // bytes4(keccak256("InvalidFromAddressError(address)")) | ||||
|     bytes4 internal constant INVALID_FROM_ADDRESS_ERROR_SELECTOR = | ||||
|         0x906bfb3c; | ||||
|  | ||||
|     // bytes4(keccak256("AmountsLengthMustEqualOneError(uint256)")) | ||||
|     bytes4 internal constant AMOUNTS_LENGTH_MUST_EQUAL_ONE_ERROR_SELECTOR = | ||||
|         0xba9be200; | ||||
|  | ||||
|     // bytes4(keccak256("TooFewBrokerAssetsProvidedError(uint256)")) | ||||
|     bytes4 internal constant TOO_FEW_BROKER_ASSETS_PROVIDED_ERROR_SELECTOR = | ||||
|         0x55272586; | ||||
|  | ||||
|     // bytes4(keccak256("InvalidFunctionSelectorError(bytes4)")) | ||||
|     bytes4 internal constant INVALID_FUNCTION_SELECTOR_ERROR_SELECTOR = | ||||
|         0x540943f1; | ||||
|  | ||||
|     // bytes4(keccak256("OnlyERC1155ProxyError(address)")) | ||||
|     bytes4 internal constant ONLY_ERC_1155_PROXY_ERROR_SELECTOR = | ||||
|         0xccc529af; | ||||
|  | ||||
|     // solhint-disable func-name-mixedcase | ||||
|     function InvalidFromAddressError( | ||||
|         address from | ||||
|     ) | ||||
|         internal | ||||
|         pure | ||||
|         returns (bytes memory) | ||||
|     { | ||||
|         return abi.encodeWithSelector( | ||||
|             INVALID_FROM_ADDRESS_ERROR_SELECTOR, | ||||
|             from | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     function AmountsLengthMustEqualOneError( | ||||
|         uint256 amountsLength | ||||
|     ) | ||||
|         internal | ||||
|         pure | ||||
|         returns (bytes memory) | ||||
|     { | ||||
|         return abi.encodeWithSelector( | ||||
|             AMOUNTS_LENGTH_MUST_EQUAL_ONE_ERROR_SELECTOR, | ||||
|             amountsLength | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     function TooFewBrokerAssetsProvidedError( | ||||
|         uint256 numBrokeredAssets | ||||
|     ) | ||||
|         internal | ||||
|         pure | ||||
|         returns (bytes memory) | ||||
|     { | ||||
|         return abi.encodeWithSelector( | ||||
|             TOO_FEW_BROKER_ASSETS_PROVIDED_ERROR_SELECTOR, | ||||
|             numBrokeredAssets | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     function InvalidFunctionSelectorError( | ||||
|         bytes4 selector | ||||
|     ) | ||||
|         internal | ||||
|         pure | ||||
|         returns (bytes memory) | ||||
|     { | ||||
|         return abi.encodeWithSelector( | ||||
|             INVALID_FUNCTION_SELECTOR_ERROR_SELECTOR, | ||||
|             selector | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     function OnlyERC1155ProxyError( | ||||
|         address sender | ||||
|     ) | ||||
|         internal | ||||
|         pure | ||||
|         returns (bytes memory) | ||||
|     { | ||||
|         return abi.encodeWithSelector( | ||||
|             ONLY_ERC_1155_PROXY_ERROR_SELECTOR, | ||||
|             sender | ||||
|         ); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,61 @@ | ||||
| /* | ||||
|  | ||||
|   Copyright 2019 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.5.9; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "@0x/contracts-utils/contracts/src/LibBytes.sol"; | ||||
| import "../interfaces/IGodsUnchained.sol"; | ||||
| import "../interfaces/IPropertyValidator.sol"; | ||||
|  | ||||
|  | ||||
| contract GodsUnchainedValidator is | ||||
|     IPropertyValidator | ||||
| { | ||||
|     IGodsUnchained internal GODS_UNCHAINED; // solhint-disable-line var-name-mixedcase | ||||
|  | ||||
|     using LibBytes for bytes; | ||||
|  | ||||
|     constructor(address _godsUnchained) | ||||
|         public | ||||
|     { | ||||
|         GODS_UNCHAINED = IGodsUnchained(_godsUnchained); | ||||
|     } | ||||
|  | ||||
|     /// @dev Checks that the given card (encoded as assetData) has the proto and quality encoded in `propertyData`. | ||||
|     ///      Reverts if the card doesn't match the specified proto and quality. | ||||
|     /// @param tokenId The ERC721 tokenId of the card to check. | ||||
|     /// @param propertyData Encoded proto and quality that the card is expected to have. | ||||
|     function checkBrokerAsset( | ||||
|         uint256 tokenId, | ||||
|         bytes calldata propertyData | ||||
|     ) | ||||
|         external | ||||
|         view | ||||
|     { | ||||
|         (uint16 expectedProto, uint8 expectedQuality) = abi.decode( | ||||
|             propertyData, | ||||
|             (uint16, uint8) | ||||
|         ); | ||||
|  | ||||
|         // Validate card properties. | ||||
|         (uint16 proto, uint8 quality) = GODS_UNCHAINED.getDetails(tokenId); | ||||
|         require(proto == expectedProto, "GodsUnchainedValidator/PROTO_MISMATCH"); | ||||
|         require(quality == expectedQuality, "GodsUnchainedValidator/QUALITY_MISMATCH"); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										55
									
								
								contracts/broker/contracts/test/TestGodsUnchained.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								contracts/broker/contracts/test/TestGodsUnchained.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,55 @@ | ||||
| /* | ||||
|  | ||||
|   Copyright 2019 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.5.9; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "@0x/contracts-erc721/contracts/test/DummyERC721Token.sol"; | ||||
| import "../src/interfaces/IGodsUnchained.sol"; | ||||
|  | ||||
|  | ||||
| contract TestGodsUnchained is | ||||
|     IGodsUnchained, | ||||
|     DummyERC721Token | ||||
| { | ||||
|     mapping (uint256 => uint16) internal _protoByTokenId; | ||||
|     mapping (uint256 => uint8) internal _qualityByTokenId; | ||||
|  | ||||
|     constructor ( | ||||
|         string memory _name, | ||||
|         string memory _symbol | ||||
|     ) | ||||
|         public | ||||
|         DummyERC721Token(_name, _symbol) | ||||
|     {} // solhint-disable-line no-empty-blocks | ||||
|  | ||||
|     function setTokenProperties(uint256 tokenId, uint16 proto, uint8 quality) | ||||
|         external | ||||
|     { | ||||
|         _protoByTokenId[tokenId] = proto; | ||||
|         _qualityByTokenId[tokenId] = quality; | ||||
|     } | ||||
|  | ||||
|     function getDetails(uint256 tokenId) | ||||
|         external | ||||
|         view | ||||
|         returns (uint16 proto, uint8 quality) | ||||
|     { | ||||
|         return (_protoByTokenId[tokenId], _qualityByTokenId[tokenId]); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										96
									
								
								contracts/broker/package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								contracts/broker/package.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,96 @@ | ||||
| { | ||||
|     "name": "@0x/contracts-broker", | ||||
|     "version": "1.1.3", | ||||
|     "engines": { | ||||
|         "node": ">=6.12" | ||||
|     }, | ||||
|     "description": "Extension of 0x protocol for property-based orders", | ||||
|     "main": "lib/src/index.js", | ||||
|     "directories": { | ||||
|         "test": "test" | ||||
|     }, | ||||
|     "scripts": { | ||||
|         "build": "yarn build:contracts && yarn build:ts", | ||||
|         "build:contracts": "run-s compile contracts:gen generate_contract_wrappers contracts:copy", | ||||
|         "build:ts": "tsc -b", | ||||
|         "build:ci": "yarn build", | ||||
|         "test": "yarn run_mocha", | ||||
|         "rebuild_and_test": "run-s build test", | ||||
|         "test:coverage": "SOLIDITY_COVERAGE=true run-s build run_mocha coverage:report:text coverage:report:lcov", | ||||
|         "test:profiler": "SOLIDITY_PROFILER=true run-s build run_mocha profiler:report:html", | ||||
|         "test:trace": "SOLIDITY_REVERT_TRACE=true run-s build run_mocha", | ||||
|         "run_mocha": "mocha --require source-map-support/register --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit", | ||||
|         "compile": "sol-compiler", | ||||
|         "watch": "sol-compiler -w", | ||||
|         "clean": "shx rm -rf lib test/generated-artifacts test/generated-wrappers generated-artifacts generated-wrappers", | ||||
|         "generate_contract_wrappers": "abi-gen --debug --abis  ${npm_package_config_abis} --output test/generated-wrappers --backend ethers", | ||||
|         "lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./test/generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts", | ||||
|         "coverage:report:text": "istanbul report text", | ||||
|         "coverage:report:html": "istanbul report html && open coverage/index.html", | ||||
|         "profiler:report:html": "istanbul report html && open coverage/index.html", | ||||
|         "coverage:report:lcov": "istanbul report lcov", | ||||
|         "test:circleci": "yarn test", | ||||
|         "contracts:gen": "contracts-gen generate", | ||||
|         "contracts:copy": "contracts-gen copy", | ||||
|         "lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol", | ||||
|         "compile:truffle": "truffle compile", | ||||
|         "docs:md": "ts-doc-gen --sourceDir='$PROJECT_FILES' --output=$MD_FILE_DIR --fileExtension=mdx --tsconfig=./typedoc-tsconfig.json", | ||||
|         "docs:json": "typedoc --excludePrivate --excludeExternals --excludeProtected --ignoreCompilerErrors --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES" | ||||
|     }, | ||||
|     "config": { | ||||
|         "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.", | ||||
|         "abis": "./test/generated-artifacts/@(Broker|GodsUnchainedValidator|IBroker|IGodsUnchained|IPropertyValidator|LibBrokerRichErrors|TestGodsUnchained).json" | ||||
|     }, | ||||
|     "repository": { | ||||
|         "type": "git", | ||||
|         "url": "https://github.com/0xProject/0x-monorepo.git" | ||||
|     }, | ||||
|     "license": "Apache-2.0", | ||||
|     "bugs": { | ||||
|         "url": "https://github.com/0xProject/0x-monorepo/issues" | ||||
|     }, | ||||
|     "homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md", | ||||
|     "devDependencies": { | ||||
|         "@0x/abi-gen": "^5.2.2", | ||||
|         "@0x/contracts-asset-proxy": "^3.2.4", | ||||
|         "@0x/contracts-erc20": "^3.1.4", | ||||
|         "@0x/contracts-erc721": "^3.1.4", | ||||
|         "@0x/contracts-exchange": "^3.2.4", | ||||
|         "@0x/contracts-exchange-libs": "^4.3.4", | ||||
|         "@0x/contracts-gen": "^2.0.8", | ||||
|         "@0x/contracts-test-utils": "^5.3.1", | ||||
|         "@0x/contracts-utils": "^4.4.2", | ||||
|         "@0x/sol-compiler": "^4.0.8", | ||||
|         "@0x/ts-doc-gen": "^0.0.22", | ||||
|         "@0x/tslint-config": "^4.0.0", | ||||
|         "@0x/types": "^3.1.2", | ||||
|         "@0x/web3-wrapper": "^7.0.7", | ||||
|         "@types/lodash": "4.14.104", | ||||
|         "@types/mocha": "^5.2.7", | ||||
|         "@types/node": "*", | ||||
|         "chai": "^4.0.1", | ||||
|         "chai-as-promised": "^7.1.0", | ||||
|         "chai-bignumber": "^3.0.0", | ||||
|         "dirty-chai": "^2.0.1", | ||||
|         "lodash": "^4.17.11", | ||||
|         "make-promises-safe": "^1.1.0", | ||||
|         "mocha": "^6.2.0", | ||||
|         "npm-run-all": "^4.1.2", | ||||
|         "shx": "^0.2.2", | ||||
|         "solhint": "^1.4.1", | ||||
|         "truffle": "^5.0.32", | ||||
|         "tslint": "5.11.0", | ||||
|         "typedoc": "^0.15.0", | ||||
|         "typescript": "3.0.1" | ||||
|     }, | ||||
|     "dependencies": { | ||||
|         "@0x/base-contract": "^6.2.1", | ||||
|         "@0x/order-utils": "^10.2.3", | ||||
|         "@0x/typescript-typings": "^5.0.2", | ||||
|         "@0x/utils": "^5.4.1", | ||||
|         "ethereum-types": "^3.1.0" | ||||
|     }, | ||||
|     "publishConfig": { | ||||
|         "access": "public" | ||||
|     } | ||||
| } | ||||
							
								
								
									
										23
									
								
								contracts/broker/src/artifacts.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								contracts/broker/src/artifacts.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| /* | ||||
|  * ----------------------------------------------------------------------------- | ||||
|  * Warning: This file is auto-generated by contracts-gen. Don't edit manually. | ||||
|  * ----------------------------------------------------------------------------- | ||||
|  */ | ||||
| import { ContractArtifact } from 'ethereum-types'; | ||||
|  | ||||
| import * as Broker from '../generated-artifacts/Broker.json'; | ||||
| import * as GodsUnchainedValidator from '../generated-artifacts/GodsUnchainedValidator.json'; | ||||
| import * as IBroker from '../generated-artifacts/IBroker.json'; | ||||
| import * as IGodsUnchained from '../generated-artifacts/IGodsUnchained.json'; | ||||
| import * as IPropertyValidator from '../generated-artifacts/IPropertyValidator.json'; | ||||
| import * as LibBrokerRichErrors from '../generated-artifacts/LibBrokerRichErrors.json'; | ||||
| import * as TestGodsUnchained from '../generated-artifacts/TestGodsUnchained.json'; | ||||
| export const artifacts = { | ||||
|     Broker: Broker as ContractArtifact, | ||||
|     IBroker: IBroker as ContractArtifact, | ||||
|     IGodsUnchained: IGodsUnchained as ContractArtifact, | ||||
|     IPropertyValidator: IPropertyValidator as ContractArtifact, | ||||
|     LibBrokerRichErrors: LibBrokerRichErrors as ContractArtifact, | ||||
|     GodsUnchainedValidator: GodsUnchainedValidator as ContractArtifact, | ||||
|     TestGodsUnchained: TestGodsUnchained as ContractArtifact, | ||||
| }; | ||||
							
								
								
									
										59
									
								
								contracts/broker/src/gods_unchained_utils.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								contracts/broker/src/gods_unchained_utils.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,59 @@ | ||||
| import { assetDataUtils } from '@0x/order-utils'; | ||||
| import { ERC1155AssetData } from '@0x/types'; | ||||
| import { AbiEncoder, BigNumber } from '@0x/utils'; | ||||
|  | ||||
| export interface GodsUnchainedProperties { | ||||
|     proto: BigNumber | number; | ||||
|     quality: BigNumber | number; | ||||
| } | ||||
|  | ||||
| const propertyDataEncoder = AbiEncoder.create([{ name: 'proto', type: 'uint16' }, { name: 'quality', type: 'uint8' }]); | ||||
| const brokerDataEncoder = AbiEncoder.create([ | ||||
|     { name: 'godsUnchainedAddress', type: 'address' }, | ||||
|     { name: 'validatorAddress', type: 'address' }, | ||||
|     { name: 'propertyData', type: 'bytes' }, | ||||
| ]); | ||||
|  | ||||
| /** | ||||
|  * Encodes the given proto and quality into the bytes format expected by the GodsUnchainedValidator. | ||||
|  */ | ||||
| export function encodePropertyData(properties: GodsUnchainedProperties): string { | ||||
|     return propertyDataEncoder.encode(properties); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Encodes the given proto and quality into ERC1155 asset data to be used as the takerAssetData | ||||
|  * of a property-based GodsUnchained order. Must also provide the addresses of the Broker, | ||||
|  * GodsUnchained, and GodsUnchainedValidator contracts. The optional bundleSize parameter specifies | ||||
|  * how many cards are expected for each "unit" of the takerAssetAmount. For example, If the | ||||
|  * takerAssetAmount is 3 and the bundleSize is 2, the taker must provide 2, 4, or 6 cards | ||||
|  * with the given proto and quality to fill the order. If an odd number is provided, the fill fails. | ||||
|  */ | ||||
| export function encodeBrokerAssetData( | ||||
|     brokerAddress: string, | ||||
|     godsUnchainedAddress: string, | ||||
|     validatorAddress: string, | ||||
|     properties: GodsUnchainedProperties, | ||||
|     bundleSize: number = 1, | ||||
| ): string { | ||||
|     const propertyData = propertyDataEncoder.encode(properties); | ||||
|     const brokerData = brokerDataEncoder.encode({ godsUnchainedAddress, validatorAddress, propertyData }); | ||||
|     return assetDataUtils.encodeERC1155AssetData(brokerAddress, [], [new BigNumber(bundleSize)], brokerData); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Decodes proto and quality from the bytes format expected by the GodsUnchainedValidator. | ||||
|  */ | ||||
| export function decodePropertyData(propertyData: string): GodsUnchainedProperties { | ||||
|     return propertyDataEncoder.decode(propertyData); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Decodes proto and quality from the ERC1155 takerAssetData of a property-based GodsUnchained order. | ||||
|  */ | ||||
| export function decodeBrokerAssetData(brokerAssetData: string): GodsUnchainedProperties { | ||||
|     // tslint:disable-next-line:no-unnecessary-type-assertion | ||||
|     const { callbackData: brokerData } = assetDataUtils.decodeAssetDataOrThrow(brokerAssetData) as ERC1155AssetData; | ||||
|     const { propertyData } = brokerDataEncoder.decode(brokerData); | ||||
|     return decodePropertyData(propertyData); | ||||
| } | ||||
							
								
								
									
										32
									
								
								contracts/broker/src/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								contracts/broker/src/index.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | ||||
| export { artifacts } from './artifacts'; | ||||
| export { BrokerContract, GodsUnchainedValidatorContract, TestGodsUnchainedContract } from './wrappers'; | ||||
| export * from './gods_unchained_utils'; | ||||
| export { BrokerRevertErrors } from '@0x/utils'; | ||||
| export { | ||||
|     ContractArtifact, | ||||
|     ContractChains, | ||||
|     CompilerOpts, | ||||
|     StandardContractOutput, | ||||
|     CompilerSettings, | ||||
|     ContractChainData, | ||||
|     ContractAbi, | ||||
|     DevdocOutput, | ||||
|     EvmOutput, | ||||
|     CompilerSettingsMetadata, | ||||
|     OptimizerSettings, | ||||
|     OutputField, | ||||
|     ParamDescription, | ||||
|     EvmBytecodeOutput, | ||||
|     AbiDefinition, | ||||
|     FunctionAbi, | ||||
|     EventAbi, | ||||
|     RevertErrorAbi, | ||||
|     EventParameter, | ||||
|     DataItem, | ||||
|     MethodAbi, | ||||
|     ConstructorAbi, | ||||
|     FallbackAbi, | ||||
|     ConstructorStateMutability, | ||||
|     TupleDataItem, | ||||
|     StateMutability, | ||||
| } from 'ethereum-types'; | ||||
							
								
								
									
										12
									
								
								contracts/broker/src/wrappers.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								contracts/broker/src/wrappers.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | ||||
| /* | ||||
|  * ----------------------------------------------------------------------------- | ||||
|  * Warning: This file is auto-generated by contracts-gen. Don't edit manually. | ||||
|  * ----------------------------------------------------------------------------- | ||||
|  */ | ||||
| export * from '../generated-wrappers/broker'; | ||||
| export * from '../generated-wrappers/gods_unchained_validator'; | ||||
| export * from '../generated-wrappers/i_broker'; | ||||
| export * from '../generated-wrappers/i_gods_unchained'; | ||||
| export * from '../generated-wrappers/i_property_validator'; | ||||
| export * from '../generated-wrappers/lib_broker_rich_errors'; | ||||
| export * from '../generated-wrappers/test_gods_unchained'; | ||||
							
								
								
									
										23
									
								
								contracts/broker/test/artifacts.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								contracts/broker/test/artifacts.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| /* | ||||
|  * ----------------------------------------------------------------------------- | ||||
|  * Warning: This file is auto-generated by contracts-gen. Don't edit manually. | ||||
|  * ----------------------------------------------------------------------------- | ||||
|  */ | ||||
| import { ContractArtifact } from 'ethereum-types'; | ||||
|  | ||||
| import * as Broker from '../test/generated-artifacts/Broker.json'; | ||||
| import * as GodsUnchainedValidator from '../test/generated-artifacts/GodsUnchainedValidator.json'; | ||||
| import * as IBroker from '../test/generated-artifacts/IBroker.json'; | ||||
| import * as IGodsUnchained from '../test/generated-artifacts/IGodsUnchained.json'; | ||||
| import * as IPropertyValidator from '../test/generated-artifacts/IPropertyValidator.json'; | ||||
| import * as LibBrokerRichErrors from '../test/generated-artifacts/LibBrokerRichErrors.json'; | ||||
| import * as TestGodsUnchained from '../test/generated-artifacts/TestGodsUnchained.json'; | ||||
| export const artifacts = { | ||||
|     Broker: Broker as ContractArtifact, | ||||
|     IBroker: IBroker as ContractArtifact, | ||||
|     IGodsUnchained: IGodsUnchained as ContractArtifact, | ||||
|     IPropertyValidator: IPropertyValidator as ContractArtifact, | ||||
|     LibBrokerRichErrors: LibBrokerRichErrors as ContractArtifact, | ||||
|     GodsUnchainedValidator: GodsUnchainedValidator as ContractArtifact, | ||||
|     TestGodsUnchained: TestGodsUnchained as ContractArtifact, | ||||
| }; | ||||
							
								
								
									
										56
									
								
								contracts/broker/test/gods_unchained_validator_test.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								contracts/broker/test/gods_unchained_validator_test.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,56 @@ | ||||
| import { blockchainTests, constants, expect, getRandomInteger } from '@0x/contracts-test-utils'; | ||||
| import { BigNumber } from '@0x/utils'; | ||||
| import * as _ from 'lodash'; | ||||
|  | ||||
| import { encodePropertyData } from '../src/gods_unchained_utils'; | ||||
|  | ||||
| import { artifacts } from './artifacts'; | ||||
| import { GodsUnchainedValidatorContract, TestGodsUnchainedContract } from './wrappers'; | ||||
|  | ||||
| blockchainTests.resets('GodsUnchainedValidator unit tests', env => { | ||||
|     let godsUnchained: TestGodsUnchainedContract; | ||||
|     let validator: GodsUnchainedValidatorContract; | ||||
|  | ||||
|     before(async () => { | ||||
|         godsUnchained = await TestGodsUnchainedContract.deployFrom0xArtifactAsync( | ||||
|             artifacts.TestGodsUnchained, | ||||
|             env.provider, | ||||
|             env.txDefaults, | ||||
|             artifacts, | ||||
|             'Gods Unchained Cards', | ||||
|             'GU', | ||||
|         ); | ||||
|  | ||||
|         validator = await GodsUnchainedValidatorContract.deployFrom0xArtifactAsync( | ||||
|             artifacts.GodsUnchainedValidator, | ||||
|             env.provider, | ||||
|             env.txDefaults, | ||||
|             artifacts, | ||||
|             godsUnchained.address, | ||||
|         ); | ||||
|     }); | ||||
|  | ||||
|     describe('checkBrokerAsset', () => { | ||||
|         const proto = new BigNumber(42); | ||||
|         const quality = new BigNumber(7); | ||||
|         const propertyData = encodePropertyData({ proto, quality }); | ||||
|  | ||||
|         it('succeeds if assetData proto and quality match propertyData', async () => { | ||||
|             const tokenId = getRandomInteger(0, constants.MAX_UINT256); | ||||
|             await godsUnchained.setTokenProperties(tokenId, proto, quality).awaitTransactionSuccessAsync(); | ||||
|             await validator.checkBrokerAsset(tokenId, propertyData).callAsync(); | ||||
|         }); | ||||
|         it("reverts if assetData proto doesn't match propertyData", async () => { | ||||
|             const tokenId = getRandomInteger(0, constants.MAX_UINT256); | ||||
|             await godsUnchained.setTokenProperties(tokenId, proto.plus(1), quality).awaitTransactionSuccessAsync(); | ||||
|             const tx = validator.checkBrokerAsset(tokenId, propertyData).callAsync(); | ||||
|             expect(tx).to.revertWith('PROTO_MISMATCH'); | ||||
|         }); | ||||
|         it("reverts if assetData quality doesn't match proeprtyData", async () => { | ||||
|             const tokenId = getRandomInteger(0, constants.MAX_UINT256); | ||||
|             await godsUnchained.setTokenProperties(tokenId, proto, quality.plus(1)).awaitTransactionSuccessAsync(); | ||||
|             const tx = validator.checkBrokerAsset(tokenId, propertyData).callAsync(); | ||||
|             expect(tx).to.revertWith('QUALITY_MISMATCH'); | ||||
|         }); | ||||
|     }); | ||||
| }); | ||||
							
								
								
									
										12
									
								
								contracts/broker/test/wrappers.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								contracts/broker/test/wrappers.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | ||||
| /* | ||||
|  * ----------------------------------------------------------------------------- | ||||
|  * Warning: This file is auto-generated by contracts-gen. Don't edit manually. | ||||
|  * ----------------------------------------------------------------------------- | ||||
|  */ | ||||
| export * from '../test/generated-wrappers/broker'; | ||||
| export * from '../test/generated-wrappers/gods_unchained_validator'; | ||||
| export * from '../test/generated-wrappers/i_broker'; | ||||
| export * from '../test/generated-wrappers/i_gods_unchained'; | ||||
| export * from '../test/generated-wrappers/i_property_validator'; | ||||
| export * from '../test/generated-wrappers/lib_broker_rich_errors'; | ||||
| export * from '../test/generated-wrappers/test_gods_unchained'; | ||||
							
								
								
									
										96
									
								
								contracts/broker/truffle-config.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								contracts/broker/truffle-config.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,96 @@ | ||||
| /** | ||||
|  * Use this file to configure your truffle project. It's seeded with some | ||||
|  * common settings for different networks and features like migrations, | ||||
|  * compilation and testing. Uncomment the ones you need or modify | ||||
|  * them to suit your project as necessary. | ||||
|  * | ||||
|  * More information about configuration can be found at: | ||||
|  * | ||||
|  * truffleframework.com/docs/advanced/configuration | ||||
|  * | ||||
|  * To deploy via Infura you'll need a wallet provider (like truffle-hdwallet-provider) | ||||
|  * to sign your transactions before they're sent to a remote public node. Infura accounts | ||||
|  * are available for free at: infura.io/register. | ||||
|  * | ||||
|  * You'll also need a mnemonic - the twelve word phrase the wallet uses to generate | ||||
|  * public/private key pairs. If you're publishing your code to GitHub make sure you load this | ||||
|  * phrase from a file you've .gitignored so it doesn't accidentally become public. | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| // const HDWalletProvider = require('truffle-hdwallet-provider'); | ||||
| // const infuraKey = "fj4jll3k....."; | ||||
| // | ||||
| // const fs = require('fs'); | ||||
| // const mnemonic = fs.readFileSync(".secret").toString().trim(); | ||||
|  | ||||
| module.exports = { | ||||
|     /** | ||||
|      * Networks define how you connect to your ethereum client and let you set the | ||||
|      * defaults web3 uses to send transactions. If you don't specify one truffle | ||||
|      * will spin up a development blockchain for you on port 9545 when you | ||||
|      * run `develop` or `test`. You can ask a truffle command to use a specific | ||||
|      * network from the command line, e.g | ||||
|      * | ||||
|      * $ truffle test --network <network-name> | ||||
|      */ | ||||
|  | ||||
|     networks: { | ||||
|         // Useful for testing. The `development` name is special - truffle uses it by default | ||||
|         // if it's defined here and no other network is specified at the command line. | ||||
|         // You should run a client (like ganache-cli, geth or parity) in a separate terminal | ||||
|         // tab if you use this network and you must also set the `host`, `port` and `network_id` | ||||
|         // options below to some value. | ||||
|         // | ||||
|         // development: { | ||||
|         //  host: "127.0.0.1",     // Localhost (default: none) | ||||
|         //  port: 8545,            // Standard Ethereum port (default: none) | ||||
|         //  network_id: "*",       // Any network (default: none) | ||||
|         // }, | ||||
|         // Another network with more advanced options... | ||||
|         // advanced: { | ||||
|         // port: 8777,             // Custom port | ||||
|         // network_id: 1342,       // Custom network | ||||
|         // gas: 8500000,           // Gas sent with each transaction (default: ~6700000) | ||||
|         // gasPrice: 20000000000,  // 20 gwei (in wei) (default: 100 gwei) | ||||
|         // from: <address>,        // Account to send txs from (default: accounts[0]) | ||||
|         // websockets: true        // Enable EventEmitter interface for web3 (default: false) | ||||
|         // }, | ||||
|         // Useful for deploying to a public network. | ||||
|         // NB: It's important to wrap the provider as a function. | ||||
|         // ropsten: { | ||||
|         // provider: () => new HDWalletProvider(mnemonic, `https://ropsten.infura.io/v3/YOUR-PROJECT-ID`), | ||||
|         // network_id: 3,       // Ropsten's id | ||||
|         // gas: 5500000,        // Ropsten has a lower block limit than mainnet | ||||
|         // confirmations: 2,    // # of confs to wait between deployments. (default: 0) | ||||
|         // timeoutBlocks: 200,  // # of blocks before a deployment times out  (minimum/default: 50) | ||||
|         // skipDryRun: true     // Skip dry run before migrations? (default: false for public nets ) | ||||
|         // }, | ||||
|         // Useful for private networks | ||||
|         // private: { | ||||
|         // provider: () => new HDWalletProvider(mnemonic, `https://network.io`), | ||||
|         // network_id: 2111,   // This network is yours, in the cloud. | ||||
|         // production: true    // Treats this network as if it was a public net. (default: false) | ||||
|         // } | ||||
|     }, | ||||
|  | ||||
|     // Set default mocha options here, use special reporters etc. | ||||
|     mocha: { | ||||
|         // timeout: 100000 | ||||
|     }, | ||||
|  | ||||
|     // Configure your compilers | ||||
|     compilers: { | ||||
|         solc: { | ||||
|             version: '0.5.9', | ||||
|             settings: { | ||||
|                 evmVersion: 'istanbul', | ||||
|                 optimizer: { | ||||
|                     enabled: true, | ||||
|                     runs: 1000000, | ||||
|                     details: { yul: true, deduplicate: true, cse: true, constantOptimizer: true }, | ||||
|                 }, | ||||
|             }, | ||||
|         }, | ||||
|     }, | ||||
| }; | ||||
							
								
								
									
										22
									
								
								contracts/broker/tsconfig.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								contracts/broker/tsconfig.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| { | ||||
|     "extends": "../../tsconfig", | ||||
|     "compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true }, | ||||
|     "include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"], | ||||
|     "files": [ | ||||
|         "generated-artifacts/Broker.json", | ||||
|         "generated-artifacts/GodsUnchainedValidator.json", | ||||
|         "generated-artifacts/IBroker.json", | ||||
|         "generated-artifacts/IGodsUnchained.json", | ||||
|         "generated-artifacts/IPropertyValidator.json", | ||||
|         "generated-artifacts/LibBrokerRichErrors.json", | ||||
|         "generated-artifacts/TestGodsUnchained.json", | ||||
|         "test/generated-artifacts/Broker.json", | ||||
|         "test/generated-artifacts/GodsUnchainedValidator.json", | ||||
|         "test/generated-artifacts/IBroker.json", | ||||
|         "test/generated-artifacts/IGodsUnchained.json", | ||||
|         "test/generated-artifacts/IPropertyValidator.json", | ||||
|         "test/generated-artifacts/LibBrokerRichErrors.json", | ||||
|         "test/generated-artifacts/TestGodsUnchained.json" | ||||
|     ], | ||||
|     "exclude": ["./deploy/solc/solc_bin"] | ||||
| } | ||||
							
								
								
									
										6
									
								
								contracts/broker/tslint.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								contracts/broker/tslint.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| { | ||||
|     "extends": ["@0x/tslint-config"], | ||||
|     "rules": { | ||||
|         "custom-no-magic-numbers": false | ||||
|     } | ||||
| } | ||||
							
								
								
									
										7
									
								
								contracts/broker/typedoc-tsconfig.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								contracts/broker/typedoc-tsconfig.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| { | ||||
|     "extends": "../../typedoc-tsconfig", | ||||
|     "compilerOptions": { | ||||
|         "outDir": "lib" | ||||
|     }, | ||||
|     "include": ["./src/**/*", "./test/**/*"] | ||||
| } | ||||
| @@ -1,4 +1,77 @@ | ||||
| [ | ||||
|     { | ||||
|         "timestamp": 1582837861, | ||||
|         "version": "3.1.4", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1582677073, | ||||
|         "version": "3.1.3", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1582623685, | ||||
|         "version": "3.1.2", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1581748629, | ||||
|         "version": "3.1.1", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "version": "3.1.0", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Update tests.", | ||||
|                 "pr": 2462 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1581204851 | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1580988106, | ||||
|         "version": "3.0.6", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1580811564, | ||||
|         "version": "3.0.5", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1579682890, | ||||
|         "version": "3.0.4", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1578272714, | ||||
|         "version": "3.0.3", | ||||
|   | ||||
| @@ -5,6 +5,38 @@ Edit the package's CHANGELOG.json file only. | ||||
|  | ||||
| CHANGELOG | ||||
|  | ||||
| ## v3.1.4 - _February 27, 2020_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v3.1.3 - _February 26, 2020_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v3.1.2 - _February 25, 2020_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v3.1.1 - _February 15, 2020_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v3.1.0 - _February 8, 2020_ | ||||
|  | ||||
|     * Update tests. (#2462) | ||||
|  | ||||
| ## v3.0.6 - _February 6, 2020_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v3.0.5 - _February 4, 2020_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v3.0.4 - _January 22, 2020_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v3.0.3 - _January 6, 2020_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|   | ||||
| @@ -2,8 +2,9 @@ | ||||
|     "artifactsDir": "./test/generated-artifacts", | ||||
|     "contractsDir": "./contracts", | ||||
|     "useDockerisedSolc": false, | ||||
|     "shouldSaveStandardInput": true, | ||||
|     "compilerSettings": { | ||||
|         "evmVersion": "constantinople", | ||||
|         "evmVersion": "istanbul", | ||||
|         "optimizer": { | ||||
|             "enabled": true, | ||||
|             "runs": 1000000, | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "name": "@0x/contracts-coordinator", | ||||
|     "version": "3.0.3", | ||||
|     "version": "3.1.4", | ||||
|     "engines": { | ||||
|         "node": ">=6.12" | ||||
|     }, | ||||
| @@ -52,19 +52,19 @@ | ||||
|     }, | ||||
|     "homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md", | ||||
|     "devDependencies": { | ||||
|         "@0x/abi-gen": "^5.0.3", | ||||
|         "@0x/contracts-asset-proxy": "^3.1.0", | ||||
|         "@0x/contracts-dev-utils": "^1.0.3", | ||||
|         "@0x/contracts-erc20": "^3.0.3", | ||||
|         "@0x/contracts-exchange": "^3.0.3", | ||||
|         "@0x/contracts-gen": "^2.0.3", | ||||
|         "@0x/contracts-test-utils": "^5.1.0", | ||||
|         "@0x/dev-utils": "^3.1.0", | ||||
|         "@0x/order-utils": "^10.1.0", | ||||
|         "@0x/sol-compiler": "^4.0.3", | ||||
|         "@0x/abi-gen": "^5.2.2", | ||||
|         "@0x/contracts-asset-proxy": "^3.2.4", | ||||
|         "@0x/contracts-dev-utils": "^1.3.2", | ||||
|         "@0x/contracts-erc20": "^3.1.4", | ||||
|         "@0x/contracts-exchange": "^3.2.4", | ||||
|         "@0x/contracts-gen": "^2.0.8", | ||||
|         "@0x/contracts-test-utils": "^5.3.1", | ||||
|         "@0x/dev-utils": "^3.2.1", | ||||
|         "@0x/order-utils": "^10.2.3", | ||||
|         "@0x/sol-compiler": "^4.0.8", | ||||
|         "@0x/ts-doc-gen": "^0.0.22", | ||||
|         "@0x/tslint-config": "^4.0.0", | ||||
|         "@0x/web3-wrapper": "^7.0.3", | ||||
|         "@0x/web3-wrapper": "^7.0.7", | ||||
|         "@types/lodash": "4.14.104", | ||||
|         "@types/mocha": "^5.2.7", | ||||
|         "@types/node": "*", | ||||
| @@ -84,15 +84,15 @@ | ||||
|         "typescript": "3.0.1" | ||||
|     }, | ||||
|     "dependencies": { | ||||
|         "@0x/assert": "^3.0.3", | ||||
|         "@0x/base-contract": "^6.0.3", | ||||
|         "@0x/contract-addresses": "^4.2.0", | ||||
|         "@0x/contracts-utils": "^4.0.3", | ||||
|         "@0x/json-schemas": "^5.0.3", | ||||
|         "@0x/types": "^3.1.1", | ||||
|         "@0x/typescript-typings": "^5.0.1", | ||||
|         "@0x/utils": "^5.1.2", | ||||
|         "ethereum-types": "^3.0.0", | ||||
|         "@0x/assert": "^3.0.7", | ||||
|         "@0x/base-contract": "^6.2.1", | ||||
|         "@0x/contract-addresses": "^4.8.0", | ||||
|         "@0x/contracts-utils": "^4.4.2", | ||||
|         "@0x/json-schemas": "^5.0.7", | ||||
|         "@0x/types": "^3.1.2", | ||||
|         "@0x/typescript-typings": "^5.0.2", | ||||
|         "@0x/utils": "^5.4.1", | ||||
|         "ethereum-types": "^3.1.0", | ||||
|         "http-status-codes": "^1.3.2" | ||||
|     }, | ||||
|     "publishConfig": { | ||||
|   | ||||
| @@ -14,16 +14,12 @@ export class ApprovalFactory { | ||||
|         this._verifyingContractAddress = verifyingContract; | ||||
|     } | ||||
|  | ||||
|     public async newSignedApprovalAsync( | ||||
|     public newSignedApproval( | ||||
|         transaction: SignedZeroExTransaction, | ||||
|         txOrigin: string, | ||||
|         signatureType: SignatureType = SignatureType.EthSign, | ||||
|     ): Promise<SignedCoordinatorApproval> { | ||||
|         const approvalHashBuff = await hashUtils.getApprovalHashBufferAsync( | ||||
|             transaction, | ||||
|             this._verifyingContractAddress, | ||||
|             txOrigin, | ||||
|         ); | ||||
|     ): SignedCoordinatorApproval { | ||||
|         const approvalHashBuff = hashUtils.getApprovalHashBuffer(transaction, this._verifyingContractAddress, txOrigin); | ||||
|         const signatureBuff = signingUtils.signMessage(approvalHashBuff, this._privateKey, signatureType); | ||||
|         const signedApproval = { | ||||
|             txOrigin, | ||||
|   | ||||
| @@ -3,27 +3,13 @@ import { SignedZeroExTransaction } from '@0x/types'; | ||||
| import { hexUtils, signTypedDataUtils } from '@0x/utils'; | ||||
|  | ||||
| export const hashUtils = { | ||||
|     async getApprovalHashBufferAsync( | ||||
|         transaction: SignedZeroExTransaction, | ||||
|         verifyingContract: string, | ||||
|         txOrigin: string, | ||||
|     ): Promise<Buffer> { | ||||
|         const typedData = await eip712Utils.createCoordinatorApprovalTypedDataAsync( | ||||
|             transaction, | ||||
|             verifyingContract, | ||||
|             txOrigin, | ||||
|         ); | ||||
|     getApprovalHashBuffer(transaction: SignedZeroExTransaction, verifyingContract: string, txOrigin: string): Buffer { | ||||
|         const typedData = eip712Utils.createCoordinatorApprovalTypedData(transaction, verifyingContract, txOrigin); | ||||
|         const hashBuffer = signTypedDataUtils.generateTypedDataHash(typedData); | ||||
|         return hashBuffer; | ||||
|     }, | ||||
|     async getApprovalHashHexAsync( | ||||
|         transaction: SignedZeroExTransaction, | ||||
|         verifyingContract: string, | ||||
|         txOrigin: string, | ||||
|     ): Promise<string> { | ||||
|         const hashHex = hexUtils.concat( | ||||
|             await hashUtils.getApprovalHashBufferAsync(transaction, verifyingContract, txOrigin), | ||||
|         ); | ||||
|     getApprovalHashHex(transaction: SignedZeroExTransaction, verifyingContract: string, txOrigin: string): string { | ||||
|         const hashHex = hexUtils.toHex(hashUtils.getApprovalHashBuffer(transaction, verifyingContract, txOrigin)); | ||||
|         return hashHex; | ||||
|     }, | ||||
| }; | ||||
|   | ||||
| @@ -35,6 +35,7 @@ export { | ||||
|     OutputField, | ||||
|     ParamDescription, | ||||
|     EvmBytecodeOutput, | ||||
|     EvmBytecodeOutputLinkReferences, | ||||
|     AbiDefinition, | ||||
|     FunctionAbi, | ||||
|     EventAbi, | ||||
|   | ||||
| @@ -44,11 +44,7 @@ blockchainTests.resets('Libs tests', env => { | ||||
|                 transactionHash: transactionHashUtils.getTransactionHashHex(signedTx), | ||||
|                 transactionSignature: signedTx.signature, | ||||
|             }; | ||||
|             const expectedApprovalHash = await hashUtils.getApprovalHashHexAsync( | ||||
|                 signedTx, | ||||
|                 coordinatorContract.address, | ||||
|                 txOrigin, | ||||
|             ); | ||||
|             const expectedApprovalHash = hashUtils.getApprovalHashHex(signedTx, coordinatorContract.address, txOrigin); | ||||
|             const approvalHash = await coordinatorContract.getCoordinatorApprovalHash(approval).callAsync(); | ||||
|             expect(expectedApprovalHash).to.eq(approvalHash); | ||||
|         }); | ||||
|   | ||||
| @@ -236,7 +236,7 @@ blockchainTests.resets('Mixins tests', env => { | ||||
|                 const orders = [defaultOrder]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const approval = await approvalFactory1.newSignedApprovalAsync(transaction, transactionSignerAddress); | ||||
|                 const approval = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress); | ||||
|                 await mixins | ||||
|                     .assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, [ | ||||
|                         approval.signature, | ||||
| @@ -251,7 +251,7 @@ blockchainTests.resets('Mixins tests', env => { | ||||
|                 const orders = [order]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const approval = await approvalFactory1.newSignedApprovalAsync(transaction, transactionSignerAddress); | ||||
|                 const approval = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress); | ||||
|                 await mixins | ||||
|                     .assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, [ | ||||
|                         approval.signature, | ||||
| @@ -272,7 +272,7 @@ blockchainTests.resets('Mixins tests', env => { | ||||
|                 const orders = [defaultOrder]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const approval = await approvalFactory1.newSignedApprovalAsync(transaction, transactionSignerAddress); | ||||
|                 const approval = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress); | ||||
|                 await mixins | ||||
|                     .assertValidCoordinatorApprovals(transaction, approvalSignerAddress1, transaction.signature, [ | ||||
|                         approval.signature, | ||||
| @@ -293,7 +293,7 @@ blockchainTests.resets('Mixins tests', env => { | ||||
|                 const orders = [defaultOrder]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const approval = await approvalFactory1.newSignedApprovalAsync(transaction, transactionSignerAddress); | ||||
|                 const approval = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress); | ||||
|                 const signature = hexUtils.concat( | ||||
|                     hexUtils.slice(approval.signature, 0, 2), | ||||
|                     '0xFFFFFFFF', | ||||
| @@ -314,7 +314,7 @@ blockchainTests.resets('Mixins tests', env => { | ||||
|                 const orders = [defaultOrder]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const approval = await approvalFactory1.newSignedApprovalAsync(transaction, transactionSignerAddress); | ||||
|                 const approval = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress); | ||||
|  | ||||
|                 const tx = mixins | ||||
|                     .assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, [ | ||||
| @@ -335,7 +335,7 @@ blockchainTests.resets('Mixins tests', env => { | ||||
|                 const orders = [defaultOrder, defaultOrder]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const approval = await approvalFactory1.newSignedApprovalAsync(transaction, transactionSignerAddress); | ||||
|                 const approval = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress); | ||||
|                 await mixins | ||||
|                     .assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, [ | ||||
|                         approval.signature, | ||||
| @@ -349,7 +349,7 @@ blockchainTests.resets('Mixins tests', env => { | ||||
|                 })); | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const approval = await approvalFactory1.newSignedApprovalAsync(transaction, transactionSignerAddress); | ||||
|                 const approval = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress); | ||||
|                 await mixins | ||||
|                     .assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, [ | ||||
|                         approval.signature, | ||||
| @@ -371,7 +371,7 @@ blockchainTests.resets('Mixins tests', env => { | ||||
|                 const orders = [defaultOrder, { ...defaultOrder, senderAddress: constants.NULL_ADDRESS }]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const approval = await approvalFactory1.newSignedApprovalAsync(transaction, transactionSignerAddress); | ||||
|                 const approval = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress); | ||||
|                 await mixins | ||||
|                     .assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, [ | ||||
|                         approval.signature, | ||||
| @@ -382,8 +382,8 @@ blockchainTests.resets('Mixins tests', env => { | ||||
|                 const orders = [defaultOrder, { ...defaultOrder, feeRecipientAddress: approvalSignerAddress2 }]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const approval1 = await approvalFactory1.newSignedApprovalAsync(transaction, transactionSignerAddress); | ||||
|                 const approval2 = await approvalFactory2.newSignedApprovalAsync(transaction, transactionSignerAddress); | ||||
|                 const approval1 = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress); | ||||
|                 const approval2 = approvalFactory2.newSignedApproval(transaction, transactionSignerAddress); | ||||
|                 await mixins | ||||
|                     .assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, [ | ||||
|                         approval1.signature, | ||||
| @@ -403,7 +403,7 @@ blockchainTests.resets('Mixins tests', env => { | ||||
|                 const orders = [defaultOrder, { ...defaultOrder, feeRecipientAddress: approvalSignerAddress2 }]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const approval2 = await approvalFactory2.newSignedApprovalAsync(transaction, transactionSignerAddress); | ||||
|                 const approval2 = approvalFactory2.newSignedApproval(transaction, transactionSignerAddress); | ||||
|  | ||||
|                 const tx = mixins | ||||
|                     .assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, [ | ||||
| @@ -429,7 +429,7 @@ blockchainTests.resets('Mixins tests', env => { | ||||
|                 const orders = [defaultOrder, defaultOrder]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const approval = await approvalFactory1.newSignedApprovalAsync(transaction, transactionSignerAddress); | ||||
|                 const approval = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress); | ||||
|                 const signature = hexUtils.concat( | ||||
|                     hexUtils.slice(approval.signature, 0, 2), | ||||
|                     '0xFFFFFFFF', | ||||
| @@ -450,8 +450,8 @@ blockchainTests.resets('Mixins tests', env => { | ||||
|                 const orders = [defaultOrder, { ...defaultOrder, feeRecipientAddress: approvalSignerAddress2 }]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const approval1 = await approvalFactory1.newSignedApprovalAsync(transaction, transactionSignerAddress); | ||||
|                 const approval2 = await approvalFactory2.newSignedApprovalAsync(transaction, transactionSignerAddress); | ||||
|                 const approval1 = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress); | ||||
|                 const approval2 = approvalFactory2.newSignedApproval(transaction, transactionSignerAddress); | ||||
|                 const approvalSignature2 = hexUtils.concat( | ||||
|                     hexUtils.slice(approval2.signature, 0, 2), | ||||
|                     '0xFFFFFFFF', | ||||
| @@ -473,7 +473,7 @@ blockchainTests.resets('Mixins tests', env => { | ||||
|                 const orders = [defaultOrder, { ...defaultOrder, feeRecipientAddress: approvalSignerAddress2 }]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const approval2 = await approvalFactory2.newSignedApprovalAsync(transaction, transactionSignerAddress); | ||||
|                 const approval2 = approvalFactory2.newSignedApproval(transaction, transactionSignerAddress); | ||||
|                 const approvalSignature2 = hexUtils.concat( | ||||
|                     hexUtils.slice(approval2.signature, 0, 2), | ||||
|                     '0xFFFFFFFF', | ||||
| @@ -494,7 +494,7 @@ blockchainTests.resets('Mixins tests', env => { | ||||
|                 const orders = [defaultOrder, defaultOrder]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const approval1 = await approvalFactory1.newSignedApprovalAsync(transaction, transactionSignerAddress); | ||||
|                 const approval1 = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress); | ||||
|  | ||||
|                 const tx = mixins | ||||
|                     .assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, [ | ||||
|   | ||||
| @@ -84,7 +84,7 @@ module.exports = { | ||||
|         solc: { | ||||
|             version: '0.5.9', | ||||
|             settings: { | ||||
|                 evmVersion: 'constantinople', | ||||
|                 evmVersion: 'istanbul', | ||||
|                 optimizer: { | ||||
|                     enabled: true, | ||||
|                     runs: 1000000, | ||||
|   | ||||
| @@ -1,4 +1,91 @@ | ||||
| [ | ||||
|     { | ||||
|         "timestamp": 1582837861, | ||||
|         "version": "1.3.2", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1582677073, | ||||
|         "version": "1.3.1", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "version": "1.3.0", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Update `DevUtils` addresses in `DeploymentConstants`", | ||||
|                 "pr": 2493 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1582623685 | ||||
|     }, | ||||
|     { | ||||
|         "version": "1.2.0", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Add `DydxBridge` order validation", | ||||
|                 "pr": 2466 | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1581748629, | ||||
|         "version": "1.1.1", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "version": "1.1.0", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Refactor mixins into public libraries.", | ||||
|                 "pr": 2464 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Remove `LibTransactionDecoder` export", | ||||
|                 "pr": 2464 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1581204851 | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1580988106, | ||||
|         "version": "1.0.6", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1580811564, | ||||
|         "version": "1.0.5", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1579682890, | ||||
|         "version": "1.0.4", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "version": "1.0.3", | ||||
|         "changes": [ | ||||
|   | ||||
| @@ -5,6 +5,43 @@ Edit the package's CHANGELOG.json file only. | ||||
|  | ||||
| CHANGELOG | ||||
|  | ||||
| ## v1.3.2 - _February 27, 2020_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v1.3.1 - _February 26, 2020_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v1.3.0 - _February 25, 2020_ | ||||
|  | ||||
|     * Update `DevUtils` addresses in `DeploymentConstants` (#2493) | ||||
|  | ||||
| ## v1.2.0 - _Invalid date_ | ||||
|  | ||||
|     * Add `DydxBridge` order validation (#2466) | ||||
|  | ||||
| ## v1.1.1 - _February 15, 2020_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v1.1.0 - _February 8, 2020_ | ||||
|  | ||||
|     * Refactor mixins into public libraries. (#2464) | ||||
|     * Remove `LibTransactionDecoder` export (#2464) | ||||
|  | ||||
| ## v1.0.6 - _February 6, 2020_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v1.0.5 - _February 4, 2020_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v1.0.4 - _January 22, 2020_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v1.0.3 - _January 6, 2020_ | ||||
|  | ||||
|     * Fixed ERC721 duplicate token ID bug (#2400) | ||||
|   | ||||
| @@ -41,13 +41,13 @@ yarn install | ||||
| To build this package and all other monorepo packages that it depends on, run the following from the monorepo root directory: | ||||
|  | ||||
| ```bash | ||||
| PKG=@0x/contracts-extensions yarn build | ||||
| PKG=@0x/contracts-dev-utils yarn build | ||||
| ``` | ||||
|  | ||||
| Or continuously rebuild on change: | ||||
|  | ||||
| ```bash | ||||
| PKG=@0x/contracts-extensions yarn watch | ||||
| PKG=@0x/contracts-dev-utils yarn watch | ||||
| ``` | ||||
|  | ||||
| ### Clean | ||||
|   | ||||
| @@ -3,11 +3,12 @@ | ||||
|     "contractsDir": "./contracts", | ||||
|     "useDockerisedSolc": false, | ||||
|     "isOfflineMode": false, | ||||
|     "shouldSaveStandardInput": true, | ||||
|     "compilerSettings": { | ||||
|         "evmVersion": "constantinople", | ||||
|         "evmVersion": "istanbul", | ||||
|         "optimizer": { | ||||
|             "enabled": true, | ||||
|             "runs": 200, | ||||
|             "runs": 5000, | ||||
|             "details": { "yul": true, "deduplicate": true, "cse": true, "constantOptimizer": true } | ||||
|         }, | ||||
|         "outputSelection": { | ||||
|   | ||||
							
								
								
									
										54
									
								
								contracts/dev-utils/contracts/src/Addresses.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								contracts/dev-utils/contracts/src/Addresses.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,54 @@ | ||||
| /* | ||||
|  | ||||
|   Copyright 2019 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.5.16; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetData.sol"; | ||||
| import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol"; | ||||
| import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; | ||||
|  | ||||
|  | ||||
| // solhint-disable no-empty-blocks | ||||
| contract Addresses is | ||||
|     DeploymentConstants | ||||
| { | ||||
|     address public exchangeAddress; | ||||
|     address public erc20ProxyAddress; | ||||
|     address public erc721ProxyAddress; | ||||
|     address public erc1155ProxyAddress; | ||||
|     address public staticCallProxyAddress; | ||||
|     address public chaiBridgeAddress; | ||||
|     address public dydxBridgeAddress; | ||||
|  | ||||
|     constructor ( | ||||
|         address exchange_, | ||||
|         address chaiBridge_, | ||||
|         address dydxBridge_ | ||||
|     ) | ||||
|         public | ||||
|     { | ||||
|         exchangeAddress = exchange_; | ||||
|         chaiBridgeAddress = chaiBridge_; | ||||
|         dydxBridgeAddress = dydxBridge_; | ||||
|         erc20ProxyAddress = IExchange(exchange_).getAssetProxy(IAssetData(address(0)).ERC20Token.selector); | ||||
|         erc721ProxyAddress = IExchange(exchange_).getAssetProxy(IAssetData(address(0)).ERC721Token.selector); | ||||
|         erc1155ProxyAddress = IExchange(exchange_).getAssetProxy(IAssetData(address(0)).ERC1155Assets.selector); | ||||
|         staticCallProxyAddress = IExchange(exchange_).getAssetProxy(IAssetData(address(0)).StaticCall.selector); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										388
									
								
								contracts/dev-utils/contracts/src/AssetBalance.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										388
									
								
								contracts/dev-utils/contracts/src/AssetBalance.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,388 @@ | ||||
| /* | ||||
|  | ||||
|   Copyright 2019 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.5.16; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "@0x/contracts-utils/contracts/src/LibBytes.sol"; | ||||
| import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetData.sol"; | ||||
| import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetProxy.sol"; | ||||
| import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol"; | ||||
| import "@0x/contracts-erc721/contracts/src/interfaces/IERC721Token.sol"; | ||||
| import "@0x/contracts-erc1155/contracts/src/interfaces/IERC1155.sol"; | ||||
| import "@0x/contracts-asset-proxy/contracts/src/interfaces/IChai.sol"; | ||||
| import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol"; | ||||
| import "./Addresses.sol"; | ||||
| import "./LibDydxBalance.sol"; | ||||
|  | ||||
|  | ||||
| contract AssetBalance is | ||||
|     Addresses | ||||
| { | ||||
|     // 2^256 - 1 | ||||
|     uint256 constant internal _MAX_UINT256 = uint256(-1); | ||||
|  | ||||
|     using LibBytes for bytes; | ||||
|  | ||||
|     /// @dev Returns the owner's balance of the assets(s) specified in | ||||
|     /// assetData.  When the asset data contains multiple assets (eg in | ||||
|     /// ERC1155 or Multi-Asset), the return value indicates how many | ||||
|     /// complete "baskets" of those assets are owned by owner. | ||||
|     /// @param ownerAddress Owner of the assets specified by assetData. | ||||
|     /// @param assetData Details of asset, encoded per the AssetProxy contract specification. | ||||
|     /// @return Number of assets (or asset baskets) held by owner. | ||||
|     function getBalance(address ownerAddress, bytes memory assetData) | ||||
|         public | ||||
|         returns (uint256 balance) | ||||
|     { | ||||
|         // Get id of AssetProxy contract | ||||
|         bytes4 assetProxyId = assetData.readBytes4(0); | ||||
|  | ||||
|         if (assetProxyId == IAssetData(address(0)).ERC20Token.selector) { | ||||
|             // Get ERC20 token address | ||||
|             address tokenAddress = assetData.readAddress(16); | ||||
|             balance = LibERC20Token.balanceOf(tokenAddress, ownerAddress); | ||||
|  | ||||
|         } else if (assetProxyId == IAssetData(address(0)).ERC721Token.selector) { | ||||
|             // Get ERC721 token address and id | ||||
|             (, address tokenAddress, uint256 tokenId) = LibAssetData.decodeERC721AssetData(assetData); | ||||
|  | ||||
|             // Check if id is owned by ownerAddress | ||||
|             bytes memory ownerOfCalldata = abi.encodeWithSelector( | ||||
|                 IERC721Token(address(0)).ownerOf.selector, | ||||
|                 tokenId | ||||
|             ); | ||||
|  | ||||
|             (bool success, bytes memory returnData) = tokenAddress.staticcall(ownerOfCalldata); | ||||
|             address currentOwnerAddress = (success && returnData.length == 32) ? returnData.readAddress(12) : address(0); | ||||
|             balance = currentOwnerAddress == ownerAddress ? 1 : 0; | ||||
|  | ||||
|         } else if (assetProxyId == IAssetData(address(0)).ERC1155Assets.selector) { | ||||
|             // Get ERC1155 token address, array of ids, and array of values | ||||
|             (, address tokenAddress, uint256[] memory tokenIds, uint256[] memory tokenValues,) = LibAssetData.decodeERC1155AssetData(assetData); | ||||
|  | ||||
|             uint256 length = tokenIds.length; | ||||
|             for (uint256 i = 0; i != length; i++) { | ||||
|                 // Skip over the token if the corresponding value is 0. | ||||
|                 if (tokenValues[i] == 0) { | ||||
|                     continue; | ||||
|                 } | ||||
|  | ||||
|                 // Encode data for `balanceOf(ownerAddress, tokenIds[i]) | ||||
|                 bytes memory balanceOfData = abi.encodeWithSelector( | ||||
|                     IERC1155(address(0)).balanceOf.selector, | ||||
|                     ownerAddress, | ||||
|                     tokenIds[i] | ||||
|                 ); | ||||
|  | ||||
|                 // Query balance | ||||
|                 (bool success, bytes memory returnData) = tokenAddress.staticcall(balanceOfData); | ||||
|                 uint256 totalBalance = success && returnData.length == 32 ? returnData.readUint256(0) : 0; | ||||
|  | ||||
|                 // Scale total balance down by corresponding value in assetData | ||||
|                 uint256 scaledBalance = totalBalance / tokenValues[i]; | ||||
|                 if (scaledBalance == 0) { | ||||
|                     return 0; | ||||
|                 } | ||||
|                 if (scaledBalance < balance || balance == 0) { | ||||
|                     balance = scaledBalance; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|         } else if (assetProxyId == IAssetData(address(0)).StaticCall.selector) { | ||||
|             // Encode data for `staticCallProxy.transferFrom(assetData,...)` | ||||
|             bytes memory transferFromData = abi.encodeWithSelector( | ||||
|                 IAssetProxy(address(0)).transferFrom.selector, | ||||
|                 assetData, | ||||
|                 address(0),  // `from` address is not used | ||||
|                 address(0),  // `to` address is not used | ||||
|                 0            // `amount` is not used | ||||
|             ); | ||||
|  | ||||
|             // Check if staticcall would be successful | ||||
|             (bool success,) = staticCallProxyAddress.staticcall(transferFromData); | ||||
|  | ||||
|             // Success means that the staticcall can be made an unlimited amount of times | ||||
|             balance = success ? _MAX_UINT256 : 0; | ||||
|  | ||||
|         } else if (assetProxyId == IAssetData(address(0)).ERC20Bridge.selector) { | ||||
|             // Get address of ERC20 token and bridge contract | ||||
|             (, address tokenAddress, address bridgeAddress, ) = LibAssetData.decodeERC20BridgeAssetData(assetData); | ||||
|             if (tokenAddress == _getDaiAddress() && bridgeAddress == chaiBridgeAddress) { | ||||
|                 uint256 chaiBalance = LibERC20Token.balanceOf(_getChaiAddress(), ownerAddress); | ||||
|                 // Calculate Dai balance | ||||
|                 balance = _convertChaiToDaiAmount(chaiBalance); | ||||
|             } | ||||
|             // Balance will be 0 if bridge is not supported | ||||
|  | ||||
|         } else if (assetProxyId == IAssetData(address(0)).MultiAsset.selector) { | ||||
|             // Get array of values and array of assetDatas | ||||
|             (, uint256[] memory assetAmounts, bytes[] memory nestedAssetData) = LibAssetData.decodeMultiAssetData(assetData); | ||||
|  | ||||
|             uint256 length = nestedAssetData.length; | ||||
|             for (uint256 i = 0; i != length; i++) { | ||||
|                 // Skip over the asset if the corresponding amount is 0. | ||||
|                 if (assetAmounts[i] == 0) { | ||||
|                     continue; | ||||
|                 } | ||||
|  | ||||
|                 // Query balance of individual assetData | ||||
|                 uint256 totalBalance = getBalance(ownerAddress, nestedAssetData[i]); | ||||
|  | ||||
|                 // Scale total balance down by corresponding value in assetData | ||||
|                 uint256 scaledBalance = totalBalance / assetAmounts[i]; | ||||
|                 if (scaledBalance == 0) { | ||||
|                     return 0; | ||||
|                 } | ||||
|                 if (scaledBalance < balance || balance == 0) { | ||||
|                     balance = scaledBalance; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Balance will be 0 if assetProxyId is unknown | ||||
|         return balance; | ||||
|     } | ||||
|  | ||||
|     /// @dev Calls getBalance() for each element of assetData. | ||||
|     /// @param ownerAddress Owner of the assets specified by assetData. | ||||
|     /// @param assetData Array of asset details, each encoded per the AssetProxy contract specification. | ||||
|     /// @return Array of asset balances from getBalance(), with each element | ||||
|     /// corresponding to the same-indexed element in the assetData input. | ||||
|     function getBatchBalances(address ownerAddress, bytes[] memory assetData) | ||||
|         public | ||||
|         returns (uint256[] memory balances) | ||||
|     { | ||||
|         uint256 length = assetData.length; | ||||
|         balances = new uint256[](length); | ||||
|         for (uint256 i = 0; i != length; i++) { | ||||
|             balances[i] = getBalance(ownerAddress, assetData[i]); | ||||
|         } | ||||
|         return balances; | ||||
|     } | ||||
|  | ||||
|     /// @dev Returns the number of asset(s) (described by assetData) that | ||||
|     /// the corresponding AssetProxy contract is authorized to spend.  When the asset data contains | ||||
|     /// multiple assets (eg for Multi-Asset), the return value indicates | ||||
|     /// how many complete "baskets" of those assets may be spent by all of the corresponding | ||||
|     /// AssetProxy contracts. | ||||
|     /// @param ownerAddress Owner of the assets specified by assetData. | ||||
|     /// @param assetData Details of asset, encoded per the AssetProxy contract specification. | ||||
|     /// @return Number of assets (or asset baskets) that the corresponding AssetProxy is authorized to spend. | ||||
|     function getAssetProxyAllowance(address ownerAddress, bytes memory assetData) | ||||
|         public | ||||
|         returns (uint256 allowance) | ||||
|     { | ||||
|         // Get id of AssetProxy contract | ||||
|         bytes4 assetProxyId = assetData.readBytes4(0); | ||||
|  | ||||
|         if (assetProxyId == IAssetData(address(0)).MultiAsset.selector) { | ||||
|             // Get array of values and array of assetDatas | ||||
|             (, uint256[] memory amounts, bytes[] memory nestedAssetData) = LibAssetData.decodeMultiAssetData(assetData); | ||||
|  | ||||
|             uint256 length = nestedAssetData.length; | ||||
|             for (uint256 i = 0; i != length; i++) { | ||||
|                 // Skip over the asset if the corresponding amount is 0. | ||||
|                 if (amounts[i] == 0) { | ||||
|                     continue; | ||||
|                 } | ||||
|  | ||||
|                 // Query allowance of individual assetData | ||||
|                 uint256 totalAllowance = getAssetProxyAllowance(ownerAddress, nestedAssetData[i]); | ||||
|  | ||||
|                 // Scale total allowance down by corresponding value in assetData | ||||
|                 uint256 scaledAllowance = totalAllowance / amounts[i]; | ||||
|                 if (scaledAllowance == 0) { | ||||
|                     return 0; | ||||
|                 } | ||||
|                 if (scaledAllowance < allowance || allowance == 0) { | ||||
|                     allowance = scaledAllowance; | ||||
|                 } | ||||
|             } | ||||
|             return allowance; | ||||
|         } | ||||
|  | ||||
|         if (assetProxyId == IAssetData(address(0)).ERC20Token.selector) { | ||||
|             // Get ERC20 token address | ||||
|             address tokenAddress = assetData.readAddress(16); | ||||
|             allowance = LibERC20Token.allowance(tokenAddress, ownerAddress, erc20ProxyAddress); | ||||
|  | ||||
|         } else if (assetProxyId == IAssetData(address(0)).ERC721Token.selector) { | ||||
|             // Get ERC721 token address and id | ||||
|             (, address tokenAddress, uint256 tokenId) = LibAssetData.decodeERC721AssetData(assetData); | ||||
|  | ||||
|             // Encode data for `isApprovedForAll(ownerAddress, erc721ProxyAddress)` | ||||
|             bytes memory isApprovedForAllData = abi.encodeWithSelector( | ||||
|                 IERC721Token(address(0)).isApprovedForAll.selector, | ||||
|                 ownerAddress, | ||||
|                 erc721ProxyAddress | ||||
|             ); | ||||
|  | ||||
|             (bool success, bytes memory returnData) = tokenAddress.staticcall(isApprovedForAllData); | ||||
|  | ||||
|             // If not approved for all, call `getApproved(tokenId)` | ||||
|             if (!success || returnData.length != 32 || returnData.readUint256(0) != 1) { | ||||
|                 // Encode data for `getApproved(tokenId)` | ||||
|                 bytes memory getApprovedData = abi.encodeWithSelector(IERC721Token(address(0)).getApproved.selector, tokenId); | ||||
|                 (success, returnData) = tokenAddress.staticcall(getApprovedData); | ||||
|  | ||||
|                 // Allowance is 1 if successful and the approved address is the ERC721Proxy | ||||
|                 allowance = success && returnData.length == 32 && returnData.readAddress(12) == erc721ProxyAddress ? 1 : 0; | ||||
|             } else { | ||||
|                 // Allowance is 2^256 - 1 if `isApprovedForAll` returned true | ||||
|                 allowance = _MAX_UINT256; | ||||
|             } | ||||
|  | ||||
|         } else if (assetProxyId == IAssetData(address(0)).ERC1155Assets.selector) { | ||||
|             // Get ERC1155 token address | ||||
|             (, address tokenAddress, , , ) = LibAssetData.decodeERC1155AssetData(assetData); | ||||
|  | ||||
|             // Encode data for `isApprovedForAll(ownerAddress, erc1155ProxyAddress)` | ||||
|             bytes memory isApprovedForAllData = abi.encodeWithSelector( | ||||
|                 IERC1155(address(0)).isApprovedForAll.selector, | ||||
|                 ownerAddress, | ||||
|                 erc1155ProxyAddress | ||||
|             ); | ||||
|  | ||||
|             // Query allowance | ||||
|             (bool success, bytes memory returnData) = tokenAddress.staticcall(isApprovedForAllData); | ||||
|             allowance = success && returnData.length == 32 && returnData.readUint256(0) == 1 ? _MAX_UINT256 : 0; | ||||
|  | ||||
|         } else if (assetProxyId == IAssetData(address(0)).StaticCall.selector) { | ||||
|             // The StaticCallProxy does not require any approvals | ||||
|             allowance = _MAX_UINT256; | ||||
|  | ||||
|         } else if (assetProxyId == IAssetData(address(0)).ERC20Bridge.selector) { | ||||
|             // Get address of ERC20 token and bridge contract | ||||
|             (, address tokenAddress, address bridgeAddress,) = | ||||
|                 LibAssetData.decodeERC20BridgeAssetData(assetData); | ||||
|             if (tokenAddress == _getDaiAddress() && bridgeAddress == chaiBridgeAddress) { | ||||
|                 uint256 chaiAllowance = LibERC20Token.allowance(_getChaiAddress(), ownerAddress, chaiBridgeAddress); | ||||
|                 // Dai allowance is unlimited if Chai allowance is unlimited | ||||
|                 allowance = chaiAllowance == _MAX_UINT256 ? _MAX_UINT256 : _convertChaiToDaiAmount(chaiAllowance); | ||||
|             } else if (bridgeAddress == dydxBridgeAddress) { | ||||
|                 allowance = LibDydxBalance.getDydxMakerAllowance(ownerAddress, bridgeAddress, _getDydxAddress()); | ||||
|             } | ||||
|             // Allowance will be 0 if bridge is not supported | ||||
|         } | ||||
|  | ||||
|         // Allowance will be 0 if the assetProxyId is unknown | ||||
|         return allowance; | ||||
|     } | ||||
|  | ||||
|     /// @dev Calls getAssetProxyAllowance() for each element of assetData. | ||||
|     /// @param ownerAddress Owner of the assets specified by assetData. | ||||
|     /// @param assetData Array of asset details, each encoded per the AssetProxy contract specification. | ||||
|     /// @return An array of asset allowances from getAllowance(), with each | ||||
|     /// element corresponding to the same-indexed element in the assetData input. | ||||
|     function getBatchAssetProxyAllowances(address ownerAddress, bytes[] memory assetData) | ||||
|         public | ||||
|         returns (uint256[] memory allowances) | ||||
|     { | ||||
|         uint256 length = assetData.length; | ||||
|         allowances = new uint256[](length); | ||||
|         for (uint256 i = 0; i != length; i++) { | ||||
|             allowances[i] = getAssetProxyAllowance(ownerAddress, assetData[i]); | ||||
|         } | ||||
|         return allowances; | ||||
|     } | ||||
|  | ||||
|     /// @dev Calls getBalance() and getAllowance() for assetData. | ||||
|     /// @param ownerAddress Owner of the assets specified by assetData. | ||||
|     /// @param assetData Details of asset, encoded per the AssetProxy contract specification. | ||||
|     /// @return Number of assets (or asset baskets) held by owner, and number | ||||
|     /// of assets (or asset baskets) that the corresponding AssetProxy is authorized to spend. | ||||
|     function getBalanceAndAssetProxyAllowance( | ||||
|         address ownerAddress, | ||||
|         bytes memory assetData | ||||
|     ) | ||||
|         public | ||||
|         returns (uint256 balance, uint256 allowance) | ||||
|     { | ||||
|         balance = getBalance(ownerAddress, assetData); | ||||
|         allowance = getAssetProxyAllowance(ownerAddress, assetData); | ||||
|         return (balance, allowance); | ||||
|     } | ||||
|  | ||||
|     /// @dev Calls getBatchBalances() and getBatchAllowances() for each element of assetData. | ||||
|     /// @param ownerAddress Owner of the assets specified by assetData. | ||||
|     /// @param assetData Array of asset details, each encoded per the AssetProxy contract specification. | ||||
|     /// @return An array of asset balances from getBalance(), and an array of | ||||
|     /// asset allowances from getAllowance(), with each element | ||||
|     /// corresponding to the same-indexed element in the assetData input. | ||||
|     function getBatchBalancesAndAssetProxyAllowances( | ||||
|         address ownerAddress, | ||||
|         bytes[] memory assetData | ||||
|     ) | ||||
|         public | ||||
|         returns (uint256[] memory balances, uint256[] memory allowances) | ||||
|     { | ||||
|         balances = getBatchBalances(ownerAddress, assetData); | ||||
|         allowances = getBatchAssetProxyAllowances(ownerAddress, assetData); | ||||
|         return (balances, allowances); | ||||
|     } | ||||
|  | ||||
|     /// @dev Converts an amount of Chai into its equivalent Dai amount. | ||||
|     ///      Also accumulates Dai from DSR if called after the last time it was collected. | ||||
|     /// @param chaiAmount Amount of Chai to converts. | ||||
|     function _convertChaiToDaiAmount(uint256 chaiAmount) | ||||
|         internal | ||||
|         returns (uint256 daiAmount) | ||||
|     { | ||||
|         PotLike pot = IChai(_getChaiAddress()).pot(); | ||||
|         // Accumulate savings if called after last time savings were collected | ||||
|         // solhint-disable-next-line not-rely-on-time | ||||
|         uint256 chiMultiplier = (now > pot.rho()) | ||||
|             ? pot.drip() | ||||
|             : pot.chi(); | ||||
|         daiAmount = LibMath.getPartialAmountFloor(chiMultiplier, 10**27, chaiAmount); | ||||
|         return daiAmount; | ||||
|     } | ||||
|  | ||||
|     /// @dev Returns an order MAKER's balance of the assets(s) specified in | ||||
|     ///      makerAssetData. Unlike `getBalanceAndAssetProxyAllowance()`, this | ||||
|     ///      can handle maker asset types that depend on taker tokens being | ||||
|     ///      transferred to the maker first. | ||||
|     /// @param order The order. | ||||
|     /// @return balance Quantity of assets transferrable from maker to taker. | ||||
|     function _getConvertibleMakerBalanceAndAssetProxyAllowance( | ||||
|         LibOrder.Order memory order | ||||
|     ) | ||||
|         internal | ||||
|         returns (uint256 balance, uint256 allowance) | ||||
|     { | ||||
|         if (order.makerAssetData.length < 4) { | ||||
|             return (0, 0); | ||||
|         } | ||||
|         bytes4 assetProxyId = order.makerAssetData.readBytes4(0); | ||||
|         // Handle dydx bridge assets. | ||||
|         if (assetProxyId == IAssetData(address(0)).ERC20Bridge.selector) { | ||||
|             (, , address bridgeAddress, ) = LibAssetData.decodeERC20BridgeAssetData(order.makerAssetData); | ||||
|             if (bridgeAddress == dydxBridgeAddress) { | ||||
|                 return ( | ||||
|                     LibDydxBalance.getDydxMakerBalance(order, _getDydxAddress()), | ||||
|                     getAssetProxyAllowance(order.makerAddress, order.makerAssetData) | ||||
|                 ); | ||||
|             } | ||||
|         } | ||||
|         return ( | ||||
|             getBalance(order.makerAddress, order.makerAssetData), | ||||
|             getAssetProxyAllowance(order.makerAddress, order.makerAssetData) | ||||
|         ); | ||||
|     } | ||||
| } | ||||
| @@ -16,7 +16,7 @@ | ||||
|  | ||||
| */ | ||||
|  | ||||
| pragma solidity ^0.5.5; | ||||
| pragma solidity ^0.5.16; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "@0x/contracts-exchange-libs/contracts/src/LibEIP712ExchangeDomain.sol"; | ||||
| @@ -24,27 +24,39 @@ import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; | ||||
| import "@0x/contracts-exchange-libs/contracts/src/LibZeroExTransaction.sol"; | ||||
| import "@0x/contracts-utils/contracts/src/LibEIP712.sol"; | ||||
| import "@0x/contracts-utils/contracts/src/LibBytes.sol"; | ||||
| import "./Addresses.sol"; | ||||
| import "./OrderValidationUtils.sol"; | ||||
| import "./OrderTransferSimulationUtils.sol"; | ||||
| import "./LibTransactionDecoder.sol"; | ||||
| import "./EthBalanceChecker.sol"; | ||||
| import "./ExternalFunctions.sol"; | ||||
|  | ||||
|  | ||||
| // solhint-disable no-empty-blocks | ||||
| contract DevUtils is | ||||
|     Addresses, | ||||
|     OrderValidationUtils, | ||||
|     LibTransactionDecoder, | ||||
|     LibEIP712ExchangeDomain, | ||||
|     EthBalanceChecker | ||||
|     EthBalanceChecker, | ||||
|     ExternalFunctions | ||||
| { | ||||
|     constructor (address _exchange) | ||||
|     constructor ( | ||||
|         address exchange_, | ||||
|         address chaiBridge_, | ||||
|         address dydxBridge_ | ||||
|     ) | ||||
|         public | ||||
|         OrderValidationUtils(_exchange) | ||||
|         OrderTransferSimulationUtils(_exchange) | ||||
|         Addresses( | ||||
|             exchange_, | ||||
|             chaiBridge_, | ||||
|             dydxBridge_ | ||||
|         ) | ||||
|         LibEIP712ExchangeDomain(uint256(0), address(0)) // null args because because we only use constants | ||||
|     {} | ||||
|  | ||||
|     function getOrderHash(LibOrder.Order memory order, uint256 chainId, address exchange) | ||||
|     function getOrderHash( | ||||
|         LibOrder.Order memory order, | ||||
|         uint256 chainId, | ||||
|         address exchange | ||||
|     ) | ||||
|         public | ||||
|         pure | ||||
|         returns (bytes32 orderHash) | ||||
|   | ||||
| @@ -16,7 +16,7 @@ | ||||
|  | ||||
| */ | ||||
|  | ||||
| pragma solidity ^0.5.5; | ||||
| pragma solidity ^0.5.16; | ||||
|  | ||||
|  | ||||
| contract EthBalanceChecker { | ||||
|   | ||||
							
								
								
									
										322
									
								
								contracts/dev-utils/contracts/src/ExternalFunctions.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										322
									
								
								contracts/dev-utils/contracts/src/ExternalFunctions.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,322 @@ | ||||
| /* | ||||
|  | ||||
|   Copyright 2019 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.5.16; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "./Addresses.sol"; | ||||
| import "./LibAssetData.sol"; | ||||
| import "./LibTransactionDecoder.sol"; | ||||
| import "./LibOrderTransferSimulation.sol"; | ||||
|  | ||||
|  | ||||
| contract ExternalFunctions is | ||||
|     Addresses | ||||
| { | ||||
|  | ||||
|     /// @dev Decodes the call data for an Exchange contract method call. | ||||
|     /// @param transactionData ABI-encoded calldata for an Exchange | ||||
|     ///     contract method call. | ||||
|     /// @return The name of the function called, and the parameters it was | ||||
|     ///     given.  For single-order fills and cancels, the arrays will have | ||||
|     ///     just one element. | ||||
|     function decodeZeroExTransactionData(bytes memory transactionData) | ||||
|         public | ||||
|         pure | ||||
|         returns( | ||||
|             string memory functionName, | ||||
|             LibOrder.Order[] memory orders, | ||||
|             uint256[] memory takerAssetFillAmounts, | ||||
|             bytes[] memory signatures | ||||
|         ) | ||||
|     { | ||||
|         return LibTransactionDecoder.decodeZeroExTransactionData(transactionData); | ||||
|     } | ||||
|  | ||||
|     /// @dev Decode AssetProxy identifier | ||||
|     /// @param assetData AssetProxy-compliant asset data describing an ERC-20, ERC-721, ERC1155, or MultiAsset asset. | ||||
|     /// @return The AssetProxy identifier | ||||
|     function decodeAssetProxyId(bytes memory assetData) | ||||
|         public | ||||
|         pure | ||||
|         returns ( | ||||
|             bytes4 assetProxyId | ||||
|         ) | ||||
|     { | ||||
|         return LibAssetData.decodeAssetProxyId(assetData); | ||||
|     } | ||||
|  | ||||
|     /// @dev Encode ERC-20 asset data into the format described in the AssetProxy contract specification. | ||||
|     /// @param tokenAddress The address of the ERC-20 contract hosting the asset to be traded. | ||||
|     /// @return AssetProxy-compliant data describing the asset. | ||||
|     function encodeERC20AssetData(address tokenAddress) | ||||
|         public | ||||
|         pure | ||||
|         returns (bytes memory assetData) | ||||
|     { | ||||
|         return LibAssetData.encodeERC20AssetData(tokenAddress); | ||||
|     } | ||||
|  | ||||
|     /// @dev Decode ERC-20 asset data from the format described in the AssetProxy contract specification. | ||||
|     /// @param assetData AssetProxy-compliant asset data describing an ERC-20 asset. | ||||
|     /// @return The AssetProxy identifier, and the address of the ERC-20 | ||||
|     /// contract hosting this asset. | ||||
|     function decodeERC20AssetData(bytes memory assetData) | ||||
|         public | ||||
|         pure | ||||
|         returns ( | ||||
|             bytes4 assetProxyId, | ||||
|             address tokenAddress | ||||
|         ) | ||||
|     { | ||||
|         return LibAssetData.decodeERC20AssetData(assetData); | ||||
|     } | ||||
|  | ||||
|     /// @dev Encode ERC-721 asset data into the format described in the AssetProxy specification. | ||||
|     /// @param tokenAddress The address of the ERC-721 contract hosting the asset to be traded. | ||||
|     /// @param tokenId The identifier of the specific asset to be traded. | ||||
|     /// @return AssetProxy-compliant asset data describing the asset. | ||||
|     function encodeERC721AssetData(address tokenAddress, uint256 tokenId) | ||||
|         public | ||||
|         pure | ||||
|         returns (bytes memory assetData) | ||||
|     { | ||||
|         return LibAssetData.encodeERC721AssetData(tokenAddress, tokenId); | ||||
|     } | ||||
|  | ||||
|     /// @dev Decode ERC-721 asset data from the format described in the AssetProxy contract specification. | ||||
|     /// @param assetData AssetProxy-compliant asset data describing an ERC-721 asset. | ||||
|     /// @return The ERC-721 AssetProxy identifier, the address of the ERC-721 | ||||
|     /// contract hosting this asset, and the identifier of the specific | ||||
|     /// asset to be traded. | ||||
|     function decodeERC721AssetData(bytes memory assetData) | ||||
|         public | ||||
|         pure | ||||
|         returns ( | ||||
|             bytes4 assetProxyId, | ||||
|             address tokenAddress, | ||||
|             uint256 tokenId | ||||
|         ) | ||||
|     { | ||||
|         return LibAssetData.decodeERC721AssetData(assetData); | ||||
|     } | ||||
|  | ||||
|     /// @dev Encode ERC-1155 asset data into the format described in the AssetProxy contract specification. | ||||
|     /// @param tokenAddress The address of the ERC-1155 contract hosting the asset(s) to be traded. | ||||
|     /// @param tokenIds The identifiers of the specific assets to be traded. | ||||
|     /// @param tokenValues The amounts of each asset to be traded. | ||||
|     /// @param callbackData Data to be passed to receiving contracts when a transfer is performed. | ||||
|     /// @return AssetProxy-compliant asset data describing the set of assets. | ||||
|     function encodeERC1155AssetData( | ||||
|         address tokenAddress, | ||||
|         uint256[] memory tokenIds, | ||||
|         uint256[] memory tokenValues, | ||||
|         bytes memory callbackData | ||||
|     ) | ||||
|         public | ||||
|         pure | ||||
|         returns (bytes memory assetData) | ||||
|     { | ||||
|         return LibAssetData.encodeERC1155AssetData( | ||||
|             tokenAddress, | ||||
|             tokenIds, | ||||
|             tokenValues, | ||||
|             callbackData | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     /// @dev Decode ERC-1155 asset data from the format described in the AssetProxy contract specification. | ||||
|     /// @param assetData AssetProxy-compliant asset data describing an ERC-1155 set of assets. | ||||
|     /// @return The ERC-1155 AssetProxy identifier, the address of the ERC-1155 | ||||
|     /// contract hosting the assets, an array of the identifiers of the | ||||
|     /// assets to be traded, an array of asset amounts to be traded, and | ||||
|     /// callback data.  Each element of the arrays corresponds to the | ||||
|     /// same-indexed element of the other array.  Return values specified as | ||||
|     /// `memory` are returned as pointers to locations within the memory of | ||||
|     /// the input parameter `assetData`. | ||||
|     function decodeERC1155AssetData(bytes memory assetData) | ||||
|         public | ||||
|         pure | ||||
|         returns ( | ||||
|             bytes4 assetProxyId, | ||||
|             address tokenAddress, | ||||
|             uint256[] memory tokenIds, | ||||
|             uint256[] memory tokenValues, | ||||
|             bytes memory callbackData | ||||
|         ) | ||||
|     { | ||||
|         return LibAssetData.decodeERC1155AssetData(assetData); | ||||
|     } | ||||
|  | ||||
|     /// @dev Encode data for multiple assets, per the AssetProxy contract specification. | ||||
|     /// @param amounts The amounts of each asset to be traded. | ||||
|     /// @param nestedAssetData AssetProxy-compliant data describing each asset to be traded. | ||||
|     /// @return AssetProxy-compliant data describing the set of assets. | ||||
|     function encodeMultiAssetData(uint256[] memory amounts, bytes[] memory nestedAssetData) | ||||
|         public | ||||
|         pure | ||||
|         returns (bytes memory assetData) | ||||
|     { | ||||
|         return LibAssetData.encodeMultiAssetData(amounts, nestedAssetData); | ||||
|     } | ||||
|  | ||||
|     /// @dev Decode multi-asset data from the format described in the AssetProxy contract specification. | ||||
|     /// @param assetData AssetProxy-compliant data describing a multi-asset basket. | ||||
|     /// @return The Multi-Asset AssetProxy identifier, an array of the amounts | ||||
|     /// of the assets to be traded, and an array of the | ||||
|     /// AssetProxy-compliant data describing each asset to be traded.  Each | ||||
|     /// element of the arrays corresponds to the same-indexed element of the other array. | ||||
|     function decodeMultiAssetData(bytes memory assetData) | ||||
|         public | ||||
|         pure | ||||
|         returns ( | ||||
|             bytes4 assetProxyId, | ||||
|             uint256[] memory amounts, | ||||
|             bytes[] memory nestedAssetData | ||||
|         ) | ||||
|     { | ||||
|         return LibAssetData.decodeMultiAssetData(assetData); | ||||
|     } | ||||
|  | ||||
|     /// @dev Encode StaticCall asset data into the format described in the AssetProxy contract specification. | ||||
|     /// @param staticCallTargetAddress Target address of StaticCall. | ||||
|     /// @param staticCallData Data that will be passed to staticCallTargetAddress in the StaticCall. | ||||
|     /// @param expectedReturnDataHash Expected Keccak-256 hash of the StaticCall return data. | ||||
|     /// @return AssetProxy-compliant asset data describing the set of assets. | ||||
|     function encodeStaticCallAssetData( | ||||
|         address staticCallTargetAddress, | ||||
|         bytes memory staticCallData, | ||||
|         bytes32 expectedReturnDataHash | ||||
|     ) | ||||
|         public | ||||
|         pure | ||||
|         returns (bytes memory assetData) | ||||
|     { | ||||
|         return LibAssetData.encodeStaticCallAssetData( | ||||
|             staticCallTargetAddress, | ||||
|             staticCallData, | ||||
|             expectedReturnDataHash | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     /// @dev Decode StaticCall asset data from the format described in the AssetProxy contract specification. | ||||
|     /// @param assetData AssetProxy-compliant asset data describing a StaticCall asset | ||||
|     /// @return The StaticCall AssetProxy identifier, the target address of the StaticCAll, the data to be | ||||
|     /// passed to the target address, and the expected Keccak-256 hash of the static call return data. | ||||
|     function decodeStaticCallAssetData(bytes memory assetData) | ||||
|         public | ||||
|         pure | ||||
|         returns ( | ||||
|             bytes4 assetProxyId, | ||||
|             address staticCallTargetAddress, | ||||
|             bytes memory staticCallData, | ||||
|             bytes32 expectedReturnDataHash | ||||
|         ) | ||||
|     { | ||||
|         return LibAssetData.decodeStaticCallAssetData(assetData); | ||||
|     } | ||||
|  | ||||
|     /// @dev Decode ERC20Bridge asset data from the format described in the AssetProxy contract specification. | ||||
|     /// @param assetData AssetProxy-compliant asset data describing an ERC20Bridge asset | ||||
|     /// @return The ERC20BridgeProxy identifier, the address of the ERC20 token to transfer, the address | ||||
|     /// of the bridge contract, and extra data to be passed to the bridge contract. | ||||
|     function decodeERC20BridgeAssetData(bytes memory assetData) | ||||
|         public | ||||
|         pure | ||||
|         returns ( | ||||
|             bytes4 assetProxyId, | ||||
|             address tokenAddress, | ||||
|             address bridgeAddress, | ||||
|             bytes memory bridgeData | ||||
|         ) | ||||
|     { | ||||
|         return LibAssetData.decodeERC20BridgeAssetData(assetData); | ||||
|     } | ||||
|  | ||||
|     /// @dev Reverts if assetData is not of a valid format for its given proxy id. | ||||
|     /// @param assetData AssetProxy compliant asset data. | ||||
|     function revertIfInvalidAssetData(bytes memory assetData) | ||||
|         public | ||||
|         pure | ||||
|     { | ||||
|         return LibAssetData.revertIfInvalidAssetData(assetData); | ||||
|     } | ||||
|  | ||||
|     /// @dev Simulates the maker transfers within an order and returns the index of the first failed transfer. | ||||
|     /// @param order The order to simulate transfers for. | ||||
|     /// @param takerAddress The address of the taker that will fill the order. | ||||
|     /// @param takerAssetFillAmount The amount of takerAsset that the taker wished to fill. | ||||
|     /// @return The index of the first failed transfer (or 4 if all transfers are successful). | ||||
|     function getSimulatedOrderMakerTransferResults( | ||||
|         LibOrder.Order memory order, | ||||
|         address takerAddress, | ||||
|         uint256 takerAssetFillAmount | ||||
|     ) | ||||
|         public | ||||
|         returns (LibOrderTransferSimulation.OrderTransferResults orderTransferResults) | ||||
|     { | ||||
|         return LibOrderTransferSimulation.getSimulatedOrderMakerTransferResults( | ||||
|             exchangeAddress, | ||||
|             order, | ||||
|             takerAddress, | ||||
|             takerAssetFillAmount | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     /// @dev Simulates all of the transfers within an order and returns the index of the first failed transfer. | ||||
|     /// @param order The order to simulate transfers for. | ||||
|     /// @param takerAddress The address of the taker that will fill the order. | ||||
|     /// @param takerAssetFillAmount The amount of takerAsset that the taker wished to fill. | ||||
|     /// @return The index of the first failed transfer (or 4 if all transfers are successful). | ||||
|     function getSimulatedOrderTransferResults( | ||||
|         LibOrder.Order memory order, | ||||
|         address takerAddress, | ||||
|         uint256 takerAssetFillAmount | ||||
|     ) | ||||
|         public | ||||
|         returns (LibOrderTransferSimulation.OrderTransferResults orderTransferResults) | ||||
|     { | ||||
|         return LibOrderTransferSimulation.getSimulatedOrderTransferResults( | ||||
|             exchangeAddress, | ||||
|             order, | ||||
|             takerAddress, | ||||
|             takerAssetFillAmount | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     /// @dev Simulates all of the transfers for each given order and returns the indices of each first failed transfer. | ||||
|     /// @param orders Array of orders to individually simulate transfers for. | ||||
|     /// @param takerAddresses Array of addresses of takers that will fill each order. | ||||
|     /// @param takerAssetFillAmounts Array of amounts of takerAsset that will be filled for each order. | ||||
|     /// @return The indices of the first failed transfer (or 4 if all transfers are successful) for each order. | ||||
|     function getSimulatedOrdersTransferResults( | ||||
|         LibOrder.Order[] memory orders, | ||||
|         address[] memory takerAddresses, | ||||
|         uint256[] memory takerAssetFillAmounts | ||||
|     ) | ||||
|         public | ||||
|         returns (LibOrderTransferSimulation.OrderTransferResults[] memory orderTransferResults) | ||||
|     { | ||||
|         return LibOrderTransferSimulation.getSimulatedOrdersTransferResults( | ||||
|             exchangeAddress, | ||||
|             orders, | ||||
|             takerAddresses, | ||||
|             takerAssetFillAmounts | ||||
|         ); | ||||
|     } | ||||
| } | ||||
| @@ -16,306 +16,17 @@ | ||||
|  | ||||
| */ | ||||
|  | ||||
| pragma solidity ^0.5.5; | ||||
| pragma solidity ^0.5.16; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "@0x/contracts-utils/contracts/src/LibBytes.sol"; | ||||
| import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol"; | ||||
| import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetData.sol"; | ||||
| import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetProxy.sol"; | ||||
| import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; | ||||
| import "@0x/contracts-erc721/contracts/src/interfaces/IERC721Token.sol"; | ||||
| import "@0x/contracts-erc1155/contracts/src/interfaces/IERC1155.sol"; | ||||
|  | ||||
|  | ||||
| contract LibAssetData { | ||||
|  | ||||
|     // 2^256 - 1 | ||||
|     uint256 constant internal _MAX_UINT256 = uint256(-1); | ||||
| library LibAssetData { | ||||
|  | ||||
|     using LibBytes for bytes; | ||||
|  | ||||
|     // solhint-disable var-name-mixedcase | ||||
|     IExchange internal _EXCHANGE; | ||||
|     address internal _ERC20_PROXY_ADDRESS; | ||||
|     address internal _ERC721_PROXY_ADDRESS; | ||||
|     address internal _ERC1155_PROXY_ADDRESS; | ||||
|     address internal _STATIC_CALL_PROXY_ADDRESS; | ||||
|     // solhint-enable var-name-mixedcase | ||||
|  | ||||
|     constructor (address _exchange) | ||||
|         public | ||||
|     { | ||||
|         _EXCHANGE = IExchange(_exchange); | ||||
|         _ERC20_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(IAssetData(address(0)).ERC20Token.selector); | ||||
|         _ERC721_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(IAssetData(address(0)).ERC721Token.selector); | ||||
|         _ERC1155_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(IAssetData(address(0)).ERC1155Assets.selector); | ||||
|         _STATIC_CALL_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(IAssetData(address(0)).StaticCall.selector); | ||||
|     } | ||||
|  | ||||
|     /// @dev Returns the owner's balance of the assets(s) specified in | ||||
|     /// assetData.  When the asset data contains multiple assets (eg in | ||||
|     /// ERC1155 or Multi-Asset), the return value indicates how many | ||||
|     /// complete "baskets" of those assets are owned by owner. | ||||
|     /// @param ownerAddress Owner of the assets specified by assetData. | ||||
|     /// @param assetData Details of asset, encoded per the AssetProxy contract specification. | ||||
|     /// @return Number of assets (or asset baskets) held by owner. | ||||
|     function getBalance(address ownerAddress, bytes memory assetData) | ||||
|         public | ||||
|         view | ||||
|         returns (uint256 balance) | ||||
|     { | ||||
|         // Get id of AssetProxy contract | ||||
|         bytes4 assetProxyId = assetData.readBytes4(0); | ||||
|  | ||||
|         if (assetProxyId == IAssetData(address(0)).ERC20Token.selector) { | ||||
|             // Get ERC20 token address | ||||
|             address tokenAddress = assetData.readAddress(16); | ||||
|  | ||||
|             // Encode data for `balanceOf(ownerAddress)` | ||||
|             bytes memory balanceOfData = abi.encodeWithSelector( | ||||
|                 IERC20Token(address(0)).balanceOf.selector, | ||||
|                 ownerAddress | ||||
|             ); | ||||
|  | ||||
|             // Query balance | ||||
|             (bool success, bytes memory returnData) = tokenAddress.staticcall(balanceOfData); | ||||
|             balance = success && returnData.length == 32 ? returnData.readUint256(0) : 0; | ||||
|         } else if (assetProxyId == IAssetData(address(0)).ERC721Token.selector) { | ||||
|             // Get ERC721 token address and id | ||||
|             (, address tokenAddress, uint256 tokenId) = decodeERC721AssetData(assetData); | ||||
|  | ||||
|             // Check if id is owned by ownerAddress | ||||
|             bytes memory ownerOfCalldata = abi.encodeWithSelector( | ||||
|                 IERC721Token(address(0)).ownerOf.selector, | ||||
|                 tokenId | ||||
|             ); | ||||
|  | ||||
|             (bool success, bytes memory returnData) = tokenAddress.staticcall(ownerOfCalldata); | ||||
|             address currentOwnerAddress = (success && returnData.length == 32) ? returnData.readAddress(12) : address(0); | ||||
|             balance = currentOwnerAddress == ownerAddress ? 1 : 0; | ||||
|         } else if (assetProxyId == IAssetData(address(0)).ERC1155Assets.selector) { | ||||
|             // Get ERC1155 token address, array of ids, and array of values | ||||
|             (, address tokenAddress, uint256[] memory tokenIds, uint256[] memory tokenValues,) = decodeERC1155AssetData(assetData); | ||||
|  | ||||
|             uint256 length = tokenIds.length; | ||||
|             for (uint256 i = 0; i != length; i++) { | ||||
|                 // Encode data for `balanceOf(ownerAddress, tokenIds[i]) | ||||
|                 bytes memory balanceOfData = abi.encodeWithSelector( | ||||
|                     IERC1155(address(0)).balanceOf.selector, | ||||
|                     ownerAddress, | ||||
|                     tokenIds[i] | ||||
|                 ); | ||||
|  | ||||
|                 // Query balance | ||||
|                 (bool success, bytes memory returnData) = tokenAddress.staticcall(balanceOfData); | ||||
|                 uint256 totalBalance = success && returnData.length == 32 ? returnData.readUint256(0) : 0; | ||||
|  | ||||
|                 // Scale total balance down by corresponding value in assetData | ||||
|                 uint256 scaledBalance = totalBalance / tokenValues[i]; | ||||
|                 if (scaledBalance < balance || balance == 0) { | ||||
|                     balance = scaledBalance; | ||||
|                 } | ||||
|             } | ||||
|         } else if (assetProxyId == IAssetData(address(0)).StaticCall.selector) { | ||||
|             // Encode data for `staticCallProxy.transferFrom(assetData,...)` | ||||
|             bytes memory transferFromData = abi.encodeWithSelector( | ||||
|                 IAssetProxy(address(0)).transferFrom.selector, | ||||
|                 assetData, | ||||
|                 address(0),  // `from` address is not used | ||||
|                 address(0),  // `to` address is not used | ||||
|                 0            // `amount` is not used | ||||
|             ); | ||||
|  | ||||
|             // Check if staticcall would be successful | ||||
|             (bool success,) = _STATIC_CALL_PROXY_ADDRESS.staticcall(transferFromData); | ||||
|  | ||||
|             // Success means that the staticcall can be made an unlimited amount of times | ||||
|             balance = success ? _MAX_UINT256 : 0; | ||||
|         } else if (assetProxyId == IAssetData(address(0)).MultiAsset.selector) { | ||||
|             // Get array of values and array of assetDatas | ||||
|             (, uint256[] memory assetAmounts, bytes[] memory nestedAssetData) = decodeMultiAssetData(assetData); | ||||
|  | ||||
|             uint256 length = nestedAssetData.length; | ||||
|             for (uint256 i = 0; i != length; i++) { | ||||
|                 // Query balance of individual assetData | ||||
|                 uint256 totalBalance = getBalance(ownerAddress, nestedAssetData[i]); | ||||
|  | ||||
|                 // Scale total balance down by corresponding value in assetData | ||||
|                 uint256 scaledBalance = totalBalance / assetAmounts[i]; | ||||
|                 if (scaledBalance < balance || balance == 0) { | ||||
|                     balance = scaledBalance; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Balance will be 0 if assetProxyId is unknown | ||||
|         return balance; | ||||
|     } | ||||
|  | ||||
|     /// @dev Calls getBalance() for each element of assetData. | ||||
|     /// @param ownerAddress Owner of the assets specified by assetData. | ||||
|     /// @param assetData Array of asset details, each encoded per the AssetProxy contract specification. | ||||
|     /// @return Array of asset balances from getBalance(), with each element | ||||
|     /// corresponding to the same-indexed element in the assetData input. | ||||
|     function getBatchBalances(address ownerAddress, bytes[] memory assetData) | ||||
|         public | ||||
|         view | ||||
|         returns (uint256[] memory balances) | ||||
|     { | ||||
|         uint256 length = assetData.length; | ||||
|         balances = new uint256[](length); | ||||
|         for (uint256 i = 0; i != length; i++) { | ||||
|             balances[i] = getBalance(ownerAddress, assetData[i]); | ||||
|         } | ||||
|         return balances; | ||||
|     } | ||||
|  | ||||
|     /// @dev Returns the number of asset(s) (described by assetData) that | ||||
|     /// the corresponding AssetProxy contract is authorized to spend.  When the asset data contains | ||||
|     /// multiple assets (eg for Multi-Asset), the return value indicates | ||||
|     /// how many complete "baskets" of those assets may be spent by all of the corresponding | ||||
|     /// AssetProxy contracts. | ||||
|     /// @param ownerAddress Owner of the assets specified by assetData. | ||||
|     /// @param assetData Details of asset, encoded per the AssetProxy contract specification. | ||||
|     /// @return Number of assets (or asset baskets) that the corresponding AssetProxy is authorized to spend. | ||||
|     function getAssetProxyAllowance(address ownerAddress, bytes memory assetData) | ||||
|         public | ||||
|         view | ||||
|         returns (uint256 allowance) | ||||
|     { | ||||
|         // Get id of AssetProxy contract | ||||
|         bytes4 assetProxyId = assetData.readBytes4(0); | ||||
|  | ||||
|         if (assetProxyId == IAssetData(address(0)).MultiAsset.selector) { | ||||
|             // Get array of values and array of assetDatas | ||||
|             (, uint256[] memory amounts, bytes[] memory nestedAssetData) = decodeMultiAssetData(assetData); | ||||
|  | ||||
|             uint256 length = nestedAssetData.length; | ||||
|             for (uint256 i = 0; i != length; i++) { | ||||
|                 // Query allowance of individual assetData | ||||
|                 uint256 totalAllowance = getAssetProxyAllowance(ownerAddress, nestedAssetData[i]); | ||||
|  | ||||
|                 // Scale total allowance down by corresponding value in assetData | ||||
|                 uint256 scaledAllowance = totalAllowance / amounts[i]; | ||||
|                 if (scaledAllowance < allowance || allowance == 0) { | ||||
|                     allowance = scaledAllowance; | ||||
|                 } | ||||
|             } | ||||
|             return allowance; | ||||
|         } | ||||
|  | ||||
|         if (assetProxyId == IAssetData(address(0)).ERC20Token.selector) { | ||||
|             // Get ERC20 token address | ||||
|             address tokenAddress = assetData.readAddress(16); | ||||
|  | ||||
|             // Encode data for `allowance(ownerAddress, _ERC20_PROXY_ADDRESS)` | ||||
|             bytes memory allowanceData = abi.encodeWithSelector( | ||||
|                 IERC20Token(address(0)).allowance.selector, | ||||
|                 ownerAddress, | ||||
|                 _ERC20_PROXY_ADDRESS | ||||
|             ); | ||||
|  | ||||
|             // Query allowance | ||||
|             (bool success, bytes memory returnData) = tokenAddress.staticcall(allowanceData); | ||||
|             allowance = success && returnData.length == 32 ? returnData.readUint256(0) : 0; | ||||
|         } else if (assetProxyId == IAssetData(address(0)).ERC721Token.selector) { | ||||
|             // Get ERC721 token address and id | ||||
|             (, address tokenAddress, uint256 tokenId) = decodeERC721AssetData(assetData); | ||||
|  | ||||
|             // Encode data for `isApprovedForAll(ownerAddress, _ERC721_PROXY_ADDRESS)` | ||||
|             bytes memory isApprovedForAllData = abi.encodeWithSelector( | ||||
|                 IERC721Token(address(0)).isApprovedForAll.selector, | ||||
|                 ownerAddress, | ||||
|                 _ERC721_PROXY_ADDRESS | ||||
|             ); | ||||
|  | ||||
|             (bool success, bytes memory returnData) = tokenAddress.staticcall(isApprovedForAllData); | ||||
|  | ||||
|             // If not approved for all, call `getApproved(tokenId)` | ||||
|             if (!success || returnData.length != 32 || returnData.readUint256(0) != 1) { | ||||
|                 // Encode data for `getApproved(tokenId)` | ||||
|                 bytes memory getApprovedData = abi.encodeWithSelector(IERC721Token(address(0)).getApproved.selector, tokenId); | ||||
|                 (success, returnData) = tokenAddress.staticcall(getApprovedData); | ||||
|  | ||||
|                 // Allowance is 1 if successful and the approved address is the ERC721Proxy | ||||
|                 allowance = success && returnData.length == 32 && returnData.readAddress(12) == _ERC721_PROXY_ADDRESS ? 1 : 0; | ||||
|             } else { | ||||
|                 // Allowance is 2^256 - 1 if `isApprovedForAll` returned true | ||||
|                 allowance = _MAX_UINT256; | ||||
|             } | ||||
|         } else if (assetProxyId == IAssetData(address(0)).ERC1155Assets.selector) { | ||||
|             // Get ERC1155 token address | ||||
|             (, address tokenAddress, , , ) = decodeERC1155AssetData(assetData); | ||||
|  | ||||
|             // Encode data for `isApprovedForAll(ownerAddress, _ERC1155_PROXY_ADDRESS)` | ||||
|             bytes memory isApprovedForAllData = abi.encodeWithSelector( | ||||
|                 IERC1155(address(0)).isApprovedForAll.selector, | ||||
|                 ownerAddress, | ||||
|                 _ERC1155_PROXY_ADDRESS | ||||
|             ); | ||||
|  | ||||
|             // Query allowance | ||||
|             (bool success, bytes memory returnData) = tokenAddress.staticcall(isApprovedForAllData); | ||||
|             allowance = success && returnData.length == 32 && returnData.readUint256(0) == 1 ? _MAX_UINT256 : 0; | ||||
|         } else if (assetProxyId == IAssetData(address(0)).StaticCall.selector) { | ||||
|             // The StaticCallProxy does not require any approvals | ||||
|             allowance = _MAX_UINT256; | ||||
|         } | ||||
|  | ||||
|         // Allowance will be 0 if the assetProxyId is unknown | ||||
|         return allowance; | ||||
|     } | ||||
|  | ||||
|     /// @dev Calls getAssetProxyAllowance() for each element of assetData. | ||||
|     /// @param ownerAddress Owner of the assets specified by assetData. | ||||
|     /// @param assetData Array of asset details, each encoded per the AssetProxy contract specification. | ||||
|     /// @return An array of asset allowances from getAllowance(), with each | ||||
|     /// element corresponding to the same-indexed element in the assetData input. | ||||
|     function getBatchAssetProxyAllowances(address ownerAddress, bytes[] memory assetData) | ||||
|         public | ||||
|         view | ||||
|         returns (uint256[] memory allowances) | ||||
|     { | ||||
|         uint256 length = assetData.length; | ||||
|         allowances = new uint256[](length); | ||||
|         for (uint256 i = 0; i != length; i++) { | ||||
|             allowances[i] = getAssetProxyAllowance(ownerAddress, assetData[i]); | ||||
|         } | ||||
|         return allowances; | ||||
|     } | ||||
|  | ||||
|     /// @dev Calls getBalance() and getAllowance() for assetData. | ||||
|     /// @param ownerAddress Owner of the assets specified by assetData. | ||||
|     /// @param assetData Details of asset, encoded per the AssetProxy contract specification. | ||||
|     /// @return Number of assets (or asset baskets) held by owner, and number | ||||
|     /// of assets (or asset baskets) that the corresponding AssetProxy is authorized to spend. | ||||
|     function getBalanceAndAssetProxyAllowance(address ownerAddress, bytes memory assetData) | ||||
|         public | ||||
|         view | ||||
|         returns (uint256 balance, uint256 allowance) | ||||
|     { | ||||
|         balance = getBalance(ownerAddress, assetData); | ||||
|         allowance = getAssetProxyAllowance(ownerAddress, assetData); | ||||
|         return (balance, allowance); | ||||
|     } | ||||
|  | ||||
|     /// @dev Calls getBatchBalances() and getBatchAllowances() for each element of assetData. | ||||
|     /// @param ownerAddress Owner of the assets specified by assetData. | ||||
|     /// @param assetData Array of asset details, each encoded per the AssetProxy contract specification. | ||||
|     /// @return An array of asset balances from getBalance(), and an array of | ||||
|     /// asset allowances from getAllowance(), with each element | ||||
|     /// corresponding to the same-indexed element in the assetData input. | ||||
|     function getBatchBalancesAndAssetProxyAllowances(address ownerAddress, bytes[] memory assetData) | ||||
|         public | ||||
|         view | ||||
|         returns (uint256[] memory balances, uint256[] memory allowances) | ||||
|     { | ||||
|         balances = getBatchBalances(ownerAddress, assetData); | ||||
|         allowances = getBatchAssetProxyAllowances(ownerAddress, assetData); | ||||
|         return (balances, allowances); | ||||
|     } | ||||
|  | ||||
|     /// @dev Decode AssetProxy identifier | ||||
|     /// @param assetData AssetProxy-compliant asset data describing an ERC-20, ERC-721, ERC1155, or MultiAsset asset. | ||||
|     /// @return The AssetProxy identifier | ||||
| @@ -589,6 +300,35 @@ contract LibAssetData { | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     /// @dev Decode ERC20Bridge asset data from the format described in the AssetProxy contract specification. | ||||
|     /// @param assetData AssetProxy-compliant asset data describing an ERC20Bridge asset | ||||
|     /// @return The ERC20BridgeProxy identifier, the address of the ERC20 token to transfer, the address | ||||
|     /// of the bridge contract, and extra data to be passed to the bridge contract. | ||||
|     function decodeERC20BridgeAssetData(bytes memory assetData) | ||||
|         public | ||||
|         pure | ||||
|         returns ( | ||||
|             bytes4 assetProxyId, | ||||
|             address tokenAddress, | ||||
|             address bridgeAddress, | ||||
|             bytes memory bridgeData | ||||
|         ) | ||||
|     { | ||||
|         assetProxyId = assetData.readBytes4(0); | ||||
|  | ||||
|         require( | ||||
|             assetProxyId == IAssetData(address(0)).ERC20Bridge.selector, | ||||
|             "WRONG_PROXY_ID" | ||||
|         ); | ||||
|  | ||||
|         (tokenAddress, bridgeAddress, bridgeData) = abi.decode( | ||||
|             assetData.slice(4, assetData.length), | ||||
|             (address, address, bytes) | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     /// @dev Reverts if assetData is not of a valid format for its given proxy id. | ||||
|     /// @param assetData AssetProxy compliant asset data. | ||||
|     function revertIfInvalidAssetData(bytes memory assetData) | ||||
|         public | ||||
|         pure | ||||
| @@ -605,6 +345,8 @@ contract LibAssetData { | ||||
|             decodeMultiAssetData(assetData); | ||||
|         } else if (assetProxyId == IAssetData(address(0)).StaticCall.selector) { | ||||
|             decodeStaticCallAssetData(assetData); | ||||
|         } else if (assetProxyId == IAssetData(address(0)).ERC20Bridge.selector) { | ||||
|             decodeERC20BridgeAssetData(assetData); | ||||
|         } else { | ||||
|             revert("WRONG_PROXY_ID"); | ||||
|         } | ||||
|   | ||||
							
								
								
									
										436
									
								
								contracts/dev-utils/contracts/src/LibDydxBalance.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										436
									
								
								contracts/dev-utils/contracts/src/LibDydxBalance.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,436 @@ | ||||
| /* | ||||
|  | ||||
|   Copyright 2019 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.5.16; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetData.sol"; | ||||
| import "@0x/contracts-asset-proxy/contracts/src/interfaces/IDydxBridge.sol"; | ||||
| import "@0x/contracts-asset-proxy/contracts/src/interfaces/IDydx.sol"; | ||||
| import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol"; | ||||
| import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; | ||||
| import "@0x/contracts-utils/contracts/src/LibBytes.sol"; | ||||
| import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; | ||||
| import "@0x/contracts-utils/contracts/src/D18.sol"; | ||||
| import "./LibAssetData.sol"; | ||||
|  | ||||
|  | ||||
| library LibDydxBalance { | ||||
|  | ||||
|     using LibBytes for bytes; | ||||
|     using LibSafeMath for uint256; | ||||
|  | ||||
|     /// @dev Padding % added to the minimum collateralization ratio to | ||||
|     ///      prevent withdrawing exactly the amount that would make an account | ||||
|     ///      insolvent. 1 bps. | ||||
|     int256 private constant MARGIN_RATIO_PADDING = 0.0001e18; | ||||
|  | ||||
|     /// @dev Structure that holds all pertinent info needed to perform a balance | ||||
|     ///      check. | ||||
|     struct BalanceCheckInfo { | ||||
|         IDydx dydx; | ||||
|         address bridgeAddress; | ||||
|         address makerAddress; | ||||
|         address makerTokenAddress; | ||||
|         address takerTokenAddress; | ||||
|         int256 orderMakerToTakerRate; | ||||
|         uint256[] accounts; | ||||
|         IDydxBridge.BridgeAction[] actions; | ||||
|     } | ||||
|  | ||||
|     /// @dev Gets the maker asset allowance for a Dydx bridge order. | ||||
|     /// @param makerAddress The maker of the order. | ||||
|     /// @param bridgeAddress The address of the Dydx bridge. | ||||
|     /// @param dydx The Dydx contract address. | ||||
|     /// @return allowance The maker asset allowance. | ||||
|     function getDydxMakerAllowance(address makerAddress, address bridgeAddress, address dydx) | ||||
|         public | ||||
|         view | ||||
|         returns (uint256 allowance) | ||||
|     { | ||||
|         // Allowance is infinite if the dydx bridge is an operator for the maker. | ||||
|         return IDydx(dydx).getIsLocalOperator(makerAddress, bridgeAddress) | ||||
|             ? uint256(-1) : 0; | ||||
|     } | ||||
|  | ||||
|     /// @dev Gets the maker allowance for a | ||||
|     /// @dev Get the maker asset balance of an order with a `DydxBridge` maker asset. | ||||
|     /// @param order An order with a dydx maker asset. | ||||
|     /// @param dydx The address of the dydx contract. | ||||
|     /// @return balance The maker asset balance. | ||||
|     function getDydxMakerBalance(LibOrder.Order memory order, address dydx) | ||||
|         public | ||||
|         view | ||||
|         returns (uint256 balance) | ||||
|     { | ||||
|         BalanceCheckInfo memory info = _getBalanceCheckInfo(order, dydx); | ||||
|         // Actions must be well-formed. | ||||
|         if (!_areActionsWellFormed(info)) { | ||||
|             return 0; | ||||
|         } | ||||
|         // If the rate we withdraw maker tokens is less than one, the asset | ||||
|         // proxy will throw because we will always transfer less maker tokens | ||||
|         // than asked. | ||||
|         if (_getMakerTokenWithdrawRate(info) < D18.one()) { | ||||
|             return 0; | ||||
|         } | ||||
|         // The maker balance is the smaller of: | ||||
|         return LibSafeMath.min256( | ||||
|             // How many times we can execute all the deposit actions. | ||||
|             _getDepositableMakerAmount(info), | ||||
|             // How many times we can execute all the actions before the an | ||||
|             // account becomes undercollateralized. | ||||
|             _getSolventMakerAmount(info) | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     /// @dev Checks that: | ||||
|     ///      1. Actions are arranged as [...deposits, withdraw]. | ||||
|     ///      2. There is only one deposit for each market ID. | ||||
|     ///      3. Every action has a valid account index. | ||||
|     ///      4. There is exactly one withdraw at the end and it is for the | ||||
|     ///         maker token. | ||||
|     /// @param info State from `_getBalanceCheckInfo()`. | ||||
|     /// @return areWellFormed Whether the actions are well-formed. | ||||
|     function _areActionsWellFormed(BalanceCheckInfo memory info) | ||||
|         internal | ||||
|         view | ||||
|         returns (bool areWellFormed) | ||||
|     { | ||||
|         if (info.actions.length == 0) { | ||||
|             return false; | ||||
|         } | ||||
|         uint256 depositCount = 0; | ||||
|         // Count the number of deposits. | ||||
|         for (; depositCount < info.actions.length; ++depositCount) { | ||||
|             IDydxBridge.BridgeAction memory action = info.actions[depositCount]; | ||||
|             if (action.actionType != IDydxBridge.BridgeActionType.Deposit) { | ||||
|                 break; | ||||
|             } | ||||
|             // Search all prior actions for the same market ID. | ||||
|             uint256 marketId = action.marketId; | ||||
|             for (uint256 j = 0; j < depositCount; ++j) { | ||||
|                 if (info.actions[j].marketId == marketId) { | ||||
|                     // Market ID is not unique. | ||||
|                     return false; | ||||
|                 } | ||||
|             } | ||||
|             // Check that the account index is within the valid range. | ||||
|             if (action.accountIdx >= info.accounts.length) { | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
|         // There must be exactly one withdraw action at the end. | ||||
|         if (depositCount + 1 != info.actions.length) { | ||||
|             return false; | ||||
|         } | ||||
|         IDydxBridge.BridgeAction memory withdraw = info.actions[depositCount]; | ||||
|         if (withdraw.actionType != IDydxBridge.BridgeActionType.Withdraw) { | ||||
|             return false; | ||||
|         } | ||||
|         // And it must be for the maker token. | ||||
|         if (info.dydx.getMarketTokenAddress(withdraw.marketId) != info.makerTokenAddress) { | ||||
|             return false; | ||||
|         } | ||||
|         // Check the account index. | ||||
|         return withdraw.accountIdx < info.accounts.length; | ||||
|     } | ||||
|  | ||||
|     /// @dev Returns the rate at which we withdraw maker tokens. | ||||
|     /// @param info State from `_getBalanceCheckInfo()`. | ||||
|     /// @return makerTokenWithdrawRate Maker token withdraw rate. | ||||
|     function _getMakerTokenWithdrawRate(BalanceCheckInfo memory info) | ||||
|         internal | ||||
|         pure | ||||
|         returns (int256 makerTokenWithdrawRate) | ||||
|     { | ||||
|         // The last action is always a withdraw for the maker token. | ||||
|         IDydxBridge.BridgeAction memory withdraw = info.actions[info.actions.length - 1]; | ||||
|         return _getActionRate(withdraw); | ||||
|     } | ||||
|  | ||||
|     /// @dev Get how much maker asset we can transfer before a deposit fails. | ||||
|     /// @param info State from `_getBalanceCheckInfo()`. | ||||
|     function _getDepositableMakerAmount(BalanceCheckInfo memory info) | ||||
|         internal | ||||
|         view | ||||
|         returns (uint256 depositableMakerAmount) | ||||
|     { | ||||
|         depositableMakerAmount = uint256(-1); | ||||
|         // Take the minimum maker amount from all deposits. | ||||
|         for (uint256 i = 0; i < info.actions.length; ++i) { | ||||
|             IDydxBridge.BridgeAction memory action = info.actions[i]; | ||||
|             // Only looking at deposit actions. | ||||
|             if (action.actionType != IDydxBridge.BridgeActionType.Deposit) { | ||||
|                 continue; | ||||
|             } | ||||
|             // `depositRate` is the rate at which we convert a maker token into | ||||
|             // a taker token for deposit. | ||||
|             int256 depositRate = _getActionRate(action); | ||||
|             // Taker tokens will be transferred to the maker for every fill, so | ||||
|             // we reduce the effective deposit rate if we're depositing the taker | ||||
|             // token. | ||||
|             address depositToken = info.dydx.getMarketTokenAddress(action.marketId); | ||||
|             if (info.takerTokenAddress != address(0) && depositToken == info.takerTokenAddress) { | ||||
|                 depositRate = D18.sub(depositRate, info.orderMakerToTakerRate); | ||||
|             } | ||||
|             // If the deposit rate is > 0, we are limited by the transferrable | ||||
|             // token balance of the maker. | ||||
|             if (depositRate > 0) { | ||||
|                 uint256 supply = _getTransferabeTokenAmount( | ||||
|                     depositToken, | ||||
|                     info.makerAddress, | ||||
|                     address(info.dydx) | ||||
|                 ); | ||||
|                 depositableMakerAmount = LibSafeMath.min256( | ||||
|                     depositableMakerAmount, | ||||
|                     uint256(D18.div(supply, depositRate)) | ||||
|                 ); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// @dev Get how much maker asset we can transfer before an account | ||||
|     ///      becomes insolvent. | ||||
|     /// @param info State from `_getBalanceCheckInfo()`. | ||||
|     function _getSolventMakerAmount(BalanceCheckInfo memory info) | ||||
|         internal | ||||
|         view | ||||
|         returns (uint256 solventMakerAmount) | ||||
|     { | ||||
|         solventMakerAmount = uint256(-1); | ||||
|         assert(info.actions.length >= 1); | ||||
|         IDydxBridge.BridgeAction memory withdraw = info.actions[info.actions.length - 1]; | ||||
|         assert(withdraw.actionType == IDydxBridge.BridgeActionType.Withdraw); | ||||
|         int256 minCr = D18.add(_getMinimumCollateralizationRatio(info.dydx), MARGIN_RATIO_PADDING); | ||||
|         // Loop through the accounts. | ||||
|         for (uint256 accountIdx = 0; accountIdx < info.accounts.length; ++accountIdx) { | ||||
|             (uint256 supplyValue, uint256 borrowValue) = | ||||
|                 _getAccountMarketValues(info, info.accounts[accountIdx]); | ||||
|             // All accounts must currently be solvent. | ||||
|             if (borrowValue != 0 && D18.div(supplyValue, borrowValue) < minCr) { | ||||
|                 return 0; | ||||
|             } | ||||
|             // If this is the same account used to in the withdraw/borrow action, | ||||
|             // compute the maker amount at which it will become insolvent. | ||||
|             if (accountIdx != withdraw.accountIdx) { | ||||
|                 continue; | ||||
|             } | ||||
|             // Compute the deposit/collateralization rate, which is the rate at | ||||
|             // which (USD) value is added to the account across all markets. | ||||
|             int256 dd = 0; | ||||
|             for (uint256 i = 0; i < info.actions.length - 1; ++i) { | ||||
|                 IDydxBridge.BridgeAction memory deposit = info.actions[i]; | ||||
|                 assert(deposit.actionType == IDydxBridge.BridgeActionType.Deposit); | ||||
|                 if (deposit.accountIdx == accountIdx) { | ||||
|                     dd = D18.add( | ||||
|                         dd, | ||||
|                         _getActionRateValue( | ||||
|                             info, | ||||
|                             deposit | ||||
|                         ) | ||||
|                     ); | ||||
|                 } | ||||
|             } | ||||
|             // Compute the borrow/withdraw rate, which is the rate at which | ||||
|             // (USD) value is deducted from the account. | ||||
|             int256 db = _getActionRateValue( | ||||
|                 info, | ||||
|                 withdraw | ||||
|             ); | ||||
|             // If the deposit to withdraw ratio is >= the minimum collateralization | ||||
|             // ratio, then we will never become insolvent at these prices. | ||||
|             if (D18.div(dd, db) >= minCr) { | ||||
|                 continue; | ||||
|             } | ||||
|             // If the adjusted deposit rates are equal, the account will remain | ||||
|             // at the same level of collateralization. | ||||
|             if (D18.mul(minCr, db) == dd) { | ||||
|                 continue; | ||||
|             } | ||||
|             // The collateralization ratio for this account, parameterized by | ||||
|             // `t` (maker amount), is given by: | ||||
|             //      `cr = (supplyValue + t * dd) / (borrowValue + t * db)` | ||||
|             // Solving for `t` gives us: | ||||
|             //      `t = (supplyValue - cr * borrowValue) / (cr * db - dd)` | ||||
|             int256 t = D18.div( | ||||
|                 D18.sub(supplyValue, D18.mul(minCr, borrowValue)), | ||||
|                 D18.sub(D18.mul(minCr, db), dd) | ||||
|             ); | ||||
|             solventMakerAmount = LibSafeMath.min256( | ||||
|                 solventMakerAmount, | ||||
|                 // `t` is in maker token units, so convert it to maker wei. | ||||
|                 _toWei(info.makerTokenAddress, uint256(D18.clip(t))) | ||||
|             ); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// @dev Create a `BalanceCheckInfo` struct. | ||||
|     /// @param order An order with a `DydxBridge` maker asset. | ||||
|     /// @param dydx The address of the Dydx contract. | ||||
|     /// @return info The `BalanceCheckInfo` struct. | ||||
|     function _getBalanceCheckInfo(LibOrder.Order memory order, address dydx) | ||||
|         private | ||||
|         pure | ||||
|         returns (BalanceCheckInfo memory info) | ||||
|     { | ||||
|         bytes memory rawBridgeData; | ||||
|         (, info.makerTokenAddress, info.bridgeAddress, rawBridgeData) = | ||||
|             LibAssetData.decodeERC20BridgeAssetData(order.makerAssetData); | ||||
|         info.dydx = IDydx(dydx); | ||||
|         info.makerAddress = order.makerAddress; | ||||
|         if (order.takerAssetData.length == 36) { | ||||
|             if (order.takerAssetData.readBytes4(0) == IAssetData(0).ERC20Token.selector) { | ||||
|                 (, info.takerTokenAddress) = | ||||
|                     LibAssetData.decodeERC20AssetData(order.takerAssetData); | ||||
|             } | ||||
|         } | ||||
|         info.orderMakerToTakerRate = D18.div(order.takerAssetAmount, order.makerAssetAmount); | ||||
|         (IDydxBridge.BridgeData memory bridgeData) = | ||||
|             abi.decode(rawBridgeData, (IDydxBridge.BridgeData)); | ||||
|         info.accounts = bridgeData.accountNumbers; | ||||
|         info.actions = bridgeData.actions; | ||||
|     } | ||||
|  | ||||
|     /// @dev Returns the conversion rate for an action. | ||||
|     /// @param action A `BridgeAction`. | ||||
|     function _getActionRate(IDydxBridge.BridgeAction memory action) | ||||
|         private | ||||
|         pure | ||||
|         returns (int256 rate) | ||||
|     { | ||||
|         rate = action.conversionRateDenominator == 0 | ||||
|             ? D18.one() | ||||
|             : D18.div( | ||||
|                 action.conversionRateNumerator, | ||||
|                 action.conversionRateDenominator | ||||
|             ); | ||||
|     } | ||||
|  | ||||
|     /// @dev Returns the USD value of an action based on its conversion rate | ||||
|     ///      and market prices. | ||||
|     /// @param info State from `_getBalanceCheckInfo()`. | ||||
|     /// @param action A `BridgeAction`. | ||||
|     function _getActionRateValue( | ||||
|         BalanceCheckInfo memory info, | ||||
|         IDydxBridge.BridgeAction memory action | ||||
|     ) | ||||
|         private | ||||
|         view | ||||
|         returns (int256 value) | ||||
|     { | ||||
|         address toToken = info.dydx.getMarketTokenAddress(action.marketId); | ||||
|         uint256 fromTokenDecimals = LibERC20Token.decimals(info.makerTokenAddress); | ||||
|         uint256 toTokenDecimals = LibERC20Token.decimals(toToken); | ||||
|         // First express the rate as 18-decimal units. | ||||
|         value = toTokenDecimals > fromTokenDecimals | ||||
|             ? int256( | ||||
|                 uint256(_getActionRate(action)) | ||||
|                     .safeDiv(10 ** (toTokenDecimals - fromTokenDecimals)) | ||||
|             ) | ||||
|             : int256( | ||||
|                 uint256(_getActionRate(action)) | ||||
|                     .safeMul(10 ** (fromTokenDecimals - toTokenDecimals)) | ||||
|             ); | ||||
|         // Prices have 18 + (18 - TOKEN_DECIMALS) decimal places because | ||||
|         // consistency is stupid. | ||||
|         uint256 price = info.dydx.getMarketPrice(action.marketId).value; | ||||
|         // Make prices have 18 decimals. | ||||
|         if (toTokenDecimals > 18) { | ||||
|             price = price.safeMul(10 ** (toTokenDecimals - 18)); | ||||
|         } else { | ||||
|             price = price.safeDiv(10 ** (18 - toTokenDecimals)); | ||||
|         } | ||||
|         // The action value is the action rate times the price. | ||||
|         value = D18.mul(price, value); | ||||
|         // Scale by the market premium. | ||||
|         int256 marketPremium = D18.add( | ||||
|             D18.one(), | ||||
|             info.dydx.getMarketMarginPremium(action.marketId).value | ||||
|         ); | ||||
|         if (action.actionType == IDydxBridge.BridgeActionType.Deposit) { | ||||
|             value = D18.div(value, marketPremium); | ||||
|         } else { | ||||
|             value = D18.mul(value, marketPremium); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// @dev Convert a `D18` fraction of 1 token to the equivalent integer wei. | ||||
|     /// @param token Address the of the token. | ||||
|     /// @param units Token units expressed with 18 digit precision. | ||||
|     function _toWei(address token, uint256 units) | ||||
|         private | ||||
|         view | ||||
|         returns (uint256 rate) | ||||
|     { | ||||
|         uint256 decimals = LibERC20Token.decimals(token); | ||||
|         rate = decimals > 18 | ||||
|             ? units.safeMul(10 ** (decimals - 18)) | ||||
|             : units.safeDiv(10 ** (18 - decimals)); | ||||
|     } | ||||
|  | ||||
|     /// @dev Get the global minimum collateralization ratio required for | ||||
|     ///      an account to be considered solvent. | ||||
|     /// @param dydx The Dydx interface. | ||||
|     function _getMinimumCollateralizationRatio(IDydx dydx) | ||||
|         private | ||||
|         view | ||||
|         returns (int256 ratio) | ||||
|     { | ||||
|         IDydx.RiskParams memory riskParams = dydx.getRiskParams(); | ||||
|         return D18.add(D18.one(), D18.toSigned(riskParams.marginRatio.value)); | ||||
|     } | ||||
|  | ||||
|     /// @dev Get the total supply and borrow values for an account across all markets. | ||||
|     /// @param info State from `_getBalanceCheckInfo()`. | ||||
|     /// @param account The Dydx account identifier. | ||||
|     function _getAccountMarketValues(BalanceCheckInfo memory info, uint256 account) | ||||
|         private | ||||
|         view | ||||
|         returns (uint256 supplyValue, uint256 borrowValue) | ||||
|     { | ||||
|         (IDydx.Value memory supplyValue_, IDydx.Value memory borrowValue_) = | ||||
|             info.dydx.getAdjustedAccountValues(IDydx.AccountInfo( | ||||
|                 info.makerAddress, | ||||
|                 account | ||||
|             )); | ||||
|         // Account values have 36 decimal places because dydx likes to make sure | ||||
|         // you're paying attention. | ||||
|         return (supplyValue_.value / 1e18, borrowValue_.value / 1e18); | ||||
|     } | ||||
|  | ||||
|     /// @dev Get the amount of an ERC20 token held by `owner` that can be transferred | ||||
|     ///      by `spender`. | ||||
|     /// @param tokenAddress The address of the ERC20 token. | ||||
|     /// @param owner The address of the token holder. | ||||
|     /// @param spender The address of the token spender. | ||||
|     function _getTransferabeTokenAmount( | ||||
|         address tokenAddress, | ||||
|         address owner, | ||||
|         address spender | ||||
|     ) | ||||
|         private | ||||
|         view | ||||
|         returns (uint256 transferableAmount) | ||||
|     { | ||||
|         return LibSafeMath.min256( | ||||
|             LibERC20Token.allowance(tokenAddress, owner, spender), | ||||
|             LibERC20Token.balanceOf(tokenAddress, owner) | ||||
|         ); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										227
									
								
								contracts/dev-utils/contracts/src/LibOrderTransferSimulation.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										227
									
								
								contracts/dev-utils/contracts/src/LibOrderTransferSimulation.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,227 @@ | ||||
| /* | ||||
|  | ||||
|   Copyright 2019 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.5.16; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
|  | ||||
| import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol"; | ||||
| import "@0x/contracts-exchange/contracts/src/libs/LibExchangeRichErrorDecoder.sol"; | ||||
| import "@0x/contracts-exchange-libs/contracts/src/LibExchangeRichErrors.sol"; | ||||
| import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; | ||||
| import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol"; | ||||
| import "@0x/contracts-utils/contracts/src/LibBytes.sol"; | ||||
|  | ||||
|  | ||||
| library LibOrderTransferSimulation { | ||||
|     using LibBytes for bytes; | ||||
|  | ||||
|     enum OrderTransferResults { | ||||
|         TakerAssetDataFailed,     // Transfer of takerAsset failed | ||||
|         MakerAssetDataFailed,     // Transfer of makerAsset failed | ||||
|         TakerFeeAssetDataFailed,  // Transfer of takerFeeAsset failed | ||||
|         MakerFeeAssetDataFailed,  // Transfer of makerFeeAsset failed | ||||
|         TransfersSuccessful       // All transfers in the order were successful | ||||
|     } | ||||
|  | ||||
|     // NOTE(jalextowle): This is a random address that we use to avoid issues that addresses like `address(1)` | ||||
|     // may cause later. | ||||
|     address constant internal UNUSED_ADDRESS = address(0x377f698C4c287018D09b516F415317aEC5919332); | ||||
|  | ||||
|     // keccak256(abi.encodeWithSignature("Error(string)", "TRANSFERS_SUCCESSFUL")); | ||||
|     bytes32 constant internal _TRANSFERS_SUCCESSFUL_RESULT_HASH = 0xf43f26ea5a94b478394a975e856464913dc1a8a1ca70939d974aa7c238aa0ce0; | ||||
|  | ||||
|     /// @dev Simulates the maker transfers within an order and returns the index of the first failed transfer. | ||||
|     /// @param order The order to simulate transfers for. | ||||
|     /// @param takerAddress The address of the taker that will fill the order. | ||||
|     /// @param takerAssetFillAmount The amount of takerAsset that the taker wished to fill. | ||||
|     /// @return The index of the first failed transfer (or 4 if all transfers are successful). | ||||
|     function getSimulatedOrderMakerTransferResults( | ||||
|         address exchange, | ||||
|         LibOrder.Order memory order, | ||||
|         address takerAddress, | ||||
|         uint256 takerAssetFillAmount | ||||
|     ) | ||||
|         public | ||||
|         returns (OrderTransferResults orderTransferResults) | ||||
|     { | ||||
|         LibFillResults.FillResults memory fillResults = LibFillResults.calculateFillResults( | ||||
|             order, | ||||
|             takerAssetFillAmount, | ||||
|             IExchange(exchange).protocolFeeMultiplier(), | ||||
|             tx.gasprice | ||||
|         ); | ||||
|  | ||||
|         bytes[] memory assetData = new bytes[](2); | ||||
|         address[] memory fromAddresses = new address[](2); | ||||
|         address[] memory toAddresses = new address[](2); | ||||
|         uint256[] memory amounts = new uint256[](2); | ||||
|  | ||||
|         // Transfer `makerAsset` from maker to taker | ||||
|         assetData[0] = order.makerAssetData; | ||||
|         fromAddresses[0] = order.makerAddress; | ||||
|         toAddresses[0] = takerAddress == address(0) ? UNUSED_ADDRESS : takerAddress; | ||||
|         amounts[0] = fillResults.makerAssetFilledAmount; | ||||
|  | ||||
|         // Transfer `makerFeeAsset` from maker to feeRecipient | ||||
|         assetData[1] = order.makerFeeAssetData; | ||||
|         fromAddresses[1] = order.makerAddress; | ||||
|         toAddresses[1] = order.feeRecipientAddress == address(0) ? UNUSED_ADDRESS : order.feeRecipientAddress; | ||||
|         amounts[1] = fillResults.makerFeePaid; | ||||
|  | ||||
|         return _simulateTransferFromCalls( | ||||
|             exchange, | ||||
|             assetData, | ||||
|             fromAddresses, | ||||
|             toAddresses, | ||||
|             amounts | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     /// @dev Simulates all of the transfers within an order and returns the index of the first failed transfer. | ||||
|     /// @param order The order to simulate transfers for. | ||||
|     /// @param takerAddress The address of the taker that will fill the order. | ||||
|     /// @param takerAssetFillAmount The amount of takerAsset that the taker wished to fill. | ||||
|     /// @return The index of the first failed transfer (or 4 if all transfers are successful). | ||||
|     function getSimulatedOrderTransferResults( | ||||
|         address exchange, | ||||
|         LibOrder.Order memory order, | ||||
|         address takerAddress, | ||||
|         uint256 takerAssetFillAmount | ||||
|     ) | ||||
|         public | ||||
|         returns (OrderTransferResults orderTransferResults) | ||||
|     { | ||||
|         LibFillResults.FillResults memory fillResults = LibFillResults.calculateFillResults( | ||||
|             order, | ||||
|             takerAssetFillAmount, | ||||
|             IExchange(exchange).protocolFeeMultiplier(), | ||||
|             tx.gasprice | ||||
|         ); | ||||
|  | ||||
|         // Create input arrays | ||||
|         bytes[] memory assetData = new bytes[](4); | ||||
|         address[] memory fromAddresses = new address[](4); | ||||
|         address[] memory toAddresses = new address[](4); | ||||
|         uint256[] memory amounts = new uint256[](4); | ||||
|  | ||||
|         // Transfer `takerAsset` from taker to maker | ||||
|         assetData[0] = order.takerAssetData; | ||||
|         fromAddresses[0] = takerAddress; | ||||
|         toAddresses[0] = order.makerAddress; | ||||
|         amounts[0] = takerAssetFillAmount; | ||||
|  | ||||
|         // Transfer `makerAsset` from maker to taker | ||||
|         assetData[1] = order.makerAssetData; | ||||
|         fromAddresses[1] = order.makerAddress; | ||||
|         toAddresses[1] = takerAddress == address(0) ? UNUSED_ADDRESS : takerAddress; | ||||
|         amounts[1] = fillResults.makerAssetFilledAmount; | ||||
|  | ||||
|         // Transfer `takerFeeAsset` from taker to feeRecipient | ||||
|         assetData[2] = order.takerFeeAssetData; | ||||
|         fromAddresses[2] = takerAddress; | ||||
|         toAddresses[2] = order.feeRecipientAddress == address(0) ? UNUSED_ADDRESS : order.feeRecipientAddress; | ||||
|         amounts[2] = fillResults.takerFeePaid; | ||||
|  | ||||
|         // Transfer `makerFeeAsset` from maker to feeRecipient | ||||
|         assetData[3] = order.makerFeeAssetData; | ||||
|         fromAddresses[3] = order.makerAddress; | ||||
|         toAddresses[3] = order.feeRecipientAddress == address(0) ? UNUSED_ADDRESS : order.feeRecipientAddress; | ||||
|         amounts[3] = fillResults.makerFeePaid; | ||||
|  | ||||
|         return _simulateTransferFromCalls( | ||||
|             exchange, | ||||
|             assetData, | ||||
|             fromAddresses, | ||||
|             toAddresses, | ||||
|             amounts | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     /// @dev Simulates all of the transfers for each given order and returns the indices of each first failed transfer. | ||||
|     /// @param orders Array of orders to individually simulate transfers for. | ||||
|     /// @param takerAddresses Array of addresses of takers that will fill each order. | ||||
|     /// @param takerAssetFillAmounts Array of amounts of takerAsset that will be filled for each order. | ||||
|     /// @return The indices of the first failed transfer (or 4 if all transfers are successful) for each order. | ||||
|     function getSimulatedOrdersTransferResults( | ||||
|         address exchange, | ||||
|         LibOrder.Order[] memory orders, | ||||
|         address[] memory takerAddresses, | ||||
|         uint256[] memory takerAssetFillAmounts | ||||
|     ) | ||||
|         public | ||||
|         returns (OrderTransferResults[] memory orderTransferResults) | ||||
|     { | ||||
|         uint256 length = orders.length; | ||||
|         orderTransferResults = new OrderTransferResults[](length); | ||||
|         for (uint256 i = 0; i != length; i++) { | ||||
|             orderTransferResults[i] = getSimulatedOrderTransferResults( | ||||
|                 exchange, | ||||
|                 orders[i], | ||||
|                 takerAddresses[i], | ||||
|                 takerAssetFillAmounts[i] | ||||
|             ); | ||||
|         } | ||||
|         return orderTransferResults; | ||||
|     } | ||||
|  | ||||
|     /// @dev Makes the simulation call with information about the transfers and processes | ||||
|     ///      the returndata. | ||||
|     /// @param assetData The assetdata to use to make transfers. | ||||
|     /// @param fromAddresses The addresses to transfer funds. | ||||
|     /// @param toAddresses The addresses that will receive funds | ||||
|     /// @param amounts The amounts involved in the transfer. | ||||
|     function _simulateTransferFromCalls( | ||||
|         address exchange, | ||||
|         bytes[] memory assetData, | ||||
|         address[] memory fromAddresses, | ||||
|         address[] memory toAddresses, | ||||
|         uint256[] memory amounts | ||||
|     ) | ||||
|         private | ||||
|         returns (OrderTransferResults orderTransferResults) | ||||
|     { | ||||
|         // Encode data for `simulateDispatchTransferFromCalls(assetData, fromAddresses, toAddresses, amounts)` | ||||
|         bytes memory simulateDispatchTransferFromCallsData = abi.encodeWithSelector( | ||||
|             IExchange(address(0)).simulateDispatchTransferFromCalls.selector, | ||||
|             assetData, | ||||
|             fromAddresses, | ||||
|             toAddresses, | ||||
|             amounts | ||||
|         ); | ||||
|  | ||||
|         // Perform call and catch revert | ||||
|         (, bytes memory returnData) = address(exchange).call(simulateDispatchTransferFromCallsData); | ||||
|  | ||||
|         bytes4 selector = returnData.readBytes4(0); | ||||
|         if (selector == LibExchangeRichErrors.AssetProxyDispatchErrorSelector()) { | ||||
|             // Decode AssetProxyDispatchError and return index of failed transfer | ||||
|             (, bytes32 failedTransferIndex,) = LibExchangeRichErrorDecoder.decodeAssetProxyDispatchError(returnData); | ||||
|             return OrderTransferResults(uint8(uint256(failedTransferIndex))); | ||||
|         } else if (selector == LibExchangeRichErrors.AssetProxyTransferErrorSelector()) { | ||||
|             // Decode AssetProxyTransferError and return index of failed transfer | ||||
|             (bytes32 failedTransferIndex, ,) = LibExchangeRichErrorDecoder.decodeAssetProxyTransferError(returnData); | ||||
|             return OrderTransferResults(uint8(uint256(failedTransferIndex))); | ||||
|         } else if (keccak256(returnData) == _TRANSFERS_SUCCESSFUL_RESULT_HASH) { | ||||
|             // All transfers were successful | ||||
|             return OrderTransferResults.TransfersSuccessful; | ||||
|         } else { | ||||
|             revert("UNKNOWN_RETURN_DATA"); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -16,7 +16,7 @@ | ||||
|  | ||||
| */ | ||||
|  | ||||
| pragma solidity ^0.5.5; | ||||
| pragma solidity ^0.5.16; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol"; | ||||
| @@ -24,7 +24,7 @@ import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; | ||||
| import "@0x/contracts-utils/contracts/src/LibBytes.sol"; | ||||
|  | ||||
|  | ||||
| contract LibTransactionDecoder { | ||||
| library LibTransactionDecoder { | ||||
|  | ||||
|     using LibBytes for bytes; | ||||
|  | ||||
|   | ||||
| @@ -28,9 +28,8 @@ import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol"; | ||||
| import "@0x/contracts-utils/contracts/src/LibBytes.sol"; | ||||
|  | ||||
|  | ||||
| contract OrderTransferSimulationUtils is | ||||
|     LibExchangeRichErrorDecoder | ||||
| { | ||||
| contract OrderTransferSimulationUtils { | ||||
|  | ||||
|     using LibBytes for bytes; | ||||
|  | ||||
|     enum OrderTransferResults { | ||||
| @@ -41,6 +40,10 @@ contract OrderTransferSimulationUtils is | ||||
|         TransfersSuccessful       // All transfers in the order were successful | ||||
|     } | ||||
|  | ||||
|     // NOTE(jalextowle): This is a random address that we use to avoid issues that addresses like `address(1)` | ||||
|     // may cause later. | ||||
|     address constant internal UNUSED_ADDRESS = address(0x377f698C4c287018D09b516F415317aEC5919332); | ||||
|  | ||||
|     // keccak256(abi.encodeWithSignature("Error(string)", "TRANSFERS_SUCCESSFUL")); | ||||
|     bytes32 constant internal _TRANSFERS_SUCCESSFUL_RESULT_HASH = 0xf43f26ea5a94b478394a975e856464913dc1a8a1ca70939d974aa7c238aa0ce0; | ||||
|  | ||||
| @@ -82,13 +85,13 @@ contract OrderTransferSimulationUtils is | ||||
|         // Transfer `makerAsset` from maker to taker | ||||
|         assetData[0] = order.makerAssetData; | ||||
|         fromAddresses[0] = order.makerAddress; | ||||
|         toAddresses[0] = takerAddress; | ||||
|         toAddresses[0] = takerAddress == address(0) ? UNUSED_ADDRESS : takerAddress; | ||||
|         amounts[0] = fillResults.makerAssetFilledAmount; | ||||
|  | ||||
|         // Transfer `makerFeeAsset` from maker to feeRecipient | ||||
|         assetData[1] = order.makerFeeAssetData; | ||||
|         fromAddresses[1] = order.makerAddress; | ||||
|         toAddresses[1] = order.feeRecipientAddress; | ||||
|         toAddresses[1] = order.feeRecipientAddress == address(0) ? UNUSED_ADDRESS : order.feeRecipientAddress; | ||||
|         amounts[1] = fillResults.makerFeePaid; | ||||
|  | ||||
|         return _simulateTransferFromCalls( | ||||
| @@ -134,19 +137,19 @@ contract OrderTransferSimulationUtils is | ||||
|         // Transfer `makerAsset` from maker to taker | ||||
|         assetData[1] = order.makerAssetData; | ||||
|         fromAddresses[1] = order.makerAddress; | ||||
|         toAddresses[1] = takerAddress; | ||||
|         toAddresses[1] = takerAddress == address(0) ? UNUSED_ADDRESS : takerAddress; | ||||
|         amounts[1] = fillResults.makerAssetFilledAmount; | ||||
|  | ||||
|         // Transfer `takerFeeAsset` from taker to feeRecipient | ||||
|         assetData[2] = order.takerFeeAssetData; | ||||
|         fromAddresses[2] = takerAddress; | ||||
|         toAddresses[2] = order.feeRecipientAddress; | ||||
|         toAddresses[2] = order.feeRecipientAddress == address(0) ? UNUSED_ADDRESS : order.feeRecipientAddress; | ||||
|         amounts[2] = fillResults.takerFeePaid; | ||||
|  | ||||
|         // Transfer `makerFeeAsset` from maker to feeRecipient | ||||
|         assetData[3] = order.makerFeeAssetData; | ||||
|         fromAddresses[3] = order.makerAddress; | ||||
|         toAddresses[3] = order.feeRecipientAddress; | ||||
|         toAddresses[3] = order.feeRecipientAddress == address(0) ? UNUSED_ADDRESS : order.feeRecipientAddress; | ||||
|         amounts[3] = fillResults.makerFeePaid; | ||||
|  | ||||
|         return _simulateTransferFromCalls( | ||||
| @@ -212,11 +215,13 @@ contract OrderTransferSimulationUtils is | ||||
|         bytes4 selector = returnData.readBytes4(0); | ||||
|         if (selector == LibExchangeRichErrors.AssetProxyDispatchErrorSelector()) { | ||||
|             // Decode AssetProxyDispatchError and return index of failed transfer | ||||
|             (, bytes32 failedTransferIndex,) = decodeAssetProxyDispatchError(returnData); | ||||
|             (, bytes32 failedTransferIndex,) = LibExchangeRichErrorDecoder | ||||
|                 .decodeAssetProxyDispatchError(returnData); | ||||
|             return OrderTransferResults(uint8(uint256(failedTransferIndex))); | ||||
|         } else if (selector == LibExchangeRichErrors.AssetProxyTransferErrorSelector()) { | ||||
|             // Decode AssetProxyTransferError and return index of failed transfer | ||||
|             (bytes32 failedTransferIndex, ,) = decodeAssetProxyTransferError(returnData); | ||||
|             (bytes32 failedTransferIndex, ,) = LibExchangeRichErrorDecoder | ||||
|                 .decodeAssetProxyTransferError(returnData); | ||||
|             return OrderTransferResults(uint8(uint256(failedTransferIndex))); | ||||
|         } else if (keccak256(returnData) == _TRANSFERS_SUCCESSFUL_RESULT_HASH) { | ||||
|             // All transfers were successful | ||||
|   | ||||
| @@ -16,30 +16,26 @@ | ||||
|  | ||||
| */ | ||||
|  | ||||
| pragma solidity ^0.5.9; | ||||
| pragma solidity ^0.5.16; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol"; | ||||
| import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; | ||||
| import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol"; | ||||
| import "@0x/contracts-utils/contracts/src/LibBytes.sol"; | ||||
| import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; | ||||
| import "./Addresses.sol"; | ||||
| import "./AssetBalance.sol"; | ||||
| import "./LibAssetData.sol"; | ||||
| import "./OrderTransferSimulationUtils.sol"; | ||||
| import "./LibOrderTransferSimulation.sol"; | ||||
|  | ||||
|  | ||||
| contract OrderValidationUtils is | ||||
|     LibAssetData, | ||||
|     OrderTransferSimulationUtils | ||||
|     Addresses, | ||||
|     AssetBalance | ||||
| { | ||||
|     using LibBytes for bytes; | ||||
|     using LibSafeMath for uint256; | ||||
|  | ||||
|     constructor (address _exchange) | ||||
|         public | ||||
|         LibAssetData(_exchange) | ||||
|     {} | ||||
|  | ||||
|     /// @dev Fetches all order-relevant information needed to validate if the supplied order is fillable. | ||||
|     /// @param order The order structure. | ||||
|     /// @param signature Signature provided by maker that proves the order's authenticity. | ||||
| @@ -59,23 +55,22 @@ contract OrderValidationUtils is | ||||
|         ) | ||||
|     { | ||||
|         // Get info specific to order | ||||
|         orderInfo = _EXCHANGE.getOrderInfo(order); | ||||
|         orderInfo = IExchange(exchangeAddress).getOrderInfo(order); | ||||
|  | ||||
|         // Validate the maker's signature | ||||
|         address makerAddress = order.makerAddress; | ||||
|         isValidSignature = _EXCHANGE.isValidOrderSignature( | ||||
|         isValidSignature = IExchange(exchangeAddress).isValidOrderSignature( | ||||
|             order, | ||||
|             signature | ||||
|         ); | ||||
|  | ||||
|         // Get the transferable amount of the `makerAsset` | ||||
|         uint256 transferableMakerAssetAmount = getTransferableAssetAmount(makerAddress, order.makerAssetData); | ||||
|         uint256 transferableMakerAssetAmount = _getTransferableConvertedMakerAssetAmount( | ||||
|             order | ||||
|         ); | ||||
|  | ||||
|         // Assign to stack variables to reduce redundant mloads/sloads | ||||
|         uint256 takerAssetAmount = order.takerAssetAmount; | ||||
|         uint256 makerFee = order.makerFee; | ||||
|  | ||||
|         // Get the amount of `takerAsset` that is transferable to maker given the transferability of `makerAsset`, `makerFeeAsset`, | ||||
|         // Get the amount of `takerAsset` that is transferable to maker given the | ||||
|         // transferability of `makerAsset`, `makerFeeAsset`, | ||||
|         // and the total amounts specified in the order | ||||
|         uint256 transferableTakerAssetAmount; | ||||
|         if (order.makerAssetData.equals(order.makerFeeAssetData)) { | ||||
| @@ -83,32 +78,35 @@ contract OrderValidationUtils is | ||||
|             // transferableMakerAssetAmount / (makerAssetAmount + makerFee) | ||||
|             transferableTakerAssetAmount = LibMath.getPartialAmountFloor( | ||||
|                 transferableMakerAssetAmount, | ||||
|                 order.makerAssetAmount.safeAdd(makerFee), | ||||
|                 takerAssetAmount | ||||
|                 order.makerAssetAmount.safeAdd(order.makerFee), | ||||
|                 order.takerAssetAmount | ||||
|             ); | ||||
|         } else { | ||||
|             // If `makerFee` is 0, the % that can be filled is (transferableMakerAssetAmount / makerAssetAmount) | ||||
|             if (makerFee == 0) { | ||||
|             if (order.makerFee == 0) { | ||||
|                 transferableTakerAssetAmount = LibMath.getPartialAmountFloor( | ||||
|                     transferableMakerAssetAmount, | ||||
|                     order.makerAssetAmount, | ||||
|                     takerAssetAmount | ||||
|                     order.takerAssetAmount | ||||
|                 ); | ||||
|  | ||||
|             // If `makerAsset` does not equal `makerFeeAsset`, the % that can be filled is the lower of | ||||
|             // (transferableMakerAssetAmount / makerAssetAmount) and (transferableMakerAssetFeeAmount / makerFee) | ||||
|             } else { | ||||
|                 // Get the transferable amount of the `makerFeeAsset` | ||||
|                 uint256 transferableMakerFeeAssetAmount = getTransferableAssetAmount(makerAddress, order.makerFeeAssetData); | ||||
|                 uint256 transferableMakerFeeAssetAmount = getTransferableAssetAmount( | ||||
|                     makerAddress, | ||||
|                     order.makerFeeAssetData | ||||
|                 ); | ||||
|                 uint256 transferableMakerToTakerAmount = LibMath.getPartialAmountFloor( | ||||
|                     transferableMakerAssetAmount, | ||||
|                     order.makerAssetAmount, | ||||
|                     takerAssetAmount | ||||
|                     order.takerAssetAmount | ||||
|                 ); | ||||
|                 uint256 transferableMakerFeeToTakerAmount = LibMath.getPartialAmountFloor( | ||||
|                     transferableMakerFeeAssetAmount, | ||||
|                     makerFee, | ||||
|                     takerAssetAmount | ||||
|                     order.makerFee, | ||||
|                     order.takerAssetAmount | ||||
|                 ); | ||||
|                 transferableTakerAssetAmount = LibSafeMath.min256(transferableMakerToTakerAmount, transferableMakerFeeToTakerAmount); | ||||
|             } | ||||
| @@ -116,16 +114,21 @@ contract OrderValidationUtils is | ||||
|  | ||||
|         // `fillableTakerAssetAmount` is the lower of the order's remaining `takerAssetAmount` and the `transferableTakerAssetAmount` | ||||
|         fillableTakerAssetAmount = LibSafeMath.min256( | ||||
|             takerAssetAmount.safeSub(orderInfo.orderTakerAssetFilledAmount), | ||||
|             order.takerAssetAmount.safeSub(orderInfo.orderTakerAssetFilledAmount), | ||||
|             transferableTakerAssetAmount | ||||
|         ); | ||||
|  | ||||
|         // Execute the maker transfers. | ||||
|         fillableTakerAssetAmount = getSimulatedOrderMakerTransferResults( | ||||
|             order, | ||||
|             order.takerAddress, | ||||
|             fillableTakerAssetAmount | ||||
|         ) == OrderTransferResults.TransfersSuccessful ? fillableTakerAssetAmount : 0; | ||||
|         // Ensure that all of the asset data is valid. Fee asset data only needs | ||||
|         // to be valid if the fees are nonzero. | ||||
|         if (!_areOrderAssetDatasValid(order)) { | ||||
|             fillableTakerAssetAmount = 0; | ||||
|         } | ||||
|  | ||||
|         // If the order is not fillable, then the fillable taker asset amount is | ||||
|         // zero by definition. | ||||
|         if (orderInfo.orderStatus != LibOrder.OrderStatus.FILLABLE) { | ||||
|             fillableTakerAssetAmount = 0; | ||||
|         } | ||||
|  | ||||
|         return (orderInfo, fillableTakerAssetAmount, isValidSignature); | ||||
|     } | ||||
| @@ -163,7 +166,7 @@ contract OrderValidationUtils is | ||||
|         return (ordersInfo, fillableTakerAssetAmounts, isValidSignature); | ||||
|     } | ||||
|  | ||||
|     /// @dev Gets the amount of an asset transferable by the owner. | ||||
|     /// @dev Gets the amount of an asset transferable by the maker of an order. | ||||
|     /// @param ownerAddress Address of the owner of the asset. | ||||
|     /// @param assetData Description of tokens, per the AssetProxy contract specification. | ||||
|     /// @return The amount of the asset tranferable by the owner. | ||||
| @@ -173,11 +176,104 @@ contract OrderValidationUtils is | ||||
|     /// the individual asset amounts located within the `assetData`. | ||||
|     function getTransferableAssetAmount(address ownerAddress, bytes memory assetData) | ||||
|         public | ||||
|         view | ||||
|         returns (uint256 transferableAssetAmount) | ||||
|     { | ||||
|         (uint256 balance, uint256 allowance) = getBalanceAndAssetProxyAllowance(ownerAddress, assetData); | ||||
|         (uint256 balance, uint256 allowance) = getBalanceAndAssetProxyAllowance( | ||||
|             ownerAddress, | ||||
|             assetData | ||||
|         ); | ||||
|         transferableAssetAmount = LibSafeMath.min256(balance, allowance); | ||||
|         return transferableAssetAmount; | ||||
|     } | ||||
|  | ||||
|     /// @dev Gets the amount of an asset transferable by the maker of an order. | ||||
|     ///      Similar to `getTransferableAssetAmount()`, but can handle maker asset | ||||
|     ///      types that depend on taker assets being transferred first (e.g., Dydx bridge). | ||||
|     /// @param order The order. | ||||
|     /// @return transferableAssetAmount Amount of maker asset that can be transferred. | ||||
|     function _getTransferableConvertedMakerAssetAmount( | ||||
|         LibOrder.Order memory order | ||||
|     ) | ||||
|         internal | ||||
|         returns (uint256 transferableAssetAmount) | ||||
|     { | ||||
|         (uint256 balance, uint256 allowance) = _getConvertibleMakerBalanceAndAssetProxyAllowance(order); | ||||
|         transferableAssetAmount = LibSafeMath.min256(balance, allowance); | ||||
|         return LibSafeMath.min256(transferableAssetAmount, order.makerAssetAmount); | ||||
|     } | ||||
|  | ||||
|     /// @dev Checks that the asset data contained in a ZeroEx is valid and returns | ||||
|     /// a boolean that indicates whether or not the asset data was found to be valid. | ||||
|     /// @param order A ZeroEx order to validate. | ||||
|     /// @return The validatity of the asset data. | ||||
|     function _areOrderAssetDatasValid(LibOrder.Order memory order) | ||||
|         internal | ||||
|         pure | ||||
|         returns (bool) | ||||
|     { | ||||
|         return _isAssetDataValid(order.makerAssetData) && | ||||
|             (order.makerFee == 0 || _isAssetDataValid(order.makerFeeAssetData)) && | ||||
|             _isAssetDataValid(order.takerAssetData) && | ||||
|             (order.takerFee == 0 || _isAssetDataValid(order.takerFeeAssetData)); | ||||
|     } | ||||
|  | ||||
|     /// @dev This function handles the edge cases around taker validation. This function | ||||
|     ///      currently attempts to find duplicate ERC721 token's in the taker | ||||
|     ///      multiAssetData. | ||||
|     /// @param assetData The asset data that should be validated. | ||||
|     /// @return Whether or not the order should be considered valid. | ||||
|     function _isAssetDataValid(bytes memory assetData) | ||||
|         internal | ||||
|         pure | ||||
|         returns (bool) | ||||
|     { | ||||
|         // Asset data must be composed of an asset proxy Id and a bytes segment with | ||||
|         // a length divisible by 32. | ||||
|         if (assetData.length % 32 != 4) { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         // Only process the taker asset data if it is multiAssetData. | ||||
|         bytes4 assetProxyId = assetData.readBytes4(0); | ||||
|         if (assetProxyId != IAssetData(address(0)).MultiAsset.selector) { | ||||
|             return true; | ||||
|         } | ||||
|  | ||||
|         // Get array of values and array of assetDatas | ||||
|         (, , bytes[] memory nestedAssetData) = | ||||
|             LibAssetData.decodeMultiAssetData(assetData); | ||||
|  | ||||
|         uint256 length = nestedAssetData.length; | ||||
|         for (uint256 i = 0; i != length; i++) { | ||||
|             // TODO(jalextowle): Implement similar validation for non-fungible ERC1155 asset data. | ||||
|             bytes4 nestedAssetProxyId = nestedAssetData[i].readBytes4(0); | ||||
|             if (nestedAssetProxyId == IAssetData(address(0)).ERC721Token.selector) { | ||||
|                 if (_isAssetDataDuplicated(nestedAssetData, i)) { | ||||
|                     return false; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     /// Determines whether or not asset data is duplicated later in the nested asset data. | ||||
|     /// @param nestedAssetData The asset data to scan for duplication. | ||||
|     /// @param startIdx The index where the scan should begin. | ||||
|     /// @return A boolean reflecting whether or not the starting asset data was duplicated. | ||||
|     function _isAssetDataDuplicated( | ||||
|         bytes[] memory nestedAssetData, | ||||
|         uint256 startIdx | ||||
|     ) | ||||
|         internal | ||||
|         pure | ||||
|         returns (bool) | ||||
|     { | ||||
|         uint256 length = nestedAssetData.length; | ||||
|         for (uint256 i = startIdx + 1; i < length; i++) { | ||||
|             if (nestedAssetData[startIdx].equals(nestedAssetData[i])) { | ||||
|                 return true; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
							
								
								
									
										181
									
								
								contracts/dev-utils/contracts/test/TestDydx.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										181
									
								
								contracts/dev-utils/contracts/test/TestDydx.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,181 @@ | ||||
| /* | ||||
|  | ||||
|   Copyright 2019 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.5.16; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "@0x/contracts-asset-proxy/contracts/src/interfaces/IDydx.sol"; | ||||
| import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol"; | ||||
|  | ||||
|  | ||||
| // solhint-disable separate-by-one-line-in-contract | ||||
| contract TestDydx { | ||||
|  | ||||
|     struct OperatorConfig { | ||||
|         address owner; | ||||
|         address operator; | ||||
|     } | ||||
|  | ||||
|     struct AccountConfig { | ||||
|         address owner; | ||||
|         uint256 accountId; | ||||
|         int256[] balances; | ||||
|     } | ||||
|  | ||||
|     struct MarketInfo { | ||||
|         address token; | ||||
|         uint256 price; | ||||
|     } | ||||
|  | ||||
|     struct TestConfig { | ||||
|         uint256 marginRatio; | ||||
|         OperatorConfig[] operators; | ||||
|         AccountConfig[] accounts; | ||||
|         MarketInfo[] markets; | ||||
|     } | ||||
|  | ||||
|     mapping (bytes32 => bool) private _operators; | ||||
|     mapping (bytes32 => int256) private _balance; | ||||
|     MarketInfo[] private _markets; | ||||
|     uint256 private _marginRatio; | ||||
|  | ||||
|     constructor(TestConfig memory config) public { | ||||
|         _marginRatio = config.marginRatio; | ||||
|         for (uint256 marketId = 0; marketId < config.markets.length; ++marketId) { | ||||
|             _markets.push(config.markets[marketId]); | ||||
|         } | ||||
|         for (uint256 i = 0; i < config.operators.length; ++i) { | ||||
|             OperatorConfig memory op = config.operators[i]; | ||||
|             _operators[_getOperatorHash(op.owner, op.operator)] = true; | ||||
|         } | ||||
|         for (uint256 i = 0; i < config.accounts.length; ++i) { | ||||
|             AccountConfig memory acct = config.accounts[i]; | ||||
|             for (uint256 marketId = 0; marketId < acct.balances.length; ++marketId) { | ||||
|                 _balance[_getBalanceHash(acct.owner, acct.accountId, marketId)] = | ||||
|                     acct.balances[marketId]; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     function getIsLocalOperator( | ||||
|         address owner, | ||||
|         address operator | ||||
|     ) | ||||
|         external | ||||
|         view | ||||
|         returns (bool isLocalOperator) | ||||
|     { | ||||
|         return _operators[_getOperatorHash(owner, operator)]; | ||||
|     } | ||||
|  | ||||
|     function getMarketTokenAddress( | ||||
|         uint256 marketId | ||||
|     ) | ||||
|         external | ||||
|         view | ||||
|         returns (address tokenAddress) | ||||
|     { | ||||
|         return _markets[marketId].token; | ||||
|     } | ||||
|  | ||||
|     function getRiskParams() | ||||
|         external | ||||
|         view | ||||
|         returns (IDydx.RiskParams memory riskParams) | ||||
|     { | ||||
|         return IDydx.RiskParams({ | ||||
|             marginRatio: IDydx.D256(_marginRatio), | ||||
|             liquidationSpread: IDydx.D256(0), | ||||
|             earningsRate: IDydx.D256(0), | ||||
|             minBorrowedValue: IDydx.Value(0) | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     function getAdjustedAccountValues( | ||||
|         IDydx.AccountInfo calldata account | ||||
|     ) | ||||
|         external | ||||
|         view | ||||
|         returns (IDydx.Value memory supplyValue, IDydx.Value memory borrowValue) | ||||
|     { | ||||
|         for (uint256 marketId = 0; marketId < _markets.length; ++marketId) { | ||||
|             int256 balance = | ||||
|                 _balance[_getBalanceHash(account.owner, account.number, marketId)]; | ||||
|             // Account values have 36 decimal places. | ||||
|             // `getMarketPrice()` returns a unit with | ||||
|             // 18 + (18 - TOKEN_DECIMALS) decimal places so multiplying the price | ||||
|             // with the wei balance will result in a 36 decimal value. | ||||
|             balance = balance * int256(getMarketPrice(marketId).value); | ||||
|             if (balance >= 0) { | ||||
|                 supplyValue.value += uint256(balance); | ||||
|             } else { | ||||
|                 borrowValue.value += uint256(-balance); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     function getMarketMarginPremium(uint256) | ||||
|         external | ||||
|         view | ||||
|         returns (IDydx.D256 memory premium) | ||||
|     { | ||||
|         // Return 0. | ||||
|         return premium; | ||||
|     } | ||||
|  | ||||
|     function getMarketPrice( | ||||
|         uint256 marketId | ||||
|     ) | ||||
|         public | ||||
|         view | ||||
|         returns (IDydx.Price memory price) | ||||
|     { | ||||
|         MarketInfo memory market = _markets[marketId]; | ||||
|         uint256 decimals = LibERC20Token.decimals(market.token); | ||||
|         price.value = _markets[marketId].price; | ||||
|         // Market prices have 18 + (18 - TOKEN_DECIMALS) | ||||
|         if (decimals > 18) { | ||||
|             price.value /= 10 ** (decimals - 18); | ||||
|         } else { | ||||
|             price.value *= 10 ** (18 - decimals); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     function _getOperatorHash(address owner, address operator) | ||||
|         private | ||||
|         pure | ||||
|         returns (bytes32 operatorHash) | ||||
|     { | ||||
|         return keccak256(abi.encode( | ||||
|             owner, | ||||
|             operator | ||||
|         )); | ||||
|     } | ||||
|  | ||||
|     function _getBalanceHash(address owner, uint256 accountId, uint256 marketId) | ||||
|         private | ||||
|         pure | ||||
|         returns (bytes32 balanceHash) | ||||
|     { | ||||
|         return keccak256(abi.encode( | ||||
|             owner, | ||||
|             accountId, | ||||
|             marketId | ||||
|         )); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										116
									
								
								contracts/dev-utils/contracts/test/TestLibDydxBalance.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										116
									
								
								contracts/dev-utils/contracts/test/TestLibDydxBalance.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,116 @@ | ||||
| /* | ||||
|  | ||||
|   Copyright 2019 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.5.16; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "../src/LibDydxBalance.sol"; | ||||
|  | ||||
|  | ||||
| contract TestLibDydxBalanceToken { | ||||
|  | ||||
|     uint8 public decimals; | ||||
|     mapping (address => uint256) public balanceOf; | ||||
|     mapping (address => mapping (address => uint256)) public allowance; | ||||
|  | ||||
|     constructor(uint8 decimals_) public { | ||||
|         decimals = decimals_; | ||||
|     } | ||||
|  | ||||
|     function setBalance(address owner, uint256 balance) external { | ||||
|         balanceOf[owner] = balance; | ||||
|     } | ||||
|  | ||||
|     function setApproval( | ||||
|         address owner, | ||||
|         address spender, | ||||
|         uint256 allowance_ | ||||
|     ) | ||||
|         external | ||||
|     { | ||||
|         allowance[owner][spender] = allowance_; | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
| contract TestLibDydxBalance { | ||||
|  | ||||
|     mapping (address => TestLibDydxBalanceToken) private tokens; | ||||
|  | ||||
|     function createToken(uint8 decimals) external returns (address) { | ||||
|         TestLibDydxBalanceToken token = new TestLibDydxBalanceToken(decimals); | ||||
|         return address(tokens[address(token)] = token); | ||||
|     } | ||||
|  | ||||
|     function setTokenBalance( | ||||
|         address tokenAddress, | ||||
|         address owner, | ||||
|         uint256 balance | ||||
|     ) | ||||
|         external | ||||
|     { | ||||
|         tokens[tokenAddress].setBalance(owner, balance); | ||||
|     } | ||||
|  | ||||
|     function setTokenApproval( | ||||
|         address tokenAddress, | ||||
|         address owner, | ||||
|         address spender, | ||||
|         uint256 allowance | ||||
|     ) | ||||
|         external | ||||
|     { | ||||
|         tokens[tokenAddress].setApproval(owner, spender, allowance); | ||||
|     } | ||||
|  | ||||
|     function getDydxMakerBalance(LibOrder.Order memory order, address dydx) | ||||
|         public | ||||
|         view | ||||
|         returns (uint256 balance) | ||||
|     { | ||||
|         return LibDydxBalance.getDydxMakerBalance(order, dydx); | ||||
|     } | ||||
|  | ||||
|     function getSolventMakerAmount( | ||||
|         LibDydxBalance.BalanceCheckInfo memory info | ||||
|     ) | ||||
|         public | ||||
|         view | ||||
|         returns (uint256 solventMakerAmount) | ||||
|     { | ||||
|         return LibDydxBalance._getSolventMakerAmount(info); | ||||
|     } | ||||
|  | ||||
|     function getDepositableMakerAmount( | ||||
|         LibDydxBalance.BalanceCheckInfo memory info | ||||
|     ) | ||||
|         public | ||||
|         view | ||||
|         returns (uint256 depositableMakerAmount) | ||||
|     { | ||||
|         return LibDydxBalance._getDepositableMakerAmount(info); | ||||
|     } | ||||
|  | ||||
|     function areActionsWellFormed(LibDydxBalance.BalanceCheckInfo memory info) | ||||
|         public | ||||
|         view | ||||
|         returns (bool areWellFormed) | ||||
|     { | ||||
|         return LibDydxBalance._areActionsWellFormed(info); | ||||
|     } | ||||
| } | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "name": "@0x/contracts-dev-utils", | ||||
|     "version": "1.0.3", | ||||
|     "version": "1.3.2", | ||||
|     "engines": { | ||||
|         "node": ">=6.12" | ||||
|     }, | ||||
| @@ -8,7 +8,7 @@ | ||||
|     "main": "lib/src/index.js", | ||||
|     "scripts": { | ||||
|         "build": "yarn pre_build && tsc -b", | ||||
|         "test": "yarn assert_deployable && echo !!! Tests are run via @0x/contracts-integrations !!!", | ||||
|         "test": "yarn assert_deployable && yarn mocha -t 10000 -b ./lib/test/**_test.js", | ||||
|         "assert_deployable": "node -e \"const bytecodeLen = (require('./generated-artifacts/DevUtils.json').compilerOutput.evm.bytecode.object.length-2)/2; assert(bytecodeLen<=0x6000,'DevUtils contract is too big to deploy, per EIP-170. '+bytecodeLen+'>'+0x6000)\"", | ||||
|         "build:ci": "yarn build", | ||||
|         "pre_build": "run-s compile quantify_bytecode contracts:gen generate_contract_wrappers contracts:copy", | ||||
| @@ -27,8 +27,8 @@ | ||||
|         "docs:json": "typedoc --excludePrivate --excludeExternals --excludeProtected --ignoreCompilerErrors --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES" | ||||
|     }, | ||||
|     "config": { | ||||
|         "publicInterfaceContracts": "DevUtils,LibAssetData,LibTransactionDecoder", | ||||
|         "abis": "./test/generated-artifacts/@(DevUtils|EthBalanceChecker|LibAssetData|LibTransactionDecoder|OrderTransferSimulationUtils|OrderValidationUtils).json", | ||||
|         "publicInterfaceContracts": "DevUtils,LibAssetData,LibDydxBalance,LibOrderTransferSimulation,LibTransactionDecoder", | ||||
|         "abis": "./test/generated-artifacts/@(Addresses|AssetBalance|DevUtils|EthBalanceChecker|ExternalFunctions|LibAssetData|LibDydxBalance|LibOrderTransferSimulation|LibTransactionDecoder|OrderTransferSimulationUtils|OrderValidationUtils|TestDydx|TestLibDydxBalance).json", | ||||
|         "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually." | ||||
|     }, | ||||
|     "repository": { | ||||
| @@ -41,14 +41,19 @@ | ||||
|     }, | ||||
|     "homepage": "https://github.com/0xProject/0x-monorepo/contracts/dev-utils/README.md", | ||||
|     "devDependencies": { | ||||
|         "@0x/abi-gen": "^5.0.3", | ||||
|         "@0x/assert": "^3.0.3", | ||||
|         "@0x/contracts-gen": "^2.0.3", | ||||
|         "@0x/sol-compiler": "^4.0.3", | ||||
|         "@0x/abi-gen": "^5.2.2", | ||||
|         "@0x/assert": "^3.0.7", | ||||
|         "@0x/contracts-asset-proxy": "^3.2.4", | ||||
|         "@0x/contracts-erc20": "^3.1.4", | ||||
|         "@0x/contracts-gen": "^2.0.8", | ||||
|         "@0x/contracts-test-utils": "^5.3.1", | ||||
|         "@0x/sol-compiler": "^4.0.8", | ||||
|         "@0x/ts-doc-gen": "^0.0.22", | ||||
|         "@0x/tslint-config": "^4.0.0", | ||||
|         "@0x/types": "^3.1.2", | ||||
|         "@0x/utils": "^5.4.1", | ||||
|         "@types/node": "*", | ||||
|         "ethereum-types": "^3.0.0", | ||||
|         "ethereum-types": "^3.1.0", | ||||
|         "ethers": "~4.0.4", | ||||
|         "npm-run-all": "^4.1.2", | ||||
|         "shx": "^0.2.2", | ||||
| @@ -59,7 +64,7 @@ | ||||
|         "typescript": "3.0.1" | ||||
|     }, | ||||
|     "dependencies": { | ||||
|         "@0x/base-contract": "^6.0.3" | ||||
|         "@0x/base-contract": "^6.2.1" | ||||
|     }, | ||||
|     "publishConfig": { | ||||
|         "access": "public" | ||||
|   | ||||
| @@ -7,9 +7,13 @@ import { ContractArtifact } from 'ethereum-types'; | ||||
|  | ||||
| import * as DevUtils from '../generated-artifacts/DevUtils.json'; | ||||
| import * as LibAssetData from '../generated-artifacts/LibAssetData.json'; | ||||
| import * as LibDydxBalance from '../generated-artifacts/LibDydxBalance.json'; | ||||
| import * as LibOrderTransferSimulation from '../generated-artifacts/LibOrderTransferSimulation.json'; | ||||
| import * as LibTransactionDecoder from '../generated-artifacts/LibTransactionDecoder.json'; | ||||
| export const artifacts = { | ||||
|     DevUtils: DevUtils as ContractArtifact, | ||||
|     LibAssetData: LibAssetData as ContractArtifact, | ||||
|     LibDydxBalance: LibDydxBalance as ContractArtifact, | ||||
|     LibOrderTransferSimulation: LibOrderTransferSimulation as ContractArtifact, | ||||
|     LibTransactionDecoder: LibTransactionDecoder as ContractArtifact, | ||||
| }; | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| export { artifacts } from './artifacts'; | ||||
| export { DevUtilsContract, LibAssetDataContract, LibTransactionDecoderContract } from './wrappers'; | ||||
| export { DevUtilsContract } from './wrappers'; | ||||
| export { | ||||
|     ContractArtifact, | ||||
|     ContractChains, | ||||
| @@ -15,6 +15,7 @@ export { | ||||
|     OutputField, | ||||
|     ParamDescription, | ||||
|     EvmBytecodeOutput, | ||||
|     EvmBytecodeOutputLinkReferences, | ||||
|     AbiDefinition, | ||||
|     FunctionAbi, | ||||
|     EventAbi, | ||||
|   | ||||
| @@ -5,4 +5,6 @@ | ||||
|  */ | ||||
| export * from '../generated-wrappers/dev_utils'; | ||||
| export * from '../generated-wrappers/lib_asset_data'; | ||||
| export * from '../generated-wrappers/lib_dydx_balance'; | ||||
| export * from '../generated-wrappers/lib_order_transfer_simulation'; | ||||
| export * from '../generated-wrappers/lib_transaction_decoder'; | ||||
|   | ||||
| @@ -5,17 +5,31 @@ | ||||
|  */ | ||||
| import { ContractArtifact } from 'ethereum-types'; | ||||
|  | ||||
| import * as Addresses from '../test/generated-artifacts/Addresses.json'; | ||||
| import * as AssetBalance from '../test/generated-artifacts/AssetBalance.json'; | ||||
| import * as DevUtils from '../test/generated-artifacts/DevUtils.json'; | ||||
| import * as EthBalanceChecker from '../test/generated-artifacts/EthBalanceChecker.json'; | ||||
| import * as ExternalFunctions from '../test/generated-artifacts/ExternalFunctions.json'; | ||||
| import * as LibAssetData from '../test/generated-artifacts/LibAssetData.json'; | ||||
| import * as LibDydxBalance from '../test/generated-artifacts/LibDydxBalance.json'; | ||||
| import * as LibOrderTransferSimulation from '../test/generated-artifacts/LibOrderTransferSimulation.json'; | ||||
| import * as LibTransactionDecoder from '../test/generated-artifacts/LibTransactionDecoder.json'; | ||||
| import * as OrderTransferSimulationUtils from '../test/generated-artifacts/OrderTransferSimulationUtils.json'; | ||||
| import * as OrderValidationUtils from '../test/generated-artifacts/OrderValidationUtils.json'; | ||||
| import * as TestDydx from '../test/generated-artifacts/TestDydx.json'; | ||||
| import * as TestLibDydxBalance from '../test/generated-artifacts/TestLibDydxBalance.json'; | ||||
| export const artifacts = { | ||||
|     Addresses: Addresses as ContractArtifact, | ||||
|     AssetBalance: AssetBalance as ContractArtifact, | ||||
|     DevUtils: DevUtils as ContractArtifact, | ||||
|     EthBalanceChecker: EthBalanceChecker as ContractArtifact, | ||||
|     ExternalFunctions: ExternalFunctions as ContractArtifact, | ||||
|     LibAssetData: LibAssetData as ContractArtifact, | ||||
|     LibDydxBalance: LibDydxBalance as ContractArtifact, | ||||
|     LibOrderTransferSimulation: LibOrderTransferSimulation as ContractArtifact, | ||||
|     LibTransactionDecoder: LibTransactionDecoder as ContractArtifact, | ||||
|     OrderTransferSimulationUtils: OrderTransferSimulationUtils as ContractArtifact, | ||||
|     OrderValidationUtils: OrderValidationUtils as ContractArtifact, | ||||
|     TestDydx: TestDydx as ContractArtifact, | ||||
|     TestLibDydxBalance: TestLibDydxBalance as ContractArtifact, | ||||
| }; | ||||
|   | ||||
							
								
								
									
										1170
									
								
								contracts/dev-utils/test/lib_dydx_balance_test.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1170
									
								
								contracts/dev-utils/test/lib_dydx_balance_test.ts
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -3,9 +3,16 @@ | ||||
|  * Warning: This file is auto-generated by contracts-gen. Don't edit manually. | ||||
|  * ----------------------------------------------------------------------------- | ||||
|  */ | ||||
| export * from '../test/generated-wrappers/addresses'; | ||||
| export * from '../test/generated-wrappers/asset_balance'; | ||||
| export * from '../test/generated-wrappers/dev_utils'; | ||||
| export * from '../test/generated-wrappers/eth_balance_checker'; | ||||
| export * from '../test/generated-wrappers/external_functions'; | ||||
| export * from '../test/generated-wrappers/lib_asset_data'; | ||||
| export * from '../test/generated-wrappers/lib_dydx_balance'; | ||||
| export * from '../test/generated-wrappers/lib_order_transfer_simulation'; | ||||
| export * from '../test/generated-wrappers/lib_transaction_decoder'; | ||||
| export * from '../test/generated-wrappers/order_transfer_simulation_utils'; | ||||
| export * from '../test/generated-wrappers/order_validation_utils'; | ||||
| export * from '../test/generated-wrappers/test_dydx'; | ||||
| export * from '../test/generated-wrappers/test_lib_dydx_balance'; | ||||
|   | ||||
| @@ -84,7 +84,7 @@ module.exports = { | ||||
|         solc: { | ||||
|             version: '0.5.9', | ||||
|             settings: { | ||||
|                 evmVersion: 'constantinople', | ||||
|                 evmVersion: 'istanbul', | ||||
|                 optimizer: { | ||||
|                     enabled: true, | ||||
|                     runs: 1000000, | ||||
|   | ||||
| @@ -5,13 +5,22 @@ | ||||
|     "files": [ | ||||
|         "generated-artifacts/DevUtils.json", | ||||
|         "generated-artifacts/LibAssetData.json", | ||||
|         "generated-artifacts/LibDydxBalance.json", | ||||
|         "generated-artifacts/LibOrderTransferSimulation.json", | ||||
|         "generated-artifacts/LibTransactionDecoder.json", | ||||
|         "test/generated-artifacts/Addresses.json", | ||||
|         "test/generated-artifacts/AssetBalance.json", | ||||
|         "test/generated-artifacts/DevUtils.json", | ||||
|         "test/generated-artifacts/EthBalanceChecker.json", | ||||
|         "test/generated-artifacts/ExternalFunctions.json", | ||||
|         "test/generated-artifacts/LibAssetData.json", | ||||
|         "test/generated-artifacts/LibDydxBalance.json", | ||||
|         "test/generated-artifacts/LibOrderTransferSimulation.json", | ||||
|         "test/generated-artifacts/LibTransactionDecoder.json", | ||||
|         "test/generated-artifacts/OrderTransferSimulationUtils.json", | ||||
|         "test/generated-artifacts/OrderValidationUtils.json" | ||||
|         "test/generated-artifacts/OrderValidationUtils.json", | ||||
|         "test/generated-artifacts/TestDydx.json", | ||||
|         "test/generated-artifacts/TestLibDydxBalance.json" | ||||
|     ], | ||||
|     "exclude": ["./deploy/solc/solc_bin"] | ||||
| } | ||||
|   | ||||
| @@ -1,4 +1,77 @@ | ||||
| [ | ||||
|     { | ||||
|         "timestamp": 1582837861, | ||||
|         "version": "2.1.4", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1582677073, | ||||
|         "version": "2.1.3", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1582623685, | ||||
|         "version": "2.1.2", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1581748629, | ||||
|         "version": "2.1.1", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "version": "2.1.0", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Fix broken tests", | ||||
|                 "pr": 2462 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1581204851 | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1580988106, | ||||
|         "version": "2.0.6", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1580811564, | ||||
|         "version": "2.0.5", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1579682890, | ||||
|         "version": "2.0.4", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1578272714, | ||||
|         "version": "2.0.3", | ||||
|   | ||||
| @@ -5,6 +5,38 @@ Edit the package's CHANGELOG.json file only. | ||||
|  | ||||
| CHANGELOG | ||||
|  | ||||
| ## v2.1.4 - _February 27, 2020_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v2.1.3 - _February 26, 2020_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v2.1.2 - _February 25, 2020_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v2.1.1 - _February 15, 2020_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v2.1.0 - _February 8, 2020_ | ||||
|  | ||||
|     * Fix broken tests (#2462) | ||||
|  | ||||
| ## v2.0.6 - _February 6, 2020_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v2.0.5 - _February 4, 2020_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v2.0.4 - _January 22, 2020_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v2.0.3 - _January 6, 2020_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|   | ||||
| @@ -3,8 +3,9 @@ | ||||
|     "contractsDir": "./contracts", | ||||
|     "useDockerisedSolc": false, | ||||
|     "isOfflineMode": false, | ||||
|     "shouldSaveStandardInput": true, | ||||
|     "compilerSettings": { | ||||
|         "evmVersion": "constantinople", | ||||
|         "evmVersion": "istanbul", | ||||
|         "optimizer": { | ||||
|             "enabled": true, | ||||
|             "runs": 1000000, | ||||
|   | ||||
| @@ -17,6 +17,7 @@ | ||||
| */ | ||||
|  | ||||
| pragma solidity ^0.5.9; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; | ||||
| import "@0x/contracts-utils/contracts/src/LibAddress.sol"; | ||||
|   | ||||
| @@ -1,4 +1,23 @@ | ||||
| /* | ||||
|  | ||||
|   Copyright 2019 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.5.9; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; | ||||
| import "./ERC1155.sol"; | ||||
|   | ||||
| @@ -17,6 +17,7 @@ | ||||
| */ | ||||
|  | ||||
| pragma solidity ^0.5.9; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
|  | ||||
| contract MixinNonFungibleToken { | ||||
| @@ -64,7 +65,7 @@ contract MixinNonFungibleToken { | ||||
|         // A base type has the NF bit but does has an index. | ||||
|         return (id & TYPE_NF_BIT == TYPE_NF_BIT) && (id & NF_INDEX_MASK != 0); | ||||
|     } | ||||
|      | ||||
|  | ||||
|     /// @dev returns owner of a non-fungible token | ||||
|     function ownerOf(uint256 id) public view returns (address) { | ||||
|         return nfOwners[id]; | ||||
|   | ||||
| @@ -17,13 +17,14 @@ | ||||
| */ | ||||
|  | ||||
| pragma solidity ^0.5.9; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
|  | ||||
| /// @title ERC-1155 Multi Token Standard | ||||
| /// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1155.md | ||||
| /// Note: The ERC-165 identifier for this interface is 0xd9b67a26. | ||||
| interface IERC1155 { | ||||
|      | ||||
|  | ||||
|     /// @dev Either TransferSingle or TransferBatch MUST emit when tokens are transferred, | ||||
|     ///      including zero value transfers as well as minting or burning. | ||||
|     /// Operator will always be msg.sender. | ||||
|   | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user