Compare commits
	
		
			455 Commits
		
	
	
		
			@0x/contra
			...
			monorepo@9
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 9e9e0d6592 | ||
|  | cb5f9ba97d | ||
|  | 34538f2ced | ||
|  | 2575644920 | ||
|  | b4b43a9e9e | ||
|  | df97b20913 | ||
|  | 9e3cc379ed | ||
|  | c1d78a94a2 | ||
|  | 7f4cbba076 | ||
|  | bdca84fe72 | ||
|  | cf8fd7103b | ||
|  | 8e8cdbd413 | ||
|  | 30f01681d4 | ||
|  | ecf1ad8da1 | ||
|  | 42dc112a13 | ||
|  | 58276cefce | ||
|  | 4b6501a739 | ||
|  | 724085e068 | ||
|  | 21fab3ef9f | ||
|  | db8837f4ce | ||
|  | 5781cdf6da | ||
|  | 874eb1602f | ||
|  | 82149917b7 | ||
|  | f11d8a5bd8 | ||
|  | f0d7d10fe7 | ||
|  | 9d4d9ce978 | ||
|  | 96a38602b8 | ||
|  | 90d3558d31 | ||
|  | e491a56dd0 | ||
|  | 4d8eb61924 | ||
|  | 17fab541c6 | ||
|  | 91de35e8e9 | ||
|  | f61964676a | ||
|  | 41a34c19bb | ||
|  | d90810d127 | ||
|  | 7f3d281faa | ||
|  | 812c306805 | ||
|  | fc1c59f374 | ||
|  | 35eac1e3ff | ||
|  | e16041d7fa | ||
|  | b8fc84ecc8 | ||
|  | 572c576e15 | ||
|  | 9df7f80fbb | ||
|  | f003400135 | ||
|  | ca7616c1d2 | ||
|  | a4a2bfdf35 | ||
|  | eb6bbb6e78 | ||
|  | 4d0172f634 | ||
|  | 3b61e0e126 | ||
|  | 1540a91835 | ||
|  | 2bcce9eed0 | ||
|  | 1e53564386 | ||
|  | d1c72706ef | ||
|  | bd9e531257 | ||
|  | 48436424db | ||
|  | 4f10d7f859 | ||
|  | 80e5a29444 | ||
|  | 0ec8a4a160 | ||
|  | 810bf7af0c | ||
|  | e7825206bf | ||
|  | 2b887c336a | ||
|  | 48ecd32d5d | ||
|  | 1f5a0987cb | ||
|  | f33a9d162a | ||
|  | c2919bcdb0 | ||
|  | 120d554a6b | ||
|  | 44f268a7ee | ||
|  | 3c7a0bcd85 | ||
|  | 8e2e9e9331 | ||
|  | 91c26fc046 | ||
|  | afcfe58add | ||
|  | 8d423be223 | ||
|  | 03b7314550 | ||
|  | 1a7e425780 | ||
|  | 8bc5faff3c | ||
|  | 2676278a66 | ||
|  | 6376b3baf3 | ||
|  | e569abe740 | ||
|  | 71be9ef92a | ||
|  | 4990c4903d | ||
|  | 9d468e2383 | ||
|  | 109cac013c | ||
|  | 0d8a9921cd | ||
|  | 2a5f5f7312 | ||
|  | fe54fbefbb | ||
|  | fc824b8d06 | ||
|  | d91a7b6d0e | ||
|  | aa4b3f93fa | ||
|  | efe8225d18 | ||
|  | b2c0f8c158 | ||
|  | 66dce8794d | ||
|  | 30d54407e6 | ||
|  | 6324a92ec5 | ||
|  | 67e7b5c124 | ||
|  | 35099d9b2f | ||
|  | e07f7b54e0 | ||
|  | 5c409929b4 | ||
|  | 1a504fdde9 | ||
|  | 4b06fd511b | ||
|  | def6727286 | ||
|  | bedaa0db16 | ||
|  | 90640a4fcf | ||
|  | 0142d07f10 | ||
|  | c9d85cfc7d | ||
|  | 64304c1991 | ||
|  | 993adc3578 | ||
|  | 8813bd26f6 | ||
|  | 35925de320 | ||
|  | 3b426a3f07 | ||
|  | 5104fd5dcf | ||
|  | a5a9ca9e46 | ||
|  | ba0f07e3b2 | ||
|  | 8614475324 | ||
|  | 744dda144b | ||
|  | 13d47915f4 | ||
|  | 3059b85e41 | ||
|  | 184ea4a67f | ||
|  | 8032f536ed | ||
|  | fba3870ef1 | ||
|  | 2915ee08ea | ||
|  | 86b76a3e75 | ||
|  | bc1dca3f6f | ||
|  | 5db1820123 | ||
|  | 657c35fb86 | ||
|  | 9432a84468 | ||
|  | 15a5bc02ef | ||
|  | f011be9347 | ||
|  | b6094fdb34 | ||
|  | 9e6ab9f585 | ||
|  | 869d2c02fa | ||
|  | 3b1dca0e70 | ||
|  | 595358fa69 | ||
|  | 8a8ec79c6c | ||
|  | 6252446bd3 | ||
|  | 403ceebff9 | ||
|  | 4767882ed3 | ||
|  | 3b9d84fa58 | ||
|  | 6fd96a6fd7 | ||
|  | c93b02d55e | ||
|  | 568f87d5eb | ||
|  | 49ad0f0d54 | ||
|  | 0e642f59e1 | ||
|  | 7c5730fb03 | ||
|  | 45f0f755ab | ||
|  | 1ef2913c5b | ||
|  | fecbf220b6 | ||
|  | 17a5f05cf3 | ||
|  | 6a852ab0ed | ||
|  | ec26cff656 | ||
|  | cdd34a1214 | ||
|  | 857a4042ef | ||
|  | f51c80adb2 | ||
|  | e61f23d001 | ||
|  | cbe4c4fbf9 | ||
|  | deffdabc30 | ||
|  | 8811a5387a | ||
|  | 9336d4e545 | ||
|  | f65d8cc325 | ||
|  | 68656c4083 | ||
|  | 44793a9cf9 | ||
|  | 2d0ad6f181 | ||
|  | a7f0717afb | ||
|  | a9022352e7 | ||
|  | 9b2231ed24 | ||
|  | c123200f38 | ||
|  | 3c6c4128a6 | ||
|  | 47e050cbaf | ||
|  | 62d15117c5 | ||
|  | fb8360edfd | ||
|  | e557f2fb48 | ||
|  | c957b48281 | ||
|  | c15c5e12b0 | ||
|  | 15c3c8074c | ||
|  | cba72c811d | ||
|  | 28a2e56003 | ||
|  | 8c4c3d56c6 | ||
|  | 911fcc0bed | ||
|  | 55fd16ccf1 | ||
|  | 4e05e41f7f | ||
|  | ebab80cff7 | ||
|  | 91cb162662 | ||
|  | fa26f8de51 | ||
|  | 26602ac2db | ||
|  | 0b8af181d8 | ||
|  | 19d661d324 | ||
|  | 7d29b36246 | ||
|  | 8ba7b95e86 | ||
|  | 30c72daed5 | ||
|  | 575cb99839 | ||
|  | 0c064bf85b | ||
|  | 0f3610c92a | ||
|  | c8ef10baaf | ||
|  | 16dc73bd1e | ||
|  | 4f56d68689 | ||
|  | 8e6d92cad5 | ||
|  | 3a1c464543 | ||
|  | a0c2f6b7b4 | ||
|  | 7bfbf0ad3a | ||
|  | 82ee6750c7 | ||
|  | c37fc30c55 | ||
|  | 09d13b2bfa | ||
|  | af0de72bc3 | ||
|  | 43e32f6a1a | ||
|  | e9e6452890 | ||
|  | 5f699b0c47 | ||
|  | bf18b86f9f | ||
|  | 56f7dd7538 | ||
|  | 7aa88307f6 | ||
|  | 8aa69233e0 | ||
|  | e843333918 | ||
|  | 133a4dc4e1 | ||
|  | c7945a542e | ||
|  | b4e00baa07 | ||
|  | dde570706a | ||
|  | 0b3e3ab990 | ||
|  | 205c895d75 | ||
|  | 6402d29dd4 | ||
|  | dc18999931 | ||
|  | 43f8101d0b | ||
|  | 3d56c06ff3 | ||
|  | db9be73fec | ||
|  | a02892cbc8 | ||
|  | 49c67fbb18 | ||
|  | 6f2e79208a | ||
|  | ceb3ba4116 | ||
|  | 08d4f1402f | ||
|  | 77fa97f259 | ||
|  | 3ac5d9add5 | ||
|  | cab89f312a | ||
|  | 8972475389 | ||
|  | 330f2d54e2 | ||
|  | 9c181f09ba | ||
|  | 011ecb8f4b | ||
|  | bc2a9beb14 | ||
|  | 091f5ed8b8 | ||
|  | ea9f535a7c | ||
|  | f246314b1d | ||
|  | cdfd62a296 | ||
|  | dcff7d511b | ||
|  | 16a5475d24 | ||
|  | 42468c3fa2 | ||
|  | 9312d5d9f7 | ||
|  | 33a0c22021 | ||
|  | 58e9c70203 | ||
|  | 0067f10a6a | ||
|  | 59210f5e5e | ||
|  | 1c695b2759 | ||
|  | c7222c17ae | ||
|  | 0f237d22f9 | ||
|  | b1b1162b60 | ||
|  | 6ee1605a77 | ||
|  | a22b2e7a9f | ||
|  | 86ed32a007 | ||
|  | 8e8ea6a3ab | ||
|  | cc7452da8f | ||
|  | 06715201a7 | ||
|  | 281658ba34 | ||
|  | f192648c76 | ||
|  | 07e1d502e7 | ||
|  | 703e890918 | ||
|  | 096950729e | ||
|  | 8869d79c68 | ||
|  | 752dd04546 | ||
|  | 3e5d166ec4 | ||
|  | 64bc1b0990 | ||
|  | 548b0db6ea | ||
|  | c9607e8b2c | ||
|  | c676ecb8cf | ||
|  | 39804fdc83 | ||
|  | 1a1dc89454 | ||
|  | e427698956 | ||
|  | 575af6b6e8 | ||
|  | 3a1fc9ee5f | ||
|  | 1237c7d479 | ||
|  | c44e16a88f | ||
|  | 06c180475e | ||
|  | 74a2c3a199 | ||
|  | 9ac715f99d | ||
|  | 22e39f782f | ||
|  | f5a6b84fa3 | ||
|  | 718407ba6f | ||
|  | e603a81a46 | ||
|  | 03e35846fb | ||
|  | c87364f86b | ||
|  | a794a33551 | ||
|  | 494b437f1a | ||
|  | 92b80fc436 | ||
|  | d66101cd9d | ||
|  | 89ae04803f | ||
|  | be95bce4cd | ||
|  | 01aee08c02 | ||
|  | 6cba9fd77f | ||
|  | 673d45361f | ||
|  | d91a7fc663 | ||
|  | ce8fd44234 | ||
|  | 6617ad9531 | ||
|  | 10f8051835 | ||
|  | e7dc7167d0 | ||
|  | 359b804001 | ||
|  | fd9084b345 | ||
|  | 44dac2cd80 | ||
|  | a66ea2bf74 | ||
|  | a362e9d2d8 | ||
|  | 1885957bd3 | ||
|  | 1a409c3731 | ||
|  | 7b7c64fc6a | ||
|  | 102fcd3fb8 | ||
|  | 566e05aea4 | ||
|  | f014370531 | ||
|  | dfbbe9daa2 | ||
|  | 6b653fb00d | ||
|  | 21cf2319d5 | ||
|  | 4210477e71 | ||
|  | 93b02e93b9 | ||
|  | f4cb8cfb7e | ||
|  | ce9f051d42 | ||
|  | 083216a0c6 | ||
|  | 820b40e227 | ||
|  | 59a38a8db0 | ||
|  | d0884dcb4d | ||
|  | c7ca625408 | ||
|  | e46f51339a | ||
|  | b45ec47eee | ||
|  | c50cbd7a75 | ||
|  | 5ddc35fdf2 | ||
|  | d6c064b9c3 | ||
|  | caf6329bb3 | ||
|  | 008938cf5b | ||
|  | 3fd29656cb | ||
|  | ffac52f42e | ||
|  | 9114510c00 | ||
|  | 2dbda6fc42 | ||
|  | eae4001622 | ||
|  | 727d0498b6 | ||
|  | e43f2d39bf | ||
|  | cde0169733 | ||
|  | 0e90b0e7d0 | ||
|  | b793a31cdd | ||
|  | 23198174f3 | ||
|  | 523bc3f951 | ||
|  | 41d99e77c7 | ||
|  | 90193c8197 | ||
|  | 6f5c62914e | ||
|  | 17faeae47d | ||
|  | 7283a16710 | ||
|  | 52c3dc4ad8 | ||
|  | 1cf8ae5909 | ||
|  | 51282953bd | ||
|  | a6603d6bd6 | ||
|  | 54a03eacd6 | ||
|  | 43fa753a13 | ||
|  | 9d9fe882b6 | ||
|  | 4f6958b7b5 | ||
|  | 9a5752fff9 | ||
|  | c21932d149 | ||
|  | ce6c05637f | ||
|  | b0699fc238 | ||
|  | 8bf7c4cf48 | ||
|  | 9f6d113fe8 | ||
|  | 646507c41a | ||
|  | 65f2626544 | ||
|  | 7155d878b3 | ||
|  | 361576814c | ||
|  | aa541d0cad | ||
|  | 7e58385a78 | ||
|  | b5545255d0 | ||
|  | a22ba8647c | ||
|  | 22fc0b4337 | ||
|  | 063d6ff24e | ||
|  | 09c0b83fe3 | ||
|  | a42f3d189c | ||
|  | 7815da7257 | ||
|  | 8e2b971f5a | ||
|  | 3fd7132a0d | ||
|  | 93edb083fa | ||
|  | 9e41c648dc | ||
|  | a7ef54dbff | ||
|  | 414084a7ad | ||
|  | 681e6eab7a | ||
|  | 701b203c58 | ||
|  | cbd0ca4b60 | ||
|  | 1626566f93 | ||
|  | ac75053f69 | ||
|  | 13afc65b54 | ||
|  | aa0a1bb54d | ||
|  | 2e36c7ef83 | ||
|  | 43399a9ad9 | ||
|  | 2ef546210d | ||
|  | 7b379f3933 | ||
|  | f8ac986a0f | ||
|  | dc0a78434d | ||
|  | d1b0384aef | ||
|  | 7ac7f45c4a | ||
|  | b3c7ccec57 | ||
|  | 93725ecec0 | ||
|  | 3c31ef188a | ||
|  | 53df2130ea | ||
|  | 8b695f9b98 | ||
|  | d914f6fce9 | ||
|  | e2e5152648 | ||
|  | d3dcf7fb0c | ||
|  | a0f5a8b64b | ||
|  | ee508f70bc | ||
|  | 200b3d450f | ||
|  | 52fc7517f9 | ||
|  | cf517b1459 | ||
|  | c17984b74f | ||
|  | 589d2212ee | ||
|  | 9b922f746b | ||
|  | 0e7387550c | ||
|  | dbf22583b5 | ||
|  | 6825eb442b | ||
|  | 45f284973a | ||
|  | ef6e691646 | ||
|  | e67888d65f | ||
|  | 584f8b13fe | ||
|  | f993b6d1ed | ||
|  | 035dc607db | ||
|  | cf2053ec77 | ||
|  | 3840ebf538 | ||
|  | 80cb6b654b | ||
|  | ab70c4df74 | ||
|  | 95e461072f | ||
|  | 2593f1ff30 | ||
|  | c2261a6bbe | ||
|  | b383781870 | ||
|  | 7d121bafd0 | ||
|  | 6a2911d10f | ||
|  | 17362bcf44 | ||
|  | 87906a3af1 | ||
|  | c0c27ed637 | ||
|  | 6be5552944 | ||
|  | b4ae42cc9a | ||
|  | 3c6957095d | ||
|  | 2020d87824 | ||
|  | ac1063dd68 | ||
|  | b8e01d7be5 | ||
|  | 24e4567b25 | ||
|  | ccf40fd65e | ||
|  | d4729e2669 | ||
|  | 52d38c63de | ||
|  | 086c30831d | ||
|  | 4be83de7e5 | ||
|  | 650efb95e2 | ||
|  | 3948f8b66b | ||
|  | ffcd297e5b | ||
|  | cfb099c65c | ||
|  | ba5c702a9e | ||
|  | 9d4010299a | ||
|  | b5492bb023 | ||
|  | 76724a6c73 | ||
|  | 57ec0858fe | ||
|  | b281b9aac8 | ||
|  | f4453c0966 | ||
|  | ebd328db06 | 
| @@ -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-dev-utils @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-tests @0x/contracts-staking | ||||
|     test-exchange-ganache-3.0: | ||||
|         resource_class: medium+ | ||||
|         docker: | ||||
| @@ -58,6 +58,16 @@ jobs: | ||||
|                   keys: | ||||
|                       - repo-{{ .Environment.CIRCLE_SHA1 }} | ||||
|             - run: yarn wsrun test:circleci @0x/contracts-exchange | ||||
|     test-integrations-ganache-3.0: | ||||
|         resource_class: medium+ | ||||
|         docker: | ||||
|             - image: nikolaik/python-nodejs:python3.7-nodejs8 | ||||
|         working_directory: ~/repo | ||||
|         steps: | ||||
|             - restore_cache: | ||||
|                   keys: | ||||
|                       - repo-{{ .Environment.CIRCLE_SHA1 }} | ||||
|             - run: yarn wsrun test:circleci @0x/contracts-integrations | ||||
|     test-contracts-rest-ganache-3.0: | ||||
|         resource_class: medium+ | ||||
|         docker: | ||||
| @@ -67,11 +77,11 @@ 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-dev-utils @0x/contracts-staking | ||||
|             # TODO(dorothy-zbornak): Re-enable after updating this package for 3.0. | ||||
|             - 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 | ||||
|             # 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. | ||||
|             # - run: yarn wsrun test:circleci @0x/contracts-extensions | ||||
|             # TODO(abandeali): Re-enable after this package is complete. | ||||
|             # - run: yarn wsrun test:circleci @0x/contracts-coordinator | ||||
|     test-publish: | ||||
|         resource_class: medium+ | ||||
|         docker: | ||||
| @@ -82,7 +92,7 @@ jobs: | ||||
|             - restore_cache: | ||||
|                   keys: | ||||
|                       - repo-{{ .Environment.CIRCLE_SHA1 }} | ||||
|             - run:  | ||||
|             - run: | ||||
|                 command: yarn test:publish:circleci | ||||
|                 no_output_timeout: 1800 | ||||
|     test-doc-generation: | ||||
| @@ -108,6 +118,9 @@ jobs: | ||||
|             - run: yarn wsrun test:circleci @0x/abi-gen | ||||
|             # TODO (xianny): Needs to be updated for 3.0 | ||||
|             # - run: yarn wsrun test:circleci @0x/asset-buyer | ||||
|             # TODO: Needs to be updated for 3.0.  At that time, also remove | ||||
|             # exclusion from monorepo package.json's test script. | ||||
|             # - run: yarn wsrun test:circleci @0x/asset-swapper | ||||
|             - run: yarn wsrun test:circleci @0x/contract-artifacts | ||||
|             - run: yarn wsrun test:circleci @0x/assert | ||||
|             - run: yarn wsrun test:circleci @0x/base-contract | ||||
| @@ -117,6 +130,9 @@ jobs: | ||||
|             - run: yarn wsrun test:circleci @0x/dev-utils | ||||
|             - run: yarn wsrun test:circleci @0x/json-schemas | ||||
|             - run: yarn wsrun test:circleci @0x/order-utils | ||||
|             # TODO: Needs to be updated for 3.0. At that time, also remove | ||||
|             # exclusion from monorepo package.json's test script. | ||||
|             # - run: yarn wsrun test:circleci @0x/orderbook | ||||
|             - run: yarn wsrun test:circleci @0x/sol-compiler | ||||
|             - run: yarn wsrun test:circleci @0x/sol-tracing-utils | ||||
|             - run: yarn wsrun test:circleci @0x/sol-doc | ||||
| @@ -184,14 +200,33 @@ jobs: | ||||
|         working_directory: ~/repo | ||||
|         docker: | ||||
|             - image: nikolaik/python-nodejs:python3.7-nodejs8 | ||||
|             - image: 0xorg/ganache-cli:2.2.2 | ||||
|             - image: 0xorg/launch-kit-backend:74bcc39 | ||||
|             - image: 0xorg/ganache-cli:4.4.0-beta.1 | ||||
|               environment: | ||||
|                   RPC_URL: http://localhost:8545 | ||||
|                   NETWORK_ID: 50 | ||||
|                   WHITELIST_ALL_TOKENS: True | ||||
|                   VERSION: 4.4.0-beta.1 | ||||
|                   SNAPSHOT_NAME: 0x_ganache_snapshot-v3-beta | ||||
|             - image: 0xorg/mesh:6.0.0-beta-0xv3 | ||||
|               environment: | ||||
|                   ETHEREUM_RPC_URL: 'http://localhost:8545' | ||||
|                   ETHEREUM_NETWORK_ID: '50' | ||||
|                   ETHEREUM_CHAIN_ID: '1337' | ||||
|                   USE_BOOTSTRAP_LIST: 'true' | ||||
|                   VERBOSITY: 3 | ||||
|                   PRIVATE_KEY_PATH: '' | ||||
|                   BLOCK_POLLING_INTERVAL: '5s' | ||||
|                   P2P_LISTEN_PORT: '60557' | ||||
|               command: | | ||||
|                   sh -c "until printf 'POST /\r\nContent-Length: 26\r\n\r\n{\"method\":\"net_listening\"}' | nc localhost 8545 | grep true; do continue; done; node_modules/.bin/forever ts/lib/index.js" | ||||
|                   sh -c "waitForGanache () { until printf 'POST /\r\nContent-Length: 26\r\n\r\n{\"method\":\"net_listening\"}' | nc localhost 8545 | grep true; do continue; done }; waitForGanache && ./mesh" | ||||
|             - image: 0xorg/launch-kit-backend:v3 | ||||
|               environment: | ||||
|                   RPC_URL: 'http://localhost:8545' | ||||
|                   CHAIN_ID: 1337 | ||||
|                   WHITELIST_ALL_TOKENS: True | ||||
|                   FEE_RECIPIENT: '0x0000000000000000000000000000000000000001' | ||||
|                   MAKER_FEE_UNIT_AMOUNT: 0 | ||||
|                   TAKER_FEE_UNIT_AMOUNT: 0 | ||||
|                   MESH_ENDPOINT: 'ws://localhost:60557' | ||||
|               command: | | ||||
|                   sh -c "waitForMesh () { sleep 5; }; waitForMesh && node_modules/.bin/forever ts/lib/index.js" | ||||
|         steps: | ||||
|             - checkout | ||||
|             - restore_cache: | ||||
| @@ -213,8 +248,14 @@ jobs: | ||||
|             - run: | ||||
|                   command: | | ||||
|                       cd python-packages | ||||
|                       ./parallel_without_sra_client coverage run setup.py test | ||||
|                       ./parallel coverage run setup.py test | ||||
|                       ./build_docs | ||||
|             - run: | ||||
|                   command: | | ||||
|                       # copy generated wrappers into contract_wrappers/build, | ||||
|                       # JUST so CircleCI will persist them as build artifacts. | ||||
|                       cd python-packages/contract_wrappers/src/zero_ex | ||||
|                       for i in contract_wrappers/[^__]*/; do mkdir -p ../../build/$i; cp $i/__init__.py ../../build/$i; done | ||||
|             - save_cache: | ||||
|                   key: coverage-python-contract-addresses-{{ .Environment.CIRCLE_SHA1 }} | ||||
|                   paths: | ||||
| @@ -239,8 +280,6 @@ jobs: | ||||
|                   key: coverage-python-sra-client-{{ .Environment.CIRCLE_SHA1 }} | ||||
|                   paths: | ||||
|                       - ~/repo/python-packages/sra_client/.coverage | ||||
|             - store_artifacts: | ||||
|                   path: ~/repo/python-packages/contract_wrappers/src/zero_ex/contract_wrappers/*/__init__.py | ||||
|             - store_artifacts: | ||||
|                   path: ~/repo/python-packages/contract_addresses/build | ||||
|             - store_artifacts: | ||||
| @@ -394,6 +433,9 @@ workflows: | ||||
|             - test-exchange-ganache-3.0: | ||||
|                   requires: | ||||
|                       - build | ||||
|             - test-integrations-ganache-3.0: | ||||
|                   requires: | ||||
|                       - build | ||||
|             - test-contracts-rest-ganache-3.0: | ||||
|                   requires: | ||||
|                       - build | ||||
| @@ -415,12 +457,11 @@ workflows: | ||||
|                       - test-exchange-ganache-3.0 | ||||
|                       - test-rest | ||||
|                       - static-tests | ||||
|             # - test-python: | ||||
|             #       requires: | ||||
|             #           - build | ||||
|             #           - test-rest | ||||
|             # - static-tests-python: | ||||
|             #       requires: | ||||
|             #           - test-python | ||||
|             - test-python: | ||||
|                   requires: | ||||
|                       - build | ||||
|             - static-tests-python: | ||||
|                   requires: | ||||
|                       - build | ||||
|             # skip python tox run for now, as we don't yet have multiple test environments to support. | ||||
|             # - test-rest-python | ||||
|   | ||||
							
								
								
									
										2
									
								
								.github/autolabeler.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/autolabeler.yml
									
									
									
									
										vendored
									
									
								
							| @@ -32,5 +32,3 @@ contracts: ['contracts'] | ||||
| @0x/json-schemas: ['packages/json-schemas'] | ||||
| @0x/ethereum-types: ['ethereum-types'] | ||||
| @0x/connect: ['packages/connect'] | ||||
| @0x/testnet-faucets: ['packages/testnet-faucets'] | ||||
| @0x/monorepo-scripts: ['packages/monorepo-scripts'] | ||||
|   | ||||
							
								
								
									
										46
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										46
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -78,23 +78,35 @@ TODO.md | ||||
| # VSCode file | ||||
| .vscode | ||||
|  | ||||
| # server cli | ||||
| packages/testnet-faucets/server/ | ||||
|  | ||||
| # generated contract artifacts/ | ||||
| contracts/integrations/generated-artifacts/ | ||||
| contracts/integrations/test/generated-artifacts/ | ||||
| contracts/staking/generated-artifacts/ | ||||
| contracts/staking/test/generated-artifacts/ | ||||
| contracts/coordinator/generated-artifacts/ | ||||
| contracts/coordinator/test/generated-artifacts/ | ||||
| contracts/exchange/generated-artifacts/ | ||||
| contracts/exchange/test/generated-artifacts/ | ||||
| contracts/asset-proxy/generated-artifacts/ | ||||
| contracts/asset-proxy/test/generated-artifacts/ | ||||
| contracts/multisig/generated-artifacts/ | ||||
| contracts/multisig/test/generated-artifacts/ | ||||
| contracts/utils/generated-artifacts/ | ||||
| contracts/utils/test/generated-artifacts/ | ||||
| contracts/exchange-libs/generated-artifacts/ | ||||
| contracts/exchange-libs/test/generated-artifacts/ | ||||
| contracts/erc20/generated-artifacts/ | ||||
| contracts/erc20/test/generated-artifacts/ | ||||
| contracts/erc721/generated-artifacts/ | ||||
| contracts/erc721/test/generated-artifacts/ | ||||
| contracts/erc1155/generated-artifacts/ | ||||
| contracts/erc1155/test/generated-artifacts/ | ||||
| contracts/extensions/generated-artifacts/ | ||||
| contracts/extensions/test/generated-artifacts/ | ||||
| contracts/exchange-forwarder/generated-artifacts/ | ||||
| contracts/exchange-forwarder/test/generated-artifacts/ | ||||
| contracts/dev-utils/generated-artifacts/ | ||||
| contracts/dev-utils/test/generated-artifacts/ | ||||
| packages/sol-tracing-utils/test/fixtures/artifacts/ | ||||
| python-packages/contract_artifacts/src/zero_ex/contract_artifacts/artifacts/ | ||||
|  | ||||
| @@ -115,19 +127,35 @@ contracts/dev-utils/build/ | ||||
|  | ||||
| # generated contract wrappers | ||||
| packages/python-contract-wrappers/generated/ | ||||
| contracts/integrations/generated-wrappers/ | ||||
| contracts/integrations/test/generated-wrappers/ | ||||
| contracts/staking/generated-wrappers/ | ||||
| contracts/staking/test/generated-wrappers/ | ||||
| contracts/coordinator/generated-wrappers/ | ||||
| contracts/coordinator/test/generated-wrappers/ | ||||
| contracts/exchange/generated-wrappers/ | ||||
| contracts/exchange/test/generated-wrappers/ | ||||
| contracts/asset-proxy/generated-wrappers/ | ||||
| contracts/asset-proxy/test/generated-wrappers/ | ||||
| contracts/multisig/generated-wrappers/ | ||||
| contracts/multisig/test/generated-wrappers/ | ||||
| contracts/utils/generated-wrappers/ | ||||
| contracts/utils/test/generated-wrappers/ | ||||
| contracts/exchange-libs/generated-wrappers/ | ||||
| contracts/exchange-libs/test/generated-wrappers/ | ||||
| contracts/erc20/generated-wrappers/ | ||||
| contracts/erc20/test/generated-wrappers/ | ||||
| contracts/erc721/generated-wrappers/ | ||||
| contracts/erc721/test/generated-wrappers/ | ||||
| contracts/erc1155/generated-wrappers/ | ||||
| contracts/erc1155/test/generated-wrappers/ | ||||
| contracts/extensions/generated-wrappers/ | ||||
| contracts/extensions/test/generated-wrappers/ | ||||
| contracts/exchange-forwarder/generated-wrappers/ | ||||
| contracts/exchange-forwarder/test/generated-wrappers/ | ||||
| contracts/dev-utils/generated-wrappers/ | ||||
| contracts/dev-utils/test/generated-wrappers/ | ||||
| python-packages/contract_wrappers/src/zero_ex/contract_wrappers/dev_utils/__init__.py | ||||
| python-packages/contract_wrappers/src/zero_ex/contract_wrappers/erc20_token/__init__.py | ||||
| python-packages/contract_wrappers/src/zero_ex/contract_wrappers/exchange/__init__.py | ||||
| python-packages/contract_wrappers/src/zero_ex/contract_wrappers/asset_proxy_owner/__init__.py | ||||
| @@ -136,16 +164,20 @@ python-packages/contract_wrappers/src/zero_ex/contract_wrappers/coordinator_regi | ||||
| python-packages/contract_wrappers/src/zero_ex/contract_wrappers/dummy_erc20_token/__init__.py | ||||
| python-packages/contract_wrappers/src/zero_ex/contract_wrappers/dummy_erc721_token/__init__.py | ||||
| python-packages/contract_wrappers/src/zero_ex/contract_wrappers/dutch_auction/__init__.py | ||||
| python-packages/contract_wrappers/src/zero_ex/contract_wrappers/erc1155_mintable/__init__.py | ||||
| python-packages/contract_wrappers/src/zero_ex/contract_wrappers/erc1155_proxy/__init__.py | ||||
| python-packages/contract_wrappers/src/zero_ex/contract_wrappers/erc20_proxy/__init__.py | ||||
| python-packages/contract_wrappers/src/zero_ex/contract_wrappers/erc721_proxy/__init__.py | ||||
| python-packages/contract_wrappers/src/zero_ex/contract_wrappers/erc721_token/__init__.py | ||||
| python-packages/contract_wrappers/src/zero_ex/contract_wrappers/eth_balance_checker/__init__.py | ||||
| python-packages/contract_wrappers/src/zero_ex/contract_wrappers/forwarder/__init__.py | ||||
| python-packages/contract_wrappers/src/zero_ex/contract_wrappers/i_asset_proxy/__init__.py | ||||
| python-packages/contract_wrappers/src/zero_ex/contract_wrappers/i_validator/__init__.py | ||||
| python-packages/contract_wrappers/src/zero_ex/contract_wrappers/i_wallet/__init__.py | ||||
| python-packages/contract_wrappers/src/zero_ex/contract_wrappers/multi_asset_proxy/__init__.py | ||||
| python-packages/contract_wrappers/src/zero_ex/contract_wrappers/order_validator/__init__.py | ||||
| python-packages/contract_wrappers/src/zero_ex/contract_wrappers/staking/__init__.py | ||||
| python-packages/contract_wrappers/src/zero_ex/contract_wrappers/staking_proxy/__init__.py | ||||
| python-packages/contract_wrappers/src/zero_ex/contract_wrappers/static_call_proxy/__init__.py | ||||
| python-packages/contract_wrappers/src/zero_ex/contract_wrappers/weth9/__init__.py | ||||
| python-packages/contract_wrappers/src/zero_ex/contract_wrappers/zrx_token/__init__.py | ||||
|  | ||||
| @@ -162,10 +194,14 @@ __pycache__ | ||||
| python-packages/*/src/*.egg-info | ||||
| python-packages/*/.coverage | ||||
|  | ||||
| # python keeps package-local copies of json schemas | ||||
| # python keeps package-local copies of json schemas and contract addresses | ||||
| python-packages/json_schemas/src/zero_ex/json_schemas/schemas | ||||
| python-packages/contract_addresses/src/zero_ex/contract_addresses/addresses.json | ||||
|  | ||||
| # Doc README copy | ||||
| packages/*/docs/README.md | ||||
|  | ||||
| .DS_Store | ||||
|  | ||||
| # the snapshot that gets built for migrations sure does have a ton of files | ||||
| packages/migrations/0x_ganache_snapshot* | ||||
|   | ||||
| @@ -1,31 +1,61 @@ | ||||
| lib | ||||
| .nyc_output | ||||
| /contracts/integrations/generated-wrappers | ||||
| /contracts/integrations/test/generated-wrappers | ||||
| /contracts/integrations/generated-artifacts | ||||
| /contracts/integrations/test/generated-artifacts | ||||
| /contracts/staking/generated-wrappers | ||||
| /contracts/staking/test/generated-wrappers | ||||
| /contracts/staking/generated-artifacts | ||||
| /contracts/staking/test/generated-artifacts | ||||
| /contracts/coordinator/generated-wrappers | ||||
| /contracts/coordinator/test/generated-wrappers | ||||
| /contracts/coordinator/generated-artifacts | ||||
| /contracts/coordinator/test/generated-artifacts | ||||
| /contracts/exchange/generated-wrappers | ||||
| /contracts/exchange/test/generated-wrappers | ||||
| /contracts/exchange/generated-artifacts | ||||
| /contracts/exchange/test/generated-artifacts | ||||
| /contracts/asset-proxy/generated-wrappers | ||||
| /contracts/asset-proxy/test/generated-wrappers | ||||
| /contracts/asset-proxy/generated-artifacts | ||||
| /contracts/asset-proxy/test/generated-artifacts | ||||
| /contracts/multisig/generated-wrappers | ||||
| /contracts/multisig/test/generated-wrappers | ||||
| /contracts/multisig/generated-artifacts | ||||
| /contracts/multisig/test/generated-artifacts | ||||
| /contracts/utils/generated-wrappers | ||||
| /contracts/utils/test/generated-wrappers | ||||
| /contracts/utils/generated-artifacts | ||||
| /contracts/utils/test/generated-artifacts | ||||
| /contracts/exchange-libs/generated-wrappers | ||||
| /contracts/exchange-libs/test/generated-wrappers | ||||
| /contracts/exchange-libs/generated-artifacts | ||||
| /contracts/exchange-libs/test/generated-artifacts | ||||
| /contracts/erc20/generated-wrappers | ||||
| /contracts/erc20/test/generated-wrappers | ||||
| /contracts/erc20/generated-artifacts | ||||
| /contracts/erc20/test/generated-artifacts | ||||
| /contracts/erc721/generated-wrappers | ||||
| /contracts/erc721/test/generated-wrappers | ||||
| /contracts/erc721/generated-artifacts | ||||
| /contracts/erc721/test/generated-artifacts | ||||
| /contracts/erc1155/generated-wrappers | ||||
| /contracts/erc1155/test/generated-wrappers | ||||
| /contracts/erc1155/generated-artifacts | ||||
| /contracts/erc1155/test/generated-artifacts | ||||
| /contracts/extensions/generated-wrappers | ||||
| /contracts/extensions/test/generated-wrappers | ||||
| /contracts/extensions/generated-artifacts | ||||
| /contracts/extensions/test/generated-artifacts | ||||
| /contracts/exchange-forwarder/generated-wrappers | ||||
| /contracts/exchange-forwarder/test/generated-wrappers | ||||
| /contracts/exchange-forwarder/generated-artifacts | ||||
| /contracts/exchange-forwarder/test/generated-artifacts | ||||
| /contracts/dev-utils/generated-wrappers | ||||
| /contracts/dev-utils/test/generated-wrappers | ||||
| /contracts/dev-utils/generated-artifacts | ||||
| /contracts/dev-utils/test/generated-artifacts | ||||
| /contracts/staking/build/ | ||||
| /contracts/coordinator/build/ | ||||
| /contracts/exchange/build/ | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "tabWidth": 4, | ||||
|     "printWidth": 120, | ||||
|     "trailingComma": all, | ||||
|     "singleQuote": true | ||||
|     "tabWidth": 4, | ||||
|     "singleQuote": true, | ||||
|     "trailingComma": "all" | ||||
| } | ||||
|   | ||||
| @@ -96,10 +96,9 @@ These packages are all under development. See [/contracts/README.md](/contracts/ | ||||
|  | ||||
| #### Private Packages | ||||
|  | ||||
| | Package                                            | Description                                                                      | | ||||
| | -------------------------------------------------- | -------------------------------------------------------------------------------- | | ||||
| | [`@0x/instant`](/packages/instant)                 | A free and flexible way to offer simple crypto purchasing in any app or website. | | ||||
| | [`@0x/testnet-faucets`](/packages/testnet-faucets) | A faucet micro-service that dispenses test ERC20 tokens or Ether                 | | ||||
| | Package                            | Description                                                                      | | ||||
| | ---------------------------------- | -------------------------------------------------------------------------------- | | ||||
| | [`@0x/instant`](/packages/instant) | A free and flexible way to offer simple crypto purchasing in any app or website. | | ||||
|  | ||||
| ## Usage | ||||
|  | ||||
|   | ||||
							
								
								
									
										10
									
								
								contracts/asset-proxy/.npmignore
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								contracts/asset-proxy/.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 | ||||
| @@ -1,4 +1,24 @@ | ||||
| [ | ||||
|     { | ||||
|         "version": "2.3.0-beta.2", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils", | ||||
|                 "pr": 2330 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1574030254 | ||||
|     }, | ||||
|     { | ||||
|         "version": "2.3.0-beta.1", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "ERC20Wrapper and ERC1155ProxyWrapper constructors now require an instance of DevUtilsContract", | ||||
|                 "pr": 2034 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1573159180 | ||||
|     }, | ||||
|     { | ||||
|         "version": "2.3.0-beta.0", | ||||
|         "changes": [ | ||||
| @@ -25,6 +45,14 @@ | ||||
|             { | ||||
|                 "note": "Add `Eth2DaiBridge`", | ||||
|                 "pr": 2221 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Add `UniswapBridge`", | ||||
|                 "pr": 2233 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Replaced `SafeMath` with `LibSafeMath`", | ||||
|                 "pr": 2254 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1570135330 | ||||
|   | ||||
| @@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only. | ||||
|  | ||||
| CHANGELOG | ||||
|  | ||||
| ## v2.3.0-beta.2 - _November 17, 2019_ | ||||
|  | ||||
|     * Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils (#2330) | ||||
|  | ||||
| ## v2.3.0-beta.1 - _November 7, 2019_ | ||||
|  | ||||
|     * ERC20Wrapper and ERC1155ProxyWrapper constructors now require an instance of DevUtilsContract (#2034) | ||||
|  | ||||
| ## v2.3.0-beta.0 - _October 3, 2019_ | ||||
|  | ||||
|     * Disallow the zero address from being made an authorized address in MixinAuthorizable, and created an archive directory that includes an old version of Ownable (#2019) | ||||
| @@ -13,6 +21,8 @@ CHANGELOG | ||||
|     * Remove unused dependency on IAuthorizable in IAssetProxy (#1910) | ||||
|     * Add `ERC20BridgeProxy` (#2220) | ||||
|     * Add `Eth2DaiBridge` (#2221) | ||||
|     * Add `UniswapBridge` (#2233) | ||||
|     * Replaced `SafeMath` with `LibSafeMath` (#2254) | ||||
|  | ||||
| ## v2.2.8 - _September 17, 2019_ | ||||
|  | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| { | ||||
|     "artifactsDir": "./generated-artifacts", | ||||
|     "artifactsDir": "./test/generated-artifacts", | ||||
|     "contractsDir": "./contracts", | ||||
|     "useDockerisedSolc": false, | ||||
|     "isOfflineMode": false, | ||||
|   | ||||
| @@ -19,7 +19,7 @@ | ||||
| pragma solidity ^0.5.9; | ||||
|  | ||||
| import "@0x/contracts-utils/contracts/src/LibBytes.sol"; | ||||
| import "@0x/contracts-utils/contracts/src/SafeMath.sol"; | ||||
| import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; | ||||
| import "@0x/contracts-erc1155/contracts/src/interfaces/IERC1155.sol"; | ||||
| import "../archive/MixinAuthorizable.sol"; | ||||
| import "./interfaces/IAssetProxy.sol"; | ||||
| @@ -27,10 +27,10 @@ import "./interfaces/IAssetProxy.sol"; | ||||
|  | ||||
| contract ERC1155Proxy is | ||||
|     MixinAuthorizable, | ||||
|     SafeMath, | ||||
|     IAssetProxy | ||||
| { | ||||
|     using LibBytes for bytes; | ||||
|     using LibSafeMath for uint256; | ||||
|  | ||||
|     // Id of this proxy. | ||||
|     bytes4 constant internal PROXY_ID = bytes4(keccak256("ERC1155Assets(address,uint256[],uint256[],bytes)")); | ||||
| @@ -71,7 +71,7 @@ contract ERC1155Proxy is | ||||
|             // to avoid copying over `ids` or `data`. This is possible if they are | ||||
|             // identical to `values` and the offsets for each are pointing to the | ||||
|             // same location in the ABI encoded calldata. | ||||
|             scaledValues[i] = _safeMul(values[i], amount); | ||||
|             scaledValues[i] = values[i].safeMul(amount); | ||||
|         } | ||||
|  | ||||
|         // Execute `safeBatchTransferFrom` call | ||||
|   | ||||
| @@ -73,7 +73,7 @@ contract ERC20BridgeProxy is | ||||
|         uint256 balanceBefore = balanceOf(tokenAddress, to); | ||||
|         // Call the bridge, who should transfer `amount` of `tokenAddress` to | ||||
|         // `to`. | ||||
|         bytes4 success = IERC20Bridge(bridgeAddress).withdrawTo( | ||||
|         bytes4 success = IERC20Bridge(bridgeAddress).bridgeTransferFrom( | ||||
|             tokenAddress, | ||||
|             from, | ||||
|             to, | ||||
|   | ||||
| @@ -20,9 +20,10 @@ 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 "../interfaces/IERC20Bridge.sol"; | ||||
| import "../interfaces/IEth2Dai.sol"; | ||||
| import "../interfaces/IWallet.sol"; | ||||
|  | ||||
|  | ||||
| // solhint-disable space-after-comma | ||||
| @@ -42,7 +43,7 @@ contract Eth2DaiBridge is | ||||
|     /// @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 withdrawTo( | ||||
|     function bridgeTransferFrom( | ||||
|         address toTokenAddress, | ||||
|         address /* from */, | ||||
|         address to, | ||||
| @@ -57,7 +58,7 @@ contract Eth2DaiBridge is | ||||
|  | ||||
|         IEth2Dai exchange = _getEth2DaiContract(); | ||||
|         // Grant an allowance to the exchange to spend `fromTokenAddress` token. | ||||
|         IERC20Token(fromTokenAddress).approve(address(exchange), uint256(-1)); | ||||
|         LibERC20Token.approve(fromTokenAddress, address(exchange), uint256(-1)); | ||||
|  | ||||
|         // Try to sell all of this contract's `fromTokenAddress` token balance. | ||||
|         uint256 boughtAmount = _getEth2DaiContract().sellAllAmount( | ||||
| @@ -67,7 +68,7 @@ contract Eth2DaiBridge is | ||||
|             amount | ||||
|         ); | ||||
|         // Transfer the converted `toToken`s to `to`. | ||||
|         _transferERC20Token(toTokenAddress, to, boughtAmount); | ||||
|         LibERC20Token.transfer(toTokenAddress, to, boughtAmount); | ||||
|         return BRIDGE_SUCCESS; | ||||
|     } | ||||
|  | ||||
| @@ -94,49 +95,4 @@ contract Eth2DaiBridge is | ||||
|     { | ||||
|         return IEth2Dai(ETH2DAI_ADDRESS); | ||||
|     } | ||||
|  | ||||
|     /// @dev Permissively transfers an ERC20 token that may not adhere to | ||||
|     ///      specs. | ||||
|     /// @param tokenAddress The token contract address. | ||||
|     /// @param to The token recipient. | ||||
|     /// @param amount The amount of tokens to transfer. | ||||
|     function _transferERC20Token( | ||||
|         address tokenAddress, | ||||
|         address to, | ||||
|         uint256 amount | ||||
|     ) | ||||
|         private | ||||
|     { | ||||
|         // Transfer tokens. | ||||
|         // We do a raw call so we can check the success separate | ||||
|         // from the return data. | ||||
|         (bool didSucceed, bytes memory returnData) = tokenAddress.call( | ||||
|             abi.encodeWithSelector( | ||||
|                 IERC20Token(0).transfer.selector, | ||||
|                 to, | ||||
|                 amount | ||||
|             ) | ||||
|         ); | ||||
|         if (!didSucceed) { | ||||
|             assembly { revert(add(returnData, 0x20), mload(returnData)) } | ||||
|         } | ||||
|  | ||||
|         // Check return data. | ||||
|         // If there is no return data, we assume the token incorrectly | ||||
|         // does not return a bool. In this case we expect it to revert | ||||
|         // on failure, which was handled above. | ||||
|         // If the token does return data, we require that it is a single | ||||
|         // value that evaluates to true. | ||||
|         assembly { | ||||
|             if returndatasize { | ||||
|                 didSucceed := 0 | ||||
|                 if eq(returndatasize, 32) { | ||||
|                     // First 64 bytes of memory are reserved scratch space | ||||
|                     returndatacopy(0, 0, 32) | ||||
|                     didSucceed := mload(0) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         require(didSucceed, "ERC20_TRANSFER_FAILED"); | ||||
|     } | ||||
| } | ||||
|   | ||||
							
								
								
									
										219
									
								
								contracts/asset-proxy/contracts/src/bridges/UniswapBridge.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										219
									
								
								contracts/asset-proxy/contracts/src/bridges/UniswapBridge.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,219 @@ | ||||
| /* | ||||
|  | ||||
|   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/interfaces/IEtherToken.sol"; | ||||
| import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol"; | ||||
| import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol"; | ||||
| import "../interfaces/IUniswapExchangeFactory.sol"; | ||||
| import "../interfaces/IUniswapExchange.sol"; | ||||
| import "../interfaces/IERC20Bridge.sol"; | ||||
|  | ||||
|  | ||||
| // solhint-disable space-after-comma | ||||
| // solhint-disable not-rely-on-time | ||||
| contract UniswapBridge is | ||||
|     IERC20Bridge, | ||||
|     IWallet | ||||
| { | ||||
|     /* Mainnet addresses */ | ||||
|     address constant private UNISWAP_EXCHANGE_FACTORY_ADDRESS = 0xc0a47dFe034B400B47bDaD5FecDa2621de6c4d95; | ||||
|     address constant private WETH_ADDRESS = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; | ||||
|  | ||||
|     // Struct to hold `bridgeTransferFrom()` local variables in memory and to avoid | ||||
|     // stack overflows. | ||||
|     struct WithdrawToState { | ||||
|         IUniswapExchange exchange; | ||||
|         uint256 fromTokenBalance; | ||||
|         IEtherToken weth; | ||||
|     } | ||||
|  | ||||
|     // solhint-disable no-empty-blocks | ||||
|     /// @dev Payable fallback to receive ETH from uniswap. | ||||
|     function () | ||||
|         external | ||||
|         payable | ||||
|     {} | ||||
|  | ||||
|     /// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of | ||||
|     ///      `toTokenAddress` tokens by selling the entirety of the `fromTokenAddress` | ||||
|     ///      token encoded in the bridge data. | ||||
|     /// @param toTokenAddress The token to buy and transfer to `to`. | ||||
|     /// @param to The recipient of the bought tokens. | ||||
|     /// @param amount Minimum amount of `toTokenAddress` tokens to buy. | ||||
|     /// @param bridgeData The abi-encoded "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) | ||||
|     { | ||||
|         // State memory object to avoid stack overflows. | ||||
|         WithdrawToState memory state; | ||||
|         // Decode the bridge data to get the `fromTokenAddress`. | ||||
|         (address fromTokenAddress) = abi.decode(bridgeData, (address)); | ||||
|  | ||||
|         // Just transfer the tokens if they're the same. | ||||
|         if (fromTokenAddress == toTokenAddress) { | ||||
|             LibERC20Token.transfer(fromTokenAddress, to, amount); | ||||
|             return BRIDGE_SUCCESS; | ||||
|         } | ||||
|  | ||||
|         // Get the exchange for the token pair. | ||||
|         state.exchange = _getUniswapExchangeForTokenPair( | ||||
|             fromTokenAddress, | ||||
|             toTokenAddress | ||||
|         ); | ||||
|         // Get our balance of `fromTokenAddress` token. | ||||
|         state.fromTokenBalance = IERC20Token(fromTokenAddress).balanceOf(address(this)); | ||||
|         // Get the weth contract. | ||||
|         state.weth = getWethContract(); | ||||
|  | ||||
|         // Convert from WETH to a token. | ||||
|         if (fromTokenAddress == address(state.weth)) { | ||||
|             // Unwrap the WETH. | ||||
|             state.weth.withdraw(state.fromTokenBalance); | ||||
|             // Buy as much of `toTokenAddress` token with ETH as possible and | ||||
|             // transfer it to `to`. | ||||
|             state.exchange.ethToTokenTransferInput.value(state.fromTokenBalance)( | ||||
|                 // Minimum buy amount. | ||||
|                 amount, | ||||
|                 // Expires after this block. | ||||
|                 block.timestamp, | ||||
|                 // Recipient is `to`. | ||||
|                 to | ||||
|             ); | ||||
|  | ||||
|         // Convert from a token to WETH. | ||||
|         } else if (toTokenAddress == address(state.weth)) { | ||||
|             // Grant the exchange an allowance. | ||||
|             _grantExchangeAllowance(state.exchange, fromTokenAddress); | ||||
|             // Buy as much ETH with `fromTokenAddress` token as possible. | ||||
|             uint256 ethBought = state.exchange.tokenToEthSwapInput( | ||||
|                 // Sell all tokens we hold. | ||||
|                 state.fromTokenBalance, | ||||
|                 // Minimum buy amount. | ||||
|                 amount, | ||||
|                 // Expires after this block. | ||||
|                 block.timestamp | ||||
|             ); | ||||
|             // Wrap the ETH. | ||||
|             state.weth.deposit.value(ethBought)(); | ||||
|             // Transfer the WETH to `to`. | ||||
|             IEtherToken(toTokenAddress).transfer(to, ethBought); | ||||
|  | ||||
|         // Convert from one token to another. | ||||
|         } else { | ||||
|             // Grant the exchange an allowance. | ||||
|             _grantExchangeAllowance(state.exchange, fromTokenAddress); | ||||
|             // Buy as much `toTokenAddress` token with `fromTokenAddress` token | ||||
|             // and transfer it to `to`. | ||||
|             state.exchange.tokenToTokenTransferInput( | ||||
|                 // Sell all tokens we hold. | ||||
|                 state.fromTokenBalance, | ||||
|                 // Minimum buy amount. | ||||
|                 amount, | ||||
|                 // No minimum intermediate ETH buy amount. | ||||
|                 0, | ||||
|                 // Expires after this block. | ||||
|                 block.timestamp, | ||||
|                 // Recipient is `to`. | ||||
|                 to, | ||||
|                 // Convert to `toTokenAddress`. | ||||
|                 toTokenAddress | ||||
|             ); | ||||
|         } | ||||
|         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 Success bytes, always. | ||||
|     function isValidSignature( | ||||
|         bytes32, | ||||
|         bytes calldata | ||||
|     ) | ||||
|         external | ||||
|         view | ||||
|         returns (bytes4 magicValue) | ||||
|     { | ||||
|         return LEGACY_WALLET_MAGIC_VALUE; | ||||
|     } | ||||
|  | ||||
|     /// @dev Overridable way to get the weth contract. | ||||
|     /// @return token The WETH contract. | ||||
|     function getWethContract() | ||||
|         public | ||||
|         view | ||||
|         returns (IEtherToken token) | ||||
|     { | ||||
|         return IEtherToken(WETH_ADDRESS); | ||||
|     } | ||||
|  | ||||
|     /// @dev Overridable way to get the uniswap exchange factory contract. | ||||
|     /// @return factory The exchange factory contract. | ||||
|     function getUniswapExchangeFactoryContract() | ||||
|         public | ||||
|         view | ||||
|         returns (IUniswapExchangeFactory factory) | ||||
|     { | ||||
|         return IUniswapExchangeFactory(UNISWAP_EXCHANGE_FACTORY_ADDRESS); | ||||
|     } | ||||
|  | ||||
|     /// @dev Grants an unlimited allowance to the exchange for its token | ||||
|     ///      on behalf of this contract. | ||||
|     /// @param exchange The Uniswap token exchange. | ||||
|     /// @param tokenAddress The token address for the exchange. | ||||
|     function _grantExchangeAllowance(IUniswapExchange exchange, address tokenAddress) | ||||
|         private | ||||
|     { | ||||
|         LibERC20Token.approve(tokenAddress, address(exchange), uint256(-1)); | ||||
|     } | ||||
|  | ||||
|     /// @dev Retrieves the uniswap exchange for a given token pair. | ||||
|     ///      In the case of a WETH-token exchange, this will be the non-WETH token. | ||||
|     ///      In th ecase of a token-token exchange, this will be the first token. | ||||
|     /// @param fromTokenAddress The address of the token we are converting from. | ||||
|     /// @param toTokenAddress The address of the token we are converting to. | ||||
|     /// @return exchange The uniswap exchange. | ||||
|     function _getUniswapExchangeForTokenPair( | ||||
|         address fromTokenAddress, | ||||
|         address toTokenAddress | ||||
|     ) | ||||
|         private | ||||
|         view | ||||
|         returns (IUniswapExchange exchange) | ||||
|     { | ||||
|         address exchangeTokenAddress = fromTokenAddress; | ||||
|         // Whichever isn't WETH is the exchange token. | ||||
|         if (fromTokenAddress == address(getWethContract())) { | ||||
|             exchangeTokenAddress = toTokenAddress; | ||||
|         } | ||||
|         exchange = getUniswapExchangeFactoryContract().getExchange(exchangeTokenAddress); | ||||
|         require(address(exchange) != address(0), "NO_UNISWAP_EXCHANGE_FOR_TOKEN"); | ||||
|         return exchange; | ||||
|     } | ||||
| } | ||||
| @@ -31,7 +31,7 @@ contract IERC20Bridge { | ||||
|     /// @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. | ||||
|     function withdrawTo( | ||||
|     function bridgeTransferFrom( | ||||
|         address tokenAddress, | ||||
|         address from, | ||||
|         address to, | ||||
|   | ||||
| @@ -0,0 +1,77 @@ | ||||
| /* | ||||
|  | ||||
|   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; | ||||
|  | ||||
|  | ||||
| interface IUniswapExchange { | ||||
|  | ||||
|     /// @dev Buys at least `minTokensBought` tokens with ETH and transfer them | ||||
|     ///      to `recipient`. | ||||
|     /// @param minTokensBought The minimum number of tokens to buy. | ||||
|     /// @param deadline Time when this order expires. | ||||
|     /// @param recipient Who to transfer the tokens to. | ||||
|     /// @return tokensBought Amount of tokens bought. | ||||
|     function ethToTokenTransferInput( | ||||
|         uint256 minTokensBought, | ||||
|         uint256 deadline, | ||||
|         address recipient | ||||
|     ) | ||||
|         external | ||||
|         payable | ||||
|         returns (uint256 tokensBought); | ||||
|  | ||||
|     /// @dev Buys at least `minEthBought` ETH with tokens. | ||||
|     /// @param tokensSold Amount of tokens to sell. | ||||
|     /// @param minEthBought The minimum amount of ETH to buy. | ||||
|     /// @param deadline Time when this order expires. | ||||
|     /// @return ethBought Amount of tokens bought. | ||||
|     function tokenToEthSwapInput( | ||||
|         uint256 tokensSold, | ||||
|         uint256 minEthBought, | ||||
|         uint256 deadline | ||||
|     ) | ||||
|         external | ||||
|         returns (uint256 ethBought); | ||||
|  | ||||
|     /// @dev Buys at least `minTokensBought` tokens with the exchange token | ||||
|     ///      and transfer them to `recipient`. | ||||
|     /// @param minTokensBought The minimum number of tokens to buy. | ||||
|     /// @param minEthBought The minimum amount of intermediate ETH to buy. | ||||
|     /// @param deadline Time when this order expires. | ||||
|     /// @param recipient Who to transfer the tokens to. | ||||
|     /// @param toTokenAddress The token being bought. | ||||
|     /// @return tokensBought Amount of tokens bought. | ||||
|     function tokenToTokenTransferInput( | ||||
|         uint256 tokensSold, | ||||
|         uint256 minTokensBought, | ||||
|         uint256 minEthBought, | ||||
|         uint256 deadline, | ||||
|         address recipient, | ||||
|         address toTokenAddress | ||||
|     ) | ||||
|         external | ||||
|         returns (uint256 tokensBought); | ||||
|  | ||||
|     /// @dev Retrieves the token that is associated with this exchange. | ||||
|     /// @return tokenAddress The token address. | ||||
|     function toTokenAddress() | ||||
|         external | ||||
|         view | ||||
|         returns (address tokenAddress); | ||||
| } | ||||
| @@ -16,22 +16,17 @@ | ||||
| 
 | ||||
| */ | ||||
| 
 | ||||
| pragma solidity ^0.5.5; | ||||
| pragma experimental ABIEncoderV2; | ||||
| pragma solidity ^0.5.9; | ||||
| 
 | ||||
| import "@0x/contracts-exchange-libs/contracts/src/LibEIP712ExchangeDomain.sol"; | ||||
| import "../src/MixinSignatureValidator.sol"; | ||||
| import "../src/MixinTransactions.sol"; | ||||
| import "./IUniswapExchange.sol"; | ||||
| 
 | ||||
| 
 | ||||
| contract TestSignatureValidator is | ||||
|     LibEIP712ExchangeDomain, | ||||
|     MixinSignatureValidator | ||||
| { | ||||
| interface IUniswapExchangeFactory { | ||||
| 
 | ||||
|     // solhint-disable no-empty-blocks | ||||
|     constructor (uint256 chainId) | ||||
|         public | ||||
|         LibEIP712ExchangeDomain(chainId, address(0)) | ||||
|     {} | ||||
|     /// @dev Get the exchange for a token. | ||||
|     /// @param tokenAddress The address of the token contract. | ||||
|     function getExchange(address tokenAddress) | ||||
|         external | ||||
|         view | ||||
|         returns (IUniswapExchange); | ||||
| } | ||||
| @@ -72,7 +72,7 @@ contract TestERC20Bridge is | ||||
|         testToken.setBalance(owner, balance); | ||||
|     } | ||||
|  | ||||
|     function withdrawTo( | ||||
|     function bridgeTransferFrom( | ||||
|         address tokenAddress, | ||||
|         address from, | ||||
|         address to, | ||||
|   | ||||
							
								
								
									
										432
									
								
								contracts/asset-proxy/contracts/test/TestUniswapBridge.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										432
									
								
								contracts/asset-proxy/contracts/test/TestUniswapBridge.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,432 @@ | ||||
| /* | ||||
|  | ||||
|   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-utils/contracts/src/LibSafeMath.sol"; | ||||
| import "../src/bridges/UniswapBridge.sol"; | ||||
| import "../src/interfaces/IUniswapExchangeFactory.sol"; | ||||
| import "../src/interfaces/IUniswapExchange.sol"; | ||||
|  | ||||
|  | ||||
| // solhint-disable no-simple-event-func-name | ||||
| contract TestEventsRaiser { | ||||
|  | ||||
|     event TokenTransfer( | ||||
|         address token, | ||||
|         address from, | ||||
|         address to, | ||||
|         uint256 amount | ||||
|     ); | ||||
|  | ||||
|     event TokenApprove( | ||||
|         address spender, | ||||
|         uint256 allowance | ||||
|     ); | ||||
|  | ||||
|     event WethDeposit( | ||||
|         uint256 amount | ||||
|     ); | ||||
|  | ||||
|     event WethWithdraw( | ||||
|         uint256 amount | ||||
|     ); | ||||
|  | ||||
|     event EthToTokenTransferInput( | ||||
|         address exchange, | ||||
|         uint256 minTokensBought, | ||||
|         uint256 deadline, | ||||
|         address recipient | ||||
|     ); | ||||
|  | ||||
|     event TokenToEthSwapInput( | ||||
|         address exchange, | ||||
|         uint256 tokensSold, | ||||
|         uint256 minEthBought, | ||||
|         uint256 deadline | ||||
|     ); | ||||
|  | ||||
|     event TokenToTokenTransferInput( | ||||
|         address exchange, | ||||
|         uint256 tokensSold, | ||||
|         uint256 minTokensBought, | ||||
|         uint256 minEthBought, | ||||
|         uint256 deadline, | ||||
|         address recipient, | ||||
|         address toTokenAddress | ||||
|     ); | ||||
|  | ||||
|     function raiseEthToTokenTransferInput( | ||||
|         uint256 minTokensBought, | ||||
|         uint256 deadline, | ||||
|         address recipient | ||||
|     ) | ||||
|         external | ||||
|     { | ||||
|         emit EthToTokenTransferInput( | ||||
|             msg.sender, | ||||
|             minTokensBought, | ||||
|             deadline, | ||||
|             recipient | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     function raiseTokenToEthSwapInput( | ||||
|         uint256 tokensSold, | ||||
|         uint256 minEthBought, | ||||
|         uint256 deadline | ||||
|     ) | ||||
|         external | ||||
|     { | ||||
|         emit TokenToEthSwapInput( | ||||
|             msg.sender, | ||||
|             tokensSold, | ||||
|             minEthBought, | ||||
|             deadline | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     function raiseTokenToTokenTransferInput( | ||||
|         uint256 tokensSold, | ||||
|         uint256 minTokensBought, | ||||
|         uint256 minEthBought, | ||||
|         uint256 deadline, | ||||
|         address recipient, | ||||
|         address toTokenAddress | ||||
|     ) | ||||
|         external | ||||
|     { | ||||
|         emit TokenToTokenTransferInput( | ||||
|             msg.sender, | ||||
|             tokensSold, | ||||
|             minTokensBought, | ||||
|             minEthBought, | ||||
|             deadline, | ||||
|             recipient, | ||||
|             toTokenAddress | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     function raiseTokenTransfer( | ||||
|         address from, | ||||
|         address to, | ||||
|         uint256 amount | ||||
|     ) | ||||
|         external | ||||
|     { | ||||
|         emit TokenTransfer( | ||||
|             msg.sender, | ||||
|             from, | ||||
|             to, | ||||
|             amount | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     function raiseTokenApprove(address spender, uint256 allowance) | ||||
|         external | ||||
|     { | ||||
|         emit TokenApprove(spender, allowance); | ||||
|     } | ||||
|  | ||||
|     function raiseWethDeposit(uint256 amount) | ||||
|         external | ||||
|     { | ||||
|         emit WethDeposit(amount); | ||||
|     } | ||||
|  | ||||
|     function raiseWethWithdraw(uint256 amount) | ||||
|         external | ||||
|     { | ||||
|         emit WethWithdraw(amount); | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
| /// @dev A minimalist ERC20/WETH token. | ||||
| contract TestToken { | ||||
|  | ||||
|     using LibSafeMath for uint256; | ||||
|  | ||||
|     mapping (address => uint256) public balances; | ||||
|     string private _nextRevertReason; | ||||
|  | ||||
|     /// @dev Set the balance for `owner`. | ||||
|     function setBalance(address owner) | ||||
|         external | ||||
|         payable | ||||
|     { | ||||
|         balances[owner] = msg.value; | ||||
|     } | ||||
|  | ||||
|     /// @dev Set the revert reason for `transfer()`, | ||||
|     ///      `deposit()`, and `withdraw()`. | ||||
|     function setRevertReason(string calldata reason) | ||||
|         external | ||||
|     { | ||||
|         _nextRevertReason = reason; | ||||
|     } | ||||
|  | ||||
|     /// @dev Just calls `raiseTokenTransfer()` on the caller. | ||||
|     function transfer(address to, uint256 amount) | ||||
|         external | ||||
|         returns (bool) | ||||
|     { | ||||
|         _revertIfReasonExists(); | ||||
|         TestEventsRaiser(msg.sender).raiseTokenTransfer(msg.sender, to, amount); | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     /// @dev Just calls `raiseTokenApprove()` on the caller. | ||||
|     function approve(address spender, uint256 allowance) | ||||
|         external | ||||
|         returns (bool) | ||||
|     { | ||||
|         TestEventsRaiser(msg.sender).raiseTokenApprove(spender, allowance); | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     /// @dev `IWETH.deposit()` that increases balances and calls | ||||
|     ///     `raiseWethDeposit()` on the caller. | ||||
|     function deposit() | ||||
|         external | ||||
|         payable | ||||
|     { | ||||
|         _revertIfReasonExists(); | ||||
|         balances[msg.sender] += balances[msg.sender].safeAdd(msg.value); | ||||
|         TestEventsRaiser(msg.sender).raiseWethDeposit(msg.value); | ||||
|     } | ||||
|  | ||||
|     /// @dev `IWETH.withdraw()` that just reduces balances and calls | ||||
|     ///       `raiseWethWithdraw()` on the caller. | ||||
|     function withdraw(uint256 amount) | ||||
|         external | ||||
|     { | ||||
|         _revertIfReasonExists(); | ||||
|         balances[msg.sender] = balances[msg.sender].safeSub(amount); | ||||
|         msg.sender.transfer(amount); | ||||
|         TestEventsRaiser(msg.sender).raiseWethWithdraw(amount); | ||||
|     } | ||||
|  | ||||
|     /// @dev Retrieve the balance for `owner`. | ||||
|     function balanceOf(address owner) | ||||
|         external | ||||
|         view | ||||
|         returns (uint256) | ||||
|     { | ||||
|         return balances[owner]; | ||||
|     } | ||||
|  | ||||
|     function _revertIfReasonExists() | ||||
|         private | ||||
|         view | ||||
|     { | ||||
|         if (bytes(_nextRevertReason).length != 0) { | ||||
|             revert(_nextRevertReason); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
| contract TestExchange is | ||||
|     IUniswapExchange | ||||
| { | ||||
|     address public tokenAddress; | ||||
|     string private _nextRevertReason; | ||||
|  | ||||
|     constructor(address _tokenAddress) public { | ||||
|         tokenAddress = _tokenAddress; | ||||
|     } | ||||
|  | ||||
|     function setFillBehavior( | ||||
|         string calldata revertReason | ||||
|     ) | ||||
|         external | ||||
|         payable | ||||
|     { | ||||
|         _nextRevertReason = revertReason; | ||||
|     } | ||||
|  | ||||
|     function ethToTokenTransferInput( | ||||
|         uint256 minTokensBought, | ||||
|         uint256 deadline, | ||||
|         address recipient | ||||
|     ) | ||||
|         external | ||||
|         payable | ||||
|         returns (uint256 tokensBought) | ||||
|     { | ||||
|         TestEventsRaiser(msg.sender).raiseEthToTokenTransferInput( | ||||
|             minTokensBought, | ||||
|             deadline, | ||||
|             recipient | ||||
|         ); | ||||
|         _revertIfReasonExists(); | ||||
|         return address(this).balance; | ||||
|     } | ||||
|  | ||||
|     function tokenToEthSwapInput( | ||||
|         uint256 tokensSold, | ||||
|         uint256 minEthBought, | ||||
|         uint256 deadline | ||||
|     ) | ||||
|         external | ||||
|         returns (uint256 ethBought) | ||||
|     { | ||||
|         TestEventsRaiser(msg.sender).raiseTokenToEthSwapInput( | ||||
|             tokensSold, | ||||
|             minEthBought, | ||||
|             deadline | ||||
|         ); | ||||
|         _revertIfReasonExists(); | ||||
|         uint256 fillAmount = address(this).balance; | ||||
|         msg.sender.transfer(fillAmount); | ||||
|         return fillAmount; | ||||
|     } | ||||
|  | ||||
|     function tokenToTokenTransferInput( | ||||
|         uint256 tokensSold, | ||||
|         uint256 minTokensBought, | ||||
|         uint256 minEthBought, | ||||
|         uint256 deadline, | ||||
|         address recipient, | ||||
|         address toTokenAddress | ||||
|     ) | ||||
|         external | ||||
|         returns (uint256 tokensBought) | ||||
|     { | ||||
|         TestEventsRaiser(msg.sender).raiseTokenToTokenTransferInput( | ||||
|             tokensSold, | ||||
|             minTokensBought, | ||||
|             minEthBought, | ||||
|             deadline, | ||||
|             recipient, | ||||
|             toTokenAddress | ||||
|         ); | ||||
|         _revertIfReasonExists(); | ||||
|         return address(this).balance; | ||||
|     } | ||||
|  | ||||
|     function toTokenAddress() | ||||
|         external | ||||
|         view | ||||
|         returns (address _tokenAddress) | ||||
|     { | ||||
|         return tokenAddress; | ||||
|     } | ||||
|  | ||||
|     function _revertIfReasonExists() | ||||
|         private | ||||
|         view | ||||
|     { | ||||
|         if (bytes(_nextRevertReason).length != 0) { | ||||
|             revert(_nextRevertReason); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
| /// @dev UniswapBridge overridden to mock tokens and implement IUniswapExchangeFactory. | ||||
| contract TestUniswapBridge is | ||||
|     IUniswapExchangeFactory, | ||||
|     TestEventsRaiser, | ||||
|     UniswapBridge | ||||
| { | ||||
|     TestToken public wethToken; | ||||
|     // Token address to TestToken instance. | ||||
|     mapping (address => TestToken) private _testTokens; | ||||
|     // Token address to TestExchange instance. | ||||
|     mapping (address => TestExchange) private _testExchanges; | ||||
|  | ||||
|     constructor() public { | ||||
|         wethToken = new TestToken(); | ||||
|         _testTokens[address(wethToken)] = wethToken; | ||||
|     } | ||||
|  | ||||
|     /// @dev Sets the balance of this contract for an existing token. | ||||
|     ///      The wei attached will be the balance. | ||||
|     function setTokenBalance(address tokenAddress) | ||||
|         external | ||||
|         payable | ||||
|     { | ||||
|         TestToken token = _testTokens[tokenAddress]; | ||||
|         token.deposit.value(msg.value)(); | ||||
|     } | ||||
|  | ||||
|     /// @dev Sets the revert reason for an existing token. | ||||
|     function setTokenRevertReason(address tokenAddress, string calldata revertReason) | ||||
|         external | ||||
|     { | ||||
|         TestToken token = _testTokens[tokenAddress]; | ||||
|         token.setRevertReason(revertReason); | ||||
|     } | ||||
|  | ||||
|     /// @dev Create a token and exchange (if they don't exist) for a new token | ||||
|     ///      and sets the exchange revert and fill behavior. The wei attached | ||||
|     ///      will be the fill amount for the exchange. | ||||
|     /// @param tokenAddress The token address. If zero, one will be created. | ||||
|     /// @param revertReason The revert reason for exchange operations. | ||||
|     function createTokenAndExchange( | ||||
|         address tokenAddress, | ||||
|         string calldata revertReason | ||||
|     ) | ||||
|         external | ||||
|         payable | ||||
|         returns (TestToken token, TestExchange exchange) | ||||
|     { | ||||
|         token = TestToken(tokenAddress); | ||||
|         if (tokenAddress == address(0)) { | ||||
|             token = new TestToken(); | ||||
|         } | ||||
|         _testTokens[address(token)] = token; | ||||
|         exchange = _testExchanges[address(token)]; | ||||
|         if (address(exchange) == address(0)) { | ||||
|             _testExchanges[address(token)] = exchange = new TestExchange(address(token)); | ||||
|         } | ||||
|         exchange.setFillBehavior.value(msg.value)(revertReason); | ||||
|         return (token, exchange); | ||||
|     } | ||||
|  | ||||
|     /// @dev `IUniswapExchangeFactory.getExchange` | ||||
|     function getExchange(address tokenAddress) | ||||
|         external | ||||
|         view | ||||
|         returns (IUniswapExchange) | ||||
|     { | ||||
|         return IUniswapExchange(_testExchanges[tokenAddress]); | ||||
|     } | ||||
|  | ||||
|     // @dev Use `wethToken`. | ||||
|     function getWethContract() | ||||
|         public | ||||
|         view | ||||
|         returns (IEtherToken) | ||||
|     { | ||||
|         return IEtherToken(address(wethToken)); | ||||
|     } | ||||
|  | ||||
|     // @dev This contract will double as the Uniswap contract. | ||||
|     function getUniswapExchangeFactoryContract() | ||||
|         public | ||||
|         view | ||||
|         returns (IUniswapExchangeFactory) | ||||
|     { | ||||
|         return IUniswapExchangeFactory(address(this)); | ||||
|     } | ||||
| } | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "name": "@0x/contracts-asset-proxy", | ||||
|     "version": "2.3.0-beta.0", | ||||
|     "version": "2.3.0-beta.2", | ||||
|     "engines": { | ||||
|         "node": ">=6.12" | ||||
|     }, | ||||
| @@ -12,7 +12,7 @@ | ||||
|     "scripts": { | ||||
|         "build": "yarn pre_build && tsc -b", | ||||
|         "build:ci": "yarn build", | ||||
|         "pre_build": "run-s compile contracts:gen generate_contract_wrappers", | ||||
|         "pre_build": "run-s compile contracts:gen generate_contract_wrappers contracts:copy", | ||||
|         "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", | ||||
| @@ -21,21 +21,23 @@ | ||||
|         "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 generated-artifacts generated-wrappers", | ||||
|         "generate_contract_wrappers": "abi-gen --abis  ${npm_package_config_abis} --output generated-wrappers --backend ethers", | ||||
|         "lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts", | ||||
|         "fix": "tslint --fix --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts", | ||||
|         "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", | ||||
|         "fix": "tslint --fix --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", | ||||
|         "contracts:gen": "contracts-gen generate", | ||||
|         "contracts:copy": "contracts-gen copy", | ||||
|         "lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol", | ||||
|         "compile:truffle": "truffle compile" | ||||
|     }, | ||||
|     "config": { | ||||
|         "abis": "./generated-artifacts/@(ERC1155Proxy|ERC20BridgeProxy|ERC20Proxy|ERC721Proxy|Eth2DaiBridge|IAssetData|IAssetProxy|IAssetProxyDispatcher|IAuthorizable|IERC20Bridge|IEth2Dai|IWallet|MixinAssetProxyDispatcher|MixinAuthorizable|MultiAssetProxy|Ownable|StaticCallProxy|TestERC20Bridge|TestEth2DaiBridge|TestStaticCallTarget).json", | ||||
|         "publicInterfaceContracts": "ERC1155Proxy,ERC20Proxy,ERC721Proxy,MultiAssetProxy,StaticCallProxy,ERC20BridgeProxy,Eth2DaiBridge,IAssetData,IAssetProxy,UniswapBridge,TestStaticCallTarget", | ||||
|         "abis": "./test/generated-artifacts/@(ERC1155Proxy|ERC20BridgeProxy|ERC20Proxy|ERC721Proxy|Eth2DaiBridge|IAssetData|IAssetProxy|IAssetProxyDispatcher|IAuthorizable|IERC20Bridge|IEth2Dai|IUniswapExchange|IUniswapExchangeFactory|MixinAssetProxyDispatcher|MixinAuthorizable|MultiAssetProxy|Ownable|StaticCallProxy|TestERC20Bridge|TestEth2DaiBridge|TestStaticCallTarget|TestUniswapBridge|UniswapBridge).json", | ||||
|         "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually." | ||||
|     }, | ||||
|     "repository": { | ||||
| @@ -48,12 +50,14 @@ | ||||
|     }, | ||||
|     "homepage": "https://github.com/0xProject/0x-monorepo/contracts/protocol/README.md", | ||||
|     "devDependencies": { | ||||
|         "@0x/abi-gen": "^4.3.0-beta.0", | ||||
|         "@0x/contracts-gen": "^1.1.0-beta.0", | ||||
|         "@0x/contracts-test-utils": "^3.2.0-beta.0", | ||||
|         "@0x/dev-utils": "^2.4.0-beta.0", | ||||
|         "@0x/sol-compiler": "^3.2.0-beta.0", | ||||
|         "@0x/tslint-config": "^3.0.1", | ||||
|         "@0x/abi-gen": "^4.4.0-beta.2", | ||||
|         "@0x/contracts-gen": "^1.1.0-beta.2", | ||||
|         "@0x/contracts-test-utils": "^3.2.0-beta.2", | ||||
|         "@0x/contracts-utils": "^3.3.0-beta.2", | ||||
|         "@0x/dev-utils": "^2.4.0-beta.2", | ||||
|         "@0x/sol-compiler": "^3.2.0-beta.2", | ||||
|         "@0x/tslint-config": "^3.1.0-beta.2", | ||||
|         "@0x/types": "^2.5.0-beta.2", | ||||
|         "@types/lodash": "4.14.104", | ||||
|         "@types/mocha": "^5.2.7", | ||||
|         "@types/node": "*", | ||||
| @@ -61,6 +65,7 @@ | ||||
|         "chai-as-promised": "^7.1.0", | ||||
|         "chai-bignumber": "^3.0.0", | ||||
|         "dirty-chai": "^2.0.1", | ||||
|         "ethereumjs-util": "^5.1.1", | ||||
|         "make-promises-safe": "^1.1.0", | ||||
|         "mocha": "^6.2.0", | ||||
|         "npm-run-all": "^4.1.2", | ||||
| @@ -71,18 +76,16 @@ | ||||
|         "typescript": "3.0.1" | ||||
|     }, | ||||
|     "dependencies": { | ||||
|         "@0x/base-contract": "^5.5.0-beta.0", | ||||
|         "@0x/contracts-erc1155": "^1.2.0-beta.0", | ||||
|         "@0x/contracts-erc20": "^2.3.0-beta.0", | ||||
|         "@0x/contracts-erc721": "^2.2.0-beta.0", | ||||
|         "@0x/contracts-utils": "^3.3.0-beta.0", | ||||
|         "@0x/order-utils": "^8.5.0-beta.0", | ||||
|         "@0x/types": "^2.5.0-beta.0", | ||||
|         "@0x/typescript-typings": "^4.4.0-beta.0", | ||||
|         "@0x/utils": "^4.6.0-beta.0", | ||||
|         "@0x/web3-wrapper": "^6.1.0-beta.0", | ||||
|         "ethereum-types": "^2.2.0-beta.0", | ||||
|         "ethereumjs-util": "^5.1.1", | ||||
|         "@0x/base-contract": "^5.5.0-beta.2", | ||||
|         "@0x/contracts-dev-utils": "^0.1.0-beta.2", | ||||
|         "@0x/contracts-erc1155": "^1.2.0-beta.2", | ||||
|         "@0x/contracts-erc20": "^2.3.0-beta.2", | ||||
|         "@0x/contracts-erc721": "^2.2.0-beta.2", | ||||
|         "@0x/order-utils": "^8.5.0-beta.2", | ||||
|         "@0x/typescript-typings": "^4.4.0-beta.2", | ||||
|         "@0x/utils": "^4.6.0-beta.2", | ||||
|         "@0x/web3-wrapper": "^6.1.0-beta.2", | ||||
|         "ethereum-types": "^2.2.0-beta.2", | ||||
|         "lodash": "^4.17.11" | ||||
|     }, | ||||
|     "publishConfig": { | ||||
|   | ||||
| @@ -12,38 +12,20 @@ import * as ERC721Proxy from '../generated-artifacts/ERC721Proxy.json'; | ||||
| import * as Eth2DaiBridge from '../generated-artifacts/Eth2DaiBridge.json'; | ||||
| import * as IAssetData from '../generated-artifacts/IAssetData.json'; | ||||
| 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 IERC20Bridge from '../generated-artifacts/IERC20Bridge.json'; | ||||
| import * as IEth2Dai from '../generated-artifacts/IEth2Dai.json'; | ||||
| import * as IWallet from '../generated-artifacts/IWallet.json'; | ||||
| import * as MixinAssetProxyDispatcher from '../generated-artifacts/MixinAssetProxyDispatcher.json'; | ||||
| import * as MixinAuthorizable from '../generated-artifacts/MixinAuthorizable.json'; | ||||
| import * as MultiAssetProxy from '../generated-artifacts/MultiAssetProxy.json'; | ||||
| import * as Ownable from '../generated-artifacts/Ownable.json'; | ||||
| import * as StaticCallProxy from '../generated-artifacts/StaticCallProxy.json'; | ||||
| import * as TestERC20Bridge from '../generated-artifacts/TestERC20Bridge.json'; | ||||
| import * as TestEth2DaiBridge from '../generated-artifacts/TestEth2DaiBridge.json'; | ||||
| import * as TestStaticCallTarget from '../generated-artifacts/TestStaticCallTarget.json'; | ||||
| import * as UniswapBridge from '../generated-artifacts/UniswapBridge.json'; | ||||
| export const artifacts = { | ||||
|     MixinAssetProxyDispatcher: MixinAssetProxyDispatcher as ContractArtifact, | ||||
|     MixinAuthorizable: MixinAuthorizable as ContractArtifact, | ||||
|     Ownable: Ownable as ContractArtifact, | ||||
|     ERC1155Proxy: ERC1155Proxy as ContractArtifact, | ||||
|     ERC20BridgeProxy: ERC20BridgeProxy as ContractArtifact, | ||||
|     ERC20Proxy: ERC20Proxy as ContractArtifact, | ||||
|     ERC721Proxy: ERC721Proxy as ContractArtifact, | ||||
|     MultiAssetProxy: MultiAssetProxy as ContractArtifact, | ||||
|     StaticCallProxy: StaticCallProxy as ContractArtifact, | ||||
|     ERC20BridgeProxy: ERC20BridgeProxy as ContractArtifact, | ||||
|     Eth2DaiBridge: Eth2DaiBridge as ContractArtifact, | ||||
|     IAssetData: IAssetData as ContractArtifact, | ||||
|     IAssetProxy: IAssetProxy as ContractArtifact, | ||||
|     IAssetProxyDispatcher: IAssetProxyDispatcher as ContractArtifact, | ||||
|     IAuthorizable: IAuthorizable as ContractArtifact, | ||||
|     IERC20Bridge: IERC20Bridge as ContractArtifact, | ||||
|     IEth2Dai: IEth2Dai as ContractArtifact, | ||||
|     IWallet: IWallet as ContractArtifact, | ||||
|     TestERC20Bridge: TestERC20Bridge as ContractArtifact, | ||||
|     TestEth2DaiBridge: TestEth2DaiBridge as ContractArtifact, | ||||
|     UniswapBridge: UniswapBridge as ContractArtifact, | ||||
|     TestStaticCallTarget: TestStaticCallTarget as ContractArtifact, | ||||
| }; | ||||
|   | ||||
| @@ -1,3 +1,4 @@ | ||||
| import { DevUtilsContract } from '@0x/contracts-dev-utils'; | ||||
| import { artifacts as erc1155Artifacts, ERC1155MintableContract, Erc1155Wrapper } from '@0x/contracts-erc1155'; | ||||
| import { | ||||
|     constants, | ||||
| @@ -7,13 +8,14 @@ import { | ||||
|     LogDecoder, | ||||
|     txDefaults, | ||||
| } from '@0x/contracts-test-utils'; | ||||
| import { assetDataUtils } from '@0x/order-utils'; | ||||
| import { BigNumber } from '@0x/utils'; | ||||
| import { Web3Wrapper } from '@0x/web3-wrapper'; | ||||
| import { Provider, TransactionReceiptWithDecodedLogs } from 'ethereum-types'; | ||||
| import * as _ from 'lodash'; | ||||
| 
 | ||||
| import { artifacts, ERC1155ProxyContract, IAssetProxyContract } from '../../src'; | ||||
| import { artifacts } from './artifacts'; | ||||
| 
 | ||||
| import { ERC1155ProxyContract, IAssetProxyContract } from './wrappers'; | ||||
| 
 | ||||
| export class ERC1155ProxyWrapper { | ||||
|     private readonly _tokenOwnerAddresses: string[]; | ||||
| @@ -26,6 +28,7 @@ export class ERC1155ProxyWrapper { | ||||
|     private readonly _logDecoder: LogDecoder; | ||||
|     private readonly _dummyTokenWrappers: Erc1155Wrapper[]; | ||||
|     private readonly _assetProxyInterface: IAssetProxyContract; | ||||
|     private readonly _devUtils: DevUtilsContract; | ||||
|     private _proxyContract?: ERC1155ProxyContract; | ||||
|     private _proxyIdIfExists?: string; | ||||
|     private _initialTokenIdsByOwner: ERC1155HoldingsByOwner = { fungible: {}, nonFungible: {} }; | ||||
| @@ -37,6 +40,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._tokenOwnerAddresses = tokenOwnerAddresses; | ||||
|         this._contractOwnerAddress = contractOwnerAddress; | ||||
|         this._fungibleTokenIds = []; | ||||
| @@ -72,7 +76,7 @@ export class ERC1155ProxyWrapper { | ||||
|             txDefaults, | ||||
|             artifacts, | ||||
|         ); | ||||
|         this._proxyIdIfExists = await this._proxyContract.getProxyId.callAsync(); | ||||
|         this._proxyIdIfExists = await this._proxyContract.getProxyId().callAsync(); | ||||
|         return this._proxyContract; | ||||
|     } | ||||
|     /** | ||||
| @@ -95,7 +99,7 @@ export class ERC1155ProxyWrapper { | ||||
|      * @param extraData extra data to append to `transferFrom` transaction. Optional. | ||||
|      * @return abi encoded tx data. | ||||
|      */ | ||||
|     public getTransferFromAbiEncodedTxData( | ||||
|     public async getTransferFromAbiEncodedTxDataAsync( | ||||
|         from: string, | ||||
|         to: string, | ||||
|         contractAddress: string, | ||||
| @@ -105,23 +109,17 @@ export class ERC1155ProxyWrapper { | ||||
|         receiverCallbackData: string, | ||||
|         authorizedSender: string, | ||||
|         assetData_?: string, | ||||
|     ): string { | ||||
|     ): Promise<string> { | ||||
|         this._validateProxyContractExistsOrThrow(); | ||||
|         const assetData = | ||||
|             assetData_ === undefined | ||||
|                 ? assetDataUtils.encodeERC1155AssetData( | ||||
|                       contractAddress, | ||||
|                       tokensToTransfer, | ||||
|                       valuesToTransfer, | ||||
|                       receiverCallbackData, | ||||
|                   ) | ||||
|                 ? await this._devUtils | ||||
|                       .encodeERC1155AssetData(contractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData) | ||||
|                       .callAsync() | ||||
|                 : assetData_; | ||||
|         const data = this._assetProxyInterface.transferFrom.getABIEncodedTransactionData( | ||||
|             assetData, | ||||
|             from, | ||||
|             to, | ||||
|             valueMultiplier, | ||||
|         ); | ||||
|         const data = this._assetProxyInterface | ||||
|             .transferFrom(assetData, from, to, valueMultiplier) | ||||
|             .getABIEncodedTransactionData(); | ||||
|         return data; | ||||
|     } | ||||
|     /** | ||||
| @@ -169,19 +167,13 @@ export class ERC1155ProxyWrapper { | ||||
|         this._validateProxyContractExistsOrThrow(); | ||||
|         const assetData = | ||||
|             assetData_ === undefined | ||||
|                 ? assetDataUtils.encodeERC1155AssetData( | ||||
|                       contractAddress, | ||||
|                       tokensToTransfer, | ||||
|                       valuesToTransfer, | ||||
|                       receiverCallbackData, | ||||
|                   ) | ||||
|                 ? await this._devUtils | ||||
|                       .encodeERC1155AssetData(contractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData) | ||||
|                       .callAsync() | ||||
|                 : assetData_; | ||||
|         const data = this._assetProxyInterface.transferFrom.getABIEncodedTransactionData( | ||||
|             assetData, | ||||
|             from, | ||||
|             to, | ||||
|             valueMultiplier, | ||||
|         ); | ||||
|         const data = this._assetProxyInterface | ||||
|             .transferFrom(assetData, from, to, valueMultiplier) | ||||
|             .getABIEncodedTransactionData(); | ||||
|         const txHash = await this._web3Wrapper.sendTransactionAsync({ | ||||
|             to: (this._proxyContract as ERC1155ProxyContract).address, | ||||
|             data, | ||||
| @@ -362,7 +354,7 @@ export class ERC1155ProxyWrapper { | ||||
|         this._validateProxyContractExistsOrThrow(); | ||||
|         const tokenContract = this._getContractFromAddress(contractAddress); | ||||
|         const operator = (this._proxyContract as ERC1155ProxyContract).address; | ||||
|         const didApproveAll = await tokenContract.isApprovedForAll.callAsync(userAddress, operator); | ||||
|         const didApproveAll = await tokenContract.isApprovedForAll(userAddress, operator).callAsync(); | ||||
|         return didApproveAll; | ||||
|     } | ||||
|     public getFungibleTokenIds(): BigNumber[] { | ||||
| @@ -1,17 +1,20 @@ | ||||
| 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 { assetDataUtils } from '@0x/order-utils'; | ||||
| import { BigNumber } from '@0x/utils'; | ||||
| import { ZeroExProvider } from 'ethereum-types'; | ||||
| import * as _ from 'lodash'; | ||||
| 
 | ||||
| import { artifacts, ERC20ProxyContract } from '../../src'; | ||||
| import { artifacts } from './artifacts'; | ||||
| 
 | ||||
| import { ERC20ProxyContract } 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 _proxyContract?: ERC20ProxyContract; | ||||
|     private _proxyIdIfExists?: string; | ||||
|     /** | ||||
| @@ -26,6 +29,7 @@ export class ERC20Wrapper { | ||||
|         this._provider = provider; | ||||
|         this._tokenOwnerAddresses = tokenOwnerAddresses; | ||||
|         this._contractOwnerAddress = contractOwnerAddress; | ||||
|         this._devUtils = new DevUtilsContract(constants.NULL_ADDRESS, provider); | ||||
|     } | ||||
|     public async deployDummyTokensAsync( | ||||
|         numberToDeploy: number, | ||||
| @@ -54,7 +58,7 @@ export class ERC20Wrapper { | ||||
|             txDefaults, | ||||
|             artifacts, | ||||
|         ); | ||||
|         this._proxyIdIfExists = await this._proxyContract.getProxyId.callAsync(); | ||||
|         this._proxyIdIfExists = await this._proxyContract.getProxyId().callAsync(); | ||||
|         return this._proxyContract; | ||||
|     } | ||||
|     public getProxyId(): string { | ||||
| @@ -66,50 +70,39 @@ export class ERC20Wrapper { | ||||
|         this._validateProxyContractExistsOrThrow(); | ||||
|         for (const dummyTokenContract of this._dummyTokenContracts) { | ||||
|             for (const tokenOwnerAddress of this._tokenOwnerAddresses) { | ||||
|                 await dummyTokenContract.setBalance.awaitTransactionSuccessAsync( | ||||
|                     tokenOwnerAddress, | ||||
|                     constants.INITIAL_ERC20_BALANCE, | ||||
|                     { from: this._contractOwnerAddress }, | ||||
|                     constants.AWAIT_TRANSACTION_MINED_MS, | ||||
|                 ); | ||||
|                 await dummyTokenContract.approve.awaitTransactionSuccessAsync( | ||||
|                     (this._proxyContract as ERC20ProxyContract).address, | ||||
|                     constants.INITIAL_ERC20_ALLOWANCE, | ||||
|                     { from: tokenOwnerAddress }, | ||||
|                     constants.AWAIT_TRANSACTION_MINED_MS, | ||||
|                 ); | ||||
|                 await dummyTokenContract | ||||
|                     .setBalance(tokenOwnerAddress, constants.INITIAL_ERC20_BALANCE) | ||||
|                     .awaitTransactionSuccessAsync({ from: this._contractOwnerAddress }); | ||||
|                 await dummyTokenContract | ||||
|                     .approve((this._proxyContract as ERC20ProxyContract).address, constants.INITIAL_ERC20_ALLOWANCE) | ||||
|                     .awaitTransactionSuccessAsync({ from: tokenOwnerAddress }); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     public async getBalanceAsync(userAddress: string, assetData: string): Promise<BigNumber> { | ||||
|         const tokenContract = this._getTokenContractFromAssetData(assetData); | ||||
|         const balance = new BigNumber(await tokenContract.balanceOf.callAsync(userAddress)); | ||||
|         const tokenContract = await this._getTokenContractFromAssetDataAsync(assetData); | ||||
|         const balance = new BigNumber(await tokenContract.balanceOf(userAddress).callAsync()); | ||||
|         return balance; | ||||
|     } | ||||
|     public async setBalanceAsync(userAddress: string, assetData: string, amount: BigNumber): Promise<void> { | ||||
|         const tokenContract = this._getTokenContractFromAssetData(assetData); | ||||
|         await tokenContract.setBalance.awaitTransactionSuccessAsync( | ||||
|             userAddress, | ||||
|             amount, | ||||
|             { from: this._contractOwnerAddress }, | ||||
|             constants.AWAIT_TRANSACTION_MINED_MS, | ||||
|         ); | ||||
|         const tokenContract = await this._getTokenContractFromAssetDataAsync(assetData); | ||||
|         await tokenContract | ||||
|             .setBalance(userAddress, amount) | ||||
|             .awaitTransactionSuccessAsync( | ||||
|                 { from: this._contractOwnerAddress }, | ||||
|                 { pollingIntervalMs: constants.AWAIT_TRANSACTION_MINED_MS }, | ||||
|             ); | ||||
|     } | ||||
|     public async getProxyAllowanceAsync(userAddress: string, assetData: string): Promise<BigNumber> { | ||||
|         const tokenContract = this._getTokenContractFromAssetData(assetData); | ||||
|         const tokenContract = await this._getTokenContractFromAssetDataAsync(assetData); | ||||
|         const proxyAddress = (this._proxyContract as ERC20ProxyContract).address; | ||||
|         const allowance = new BigNumber(await tokenContract.allowance.callAsync(userAddress, proxyAddress)); | ||||
|         const allowance = new BigNumber(await tokenContract.allowance(userAddress, proxyAddress).callAsync()); | ||||
|         return allowance; | ||||
|     } | ||||
|     public async setAllowanceAsync(userAddress: string, assetData: string, amount: BigNumber): Promise<void> { | ||||
|         const tokenContract = this._getTokenContractFromAssetData(assetData); | ||||
|         const tokenContract = await this._getTokenContractFromAssetDataAsync(assetData); | ||||
|         const proxyAddress = (this._proxyContract as ERC20ProxyContract).address; | ||||
|         await tokenContract.approve.awaitTransactionSuccessAsync( | ||||
|             proxyAddress, | ||||
|             amount, | ||||
|             { from: userAddress }, | ||||
|             constants.AWAIT_TRANSACTION_MINED_MS, | ||||
|         ); | ||||
|         await tokenContract.approve(proxyAddress, amount).awaitTransactionSuccessAsync({ from: userAddress }); | ||||
|     } | ||||
|     public async getBalancesAsync(): Promise<ERC20BalancesByOwner> { | ||||
|         this._validateDummyTokenContractsExistOrThrow(); | ||||
| @@ -118,7 +111,7 @@ export class ERC20Wrapper { | ||||
|         const balanceInfo: Array<{ tokenOwnerAddress: string; tokenAddress: string }> = []; | ||||
|         for (const dummyTokenContract of this._dummyTokenContracts) { | ||||
|             for (const tokenOwnerAddress of this._tokenOwnerAddresses) { | ||||
|                 balances.push(await dummyTokenContract.balanceOf.callAsync(tokenOwnerAddress)); | ||||
|                 balances.push(await dummyTokenContract.balanceOf(tokenOwnerAddress).callAsync()); | ||||
|                 balanceInfo.push({ | ||||
|                     tokenOwnerAddress, | ||||
|                     tokenAddress: dummyTokenContract.address, | ||||
| @@ -151,9 +144,8 @@ export class ERC20Wrapper { | ||||
|         const tokenAddresses = _.map(this._dummyTokenContracts, dummyTokenContract => dummyTokenContract.address); | ||||
|         return tokenAddresses; | ||||
|     } | ||||
|     private _getTokenContractFromAssetData(assetData: string): DummyERC20TokenContract { | ||||
|         const erc20ProxyData = assetDataUtils.decodeERC20AssetData(assetData); | ||||
|         const tokenAddress = erc20ProxyData.tokenAddress; | ||||
|     private async _getTokenContractFromAssetDataAsync(assetData: string): Promise<DummyERC20TokenContract> { | ||||
|         const [proxyId, tokenAddress] = await this._devUtils.decodeERC20AssetData(assetData).callAsync(); // 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`); | ||||
| @@ -5,7 +5,9 @@ import { BigNumber } from '@0x/utils'; | ||||
| import { ZeroExProvider } from 'ethereum-types'; | ||||
| import * as _ from 'lodash'; | ||||
| 
 | ||||
| import { artifacts, ERC721ProxyContract } from '../../src'; | ||||
| import { artifacts } from './artifacts'; | ||||
| 
 | ||||
| import { ERC721ProxyContract } from './wrappers'; | ||||
| 
 | ||||
| export class ERC721Wrapper { | ||||
|     private readonly _tokenOwnerAddresses: string[]; | ||||
| @@ -44,7 +46,7 @@ export class ERC721Wrapper { | ||||
|             txDefaults, | ||||
|             artifacts, | ||||
|         ); | ||||
|         this._proxyIdIfExists = await this._proxyContract.getProxyId.callAsync(); | ||||
|         this._proxyIdIfExists = await this._proxyContract.getProxyId().callAsync(); | ||||
|         return this._proxyContract; | ||||
|     } | ||||
|     public getProxyId(): string { | ||||
| @@ -78,7 +80,7 @@ export class ERC721Wrapper { | ||||
|     } | ||||
|     public async doesTokenExistAsync(tokenAddress: string, tokenId: BigNumber): Promise<boolean> { | ||||
|         const tokenContract = this._getTokenContractFromAssetData(tokenAddress); | ||||
|         const owner = await tokenContract.ownerOf.callAsync(tokenId); | ||||
|         const owner = await tokenContract.ownerOf(tokenId).callAsync(); | ||||
|         const doesExist = owner !== constants.NULL_ADDRESS; | ||||
|         return doesExist; | ||||
|     } | ||||
| @@ -93,22 +95,14 @@ export class ERC721Wrapper { | ||||
|     ): Promise<void> { | ||||
|         const tokenContract = this._getTokenContractFromAssetData(tokenAddress); | ||||
|         const proxyAddress = (this._proxyContract as ERC721ProxyContract).address; | ||||
|         await tokenContract.setApprovalForAll.awaitTransactionSuccessAsync( | ||||
|             proxyAddress, | ||||
|             isApproved, | ||||
|             { from: ownerAddress }, | ||||
|             constants.AWAIT_TRANSACTION_MINED_MS, | ||||
|         ); | ||||
|         await tokenContract.setApprovalForAll(proxyAddress, isApproved).awaitTransactionSuccessAsync({ | ||||
|             from: ownerAddress, | ||||
|         }); | ||||
|     } | ||||
|     public async approveAsync(to: string, tokenAddress: string, tokenId: BigNumber): Promise<void> { | ||||
|         const tokenContract = this._getTokenContractFromAssetData(tokenAddress); | ||||
|         const tokenOwner = await this.ownerOfAsync(tokenAddress, tokenId); | ||||
|         await tokenContract.approve.awaitTransactionSuccessAsync( | ||||
|             to, | ||||
|             tokenId, | ||||
|             { from: tokenOwner }, | ||||
|             constants.AWAIT_TRANSACTION_MINED_MS, | ||||
|         ); | ||||
|         await tokenContract.approve(to, tokenId).awaitTransactionSuccessAsync({ from: tokenOwner }); | ||||
|     } | ||||
|     public async transferFromAsync( | ||||
|         tokenAddress: string, | ||||
| @@ -117,40 +111,28 @@ export class ERC721Wrapper { | ||||
|         userAddress: string, | ||||
|     ): Promise<void> { | ||||
|         const tokenContract = this._getTokenContractFromAssetData(tokenAddress); | ||||
|         await tokenContract.transferFrom.awaitTransactionSuccessAsync( | ||||
|             currentOwner, | ||||
|             userAddress, | ||||
|             tokenId, | ||||
|             { from: currentOwner }, | ||||
|             constants.AWAIT_TRANSACTION_MINED_MS, | ||||
|         ); | ||||
|         await tokenContract.transferFrom(currentOwner, userAddress, tokenId).awaitTransactionSuccessAsync({ | ||||
|             from: currentOwner, | ||||
|         }); | ||||
|     } | ||||
|     public async mintAsync(tokenAddress: string, tokenId: BigNumber, userAddress: string): Promise<void> { | ||||
|         const tokenContract = this._getTokenContractFromAssetData(tokenAddress); | ||||
|         await tokenContract.mint.awaitTransactionSuccessAsync( | ||||
|             userAddress, | ||||
|             tokenId, | ||||
|             { from: this._contractOwnerAddress }, | ||||
|             constants.AWAIT_TRANSACTION_MINED_MS, | ||||
|         ); | ||||
|         await tokenContract.mint(userAddress, tokenId).awaitTransactionSuccessAsync({ | ||||
|             from: this._contractOwnerAddress, | ||||
|         }); | ||||
|     } | ||||
|     public async burnAsync(tokenAddress: string, tokenId: BigNumber, owner: string): Promise<void> { | ||||
|         const tokenContract = this._getTokenContractFromAssetData(tokenAddress); | ||||
|         await tokenContract.burn.awaitTransactionSuccessAsync( | ||||
|             owner, | ||||
|             tokenId, | ||||
|             { from: this._contractOwnerAddress }, | ||||
|             constants.AWAIT_TRANSACTION_MINED_MS, | ||||
|         ); | ||||
|         await tokenContract.burn(owner, tokenId).awaitTransactionSuccessAsync({ from: this._contractOwnerAddress }); | ||||
|     } | ||||
|     public async ownerOfAsync(tokenAddress: string, tokenId: BigNumber): Promise<string> { | ||||
|         const tokenContract = this._getTokenContractFromAssetData(tokenAddress); | ||||
|         const owner = await tokenContract.ownerOf.callAsync(tokenId); | ||||
|         const owner = await tokenContract.ownerOf(tokenId).callAsync(); | ||||
|         return owner; | ||||
|     } | ||||
|     public async isOwnerAsync(userAddress: string, tokenAddress: string, tokenId: BigNumber): Promise<boolean> { | ||||
|         const tokenContract = this._getTokenContractFromAssetData(tokenAddress); | ||||
|         const tokenOwner = await tokenContract.ownerOf.callAsync(tokenId); | ||||
|         const tokenOwner = await tokenContract.ownerOf(tokenId).callAsync(); | ||||
|         const isOwner = tokenOwner === userAddress; | ||||
|         return isOwner; | ||||
|     } | ||||
| @@ -158,13 +140,13 @@ export class ERC721Wrapper { | ||||
|         this._validateProxyContractExistsOrThrow(); | ||||
|         const tokenContract = this._getTokenContractFromAssetData(tokenAddress); | ||||
|         const operator = (this._proxyContract as ERC721ProxyContract).address; | ||||
|         const didApproveAll = await tokenContract.isApprovedForAll.callAsync(userAddress, operator); | ||||
|         const didApproveAll = await tokenContract.isApprovedForAll(userAddress, operator).callAsync(); | ||||
|         return didApproveAll; | ||||
|     } | ||||
|     public async isProxyApprovedAsync(tokenAddress: string, tokenId: BigNumber): Promise<boolean> { | ||||
|         this._validateProxyContractExistsOrThrow(); | ||||
|         const tokenContract = this._getTokenContractFromAssetData(tokenAddress); | ||||
|         const approvedAddress = await tokenContract.getApproved.callAsync(tokenId); | ||||
|         const approvedAddress = await tokenContract.getApproved(tokenId).callAsync(); | ||||
|         const proxyAddress = (this._proxyContract as ERC721ProxyContract).address; | ||||
|         const isProxyAnApprovedOperator = approvedAddress === proxyAddress; | ||||
|         return isProxyAnApprovedOperator; | ||||
| @@ -181,7 +163,7 @@ export class ERC721Wrapper { | ||||
|                     dummyTokenContract.address | ||||
|                 ]; | ||||
|                 for (const tokenId of initialTokenOwnerIds) { | ||||
|                     tokenOwnerAddresses.push(await dummyTokenContract.ownerOf.callAsync(tokenId)); | ||||
|                     tokenOwnerAddresses.push(await dummyTokenContract.ownerOf(tokenId).callAsync()); | ||||
|                     tokenInfo.push({ | ||||
|                         tokenId, | ||||
|                         tokenAddress: dummyTokenContract.address, | ||||
| @@ -1,3 +1,6 @@ | ||||
| export * from './artifacts'; | ||||
| export * from './wrappers'; | ||||
| export * from '../test/utils'; | ||||
|  | ||||
| export { ERC20Wrapper } from './erc20_wrapper'; | ||||
| export { ERC721Wrapper } from './erc721_wrapper'; | ||||
| export { ERC1155ProxyWrapper } from './erc1155_proxy_wrapper'; | ||||
|   | ||||
| @@ -10,16 +10,7 @@ export * from '../generated-wrappers/erc721_proxy'; | ||||
| export * from '../generated-wrappers/eth2_dai_bridge'; | ||||
| export * from '../generated-wrappers/i_asset_data'; | ||||
| 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_erc20_bridge'; | ||||
| export * from '../generated-wrappers/i_eth2_dai'; | ||||
| export * from '../generated-wrappers/i_wallet'; | ||||
| export * from '../generated-wrappers/mixin_asset_proxy_dispatcher'; | ||||
| export * from '../generated-wrappers/mixin_authorizable'; | ||||
| export * from '../generated-wrappers/multi_asset_proxy'; | ||||
| export * from '../generated-wrappers/ownable'; | ||||
| export * from '../generated-wrappers/static_call_proxy'; | ||||
| export * from '../generated-wrappers/test_erc20_bridge'; | ||||
| export * from '../generated-wrappers/test_eth2_dai_bridge'; | ||||
| export * from '../generated-wrappers/test_static_call_target'; | ||||
| export * from '../generated-wrappers/uniswap_bridge'; | ||||
|   | ||||
							
								
								
									
										55
									
								
								contracts/asset-proxy/test/artifacts.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								contracts/asset-proxy/test/artifacts.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,55 @@ | ||||
| /* | ||||
|  * ----------------------------------------------------------------------------- | ||||
|  * Warning: This file is auto-generated by contracts-gen. Don't edit manually. | ||||
|  * ----------------------------------------------------------------------------- | ||||
|  */ | ||||
| import { ContractArtifact } from 'ethereum-types'; | ||||
|  | ||||
| import * as ERC1155Proxy from '../test/generated-artifacts/ERC1155Proxy.json'; | ||||
| import * as ERC20BridgeProxy from '../test/generated-artifacts/ERC20BridgeProxy.json'; | ||||
| import * as ERC20Proxy from '../test/generated-artifacts/ERC20Proxy.json'; | ||||
| import * as ERC721Proxy from '../test/generated-artifacts/ERC721Proxy.json'; | ||||
| import * as Eth2DaiBridge from '../test/generated-artifacts/Eth2DaiBridge.json'; | ||||
| import * as IAssetData from '../test/generated-artifacts/IAssetData.json'; | ||||
| 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 IERC20Bridge from '../test/generated-artifacts/IERC20Bridge.json'; | ||||
| import * as IEth2Dai from '../test/generated-artifacts/IEth2Dai.json'; | ||||
| import * as IUniswapExchange from '../test/generated-artifacts/IUniswapExchange.json'; | ||||
| import * as IUniswapExchangeFactory from '../test/generated-artifacts/IUniswapExchangeFactory.json'; | ||||
| import * as MixinAssetProxyDispatcher from '../test/generated-artifacts/MixinAssetProxyDispatcher.json'; | ||||
| import * as MixinAuthorizable from '../test/generated-artifacts/MixinAuthorizable.json'; | ||||
| import * as MultiAssetProxy from '../test/generated-artifacts/MultiAssetProxy.json'; | ||||
| import * as Ownable from '../test/generated-artifacts/Ownable.json'; | ||||
| import * as StaticCallProxy from '../test/generated-artifacts/StaticCallProxy.json'; | ||||
| import * as TestERC20Bridge from '../test/generated-artifacts/TestERC20Bridge.json'; | ||||
| import * as TestEth2DaiBridge from '../test/generated-artifacts/TestEth2DaiBridge.json'; | ||||
| import * as TestStaticCallTarget from '../test/generated-artifacts/TestStaticCallTarget.json'; | ||||
| import * as TestUniswapBridge from '../test/generated-artifacts/TestUniswapBridge.json'; | ||||
| import * as UniswapBridge from '../test/generated-artifacts/UniswapBridge.json'; | ||||
| export const artifacts = { | ||||
|     MixinAssetProxyDispatcher: MixinAssetProxyDispatcher as ContractArtifact, | ||||
|     MixinAuthorizable: MixinAuthorizable as ContractArtifact, | ||||
|     Ownable: Ownable as ContractArtifact, | ||||
|     ERC1155Proxy: ERC1155Proxy as ContractArtifact, | ||||
|     ERC20BridgeProxy: ERC20BridgeProxy as ContractArtifact, | ||||
|     ERC20Proxy: ERC20Proxy as ContractArtifact, | ||||
|     ERC721Proxy: ERC721Proxy as ContractArtifact, | ||||
|     MultiAssetProxy: MultiAssetProxy as ContractArtifact, | ||||
|     StaticCallProxy: StaticCallProxy as ContractArtifact, | ||||
|     Eth2DaiBridge: Eth2DaiBridge as ContractArtifact, | ||||
|     UniswapBridge: UniswapBridge as ContractArtifact, | ||||
|     IAssetData: IAssetData as ContractArtifact, | ||||
|     IAssetProxy: IAssetProxy as ContractArtifact, | ||||
|     IAssetProxyDispatcher: IAssetProxyDispatcher as ContractArtifact, | ||||
|     IAuthorizable: IAuthorizable as ContractArtifact, | ||||
|     IERC20Bridge: IERC20Bridge as ContractArtifact, | ||||
|     IEth2Dai: IEth2Dai as ContractArtifact, | ||||
|     IUniswapExchange: IUniswapExchange as ContractArtifact, | ||||
|     IUniswapExchangeFactory: IUniswapExchangeFactory as ContractArtifact, | ||||
|     TestERC20Bridge: TestERC20Bridge as ContractArtifact, | ||||
|     TestEth2DaiBridge: TestEth2DaiBridge as ContractArtifact, | ||||
|     TestStaticCallTarget: TestStaticCallTarget as ContractArtifact, | ||||
|     TestUniswapBridge: TestUniswapBridge as ContractArtifact, | ||||
| }; | ||||
| @@ -1,18 +1,13 @@ | ||||
| import { | ||||
|     chaiSetup, | ||||
|     constants, | ||||
|     expectTransactionFailedAsync, | ||||
|     provider, | ||||
|     txDefaults, | ||||
|     web3Wrapper, | ||||
| } from '@0x/contracts-test-utils'; | ||||
| import { chaiSetup, expectTransactionFailedAsync, provider, txDefaults, web3Wrapper } from '@0x/contracts-test-utils'; | ||||
| import { BlockchainLifecycle } from '@0x/dev-utils'; | ||||
| import { RevertReason } from '@0x/types'; | ||||
| import { BigNumber } from '@0x/utils'; | ||||
| import * as chai from 'chai'; | ||||
| import * as _ from 'lodash'; | ||||
|  | ||||
| import { artifacts, MixinAuthorizableContract } from '../src'; | ||||
| import { artifacts } from './artifacts'; | ||||
|  | ||||
| import { MixinAuthorizableContract } from './wrappers'; | ||||
|  | ||||
| chaiSetup.configure(); | ||||
| const expect = chai.expect; | ||||
| @@ -54,29 +49,21 @@ describe('Authorizable', () => { | ||||
|     describe('addAuthorizedAddress', () => { | ||||
|         it('should revert if not called by owner', async () => { | ||||
|             await expectTransactionFailedAsync( | ||||
|                 authorizable.addAuthorizedAddress.sendTransactionAsync(notOwner, { from: notOwner }), | ||||
|                 authorizable.addAuthorizedAddress(notOwner).sendTransactionAsync({ from: notOwner }), | ||||
|                 RevertReason.OnlyContractOwner, | ||||
|             ); | ||||
|         }); | ||||
|  | ||||
|         it('should allow owner to add an authorized address', async () => { | ||||
|             await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync( | ||||
|                 address, | ||||
|                 { from: owner }, | ||||
|                 constants.AWAIT_TRANSACTION_MINED_MS, | ||||
|             ); | ||||
|             const isAuthorized = await authorizable.authorized.callAsync(address); | ||||
|             await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner }); | ||||
|             const isAuthorized = await authorizable.authorized(address).callAsync(); | ||||
|             expect(isAuthorized).to.be.true(); | ||||
|         }); | ||||
|  | ||||
|         it('should revert if owner attempts to authorize a duplicate address', async () => { | ||||
|             await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync( | ||||
|                 address, | ||||
|                 { from: owner }, | ||||
|                 constants.AWAIT_TRANSACTION_MINED_MS, | ||||
|             ); | ||||
|             await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner }); | ||||
|             return expectTransactionFailedAsync( | ||||
|                 authorizable.addAuthorizedAddress.sendTransactionAsync(address, { from: owner }), | ||||
|                 authorizable.addAuthorizedAddress(address).sendTransactionAsync({ from: owner }), | ||||
|                 RevertReason.TargetAlreadyAuthorized, | ||||
|             ); | ||||
|         }); | ||||
| @@ -84,35 +71,23 @@ describe('Authorizable', () => { | ||||
|  | ||||
|     describe('removeAuthorizedAddress', () => { | ||||
|         it('should revert if not called by owner', async () => { | ||||
|             await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync( | ||||
|                 address, | ||||
|                 { from: owner }, | ||||
|                 constants.AWAIT_TRANSACTION_MINED_MS, | ||||
|             ); | ||||
|             await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner }); | ||||
|             await expectTransactionFailedAsync( | ||||
|                 authorizable.removeAuthorizedAddress.sendTransactionAsync(address, { from: notOwner }), | ||||
|                 authorizable.removeAuthorizedAddress(address).sendTransactionAsync({ from: notOwner }), | ||||
|                 RevertReason.OnlyContractOwner, | ||||
|             ); | ||||
|         }); | ||||
|  | ||||
|         it('should allow owner to remove an authorized address', async () => { | ||||
|             await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync( | ||||
|                 address, | ||||
|                 { from: owner }, | ||||
|                 constants.AWAIT_TRANSACTION_MINED_MS, | ||||
|             ); | ||||
|             await authorizable.removeAuthorizedAddress.awaitTransactionSuccessAsync( | ||||
|                 address, | ||||
|                 { from: owner }, | ||||
|                 constants.AWAIT_TRANSACTION_MINED_MS, | ||||
|             ); | ||||
|             const isAuthorized = await authorizable.authorized.callAsync(address); | ||||
|             await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner }); | ||||
|             await authorizable.removeAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner }); | ||||
|             const isAuthorized = await authorizable.authorized(address).callAsync(); | ||||
|             expect(isAuthorized).to.be.false(); | ||||
|         }); | ||||
|  | ||||
|         it('should revert if owner attempts to remove an address that is not authorized', async () => { | ||||
|             return expectTransactionFailedAsync( | ||||
|                 authorizable.removeAuthorizedAddress.sendTransactionAsync(address, { | ||||
|                 authorizable.removeAuthorizedAddress(address).sendTransactionAsync({ | ||||
|                     from: owner, | ||||
|                 }), | ||||
|                 RevertReason.TargetNotAuthorized, | ||||
| @@ -122,14 +97,10 @@ describe('Authorizable', () => { | ||||
|  | ||||
|     describe('removeAuthorizedAddressAtIndex', () => { | ||||
|         it('should revert if not called by owner', async () => { | ||||
|             await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync( | ||||
|                 address, | ||||
|                 { from: owner }, | ||||
|                 constants.AWAIT_TRANSACTION_MINED_MS, | ||||
|             ); | ||||
|             await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner }); | ||||
|             const index = new BigNumber(0); | ||||
|             await expectTransactionFailedAsync( | ||||
|                 authorizable.removeAuthorizedAddressAtIndex.sendTransactionAsync(address, index, { | ||||
|                 authorizable.removeAuthorizedAddressAtIndex(address, index).sendTransactionAsync({ | ||||
|                     from: notOwner, | ||||
|                 }), | ||||
|                 RevertReason.OnlyContractOwner, | ||||
| @@ -137,14 +108,10 @@ describe('Authorizable', () => { | ||||
|         }); | ||||
|  | ||||
|         it('should revert if index is >= authorities.length', async () => { | ||||
|             await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync( | ||||
|                 address, | ||||
|                 { from: owner }, | ||||
|                 constants.AWAIT_TRANSACTION_MINED_MS, | ||||
|             ); | ||||
|             await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner }); | ||||
|             const index = new BigNumber(1); | ||||
|             return expectTransactionFailedAsync( | ||||
|                 authorizable.removeAuthorizedAddressAtIndex.sendTransactionAsync(address, index, { | ||||
|                 authorizable.removeAuthorizedAddressAtIndex(address, index).sendTransactionAsync({ | ||||
|                     from: owner, | ||||
|                 }), | ||||
|                 RevertReason.IndexOutOfBounds, | ||||
| @@ -154,7 +121,7 @@ describe('Authorizable', () => { | ||||
|         it('should revert if owner attempts to remove an address that is not authorized', async () => { | ||||
|             const index = new BigNumber(0); | ||||
|             return expectTransactionFailedAsync( | ||||
|                 authorizable.removeAuthorizedAddressAtIndex.sendTransactionAsync(address, index, { | ||||
|                 authorizable.removeAuthorizedAddressAtIndex(address, index).sendTransactionAsync({ | ||||
|                     from: owner, | ||||
|                 }), | ||||
|                 RevertReason.TargetNotAuthorized, | ||||
| @@ -164,19 +131,11 @@ describe('Authorizable', () => { | ||||
|         it('should revert if address at index does not match target', async () => { | ||||
|             const address1 = address; | ||||
|             const address2 = notOwner; | ||||
|             await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync( | ||||
|                 address1, | ||||
|                 { from: owner }, | ||||
|                 constants.AWAIT_TRANSACTION_MINED_MS, | ||||
|             ); | ||||
|             await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync( | ||||
|                 address2, | ||||
|                 { from: owner }, | ||||
|                 constants.AWAIT_TRANSACTION_MINED_MS, | ||||
|             ); | ||||
|             await authorizable.addAuthorizedAddress(address1).awaitTransactionSuccessAsync({ from: owner }); | ||||
|             await authorizable.addAuthorizedAddress(address2).awaitTransactionSuccessAsync({ from: owner }); | ||||
|             const address1Index = new BigNumber(0); | ||||
|             return expectTransactionFailedAsync( | ||||
|                 authorizable.removeAuthorizedAddressAtIndex.sendTransactionAsync(address2, address1Index, { | ||||
|                 authorizable.removeAuthorizedAddressAtIndex(address2, address1Index).sendTransactionAsync({ | ||||
|                     from: owner, | ||||
|                 }), | ||||
|                 RevertReason.AuthorizedAddressMismatch, | ||||
| @@ -184,41 +143,26 @@ describe('Authorizable', () => { | ||||
|         }); | ||||
|  | ||||
|         it('should allow owner to remove an authorized address', async () => { | ||||
|             await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync( | ||||
|                 address, | ||||
|                 { from: owner }, | ||||
|                 constants.AWAIT_TRANSACTION_MINED_MS, | ||||
|             ); | ||||
|             await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner }); | ||||
|             const index = new BigNumber(0); | ||||
|             await authorizable.removeAuthorizedAddressAtIndex.awaitTransactionSuccessAsync( | ||||
|                 address, | ||||
|                 index, | ||||
|                 { from: owner }, | ||||
|                 constants.AWAIT_TRANSACTION_MINED_MS, | ||||
|             ); | ||||
|             const isAuthorized = await authorizable.authorized.callAsync(address); | ||||
|             await authorizable.removeAuthorizedAddressAtIndex(address, index).awaitTransactionSuccessAsync({ | ||||
|                 from: owner, | ||||
|             }); | ||||
|             const isAuthorized = await authorizable.authorized(address).callAsync(); | ||||
|             expect(isAuthorized).to.be.false(); | ||||
|         }); | ||||
|     }); | ||||
|  | ||||
|     describe('getAuthorizedAddresses', () => { | ||||
|         it('should return all authorized addresses', async () => { | ||||
|             const initial = await authorizable.getAuthorizedAddresses.callAsync(); | ||||
|             const initial = await authorizable.getAuthorizedAddresses().callAsync(); | ||||
|             expect(initial).to.have.length(0); | ||||
|             await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync( | ||||
|                 address, | ||||
|                 { from: owner }, | ||||
|                 constants.AWAIT_TRANSACTION_MINED_MS, | ||||
|             ); | ||||
|             const afterAdd = await authorizable.getAuthorizedAddresses.callAsync(); | ||||
|             await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner }); | ||||
|             const afterAdd = await authorizable.getAuthorizedAddresses().callAsync(); | ||||
|             expect(afterAdd).to.have.length(1); | ||||
|             expect(afterAdd).to.include(address); | ||||
|             await authorizable.removeAuthorizedAddress.awaitTransactionSuccessAsync( | ||||
|                 address, | ||||
|                 { from: owner }, | ||||
|                 constants.AWAIT_TRANSACTION_MINED_MS, | ||||
|             ); | ||||
|             const afterRemove = await authorizable.getAuthorizedAddresses.callAsync(); | ||||
|             await authorizable.removeAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner }); | ||||
|             const afterRemove = await authorizable.getAuthorizedAddresses().callAsync(); | ||||
|             expect(afterRemove).to.have.length(0); | ||||
|         }); | ||||
|     }); | ||||
|   | ||||
| @@ -1,3 +1,4 @@ | ||||
| import { DevUtilsContract } from '@0x/contracts-dev-utils'; | ||||
| import { | ||||
|     artifacts as erc1155Artifacts, | ||||
|     DummyERC1155ReceiverBatchTokenReceivedEventArgs, | ||||
| @@ -14,16 +15,19 @@ import { | ||||
|     txDefaults, | ||||
|     web3Wrapper, | ||||
| } from '@0x/contracts-test-utils'; | ||||
| import { SafeMathRevertErrors } from '@0x/contracts-utils'; | ||||
| import { BlockchainLifecycle } from '@0x/dev-utils'; | ||||
| import { assetDataUtils } from '@0x/order-utils'; | ||||
| import { AssetProxyId, RevertReason } from '@0x/types'; | ||||
| import { BigNumber, SafeMathRevertErrors } from '@0x/utils'; | ||||
| import { BigNumber } from '@0x/utils'; | ||||
| import * as chai from 'chai'; | ||||
| import { LogWithDecodedArgs } from 'ethereum-types'; | ||||
| import * as ethUtil from 'ethereumjs-util'; | ||||
| import * as _ from 'lodash'; | ||||
|  | ||||
| import { artifacts, ERC1155ProxyContract, ERC1155ProxyWrapper } from '../src'; | ||||
| import { ERC1155ProxyWrapper } from '../src/erc1155_proxy_wrapper'; | ||||
| import { ERC1155ProxyContract, IAssetDataContract } from '../src/wrappers'; | ||||
|  | ||||
| import { artifacts } from './artifacts'; | ||||
|  | ||||
| chaiSetup.configure(); | ||||
| const expect = chai.expect; | ||||
| @@ -59,6 +63,8 @@ describe('ERC1155Proxy', () => { | ||||
|     // tokens | ||||
|     let fungibleTokens: BigNumber[]; | ||||
|     let nonFungibleTokensOwnedBySpender: BigNumber[]; | ||||
|     // devUtils for encoding and decoding assetData | ||||
|     let devUtils: DevUtilsContract; | ||||
|     // tests | ||||
|     before(async () => { | ||||
|         await blockchainLifecycle.startAsync(); | ||||
| @@ -72,16 +78,8 @@ describe('ERC1155Proxy', () => { | ||||
|         const usedAddresses = ([owner, notAuthorized, authorized, spender, receiver] = _.slice(accounts, 0, 5)); | ||||
|         erc1155ProxyWrapper = new ERC1155ProxyWrapper(provider, usedAddresses, owner); | ||||
|         erc1155Proxy = await erc1155ProxyWrapper.deployProxyAsync(); | ||||
|         await erc1155Proxy.addAuthorizedAddress.awaitTransactionSuccessAsync( | ||||
|             authorized, | ||||
|             { from: owner }, | ||||
|             constants.AWAIT_TRANSACTION_MINED_MS, | ||||
|         ); | ||||
|         await erc1155Proxy.addAuthorizedAddress.awaitTransactionSuccessAsync( | ||||
|             erc1155Proxy.address, | ||||
|             { from: owner }, | ||||
|             constants.AWAIT_TRANSACTION_MINED_MS, | ||||
|         ); | ||||
|         await erc1155Proxy.addAuthorizedAddress(authorized).awaitTransactionSuccessAsync({ from: owner }); | ||||
|         await erc1155Proxy.addAuthorizedAddress(erc1155Proxy.address).awaitTransactionSuccessAsync({ from: owner }); | ||||
|         // deploy & configure ERC1155 tokens and receiver | ||||
|         [erc1155Wrapper] = await erc1155ProxyWrapper.deployDummyContractsAsync(); | ||||
|         erc1155Contract = erc1155Wrapper.getContract(); | ||||
| @@ -103,6 +101,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 }); | ||||
|     }); | ||||
|     beforeEach(async () => { | ||||
|         await blockchainLifecycle.startAsync(); | ||||
| @@ -123,7 +123,7 @@ describe('ERC1155Proxy', () => { | ||||
|             ); | ||||
|         }); | ||||
|         it('should have an id of 0xa7cb5fb7', async () => { | ||||
|             const proxyId = await erc1155Proxy.getProxyId.callAsync(); | ||||
|             const proxyId = await erc1155Proxy.getProxyId().callAsync(); | ||||
|             const expectedProxyId = AssetProxyId.ERC1155; | ||||
|             expect(proxyId).to.equal(expectedProxyId); | ||||
|         }); | ||||
| @@ -638,12 +638,14 @@ describe('ERC1155Proxy', () => { | ||||
|                 return value.times(valueMultiplier); | ||||
|             }); | ||||
|             const erc1155ContractAddress = erc1155Wrapper.getContract().address; | ||||
|             const assetData = assetDataUtils.encodeERC1155AssetData( | ||||
|                 erc1155ContractAddress, | ||||
|                 tokensToTransfer, | ||||
|                 valuesToTransfer, | ||||
|                 receiverCallbackData, | ||||
|             ); | ||||
|             const assetData = await devUtils | ||||
|                 .encodeERC1155AssetData( | ||||
|                     erc1155ContractAddress, | ||||
|                     tokensToTransfer, | ||||
|                     valuesToTransfer, | ||||
|                     receiverCallbackData, | ||||
|                 ) | ||||
|                 .callAsync(); | ||||
|             const extraData = '0102030405060708091001020304050607080910010203040506070809100102'; | ||||
|             const assetDataWithExtraData = `${assetData}${extraData}`; | ||||
|             // check balances before transfer | ||||
| @@ -696,25 +698,20 @@ describe('ERC1155Proxy', () => { | ||||
|             const tokenUri = ''; | ||||
|             for (const tokenToCreate of tokensToCreate) { | ||||
|                 // create token | ||||
|                 await erc1155Wrapper.getContract().createWithType.awaitTransactionSuccessAsync( | ||||
|                     tokenToCreate, | ||||
|                     tokenUri, | ||||
|                     { | ||||
|                 await erc1155Wrapper | ||||
|                     .getContract() | ||||
|                     .createWithType(tokenToCreate, tokenUri) | ||||
|                     .awaitTransactionSuccessAsync({ | ||||
|                         from: owner, | ||||
|                     }, | ||||
|                     constants.AWAIT_TRANSACTION_MINED_MS, | ||||
|                 ); | ||||
|                     }); | ||||
|  | ||||
|                 // mint balance for spender | ||||
|                 await erc1155Wrapper.getContract().mintFungible.awaitTransactionSuccessAsync( | ||||
|                     tokenToCreate, | ||||
|                     [spender], | ||||
|                     [spenderInitialBalance], | ||||
|                     { | ||||
|                 await erc1155Wrapper | ||||
|                     .getContract() | ||||
|                     .mintFungible(tokenToCreate, [spender], [spenderInitialBalance]) | ||||
|                     .awaitTransactionSuccessAsync({ | ||||
|                         from: owner, | ||||
|                     }, | ||||
|                     constants.AWAIT_TRANSACTION_MINED_MS, | ||||
|                 ); | ||||
|                     }); | ||||
|             } | ||||
|             ///// Step 2/5 ///// | ||||
|             // Check balances before transfer | ||||
| @@ -747,18 +744,16 @@ describe('ERC1155Proxy', () => { | ||||
|             const tokensToTransfer = [new BigNumber(1), new BigNumber(2)]; | ||||
|             const valuesToTransfer = tokensToTransfer; | ||||
|             const valueMultiplier = new BigNumber(2); | ||||
|             const assetData = assetDataUtils.encodeERC1155AssetData( | ||||
|                 erc1155ContractAddress, | ||||
|                 tokensToTransfer, | ||||
|                 valuesToTransfer, | ||||
|                 receiverCallbackData, | ||||
|             ); | ||||
|             // remove the function selector and contract address from check, as these change on each test | ||||
|             const offsetToTokenIds = 74; | ||||
|             const assetDataWithoutContractAddress = assetData.substr(offsetToTokenIds); | ||||
|             const expectedAssetDataWithoutContractAddress = | ||||
|  | ||||
|             // 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); | ||||
|             const selector = assetDataContract.getSelector('ERC1155Assets'); | ||||
|             const assetDataWithoutContractAddress = | ||||
|                 '0000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000040102030400000000000000000000000000000000000000000000000000000000'; | ||||
|             expect(assetDataWithoutContractAddress).to.be.equal(expectedAssetDataWithoutContractAddress); | ||||
|             const assetData = `${selector}000000000000000000000000${erc1155ContractAddress.substr( | ||||
|                 2, | ||||
|             )}${assetDataWithoutContractAddress}`; | ||||
|  | ||||
|             ///// Step 4/5 ///// | ||||
|             // Transfer token IDs [1, 2] and amounts [1, 2] with a multiplier of 2; | ||||
|             // the expected trade will be token IDs [1, 2] and amounts [2, 4] | ||||
| @@ -805,25 +800,20 @@ describe('ERC1155Proxy', () => { | ||||
|             const tokenUri = ''; | ||||
|             for (const tokenToCreate of tokensToCreate) { | ||||
|                 // create token | ||||
|                 await erc1155Wrapper.getContract().createWithType.awaitTransactionSuccessAsync( | ||||
|                     tokenToCreate, | ||||
|                     tokenUri, | ||||
|                     { | ||||
|                 await erc1155Wrapper | ||||
|                     .getContract() | ||||
|                     .createWithType(tokenToCreate, tokenUri) | ||||
|                     .awaitTransactionSuccessAsync({ | ||||
|                         from: owner, | ||||
|                     }, | ||||
|                     constants.AWAIT_TRANSACTION_MINED_MS, | ||||
|                 ); | ||||
|                     }); | ||||
|  | ||||
|                 // mint balance for spender | ||||
|                 await erc1155Wrapper.getContract().mintFungible.awaitTransactionSuccessAsync( | ||||
|                     tokenToCreate, | ||||
|                     [spender], | ||||
|                     [spenderInitialBalance], | ||||
|                     { | ||||
|                 await erc1155Wrapper | ||||
|                     .getContract() | ||||
|                     .mintFungible(tokenToCreate, [spender], [spenderInitialBalance]) | ||||
|                     .awaitTransactionSuccessAsync({ | ||||
|                         from: owner, | ||||
|                     }, | ||||
|                     constants.AWAIT_TRANSACTION_MINED_MS, | ||||
|                 ); | ||||
|                     }); | ||||
|             } | ||||
|             ///// Step 2/5 ///// | ||||
|             // Check balances before transfer | ||||
| @@ -867,12 +857,14 @@ 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 = assetDataUtils.encodeERC1155AssetData( | ||||
|                 erc1155ContractAddress, | ||||
|                 tokensToTransfer, | ||||
|                 valuesToTransfer, | ||||
|                 receiverCallbackData, | ||||
|             ); | ||||
|             const generatedAssetData = await devUtils | ||||
|                 .encodeERC1155AssetData( | ||||
|                     erc1155ContractAddress, | ||||
|                     tokensToTransfer, | ||||
|                     valuesToTransfer, | ||||
|                     receiverCallbackData, | ||||
|                 ) | ||||
|                 .callAsync(); | ||||
|             // remove the function selector and contract address from check, as these change on each test | ||||
|             const offsetToTokenIds = 74; | ||||
|             const assetDataSelectorAndContractAddress = generatedAssetData.substr(0, offsetToTokenIds); | ||||
| @@ -937,25 +929,20 @@ describe('ERC1155Proxy', () => { | ||||
|             const tokenUri = ''; | ||||
|             for (const tokenToCreate of tokensToCreate) { | ||||
|                 // create token | ||||
|                 await erc1155Wrapper.getContract().createWithType.awaitTransactionSuccessAsync( | ||||
|                     tokenToCreate, | ||||
|                     tokenUri, | ||||
|                     { | ||||
|                 await erc1155Wrapper | ||||
|                     .getContract() | ||||
|                     .createWithType(tokenToCreate, tokenUri) | ||||
|                     .awaitTransactionSuccessAsync({ | ||||
|                         from: owner, | ||||
|                     }, | ||||
|                     constants.AWAIT_TRANSACTION_MINED_MS, | ||||
|                 ); | ||||
|                     }); | ||||
|  | ||||
|                 // mint balance for spender | ||||
|                 await erc1155Wrapper.getContract().mintFungible.awaitTransactionSuccessAsync( | ||||
|                     tokenToCreate, | ||||
|                     [spender], | ||||
|                     [spenderInitialBalance], | ||||
|                     { | ||||
|                 await erc1155Wrapper | ||||
|                     .getContract() | ||||
|                     .mintFungible(tokenToCreate, [spender], [spenderInitialBalance]) | ||||
|                     .awaitTransactionSuccessAsync({ | ||||
|                         from: owner, | ||||
|                     }, | ||||
|                     constants.AWAIT_TRANSACTION_MINED_MS, | ||||
|                 ); | ||||
|                     }); | ||||
|             } | ||||
|             ///// Step 2/5 ///// | ||||
|             // Check balances before transfer | ||||
| @@ -996,12 +983,14 @@ 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 = assetDataUtils.encodeERC1155AssetData( | ||||
|                 erc1155ContractAddress, | ||||
|                 tokensToTransfer, | ||||
|                 valuesToTransfer, | ||||
|                 receiverCallbackData, | ||||
|             ); | ||||
|             const generatedAssetData = await devUtils | ||||
|                 .encodeERC1155AssetData( | ||||
|                     erc1155ContractAddress, | ||||
|                     tokensToTransfer, | ||||
|                     valuesToTransfer, | ||||
|                     receiverCallbackData, | ||||
|                 ) | ||||
|                 .callAsync(); | ||||
|             // remove the function selector and contract address from check, as these change on each test | ||||
|             const offsetToTokenIds = 74; | ||||
|             const assetDataSelectorAndContractAddress = generatedAssetData.substr(0, offsetToTokenIds); | ||||
| @@ -1059,12 +1048,14 @@ describe('ERC1155Proxy', () => { | ||||
|             const valuesToTransfer = [fungibleValueToTransferLarge]; | ||||
|             const valueMultiplier = valueMultiplierSmall; | ||||
|             const erc1155ContractAddress = erc1155Wrapper.getContract().address; | ||||
|             const assetData = assetDataUtils.encodeERC1155AssetData( | ||||
|                 erc1155ContractAddress, | ||||
|                 tokensToTransfer, | ||||
|                 valuesToTransfer, | ||||
|                 receiverCallbackData, | ||||
|             ); | ||||
|             const assetData = await devUtils | ||||
|                 .encodeERC1155AssetData( | ||||
|                     erc1155ContractAddress, | ||||
|                     tokensToTransfer, | ||||
|                     valuesToTransfer, | ||||
|                     receiverCallbackData, | ||||
|                 ) | ||||
|                 .callAsync(); | ||||
|             // The asset data we just generated will look like this: | ||||
|             // a7cb5fb7 | ||||
|             // 0x         0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082 | ||||
| @@ -1106,12 +1097,14 @@ describe('ERC1155Proxy', () => { | ||||
|             const valuesToTransfer = [fungibleValueToTransferLarge]; | ||||
|             const valueMultiplier = valueMultiplierSmall; | ||||
|             const erc1155ContractAddress = erc1155Wrapper.getContract().address; | ||||
|             const assetData = assetDataUtils.encodeERC1155AssetData( | ||||
|                 erc1155ContractAddress, | ||||
|                 tokensToTransfer, | ||||
|                 valuesToTransfer, | ||||
|                 receiverCallbackData, | ||||
|             ); | ||||
|             const assetData = await devUtils | ||||
|                 .encodeERC1155AssetData( | ||||
|                     erc1155ContractAddress, | ||||
|                     tokensToTransfer, | ||||
|                     valuesToTransfer, | ||||
|                     receiverCallbackData, | ||||
|                 ) | ||||
|                 .callAsync(); | ||||
|             // The asset data we just generated will look like this: | ||||
|             // a7cb5fb7 | ||||
|             // 0x         0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082 | ||||
| @@ -1157,12 +1150,14 @@ describe('ERC1155Proxy', () => { | ||||
|             const valuesToTransfer = [fungibleValueToTransferLarge]; | ||||
|             const valueMultiplier = valueMultiplierSmall; | ||||
|             const erc1155ContractAddress = erc1155Wrapper.getContract().address; | ||||
|             const assetData = assetDataUtils.encodeERC1155AssetData( | ||||
|                 erc1155ContractAddress, | ||||
|                 tokensToTransfer, | ||||
|                 valuesToTransfer, | ||||
|                 receiverCallbackData, | ||||
|             ); | ||||
|             const assetData = await devUtils | ||||
|                 .encodeERC1155AssetData( | ||||
|                     erc1155ContractAddress, | ||||
|                     tokensToTransfer, | ||||
|                     valuesToTransfer, | ||||
|                     receiverCallbackData, | ||||
|                 ) | ||||
|                 .callAsync(); | ||||
|             // The asset data we just generated will look like this: | ||||
|             // a7cb5fb7 | ||||
|             // 0x         0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082 | ||||
| @@ -1208,12 +1203,14 @@ describe('ERC1155Proxy', () => { | ||||
|             const valuesToTransfer = [fungibleValueToTransferLarge]; | ||||
|             const valueMultiplier = valueMultiplierSmall; | ||||
|             const erc1155ContractAddress = erc1155Wrapper.getContract().address; | ||||
|             const assetData = assetDataUtils.encodeERC1155AssetData( | ||||
|                 erc1155ContractAddress, | ||||
|                 tokensToTransfer, | ||||
|                 valuesToTransfer, | ||||
|                 receiverCallbackData, | ||||
|             ); | ||||
|             const assetData = await devUtils | ||||
|                 .encodeERC1155AssetData( | ||||
|                     erc1155ContractAddress, | ||||
|                     tokensToTransfer, | ||||
|                     valuesToTransfer, | ||||
|                     receiverCallbackData, | ||||
|                 ) | ||||
|                 .callAsync(); | ||||
|             // The asset data we just generated will look like this: | ||||
|             // a7cb5fb7 | ||||
|             // 0x         0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082 | ||||
| @@ -1259,12 +1256,14 @@ describe('ERC1155Proxy', () => { | ||||
|             const valuesToTransfer = [fungibleValueToTransferLarge]; | ||||
|             const valueMultiplier = valueMultiplierSmall; | ||||
|             const erc1155ContractAddress = erc1155Wrapper.getContract().address; | ||||
|             const assetData = assetDataUtils.encodeERC1155AssetData( | ||||
|                 erc1155ContractAddress, | ||||
|                 tokensToTransfer, | ||||
|                 valuesToTransfer, | ||||
|                 receiverCallbackData, | ||||
|             ); | ||||
|             const assetData = await devUtils | ||||
|                 .encodeERC1155AssetData( | ||||
|                     erc1155ContractAddress, | ||||
|                     tokensToTransfer, | ||||
|                     valuesToTransfer, | ||||
|                     receiverCallbackData, | ||||
|                 ) | ||||
|                 .callAsync(); | ||||
|             // The asset data we just generated will look like this: | ||||
|             // a7cb5fb7 | ||||
|             // 0x         0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082 | ||||
| @@ -1311,12 +1310,14 @@ describe('ERC1155Proxy', () => { | ||||
|             const valuesToTransfer = [fungibleValueToTransferLarge]; | ||||
|             const valueMultiplier = valueMultiplierSmall; | ||||
|             const erc1155ContractAddress = erc1155Wrapper.getContract().address; | ||||
|             const assetData = assetDataUtils.encodeERC1155AssetData( | ||||
|                 erc1155ContractAddress, | ||||
|                 tokensToTransfer, | ||||
|                 valuesToTransfer, | ||||
|                 receiverCallbackData, | ||||
|             ); | ||||
|             const assetData = await devUtils | ||||
|                 .encodeERC1155AssetData( | ||||
|                     erc1155ContractAddress, | ||||
|                     tokensToTransfer, | ||||
|                     valuesToTransfer, | ||||
|                     receiverCallbackData, | ||||
|                 ) | ||||
|                 .callAsync(); | ||||
|             // The asset data we just generated will look like this: | ||||
|             // a7cb5fb7 | ||||
|             // 0x         0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082 | ||||
| @@ -1358,12 +1359,14 @@ describe('ERC1155Proxy', () => { | ||||
|             const valuesToTransfer = [fungibleValueToTransferLarge]; | ||||
|             const valueMultiplier = valueMultiplierSmall; | ||||
|             const erc1155ContractAddress = erc1155Wrapper.getContract().address; | ||||
|             const assetData = assetDataUtils.encodeERC1155AssetData( | ||||
|                 erc1155ContractAddress, | ||||
|                 tokensToTransfer, | ||||
|                 valuesToTransfer, | ||||
|                 receiverCallbackData, | ||||
|             ); | ||||
|             const assetData = await devUtils | ||||
|                 .encodeERC1155AssetData( | ||||
|                     erc1155ContractAddress, | ||||
|                     tokensToTransfer, | ||||
|                     valuesToTransfer, | ||||
|                     receiverCallbackData, | ||||
|                 ) | ||||
|                 .callAsync(); | ||||
|             // The asset data we just generated will look like this: | ||||
|             // a7cb5fb7 | ||||
|             // 0x         0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082 | ||||
| @@ -1409,12 +1412,14 @@ describe('ERC1155Proxy', () => { | ||||
|             const valuesToTransfer = [fungibleValueToTransferLarge]; | ||||
|             const valueMultiplier = valueMultiplierSmall; | ||||
|             const erc1155ContractAddress = erc1155Wrapper.getContract().address; | ||||
|             const assetData = assetDataUtils.encodeERC1155AssetData( | ||||
|                 erc1155ContractAddress, | ||||
|                 tokensToTransfer, | ||||
|                 valuesToTransfer, | ||||
|                 receiverCallbackData, | ||||
|             ); | ||||
|             const assetData = await devUtils | ||||
|                 .encodeERC1155AssetData( | ||||
|                     erc1155ContractAddress, | ||||
|                     tokensToTransfer, | ||||
|                     valuesToTransfer, | ||||
|                     receiverCallbackData, | ||||
|                 ) | ||||
|                 .callAsync(); | ||||
|             // The asset data we just generated will look like this: | ||||
|             // a7cb5fb7 | ||||
|             // 0x         0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082 | ||||
| @@ -1456,12 +1461,14 @@ describe('ERC1155Proxy', () => { | ||||
|             const valuesToTransfer = [fungibleValueToTransferLarge]; | ||||
|             const valueMultiplier = valueMultiplierSmall; | ||||
|             const erc1155ContractAddress = erc1155Wrapper.getContract().address; | ||||
|             const assetData = assetDataUtils.encodeERC1155AssetData( | ||||
|                 erc1155ContractAddress, | ||||
|                 tokensToTransfer, | ||||
|                 valuesToTransfer, | ||||
|                 receiverCallbackData, | ||||
|             ); | ||||
|             const assetData = await devUtils | ||||
|                 .encodeERC1155AssetData( | ||||
|                     erc1155ContractAddress, | ||||
|                     tokensToTransfer, | ||||
|                     valuesToTransfer, | ||||
|                     receiverCallbackData, | ||||
|                 ) | ||||
|                 .callAsync(); | ||||
|             // The asset data we just generated will look like this: | ||||
|             // a7cb5fb7 | ||||
|             // 0x         0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082 | ||||
| @@ -1507,13 +1514,15 @@ describe('ERC1155Proxy', () => { | ||||
|             const valuesToTransfer = [fungibleValueToTransferLarge]; | ||||
|             const valueMultiplier = valueMultiplierSmall; | ||||
|             const erc1155ContractAddress = erc1155Wrapper.getContract().address; | ||||
|             const assetData = assetDataUtils.encodeERC1155AssetData( | ||||
|                 erc1155ContractAddress, | ||||
|                 tokensToTransfer, | ||||
|                 valuesToTransfer, | ||||
|                 receiverCallbackData, | ||||
|             ); | ||||
|             const txData = erc1155ProxyWrapper.getTransferFromAbiEncodedTxData( | ||||
|             const assetData = await devUtils | ||||
|                 .encodeERC1155AssetData( | ||||
|                     erc1155ContractAddress, | ||||
|                     tokensToTransfer, | ||||
|                     valuesToTransfer, | ||||
|                     receiverCallbackData, | ||||
|                 ) | ||||
|                 .callAsync(); | ||||
|             const txData = await erc1155ProxyWrapper.getTransferFromAbiEncodedTxDataAsync( | ||||
|                 spender, | ||||
|                 receiverContract, | ||||
|                 erc1155Contract.address, | ||||
| @@ -1538,13 +1547,15 @@ describe('ERC1155Proxy', () => { | ||||
|             const valuesToTransfer = [fungibleValueToTransferLarge]; | ||||
|             const valueMultiplier = valueMultiplierSmall; | ||||
|             const erc1155ContractAddress = erc1155Wrapper.getContract().address; | ||||
|             const assetData = assetDataUtils.encodeERC1155AssetData( | ||||
|                 erc1155ContractAddress, | ||||
|                 tokensToTransfer, | ||||
|                 valuesToTransfer, | ||||
|                 receiverCallbackData, | ||||
|             ); | ||||
|             const txData = erc1155ProxyWrapper.getTransferFromAbiEncodedTxData( | ||||
|             const assetData = await devUtils | ||||
|                 .encodeERC1155AssetData( | ||||
|                     erc1155ContractAddress, | ||||
|                     tokensToTransfer, | ||||
|                     valuesToTransfer, | ||||
|                     receiverCallbackData, | ||||
|                 ) | ||||
|                 .callAsync(); | ||||
|             const txData = await erc1155ProxyWrapper.getTransferFromAbiEncodedTxDataAsync( | ||||
|                 spender, | ||||
|                 receiverContract, | ||||
|                 erc1155Contract.address, | ||||
| @@ -1667,13 +1678,9 @@ describe('ERC1155Proxy', () => { | ||||
|         it('should propagate revert reason from erc1155 contract failure', async () => { | ||||
|             // disable transfers | ||||
|             const shouldRejectTransfer = true; | ||||
|             await erc1155Receiver.setRejectTransferFlag.awaitTransactionSuccessAsync( | ||||
|                 shouldRejectTransfer, | ||||
|                 { | ||||
|                     from: owner, | ||||
|                 }, | ||||
|                 constants.AWAIT_TRANSACTION_MINED_MS, | ||||
|             ); | ||||
|             await erc1155Receiver.setRejectTransferFlag(shouldRejectTransfer).awaitTransactionSuccessAsync({ | ||||
|                 from: owner, | ||||
|             }); | ||||
|             // setup test parameters | ||||
|             const tokenHolders = [spender, receiverContract]; | ||||
|             const tokensToTransfer = fungibleTokens.slice(0, 1); | ||||
|   | ||||
| @@ -9,17 +9,15 @@ import { | ||||
|     Numberish, | ||||
|     randomAddress, | ||||
| } from '@0x/contracts-test-utils'; | ||||
| import { AuthorizableRevertErrors } from '@0x/contracts-utils'; | ||||
| import { AssetProxyId } from '@0x/types'; | ||||
| import { AbiEncoder, AuthorizableRevertErrors, BigNumber, StringRevertError } from '@0x/utils'; | ||||
| import { AbiEncoder, BigNumber, StringRevertError } from '@0x/utils'; | ||||
| import { DecodedLogs } from 'ethereum-types'; | ||||
| import * as _ from 'lodash'; | ||||
|  | ||||
| import { | ||||
|     artifacts, | ||||
|     ERC20BridgeProxyContract, | ||||
|     TestERC20BridgeBridgeWithdrawToEventArgs, | ||||
|     TestERC20BridgeContract, | ||||
| } from '../src'; | ||||
| import { artifacts } from './artifacts'; | ||||
|  | ||||
| import { ERC20BridgeProxyContract, TestERC20BridgeContract } from './wrappers'; | ||||
|  | ||||
| blockchainTests.resets('ERC20BridgeProxy unit tests', env => { | ||||
|     const PROXY_ID = AssetProxyId.ERC20Bridge; | ||||
| @@ -44,8 +42,8 @@ blockchainTests.resets('ERC20BridgeProxy unit tests', env => { | ||||
|             env.txDefaults, | ||||
|             artifacts, | ||||
|         ); | ||||
|         testTokenAddress = await bridgeContract.testToken.callAsync(); | ||||
|         await assetProxy.addAuthorizedAddress.awaitTransactionSuccessAsync(owner); | ||||
|         testTokenAddress = await bridgeContract.testToken().callAsync(); | ||||
|         await assetProxy.addAuthorizedAddress(owner).awaitTransactionSuccessAsync(); | ||||
|     }); | ||||
|  | ||||
|     interface AssetDataOpts { | ||||
| @@ -102,7 +100,7 @@ blockchainTests.resets('ERC20BridgeProxy unit tests', env => { | ||||
|     } | ||||
|  | ||||
|     async function setTestTokenBalanceAsync(_owner: string, balance: Numberish): Promise<void> { | ||||
|         await bridgeContract.setTestTokenBalance.awaitTransactionSuccessAsync(_owner, new BigNumber(balance)); | ||||
|         await bridgeContract.setTestTokenBalance(_owner, new BigNumber(balance)).awaitTransactionSuccessAsync(); | ||||
|     } | ||||
|  | ||||
|     describe('transferFrom()', () => { | ||||
| @@ -132,13 +130,9 @@ blockchainTests.resets('ERC20BridgeProxy unit tests', env => { | ||||
|  | ||||
|         async function transferFromAsync(opts?: Partial<TransferFromOpts>, caller?: string): Promise<DecodedLogs> { | ||||
|             const _opts = createTransferFromOpts(opts); | ||||
|             const { logs } = await assetProxy.transferFrom.awaitTransactionSuccessAsync( | ||||
|                 encodeAssetData(_opts.assetData), | ||||
|                 _opts.from, | ||||
|                 _opts.to, | ||||
|                 new BigNumber(_opts.amount), | ||||
|                 { from: caller }, | ||||
|             ); | ||||
|             const { logs } = await assetProxy | ||||
|                 .transferFrom(encodeAssetData(_opts.assetData), _opts.from, _opts.to, new BigNumber(_opts.amount)) | ||||
|                 .awaitTransactionSuccessAsync({ from: caller }); | ||||
|             return (logs as any) as DecodedLogs; | ||||
|         } | ||||
|  | ||||
| @@ -164,7 +158,7 @@ blockchainTests.resets('ERC20BridgeProxy unit tests', env => { | ||||
|             const opts = createTransferFromOpts(); | ||||
|             const logs = await transferFromAsync(opts); | ||||
|             expect(logs.length).to.eq(1); | ||||
|             const args = logs[0].args as TestERC20BridgeBridgeWithdrawToEventArgs; | ||||
|             const args = logs[0].args; | ||||
|             expect(args.tokenAddress).to.eq(opts.assetData.tokenAddress); | ||||
|             expect(args.from).to.eq(opts.from); | ||||
|             expect(args.to).to.eq(opts.to); | ||||
| @@ -180,12 +174,9 @@ blockchainTests.resets('ERC20BridgeProxy unit tests', env => { | ||||
|         it('fails if asset data is truncated', async () => { | ||||
|             const opts = createTransferFromOpts(); | ||||
|             const truncatedAssetData = hexSlice(encodeAssetData(opts.assetData), 0, -1); | ||||
|             const tx = assetProxy.transferFrom.awaitTransactionSuccessAsync( | ||||
|                 truncatedAssetData, | ||||
|                 opts.from, | ||||
|                 opts.to, | ||||
|                 new BigNumber(opts.amount), | ||||
|             ); | ||||
|             const tx = assetProxy | ||||
|                 .transferFrom(truncatedAssetData, opts.from, opts.to, new BigNumber(opts.amount)) | ||||
|                 .awaitTransactionSuccessAsync(); | ||||
|             return expect(tx).to.be.rejected(); | ||||
|         }); | ||||
|  | ||||
| @@ -281,18 +272,18 @@ blockchainTests.resets('ERC20BridgeProxy unit tests', env => { | ||||
|         it('retrieves the balance of the encoded token', async () => { | ||||
|             const _owner = randomAddress(); | ||||
|             const balance = getRandomInteger(1, 100e18); | ||||
|             await bridgeContract.setTestTokenBalance.awaitTransactionSuccessAsync(_owner, balance); | ||||
|             await bridgeContract.setTestTokenBalance(_owner, balance).awaitTransactionSuccessAsync(); | ||||
|             const assetData = createAssetData({ | ||||
|                 tokenAddress: testTokenAddress, | ||||
|             }); | ||||
|             const actualBalance = await assetProxy.balanceOf.callAsync(encodeAssetData(assetData), _owner); | ||||
|             const actualBalance = await assetProxy.balanceOf(encodeAssetData(assetData), _owner).callAsync(); | ||||
|             expect(actualBalance).to.bignumber.eq(balance); | ||||
|         }); | ||||
|     }); | ||||
|  | ||||
|     describe('getProxyId()', () => { | ||||
|         it('returns the correct proxy ID', async () => { | ||||
|             const proxyId = await assetProxy.getProxyId.callAsync(); | ||||
|             const proxyId = await assetProxy.getProxyId().callAsync(); | ||||
|             expect(proxyId).to.eq(PROXY_ID); | ||||
|         }); | ||||
|     }); | ||||
|   | ||||
| @@ -8,24 +8,23 @@ import { | ||||
|     hexRandom, | ||||
|     Numberish, | ||||
|     randomAddress, | ||||
|     TransactionHelper, | ||||
| } from '@0x/contracts-test-utils'; | ||||
| import { AssetProxyId } from '@0x/types'; | ||||
| import { BigNumber } from '@0x/utils'; | ||||
| import { BigNumber, RawRevertError } from '@0x/utils'; | ||||
| import { DecodedLogs } from 'ethereum-types'; | ||||
| import * as _ from 'lodash'; | ||||
|  | ||||
| import { artifacts } from './artifacts'; | ||||
|  | ||||
| import { | ||||
|     artifacts, | ||||
|     TestEth2DaiBridgeContract, | ||||
|     TestEth2DaiBridgeEvents, | ||||
|     TestEth2DaiBridgeSellAllAmountEventArgs, | ||||
|     TestEth2DaiBridgeTokenApproveEventArgs, | ||||
|     TestEth2DaiBridgeTokenTransferEventArgs, | ||||
| } from '../src'; | ||||
| } from './wrappers'; | ||||
|  | ||||
| blockchainTests.resets('Eth2DaiBridge unit tests', env => { | ||||
|     const txHelper = new TransactionHelper(env.web3Wrapper, artifacts); | ||||
|     let testContract: TestEth2DaiBridgeContract; | ||||
|  | ||||
|     before(async () => { | ||||
| @@ -40,12 +39,12 @@ blockchainTests.resets('Eth2DaiBridge unit tests', env => { | ||||
|     describe('isValidSignature()', () => { | ||||
|         it('returns success bytes', async () => { | ||||
|             const LEGACY_WALLET_MAGIC_VALUE = '0xb0671381'; | ||||
|             const result = await testContract.isValidSignature.callAsync(hexRandom(), hexRandom(_.random(0, 32))); | ||||
|             const result = await testContract.isValidSignature(hexRandom(), hexRandom(_.random(0, 32))).callAsync(); | ||||
|             expect(result).to.eq(LEGACY_WALLET_MAGIC_VALUE); | ||||
|         }); | ||||
|     }); | ||||
|  | ||||
|     describe('withdrawTo()', () => { | ||||
|     describe('bridgeTransferFrom()', () => { | ||||
|         interface WithdrawToOpts { | ||||
|             toTokenAddress?: string; | ||||
|             fromTokenAddress?: string; | ||||
| @@ -80,32 +79,30 @@ blockchainTests.resets('Eth2DaiBridge unit tests', env => { | ||||
|         async function withdrawToAsync(opts?: Partial<WithdrawToOpts>): Promise<WithdrawToResult> { | ||||
|             const _opts = createWithdrawToOpts(opts); | ||||
|             // Set the fill behavior. | ||||
|             await testContract.setFillBehavior.awaitTransactionSuccessAsync( | ||||
|                 _opts.revertReason, | ||||
|                 new BigNumber(_opts.fillAmount), | ||||
|             ); | ||||
|             await testContract | ||||
|                 .setFillBehavior(_opts.revertReason, new BigNumber(_opts.fillAmount)) | ||||
|                 .awaitTransactionSuccessAsync(); | ||||
|             // Create tokens and balances. | ||||
|             if (_opts.fromTokenAddress === undefined) { | ||||
|                 [_opts.fromTokenAddress] = await txHelper.getResultAndReceiptAsync( | ||||
|                     testContract.createToken, | ||||
|                     new BigNumber(_opts.fromTokenBalance), | ||||
|                 ); | ||||
|                 const createTokenFn = testContract.createToken(new BigNumber(_opts.fromTokenBalance)); | ||||
|                 _opts.fromTokenAddress = await createTokenFn.callAsync(); | ||||
|                 await createTokenFn.awaitTransactionSuccessAsync(); | ||||
|             } | ||||
|             if (_opts.toTokenAddress === undefined) { | ||||
|                 [_opts.toTokenAddress] = await txHelper.getResultAndReceiptAsync( | ||||
|                     testContract.createToken, | ||||
|                     constants.ZERO_AMOUNT, | ||||
|                 ); | ||||
|                 const createTokenFn = testContract.createToken(constants.ZERO_AMOUNT); | ||||
|                 _opts.toTokenAddress = await createTokenFn.callAsync(); | ||||
|                 await createTokenFn.awaitTransactionSuccessAsync(); | ||||
|             } | ||||
|             // Set the transfer behavior of `toTokenAddress`. | ||||
|             await testContract.setTransferBehavior.awaitTransactionSuccessAsync( | ||||
|                 _opts.toTokenAddress, | ||||
|                 _opts.toTokentransferRevertReason, | ||||
|                 _opts.toTokenTransferReturnData, | ||||
|             ); | ||||
|             // Call withdrawTo(). | ||||
|             const [result, { logs }] = await txHelper.getResultAndReceiptAsync( | ||||
|                 testContract.withdrawTo, | ||||
|             await testContract | ||||
|                 .setTransferBehavior( | ||||
|                     _opts.toTokenAddress, | ||||
|                     _opts.toTokentransferRevertReason, | ||||
|                     _opts.toTokenTransferReturnData, | ||||
|                 ) | ||||
|                 .awaitTransactionSuccessAsync(); | ||||
|             // Call bridgeTransferFrom(). | ||||
|             const bridgeTransferFromFn = testContract.bridgeTransferFrom( | ||||
|                 // "to" token address | ||||
|                 _opts.toTokenAddress, | ||||
|                 // Random from address. | ||||
| @@ -116,6 +113,8 @@ blockchainTests.resets('Eth2DaiBridge unit tests', env => { | ||||
|                 // ABI-encode the "from" token address as the bridge data. | ||||
|                 hexLeftPad(_opts.fromTokenAddress as string), | ||||
|             ); | ||||
|             const result = await bridgeTransferFromFn.callAsync(); | ||||
|             const { logs } = await bridgeTransferFromFn.awaitTransactionSuccessAsync(); | ||||
|             return { | ||||
|                 opts: _opts, | ||||
|                 result, | ||||
| @@ -179,14 +178,14 @@ blockchainTests.resets('Eth2DaiBridge unit tests', env => { | ||||
|             return expect(tx).to.revertWith(opts.toTokentransferRevertReason); | ||||
|         }); | ||||
|  | ||||
|         it('fails if `toTokenAddress.transfer()` returns falsey', async () => { | ||||
|         it('fails if `toTokenAddress.transfer()` returns false', async () => { | ||||
|             const opts = createWithdrawToOpts({ toTokenTransferReturnData: hexLeftPad(0) }); | ||||
|             const tx = withdrawToAsync(opts); | ||||
|             return expect(tx).to.revertWith('ERC20_TRANSFER_FAILED'); | ||||
|             return expect(tx).to.revertWith(new RawRevertError(hexLeftPad(0))); | ||||
|         }); | ||||
|  | ||||
|         it('succeeds if `toTokenAddress.transfer()` returns truthy', async () => { | ||||
|             await withdrawToAsync({ toTokenTransferReturnData: hexLeftPad(100) }); | ||||
|         it('succeeds if `toTokenAddress.transfer()` returns true', async () => { | ||||
|             await withdrawToAsync({ toTokenTransferReturnData: hexLeftPad(1) }); | ||||
|         }); | ||||
|     }); | ||||
| }); | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,3 +1,4 @@ | ||||
| import { DevUtilsContract } from '@0x/contracts-dev-utils'; | ||||
| import { | ||||
|     chaiSetup, | ||||
|     constants, | ||||
| @@ -8,13 +9,14 @@ import { | ||||
|     web3Wrapper, | ||||
| } from '@0x/contracts-test-utils'; | ||||
| import { BlockchainLifecycle } from '@0x/dev-utils'; | ||||
| import { assetDataUtils } from '@0x/order-utils'; | ||||
| import { AssetProxyId, RevertReason } from '@0x/types'; | ||||
| import { AbiEncoder, BigNumber } from '@0x/utils'; | ||||
| import * as chai from 'chai'; | ||||
| import * as ethUtil from 'ethereumjs-util'; | ||||
|  | ||||
| import { artifacts, IAssetProxyContract, StaticCallProxyContract, TestStaticCallTargetContract } from '../src'; | ||||
| import { artifacts } from './artifacts'; | ||||
|  | ||||
| import { IAssetProxyContract, StaticCallProxyContract, TestStaticCallTargetContract } from './wrappers'; | ||||
|  | ||||
| chaiSetup.configure(); | ||||
| const expect = chai.expect; | ||||
| @@ -25,6 +27,7 @@ describe('StaticCallProxy', () => { | ||||
|     let fromAddress: string; | ||||
|     let toAddress: string; | ||||
|  | ||||
|     let devUtils: DevUtilsContract; | ||||
|     let staticCallProxy: IAssetProxyContract; | ||||
|     let staticCallTarget: TestStaticCallTargetContract; | ||||
|  | ||||
| @@ -43,6 +46,7 @@ describe('StaticCallProxy', () => { | ||||
|             txDefaults, | ||||
|             artifacts, | ||||
|         ); | ||||
|         devUtils = new DevUtilsContract(constants.NULL_ADDRESS, provider); | ||||
|         staticCallProxy = new IAssetProxyContract( | ||||
|             staticCallProxyWithoutTransferFrom.address, | ||||
|             provider, | ||||
| @@ -77,26 +81,21 @@ describe('StaticCallProxy', () => { | ||||
|             ); | ||||
|         }); | ||||
|         it('should have an id of 0xc339d10a', async () => { | ||||
|             const proxyId = await staticCallProxy.getProxyId.callAsync(); | ||||
|             const proxyId = await staticCallProxy.getProxyId().callAsync(); | ||||
|             const expectedProxyId = AssetProxyId.StaticCall; | ||||
|             expect(proxyId).to.equal(expectedProxyId); | ||||
|         }); | ||||
|     }); | ||||
|     describe('transferFrom', () => { | ||||
|         it('should revert if assetData lies outside the bounds of calldata', async () => { | ||||
|             const staticCallData = staticCallTarget.noInputFunction.getABIEncodedTransactionData(); | ||||
|             const staticCallData = staticCallTarget.noInputFunction().getABIEncodedTransactionData(); | ||||
|             const expectedResultHash = constants.KECCAK256_NULL; | ||||
|             const assetData = assetDataUtils.encodeStaticCallAssetData( | ||||
|                 staticCallTarget.address, | ||||
|                 staticCallData, | ||||
|                 expectedResultHash, | ||||
|             ); | ||||
|             const txData = staticCallProxy.transferFrom.getABIEncodedTransactionData( | ||||
|                 assetData, | ||||
|                 fromAddress, | ||||
|                 toAddress, | ||||
|                 amount, | ||||
|             ); | ||||
|             const assetData = await devUtils | ||||
|                 .encodeStaticCallAssetData(staticCallTarget.address, staticCallData, expectedResultHash) | ||||
|                 .callAsync(); | ||||
|             const txData = staticCallProxy | ||||
|                 .transferFrom(assetData, fromAddress, toAddress, amount) | ||||
|                 .getABIEncodedTransactionData(); | ||||
|             const offsetToAssetData = '0000000000000000000000000000000000000000000000000000000000000080'; | ||||
|             const txDataEndBuffer = ethUtil.toBuffer((txData.length - 2) / 2 - 4); | ||||
|             const paddedTxDataEndBuffer = ethUtil.setLengthLeft(txDataEndBuffer, 32); | ||||
| @@ -114,23 +113,21 @@ 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 = assetDataUtils | ||||
|             const assetData = (await devUtils | ||||
|                 .encodeStaticCallAssetData(staticCallTarget.address, staticCallData, expectedResultHash) | ||||
|                 .slice(0, -128); | ||||
|                 .callAsync()).slice(0, -128); | ||||
|             const assetDataByteLen = (assetData.length - 2) / 2; | ||||
|             expect((assetDataByteLen - 4) % 32).to.equal(0); | ||||
|             await expectTransactionFailedWithoutReasonAsync( | ||||
|                 staticCallProxy.transferFrom.sendTransactionAsync(assetData, fromAddress, toAddress, amount), | ||||
|                 staticCallProxy.transferFrom(assetData, fromAddress, toAddress, amount).sendTransactionAsync(), | ||||
|             ); | ||||
|         }); | ||||
|         it('should revert if the offset to `staticCallData` points to outside of assetData', async () => { | ||||
|             const staticCallData = staticCallTarget.noInputFunction.getABIEncodedTransactionData(); | ||||
|             const staticCallData = staticCallTarget.noInputFunction().getABIEncodedTransactionData(); | ||||
|             const expectedResultHash = constants.KECCAK256_NULL; | ||||
|             const assetData = assetDataUtils.encodeStaticCallAssetData( | ||||
|                 staticCallTarget.address, | ||||
|                 staticCallData, | ||||
|                 expectedResultHash, | ||||
|             ); | ||||
|             const assetData = await devUtils | ||||
|                 .encodeStaticCallAssetData(staticCallTarget.address, staticCallData, expectedResultHash) | ||||
|                 .callAsync(); | ||||
|             const offsetToStaticCallData = '0000000000000000000000000000000000000000000000000000000000000060'; | ||||
|             const assetDataEndBuffer = ethUtil.toBuffer((assetData.length - 2) / 2 - 4); | ||||
|             const paddedAssetDataEndBuffer = ethUtil.setLengthLeft(assetDataEndBuffer, 32); | ||||
| @@ -141,90 +138,88 @@ describe('StaticCallProxy', () => { | ||||
|                 invalidOffsetToStaticCallData, | ||||
|             )}${newStaticCallData}`; | ||||
|             await expectTransactionFailedWithoutReasonAsync( | ||||
|                 staticCallProxy.transferFrom.sendTransactionAsync(badAssetData, fromAddress, toAddress, amount), | ||||
|                 staticCallProxy.transferFrom(badAssetData, fromAddress, toAddress, amount).sendTransactionAsync(), | ||||
|             ); | ||||
|         }); | ||||
|         it('should revert if the callTarget attempts to write to state', async () => { | ||||
|             const staticCallData = staticCallTarget.updateState.getABIEncodedTransactionData(); | ||||
|             const staticCallData = staticCallTarget.updateState().getABIEncodedTransactionData(); | ||||
|             const expectedResultHash = constants.KECCAK256_NULL; | ||||
|             const assetData = assetDataUtils.encodeStaticCallAssetData( | ||||
|                 staticCallTarget.address, | ||||
|                 staticCallData, | ||||
|                 expectedResultHash, | ||||
|             ); | ||||
|             const assetData = await devUtils | ||||
|                 .encodeStaticCallAssetData(staticCallTarget.address, staticCallData, expectedResultHash) | ||||
|                 .callAsync(); | ||||
|             await expectTransactionFailedWithoutReasonAsync( | ||||
|                 staticCallProxy.transferFrom.sendTransactionAsync(assetData, fromAddress, toAddress, amount), | ||||
|                 staticCallProxy.transferFrom(assetData, fromAddress, toAddress, amount).sendTransactionAsync(), | ||||
|             ); | ||||
|         }); | ||||
|         it('should revert with data provided by the callTarget if the staticcall reverts', async () => { | ||||
|             const staticCallData = staticCallTarget.assertEvenNumber.getABIEncodedTransactionData(new BigNumber(1)); | ||||
|             const staticCallData = staticCallTarget.assertEvenNumber(new BigNumber(1)).getABIEncodedTransactionData(); | ||||
|             const expectedResultHash = constants.KECCAK256_NULL; | ||||
|             const assetData = assetDataUtils.encodeStaticCallAssetData( | ||||
|                 staticCallTarget.address, | ||||
|                 staticCallData, | ||||
|                 expectedResultHash, | ||||
|             ); | ||||
|             const assetData = await devUtils | ||||
|                 .encodeStaticCallAssetData(staticCallTarget.address, staticCallData, expectedResultHash) | ||||
|                 .callAsync(); | ||||
|             await expectTransactionFailedAsync( | ||||
|                 staticCallProxy.transferFrom.sendTransactionAsync(assetData, fromAddress, toAddress, amount), | ||||
|                 staticCallProxy.transferFrom(assetData, fromAddress, toAddress, amount).sendTransactionAsync(), | ||||
|                 RevertReason.TargetNotEven, | ||||
|             ); | ||||
|         }); | ||||
|         it('should revert if the hash of the output is different than expected expected', async () => { | ||||
|             const staticCallData = staticCallTarget.isOddNumber.getABIEncodedTransactionData(new BigNumber(0)); | ||||
|             const staticCallData = staticCallTarget.isOddNumber(new BigNumber(0)).getABIEncodedTransactionData(); | ||||
|             const trueAsBuffer = ethUtil.toBuffer('0x0000000000000000000000000000000000000000000000000000000000000001'); | ||||
|             const expectedResultHash = ethUtil.bufferToHex(ethUtil.sha3(trueAsBuffer)); | ||||
|             const assetData = assetDataUtils.encodeStaticCallAssetData( | ||||
|                 staticCallTarget.address, | ||||
|                 staticCallData, | ||||
|                 expectedResultHash, | ||||
|             ); | ||||
|             const assetData = await devUtils | ||||
|                 .encodeStaticCallAssetData(staticCallTarget.address, staticCallData, expectedResultHash) | ||||
|                 .callAsync(); | ||||
|             await expectTransactionFailedAsync( | ||||
|                 staticCallProxy.transferFrom.sendTransactionAsync(assetData, fromAddress, toAddress, amount), | ||||
|                 staticCallProxy.transferFrom(assetData, fromAddress, toAddress, amount).sendTransactionAsync(), | ||||
|                 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 staticCallData = staticCallTarget.noInputFunction().getABIEncodedTransactionData(); | ||||
|             const expectedResultHash = constants.KECCAK256_NULL; | ||||
|             const assetData = assetDataUtils.encodeStaticCallAssetData( | ||||
|                 staticCallTarget.address, | ||||
|                 staticCallData, | ||||
|                 expectedResultHash, | ||||
|             ); | ||||
|             await staticCallProxy.transferFrom.awaitTransactionSuccessAsync(assetData, fromAddress, toAddress, amount); | ||||
|             const assetData = await devUtils | ||||
|                 .encodeStaticCallAssetData(staticCallTarget.address, staticCallData, expectedResultHash) | ||||
|                 .callAsync(); | ||||
|             await staticCallProxy | ||||
|                 .transferFrom(assetData, fromAddress, toAddress, amount) | ||||
|                 .awaitTransactionSuccessAsync(); | ||||
|         }); | ||||
|         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 = assetDataUtils.encodeStaticCallAssetData(toAddress, staticCallData, expectedResultHash); | ||||
|             await staticCallProxy.transferFrom.awaitTransactionSuccessAsync(assetData, fromAddress, toAddress, amount); | ||||
|             const assetData = await devUtils | ||||
|                 .encodeStaticCallAssetData(toAddress, staticCallData, expectedResultHash) | ||||
|                 .callAsync(); | ||||
|             await staticCallProxy | ||||
|                 .transferFrom(assetData, fromAddress, toAddress, amount) | ||||
|                 .awaitTransactionSuccessAsync(); | ||||
|         }); | ||||
|         it('should be successful if a function call with one static input returns the correct value', async () => { | ||||
|             const staticCallData = staticCallTarget.isOddNumber.getABIEncodedTransactionData(new BigNumber(1)); | ||||
|             const staticCallData = staticCallTarget.isOddNumber(new BigNumber(1)).getABIEncodedTransactionData(); | ||||
|             const trueAsBuffer = ethUtil.toBuffer('0x0000000000000000000000000000000000000000000000000000000000000001'); | ||||
|             const expectedResultHash = ethUtil.bufferToHex(ethUtil.sha3(trueAsBuffer)); | ||||
|             const assetData = assetDataUtils.encodeStaticCallAssetData( | ||||
|                 staticCallTarget.address, | ||||
|                 staticCallData, | ||||
|                 expectedResultHash, | ||||
|             ); | ||||
|             await staticCallProxy.transferFrom.awaitTransactionSuccessAsync(assetData, fromAddress, toAddress, amount); | ||||
|             const assetData = await devUtils | ||||
|                 .encodeStaticCallAssetData(staticCallTarget.address, staticCallData, expectedResultHash) | ||||
|                 .callAsync(); | ||||
|             await staticCallProxy | ||||
|                 .transferFrom(assetData, fromAddress, toAddress, amount) | ||||
|                 .awaitTransactionSuccessAsync(); | ||||
|         }); | ||||
|         it('should be successful if a function with one dynamic input is successful', async () => { | ||||
|             const dynamicInput = '0x0102030405060708'; | ||||
|             const staticCallData = staticCallTarget.dynamicInputFunction.getABIEncodedTransactionData(dynamicInput); | ||||
|             const staticCallData = staticCallTarget.dynamicInputFunction(dynamicInput).getABIEncodedTransactionData(); | ||||
|             const expectedResultHash = constants.KECCAK256_NULL; | ||||
|             const assetData = assetDataUtils.encodeStaticCallAssetData( | ||||
|                 staticCallTarget.address, | ||||
|                 staticCallData, | ||||
|                 expectedResultHash, | ||||
|             ); | ||||
|             await staticCallProxy.transferFrom.awaitTransactionSuccessAsync(assetData, fromAddress, toAddress, amount); | ||||
|             const assetData = await devUtils | ||||
|                 .encodeStaticCallAssetData(staticCallTarget.address, staticCallData, expectedResultHash) | ||||
|                 .callAsync(); | ||||
|             await staticCallProxy | ||||
|                 .transferFrom(assetData, fromAddress, toAddress, amount) | ||||
|                 .awaitTransactionSuccessAsync(); | ||||
|         }); | ||||
|         it('should be successful if a function call returns a complex type', async () => { | ||||
|             const a = new BigNumber(1); | ||||
|             const b = new BigNumber(2); | ||||
|             const staticCallData = staticCallTarget.returnComplexType.getABIEncodedTransactionData(a, b); | ||||
|             const staticCallData = staticCallTarget.returnComplexType(a, b).getABIEncodedTransactionData(); | ||||
|             const abiEncoder = new AbiEncoder.DynamicBytes({ | ||||
|                 name: '', | ||||
|                 type: 'bytes', | ||||
| @@ -237,12 +232,12 @@ describe('StaticCallProxy', () => { | ||||
|             const expectedResultHash = ethUtil.bufferToHex( | ||||
|                 ethUtil.sha3(ethUtil.toBuffer(encodedExpectedResultWithOffset)), | ||||
|             ); | ||||
|             const assetData = assetDataUtils.encodeStaticCallAssetData( | ||||
|                 staticCallTarget.address, | ||||
|                 staticCallData, | ||||
|                 expectedResultHash, | ||||
|             ); | ||||
|             await staticCallProxy.transferFrom.awaitTransactionSuccessAsync(assetData, fromAddress, toAddress, amount); | ||||
|             const assetData = await devUtils | ||||
|                 .encodeStaticCallAssetData(staticCallTarget.address, staticCallData, expectedResultHash) | ||||
|                 .callAsync(); | ||||
|             await staticCallProxy | ||||
|                 .transferFrom(assetData, fromAddress, toAddress, amount) | ||||
|                 .awaitTransactionSuccessAsync(); | ||||
|         }); | ||||
|     }); | ||||
| }); | ||||
|   | ||||
							
								
								
									
										370
									
								
								contracts/asset-proxy/test/uniswap_bridge.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										370
									
								
								contracts/asset-proxy/test/uniswap_bridge.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,370 @@ | ||||
| import { | ||||
|     blockchainTests, | ||||
|     constants, | ||||
|     expect, | ||||
|     filterLogs, | ||||
|     filterLogsToArguments, | ||||
|     getRandomInteger, | ||||
|     hexLeftPad, | ||||
|     hexRandom, | ||||
|     Numberish, | ||||
|     randomAddress, | ||||
| } from '@0x/contracts-test-utils'; | ||||
| import { AssetProxyId } from '@0x/types'; | ||||
| import { BigNumber } from '@0x/utils'; | ||||
| import { DecodedLogs } from 'ethereum-types'; | ||||
| import * as _ from 'lodash'; | ||||
|  | ||||
| import { artifacts } from './artifacts'; | ||||
|  | ||||
| import { | ||||
|     TestUniswapBridgeContract, | ||||
|     TestUniswapBridgeEthToTokenTransferInputEventArgs as EthToTokenTransferInputArgs, | ||||
|     TestUniswapBridgeEvents as ContractEvents, | ||||
|     TestUniswapBridgeTokenApproveEventArgs as TokenApproveArgs, | ||||
|     TestUniswapBridgeTokenToEthSwapInputEventArgs as TokenToEthSwapInputArgs, | ||||
|     TestUniswapBridgeTokenToTokenTransferInputEventArgs as TokenToTokenTransferInputArgs, | ||||
|     TestUniswapBridgeTokenTransferEventArgs as TokenTransferArgs, | ||||
|     TestUniswapBridgeWethDepositEventArgs as WethDepositArgs, | ||||
|     TestUniswapBridgeWethWithdrawEventArgs as WethWithdrawArgs, | ||||
| } from './wrappers'; | ||||
|  | ||||
| blockchainTests.resets('UniswapBridge unit tests', env => { | ||||
|     let testContract: TestUniswapBridgeContract; | ||||
|     let wethTokenAddress: string; | ||||
|  | ||||
|     before(async () => { | ||||
|         testContract = await TestUniswapBridgeContract.deployFrom0xArtifactAsync( | ||||
|             artifacts.TestUniswapBridge, | ||||
|             env.provider, | ||||
|             env.txDefaults, | ||||
|             artifacts, | ||||
|         ); | ||||
|         wethTokenAddress = await testContract.wethToken().callAsync(); | ||||
|     }); | ||||
|  | ||||
|     describe('isValidSignature()', () => { | ||||
|         it('returns success bytes', async () => { | ||||
|             const LEGACY_WALLET_MAGIC_VALUE = '0xb0671381'; | ||||
|             const result = await testContract.isValidSignature(hexRandom(), hexRandom(_.random(0, 32))).callAsync(); | ||||
|             expect(result).to.eq(LEGACY_WALLET_MAGIC_VALUE); | ||||
|         }); | ||||
|     }); | ||||
|  | ||||
|     describe('bridgeTransferFrom()', () => { | ||||
|         interface WithdrawToOpts { | ||||
|             fromTokenAddress: string; | ||||
|             toTokenAddress: string; | ||||
|             fromTokenBalance: Numberish; | ||||
|             toAddress: string; | ||||
|             amount: Numberish; | ||||
|             exchangeRevertReason: string; | ||||
|             exchangeFillAmount: Numberish; | ||||
|             toTokenRevertReason: string; | ||||
|             fromTokenRevertReason: string; | ||||
|         } | ||||
|  | ||||
|         function createWithdrawToOpts(opts?: Partial<WithdrawToOpts>): WithdrawToOpts { | ||||
|             return { | ||||
|                 fromTokenAddress: constants.NULL_ADDRESS, | ||||
|                 toTokenAddress: constants.NULL_ADDRESS, | ||||
|                 fromTokenBalance: getRandomInteger(1, 1e18), | ||||
|                 toAddress: randomAddress(), | ||||
|                 amount: getRandomInteger(1, 1e18), | ||||
|                 exchangeRevertReason: '', | ||||
|                 exchangeFillAmount: getRandomInteger(1, 1e18), | ||||
|                 toTokenRevertReason: '', | ||||
|                 fromTokenRevertReason: '', | ||||
|                 ...opts, | ||||
|             }; | ||||
|         } | ||||
|  | ||||
|         interface WithdrawToResult { | ||||
|             opts: WithdrawToOpts; | ||||
|             result: string; | ||||
|             logs: DecodedLogs; | ||||
|             blockTime: number; | ||||
|         } | ||||
|  | ||||
|         async function withdrawToAsync(opts?: Partial<WithdrawToOpts>): Promise<WithdrawToResult> { | ||||
|             const _opts = createWithdrawToOpts(opts); | ||||
|             const callData = { value: new BigNumber(_opts.exchangeFillAmount) }; | ||||
|             // Create the "from" token and exchange. | ||||
|             const createFromTokenFn = testContract.createTokenAndExchange( | ||||
|                 _opts.fromTokenAddress, | ||||
|                 _opts.exchangeRevertReason, | ||||
|             ); | ||||
|             [_opts.fromTokenAddress] = await createFromTokenFn.callAsync(callData); | ||||
|             await createFromTokenFn.awaitTransactionSuccessAsync(callData); | ||||
|  | ||||
|             // Create the "to" token and exchange. | ||||
|             const createToTokenFn = testContract.createTokenAndExchange( | ||||
|                 _opts.toTokenAddress, | ||||
|                 _opts.exchangeRevertReason, | ||||
|             ); | ||||
|             [_opts.toTokenAddress] = await createToTokenFn.callAsync(callData); | ||||
|             await createToTokenFn.awaitTransactionSuccessAsync(callData); | ||||
|  | ||||
|             await testContract | ||||
|                 .setTokenRevertReason(_opts.toTokenAddress, _opts.toTokenRevertReason) | ||||
|                 .awaitTransactionSuccessAsync(); | ||||
|             await testContract | ||||
|                 .setTokenRevertReason(_opts.fromTokenAddress, _opts.fromTokenRevertReason) | ||||
|                 .awaitTransactionSuccessAsync(); | ||||
|             // Set the token balance for the token we're converting from. | ||||
|             await testContract.setTokenBalance(_opts.fromTokenAddress).awaitTransactionSuccessAsync({ | ||||
|                 value: new BigNumber(_opts.fromTokenBalance), | ||||
|             }); | ||||
|             // Call bridgeTransferFrom(). | ||||
|             const bridgeTransferFromFn = testContract.bridgeTransferFrom( | ||||
|                 // The "to" token address. | ||||
|                 _opts.toTokenAddress, | ||||
|                 // The "from" address. | ||||
|                 randomAddress(), | ||||
|                 // The "to" address. | ||||
|                 _opts.toAddress, | ||||
|                 // The amount to transfer to "to" | ||||
|                 new BigNumber(_opts.amount), | ||||
|                 // ABI-encoded "from" token address. | ||||
|                 hexLeftPad(_opts.fromTokenAddress), | ||||
|             ); | ||||
|             const result = await bridgeTransferFromFn.callAsync(); | ||||
|             const receipt = await bridgeTransferFromFn.awaitTransactionSuccessAsync(); | ||||
|             return { | ||||
|                 opts: _opts, | ||||
|                 result, | ||||
|                 logs: (receipt.logs as any) as DecodedLogs, | ||||
|                 blockTime: await env.web3Wrapper.getBlockTimestampAsync(receipt.blockNumber), | ||||
|             }; | ||||
|         } | ||||
|  | ||||
|         async function getExchangeForTokenAsync(tokenAddress: string): Promise<string> { | ||||
|             return testContract.getExchange(tokenAddress).callAsync(); | ||||
|         } | ||||
|  | ||||
|         it('returns magic bytes on success', async () => { | ||||
|             const { result } = await withdrawToAsync(); | ||||
|             expect(result).to.eq(AssetProxyId.ERC20Bridge); | ||||
|         }); | ||||
|  | ||||
|         it('just transfers tokens to `to` if the same tokens are in play', async () => { | ||||
|             const createTokenFn = await testContract.createTokenAndExchange(constants.NULL_ADDRESS, ''); | ||||
|             const [tokenAddress] = await createTokenFn.callAsync(); | ||||
|             await createTokenFn.awaitTransactionSuccessAsync(); | ||||
|             const { opts, result, logs } = await withdrawToAsync({ | ||||
|                 fromTokenAddress: tokenAddress, | ||||
|                 toTokenAddress: tokenAddress, | ||||
|             }); | ||||
|             expect(result).to.eq(AssetProxyId.ERC20Bridge); | ||||
|             const transfers = filterLogsToArguments<TokenTransferArgs>(logs, ContractEvents.TokenTransfer); | ||||
|             expect(transfers.length).to.eq(1); | ||||
|             expect(transfers[0].token).to.eq(tokenAddress); | ||||
|             expect(transfers[0].from).to.eq(testContract.address); | ||||
|             expect(transfers[0].to).to.eq(opts.toAddress); | ||||
|             expect(transfers[0].amount).to.bignumber.eq(opts.amount); | ||||
|         }); | ||||
|  | ||||
|         describe('token -> token', () => { | ||||
|             it('calls `IUniswapExchange.tokenToTokenTransferInput()', async () => { | ||||
|                 const { opts, logs, blockTime } = await withdrawToAsync(); | ||||
|                 const exchangeAddress = await getExchangeForTokenAsync(opts.fromTokenAddress); | ||||
|                 const calls = filterLogsToArguments<TokenToTokenTransferInputArgs>( | ||||
|                     logs, | ||||
|                     ContractEvents.TokenToTokenTransferInput, | ||||
|                 ); | ||||
|                 expect(calls.length).to.eq(1); | ||||
|                 expect(calls[0].exchange).to.eq(exchangeAddress); | ||||
|                 expect(calls[0].tokensSold).to.bignumber.eq(opts.fromTokenBalance); | ||||
|                 expect(calls[0].minTokensBought).to.bignumber.eq(opts.amount); | ||||
|                 expect(calls[0].minEthBought).to.bignumber.eq(0); | ||||
|                 expect(calls[0].deadline).to.bignumber.eq(blockTime); | ||||
|                 expect(calls[0].recipient).to.eq(opts.toAddress); | ||||
|                 expect(calls[0].toTokenAddress).to.eq(opts.toTokenAddress); | ||||
|             }); | ||||
|  | ||||
|             it('sets allowance for "from" token', async () => { | ||||
|                 const { opts, logs } = await withdrawToAsync(); | ||||
|                 const approvals = filterLogsToArguments<TokenApproveArgs>(logs, ContractEvents.TokenApprove); | ||||
|                 const exchangeAddress = await getExchangeForTokenAsync(opts.fromTokenAddress); | ||||
|                 expect(approvals.length).to.eq(1); | ||||
|                 expect(approvals[0].spender).to.eq(exchangeAddress); | ||||
|                 expect(approvals[0].allowance).to.bignumber.eq(constants.MAX_UINT256); | ||||
|             }); | ||||
|  | ||||
|             it('sets allowance for "from" token on subsequent calls', async () => { | ||||
|                 const { opts } = await withdrawToAsync(); | ||||
|                 const { logs } = await withdrawToAsync(opts); | ||||
|                 const approvals = filterLogsToArguments<TokenApproveArgs>(logs, ContractEvents.TokenApprove); | ||||
|                 const exchangeAddress = await getExchangeForTokenAsync(opts.fromTokenAddress); | ||||
|                 expect(approvals.length).to.eq(1); | ||||
|                 expect(approvals[0].spender).to.eq(exchangeAddress); | ||||
|                 expect(approvals[0].allowance).to.bignumber.eq(constants.MAX_UINT256); | ||||
|             }); | ||||
|  | ||||
|             it('fails if "from" token does not exist', async () => { | ||||
|                 const tx = testContract | ||||
|                     .bridgeTransferFrom( | ||||
|                         randomAddress(), | ||||
|                         randomAddress(), | ||||
|                         randomAddress(), | ||||
|                         getRandomInteger(1, 1e18), | ||||
|                         hexLeftPad(randomAddress()), | ||||
|                     ) | ||||
|                     .awaitTransactionSuccessAsync(); | ||||
|                 return expect(tx).to.eventually.be.rejectedWith('NO_UNISWAP_EXCHANGE_FOR_TOKEN'); | ||||
|             }); | ||||
|  | ||||
|             it('fails if the exchange fails', async () => { | ||||
|                 const revertReason = 'FOOBAR'; | ||||
|                 const tx = withdrawToAsync({ | ||||
|                     exchangeRevertReason: revertReason, | ||||
|                 }); | ||||
|                 return expect(tx).to.eventually.be.rejectedWith(revertReason); | ||||
|             }); | ||||
|         }); | ||||
|  | ||||
|         describe('token -> ETH', () => { | ||||
|             it('calls `IUniswapExchange.tokenToEthSwapInput()`, `WETH.deposit()`, then `transfer()`', async () => { | ||||
|                 const { opts, logs, blockTime } = await withdrawToAsync({ | ||||
|                     toTokenAddress: wethTokenAddress, | ||||
|                 }); | ||||
|                 const exchangeAddress = await getExchangeForTokenAsync(opts.fromTokenAddress); | ||||
|                 let calls: any = filterLogs<TokenToEthSwapInputArgs>(logs, ContractEvents.TokenToEthSwapInput); | ||||
|                 expect(calls.length).to.eq(1); | ||||
|                 expect(calls[0].args.exchange).to.eq(exchangeAddress); | ||||
|                 expect(calls[0].args.tokensSold).to.bignumber.eq(opts.fromTokenBalance); | ||||
|                 expect(calls[0].args.minEthBought).to.bignumber.eq(opts.amount); | ||||
|                 expect(calls[0].args.deadline).to.bignumber.eq(blockTime); | ||||
|                 calls = filterLogs<WethDepositArgs>( | ||||
|                     logs.slice(calls[0].logIndex as number), | ||||
|                     ContractEvents.WethDeposit, | ||||
|                 ); | ||||
|                 expect(calls.length).to.eq(1); | ||||
|                 expect(calls[0].args.amount).to.bignumber.eq(opts.exchangeFillAmount); | ||||
|                 calls = filterLogs<TokenTransferArgs>( | ||||
|                     logs.slice(calls[0].logIndex as number), | ||||
|                     ContractEvents.TokenTransfer, | ||||
|                 ); | ||||
|                 expect(calls.length).to.eq(1); | ||||
|                 expect(calls[0].args.token).to.eq(opts.toTokenAddress); | ||||
|                 expect(calls[0].args.from).to.eq(testContract.address); | ||||
|                 expect(calls[0].args.to).to.eq(opts.toAddress); | ||||
|                 expect(calls[0].args.amount).to.bignumber.eq(opts.exchangeFillAmount); | ||||
|             }); | ||||
|  | ||||
|             it('sets allowance for "from" token', async () => { | ||||
|                 const { opts, logs } = await withdrawToAsync({ | ||||
|                     toTokenAddress: wethTokenAddress, | ||||
|                 }); | ||||
|                 const transfers = filterLogsToArguments<TokenApproveArgs>(logs, ContractEvents.TokenApprove); | ||||
|                 const exchangeAddress = await getExchangeForTokenAsync(opts.fromTokenAddress); | ||||
|                 expect(transfers.length).to.eq(1); | ||||
|                 expect(transfers[0].spender).to.eq(exchangeAddress); | ||||
|                 expect(transfers[0].allowance).to.bignumber.eq(constants.MAX_UINT256); | ||||
|             }); | ||||
|  | ||||
|             it('sets allowance for "from" token on subsequent calls', async () => { | ||||
|                 const { opts } = await withdrawToAsync({ | ||||
|                     toTokenAddress: wethTokenAddress, | ||||
|                 }); | ||||
|                 const { logs } = await withdrawToAsync(opts); | ||||
|                 const approvals = filterLogsToArguments<TokenApproveArgs>(logs, ContractEvents.TokenApprove); | ||||
|                 const exchangeAddress = await getExchangeForTokenAsync(opts.fromTokenAddress); | ||||
|                 expect(approvals.length).to.eq(1); | ||||
|                 expect(approvals[0].spender).to.eq(exchangeAddress); | ||||
|                 expect(approvals[0].allowance).to.bignumber.eq(constants.MAX_UINT256); | ||||
|             }); | ||||
|  | ||||
|             it('fails if "from" token does not exist', async () => { | ||||
|                 const tx = testContract | ||||
|                     .bridgeTransferFrom( | ||||
|                         randomAddress(), | ||||
|                         randomAddress(), | ||||
|                         randomAddress(), | ||||
|                         getRandomInteger(1, 1e18), | ||||
|                         hexLeftPad(wethTokenAddress), | ||||
|                     ) | ||||
|                     .awaitTransactionSuccessAsync(); | ||||
|                 return expect(tx).to.eventually.be.rejectedWith('NO_UNISWAP_EXCHANGE_FOR_TOKEN'); | ||||
|             }); | ||||
|  | ||||
|             it('fails if `WETH.deposit()` fails', async () => { | ||||
|                 const revertReason = 'FOOBAR'; | ||||
|                 const tx = withdrawToAsync({ | ||||
|                     toTokenAddress: wethTokenAddress, | ||||
|                     toTokenRevertReason: revertReason, | ||||
|                 }); | ||||
|                 return expect(tx).to.eventually.be.rejectedWith(revertReason); | ||||
|             }); | ||||
|  | ||||
|             it('fails if the exchange fails', async () => { | ||||
|                 const revertReason = 'FOOBAR'; | ||||
|                 const tx = withdrawToAsync({ | ||||
|                     toTokenAddress: wethTokenAddress, | ||||
|                     exchangeRevertReason: revertReason, | ||||
|                 }); | ||||
|                 return expect(tx).to.eventually.be.rejectedWith(revertReason); | ||||
|             }); | ||||
|         }); | ||||
|  | ||||
|         describe('ETH -> token', () => { | ||||
|             it('calls  `WETH.withdraw()`, then `IUniswapExchange.ethToTokenTransferInput()`', async () => { | ||||
|                 const { opts, logs, blockTime } = await withdrawToAsync({ | ||||
|                     fromTokenAddress: wethTokenAddress, | ||||
|                 }); | ||||
|                 const exchangeAddress = await getExchangeForTokenAsync(opts.toTokenAddress); | ||||
|                 let calls: any = filterLogs<WethWithdrawArgs>(logs, ContractEvents.WethWithdraw); | ||||
|                 expect(calls.length).to.eq(1); | ||||
|                 expect(calls[0].args.amount).to.bignumber.eq(opts.fromTokenBalance); | ||||
|                 calls = filterLogs<EthToTokenTransferInputArgs>( | ||||
|                     logs.slice(calls[0].logIndex as number), | ||||
|                     ContractEvents.EthToTokenTransferInput, | ||||
|                 ); | ||||
|                 expect(calls.length).to.eq(1); | ||||
|                 expect(calls[0].args.exchange).to.eq(exchangeAddress); | ||||
|                 expect(calls[0].args.minTokensBought).to.bignumber.eq(opts.amount); | ||||
|                 expect(calls[0].args.deadline).to.bignumber.eq(blockTime); | ||||
|                 expect(calls[0].args.recipient).to.eq(opts.toAddress); | ||||
|             }); | ||||
|  | ||||
|             it('does not set any allowance', async () => { | ||||
|                 const { logs } = await withdrawToAsync({ | ||||
|                     fromTokenAddress: wethTokenAddress, | ||||
|                 }); | ||||
|                 const approvals = filterLogsToArguments<TokenApproveArgs>(logs, ContractEvents.TokenApprove); | ||||
|                 expect(approvals).to.be.empty(''); | ||||
|             }); | ||||
|  | ||||
|             it('fails if "to" token does not exist', async () => { | ||||
|                 const tx = testContract | ||||
|                     .bridgeTransferFrom( | ||||
|                         wethTokenAddress, | ||||
|                         randomAddress(), | ||||
|                         randomAddress(), | ||||
|                         getRandomInteger(1, 1e18), | ||||
|                         hexLeftPad(randomAddress()), | ||||
|                     ) | ||||
|                     .awaitTransactionSuccessAsync(); | ||||
|                 return expect(tx).to.eventually.be.rejectedWith('NO_UNISWAP_EXCHANGE_FOR_TOKEN'); | ||||
|             }); | ||||
|  | ||||
|             it('fails if the `WETH.withdraw()` fails', async () => { | ||||
|                 const revertReason = 'FOOBAR'; | ||||
|                 const tx = withdrawToAsync({ | ||||
|                     fromTokenAddress: wethTokenAddress, | ||||
|                     fromTokenRevertReason: revertReason, | ||||
|                 }); | ||||
|                 return expect(tx).to.eventually.be.rejectedWith(revertReason); | ||||
|             }); | ||||
|  | ||||
|             it('fails if the exchange fails', async () => { | ||||
|                 const revertReason = 'FOOBAR'; | ||||
|                 const tx = withdrawToAsync({ | ||||
|                     fromTokenAddress: wethTokenAddress, | ||||
|                     exchangeRevertReason: revertReason, | ||||
|                 }); | ||||
|                 return expect(tx).to.eventually.be.rejectedWith(revertReason); | ||||
|             }); | ||||
|         }); | ||||
|     }); | ||||
| }); | ||||
| @@ -1,3 +0,0 @@ | ||||
| export * from './erc20_wrapper'; | ||||
| export * from './erc721_wrapper'; | ||||
| export * from './erc1155_proxy_wrapper'; | ||||
							
								
								
									
										28
									
								
								contracts/asset-proxy/test/wrappers.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								contracts/asset-proxy/test/wrappers.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | ||||
| /* | ||||
|  * ----------------------------------------------------------------------------- | ||||
|  * Warning: This file is auto-generated by contracts-gen. Don't edit manually. | ||||
|  * ----------------------------------------------------------------------------- | ||||
|  */ | ||||
| export * from '../test/generated-wrappers/erc1155_proxy'; | ||||
| export * from '../test/generated-wrappers/erc20_bridge_proxy'; | ||||
| export * from '../test/generated-wrappers/erc20_proxy'; | ||||
| export * from '../test/generated-wrappers/erc721_proxy'; | ||||
| export * from '../test/generated-wrappers/eth2_dai_bridge'; | ||||
| export * from '../test/generated-wrappers/i_asset_data'; | ||||
| 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_erc20_bridge'; | ||||
| export * from '../test/generated-wrappers/i_eth2_dai'; | ||||
| export * from '../test/generated-wrappers/i_uniswap_exchange'; | ||||
| export * from '../test/generated-wrappers/i_uniswap_exchange_factory'; | ||||
| export * from '../test/generated-wrappers/mixin_asset_proxy_dispatcher'; | ||||
| export * from '../test/generated-wrappers/mixin_authorizable'; | ||||
| export * from '../test/generated-wrappers/multi_asset_proxy'; | ||||
| export * from '../test/generated-wrappers/ownable'; | ||||
| export * from '../test/generated-wrappers/static_call_proxy'; | ||||
| export * from '../test/generated-wrappers/test_erc20_bridge'; | ||||
| export * from '../test/generated-wrappers/test_eth2_dai_bridge'; | ||||
| export * from '../test/generated-wrappers/test_static_call_target'; | ||||
| export * from '../test/generated-wrappers/test_uniswap_bridge'; | ||||
| export * from '../test/generated-wrappers/uniswap_bridge'; | ||||
| @@ -10,19 +10,33 @@ | ||||
|         "generated-artifacts/Eth2DaiBridge.json", | ||||
|         "generated-artifacts/IAssetData.json", | ||||
|         "generated-artifacts/IAssetProxy.json", | ||||
|         "generated-artifacts/IAssetProxyDispatcher.json", | ||||
|         "generated-artifacts/IAuthorizable.json", | ||||
|         "generated-artifacts/IERC20Bridge.json", | ||||
|         "generated-artifacts/IEth2Dai.json", | ||||
|         "generated-artifacts/IWallet.json", | ||||
|         "generated-artifacts/MixinAssetProxyDispatcher.json", | ||||
|         "generated-artifacts/MixinAuthorizable.json", | ||||
|         "generated-artifacts/MultiAssetProxy.json", | ||||
|         "generated-artifacts/Ownable.json", | ||||
|         "generated-artifacts/StaticCallProxy.json", | ||||
|         "generated-artifacts/TestERC20Bridge.json", | ||||
|         "generated-artifacts/TestEth2DaiBridge.json", | ||||
|         "generated-artifacts/TestStaticCallTarget.json" | ||||
|         "generated-artifacts/TestStaticCallTarget.json", | ||||
|         "generated-artifacts/UniswapBridge.json", | ||||
|         "test/generated-artifacts/ERC1155Proxy.json", | ||||
|         "test/generated-artifacts/ERC20BridgeProxy.json", | ||||
|         "test/generated-artifacts/ERC20Proxy.json", | ||||
|         "test/generated-artifacts/ERC721Proxy.json", | ||||
|         "test/generated-artifacts/Eth2DaiBridge.json", | ||||
|         "test/generated-artifacts/IAssetData.json", | ||||
|         "test/generated-artifacts/IAssetProxy.json", | ||||
|         "test/generated-artifacts/IAssetProxyDispatcher.json", | ||||
|         "test/generated-artifacts/IAuthorizable.json", | ||||
|         "test/generated-artifacts/IERC20Bridge.json", | ||||
|         "test/generated-artifacts/IEth2Dai.json", | ||||
|         "test/generated-artifacts/IUniswapExchange.json", | ||||
|         "test/generated-artifacts/IUniswapExchangeFactory.json", | ||||
|         "test/generated-artifacts/MixinAssetProxyDispatcher.json", | ||||
|         "test/generated-artifacts/MixinAuthorizable.json", | ||||
|         "test/generated-artifacts/MultiAssetProxy.json", | ||||
|         "test/generated-artifacts/Ownable.json", | ||||
|         "test/generated-artifacts/StaticCallProxy.json", | ||||
|         "test/generated-artifacts/TestERC20Bridge.json", | ||||
|         "test/generated-artifacts/TestEth2DaiBridge.json", | ||||
|         "test/generated-artifacts/TestStaticCallTarget.json", | ||||
|         "test/generated-artifacts/TestUniswapBridge.json", | ||||
|         "test/generated-artifacts/UniswapBridge.json" | ||||
|     ], | ||||
|     "exclude": ["./deploy/solc/solc_bin"] | ||||
| } | ||||
|   | ||||
							
								
								
									
										10
									
								
								contracts/coordinator/.npmignore
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								contracts/coordinator/.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 | ||||
| @@ -1,4 +1,31 @@ | ||||
| [ | ||||
|     { | ||||
|         "version": "2.1.0-beta.2", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils", | ||||
|                 "pr": 2330 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Introduced new export CoordinatorRevertErrors", | ||||
|                 "pr": 2321 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Added dependency on @0x/contracts-utils", | ||||
|                 "pr": 2321 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1574030254 | ||||
|     }, | ||||
|     { | ||||
|         "version": "2.1.0-beta.1", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1573159180 | ||||
|     }, | ||||
|     { | ||||
|         "version": "2.1.0-beta.0", | ||||
|         "changes": [ | ||||
|   | ||||
| @@ -5,6 +5,16 @@ Edit the package's CHANGELOG.json file only. | ||||
|  | ||||
| CHANGELOG | ||||
|  | ||||
| ## v2.1.0-beta.2 - _November 17, 2019_ | ||||
|  | ||||
|     * Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils (#2330) | ||||
|     * Introduced new export CoordinatorRevertErrors (#2321) | ||||
|     * Added dependency on @0x/contracts-utils (#2321) | ||||
|  | ||||
| ## v2.1.0-beta.1 - _November 7, 2019_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v2.1.0-beta.0 - _October 3, 2019_ | ||||
|  | ||||
|     * Add chainId to domain separator (#1742) | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| { | ||||
|     "artifactsDir": "./generated-artifacts", | ||||
|     "artifactsDir": "./test/generated-artifacts", | ||||
|     "contractsDir": "./contracts", | ||||
|     "useDockerisedSolc": false, | ||||
|     "compilerSettings": { | ||||
|   | ||||
| @@ -19,12 +19,15 @@ | ||||
| pragma solidity ^0.5.9; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "@0x/contracts-exchange-libs/contracts/src/LibEIP712ExchangeDomain.sol"; | ||||
| import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; | ||||
| import "@0x/contracts-exchange-libs/contracts/src/LibZeroExTransaction.sol"; | ||||
| import "@0x/contracts-utils/contracts/src/LibBytes.sol"; | ||||
| import "@0x/contracts-utils/contracts/src/LibAddressArray.sol"; | ||||
| import "@0x/contracts-utils/contracts/src/LibBytes.sol"; | ||||
| import "@0x/contracts-utils/contracts/src/LibRichErrors.sol"; | ||||
| import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol"; | ||||
| import "./libs/LibCoordinatorApproval.sol"; | ||||
| import "./libs/LibCoordinatorRichErrors.sol"; | ||||
| import "./interfaces/ICoordinatorSignatureValidator.sol"; | ||||
| import "./interfaces/ICoordinatorApprovalVerifier.sol"; | ||||
|  | ||||
| @@ -32,7 +35,7 @@ import "./interfaces/ICoordinatorApprovalVerifier.sol"; | ||||
| // solhint-disable avoid-tx-origin | ||||
| contract MixinCoordinatorApprovalVerifier is | ||||
|     LibCoordinatorApproval, | ||||
|     LibZeroExTransaction, | ||||
|     LibEIP712ExchangeDomain, | ||||
|     ICoordinatorSignatureValidator, | ||||
|     ICoordinatorApprovalVerifier | ||||
| { | ||||
| @@ -44,13 +47,12 @@ contract MixinCoordinatorApprovalVerifier is | ||||
|     /// @param transaction 0x transaction containing salt, signerAddress, and data. | ||||
|     /// @param txOrigin Required signer of Ethereum transaction calling this function. | ||||
|     /// @param transactionSignature Proof that the transaction has been signed by the signer. | ||||
|     /// @param approvalExpirationTimeSeconds Array of expiration times in seconds for which each corresponding approval signature expires. | ||||
|     /// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each order in the transaction's Exchange calldata. | ||||
|     /// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each | ||||
|     ///        order in the transaction's Exchange calldata. | ||||
|     function assertValidCoordinatorApprovals( | ||||
|         LibZeroExTransaction.ZeroExTransaction memory transaction, | ||||
|         address txOrigin, | ||||
|         bytes memory transactionSignature, | ||||
|         uint256[] memory approvalExpirationTimeSeconds, | ||||
|         bytes[] memory approvalSignatures | ||||
|     ) | ||||
|         public | ||||
| @@ -67,7 +69,6 @@ contract MixinCoordinatorApprovalVerifier is | ||||
|                 orders, | ||||
|                 txOrigin, | ||||
|                 transactionSignature, | ||||
|                 approvalExpirationTimeSeconds, | ||||
|                 approvalSignatures | ||||
|             ); | ||||
|         } | ||||
| @@ -75,7 +76,7 @@ contract MixinCoordinatorApprovalVerifier is | ||||
|  | ||||
|     /// @dev Decodes the orders from Exchange calldata representing any fill method. | ||||
|     /// @param data Exchange calldata representing a fill method. | ||||
|     /// @return The orders from the Exchange calldata. | ||||
|     /// @return orders The orders from the Exchange calldata. | ||||
|     function decodeOrdersFromFillData(bytes memory data) | ||||
|         public | ||||
|         pure | ||||
| @@ -84,7 +85,6 @@ contract MixinCoordinatorApprovalVerifier is | ||||
|         bytes4 selector = data.readBytes4(0); | ||||
|         if ( | ||||
|             selector == IExchange(address(0)).fillOrder.selector || | ||||
|             selector == IExchange(address(0)).fillOrderNoThrow.selector || | ||||
|             selector == IExchange(address(0)).fillOrKillOrder.selector | ||||
|         ) { | ||||
|             // Decode single order | ||||
| @@ -98,8 +98,10 @@ contract MixinCoordinatorApprovalVerifier is | ||||
|             selector == IExchange(address(0)).batchFillOrders.selector || | ||||
|             selector == IExchange(address(0)).batchFillOrdersNoThrow.selector || | ||||
|             selector == IExchange(address(0)).batchFillOrKillOrders.selector || | ||||
|             selector == IExchange(address(0)).marketBuyOrders.selector || | ||||
|             selector == IExchange(address(0)).marketSellOrders.selector | ||||
|             selector == IExchange(address(0)).marketBuyOrdersNoThrow.selector || | ||||
|             selector == IExchange(address(0)).marketBuyOrdersFillOrKill.selector || | ||||
|             selector == IExchange(address(0)).marketSellOrdersNoThrow.selector || | ||||
|             selector == IExchange(address(0)).marketSellOrdersFillOrKill.selector | ||||
|         ) { | ||||
|             // Decode all orders | ||||
|             // solhint-disable indent | ||||
| @@ -107,7 +109,10 @@ contract MixinCoordinatorApprovalVerifier is | ||||
|                 data.slice(4, data.length), | ||||
|                 (LibOrder.Order[]) | ||||
|             ); | ||||
|         } else if (selector == IExchange(address(0)).matchOrders.selector) { | ||||
|         } else if ( | ||||
|             selector == IExchange(address(0)).matchOrders.selector || | ||||
|             selector == IExchange(address(0)).matchOrdersWithMaximalFill.selector | ||||
|         ) { | ||||
|             // Decode left and right orders | ||||
|             (LibOrder.Order memory leftOrder, LibOrder.Order memory rightOrder) = abi.decode( | ||||
|                 data.slice(4, data.length), | ||||
| @@ -127,27 +132,24 @@ contract MixinCoordinatorApprovalVerifier is | ||||
|     /// @param orders Array of order structs containing order specifications. | ||||
|     /// @param txOrigin Required signer of Ethereum transaction calling this function. | ||||
|     /// @param transactionSignature Proof that the transaction has been signed by the signer. | ||||
|     /// @param approvalExpirationTimeSeconds Array of expiration times in seconds for which each corresponding approval signature expires. | ||||
|     /// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each order. | ||||
|     function _assertValidTransactionOrdersApproval( | ||||
|         LibZeroExTransaction.ZeroExTransaction memory transaction, | ||||
|         LibOrder.Order[] memory orders, | ||||
|         address txOrigin, | ||||
|         bytes memory transactionSignature, | ||||
|         uint256[] memory approvalExpirationTimeSeconds, | ||||
|         bytes[] memory approvalSignatures | ||||
|     ) | ||||
|         internal | ||||
|         view | ||||
|     { | ||||
|         // Verify that Ethereum tx signer is the same as the approved txOrigin | ||||
|         require( | ||||
|             tx.origin == txOrigin, | ||||
|             "INVALID_ORIGIN" | ||||
|         ); | ||||
|         if (tx.origin != txOrigin) { | ||||
|             LibRichErrors.rrevert(LibCoordinatorRichErrors.InvalidOriginError(txOrigin)); | ||||
|         } | ||||
|  | ||||
|         // Hash 0x transaction | ||||
|         bytes32 transactionHash = getTransactionHash(transaction); | ||||
|         bytes32 transactionHash = LibZeroExTransaction.getTypedDataHash(transaction, EIP712_EXCHANGE_DOMAIN_HASH); | ||||
|  | ||||
|         // Create empty list of approval signers | ||||
|         address[] memory approvalSignerAddresses = new address[](0); | ||||
| @@ -155,21 +157,12 @@ contract MixinCoordinatorApprovalVerifier is | ||||
|         uint256 signaturesLength = approvalSignatures.length; | ||||
|         for (uint256 i = 0; i != signaturesLength; i++) { | ||||
|             // Create approval message | ||||
|             uint256 currentApprovalExpirationTimeSeconds = approvalExpirationTimeSeconds[i]; | ||||
|             CoordinatorApproval memory approval = CoordinatorApproval({ | ||||
|                 txOrigin: txOrigin, | ||||
|                 transactionHash: transactionHash, | ||||
|                 transactionSignature: transactionSignature, | ||||
|                 approvalExpirationTimeSeconds: currentApprovalExpirationTimeSeconds | ||||
|                 transactionSignature: transactionSignature | ||||
|             }); | ||||
|  | ||||
|             // Ensure approval has not expired | ||||
|             require( | ||||
|                 // solhint-disable-next-line not-rely-on-time | ||||
|                 currentApprovalExpirationTimeSeconds > block.timestamp, | ||||
|                 "APPROVAL_EXPIRED" | ||||
|             ); | ||||
|  | ||||
|             // Hash approval message and recover signer address | ||||
|             bytes32 approvalHash = getCoordinatorApprovalHash(approval); | ||||
|             address approvalSignerAddress = getSignerAddress(approvalHash, approvalSignatures[i]); | ||||
| @@ -191,10 +184,12 @@ contract MixinCoordinatorApprovalVerifier is | ||||
|             // Ensure feeRecipient of order has approved this 0x transaction | ||||
|             address approverAddress = orders[i].feeRecipientAddress; | ||||
|             bool isOrderApproved = approvalSignerAddresses.contains(approverAddress); | ||||
|             require( | ||||
|                 isOrderApproved, | ||||
|                 "INVALID_APPROVAL_SIGNATURE" | ||||
|             ); | ||||
|             if (!isOrderApproved) { | ||||
|                 LibRichErrors.rrevert(LibCoordinatorRichErrors.InvalidApprovalSignatureError( | ||||
|                     transactionHash, | ||||
|                     approverAddress | ||||
|                 )); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -20,41 +20,53 @@ pragma solidity ^0.5.9; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "@0x/contracts-exchange-libs/contracts/src/LibZeroExTransaction.sol"; | ||||
| import "@0x/contracts-utils/contracts/src/Refundable.sol"; | ||||
| import "./libs/LibConstants.sol"; | ||||
| import "./interfaces/ICoordinatorCore.sol"; | ||||
| import "./interfaces/ICoordinatorApprovalVerifier.sol"; | ||||
|  | ||||
|  | ||||
| // solhint-disable no-empty-blocks | ||||
| contract MixinCoordinatorCore is | ||||
|     Refundable, | ||||
|     LibConstants, | ||||
|     ICoordinatorApprovalVerifier, | ||||
|     ICoordinatorCore | ||||
| { | ||||
|     /// @dev Executes a 0x transaction that has been signed by the feeRecipients that correspond to each order in the transaction's Exchange calldata. | ||||
|  | ||||
|     /// @dev A payable fallback function that makes this contract "payable". This is necessary to allow | ||||
|     ///      this contract to gracefully handle refunds from the Exchange. | ||||
|     function () | ||||
|         external | ||||
|         payable | ||||
|     {} | ||||
|  | ||||
|     /// @dev Executes a 0x transaction that has been signed by the feeRecipients that correspond to | ||||
|     ///      each order in the transaction's Exchange calldata. | ||||
|     /// @param transaction 0x transaction containing salt, signerAddress, and data. | ||||
|     /// @param txOrigin Required signer of Ethereum transaction calling this function. | ||||
|     /// @param transactionSignature Proof that the transaction has been signed by the signer. | ||||
|     /// @param approvalExpirationTimeSeconds Array of expiration times in seconds for which each corresponding approval signature expires. | ||||
|     /// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each order in the transaction's Exchange calldata. | ||||
|     /// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each | ||||
|     ///        order in the transaction's Exchange calldata. | ||||
|     function executeTransaction( | ||||
|         LibZeroExTransaction.ZeroExTransaction memory transaction, | ||||
|         address txOrigin, | ||||
|         bytes memory transactionSignature, | ||||
|         uint256[] memory approvalExpirationTimeSeconds, | ||||
|         bytes[] memory approvalSignatures | ||||
|     ) | ||||
|         public | ||||
|         payable | ||||
|         refundFinalBalance | ||||
|     { | ||||
|         // Validate that the 0x transaction has been approves by each feeRecipient | ||||
|         assertValidCoordinatorApprovals( | ||||
|             transaction, | ||||
|             txOrigin, | ||||
|             transactionSignature, | ||||
|             approvalExpirationTimeSeconds, | ||||
|             approvalSignatures | ||||
|         ); | ||||
|  | ||||
|         // Execute the transaction | ||||
|         EXCHANGE.executeTransaction(transaction, transactionSignature); | ||||
|         EXCHANGE.executeTransaction.value(msg.value)(transaction, transactionSignature); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -19,7 +19,9 @@ | ||||
| pragma solidity ^0.5.9; | ||||
|  | ||||
| import "@0x/contracts-utils/contracts/src/LibBytes.sol"; | ||||
| import "@0x/contracts-utils/contracts/src/LibRichErrors.sol"; | ||||
| import "./interfaces/ICoordinatorSignatureValidator.sol"; | ||||
| import "./libs/LibCoordinatorRichErrors.sol"; | ||||
|  | ||||
|  | ||||
| contract MixinSignatureValidator is | ||||
| @@ -30,24 +32,32 @@ contract MixinSignatureValidator is | ||||
|     /// @dev Recovers the address of a signer given a hash and signature. | ||||
|     /// @param hash Any 32 byte hash. | ||||
|     /// @param signature Proof that the hash has been signed by signer. | ||||
|     /// @return signerAddress Address of the signer. | ||||
|     function getSignerAddress(bytes32 hash, bytes memory signature) | ||||
|         public | ||||
|         pure | ||||
|         returns (address signerAddress) | ||||
|     { | ||||
|         require( | ||||
|             signature.length > 0, | ||||
|             "LENGTH_GREATER_THAN_0_REQUIRED" | ||||
|         ); | ||||
|         uint256 signatureLength = signature.length; | ||||
|         if (signatureLength == 0) { | ||||
|             LibRichErrors.rrevert(LibCoordinatorRichErrors.SignatureError( | ||||
|                 LibCoordinatorRichErrors.SignatureErrorCodes.INVALID_LENGTH, | ||||
|                 hash, | ||||
|                 signature | ||||
|             )); | ||||
|         } | ||||
|  | ||||
|         // Pop last byte off of signature byte array. | ||||
|         uint8 signatureTypeRaw = uint8(signature.popLastByte()); | ||||
|         uint8 signatureTypeRaw = uint8(signature[signature.length - 1]); | ||||
|  | ||||
|         // Ensure signature is supported | ||||
|         require( | ||||
|             signatureTypeRaw < uint8(SignatureType.NSignatureTypes), | ||||
|             "SIGNATURE_UNSUPPORTED" | ||||
|         ); | ||||
|         if (signatureTypeRaw >= uint8(SignatureType.NSignatureTypes)) { | ||||
|             LibRichErrors.rrevert(LibCoordinatorRichErrors.SignatureError( | ||||
|                 LibCoordinatorRichErrors.SignatureErrorCodes.UNSUPPORTED, | ||||
|                 hash, | ||||
|                 signature | ||||
|             )); | ||||
|         } | ||||
|  | ||||
|         SignatureType signatureType = SignatureType(signatureTypeRaw); | ||||
|  | ||||
| @@ -57,25 +67,32 @@ contract MixinSignatureValidator is | ||||
|         // it an explicit option. This aids testing and analysis. It is | ||||
|         // also the initialization value for the enum type. | ||||
|         if (signatureType == SignatureType.Illegal) { | ||||
|             revert("SIGNATURE_ILLEGAL"); | ||||
|             LibRichErrors.rrevert(LibCoordinatorRichErrors.SignatureError( | ||||
|                 LibCoordinatorRichErrors.SignatureErrorCodes.ILLEGAL, | ||||
|                 hash, | ||||
|                 signature | ||||
|             )); | ||||
|  | ||||
|         // Always invalid signature. | ||||
|         // Like Illegal, this is always implicitly available and therefore | ||||
|         // offered explicitly. It can be implicitly created by providing | ||||
|         // a correctly formatted but incorrect signature. | ||||
|         } else if (signatureType == SignatureType.Invalid) { | ||||
|             require( | ||||
|                 signature.length == 0, | ||||
|                 "LENGTH_0_REQUIRED" | ||||
|             ); | ||||
|             revert("SIGNATURE_INVALID"); | ||||
|             LibRichErrors.rrevert(LibCoordinatorRichErrors.SignatureError( | ||||
|                 LibCoordinatorRichErrors.SignatureErrorCodes.INVALID, | ||||
|                 hash, | ||||
|                 signature | ||||
|             )); | ||||
|  | ||||
|         // Signature using EIP712 | ||||
|         } else if (signatureType == SignatureType.EIP712) { | ||||
|             require( | ||||
|                 signature.length == 65, | ||||
|                 "LENGTH_65_REQUIRED" | ||||
|             ); | ||||
|             if (signatureLength != 66) { | ||||
|                 LibRichErrors.rrevert(LibCoordinatorRichErrors.SignatureError( | ||||
|                     LibCoordinatorRichErrors.SignatureErrorCodes.INVALID_LENGTH, | ||||
|                     hash, | ||||
|                     signature | ||||
|                 )); | ||||
|             } | ||||
|             uint8 v = uint8(signature[0]); | ||||
|             bytes32 r = signature.readBytes32(1); | ||||
|             bytes32 s = signature.readBytes32(33); | ||||
| @@ -89,10 +106,13 @@ contract MixinSignatureValidator is | ||||
|  | ||||
|         // Signed using web3.eth_sign | ||||
|         } else if (signatureType == SignatureType.EthSign) { | ||||
|             require( | ||||
|                 signature.length == 65, | ||||
|                 "LENGTH_65_REQUIRED" | ||||
|             ); | ||||
|             if (signatureLength != 66) { | ||||
|                 LibRichErrors.rrevert(LibCoordinatorRichErrors.SignatureError( | ||||
|                     LibCoordinatorRichErrors.SignatureErrorCodes.INVALID_LENGTH, | ||||
|                     hash, | ||||
|                     signature | ||||
|                 )); | ||||
|             } | ||||
|             uint8 v = uint8(signature[0]); | ||||
|             bytes32 r = signature.readBytes32(1); | ||||
|             bytes32 s = signature.readBytes32(33); | ||||
| @@ -113,6 +133,10 @@ contract MixinSignatureValidator is | ||||
|         // that we currently support. In this case returning false | ||||
|         // may lead the caller to incorrectly believe that the | ||||
|         // signature was invalid.) | ||||
|         revert("SIGNATURE_UNSUPPORTED"); | ||||
|         LibRichErrors.rrevert(LibCoordinatorRichErrors.SignatureError( | ||||
|             LibCoordinatorRichErrors.SignatureErrorCodes.UNSUPPORTED, | ||||
|             hash, | ||||
|             signature | ||||
|         )); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -30,13 +30,12 @@ contract ICoordinatorApprovalVerifier { | ||||
|     /// @param transaction 0x transaction containing salt, signerAddress, and data. | ||||
|     /// @param txOrigin Required signer of Ethereum transaction calling this function. | ||||
|     /// @param transactionSignature Proof that the transaction has been signed by the signer. | ||||
|     /// @param approvalExpirationTimeSeconds Array of expiration times in seconds for which each corresponding approval signature expires. | ||||
|     /// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each order in the transaction's Exchange calldata. | ||||
|     /// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each | ||||
|     ///        order in the transaction's Exchange calldata. | ||||
|     function assertValidCoordinatorApprovals( | ||||
|         LibZeroExTransaction.ZeroExTransaction memory transaction, | ||||
|         address txOrigin, | ||||
|         bytes memory transactionSignature, | ||||
|         uint256[] memory approvalExpirationTimeSeconds, | ||||
|         bytes[] memory approvalSignatures | ||||
|     ) | ||||
|         public | ||||
| @@ -44,7 +43,7 @@ contract ICoordinatorApprovalVerifier { | ||||
|  | ||||
|     /// @dev Decodes the orders from Exchange calldata representing any fill method. | ||||
|     /// @param data Exchange calldata representing a fill method. | ||||
|     /// @return The orders from the Exchange calldata. | ||||
|     /// @return orders The orders from the Exchange calldata. | ||||
|     function decodeOrdersFromFillData(bytes memory data) | ||||
|         public | ||||
|         pure | ||||
|   | ||||
| @@ -24,18 +24,19 @@ import "@0x/contracts-exchange-libs/contracts/src/LibZeroExTransaction.sol"; | ||||
|  | ||||
| contract ICoordinatorCore { | ||||
|  | ||||
|     /// @dev Executes a 0x transaction that has been signed by the feeRecipients that correspond to each order in the transaction's Exchange calldata. | ||||
|     /// @dev Executes a 0x transaction that has been signed by the feeRecipients that correspond to | ||||
|     ///      each order in the transaction's Exchange calldata. | ||||
|     /// @param transaction 0x transaction containing salt, signerAddress, and data. | ||||
|     /// @param txOrigin Required signer of Ethereum transaction calling this function. | ||||
|     /// @param transactionSignature Proof that the transaction has been signed by the signer. | ||||
|     /// @param approvalExpirationTimeSeconds Array of expiration times in seconds for which each corresponding approval signature expires. | ||||
|     /// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each order in the transaction's Exchange calldata. | ||||
|     /// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each | ||||
|     ///        order in the transaction's Exchange calldata. | ||||
|     function executeTransaction( | ||||
|         LibZeroExTransaction.ZeroExTransaction memory transaction, | ||||
|         address txOrigin, | ||||
|         bytes memory transactionSignature, | ||||
|         uint256[] memory approvalExpirationTimeSeconds, | ||||
|         bytes[] memory approvalSignatures | ||||
|     ) | ||||
|         public; | ||||
|         public | ||||
|         payable; | ||||
| } | ||||
|   | ||||
| @@ -30,14 +30,14 @@ contract ICoordinatorSignatureValidator { | ||||
|         Wallet,                 // 0x04 | ||||
|         Validator,              // 0x05 | ||||
|         PreSigned,              // 0x06 | ||||
|         OrderValidator,         // 0x07 | ||||
|         WalletOrderValidator,   // 0x08 | ||||
|         NSignatureTypes         // 0x09, number of signature types. Always leave at end. | ||||
|         EIP1271Wallet,          // 0x07 | ||||
|         NSignatureTypes         // 0x08, number of signature types. Always leave at end. | ||||
|     } | ||||
|  | ||||
|     /// @dev Recovers the address of a signer given a hash and signature. | ||||
|     /// @param hash Any 32 byte hash. | ||||
|     /// @param signature Proof that the hash has been signed by signer. | ||||
|     /// @return signerAddress Address of the signer.  | ||||
|     function getSignerAddress(bytes32 hash, bytes memory signature) | ||||
|         public | ||||
|         pure | ||||
|   | ||||
| @@ -30,22 +30,24 @@ contract LibCoordinatorApproval is | ||||
|     //     "CoordinatorApproval(", | ||||
|     //     "address txOrigin,", | ||||
|     //     "bytes32 transactionHash,", | ||||
|     //     "bytes transactionSignature,", | ||||
|     //     "uint256 approvalExpirationTimeSeconds", | ||||
|     //     "bytes transactionSignature", | ||||
|     //     ")" | ||||
|     // )); | ||||
|     bytes32 constant public EIP712_COORDINATOR_APPROVAL_SCHEMA_HASH = 0x2fbcdbaa76bc7589916958ae919dfbef04d23f6bbf26de6ff317b32c6cc01e05; | ||||
|     bytes32 constant public EIP712_COORDINATOR_APPROVAL_SCHEMA_HASH = | ||||
|         0xa6511c04ca44625d50986f8c36bedc09366207a17b96e347094053a9f8507168; | ||||
|  | ||||
|     struct CoordinatorApproval { | ||||
|         address txOrigin;                       // Required signer of Ethereum transaction that is submitting approval. | ||||
|         bytes32 transactionHash;                // EIP712 hash of the transaction. | ||||
|         bytes transactionSignature;             // Signature of the 0x transaction. | ||||
|         uint256 approvalExpirationTimeSeconds;  // Timestamp in seconds for which the approval expires. | ||||
|     } | ||||
|  | ||||
|     /// @dev Calculated the EIP712 hash of the Coordinator approval mesasage using the domain separator of this contract. | ||||
|     /// @param approval Coordinator approval message containing the transaction hash, transaction signature, and expiration of the approval. | ||||
|     /// @return EIP712 hash of the Coordinator approval message with the domain separator of this contract. | ||||
|     /// @dev Calculates the EIP712 hash of the Coordinator approval mesasage using the domain | ||||
|     ///      separator of this contract. | ||||
|     /// @param approval Coordinator approval message containing the transaction hash, and transaction | ||||
|     ///        signature. | ||||
|     /// @return approvalHash EIP712 hash of the Coordinator approval message with the domain | ||||
|     ///         separator of this contract. | ||||
|     function getCoordinatorApprovalHash(CoordinatorApproval memory approval) | ||||
|         public | ||||
|         view | ||||
| @@ -55,9 +57,10 @@ contract LibCoordinatorApproval is | ||||
|         return approvalHash; | ||||
|     } | ||||
|  | ||||
|     /// @dev Calculated the EIP712 hash of the Coordinator approval mesasage with no domain separator. | ||||
|     /// @param approval Coordinator approval message containing the transaction hash, transaction signature, and expiration of the approval. | ||||
|     /// @return EIP712 hash of the Coordinator approval message with no domain separator. | ||||
|     /// @dev Calculates the EIP712 hash of the Coordinator approval mesasage with no domain separator. | ||||
|     /// @param approval Coordinator approval message containing the transaction hash, and transaction | ||||
|     //         signature. | ||||
|     /// @return result EIP712 hash of the Coordinator approval message with no domain separator. | ||||
|     function _hashCoordinatorApproval(CoordinatorApproval memory approval) | ||||
|         internal | ||||
|         pure | ||||
| @@ -67,7 +70,6 @@ contract LibCoordinatorApproval is | ||||
|         bytes memory transactionSignature = approval.transactionSignature; | ||||
|         address txOrigin = approval.txOrigin; | ||||
|         bytes32 transactionHash = approval.transactionHash; | ||||
|         uint256 approvalExpirationTimeSeconds = approval.approvalExpirationTimeSeconds; | ||||
|  | ||||
|         // Assembly for more efficiently computing: | ||||
|         // keccak256(abi.encodePacked( | ||||
| @@ -75,7 +77,6 @@ contract LibCoordinatorApproval is | ||||
|         //     approval.txOrigin, | ||||
|         //     approval.transactionHash, | ||||
|         //     keccak256(approval.transactionSignature) | ||||
|         //     approval.approvalExpirationTimeSeconds, | ||||
|         // )); | ||||
|  | ||||
|         assembly { | ||||
| @@ -89,9 +90,8 @@ contract LibCoordinatorApproval is | ||||
|             mstore(add(memPtr, 32), txOrigin)                        // txOrigin | ||||
|             mstore(add(memPtr, 64), transactionHash)                 // transactionHash | ||||
|             mstore(add(memPtr, 96), transactionSignatureHash)        // transactionSignatureHash | ||||
|             mstore(add(memPtr, 128), approvalExpirationTimeSeconds)  // approvalExpirationTimeSeconds | ||||
|             // Compute hash | ||||
|             result := keccak256(memPtr, 160) | ||||
|             result := keccak256(memPtr, 128) | ||||
|         } | ||||
|         return result; | ||||
|     } | ||||
|   | ||||
| @@ -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; | ||||
|  | ||||
|  | ||||
| library LibCoordinatorRichErrors { | ||||
|     enum SignatureErrorCodes { | ||||
|         INVALID_LENGTH, | ||||
|         UNSUPPORTED, | ||||
|         ILLEGAL, | ||||
|         INVALID | ||||
|     } | ||||
|  | ||||
|     // bytes4(keccak256("SignatureError(uint8,bytes32,bytes)")) | ||||
|     bytes4 internal constant SIGNATURE_ERROR_SELECTOR = | ||||
|         0x779c5223; | ||||
|  | ||||
|     // bytes4(keccak256("InvalidOriginError(address)")) | ||||
|     bytes4 internal constant INVALID_ORIGIN_ERROR_SELECTOR = | ||||
|         0xa458d7ff; | ||||
|  | ||||
|     // bytes4(keccak256("InvalidApprovalSignatureError(bytes32,address)")) | ||||
|     bytes4 internal constant INVALID_APPROVAL_SIGNATURE_ERROR_SELECTOR = | ||||
|         0xd789b640; | ||||
|  | ||||
|     // solhint-disable func-name-mixedcase | ||||
|     function SignatureError( | ||||
|         SignatureErrorCodes errorCode, | ||||
|         bytes32 hash, | ||||
|         bytes memory signature | ||||
|     ) | ||||
|         internal | ||||
|         pure | ||||
|         returns (bytes memory) | ||||
|     { | ||||
|         return abi.encodeWithSelector( | ||||
|             SIGNATURE_ERROR_SELECTOR, | ||||
|             errorCode, | ||||
|             hash, | ||||
|             signature | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     function InvalidOriginError( | ||||
|         address expectedOrigin | ||||
|     ) | ||||
|         internal | ||||
|         pure | ||||
|         returns (bytes memory) | ||||
|     { | ||||
|         return abi.encodeWithSelector( | ||||
|             INVALID_ORIGIN_ERROR_SELECTOR, | ||||
|             expectedOrigin | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     function InvalidApprovalSignatureError( | ||||
|         bytes32 transactionHash, | ||||
|         address approverAddress | ||||
|     ) | ||||
|         internal | ||||
|         pure | ||||
|         returns (bytes memory) | ||||
|     { | ||||
|         return abi.encodeWithSelector( | ||||
|             INVALID_APPROVAL_SIGNATURE_ERROR_SELECTOR, | ||||
|             transactionHash, | ||||
|             approverAddress | ||||
|         ); | ||||
|     } | ||||
| } | ||||
| @@ -21,15 +21,13 @@ pragma solidity ^0.5.9; | ||||
| import "@0x/contracts-utils/contracts/src/LibEIP712.sol"; | ||||
|  | ||||
|  | ||||
| contract LibEIP712CoordinatorDomain is | ||||
|     LibEIP712 | ||||
| { | ||||
| contract LibEIP712CoordinatorDomain { | ||||
|  | ||||
|     // EIP712 Domain Name value for the Coordinator | ||||
|     string constant public EIP712_COORDINATOR_DOMAIN_NAME = "0x Protocol Coordinator"; | ||||
|  | ||||
|     // EIP712 Domain Version value for the Coordinator | ||||
|     string constant public EIP712_COORDINATOR_DOMAIN_VERSION = "2.0.0"; | ||||
|     string constant public EIP712_COORDINATOR_DOMAIN_VERSION = "3.0.0"; | ||||
|  | ||||
|     // Hash of the EIP712 Domain Separator data for the Coordinator | ||||
|     // solhint-disable-next-line var-name-mixedcase | ||||
| @@ -43,7 +41,9 @@ contract LibEIP712CoordinatorDomain is | ||||
|     ) | ||||
|         public | ||||
|     { | ||||
|         address verifyingContractAddress = verifyingContractAddressIfExists == address(0) ? address(this) : verifyingContractAddressIfExists; | ||||
|         address verifyingContractAddress = verifyingContractAddressIfExists == address(0) | ||||
|             ? address(this) | ||||
|             : verifyingContractAddressIfExists; | ||||
|         EIP712_COORDINATOR_DOMAIN_HASH = LibEIP712.hashEIP712Domain( | ||||
|             EIP712_COORDINATOR_DOMAIN_NAME, | ||||
|             EIP712_COORDINATOR_DOMAIN_VERSION, | ||||
| @@ -55,7 +55,7 @@ contract LibEIP712CoordinatorDomain is | ||||
|     /// @dev Calculates EIP712 encoding for a hash struct in the EIP712 domain | ||||
|     ///      of this contract. | ||||
|     /// @param hashStruct The EIP712 hash struct. | ||||
|     /// @return EIP712 hash applied to this EIP712 Domain. | ||||
|     /// @return result EIP712 hash applied to this EIP712 Domain. | ||||
|     function _hashEIP712CoordinatorMessage(bytes32 hashStruct) | ||||
|         internal | ||||
|         view | ||||
|   | ||||
| @@ -29,7 +29,7 @@ contract MixinCoordinatorRegistryCore is | ||||
|     mapping (address => string) internal coordinatorEndpoints; | ||||
|  | ||||
|     /// @dev Called by a Coordinator operator to set the endpoint of their Coordinator. | ||||
|     /// @param coordinatorEndpoint endpoint of the Coordinator. | ||||
|     /// @param coordinatorEndpoint Endpoint of the Coordinator as a string. | ||||
|     function setCoordinatorEndpoint(string calldata coordinatorEndpoint) external { | ||||
|         address coordinatorOperator = msg.sender; | ||||
|         coordinatorEndpoints[coordinatorOperator] = coordinatorEndpoint; | ||||
| @@ -37,7 +37,8 @@ contract MixinCoordinatorRegistryCore is | ||||
|     } | ||||
|  | ||||
|     /// @dev Gets the endpoint for a Coordinator. | ||||
|     /// @param coordinatorOperator operator of the Coordinator endpoint. | ||||
|     /// @param coordinatorOperator Operator of the Coordinator endpoint. | ||||
|     /// @return coordinatorEndpoint Endpoint of the Coordinator as a string. | ||||
|     function getCoordinatorEndpoint(address coordinatorOperator) | ||||
|         external | ||||
|         view | ||||
|   | ||||
| @@ -29,11 +29,12 @@ contract ICoordinatorRegistryCore | ||||
|     ); | ||||
|  | ||||
|     /// @dev Called by a Coordinator operator to set the endpoint of their Coordinator. | ||||
|     /// @param coordinatorEndpoint endpoint of the Coordinator. | ||||
|     /// @param coordinatorEndpoint Endpoint of the Coordinator as a string. | ||||
|     function setCoordinatorEndpoint(string calldata coordinatorEndpoint) external; | ||||
|  | ||||
|     /// @dev Gets the endpoint for a Coordinator. | ||||
|     /// @param coordinatorOperator operator of the Coordinator endpoint. | ||||
|     /// @param coordinatorOperator Operator of the Coordinator endpoint. | ||||
|     /// @return coordinatorEndpoint Endpoint of the Coordinator as a string. | ||||
|     function getCoordinatorEndpoint(address coordinatorOperator) | ||||
|         external | ||||
|         view | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "name": "@0x/contracts-coordinator", | ||||
|     "version": "2.1.0-beta.0", | ||||
|     "version": "2.1.0-beta.2", | ||||
|     "engines": { | ||||
|         "node": ">=6.12" | ||||
|     }, | ||||
| @@ -12,7 +12,7 @@ | ||||
|     "scripts": { | ||||
|         "build": "yarn pre_build && tsc -b", | ||||
|         "build:ci": "yarn build", | ||||
|         "pre_build": "run-s compile contracts:gen generate_contract_wrappers", | ||||
|         "pre_build": "run-s compile contracts:gen generate_contract_wrappers contracts:copy", | ||||
|         "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", | ||||
| @@ -21,21 +21,23 @@ | ||||
|         "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 generated-artifacts generated-wrappers", | ||||
|         "generate_contract_wrappers": "abi-gen --abis  ${npm_package_config_abis} --output generated-wrappers --backend ethers", | ||||
|         "lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts", | ||||
|         "fix": "tslint --fix --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts", | ||||
|         "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", | ||||
|         "fix": "tslint --fix --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", | ||||
|         "contracts:gen": "contracts-gen generate", | ||||
|         "contracts:copy": "contracts-gen copy", | ||||
|         "lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol", | ||||
|         "compile:truffle": "truffle compile" | ||||
|     }, | ||||
|     "config": { | ||||
|         "abis": "./generated-artifacts/@(Coordinator|CoordinatorRegistry).json", | ||||
|         "publicInterfaceContracts": "Coordinator,CoordinatorRegistry,LibCoordinatorApproval,LibCoordinatorRichErrors,LibEIP712CoordinatorDomain,LibConstants", | ||||
|         "abis": "./test/generated-artifacts/@(Coordinator|CoordinatorRegistry|ICoordinatorApprovalVerifier|ICoordinatorCore|ICoordinatorRegistryCore|ICoordinatorSignatureValidator|LibConstants|LibCoordinatorApproval|LibCoordinatorRichErrors|LibEIP712CoordinatorDomain|MixinCoordinatorApprovalVerifier|MixinCoordinatorCore|MixinCoordinatorRegistryCore|MixinSignatureValidator).json", | ||||
|         "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually." | ||||
|     }, | ||||
|     "repository": { | ||||
| @@ -48,12 +50,18 @@ | ||||
|     }, | ||||
|     "homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md", | ||||
|     "devDependencies": { | ||||
|         "@0x/abi-gen": "^4.3.0-beta.0", | ||||
|         "@0x/contracts-gen": "^1.1.0-beta.0", | ||||
|         "@0x/contracts-test-utils": "^3.2.0-beta.0", | ||||
|         "@0x/dev-utils": "^2.4.0-beta.0", | ||||
|         "@0x/sol-compiler": "^3.2.0-beta.0", | ||||
|         "@0x/tslint-config": "^3.0.1", | ||||
|         "@0x/abi-gen": "^4.4.0-beta.2", | ||||
|         "@0x/contracts-asset-proxy": "^2.3.0-beta.2", | ||||
|         "@0x/contracts-dev-utils": "^0.1.0-beta.2", | ||||
|         "@0x/contracts-erc20": "^2.3.0-beta.2", | ||||
|         "@0x/contracts-exchange": "^2.2.0-beta.2", | ||||
|         "@0x/contracts-gen": "^1.1.0-beta.2", | ||||
|         "@0x/contracts-test-utils": "^3.2.0-beta.2", | ||||
|         "@0x/dev-utils": "^2.4.0-beta.2", | ||||
|         "@0x/order-utils": "^8.5.0-beta.2", | ||||
|         "@0x/sol-compiler": "^3.2.0-beta.2", | ||||
|         "@0x/tslint-config": "^3.1.0-beta.2", | ||||
|         "@0x/web3-wrapper": "^6.1.0-beta.2", | ||||
|         "@types/lodash": "4.14.104", | ||||
|         "@types/mocha": "^5.2.7", | ||||
|         "@types/node": "*", | ||||
| @@ -61,6 +69,7 @@ | ||||
|         "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", | ||||
| @@ -71,20 +80,12 @@ | ||||
|         "typescript": "3.0.1" | ||||
|     }, | ||||
|     "dependencies": { | ||||
|         "@0x/base-contract": "^5.5.0-beta.0", | ||||
|         "@0x/contracts-asset-proxy": "^2.3.0-beta.0", | ||||
|         "@0x/contracts-erc20": "^2.3.0-beta.0", | ||||
|         "@0x/contracts-exchange": "^2.2.0-beta.0", | ||||
|         "@0x/contracts-exchange-libs": "^3.1.0-beta.0", | ||||
|         "@0x/contracts-utils": "^3.3.0-beta.0", | ||||
|         "@0x/order-utils": "^8.5.0-beta.0", | ||||
|         "@0x/types": "^2.5.0-beta.0", | ||||
|         "@0x/typescript-typings": "^4.4.0-beta.0", | ||||
|         "@0x/utils": "^4.6.0-beta.0", | ||||
|         "@0x/web3-wrapper": "^6.1.0-beta.0", | ||||
|         "ethereum-types": "^2.2.0-beta.0", | ||||
|         "ethereumjs-util": "^5.1.1", | ||||
|         "lodash": "^4.17.11" | ||||
|         "@0x/base-contract": "^5.5.0-beta.2", | ||||
|         "@0x/contracts-utils": "^3.3.0-beta.2", | ||||
|         "@0x/types": "^2.5.0-beta.2", | ||||
|         "@0x/typescript-typings": "^4.4.0-beta.2", | ||||
|         "@0x/utils": "^4.6.0-beta.2", | ||||
|         "ethereum-types": "^2.2.0-beta.2" | ||||
|     }, | ||||
|     "publishConfig": { | ||||
|         "access": "public" | ||||
|   | ||||
| @@ -1,9 +1,8 @@ | ||||
| import { signingUtils } from '@0x/contracts-test-utils'; | ||||
| import { hexConcat, signingUtils } from '@0x/contracts-test-utils'; | ||||
| import { SignatureType, SignedZeroExTransaction } from '@0x/types'; | ||||
| import { BigNumber } from '@0x/utils'; | ||||
| import * as ethUtil from 'ethereumjs-util'; | ||||
| 
 | ||||
| import { hashUtils, SignedCoordinatorApproval } from './index'; | ||||
| import { hashUtils } from './hash_utils'; | ||||
| import { SignedCoordinatorApproval } from './types'; | ||||
| 
 | ||||
| export class ApprovalFactory { | ||||
|     private readonly _privateKey: Buffer; | ||||
| @@ -14,24 +13,21 @@ export class ApprovalFactory { | ||||
|         this._verifyingContractAddress = verifyingContract; | ||||
|     } | ||||
| 
 | ||||
|     public newSignedApproval( | ||||
|     public async newSignedApprovalAsync( | ||||
|         transaction: SignedZeroExTransaction, | ||||
|         txOrigin: string, | ||||
|         approvalExpirationTimeSeconds: BigNumber, | ||||
|         signatureType: SignatureType = SignatureType.EthSign, | ||||
|     ): SignedCoordinatorApproval { | ||||
|         const approvalHashBuff = hashUtils.getApprovalHashBuffer( | ||||
|     ): Promise<SignedCoordinatorApproval> { | ||||
|         const approvalHashBuff = await hashUtils.getApprovalHashBufferAsync( | ||||
|             transaction, | ||||
|             this._verifyingContractAddress, | ||||
|             txOrigin, | ||||
|             approvalExpirationTimeSeconds, | ||||
|         ); | ||||
|         const signatureBuff = signingUtils.signMessage(approvalHashBuff, this._privateKey, signatureType); | ||||
|         const signedApproval = { | ||||
|             txOrigin, | ||||
|             transaction, | ||||
|             approvalExpirationTimeSeconds, | ||||
|             signature: ethUtil.addHexPrefix(signatureBuff.toString('hex')), | ||||
|             signature: hexConcat(signatureBuff), | ||||
|         }; | ||||
|         return signedApproval; | ||||
|     } | ||||
| @@ -7,7 +7,15 @@ import { ContractArtifact } from 'ethereum-types'; | ||||
|  | ||||
| import * as Coordinator from '../generated-artifacts/Coordinator.json'; | ||||
| import * as CoordinatorRegistry from '../generated-artifacts/CoordinatorRegistry.json'; | ||||
| import * as LibConstants from '../generated-artifacts/LibConstants.json'; | ||||
| import * as LibCoordinatorApproval from '../generated-artifacts/LibCoordinatorApproval.json'; | ||||
| import * as LibCoordinatorRichErrors from '../generated-artifacts/LibCoordinatorRichErrors.json'; | ||||
| import * as LibEIP712CoordinatorDomain from '../generated-artifacts/LibEIP712CoordinatorDomain.json'; | ||||
| export const artifacts = { | ||||
|     Coordinator: Coordinator as ContractArtifact, | ||||
|     CoordinatorRegistry: CoordinatorRegistry as ContractArtifact, | ||||
|     LibCoordinatorApproval: LibCoordinatorApproval as ContractArtifact, | ||||
|     LibCoordinatorRichErrors: LibCoordinatorRichErrors as ContractArtifact, | ||||
|     LibEIP712CoordinatorDomain: LibEIP712CoordinatorDomain as ContractArtifact, | ||||
|     LibConstants: LibConstants as ContractArtifact, | ||||
| }; | ||||
|   | ||||
| @@ -1,33 +1,28 @@ | ||||
| import { hexConcat } from '@0x/contracts-test-utils'; | ||||
| import { eip712Utils } from '@0x/order-utils'; | ||||
| import { SignedZeroExTransaction } from '@0x/types'; | ||||
| import { BigNumber, signTypedDataUtils } from '@0x/utils'; | ||||
| import * as _ from 'lodash'; | ||||
| import { signTypedDataUtils } from '@0x/utils'; | ||||
| 
 | ||||
| export const hashUtils = { | ||||
|     getApprovalHashBuffer( | ||||
|     async getApprovalHashBufferAsync( | ||||
|         transaction: SignedZeroExTransaction, | ||||
|         verifyingContract: string, | ||||
|         txOrigin: string, | ||||
|         approvalExpirationTimeSeconds: BigNumber, | ||||
|     ): Buffer { | ||||
|         const typedData = eip712Utils.createCoordinatorApprovalTypedData( | ||||
|     ): Promise<Buffer> { | ||||
|         const typedData = await eip712Utils.createCoordinatorApprovalTypedDataAsync( | ||||
|             transaction, | ||||
|             verifyingContract, | ||||
|             txOrigin, | ||||
|             approvalExpirationTimeSeconds, | ||||
|         ); | ||||
|         const hashBuffer = signTypedDataUtils.generateTypedDataHash(typedData); | ||||
|         return hashBuffer; | ||||
|     }, | ||||
|     getApprovalHashHex( | ||||
|     async getApprovalHashHexAsync( | ||||
|         transaction: SignedZeroExTransaction, | ||||
|         verifyingContract: string, | ||||
|         txOrigin: string, | ||||
|         approvalExpirationTimeSeconds: BigNumber, | ||||
|     ): string { | ||||
|         const hashHex = `0x${hashUtils | ||||
|             .getApprovalHashBuffer(transaction, verifyingContract, txOrigin, approvalExpirationTimeSeconds) | ||||
|             .toString('hex')}`;
 | ||||
|     ): Promise<string> { | ||||
|         const hashHex = hexConcat(await hashUtils.getApprovalHashBufferAsync(transaction, verifyingContract, txOrigin)); | ||||
|         return hashHex; | ||||
|     }, | ||||
| }; | ||||
| @@ -1,3 +1,5 @@ | ||||
| export * from './artifacts'; | ||||
| export * from './wrappers'; | ||||
| export * from '../test/utils'; | ||||
| export import CoordinatorRevertErrors = require('./revert_errors'); | ||||
| export { ApprovalFactory } from './approval_factory'; | ||||
| export { SignedCoordinatorApproval } from './types'; | ||||
|   | ||||
							
								
								
									
										52
									
								
								contracts/coordinator/src/revert_errors.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								contracts/coordinator/src/revert_errors.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,52 @@ | ||||
| import { BigNumber, RevertError } from '@0x/utils'; | ||||
|  | ||||
| // tslint:disable:max-classes-per-file | ||||
|  | ||||
| export enum SignatureErrorCodes { | ||||
|     InvalidLength, | ||||
|     Unsupported, | ||||
|     Illegal, | ||||
|     Invalid, | ||||
| } | ||||
|  | ||||
| export class SignatureError extends RevertError { | ||||
|     constructor(errorCode?: SignatureErrorCodes, hash?: string, signature?: string) { | ||||
|         super('SignatureError', 'SignatureError(uint8 errorCode, bytes32 hash, bytes signature)', { | ||||
|             errorCode, | ||||
|             hash, | ||||
|             signature, | ||||
|         }); | ||||
|     } | ||||
| } | ||||
|  | ||||
| export class InvalidOriginError extends RevertError { | ||||
|     constructor(expectedOrigin?: string) { | ||||
|         super('InvalidOriginError', 'InvalidOriginError(address expectedOrigin)', { expectedOrigin }); | ||||
|     } | ||||
| } | ||||
|  | ||||
| export class ApprovalExpiredError extends RevertError { | ||||
|     constructor(transactionHash?: string, approvalExpirationTime?: BigNumber | number | string) { | ||||
|         super('ApprovalExpiredError', 'ApprovalExpiredError(bytes32 transactionHash, uint256 approvalExpirationTime)', { | ||||
|             transactionHash, | ||||
|             approvalExpirationTime, | ||||
|         }); | ||||
|     } | ||||
| } | ||||
|  | ||||
| export class InvalidApprovalSignatureError extends RevertError { | ||||
|     constructor(transactionHash?: string, approverAddress?: string) { | ||||
|         super( | ||||
|             'InvalidApprovalSignatureError', | ||||
|             'InvalidApprovalSignatureError(bytes32 transactionHash, address approverAddress)', | ||||
|             { transactionHash, approverAddress }, | ||||
|         ); | ||||
|     } | ||||
| } | ||||
|  | ||||
| const types = [SignatureError, InvalidOriginError, ApprovalExpiredError, InvalidApprovalSignatureError]; | ||||
|  | ||||
| // Register the types we've defined. | ||||
| for (const type of types) { | ||||
|     RevertError.registerType(type); | ||||
| } | ||||
| @@ -1,10 +1,8 @@ | ||||
| import { SignedZeroExTransaction } from '@0x/types'; | ||||
| import { BigNumber } from '@0x/utils'; | ||||
| 
 | ||||
| export interface CoordinatorApproval { | ||||
|     transaction: SignedZeroExTransaction; | ||||
|     txOrigin: string; | ||||
|     approvalExpirationTimeSeconds: BigNumber; | ||||
| } | ||||
| 
 | ||||
| export interface SignedCoordinatorApproval extends CoordinatorApproval { | ||||
| @@ -5,3 +5,7 @@ | ||||
|  */ | ||||
| export * from '../generated-wrappers/coordinator'; | ||||
| export * from '../generated-wrappers/coordinator_registry'; | ||||
| export * from '../generated-wrappers/lib_constants'; | ||||
| export * from '../generated-wrappers/lib_coordinator_approval'; | ||||
| export * from '../generated-wrappers/lib_coordinator_rich_errors'; | ||||
| export * from '../generated-wrappers/lib_e_i_p712_coordinator_domain'; | ||||
|   | ||||
							
								
								
									
										37
									
								
								contracts/coordinator/test/artifacts.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								contracts/coordinator/test/artifacts.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | ||||
| /* | ||||
|  * ----------------------------------------------------------------------------- | ||||
|  * Warning: This file is auto-generated by contracts-gen. Don't edit manually. | ||||
|  * ----------------------------------------------------------------------------- | ||||
|  */ | ||||
| import { ContractArtifact } from 'ethereum-types'; | ||||
|  | ||||
| import * as Coordinator from '../test/generated-artifacts/Coordinator.json'; | ||||
| import * as CoordinatorRegistry from '../test/generated-artifacts/CoordinatorRegistry.json'; | ||||
| import * as ICoordinatorApprovalVerifier from '../test/generated-artifacts/ICoordinatorApprovalVerifier.json'; | ||||
| import * as ICoordinatorCore from '../test/generated-artifacts/ICoordinatorCore.json'; | ||||
| import * as ICoordinatorRegistryCore from '../test/generated-artifacts/ICoordinatorRegistryCore.json'; | ||||
| import * as ICoordinatorSignatureValidator from '../test/generated-artifacts/ICoordinatorSignatureValidator.json'; | ||||
| import * as LibConstants from '../test/generated-artifacts/LibConstants.json'; | ||||
| import * as LibCoordinatorApproval from '../test/generated-artifacts/LibCoordinatorApproval.json'; | ||||
| import * as LibCoordinatorRichErrors from '../test/generated-artifacts/LibCoordinatorRichErrors.json'; | ||||
| import * as LibEIP712CoordinatorDomain from '../test/generated-artifacts/LibEIP712CoordinatorDomain.json'; | ||||
| import * as MixinCoordinatorApprovalVerifier from '../test/generated-artifacts/MixinCoordinatorApprovalVerifier.json'; | ||||
| import * as MixinCoordinatorCore from '../test/generated-artifacts/MixinCoordinatorCore.json'; | ||||
| import * as MixinCoordinatorRegistryCore from '../test/generated-artifacts/MixinCoordinatorRegistryCore.json'; | ||||
| import * as MixinSignatureValidator from '../test/generated-artifacts/MixinSignatureValidator.json'; | ||||
| export const artifacts = { | ||||
|     Coordinator: Coordinator as ContractArtifact, | ||||
|     MixinCoordinatorApprovalVerifier: MixinCoordinatorApprovalVerifier as ContractArtifact, | ||||
|     MixinCoordinatorCore: MixinCoordinatorCore as ContractArtifact, | ||||
|     MixinSignatureValidator: MixinSignatureValidator as ContractArtifact, | ||||
|     ICoordinatorApprovalVerifier: ICoordinatorApprovalVerifier as ContractArtifact, | ||||
|     ICoordinatorCore: ICoordinatorCore as ContractArtifact, | ||||
|     ICoordinatorSignatureValidator: ICoordinatorSignatureValidator as ContractArtifact, | ||||
|     LibConstants: LibConstants as ContractArtifact, | ||||
|     LibCoordinatorApproval: LibCoordinatorApproval as ContractArtifact, | ||||
|     LibCoordinatorRichErrors: LibCoordinatorRichErrors as ContractArtifact, | ||||
|     LibEIP712CoordinatorDomain: LibEIP712CoordinatorDomain as ContractArtifact, | ||||
|     CoordinatorRegistry: CoordinatorRegistry as ContractArtifact, | ||||
|     MixinCoordinatorRegistryCore: MixinCoordinatorRegistryCore as ContractArtifact, | ||||
|     ICoordinatorRegistryCore: ICoordinatorRegistryCore as ContractArtifact, | ||||
| }; | ||||
| @@ -1,531 +0,0 @@ | ||||
| import { ERC20ProxyContract, ERC20Wrapper } from '@0x/contracts-asset-proxy'; | ||||
| import { DummyERC20TokenContract } from '@0x/contracts-erc20'; | ||||
| import { | ||||
|     artifacts as exchangeArtifacts, | ||||
|     constants as exchangeConstants, | ||||
|     ExchangeCancelEventArgs, | ||||
|     ExchangeCancelUpToEventArgs, | ||||
|     ExchangeContract, | ||||
|     exchangeDataEncoder, | ||||
|     ExchangeFillEventArgs, | ||||
|     ExchangeFunctionName, | ||||
| } from '@0x/contracts-exchange'; | ||||
| import { | ||||
|     chaiSetup, | ||||
|     constants, | ||||
|     expectTransactionFailedAsync, | ||||
|     getLatestBlockTimestampAsync, | ||||
|     OrderFactory, | ||||
|     provider, | ||||
|     TransactionFactory, | ||||
|     txDefaults, | ||||
|     web3Wrapper, | ||||
| } from '@0x/contracts-test-utils'; | ||||
| import { BlockchainLifecycle } from '@0x/dev-utils'; | ||||
| import { assetDataUtils, orderHashUtils } from '@0x/order-utils'; | ||||
| import { RevertReason } from '@0x/types'; | ||||
| import { BigNumber, providerUtils } from '@0x/utils'; | ||||
| import * as chai from 'chai'; | ||||
| import { LogWithDecodedArgs } from 'ethereum-types'; | ||||
|  | ||||
| import { ApprovalFactory, artifacts, CoordinatorContract } from '../src'; | ||||
|  | ||||
| chaiSetup.configure(); | ||||
| const expect = chai.expect; | ||||
| const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); | ||||
| web3Wrapper.abiDecoder.addABI(exchangeArtifacts.Exchange.compilerOutput.abi); | ||||
| // tslint:disable:no-unnecessary-type-assertion | ||||
| describe('Coordinator tests', () => { | ||||
|     let chainId: number; | ||||
|     let makerAddress: string; | ||||
|     let owner: string; | ||||
|     let takerAddress: string; | ||||
|     let feeRecipientAddress: string; | ||||
|  | ||||
|     let erc20Proxy: ERC20ProxyContract; | ||||
|     let erc20TokenA: DummyERC20TokenContract; | ||||
|     let erc20TokenB: DummyERC20TokenContract; | ||||
|     let makerFeeToken: DummyERC20TokenContract; | ||||
|     let coordinatorContract: CoordinatorContract; | ||||
|     let exchange: ExchangeContract; | ||||
|  | ||||
|     let erc20Wrapper: ERC20Wrapper; | ||||
|     let orderFactory: OrderFactory; | ||||
|     let takerTransactionFactory: TransactionFactory; | ||||
|     let makerTransactionFactory: TransactionFactory; | ||||
|     let approvalFactory: ApprovalFactory; | ||||
|  | ||||
|     before(async () => { | ||||
|         await blockchainLifecycle.startAsync(); | ||||
|     }); | ||||
|     after(async () => { | ||||
|         await blockchainLifecycle.revertAsync(); | ||||
|     }); | ||||
|     before(async () => { | ||||
|         chainId = await providerUtils.getChainIdAsync(provider); | ||||
|         const accounts = await web3Wrapper.getAvailableAddressesAsync(); | ||||
|         const usedAddresses = ([owner, makerAddress, takerAddress, feeRecipientAddress] = accounts.slice(0, 4)); | ||||
|  | ||||
|         erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner); | ||||
|         erc20Proxy = await erc20Wrapper.deployProxyAsync(); | ||||
|         const numDummyErc20ToDeploy = 3; | ||||
|         [erc20TokenA, erc20TokenB, makerFeeToken] = await erc20Wrapper.deployDummyTokensAsync( | ||||
|             numDummyErc20ToDeploy, | ||||
|             constants.DUMMY_TOKEN_DECIMALS, | ||||
|         ); | ||||
|         await erc20Wrapper.setBalancesAndAllowancesAsync(); | ||||
|  | ||||
|         exchange = await ExchangeContract.deployFrom0xArtifactAsync( | ||||
|             exchangeArtifacts.Exchange, | ||||
|             provider, | ||||
|             txDefaults, | ||||
|             new BigNumber(chainId), | ||||
|         ); | ||||
|  | ||||
|         await web3Wrapper.awaitTransactionSuccessAsync( | ||||
|             await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, { from: owner }), | ||||
|             constants.AWAIT_TRANSACTION_MINED_MS, | ||||
|         ); | ||||
|  | ||||
|         await web3Wrapper.awaitTransactionSuccessAsync( | ||||
|             await exchange.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, { from: owner }), | ||||
|             constants.AWAIT_TRANSACTION_MINED_MS, | ||||
|         ); | ||||
|  | ||||
|         coordinatorContract = await CoordinatorContract.deployFrom0xArtifactAsync( | ||||
|             artifacts.Coordinator, | ||||
|             provider, | ||||
|             txDefaults, | ||||
|             artifacts, | ||||
|             exchange.address, | ||||
|             new BigNumber(chainId), | ||||
|         ); | ||||
|  | ||||
|         // Configure order defaults | ||||
|         const defaultOrderParams = { | ||||
|             ...constants.STATIC_ORDER_PARAMS, | ||||
|             senderAddress: coordinatorContract.address, | ||||
|             makerAddress, | ||||
|             feeRecipientAddress, | ||||
|             makerAssetData: assetDataUtils.encodeERC20AssetData(erc20TokenA.address), | ||||
|             takerAssetData: assetDataUtils.encodeERC20AssetData(erc20TokenB.address), | ||||
|             makerFeeAssetData: assetDataUtils.encodeERC20AssetData(makerFeeToken.address), | ||||
|             takerFeeAssetData: assetDataUtils.encodeERC20AssetData(makerFeeToken.address), | ||||
|             exchangeAddress: exchange.address, | ||||
|             chainId, | ||||
|         }; | ||||
|         const makerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)]; | ||||
|         const takerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(takerAddress)]; | ||||
|         const feeRecipientPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(feeRecipientAddress)]; | ||||
|         orderFactory = new OrderFactory(makerPrivateKey, defaultOrderParams); | ||||
|         makerTransactionFactory = new TransactionFactory(makerPrivateKey, exchange.address, chainId); | ||||
|         takerTransactionFactory = new TransactionFactory(takerPrivateKey, exchange.address, chainId); | ||||
|         approvalFactory = new ApprovalFactory(feeRecipientPrivateKey, coordinatorContract.address); | ||||
|     }); | ||||
|     beforeEach(async () => { | ||||
|         await blockchainLifecycle.startAsync(); | ||||
|     }); | ||||
|     afterEach(async () => { | ||||
|         await blockchainLifecycle.revertAsync(); | ||||
|     }); | ||||
|  | ||||
|     describe('single order fills', () => { | ||||
|         for (const fnName of exchangeConstants.SINGLE_FILL_FN_NAMES) { | ||||
|             it(`${fnName} should fill the order with a signed approval`, async () => { | ||||
|                 const orders = [await orderFactory.newSignedOrderAsync()]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const currentTimestamp = await getLatestBlockTimestampAsync(); | ||||
|                 const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); | ||||
|                 const approval = approvalFactory.newSignedApproval( | ||||
|                     transaction, | ||||
|                     takerAddress, | ||||
|                     approvalExpirationTimeSeconds, | ||||
|                 ); | ||||
|                 const transactionReceipt = await web3Wrapper.awaitTransactionSuccessAsync( | ||||
|                     await coordinatorContract.executeTransaction.sendTransactionAsync( | ||||
|                         transaction, | ||||
|                         takerAddress, | ||||
|                         transaction.signature, | ||||
|                         [approvalExpirationTimeSeconds], | ||||
|                         [approval.signature], | ||||
|                         { from: takerAddress }, | ||||
|                     ), | ||||
|                     constants.AWAIT_TRANSACTION_MINED_MS, | ||||
|                 ); | ||||
|                 const fillLogs = transactionReceipt.logs.filter( | ||||
|                     log => (log as LogWithDecodedArgs<ExchangeFillEventArgs>).event === 'Fill', | ||||
|                 ); | ||||
|                 expect(fillLogs.length).to.eq(1); | ||||
|                 const fillLogArgs = (fillLogs[0] as LogWithDecodedArgs<ExchangeFillEventArgs>).args; | ||||
|                 expect(fillLogArgs.makerAddress).to.eq(makerAddress); | ||||
|                 expect(fillLogArgs.takerAddress).to.eq(takerAddress); | ||||
|                 expect(fillLogArgs.senderAddress).to.eq(coordinatorContract.address); | ||||
|                 expect(fillLogArgs.feeRecipientAddress).to.eq(feeRecipientAddress); | ||||
|                 expect(fillLogArgs.makerAssetData).to.eq(orders[0].makerAssetData); | ||||
|                 expect(fillLogArgs.takerAssetData).to.eq(orders[0].takerAssetData); | ||||
|                 expect(fillLogArgs.makerAssetFilledAmount).to.bignumber.eq(orders[0].makerAssetAmount); | ||||
|                 expect(fillLogArgs.takerAssetFilledAmount).to.bignumber.eq(orders[0].takerAssetAmount); | ||||
|                 expect(fillLogArgs.makerFeePaid).to.bignumber.eq(orders[0].makerFee); | ||||
|                 expect(fillLogArgs.takerFeePaid).to.bignumber.eq(orders[0].takerFee); | ||||
|                 expect(fillLogArgs.orderHash).to.eq(orderHashUtils.getOrderHashHex(orders[0])); | ||||
|             }); | ||||
|             it(`${fnName} should fill the order if called by approver`, async () => { | ||||
|                 const orders = [await orderFactory.newSignedOrderAsync()]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const transactionReceipt = await web3Wrapper.awaitTransactionSuccessAsync( | ||||
|                     await coordinatorContract.executeTransaction.sendTransactionAsync( | ||||
|                         transaction, | ||||
|                         feeRecipientAddress, | ||||
|                         transaction.signature, | ||||
|                         [], | ||||
|                         [], | ||||
|                         { from: feeRecipientAddress }, | ||||
|                     ), | ||||
|                     constants.AWAIT_TRANSACTION_MINED_MS, | ||||
|                 ); | ||||
|                 const fillLogs = transactionReceipt.logs.filter( | ||||
|                     log => (log as LogWithDecodedArgs<ExchangeFillEventArgs>).event === 'Fill', | ||||
|                 ); | ||||
|                 expect(fillLogs.length).to.eq(1); | ||||
|                 const fillLogArgs = (fillLogs[0] as LogWithDecodedArgs<ExchangeFillEventArgs>).args; | ||||
|                 expect(fillLogArgs.makerAddress).to.eq(makerAddress); | ||||
|                 expect(fillLogArgs.takerAddress).to.eq(takerAddress); | ||||
|                 expect(fillLogArgs.senderAddress).to.eq(coordinatorContract.address); | ||||
|                 expect(fillLogArgs.feeRecipientAddress).to.eq(feeRecipientAddress); | ||||
|                 expect(fillLogArgs.makerAssetData).to.eq(orders[0].makerAssetData); | ||||
|                 expect(fillLogArgs.takerAssetData).to.eq(orders[0].takerAssetData); | ||||
|                 expect(fillLogArgs.makerAssetFilledAmount).to.bignumber.eq(orders[0].makerAssetAmount); | ||||
|                 expect(fillLogArgs.takerAssetFilledAmount).to.bignumber.eq(orders[0].takerAssetAmount); | ||||
|                 expect(fillLogArgs.makerFeePaid).to.bignumber.eq(orders[0].makerFee); | ||||
|                 expect(fillLogArgs.takerFeePaid).to.bignumber.eq(orders[0].takerFee); | ||||
|                 expect(fillLogArgs.orderHash).to.eq(orderHashUtils.getOrderHashHex(orders[0])); | ||||
|             }); | ||||
|             it(`${fnName} should revert with no approval signature`, async () => { | ||||
|                 const orders = [await orderFactory.newSignedOrderAsync()]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 await expectTransactionFailedAsync( | ||||
|                     coordinatorContract.executeTransaction.sendTransactionAsync( | ||||
|                         transaction, | ||||
|                         takerAddress, | ||||
|                         transaction.signature, | ||||
|                         [], | ||||
|                         [], | ||||
|                         { | ||||
|                             from: takerAddress, | ||||
|                             gas: constants.MAX_EXECUTE_TRANSACTION_GAS, | ||||
|                         }, | ||||
|                     ), | ||||
|                     RevertReason.InvalidApprovalSignature, | ||||
|                 ); | ||||
|             }); | ||||
|             it(`${fnName} should revert with an invalid approval signature`, async () => { | ||||
|                 const orders = [await orderFactory.newSignedOrderAsync()]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const currentTimestamp = await getLatestBlockTimestampAsync(); | ||||
|                 const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); | ||||
|                 const approval = approvalFactory.newSignedApproval( | ||||
|                     transaction, | ||||
|                     takerAddress, | ||||
|                     approvalExpirationTimeSeconds, | ||||
|                 ); | ||||
|                 const signature = `${approval.signature.slice(0, 4)}FFFFFFFF${approval.signature.slice(12)}`; | ||||
|                 await expectTransactionFailedAsync( | ||||
|                     coordinatorContract.executeTransaction.sendTransactionAsync( | ||||
|                         transaction, | ||||
|                         takerAddress, | ||||
|                         transaction.signature, | ||||
|                         [approvalExpirationTimeSeconds], | ||||
|                         [signature], | ||||
|                         { from: takerAddress }, | ||||
|                     ), | ||||
|                     RevertReason.InvalidApprovalSignature, | ||||
|                 ); | ||||
|             }); | ||||
|             it(`${fnName} should revert with an expired approval`, async () => { | ||||
|                 const orders = [await orderFactory.newSignedOrderAsync()]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const currentTimestamp = await getLatestBlockTimestampAsync(); | ||||
|                 const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).minus(constants.TIME_BUFFER); | ||||
|                 const approval = approvalFactory.newSignedApproval( | ||||
|                     transaction, | ||||
|                     takerAddress, | ||||
|                     approvalExpirationTimeSeconds, | ||||
|                 ); | ||||
|                 await expectTransactionFailedAsync( | ||||
|                     coordinatorContract.executeTransaction.sendTransactionAsync( | ||||
|                         transaction, | ||||
|                         takerAddress, | ||||
|                         transaction.signature, | ||||
|                         [approvalExpirationTimeSeconds], | ||||
|                         [approval.signature], | ||||
|                         { from: takerAddress }, | ||||
|                     ), | ||||
|                     RevertReason.ApprovalExpired, | ||||
|                 ); | ||||
|             }); | ||||
|             it(`${fnName} should revert if not called by tx signer or approver`, async () => { | ||||
|                 const orders = [await orderFactory.newSignedOrderAsync()]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const currentTimestamp = await getLatestBlockTimestampAsync(); | ||||
|                 const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); | ||||
|                 const approval = approvalFactory.newSignedApproval( | ||||
|                     transaction, | ||||
|                     takerAddress, | ||||
|                     approvalExpirationTimeSeconds, | ||||
|                 ); | ||||
|                 await expectTransactionFailedAsync( | ||||
|                     coordinatorContract.executeTransaction.sendTransactionAsync( | ||||
|                         transaction, | ||||
|                         takerAddress, | ||||
|                         transaction.signature, | ||||
|                         [approvalExpirationTimeSeconds], | ||||
|                         [approval.signature], | ||||
|                         { from: owner }, | ||||
|                     ), | ||||
|                     RevertReason.InvalidOrigin, | ||||
|                 ); | ||||
|             }); | ||||
|         } | ||||
|     }); | ||||
|     describe('batch order fills', () => { | ||||
|         for (const fnName of [...exchangeConstants.MARKET_FILL_FN_NAMES, ...exchangeConstants.BATCH_FILL_FN_NAMES]) { | ||||
|             it(`${fnName} should fill the orders with a signed approval`, async () => { | ||||
|                 const orders = [await orderFactory.newSignedOrderAsync(), await orderFactory.newSignedOrderAsync()]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const currentTimestamp = await getLatestBlockTimestampAsync(); | ||||
|                 const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); | ||||
|                 const approval = approvalFactory.newSignedApproval( | ||||
|                     transaction, | ||||
|                     takerAddress, | ||||
|                     approvalExpirationTimeSeconds, | ||||
|                 ); | ||||
|                 const transactionReceipt = await web3Wrapper.awaitTransactionSuccessAsync( | ||||
|                     await coordinatorContract.executeTransaction.sendTransactionAsync( | ||||
|                         transaction, | ||||
|                         takerAddress, | ||||
|                         transaction.signature, | ||||
|                         [approvalExpirationTimeSeconds], | ||||
|                         [approval.signature], | ||||
|                         { from: takerAddress, gas: constants.MAX_EXECUTE_TRANSACTION_GAS }, | ||||
|                     ), | ||||
|                     constants.AWAIT_TRANSACTION_MINED_MS, | ||||
|                 ); | ||||
|                 const fillLogs = transactionReceipt.logs.filter( | ||||
|                     log => (log as LogWithDecodedArgs<ExchangeFillEventArgs>).event === 'Fill', | ||||
|                 ); | ||||
|                 expect(fillLogs.length).to.eq(orders.length); | ||||
|                 orders.forEach((order, index) => { | ||||
|                     const fillLogArgs = (fillLogs[index] as LogWithDecodedArgs<ExchangeFillEventArgs>).args; | ||||
|                     expect(fillLogArgs.makerAddress).to.eq(makerAddress); | ||||
|                     expect(fillLogArgs.takerAddress).to.eq(takerAddress); | ||||
|                     expect(fillLogArgs.senderAddress).to.eq(coordinatorContract.address); | ||||
|                     expect(fillLogArgs.feeRecipientAddress).to.eq(feeRecipientAddress); | ||||
|                     expect(fillLogArgs.makerAssetData).to.eq(order.makerAssetData); | ||||
|                     expect(fillLogArgs.takerAssetData).to.eq(order.takerAssetData); | ||||
|                     expect(fillLogArgs.makerAssetFilledAmount).to.bignumber.eq(order.makerAssetAmount); | ||||
|                     expect(fillLogArgs.takerAssetFilledAmount).to.bignumber.eq(order.takerAssetAmount); | ||||
|                     expect(fillLogArgs.makerFeePaid).to.bignumber.eq(order.makerFee); | ||||
|                     expect(fillLogArgs.takerFeePaid).to.bignumber.eq(order.takerFee); | ||||
|                     expect(fillLogArgs.orderHash).to.eq(orderHashUtils.getOrderHashHex(order)); | ||||
|                 }); | ||||
|             }); | ||||
|             it(`${fnName} should fill the orders if called by approver`, async () => { | ||||
|                 const orders = [await orderFactory.newSignedOrderAsync(), await orderFactory.newSignedOrderAsync()]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const transactionReceipt = await web3Wrapper.awaitTransactionSuccessAsync( | ||||
|                     await coordinatorContract.executeTransaction.sendTransactionAsync( | ||||
|                         transaction, | ||||
|                         feeRecipientAddress, | ||||
|                         transaction.signature, | ||||
|                         [], | ||||
|                         [], | ||||
|                         { from: feeRecipientAddress, gas: constants.MAX_EXECUTE_TRANSACTION_GAS }, | ||||
|                     ), | ||||
|                     constants.AWAIT_TRANSACTION_MINED_MS, | ||||
|                 ); | ||||
|                 const fillLogs = transactionReceipt.logs.filter( | ||||
|                     log => (log as LogWithDecodedArgs<ExchangeFillEventArgs>).event === 'Fill', | ||||
|                 ); | ||||
|                 expect(fillLogs.length).to.eq(orders.length); | ||||
|                 orders.forEach((order, index) => { | ||||
|                     const fillLogArgs = (fillLogs[index] as LogWithDecodedArgs<ExchangeFillEventArgs>).args; | ||||
|                     expect(fillLogArgs.makerAddress).to.eq(makerAddress); | ||||
|                     expect(fillLogArgs.takerAddress).to.eq(takerAddress); | ||||
|                     expect(fillLogArgs.senderAddress).to.eq(coordinatorContract.address); | ||||
|                     expect(fillLogArgs.feeRecipientAddress).to.eq(feeRecipientAddress); | ||||
|                     expect(fillLogArgs.makerAssetData).to.eq(order.makerAssetData); | ||||
|                     expect(fillLogArgs.takerAssetData).to.eq(order.takerAssetData); | ||||
|                     expect(fillLogArgs.makerAssetFilledAmount).to.bignumber.eq(order.makerAssetAmount); | ||||
|                     expect(fillLogArgs.takerAssetFilledAmount).to.bignumber.eq(order.takerAssetAmount); | ||||
|                     expect(fillLogArgs.makerFeePaid).to.bignumber.eq(order.makerFee); | ||||
|                     expect(fillLogArgs.takerFeePaid).to.bignumber.eq(order.takerFee); | ||||
|                     expect(fillLogArgs.orderHash).to.eq(orderHashUtils.getOrderHashHex(order)); | ||||
|                 }); | ||||
|             }); | ||||
|             it(`${fnName} should revert with an invalid approval signature`, async () => { | ||||
|                 const orders = [await orderFactory.newSignedOrderAsync(), await orderFactory.newSignedOrderAsync()]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const currentTimestamp = await getLatestBlockTimestampAsync(); | ||||
|                 const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); | ||||
|                 const approval = approvalFactory.newSignedApproval( | ||||
|                     transaction, | ||||
|                     takerAddress, | ||||
|                     approvalExpirationTimeSeconds, | ||||
|                 ); | ||||
|                 const signature = `${approval.signature.slice(0, 4)}FFFFFFFF${approval.signature.slice(12)}`; | ||||
|                 await expectTransactionFailedAsync( | ||||
|                     coordinatorContract.executeTransaction.sendTransactionAsync( | ||||
|                         transaction, | ||||
|                         takerAddress, | ||||
|                         transaction.signature, | ||||
|                         [approvalExpirationTimeSeconds], | ||||
|                         [signature], | ||||
|                         { from: takerAddress }, | ||||
|                     ), | ||||
|                     RevertReason.InvalidApprovalSignature, | ||||
|                 ); | ||||
|             }); | ||||
|             it(`${fnName} should revert with an expired approval`, async () => { | ||||
|                 const orders = [await orderFactory.newSignedOrderAsync(), await orderFactory.newSignedOrderAsync()]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const currentTimestamp = await getLatestBlockTimestampAsync(); | ||||
|                 const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).minus(constants.TIME_BUFFER); | ||||
|                 const approval = approvalFactory.newSignedApproval( | ||||
|                     transaction, | ||||
|                     takerAddress, | ||||
|                     approvalExpirationTimeSeconds, | ||||
|                 ); | ||||
|                 await expectTransactionFailedAsync( | ||||
|                     coordinatorContract.executeTransaction.sendTransactionAsync( | ||||
|                         transaction, | ||||
|                         takerAddress, | ||||
|                         transaction.signature, | ||||
|                         [approvalExpirationTimeSeconds], | ||||
|                         [approval.signature], | ||||
|                         { from: takerAddress }, | ||||
|                     ), | ||||
|                     RevertReason.ApprovalExpired, | ||||
|                 ); | ||||
|             }); | ||||
|             it(`${fnName} should revert if not called by tx signer or approver`, async () => { | ||||
|                 const orders = [await orderFactory.newSignedOrderAsync(), await orderFactory.newSignedOrderAsync()]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const currentTimestamp = await getLatestBlockTimestampAsync(); | ||||
|                 const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); | ||||
|                 const approval = approvalFactory.newSignedApproval( | ||||
|                     transaction, | ||||
|                     takerAddress, | ||||
|                     approvalExpirationTimeSeconds, | ||||
|                 ); | ||||
|                 await expectTransactionFailedAsync( | ||||
|                     coordinatorContract.executeTransaction.sendTransactionAsync( | ||||
|                         transaction, | ||||
|                         takerAddress, | ||||
|                         transaction.signature, | ||||
|                         [approvalExpirationTimeSeconds], | ||||
|                         [approval.signature], | ||||
|                         { from: owner }, | ||||
|                     ), | ||||
|                     RevertReason.InvalidOrigin, | ||||
|                 ); | ||||
|             }); | ||||
|         } | ||||
|     }); | ||||
|     describe('cancels', () => { | ||||
|         it('cancelOrder call should be successful without an approval', async () => { | ||||
|             const orders = [await orderFactory.newSignedOrderAsync()]; | ||||
|             const data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.CancelOrder, orders); | ||||
|             const transaction = await makerTransactionFactory.newSignedTransactionAsync({ data }); | ||||
|             const transactionReceipt = await web3Wrapper.awaitTransactionSuccessAsync( | ||||
|                 await coordinatorContract.executeTransaction.sendTransactionAsync( | ||||
|                     transaction, | ||||
|                     makerAddress, | ||||
|                     transaction.signature, | ||||
|                     [], | ||||
|                     [], | ||||
|                     { | ||||
|                         from: makerAddress, | ||||
|                     }, | ||||
|                 ), | ||||
|             ); | ||||
|             const cancelLogs = transactionReceipt.logs.filter( | ||||
|                 log => (log as LogWithDecodedArgs<ExchangeCancelEventArgs>).event === 'Cancel', | ||||
|             ); | ||||
|             expect(cancelLogs.length).to.eq(1); | ||||
|             const cancelLogArgs = (cancelLogs[0] as LogWithDecodedArgs<ExchangeCancelEventArgs>).args; | ||||
|             expect(cancelLogArgs.makerAddress).to.eq(makerAddress); | ||||
|             expect(cancelLogArgs.senderAddress).to.eq(coordinatorContract.address); | ||||
|             expect(cancelLogArgs.feeRecipientAddress).to.eq(feeRecipientAddress); | ||||
|             expect(cancelLogArgs.makerAssetData).to.eq(orders[0].makerAssetData); | ||||
|             expect(cancelLogArgs.takerAssetData).to.eq(orders[0].takerAssetData); | ||||
|             expect(cancelLogArgs.orderHash).to.eq(orderHashUtils.getOrderHashHex(orders[0])); | ||||
|         }); | ||||
|         it('batchCancelOrders call should be successful without an approval', async () => { | ||||
|             const orders = [await orderFactory.newSignedOrderAsync(), await orderFactory.newSignedOrderAsync()]; | ||||
|             const data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.BatchCancelOrders, orders); | ||||
|             const transaction = await makerTransactionFactory.newSignedTransactionAsync({ data }); | ||||
|             const transactionReceipt = await web3Wrapper.awaitTransactionSuccessAsync( | ||||
|                 await coordinatorContract.executeTransaction.sendTransactionAsync( | ||||
|                     transaction, | ||||
|                     makerAddress, | ||||
|                     transaction.signature, | ||||
|                     [], | ||||
|                     [], | ||||
|                     { | ||||
|                         from: makerAddress, | ||||
|                     }, | ||||
|                 ), | ||||
|             ); | ||||
|             const cancelLogs = transactionReceipt.logs.filter( | ||||
|                 log => (log as LogWithDecodedArgs<ExchangeCancelEventArgs>).event === 'Cancel', | ||||
|             ); | ||||
|             expect(cancelLogs.length).to.eq(orders.length); | ||||
|             orders.forEach((order, index) => { | ||||
|                 const cancelLogArgs = (cancelLogs[index] as LogWithDecodedArgs<ExchangeCancelEventArgs>).args; | ||||
|                 expect(cancelLogArgs.makerAddress).to.eq(makerAddress); | ||||
|                 expect(cancelLogArgs.senderAddress).to.eq(coordinatorContract.address); | ||||
|                 expect(cancelLogArgs.feeRecipientAddress).to.eq(feeRecipientAddress); | ||||
|                 expect(cancelLogArgs.makerAssetData).to.eq(order.makerAssetData); | ||||
|                 expect(cancelLogArgs.takerAssetData).to.eq(order.takerAssetData); | ||||
|                 expect(cancelLogArgs.orderHash).to.eq(orderHashUtils.getOrderHashHex(order)); | ||||
|             }); | ||||
|         }); | ||||
|         it('cancelOrdersUpTo call should be successful without an approval', async () => { | ||||
|             const targetEpoch = constants.ZERO_AMOUNT; | ||||
|             const data = exchange.cancelOrdersUpTo.getABIEncodedTransactionData(targetEpoch); | ||||
|             const transaction = await makerTransactionFactory.newSignedTransactionAsync({ data }); | ||||
|             const transactionReceipt = await web3Wrapper.awaitTransactionSuccessAsync( | ||||
|                 await coordinatorContract.executeTransaction.sendTransactionAsync( | ||||
|                     transaction, | ||||
|                     makerAddress, | ||||
|                     transaction.signature, | ||||
|                     [], | ||||
|                     [], | ||||
|                     { | ||||
|                         from: makerAddress, | ||||
|                     }, | ||||
|                 ), | ||||
|             ); | ||||
|             const cancelLogs = transactionReceipt.logs.filter( | ||||
|                 log => (log as LogWithDecodedArgs<ExchangeCancelUpToEventArgs>).event === 'CancelUpTo', | ||||
|             ); | ||||
|             expect(cancelLogs.length).to.eq(1); | ||||
|             const cancelLogArgs = (cancelLogs[0] as LogWithDecodedArgs<ExchangeCancelUpToEventArgs>).args; | ||||
|             expect(cancelLogArgs.makerAddress).to.eq(makerAddress); | ||||
|             expect(cancelLogArgs.orderSenderAddress).to.eq(coordinatorContract.address); | ||||
|             expect(cancelLogArgs.orderEpoch).to.bignumber.eq(targetEpoch.plus(1)); | ||||
|         }); | ||||
|     }); | ||||
| }); | ||||
| // tslint:disable:max-file-line-count | ||||
| @@ -1,81 +1,73 @@ | ||||
| import { artifacts as exchangeArtifacts } from '@0x/contracts-exchange'; | ||||
| import { chaiSetup, provider, web3Wrapper } from '@0x/contracts-test-utils'; | ||||
| import { BlockchainLifecycle } from '@0x/dev-utils'; | ||||
| import * as chai from 'chai'; | ||||
| import { LogWithDecodedArgs } from 'ethereum-types'; | ||||
| import { blockchainTests, expect, verifyEvents } from '@0x/contracts-test-utils'; | ||||
|  | ||||
| import { CoordinatorRegistryCoordinatorEndpointSetEventArgs } from '../src'; | ||||
| import { artifacts } from './artifacts'; | ||||
|  | ||||
| import { CoordinatorRegistryWrapper } from './utils/coordinator_registry_wrapper'; | ||||
| import { CoordinatorRegistryContract, CoordinatorRegistryCoordinatorEndpointSetEventArgs } from './wrappers'; | ||||
|  | ||||
| chaiSetup.configure(); | ||||
| const expect = chai.expect; | ||||
| const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); | ||||
| web3Wrapper.abiDecoder.addABI(exchangeArtifacts.Exchange.compilerOutput.abi); | ||||
| // tslint:disable:no-unnecessary-type-assertion | ||||
| describe('Coordinator Registry tests', () => { | ||||
| blockchainTests.resets('Coordinator Registry tests', env => { | ||||
|     let coordinatorRegistry: CoordinatorRegistryContract; | ||||
|     let coordinatorOperator: string; | ||||
|     const coordinatorEndpoint = 'http://sometec.0x.org'; | ||||
|     const nilCoordinatorEndpoint = ''; | ||||
|     let coordinatorRegistryWrapper: CoordinatorRegistryWrapper; | ||||
|     // tests | ||||
|     before(async () => { | ||||
|         await blockchainLifecycle.startAsync(); | ||||
|     }); | ||||
|     after(async () => { | ||||
|         await blockchainLifecycle.revertAsync(); | ||||
|     }); | ||||
|     before(async () => { | ||||
|         // setup accounts (skip owner) | ||||
|         const accounts = await web3Wrapper.getAvailableAddressesAsync(); | ||||
|         const accounts = await env.getAccountAddressesAsync(); | ||||
|         [, coordinatorOperator] = accounts; | ||||
|         // deploy coordinator registry | ||||
|         coordinatorRegistryWrapper = new CoordinatorRegistryWrapper(provider); | ||||
|         await coordinatorRegistryWrapper.deployCoordinatorRegistryAsync(); | ||||
|     }); | ||||
|     beforeEach(async () => { | ||||
|         await blockchainLifecycle.startAsync(); | ||||
|     }); | ||||
|     afterEach(async () => { | ||||
|         await blockchainLifecycle.revertAsync(); | ||||
|         coordinatorRegistry = await CoordinatorRegistryContract.deployFrom0xArtifactAsync( | ||||
|             artifacts.CoordinatorRegistry, | ||||
|             env.provider, | ||||
|             env.txDefaults, | ||||
|             artifacts, | ||||
|         ); | ||||
|     }); | ||||
|     describe('core', () => { | ||||
|         it('Should successfully set a Coordinator endpoint', async () => { | ||||
|             await coordinatorRegistryWrapper.setCoordinatorEndpointAsync(coordinatorOperator, coordinatorEndpoint); | ||||
|             const recordedCoordinatorEndpoint = await coordinatorRegistryWrapper.getCoordinatorEndpointAsync( | ||||
|                 coordinatorOperator, | ||||
|             ); | ||||
|             await coordinatorRegistry.setCoordinatorEndpoint(coordinatorEndpoint).awaitTransactionSuccessAsync({ | ||||
|                 from: coordinatorOperator, | ||||
|             }); | ||||
|             const recordedCoordinatorEndpoint = await coordinatorRegistry | ||||
|                 .getCoordinatorEndpoint(coordinatorOperator) | ||||
|                 .callAsync(); | ||||
|             expect(recordedCoordinatorEndpoint).to.be.equal(coordinatorEndpoint); | ||||
|         }); | ||||
|         it('Should successfully unset a Coordinator endpoint', async () => { | ||||
|             // set Coordinator endpoint | ||||
|             await coordinatorRegistryWrapper.setCoordinatorEndpointAsync(coordinatorOperator, coordinatorEndpoint); | ||||
|             let recordedCoordinatorEndpoint = await coordinatorRegistryWrapper.getCoordinatorEndpointAsync( | ||||
|                 coordinatorOperator, | ||||
|             ); | ||||
|             await coordinatorRegistry.setCoordinatorEndpoint(coordinatorEndpoint).awaitTransactionSuccessAsync({ | ||||
|                 from: coordinatorOperator, | ||||
|             }); | ||||
|             let recordedCoordinatorEndpoint = await coordinatorRegistry | ||||
|                 .getCoordinatorEndpoint(coordinatorOperator) | ||||
|                 .callAsync(); | ||||
|             expect(recordedCoordinatorEndpoint).to.be.equal(coordinatorEndpoint); | ||||
|             // unset Coordinator endpoint | ||||
|             await coordinatorRegistryWrapper.setCoordinatorEndpointAsync(coordinatorOperator, nilCoordinatorEndpoint); | ||||
|             recordedCoordinatorEndpoint = await coordinatorRegistryWrapper.getCoordinatorEndpointAsync( | ||||
|                 coordinatorOperator, | ||||
|             ); | ||||
|             await coordinatorRegistry.setCoordinatorEndpoint(nilCoordinatorEndpoint).awaitTransactionSuccessAsync({ | ||||
|                 from: coordinatorOperator, | ||||
|             }); | ||||
|             recordedCoordinatorEndpoint = await coordinatorRegistry | ||||
|                 .getCoordinatorEndpoint(coordinatorOperator) | ||||
|                 .callAsync(); | ||||
|             expect(recordedCoordinatorEndpoint).to.be.equal(nilCoordinatorEndpoint); | ||||
|         }); | ||||
|         it('Should emit an event when setting Coordinator endpoint', async () => { | ||||
|             // set Coordinator endpoint | ||||
|             const txReceipt = await coordinatorRegistryWrapper.setCoordinatorEndpointAsync( | ||||
|                 coordinatorOperator, | ||||
|                 coordinatorEndpoint, | ||||
|             ); | ||||
|             const recordedCoordinatorEndpoint = await coordinatorRegistryWrapper.getCoordinatorEndpointAsync( | ||||
|                 coordinatorOperator, | ||||
|             ); | ||||
|             const txReceipt = await coordinatorRegistry | ||||
|                 .setCoordinatorEndpoint(coordinatorEndpoint) | ||||
|                 .awaitTransactionSuccessAsync({ | ||||
|                     from: coordinatorOperator, | ||||
|                 }); | ||||
|             const recordedCoordinatorEndpoint = await coordinatorRegistry | ||||
|                 .getCoordinatorEndpoint(coordinatorOperator) | ||||
|                 .callAsync(); | ||||
|             expect(recordedCoordinatorEndpoint).to.be.equal(coordinatorEndpoint); | ||||
|             // validate event | ||||
|             expect(txReceipt.logs.length).to.be.equal(1); | ||||
|             const log = txReceipt.logs[0] as LogWithDecodedArgs<CoordinatorRegistryCoordinatorEndpointSetEventArgs>; | ||||
|             expect(log.args.coordinatorOperator).to.be.equal(coordinatorOperator); | ||||
|             expect(log.args.coordinatorEndpoint).to.be.equal(coordinatorEndpoint); | ||||
|             const expectedEvent: CoordinatorRegistryCoordinatorEndpointSetEventArgs = { | ||||
|                 coordinatorOperator, | ||||
|                 coordinatorEndpoint, | ||||
|             }; | ||||
|             verifyEvents(txReceipt, [expectedEvent], 'CoordinatorEndpointSet'); | ||||
|         }); | ||||
|     }); | ||||
| }); | ||||
|   | ||||
| @@ -1,67 +1,35 @@ | ||||
| import { chaiSetup, constants, provider, randomAddress, txDefaults, web3Wrapper } from '@0x/contracts-test-utils'; | ||||
| import { BlockchainLifecycle } from '@0x/dev-utils'; | ||||
| import { transactionHashUtils } from '@0x/order-utils'; | ||||
| import { BigNumber, providerUtils } from '@0x/utils'; | ||||
| import * as chai from 'chai'; | ||||
| import { blockchainTests, constants, expect, randomAddress, transactionHashUtils } from '@0x/contracts-test-utils'; | ||||
| import { BigNumber } from '@0x/utils'; | ||||
|  | ||||
| import { artifacts, CoordinatorContract, hashUtils } from '../src'; | ||||
| import { hashUtils } from '../src/hash_utils'; | ||||
|  | ||||
| chaiSetup.configure(); | ||||
| const expect = chai.expect; | ||||
| const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); | ||||
| import { artifacts } from './artifacts'; | ||||
|  | ||||
| describe('Libs tests', () => { | ||||
| import { CoordinatorContract } from './wrappers'; | ||||
|  | ||||
| blockchainTests.resets('Libs tests', env => { | ||||
|     let coordinatorContract: CoordinatorContract; | ||||
|     let chainId: number; | ||||
|     const exchangeAddress = randomAddress(); | ||||
|  | ||||
|     before(async () => { | ||||
|         await blockchainLifecycle.startAsync(); | ||||
|     }); | ||||
|     after(async () => { | ||||
|         await blockchainLifecycle.revertAsync(); | ||||
|     }); | ||||
|     before(async () => { | ||||
|         chainId = await providerUtils.getChainIdAsync(provider); | ||||
|         chainId = await env.getChainIdAsync(); | ||||
|         coordinatorContract = await CoordinatorContract.deployFrom0xArtifactAsync( | ||||
|             artifacts.Coordinator, | ||||
|             provider, | ||||
|             txDefaults, | ||||
|             env.provider, | ||||
|             env.txDefaults, | ||||
|             artifacts, | ||||
|             exchangeAddress, | ||||
|             new BigNumber(chainId), | ||||
|         ); | ||||
|     }); | ||||
|     beforeEach(async () => { | ||||
|         await blockchainLifecycle.startAsync(); | ||||
|     }); | ||||
|     afterEach(async () => { | ||||
|         await blockchainLifecycle.revertAsync(); | ||||
|     }); | ||||
|  | ||||
|     describe('getTransactionHash', () => { | ||||
|         it('should return the correct transaction hash', async () => { | ||||
|             const tx = { | ||||
|                 salt: new BigNumber(0), | ||||
|                 expirationTimeSeconds: new BigNumber(0), | ||||
|                 signerAddress: constants.NULL_ADDRESS, | ||||
|                 data: '0x1234', | ||||
|                 domain: { | ||||
|                     verifyingContract: exchangeAddress, | ||||
|                     chainId, | ||||
|                 }, | ||||
|             }; | ||||
|             const expectedTxHash = transactionHashUtils.getTransactionHashHex(tx); | ||||
|             const txHash = await coordinatorContract.getTransactionHash.callAsync(tx); | ||||
|             expect(expectedTxHash).to.eq(txHash); | ||||
|         }); | ||||
|     }); | ||||
|  | ||||
|     describe('getApprovalHash', () => { | ||||
|         it('should return the correct approval hash', async () => { | ||||
|             const signedTx = { | ||||
|                 salt: new BigNumber(0), | ||||
|                 expirationTimeSeconds: new BigNumber(0), | ||||
|                 salt: constants.ZERO_AMOUNT, | ||||
|                 gasPrice: constants.ZERO_AMOUNT, | ||||
|                 expirationTimeSeconds: constants.ZERO_AMOUNT, | ||||
|                 signerAddress: constants.NULL_ADDRESS, | ||||
|                 data: '0x1234', | ||||
|                 signature: '0x5678', | ||||
| @@ -70,21 +38,18 @@ describe('Libs tests', () => { | ||||
|                     chainId, | ||||
|                 }, | ||||
|             }; | ||||
|             const approvalExpirationTimeSeconds = new BigNumber(0); | ||||
|             const txOrigin = constants.NULL_ADDRESS; | ||||
|             const approval = { | ||||
|                 txOrigin, | ||||
|                 transactionHash: transactionHashUtils.getTransactionHashHex(signedTx), | ||||
|                 transactionSignature: signedTx.signature, | ||||
|                 approvalExpirationTimeSeconds, | ||||
|             }; | ||||
|             const expectedApprovalHash = hashUtils.getApprovalHashHex( | ||||
|             const expectedApprovalHash = await hashUtils.getApprovalHashHexAsync( | ||||
|                 signedTx, | ||||
|                 coordinatorContract.address, | ||||
|                 txOrigin, | ||||
|                 approvalExpirationTimeSeconds, | ||||
|             ); | ||||
|             const approvalHash = await coordinatorContract.getCoordinatorApprovalHash.callAsync(approval); | ||||
|             const approvalHash = await coordinatorContract.getCoordinatorApprovalHash(approval).callAsync(); | ||||
|             expect(expectedApprovalHash).to.eq(approvalHash); | ||||
|         }); | ||||
|     }); | ||||
|   | ||||
| @@ -1,29 +1,28 @@ | ||||
| import { constants as exchangeConstants, exchangeDataEncoder, ExchangeFunctionName } from '@0x/contracts-exchange'; | ||||
| import { exchangeDataEncoder } from '@0x/contracts-exchange'; | ||||
| import { | ||||
|     chaiSetup, | ||||
|     blockchainTests, | ||||
|     constants, | ||||
|     expectContractCallFailedAsync, | ||||
|     getLatestBlockTimestampAsync, | ||||
|     provider, | ||||
|     ExchangeFunctionName, | ||||
|     expect, | ||||
|     hexConcat, | ||||
|     hexSlice, | ||||
|     randomAddress, | ||||
|     TransactionFactory, | ||||
|     txDefaults, | ||||
|     web3Wrapper, | ||||
|     transactionHashUtils, | ||||
| } from '@0x/contracts-test-utils'; | ||||
| import { BlockchainLifecycle } from '@0x/dev-utils'; | ||||
| import { transactionHashUtils } from '@0x/order-utils'; | ||||
| import { RevertReason, SignatureType, SignedOrder } from '@0x/types'; | ||||
| import { BigNumber, LibBytesRevertErrors, providerUtils } from '@0x/utils'; | ||||
| import * as chai from 'chai'; | ||||
| import * as ethUtil from 'ethereumjs-util'; | ||||
| import { LibBytesRevertErrors } from '@0x/contracts-utils'; | ||||
| import { SignatureType, SignedOrder } from '@0x/types'; | ||||
| import { BigNumber } from '@0x/utils'; | ||||
|  | ||||
| import { ApprovalFactory, artifacts, CoordinatorContract } from '../src'; | ||||
| import CoordinatorRevertErrors = require('../src/revert_errors'); | ||||
|  | ||||
| chaiSetup.configure(); | ||||
| const expect = chai.expect; | ||||
| const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); | ||||
| import { ApprovalFactory } from '../src/approval_factory'; | ||||
|  | ||||
| describe('Mixins tests', () => { | ||||
| import { artifacts } from './artifacts'; | ||||
|  | ||||
| import { CoordinatorContract } from './wrappers'; | ||||
|  | ||||
| blockchainTests.resets('Mixins tests', env => { | ||||
|     let chainId: number; | ||||
|     let transactionSignerAddress: string; | ||||
|     let approvalSignerAddress1: string; | ||||
| @@ -36,23 +35,17 @@ describe('Mixins tests', () => { | ||||
|     const exchangeAddress = randomAddress(); | ||||
|  | ||||
|     before(async () => { | ||||
|         await blockchainLifecycle.startAsync(); | ||||
|     }); | ||||
|     after(async () => { | ||||
|         await blockchainLifecycle.revertAsync(); | ||||
|     }); | ||||
|     before(async () => { | ||||
|         chainId = await providerUtils.getChainIdAsync(provider); | ||||
|         chainId = await env.getChainIdAsync(); | ||||
|         mixins = await CoordinatorContract.deployFrom0xArtifactAsync( | ||||
|             artifacts.Coordinator, | ||||
|             provider, | ||||
|             txDefaults, | ||||
|             env.provider, | ||||
|             env.txDefaults, | ||||
|             artifacts, | ||||
|             exchangeAddress, | ||||
|             new BigNumber(chainId), | ||||
|         ); | ||||
|         const accounts = await web3Wrapper.getAvailableAddressesAsync(); | ||||
|         [transactionSignerAddress, approvalSignerAddress1, approvalSignerAddress2] = accounts.slice(0, 3); | ||||
|         const accounts = await env.getAccountAddressesAsync(); | ||||
|         [transactionSignerAddress, approvalSignerAddress1, approvalSignerAddress2] = accounts; | ||||
|         defaultOrder = { | ||||
|             makerAddress: constants.NULL_ADDRESS, | ||||
|             takerAddress: constants.NULL_ADDRESS, | ||||
| @@ -79,72 +72,91 @@ describe('Mixins tests', () => { | ||||
|         approvalFactory1 = new ApprovalFactory(approvalSignerPrivateKey1, mixins.address); | ||||
|         approvalFactory2 = new ApprovalFactory(approvalSignerPrivateKey2, mixins.address); | ||||
|     }); | ||||
|     beforeEach(async () => { | ||||
|         await blockchainLifecycle.startAsync(); | ||||
|     }); | ||||
|     afterEach(async () => { | ||||
|         await blockchainLifecycle.revertAsync(); | ||||
|     }); | ||||
|  | ||||
|     describe('getSignerAddress', () => { | ||||
|         it('should return the correct address using the EthSign signature type', async () => { | ||||
|             const data = constants.NULL_BYTES; | ||||
|             const transaction = await transactionFactory.newSignedTransactionAsync({ data }, SignatureType.EthSign); | ||||
|             const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); | ||||
|             const signerAddress = await mixins.getSignerAddress.callAsync(transactionHash, transaction.signature); | ||||
|             const signerAddress = await mixins.getSignerAddress(transactionHash, transaction.signature).callAsync(); | ||||
|             expect(transaction.signerAddress).to.eq(signerAddress); | ||||
|         }); | ||||
|         it('should return the correct address using the EIP712 signature type', async () => { | ||||
|             const data = constants.NULL_BYTES; | ||||
|             const transaction = await transactionFactory.newSignedTransactionAsync({ data }, SignatureType.EIP712); | ||||
|             const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); | ||||
|             const signerAddress = await mixins.getSignerAddress.callAsync(transactionHash, transaction.signature); | ||||
|             const signerAddress = await mixins.getSignerAddress(transactionHash, transaction.signature).callAsync(); | ||||
|             expect(transaction.signerAddress).to.eq(signerAddress); | ||||
|         }); | ||||
|         it('should revert with with the Illegal signature type', async () => { | ||||
|             const data = constants.NULL_BYTES; | ||||
|             const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|             const illegalSignatureByte = ethUtil.toBuffer(SignatureType.Illegal).toString('hex'); | ||||
|             transaction.signature = `${transaction.signature.slice( | ||||
|                 0, | ||||
|                 transaction.signature.length - 2, | ||||
|             )}${illegalSignatureByte}`; | ||||
|             transaction.signature = hexConcat( | ||||
|                 hexSlice(transaction.signature, 0, transaction.signature.length - 1), | ||||
|                 SignatureType.Illegal, | ||||
|             ); | ||||
|             const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); | ||||
|             expect(mixins.getSignerAddress.callAsync(transactionHash, transaction.signature)).to.be.rejectedWith( | ||||
|                 RevertReason.SignatureIllegal, | ||||
|             expect(mixins.getSignerAddress(transactionHash, transaction.signature).callAsync()).to.revertWith( | ||||
|                 new CoordinatorRevertErrors.SignatureError( | ||||
|                     CoordinatorRevertErrors.SignatureErrorCodes.Illegal, | ||||
|                     transactionHash, | ||||
|                     transaction.signature, | ||||
|                 ), | ||||
|             ); | ||||
|         }); | ||||
|         it('should revert with with the Invalid signature type', async () => { | ||||
|             const data = constants.NULL_BYTES; | ||||
|             const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|             const invalidSignatureByte = ethUtil.toBuffer(SignatureType.Invalid).toString('hex'); | ||||
|             transaction.signature = `0x${invalidSignatureByte}`; | ||||
|             transaction.signature = hexConcat(SignatureType.Invalid); | ||||
|             const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); | ||||
|             expect(mixins.getSignerAddress.callAsync(transactionHash, transaction.signature)).to.be.rejectedWith( | ||||
|                 RevertReason.SignatureInvalid, | ||||
|             expect(mixins.getSignerAddress(transactionHash, transaction.signature).callAsync()).to.revertWith( | ||||
|                 new CoordinatorRevertErrors.SignatureError( | ||||
|                     CoordinatorRevertErrors.SignatureErrorCodes.Invalid, | ||||
|                     transactionHash, | ||||
|                     transaction.signature, | ||||
|                 ), | ||||
|             ); | ||||
|         }); | ||||
|         it("should revert with with a signature type that doesn't exist", async () => { | ||||
|         it('should revert with with a signature type that equals `NSignatureTypes`', async () => { | ||||
|             const data = constants.NULL_BYTES; | ||||
|             const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|             const invalidSignatureByte = '04'; | ||||
|             transaction.signature = `${transaction.signature.slice( | ||||
|                 0, | ||||
|                 transaction.signature.length - 2, | ||||
|             )}${invalidSignatureByte}`; | ||||
|             transaction.signature = hexConcat( | ||||
|                 hexSlice(transaction.signature, 0, transaction.signature.length - 1), | ||||
|                 SignatureType.NSignatureTypes, | ||||
|             ); | ||||
|             const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); | ||||
|             expect(mixins.getSignerAddress.callAsync(transactionHash, transaction.signature)).to.be.rejectedWith( | ||||
|                 RevertReason.SignatureUnsupported, | ||||
|             expect(mixins.getSignerAddress(transactionHash, transaction.signature).callAsync()).to.revertWith( | ||||
|                 new CoordinatorRevertErrors.SignatureError( | ||||
|                     CoordinatorRevertErrors.SignatureErrorCodes.Unsupported, | ||||
|                     transactionHash, | ||||
|                     transaction.signature, | ||||
|                 ), | ||||
|             ); | ||||
|         }); | ||||
|         it("should revert with with a signature type that isn't supported", async () => { | ||||
|             const data = constants.NULL_BYTES; | ||||
|             const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|             transaction.signature = hexConcat( | ||||
|                 hexSlice(transaction.signature, 0, transaction.signature.length - 1), | ||||
|                 SignatureType.Wallet, | ||||
|             ); | ||||
|             const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); | ||||
|             expect(mixins.getSignerAddress(transactionHash, transaction.signature).callAsync()).to.revertWith( | ||||
|                 new CoordinatorRevertErrors.SignatureError( | ||||
|                     CoordinatorRevertErrors.SignatureErrorCodes.Unsupported, | ||||
|                     transactionHash, | ||||
|                     transaction.signature, | ||||
|                 ), | ||||
|             ); | ||||
|         }); | ||||
|     }); | ||||
|  | ||||
|     describe('decodeOrdersFromFillData', () => { | ||||
|         for (const fnName of exchangeConstants.SINGLE_FILL_FN_NAMES) { | ||||
|         for (const fnName of constants.SINGLE_FILL_FN_NAMES) { | ||||
|             it(`should correctly decode the orders for ${fnName} data`, async () => { | ||||
|                 const orders = [defaultOrder]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const decodedOrders = await mixins.decodeOrdersFromFillData.callAsync(data); | ||||
|                 const decodedOrders = await mixins.decodeOrdersFromFillData(data).callAsync(); | ||||
|                 const decodedSignedOrders = decodedOrders.map(order => ({ | ||||
|                     ...order, | ||||
|                     signature: constants.NULL_BYTES, | ||||
| @@ -154,11 +166,11 @@ describe('Mixins tests', () => { | ||||
|                 expect(orders).to.deep.eq(decodedSignedOrders); | ||||
|             }); | ||||
|         } | ||||
|         for (const fnName of exchangeConstants.BATCH_FILL_FN_NAMES) { | ||||
|         for (const fnName of constants.BATCH_FILL_FN_NAMES) { | ||||
|             it(`should correctly decode the orders for ${fnName} data`, async () => { | ||||
|                 const orders = [defaultOrder, defaultOrder]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const decodedOrders = await mixins.decodeOrdersFromFillData.callAsync(data); | ||||
|                 const decodedOrders = await mixins.decodeOrdersFromFillData(data).callAsync(); | ||||
|                 const decodedSignedOrders = decodedOrders.map(order => ({ | ||||
|                     ...order, | ||||
|                     signature: constants.NULL_BYTES, | ||||
| @@ -168,11 +180,11 @@ describe('Mixins tests', () => { | ||||
|                 expect(orders).to.deep.eq(decodedSignedOrders); | ||||
|             }); | ||||
|         } | ||||
|         for (const fnName of exchangeConstants.MARKET_FILL_FN_NAMES) { | ||||
|         for (const fnName of constants.MARKET_FILL_FN_NAMES) { | ||||
|             it(`should correctly decode the orders for ${fnName} data`, async () => { | ||||
|                 const orders = [defaultOrder, defaultOrder]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const decodedOrders = await mixins.decodeOrdersFromFillData.callAsync(data); | ||||
|                 const decodedOrders = await mixins.decodeOrdersFromFillData(data).callAsync(); | ||||
|                 const decodedSignedOrders = decodedOrders.map(order => ({ | ||||
|                     ...order, | ||||
|                     signature: constants.NULL_BYTES, | ||||
| @@ -182,22 +194,32 @@ describe('Mixins tests', () => { | ||||
|                 expect(orders).to.deep.eq(decodedSignedOrders); | ||||
|             }); | ||||
|         } | ||||
|         for (const fnName of [ | ||||
|             ExchangeFunctionName.CancelOrder, | ||||
|             ExchangeFunctionName.BatchCancelOrders, | ||||
|             ExchangeFunctionName.CancelOrdersUpTo, | ||||
|         ]) { | ||||
|         for (const fnName of constants.MATCH_ORDER_FN_NAMES) { | ||||
|             it(`should correctly decode the orders for ${fnName} data`, async () => { | ||||
|                 const orders = [defaultOrder, defaultOrder]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const decodedOrders = await mixins.decodeOrdersFromFillData.callAsync(data); | ||||
|                 const decodedOrders = await mixins.decodeOrdersFromFillData(data).callAsync(); | ||||
|                 const decodedSignedOrders = decodedOrders.map(order => ({ | ||||
|                     ...order, | ||||
|                     signature: constants.NULL_BYTES, | ||||
|                     exchangeAddress: constants.NULL_ADDRESS, | ||||
|                     chainId, | ||||
|                 })); | ||||
|                 expect(orders).to.deep.eq(decodedSignedOrders); | ||||
|             }); | ||||
|         } | ||||
|         for (const fnName of constants.CANCEL_ORDER_FN_NAMES) { | ||||
|             it(`should correctly decode the orders for ${fnName} data`, async () => { | ||||
|                 const orders = [defaultOrder, defaultOrder]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const decodedOrders = await mixins.decodeOrdersFromFillData(data).callAsync(); | ||||
|                 const emptyArray: any[] = []; | ||||
|                 expect(emptyArray).to.deep.eq(decodedOrders); | ||||
|             }); | ||||
|         } | ||||
|         it('should decode an empty array for invalid data', async () => { | ||||
|             const data = '0x0123456789'; | ||||
|             const decodedOrders = await mixins.decodeOrdersFromFillData.callAsync(data); | ||||
|             const decodedOrders = await mixins.decodeOrdersFromFillData(data).callAsync(); | ||||
|             const emptyArray: any[] = []; | ||||
|             expect(emptyArray).to.deep.eq(decodedOrders); | ||||
|         }); | ||||
| @@ -208,33 +230,24 @@ describe('Mixins tests', () => { | ||||
|                 new BigNumber(3), // the length of data | ||||
|                 new BigNumber(4), | ||||
|             ); | ||||
|             return expect(mixins.decodeOrdersFromFillData.callAsync(data)).to.revertWith(expectedError); | ||||
|             return expect(mixins.decodeOrdersFromFillData(data).callAsync()).to.revertWith(expectedError); | ||||
|         }); | ||||
|     }); | ||||
|  | ||||
|     describe('Single order approvals', () => { | ||||
|         for (const fnName of exchangeConstants.SINGLE_FILL_FN_NAMES) { | ||||
|             it(`Should be successful: function=${fnName}, caller=tx_signer, senderAddress=[verifier], approval_sig=[approver1], expiration=[valid]`, async () => { | ||||
|         for (const fnName of constants.SINGLE_FILL_FN_NAMES) { | ||||
|             it(`Should be successful: function=${fnName}, caller=tx_signer, senderAddress=[verifier], approval_sig=[approver1]`, async () => { | ||||
|                 const orders = [defaultOrder]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const currentTimestamp = await getLatestBlockTimestampAsync(); | ||||
|                 const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); | ||||
|                 const approval = approvalFactory1.newSignedApproval( | ||||
|                     transaction, | ||||
|                     transactionSignerAddress, | ||||
|                     approvalExpirationTimeSeconds, | ||||
|                 ); | ||||
|                 await mixins.assertValidCoordinatorApprovals.callAsync( | ||||
|                     transaction, | ||||
|                     transactionSignerAddress, | ||||
|                     transaction.signature, | ||||
|                     [approvalExpirationTimeSeconds], | ||||
|                     [approval.signature], | ||||
|                     { from: transactionSignerAddress }, | ||||
|                 ); | ||||
|                 const approval = await approvalFactory1.newSignedApprovalAsync(transaction, transactionSignerAddress); | ||||
|                 await mixins | ||||
|                     .assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, [ | ||||
|                         approval.signature, | ||||
|                     ]) | ||||
|                     .callAsync({ from: transactionSignerAddress }); | ||||
|             }); | ||||
|             it(`Should be successful: function=${fnName}, caller=tx_signer, senderAddress=[null], approval_sig=[approver1], expiration=[valid]`, async () => { | ||||
|             it(`Should be successful: function=${fnName}, caller=tx_signer, senderAddress=[null], approval_sig=[approver1]`, async () => { | ||||
|                 const order = { | ||||
|                     ...defaultOrder, | ||||
|                     senderAddress: constants.NULL_ADDRESS, | ||||
| @@ -242,457 +255,257 @@ describe('Mixins tests', () => { | ||||
|                 const orders = [order]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const currentTimestamp = await getLatestBlockTimestampAsync(); | ||||
|                 const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); | ||||
|                 const approval = approvalFactory1.newSignedApproval( | ||||
|                     transaction, | ||||
|                     transactionSignerAddress, | ||||
|                     approvalExpirationTimeSeconds, | ||||
|                 ); | ||||
|                 await mixins.assertValidCoordinatorApprovals.callAsync( | ||||
|                     transaction, | ||||
|                     transactionSignerAddress, | ||||
|                     transaction.signature, | ||||
|                     [approvalExpirationTimeSeconds], | ||||
|                     [approval.signature], | ||||
|                     { from: transactionSignerAddress }, | ||||
|                 ); | ||||
|                 const approval = await approvalFactory1.newSignedApprovalAsync(transaction, transactionSignerAddress); | ||||
|                 await mixins | ||||
|                     .assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, [ | ||||
|                         approval.signature, | ||||
|                     ]) | ||||
|                     .callAsync({ from: transactionSignerAddress }); | ||||
|             }); | ||||
|             it(`Should be successful: function=${fnName}, caller=approver1, senderAddress=[verifier], approval_sig=[], expiration=[]`, async () => { | ||||
|             it(`Should be successful: function=${fnName}, caller=approver1, senderAddress=[verifier], approval_sig=[]`, async () => { | ||||
|                 const orders = [defaultOrder]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 await mixins.assertValidCoordinatorApprovals.callAsync( | ||||
|                     transaction, | ||||
|                     approvalSignerAddress1, | ||||
|                     transaction.signature, | ||||
|                     [], | ||||
|                     [], | ||||
|                     { | ||||
|                 await mixins | ||||
|                     .assertValidCoordinatorApprovals(transaction, approvalSignerAddress1, transaction.signature, []) | ||||
|                     .callAsync({ | ||||
|                         from: approvalSignerAddress1, | ||||
|                     }, | ||||
|                 ); | ||||
|                     }); | ||||
|             }); | ||||
|             it(`Should be successful: function=${fnName}, caller=approver1, senderAddress=[verifier], approval_sig=[approver1], expiration=[invalid]`, async () => { | ||||
|             it(`Should be successful: function=${fnName}, caller=approver1, senderAddress=[verifier], approval_sig=[approver1]`, async () => { | ||||
|                 const orders = [defaultOrder]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const currentTimestamp = await getLatestBlockTimestampAsync(); | ||||
|                 const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); | ||||
|                 const approval = approvalFactory1.newSignedApproval( | ||||
|                     transaction, | ||||
|                     transactionSignerAddress, | ||||
|                     approvalExpirationTimeSeconds, | ||||
|                 ); | ||||
|                 await mixins.assertValidCoordinatorApprovals.callAsync( | ||||
|                     transaction, | ||||
|                     approvalSignerAddress1, | ||||
|                     transaction.signature, | ||||
|                     [approvalExpirationTimeSeconds], | ||||
|                     [approval.signature], | ||||
|                     { from: approvalSignerAddress1 }, | ||||
|                 ); | ||||
|                 const approval = await approvalFactory1.newSignedApprovalAsync(transaction, transactionSignerAddress); | ||||
|                 await mixins | ||||
|                     .assertValidCoordinatorApprovals(transaction, approvalSignerAddress1, transaction.signature, [ | ||||
|                         approval.signature, | ||||
|                     ]) | ||||
|                     .callAsync({ from: approvalSignerAddress1 }); | ||||
|             }); | ||||
|             it(`Should be successful: function=${fnName}, caller=approver1, senderAddress=[verifier], approval_sig=[], expiration=[]`, async () => { | ||||
|             it(`Should be successful: function=${fnName}, caller=approver1, senderAddress=[verifier], approval_sig=[]`, async () => { | ||||
|                 const orders = [defaultOrder]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 await mixins.assertValidCoordinatorApprovals.callAsync( | ||||
|                     transaction, | ||||
|                     approvalSignerAddress1, | ||||
|                     transaction.signature, | ||||
|                     [], | ||||
|                     [], | ||||
|                     { | ||||
|                 await mixins | ||||
|                     .assertValidCoordinatorApprovals(transaction, approvalSignerAddress1, transaction.signature, []) | ||||
|                     .callAsync({ | ||||
|                         from: approvalSignerAddress1, | ||||
|                     }, | ||||
|                 ); | ||||
|                     }); | ||||
|             }); | ||||
|             it(`Should revert: function=${fnName}, caller=tx_signer, senderAddress=[verifier], approval_sig=[invalid], expiration=[valid]`, async () => { | ||||
|             it(`Should revert: function=${fnName}, caller=tx_signer, senderAddress=[verifier], approval_sig=[invalid]`, async () => { | ||||
|                 const orders = [defaultOrder]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const currentTimestamp = await getLatestBlockTimestampAsync(); | ||||
|                 const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); | ||||
|                 const approval = approvalFactory1.newSignedApproval( | ||||
|                     transaction, | ||||
|                     transactionSignerAddress, | ||||
|                     approvalExpirationTimeSeconds, | ||||
|                 const approval = await approvalFactory1.newSignedApprovalAsync(transaction, transactionSignerAddress); | ||||
|                 const signature = hexConcat( | ||||
|                     hexSlice(approval.signature, 0, 2), | ||||
|                     '0xFFFFFFFF', | ||||
|                     hexSlice(approval.signature, 6), | ||||
|                 ); | ||||
|                 const signature = `${approval.signature.slice(0, 4)}FFFFFFFF${approval.signature.slice(12)}`; | ||||
|                 expectContractCallFailedAsync( | ||||
|                     mixins.assertValidCoordinatorApprovals.callAsync( | ||||
|                         transaction, | ||||
|                         transactionSignerAddress, | ||||
|                         transaction.signature, | ||||
|                         [approvalExpirationTimeSeconds], | ||||
|                         [signature], | ||||
|                         { from: transactionSignerAddress }, | ||||
|                     ), | ||||
|                     RevertReason.InvalidApprovalSignature, | ||||
|                 const tx = mixins | ||||
|                     .assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, [ | ||||
|                         signature, | ||||
|                     ]) | ||||
|                     .callAsync({ from: transactionSignerAddress }); | ||||
|  | ||||
|                 const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); | ||||
|                 expect(tx).to.revertWith( | ||||
|                     new CoordinatorRevertErrors.InvalidApprovalSignatureError(transactionHash, approvalSignerAddress1), | ||||
|                 ); | ||||
|             }); | ||||
|             it(`Should revert: function=${fnName}, caller=tx_signer, senderAddress=[verifier], approval_sig=[approver1], expiration=[invalid]`, async () => { | ||||
|             it(`Should revert: function=${fnName}, caller=approver2, senderAddress=[verifier], approval_sig=[approver1]`, async () => { | ||||
|                 const orders = [defaultOrder]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const currentTimestamp = await getLatestBlockTimestampAsync(); | ||||
|                 const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).minus(constants.TIME_BUFFER); | ||||
|                 const approval = approvalFactory1.newSignedApproval( | ||||
|                     transaction, | ||||
|                     transactionSignerAddress, | ||||
|                     approvalExpirationTimeSeconds, | ||||
|                 ); | ||||
|                 expectContractCallFailedAsync( | ||||
|                     mixins.assertValidCoordinatorApprovals.callAsync( | ||||
|                         transaction, | ||||
|                         transactionSignerAddress, | ||||
|                         transaction.signature, | ||||
|                         [approvalExpirationTimeSeconds], | ||||
|                         [approval.signature], | ||||
|                         { from: transactionSignerAddress }, | ||||
|                     ), | ||||
|                     RevertReason.ApprovalExpired, | ||||
|                 ); | ||||
|             }); | ||||
|             it(`Should revert: function=${fnName}, caller=approver2, senderAddress=[verifier], approval_sig=[approver1], expiration=[valid]`, async () => { | ||||
|                 const orders = [defaultOrder]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const currentTimestamp = await getLatestBlockTimestampAsync(); | ||||
|                 const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); | ||||
|                 const approval = approvalFactory1.newSignedApproval( | ||||
|                     transaction, | ||||
|                     transactionSignerAddress, | ||||
|                     approvalExpirationTimeSeconds, | ||||
|                 ); | ||||
|                 expectContractCallFailedAsync( | ||||
|                     mixins.assertValidCoordinatorApprovals.callAsync( | ||||
|                         transaction, | ||||
|                         transactionSignerAddress, | ||||
|                         transaction.signature, | ||||
|                         [approvalExpirationTimeSeconds], | ||||
|                         [approval.signature], | ||||
|                         { from: approvalSignerAddress2 }, | ||||
|                     ), | ||||
|                     RevertReason.InvalidOrigin, | ||||
|                 ); | ||||
|                 const approval = await approvalFactory1.newSignedApprovalAsync(transaction, transactionSignerAddress); | ||||
|  | ||||
|                 const tx = mixins | ||||
|                     .assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, [ | ||||
|                         approval.signature, | ||||
|                     ]) | ||||
|                     .callAsync({ from: approvalSignerAddress2 }); | ||||
|                 expect(tx).to.revertWith(new CoordinatorRevertErrors.InvalidOriginError(transactionSignerAddress)); | ||||
|             }); | ||||
|         } | ||||
|     }); | ||||
|     describe('Batch order approvals', () => { | ||||
|         for (const fnName of [ | ||||
|             ...exchangeConstants.BATCH_FILL_FN_NAMES, | ||||
|             ...exchangeConstants.MARKET_FILL_FN_NAMES, | ||||
|             ExchangeFunctionName.MatchOrders, | ||||
|             ...constants.BATCH_FILL_FN_NAMES, | ||||
|             ...constants.MARKET_FILL_FN_NAMES, | ||||
|             ...constants.MATCH_ORDER_FN_NAMES, | ||||
|         ]) { | ||||
|             it(`Should be successful: function=${fnName} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1,approver1], approval_sig=[approver1], expiration=[valid]`, async () => { | ||||
|             it(`Should be successful: function=${fnName} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1,approver1], approval_sig=[approver1]`, async () => { | ||||
|                 const orders = [defaultOrder, defaultOrder]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const currentTimestamp = await getLatestBlockTimestampAsync(); | ||||
|                 const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); | ||||
|                 const approval = approvalFactory1.newSignedApproval( | ||||
|                     transaction, | ||||
|                     transactionSignerAddress, | ||||
|                     approvalExpirationTimeSeconds, | ||||
|                 ); | ||||
|                 await mixins.assertValidCoordinatorApprovals.callAsync( | ||||
|                     transaction, | ||||
|                     transactionSignerAddress, | ||||
|                     transaction.signature, | ||||
|                     [approvalExpirationTimeSeconds], | ||||
|                     [approval.signature], | ||||
|                     { from: transactionSignerAddress }, | ||||
|                 ); | ||||
|                 const approval = await approvalFactory1.newSignedApprovalAsync(transaction, transactionSignerAddress); | ||||
|                 await mixins | ||||
|                     .assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, [ | ||||
|                         approval.signature, | ||||
|                     ]) | ||||
|                     .callAsync({ from: transactionSignerAddress }); | ||||
|             }); | ||||
|             it(`Should be successful: function=${fnName} caller=tx_signer, senderAddress=[null,null], feeRecipient=[approver1,approver1], approval_sig=[approver1], expiration=[valid]`, async () => { | ||||
|             it(`Should be successful: function=${fnName} caller=tx_signer, senderAddress=[null,null], feeRecipient=[approver1,approver1], approval_sig=[approver1]`, async () => { | ||||
|                 const orders = [defaultOrder, defaultOrder].map(order => ({ | ||||
|                     ...order, | ||||
|                     senderAddress: constants.NULL_ADDRESS, | ||||
|                 })); | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const currentTimestamp = await getLatestBlockTimestampAsync(); | ||||
|                 const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); | ||||
|                 const approval = approvalFactory1.newSignedApproval( | ||||
|                     transaction, | ||||
|                     transactionSignerAddress, | ||||
|                     approvalExpirationTimeSeconds, | ||||
|                 ); | ||||
|                 await mixins.assertValidCoordinatorApprovals.callAsync( | ||||
|                     transaction, | ||||
|                     transactionSignerAddress, | ||||
|                     transaction.signature, | ||||
|                     [approvalExpirationTimeSeconds], | ||||
|                     [approval.signature], | ||||
|                     { from: transactionSignerAddress }, | ||||
|                 ); | ||||
|                 const approval = await approvalFactory1.newSignedApprovalAsync(transaction, transactionSignerAddress); | ||||
|                 await mixins | ||||
|                     .assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, [ | ||||
|                         approval.signature, | ||||
|                     ]) | ||||
|                     .callAsync({ from: transactionSignerAddress }); | ||||
|             }); | ||||
|             it(`Should be successful: function=${fnName} caller=tx_signer, senderAddress=[null,null], feeRecipient=[approver1,approver1], approval_sig=[], expiration=[]`, async () => { | ||||
|             it(`Should be successful: function=${fnName} caller=tx_signer, senderAddress=[null,null], feeRecipient=[approver1,approver1], approval_sig=[]`, async () => { | ||||
|                 const orders = [defaultOrder, defaultOrder].map(order => ({ | ||||
|                     ...order, | ||||
|                     senderAddress: constants.NULL_ADDRESS, | ||||
|                 })); | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 await mixins.assertValidCoordinatorApprovals.callAsync( | ||||
|                     transaction, | ||||
|                     transactionSignerAddress, | ||||
|                     transaction.signature, | ||||
|                     [], | ||||
|                     [], | ||||
|                     { from: transactionSignerAddress }, | ||||
|                 ); | ||||
|                 await mixins | ||||
|                     .assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, []) | ||||
|                     .callAsync({ from: transactionSignerAddress }); | ||||
|             }); | ||||
|             it(`Should be successful: function=${fnName} caller=tx_signer, senderAddress=[verifier,null], feeRecipient=[approver1,approver1], approval_sig=[approver1], expiration=[valid]`, async () => { | ||||
|             it(`Should be successful: function=${fnName} caller=tx_signer, senderAddress=[verifier,null], feeRecipient=[approver1,approver1], approval_sig=[approver1]`, async () => { | ||||
|                 const orders = [defaultOrder, { ...defaultOrder, senderAddress: constants.NULL_ADDRESS }]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const currentTimestamp = await getLatestBlockTimestampAsync(); | ||||
|                 const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); | ||||
|                 const approval = approvalFactory1.newSignedApproval( | ||||
|                     transaction, | ||||
|                     transactionSignerAddress, | ||||
|                     approvalExpirationTimeSeconds, | ||||
|                 ); | ||||
|                 await mixins.assertValidCoordinatorApprovals.callAsync( | ||||
|                     transaction, | ||||
|                     transactionSignerAddress, | ||||
|                     transaction.signature, | ||||
|                     [approvalExpirationTimeSeconds], | ||||
|                     [approval.signature], | ||||
|                     { from: transactionSignerAddress }, | ||||
|                 ); | ||||
|                 const approval = await approvalFactory1.newSignedApprovalAsync(transaction, transactionSignerAddress); | ||||
|                 await mixins | ||||
|                     .assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, [ | ||||
|                         approval.signature, | ||||
|                     ]) | ||||
|                     .callAsync({ from: transactionSignerAddress }); | ||||
|             }); | ||||
|             it(`Should be successful: function=${fnName} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1,approver2], approval_sig=[approver1,approver2], expiration=[valid,valid]`, async () => { | ||||
|             it(`Should be successful: function=${fnName} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1,approver2], approval_sig=[approver1,approver2]`, async () => { | ||||
|                 const orders = [defaultOrder, { ...defaultOrder, feeRecipientAddress: approvalSignerAddress2 }]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const currentTimestamp = await getLatestBlockTimestampAsync(); | ||||
|                 const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); | ||||
|                 const approval1 = approvalFactory1.newSignedApproval( | ||||
|                     transaction, | ||||
|                     transactionSignerAddress, | ||||
|                     approvalExpirationTimeSeconds, | ||||
|                 ); | ||||
|                 const approval2 = approvalFactory2.newSignedApproval( | ||||
|                     transaction, | ||||
|                     transactionSignerAddress, | ||||
|                     approvalExpirationTimeSeconds, | ||||
|                 ); | ||||
|                 await mixins.assertValidCoordinatorApprovals.callAsync( | ||||
|                     transaction, | ||||
|                     transactionSignerAddress, | ||||
|                     transaction.signature, | ||||
|                     [approvalExpirationTimeSeconds, approvalExpirationTimeSeconds], | ||||
|                     [approval1.signature, approval2.signature], | ||||
|                     { from: transactionSignerAddress }, | ||||
|                 ); | ||||
|                 const approval1 = await approvalFactory1.newSignedApprovalAsync(transaction, transactionSignerAddress); | ||||
|                 const approval2 = await approvalFactory2.newSignedApprovalAsync(transaction, transactionSignerAddress); | ||||
|                 await mixins | ||||
|                     .assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, [ | ||||
|                         approval1.signature, | ||||
|                         approval2.signature, | ||||
|                     ]) | ||||
|                     .callAsync({ from: transactionSignerAddress }); | ||||
|             }); | ||||
|             it(`Should be successful: function=${fnName} caller=approver1, senderAddress=[verifier,verifier], feeRecipient=[approver1,approver1], approval_sig=[], expiration=[]`, async () => { | ||||
|             it(`Should be successful: function=${fnName} caller=approver1, senderAddress=[verifier,verifier], feeRecipient=[approver1,approver1], approval_sig=[]`, async () => { | ||||
|                 const orders = [defaultOrder, defaultOrder]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 await mixins.assertValidCoordinatorApprovals.callAsync( | ||||
|                     transaction, | ||||
|                     approvalSignerAddress1, | ||||
|                     transaction.signature, | ||||
|                     [], | ||||
|                     [], | ||||
|                     { from: approvalSignerAddress1 }, | ||||
|                 ); | ||||
|                 await mixins | ||||
|                     .assertValidCoordinatorApprovals(transaction, approvalSignerAddress1, transaction.signature, []) | ||||
|                     .callAsync({ from: approvalSignerAddress1 }); | ||||
|             }); | ||||
|             it(`Should revert: function=${fnName} caller=approver1, senderAddress=[verifier,verifier], feeRecipient=[approver1,approver2], approval_sig=[approver2], expiration=[valid]`, async () => { | ||||
|             it(`Should revert: function=${fnName} caller=approver1, senderAddress=[verifier,verifier], feeRecipient=[approver1,approver2], approval_sig=[approver2]`, async () => { | ||||
|                 const orders = [defaultOrder, { ...defaultOrder, feeRecipientAddress: approvalSignerAddress2 }]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const currentTimestamp = await getLatestBlockTimestampAsync(); | ||||
|                 const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); | ||||
|                 const approval2 = approvalFactory2.newSignedApproval( | ||||
|                     transaction, | ||||
|                     transactionSignerAddress, | ||||
|                     approvalExpirationTimeSeconds, | ||||
|                 ); | ||||
|                 expectContractCallFailedAsync( | ||||
|                     mixins.assertValidCoordinatorApprovals.callAsync( | ||||
|                         transaction, | ||||
|                         transactionSignerAddress, | ||||
|                         transaction.signature, | ||||
|                         [approvalExpirationTimeSeconds], | ||||
|                         [approval2.signature], | ||||
|                         { from: approvalSignerAddress1 }, | ||||
|                     ), | ||||
|                     RevertReason.InvalidOrigin, | ||||
|                 ); | ||||
|                 const approval2 = await approvalFactory2.newSignedApprovalAsync(transaction, transactionSignerAddress); | ||||
|  | ||||
|                 const tx = mixins | ||||
|                     .assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, [ | ||||
|                         approval2.signature, | ||||
|                     ]) | ||||
|                     .callAsync({ from: approvalSignerAddress1 }); | ||||
|                 expect(tx).to.revertWith(new CoordinatorRevertErrors.InvalidOriginError(transactionSignerAddress)); | ||||
|             }); | ||||
|             it(`Should revert: function=${fnName} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver1], approval_sig=[], expiration=[]`, async () => { | ||||
|             it(`Should revert: function=${fnName} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver1], approval_sig=[]`, async () => { | ||||
|                 const orders = [defaultOrder, defaultOrder]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 expectContractCallFailedAsync( | ||||
|                     mixins.assertValidCoordinatorApprovals.callAsync( | ||||
|                         transaction, | ||||
|                         transactionSignerAddress, | ||||
|                         transaction.signature, | ||||
|                         [], | ||||
|                         [], | ||||
|                         { from: transactionSignerAddress }, | ||||
|                     ), | ||||
|                     RevertReason.InvalidApprovalSignature, | ||||
|                 const tx = mixins | ||||
|                     .assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, []) | ||||
|                     .callAsync({ from: transactionSignerAddress }); | ||||
|  | ||||
|                 const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); | ||||
|                 expect(tx).to.revertWith( | ||||
|                     new CoordinatorRevertErrors.InvalidApprovalSignatureError(transactionHash, approvalSignerAddress1), | ||||
|                 ); | ||||
|             }); | ||||
|             it(`Should revert: function=${fnName} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver1], approval_sig=[invalid], expiration=[valid]`, async () => { | ||||
|             it(`Should revert: function=${fnName} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver1], approval_sig=[invalid]`, async () => { | ||||
|                 const orders = [defaultOrder, defaultOrder]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const currentTimestamp = await getLatestBlockTimestampAsync(); | ||||
|                 const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); | ||||
|                 const approval = approvalFactory1.newSignedApproval( | ||||
|                     transaction, | ||||
|                     transactionSignerAddress, | ||||
|                     approvalExpirationTimeSeconds, | ||||
|                 const approval = await approvalFactory1.newSignedApprovalAsync(transaction, transactionSignerAddress); | ||||
|                 const signature = hexConcat( | ||||
|                     hexSlice(approval.signature, 0, 2), | ||||
|                     '0xFFFFFFFF', | ||||
|                     hexSlice(approval.signature, 6), | ||||
|                 ); | ||||
|                 const signature = `${approval.signature.slice(0, 4)}FFFFFFFF${approval.signature.slice(12)}`; | ||||
|                 expectContractCallFailedAsync( | ||||
|                     mixins.assertValidCoordinatorApprovals.callAsync( | ||||
|                         transaction, | ||||
|                         transactionSignerAddress, | ||||
|                         transaction.signature, | ||||
|                         [approvalExpirationTimeSeconds], | ||||
|                         [signature], | ||||
|                         { from: transactionSignerAddress }, | ||||
|                     ), | ||||
|                     RevertReason.InvalidApprovalSignature, | ||||
|                 const tx = mixins | ||||
|                     .assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, [ | ||||
|                         signature, | ||||
|                     ]) | ||||
|                     .callAsync({ from: transactionSignerAddress }); | ||||
|  | ||||
|                 const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); | ||||
|                 expect(tx).to.revertWith( | ||||
|                     new CoordinatorRevertErrors.InvalidApprovalSignatureError(transactionHash, approvalSignerAddress1), | ||||
|                 ); | ||||
|             }); | ||||
|             it(`Should revert: function=${fnName} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver2], approval_sig=[valid,invalid], expiration=[valid,valid]`, async () => { | ||||
|             it(`Should revert: function=${fnName} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver2], approval_sig=[valid,invalid]`, async () => { | ||||
|                 const orders = [defaultOrder, { ...defaultOrder, feeRecipientAddress: approvalSignerAddress2 }]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const currentTimestamp = await getLatestBlockTimestampAsync(); | ||||
|                 const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); | ||||
|                 const approval1 = approvalFactory1.newSignedApproval( | ||||
|                     transaction, | ||||
|                     transactionSignerAddress, | ||||
|                     approvalExpirationTimeSeconds, | ||||
|                 const approval1 = await approvalFactory1.newSignedApprovalAsync(transaction, transactionSignerAddress); | ||||
|                 const approval2 = await approvalFactory2.newSignedApprovalAsync(transaction, transactionSignerAddress); | ||||
|                 const approvalSignature2 = hexConcat( | ||||
|                     hexSlice(approval2.signature, 0, 2), | ||||
|                     '0xFFFFFFFF', | ||||
|                     hexSlice(approval2.signature, 6), | ||||
|                 ); | ||||
|                 const approval2 = approvalFactory2.newSignedApproval( | ||||
|                     transaction, | ||||
|                     transactionSignerAddress, | ||||
|                     approvalExpirationTimeSeconds, | ||||
|                 ); | ||||
|                 const approvalSignature2 = `${approval2.signature.slice(0, 4)}FFFFFFFF${approval2.signature.slice(12)}`; | ||||
|                 expectContractCallFailedAsync( | ||||
|                     mixins.assertValidCoordinatorApprovals.callAsync( | ||||
|                         transaction, | ||||
|                         transactionSignerAddress, | ||||
|                         transaction.signature, | ||||
|                         [approvalExpirationTimeSeconds, approvalExpirationTimeSeconds], | ||||
|                         [approval1.signature, approvalSignature2], | ||||
|                         { from: transactionSignerAddress }, | ||||
|                     ), | ||||
|                     RevertReason.InvalidApprovalSignature, | ||||
|                 const tx = mixins | ||||
|                     .assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, [ | ||||
|                         approval1.signature, | ||||
|                         approvalSignature2, | ||||
|                     ]) | ||||
|                     .callAsync({ from: transactionSignerAddress }); | ||||
|  | ||||
|                 const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); | ||||
|                 expect(tx).to.revertWith( | ||||
|                     new CoordinatorRevertErrors.InvalidApprovalSignatureError(transactionHash, approvalSignerAddress2), | ||||
|                 ); | ||||
|             }); | ||||
|             it(`Should revert: function=${fnName} caller=approver1, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver2], approval_sig=[invalid], expiration=[valid]`, async () => { | ||||
|             it(`Should revert: function=${fnName} caller=approver1, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver2], approval_sig=[invalid]`, async () => { | ||||
|                 const orders = [defaultOrder, { ...defaultOrder, feeRecipientAddress: approvalSignerAddress2 }]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const currentTimestamp = await getLatestBlockTimestampAsync(); | ||||
|                 const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); | ||||
|                 const approval2 = approvalFactory2.newSignedApproval( | ||||
|                     transaction, | ||||
|                     transactionSignerAddress, | ||||
|                     approvalExpirationTimeSeconds, | ||||
|                 const approval2 = await approvalFactory2.newSignedApprovalAsync(transaction, transactionSignerAddress); | ||||
|                 const approvalSignature2 = hexConcat( | ||||
|                     hexSlice(approval2.signature, 0, 2), | ||||
|                     '0xFFFFFFFF', | ||||
|                     hexSlice(approval2.signature, 6), | ||||
|                 ); | ||||
|                 const approvalSignature2 = `${approval2.signature.slice(0, 4)}FFFFFFFF${approval2.signature.slice(12)}`; | ||||
|                 expectContractCallFailedAsync( | ||||
|                     mixins.assertValidCoordinatorApprovals.callAsync( | ||||
|                         transaction, | ||||
|                         approvalSignerAddress1, | ||||
|                         transaction.signature, | ||||
|                         [approvalExpirationTimeSeconds], | ||||
|                         [approvalSignature2], | ||||
|                         { from: approvalSignerAddress1 }, | ||||
|                     ), | ||||
|                     RevertReason.InvalidApprovalSignature, | ||||
|                 const tx = mixins | ||||
|                     .assertValidCoordinatorApprovals(transaction, approvalSignerAddress1, transaction.signature, [ | ||||
|                         approvalSignature2, | ||||
|                     ]) | ||||
|                     .callAsync({ from: approvalSignerAddress1 }); | ||||
|  | ||||
|                 const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); | ||||
|                 expect(tx).to.revertWith( | ||||
|                     new CoordinatorRevertErrors.InvalidApprovalSignatureError(transactionHash, approvalSignerAddress2), | ||||
|                 ); | ||||
|             }); | ||||
|             it(`Should revert: function=${fnName} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver2], approval_sig=[valid,valid], expiration=[valid,invalid]`, async () => { | ||||
|                 const orders = [defaultOrder, { ...defaultOrder, feeRecipientAddress: approvalSignerAddress2 }]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const currentTimestamp = await getLatestBlockTimestampAsync(); | ||||
|                 const approvalExpirationTimeSeconds1 = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); | ||||
|                 const approvalExpirationTimeSeconds2 = new BigNumber(currentTimestamp).minus(constants.TIME_BUFFER); | ||||
|                 const approval1 = approvalFactory1.newSignedApproval( | ||||
|                     transaction, | ||||
|                     transactionSignerAddress, | ||||
|                     approvalExpirationTimeSeconds1, | ||||
|                 ); | ||||
|                 const approval2 = approvalFactory2.newSignedApproval( | ||||
|                     transaction, | ||||
|                     transactionSignerAddress, | ||||
|                     approvalExpirationTimeSeconds2, | ||||
|                 ); | ||||
|                 expectContractCallFailedAsync( | ||||
|                     mixins.assertValidCoordinatorApprovals.callAsync( | ||||
|                         transaction, | ||||
|                         transactionSignerAddress, | ||||
|                         transaction.signature, | ||||
|                         [approvalExpirationTimeSeconds1, approvalExpirationTimeSeconds2], | ||||
|                         [approval1.signature, approval2.signature], | ||||
|                         { from: transactionSignerAddress }, | ||||
|                     ), | ||||
|                     RevertReason.ApprovalExpired, | ||||
|                 ); | ||||
|             }); | ||||
|             it(`Should revert: function=${fnName} caller=approver1, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver2], approval_sig=[valid], expiration=[invalid]`, async () => { | ||||
|                 const orders = [defaultOrder, { ...defaultOrder, feeRecipientAddress: approvalSignerAddress2 }]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const currentTimestamp = await getLatestBlockTimestampAsync(); | ||||
|                 const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).minus(constants.TIME_BUFFER); | ||||
|                 const approval2 = approvalFactory2.newSignedApproval( | ||||
|                     transaction, | ||||
|                     transactionSignerAddress, | ||||
|                     approvalExpirationTimeSeconds, | ||||
|                 ); | ||||
|                 expectContractCallFailedAsync( | ||||
|                     mixins.assertValidCoordinatorApprovals.callAsync( | ||||
|                         transaction, | ||||
|                         approvalSignerAddress1, | ||||
|                         transaction.signature, | ||||
|                         [approvalExpirationTimeSeconds], | ||||
|                         [approval2.signature], | ||||
|                         { from: approvalSignerAddress1 }, | ||||
|                     ), | ||||
|                     RevertReason.ApprovalExpired, | ||||
|                 ); | ||||
|             }); | ||||
|             it(`Should revert: function=${fnName} caller=approver2, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver1], approval_sig=[valid], expiration=[valid]`, async () => { | ||||
|             it(`Should revert: function=${fnName} caller=approver2, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver1], approval_sig=[valid]`, async () => { | ||||
|                 const orders = [defaultOrder, defaultOrder]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const currentTimestamp = await getLatestBlockTimestampAsync(); | ||||
|                 const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); | ||||
|                 const approval1 = approvalFactory1.newSignedApproval( | ||||
|                     transaction, | ||||
|                     transactionSignerAddress, | ||||
|                     approvalExpirationTimeSeconds, | ||||
|                 ); | ||||
|                 expectContractCallFailedAsync( | ||||
|                     mixins.assertValidCoordinatorApprovals.callAsync( | ||||
|                         transaction, | ||||
|                         transactionSignerAddress, | ||||
|                         transaction.signature, | ||||
|                         [approvalExpirationTimeSeconds], | ||||
|                         [approval1.signature], | ||||
|                         { from: approvalSignerAddress2 }, | ||||
|                     ), | ||||
|                     RevertReason.InvalidOrigin, | ||||
|                 ); | ||||
|                 const approval1 = await approvalFactory1.newSignedApprovalAsync(transaction, transactionSignerAddress); | ||||
|  | ||||
|                 const tx = mixins | ||||
|                     .assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, [ | ||||
|                         approval1.signature, | ||||
|                     ]) | ||||
|                     .callAsync({ from: approvalSignerAddress2 }); | ||||
|                 expect(tx).to.revertWith(new CoordinatorRevertErrors.InvalidOriginError(transactionSignerAddress)); | ||||
|             }); | ||||
|         } | ||||
|     }); | ||||
| @@ -701,39 +514,24 @@ describe('Mixins tests', () => { | ||||
|             const orders = [defaultOrder]; | ||||
|             const data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.CancelOrder, orders); | ||||
|             const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|             await mixins.assertValidCoordinatorApprovals.callAsync( | ||||
|                 transaction, | ||||
|                 transactionSignerAddress, | ||||
|                 transaction.signature, | ||||
|                 [], | ||||
|                 [], | ||||
|                 { from: transactionSignerAddress }, | ||||
|             ); | ||||
|             await mixins | ||||
|                 .assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, []) | ||||
|                 .callAsync({ from: transactionSignerAddress }); | ||||
|         }); | ||||
|         it('should allow the tx signer to call `batchCancelOrders` without approval', async () => { | ||||
|             const orders = [defaultOrder, defaultOrder]; | ||||
|             const data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.BatchCancelOrders, orders); | ||||
|             const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|             await mixins.assertValidCoordinatorApprovals.callAsync( | ||||
|                 transaction, | ||||
|                 transactionSignerAddress, | ||||
|                 transaction.signature, | ||||
|                 [], | ||||
|                 [], | ||||
|                 { from: transactionSignerAddress }, | ||||
|             ); | ||||
|             await mixins | ||||
|                 .assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, []) | ||||
|                 .callAsync({ from: transactionSignerAddress }); | ||||
|         }); | ||||
|         it('should allow the tx signer to call `cancelOrdersUpTo` without approval', async () => { | ||||
|             const data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.CancelOrdersUpTo); | ||||
|             const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|             await mixins.assertValidCoordinatorApprovals.callAsync( | ||||
|                 transaction, | ||||
|                 transactionSignerAddress, | ||||
|                 transaction.signature, | ||||
|                 [], | ||||
|                 [], | ||||
|                 { from: transactionSignerAddress }, | ||||
|             ); | ||||
|             await mixins | ||||
|                 .assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, []) | ||||
|                 .callAsync({ from: transactionSignerAddress }); | ||||
|         }); | ||||
|     }); | ||||
| }); | ||||
|   | ||||
| @@ -1,65 +0,0 @@ | ||||
| import { LogDecoder, txDefaults } from '@0x/contracts-test-utils'; | ||||
| import { Web3Wrapper } from '@0x/web3-wrapper'; | ||||
| import { TransactionReceiptWithDecodedLogs, ZeroExProvider } from 'ethereum-types'; | ||||
|  | ||||
| import { artifacts, CoordinatorRegistryContract } from '../../src'; | ||||
|  | ||||
| export class CoordinatorRegistryWrapper { | ||||
|     private readonly _web3Wrapper: Web3Wrapper; | ||||
|     private readonly _provider: ZeroExProvider; | ||||
|     private readonly _logDecoder: LogDecoder; | ||||
|     private _coordinatorRegistryContract?: CoordinatorRegistryContract; | ||||
|     /** | ||||
|      * Instanitates an CoordinatorRegistryWrapper | ||||
|      * @param provider Web3 provider to use for all JSON RPC requests | ||||
|      * Instance of CoordinatorRegistryWrapper | ||||
|      */ | ||||
|     constructor(provider: ZeroExProvider) { | ||||
|         this._web3Wrapper = new Web3Wrapper(provider); | ||||
|         this._provider = provider; | ||||
|         this._logDecoder = new LogDecoder(this._web3Wrapper, artifacts); | ||||
|     } | ||||
|     public async deployCoordinatorRegistryAsync(): Promise<CoordinatorRegistryContract> { | ||||
|         this._coordinatorRegistryContract = await CoordinatorRegistryContract.deployFrom0xArtifactAsync( | ||||
|             artifacts.CoordinatorRegistry, | ||||
|             this._provider, | ||||
|             txDefaults, | ||||
|             artifacts, | ||||
|         ); | ||||
|         if (this._coordinatorRegistryContract === undefined) { | ||||
|             throw new Error(`Failed to deploy Coordinator Registry contract.`); | ||||
|         } | ||||
|         return this._coordinatorRegistryContract; | ||||
|     } | ||||
|     public async setCoordinatorEndpointAsync( | ||||
|         coordinatorOperator: string, | ||||
|         coordinatorEndpoint: string, | ||||
|     ): Promise<TransactionReceiptWithDecodedLogs> { | ||||
|         this._assertCoordinatorRegistryDeployed(); | ||||
|         const txReceipt = await this._logDecoder.getTxWithDecodedLogsAsync( | ||||
|             await (this | ||||
|                 ._coordinatorRegistryContract as CoordinatorRegistryContract).setCoordinatorEndpoint.sendTransactionAsync( | ||||
|                 coordinatorEndpoint, | ||||
|                 { | ||||
|                     from: coordinatorOperator, | ||||
|                 }, | ||||
|             ), | ||||
|         ); | ||||
|         return txReceipt; | ||||
|     } | ||||
|     public async getCoordinatorEndpointAsync(coordinatorOperator: string): Promise<string> { | ||||
|         this._assertCoordinatorRegistryDeployed(); | ||||
|         const coordinatorEndpoint = await (this | ||||
|             ._coordinatorRegistryContract as CoordinatorRegistryContract).getCoordinatorEndpoint.callAsync( | ||||
|             coordinatorOperator, | ||||
|         ); | ||||
|         return coordinatorEndpoint; | ||||
|     } | ||||
|     private _assertCoordinatorRegistryDeployed(): void { | ||||
|         if (this._coordinatorRegistryContract === undefined) { | ||||
|             throw new Error( | ||||
|                 'The Coordinator Registry contract was not deployed through the CoordinatorRegistryWrapper. Call `deployCoordinatorRegistryAsync` to deploy.', | ||||
|             ); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,3 +0,0 @@ | ||||
| export { hashUtils } from './hash_utils'; | ||||
| export { ApprovalFactory } from './approval_factory'; | ||||
| export * from './types'; | ||||
							
								
								
									
										19
									
								
								contracts/coordinator/test/wrappers.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								contracts/coordinator/test/wrappers.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| /* | ||||
|  * ----------------------------------------------------------------------------- | ||||
|  * Warning: This file is auto-generated by contracts-gen. Don't edit manually. | ||||
|  * ----------------------------------------------------------------------------- | ||||
|  */ | ||||
| export * from '../test/generated-wrappers/coordinator'; | ||||
| export * from '../test/generated-wrappers/coordinator_registry'; | ||||
| export * from '../test/generated-wrappers/i_coordinator_approval_verifier'; | ||||
| export * from '../test/generated-wrappers/i_coordinator_core'; | ||||
| export * from '../test/generated-wrappers/i_coordinator_registry_core'; | ||||
| export * from '../test/generated-wrappers/i_coordinator_signature_validator'; | ||||
| export * from '../test/generated-wrappers/lib_constants'; | ||||
| export * from '../test/generated-wrappers/lib_coordinator_approval'; | ||||
| export * from '../test/generated-wrappers/lib_coordinator_rich_errors'; | ||||
| export * from '../test/generated-wrappers/lib_e_i_p712_coordinator_domain'; | ||||
| export * from '../test/generated-wrappers/mixin_coordinator_approval_verifier'; | ||||
| export * from '../test/generated-wrappers/mixin_coordinator_core'; | ||||
| export * from '../test/generated-wrappers/mixin_coordinator_registry_core'; | ||||
| export * from '../test/generated-wrappers/mixin_signature_validator'; | ||||
| @@ -2,6 +2,27 @@ | ||||
|     "extends": "../../tsconfig", | ||||
|     "compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true }, | ||||
|     "include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"], | ||||
|     "files": ["generated-artifacts/Coordinator.json", "generated-artifacts/CoordinatorRegistry.json"], | ||||
|     "files": [ | ||||
|         "generated-artifacts/Coordinator.json", | ||||
|         "generated-artifacts/CoordinatorRegistry.json", | ||||
|         "generated-artifacts/LibConstants.json", | ||||
|         "generated-artifacts/LibCoordinatorApproval.json", | ||||
|         "generated-artifacts/LibCoordinatorRichErrors.json", | ||||
|         "generated-artifacts/LibEIP712CoordinatorDomain.json", | ||||
|         "test/generated-artifacts/Coordinator.json", | ||||
|         "test/generated-artifacts/CoordinatorRegistry.json", | ||||
|         "test/generated-artifacts/ICoordinatorApprovalVerifier.json", | ||||
|         "test/generated-artifacts/ICoordinatorCore.json", | ||||
|         "test/generated-artifacts/ICoordinatorRegistryCore.json", | ||||
|         "test/generated-artifacts/ICoordinatorSignatureValidator.json", | ||||
|         "test/generated-artifacts/LibConstants.json", | ||||
|         "test/generated-artifacts/LibCoordinatorApproval.json", | ||||
|         "test/generated-artifacts/LibCoordinatorRichErrors.json", | ||||
|         "test/generated-artifacts/LibEIP712CoordinatorDomain.json", | ||||
|         "test/generated-artifacts/MixinCoordinatorApprovalVerifier.json", | ||||
|         "test/generated-artifacts/MixinCoordinatorCore.json", | ||||
|         "test/generated-artifacts/MixinCoordinatorRegistryCore.json", | ||||
|         "test/generated-artifacts/MixinSignatureValidator.json" | ||||
|     ], | ||||
|     "exclude": ["./deploy/solc/solc_bin"] | ||||
| } | ||||
|   | ||||
							
								
								
									
										10
									
								
								contracts/dev-utils/.npmignore
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								contracts/dev-utils/.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 | ||||
| @@ -1,4 +1,36 @@ | ||||
| [ | ||||
|     { | ||||
|         "version": "0.1.0-beta.2", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils", | ||||
|                 "pr": 2330 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Add new method getOrderHash() to DevUtils contract", | ||||
|                 "pr": 2321 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Add new method getTransactionHash() to DevUtils contract", | ||||
|                 "pr": 2321 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1574030254 | ||||
|     }, | ||||
|     { | ||||
|         "version": "0.1.0-beta.1", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Add `encodeStaticCallAssetData` and `decodeStaticCallAssetData` in LibAssetData", | ||||
|                 "pr": 2034 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Add `revertIfInvalidAssetData` in LibAssetData", | ||||
|                 "pr": 2034 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1573159180 | ||||
|     }, | ||||
|     { | ||||
|         "version": "0.1.0-beta.0", | ||||
|         "changes": [ | ||||
|   | ||||
| @@ -5,6 +5,17 @@ Edit the package's CHANGELOG.json file only. | ||||
|  | ||||
| CHANGELOG | ||||
|  | ||||
| ## v0.1.0-beta.2 - _November 17, 2019_ | ||||
|  | ||||
|     * Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils (#2330) | ||||
|     * Add new method getOrderHash() to DevUtils contract (#2321) | ||||
|     * Add new method getTransactionHash() to DevUtils contract (#2321) | ||||
|  | ||||
| ## v0.1.0-beta.1 - _November 7, 2019_ | ||||
|  | ||||
|     * Add `encodeStaticCallAssetData` and `decodeStaticCallAssetData` in LibAssetData (#2034) | ||||
|     * Add `revertIfInvalidAssetData` in LibAssetData (#2034) | ||||
|  | ||||
| ## v0.1.0-beta.0 - _October 3, 2019_ | ||||
|  | ||||
|     * Use built in selectors instead of hard coded constants (#2055) | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| { | ||||
|     "artifactsDir": "./generated-artifacts", | ||||
|     "artifactsDir": "./test/generated-artifacts", | ||||
|     "contractsDir": "./contracts", | ||||
|     "useDockerisedSolc": false, | ||||
|     "isOfflineMode": false, | ||||
| @@ -7,7 +7,7 @@ | ||||
|         "evmVersion": "constantinople", | ||||
|         "optimizer": { | ||||
|             "enabled": true, | ||||
|             "runs": 10000, | ||||
|             "runs": 1666, | ||||
|             "details": { "yul": true, "deduplicate": true, "cse": true, "constantOptimizer": true } | ||||
|         }, | ||||
|         "outputSelection": { | ||||
|   | ||||
| @@ -19,6 +19,11 @@ | ||||
| pragma solidity ^0.5.5; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "@0x/contracts-exchange-libs/contracts/src/LibEIP712ExchangeDomain.sol"; | ||||
| 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 "./OrderValidationUtils.sol"; | ||||
| import "./OrderTransferSimulationUtils.sol"; | ||||
| import "./LibTransactionDecoder.sol"; | ||||
| @@ -29,6 +34,7 @@ import "./EthBalanceChecker.sol"; | ||||
| contract DevUtils is | ||||
|     OrderValidationUtils, | ||||
|     LibTransactionDecoder, | ||||
|     LibEIP712ExchangeDomain, | ||||
|     EthBalanceChecker, | ||||
|     OrderTransferSimulationUtils | ||||
| { | ||||
| @@ -36,5 +42,32 @@ contract DevUtils is | ||||
|         public | ||||
|         OrderValidationUtils(_exchange) | ||||
|         OrderTransferSimulationUtils(_exchange) | ||||
|         LibEIP712ExchangeDomain(uint256(0), address(0)) // null args because because we only use constants | ||||
|     {} | ||||
|  | ||||
|     function getOrderHash(LibOrder.Order memory order, uint256 chainId, address exchange) | ||||
|         public | ||||
|         pure | ||||
|         returns (bytes32 orderHash) | ||||
|     { | ||||
|         return LibOrder.getTypedDataHash( | ||||
|             order, | ||||
|             LibEIP712.hashEIP712Domain(_EIP712_EXCHANGE_DOMAIN_NAME, _EIP712_EXCHANGE_DOMAIN_VERSION, chainId, exchange) | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     function getTransactionHash( | ||||
|         LibZeroExTransaction.ZeroExTransaction memory transaction, | ||||
|         uint256 chainId, | ||||
|         address exchange | ||||
|     ) | ||||
|         public | ||||
|         pure | ||||
|         returns (bytes32 transactionHash) | ||||
|     { | ||||
|         return LibZeroExTransaction.getTypedDataHash( | ||||
|             transaction, | ||||
|             LibEIP712.hashEIP712Domain(_EIP712_EXCHANGE_DOMAIN_NAME, _EIP712_EXCHANGE_DOMAIN_VERSION, chainId, exchange) | ||||
|         ); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -316,6 +316,29 @@ contract LibAssetData { | ||||
|         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 | ||||
|     function decodeAssetProxyId(bytes memory assetData) | ||||
|         public | ||||
|         pure | ||||
|         returns ( | ||||
|             bytes4 assetProxyId | ||||
|         ) | ||||
|     { | ||||
|         assetProxyId = assetData.readBytes4(0); | ||||
|  | ||||
|         require( | ||||
|             assetProxyId == IAssetData(address(0)).ERC20Token.selector || | ||||
|             assetProxyId == IAssetData(address(0)).ERC721Token.selector || | ||||
|             assetProxyId == IAssetData(address(0)).ERC1155Assets.selector || | ||||
|             assetProxyId == IAssetData(address(0)).MultiAsset.selector || | ||||
|             assetProxyId == IAssetData(address(0)).StaticCall.selector, | ||||
|             "WRONG_PROXY_ID" | ||||
|         ); | ||||
|         return assetProxyId; | ||||
|     } | ||||
|  | ||||
|     /// @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. | ||||
| @@ -330,7 +353,7 @@ contract LibAssetData { | ||||
|  | ||||
|     /// @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 ERC-20 AssetProxy identifier, and the address of the ERC-20  | ||||
|     /// @return The AssetProxy identifier, and the address of the ERC-20  | ||||
|     /// contract hosting this asset. | ||||
|     function decodeERC20AssetData(bytes memory assetData) | ||||
|         public | ||||
| @@ -515,4 +538,75 @@ contract LibAssetData { | ||||
|         ); | ||||
|         // solhint-enable indent | ||||
|     } | ||||
|  | ||||
|     /// @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) | ||||
|     { | ||||
|         assetData = abi.encodeWithSelector( | ||||
|             IAssetData(address(0)).StaticCall.selector, | ||||
|             staticCallTargetAddress, | ||||
|             staticCallData, | ||||
|             expectedReturnDataHash | ||||
|         ); | ||||
|         return assetData; | ||||
|     } | ||||
|  | ||||
|     /// @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 | ||||
|         ) | ||||
|     { | ||||
|         assetProxyId = assetData.readBytes4(0); | ||||
|  | ||||
|         require( | ||||
|             assetProxyId == IAssetData(address(0)).StaticCall.selector, | ||||
|             "WRONG_PROXY_ID" | ||||
|         ); | ||||
|  | ||||
|         (staticCallTargetAddress, staticCallData, expectedReturnDataHash) = abi.decode( | ||||
|             assetData.slice(4, assetData.length), | ||||
|             (address, bytes, bytes32) | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     function revertIfInvalidAssetData(bytes memory assetData) | ||||
|         public | ||||
|         pure  | ||||
|     { | ||||
|         bytes4 assetProxyId = assetData.readBytes4(0); | ||||
|  | ||||
|         if (assetProxyId == IAssetData(address(0)).ERC20Token.selector) { | ||||
|             decodeERC20AssetData(assetData); | ||||
|         } else if (assetProxyId == IAssetData(address(0)).ERC721Token.selector) { | ||||
|             decodeERC721AssetData(assetData); | ||||
|         } else if (assetProxyId == IAssetData(address(0)).ERC1155Assets.selector) { | ||||
|             decodeERC1155AssetData(assetData); | ||||
|         } else if (assetProxyId == IAssetData(address(0)).MultiAsset.selector) { | ||||
|             decodeMultiAssetData(assetData); | ||||
|         } else if (assetProxyId == IAssetData(address(0)).StaticCall.selector) { | ||||
|             decodeStaticCallAssetData(assetData); | ||||
|         } else { | ||||
|             revert("WRONG_PROXY_ID"); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,42 +1,32 @@ | ||||
| { | ||||
|     "name": "@0x/contracts-dev-utils", | ||||
|     "version": "0.1.0-beta.0", | ||||
|     "version": "0.1.0-beta.2", | ||||
|     "engines": { | ||||
|         "node": ">=6.12" | ||||
|     }, | ||||
|     "description": "0x protocol specific utility contracts", | ||||
|     "main": "lib/src/index.js", | ||||
|     "directories": { | ||||
|         "test": "test" | ||||
|     }, | ||||
|     "scripts": { | ||||
|         "build": "yarn pre_build && tsc -b", | ||||
|         "test": "yarn assert_deployable && echo !!! Tests are run via @0x/contracts-tests !!!", | ||||
|         "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", | ||||
|         "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": "UNLIMITED_CONTRACT_SIZE=true mocha --require source-map-support/register --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit", | ||||
|         "pre_build": "run-s compile quantify_bytecode contracts:gen generate_contract_wrappers contracts:copy", | ||||
|         "compile": "sol-compiler", | ||||
|         "watch": "sol-compiler -w", | ||||
|         "clean": "shx rm -rf lib generated-artifacts generated-wrappers", | ||||
|         "generate_contract_wrappers": "abi-gen --abis  ${npm_package_config_abis} --output generated-wrappers --backend ethers", | ||||
|         "lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts", | ||||
|         "fix": "tslint --fix --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./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", | ||||
|         "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", | ||||
|         "fix": "tslint --fix --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./test/generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts", | ||||
|         "contracts:gen": "contracts-gen generate", | ||||
|         "contracts:copy": "contracts-gen copy", | ||||
|         "lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol", | ||||
|         "quantify_bytecode": "echo EVM bytecode object lengths:;for i in ./generated-artifacts/*.json; do node -e \"console.log('$i\t' + (require('$i').compilerOutput.evm.bytecode.object.length - 2) / 2)\"; done", | ||||
|         "quantify_bytecode": "echo EVM bytecode object lengths:;for i in ./test/generated-artifacts/*.json; do node -e \"console.log('$i\t' + (require('$i').compilerOutput.evm.bytecode.object.length - 2) / 2)\"; done", | ||||
|         "compile:truffle": "truffle compile" | ||||
|     }, | ||||
|     "config": { | ||||
|         "abis": "./generated-artifacts/@(DevUtils|EthBalanceChecker|LibAssetData|LibTransactionDecoder|OrderTransferSimulationUtils|OrderValidationUtils).json", | ||||
|         "publicInterfaceContracts": "DevUtils,LibAssetData,LibTransactionDecoder", | ||||
|         "abis": "./test/generated-artifacts/@(DevUtils|EthBalanceChecker|LibAssetData|LibTransactionDecoder|OrderTransferSimulationUtils|OrderValidationUtils).json", | ||||
|         "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually." | ||||
|     }, | ||||
|     "repository": { | ||||
| @@ -49,21 +39,13 @@ | ||||
|     }, | ||||
|     "homepage": "https://github.com/0xProject/0x-monorepo/contracts/dev-utils/README.md", | ||||
|     "devDependencies": { | ||||
|         "@0x/abi-gen": "^4.3.0-beta.0", | ||||
|         "@0x/contracts-gen": "^1.1.0-beta.0", | ||||
|         "@0x/contracts-test-utils": "^3.2.0-beta.0", | ||||
|         "@0x/dev-utils": "^2.4.0-beta.0", | ||||
|         "@0x/sol-compiler": "^3.2.0-beta.0", | ||||
|         "@0x/tslint-config": "^3.0.1", | ||||
|         "@types/lodash": "4.14.104", | ||||
|         "@types/mocha": "^5.2.7", | ||||
|         "@0x/abi-gen": "^4.4.0-beta.2", | ||||
|         "@0x/assert": "^2.2.0-beta.2", | ||||
|         "@0x/contracts-gen": "^1.1.0-beta.2", | ||||
|         "@0x/sol-compiler": "^3.2.0-beta.2", | ||||
|         "@0x/tslint-config": "^3.1.0-beta.2", | ||||
|         "@types/node": "*", | ||||
|         "chai": "^4.0.1", | ||||
|         "chai-as-promised": "^7.1.0", | ||||
|         "chai-bignumber": "^3.0.0", | ||||
|         "dirty-chai": "^2.0.1", | ||||
|         "make-promises-safe": "^1.1.0", | ||||
|         "mocha": "^6.2.0", | ||||
|         "ethers": "~4.0.4", | ||||
|         "npm-run-all": "^4.1.2", | ||||
|         "shx": "^0.2.2", | ||||
|         "solhint": "^1.4.1", | ||||
| @@ -72,21 +54,8 @@ | ||||
|         "typescript": "3.0.1" | ||||
|     }, | ||||
|     "dependencies": { | ||||
|         "@0x/base-contract": "^5.5.0-beta.0", | ||||
|         "@0x/contracts-asset-proxy": "^2.3.0-beta.0", | ||||
|         "@0x/contracts-erc1155": "^1.2.0-beta.0", | ||||
|         "@0x/contracts-erc20": "^2.3.0-beta.0", | ||||
|         "@0x/contracts-erc721": "^2.2.0-beta.0", | ||||
|         "@0x/contracts-exchange": "^2.2.0-beta.0", | ||||
|         "@0x/contracts-exchange-libs": "^3.1.0-beta.0", | ||||
|         "@0x/contracts-utils": "^3.3.0-beta.0", | ||||
|         "@0x/order-utils": "^8.5.0-beta.0", | ||||
|         "@0x/types": "^2.5.0-beta.0", | ||||
|         "@0x/typescript-typings": "^4.4.0-beta.0", | ||||
|         "@0x/utils": "^4.6.0-beta.0", | ||||
|         "@0x/web3-wrapper": "^6.1.0-beta.0", | ||||
|         "ethereum-types": "^2.2.0-beta.0", | ||||
|         "ethereumjs-util": "^5.1.1" | ||||
|         "@0x/base-contract": "^5.5.0-beta.2", | ||||
|         "ethereum-types": "^2.2.0-beta.2" | ||||
|     }, | ||||
|     "publishConfig": { | ||||
|         "access": "public" | ||||
|   | ||||
| @@ -6,16 +6,10 @@ | ||||
| import { ContractArtifact } from 'ethereum-types'; | ||||
|  | ||||
| import * as DevUtils from '../generated-artifacts/DevUtils.json'; | ||||
| import * as EthBalanceChecker from '../generated-artifacts/EthBalanceChecker.json'; | ||||
| import * as LibAssetData from '../generated-artifacts/LibAssetData.json'; | ||||
| import * as LibTransactionDecoder from '../generated-artifacts/LibTransactionDecoder.json'; | ||||
| import * as OrderTransferSimulationUtils from '../generated-artifacts/OrderTransferSimulationUtils.json'; | ||||
| import * as OrderValidationUtils from '../generated-artifacts/OrderValidationUtils.json'; | ||||
| export const artifacts = { | ||||
|     DevUtils: DevUtils as ContractArtifact, | ||||
|     EthBalanceChecker: EthBalanceChecker as ContractArtifact, | ||||
|     LibAssetData: LibAssetData as ContractArtifact, | ||||
|     LibTransactionDecoder: LibTransactionDecoder as ContractArtifact, | ||||
|     OrderTransferSimulationUtils: OrderTransferSimulationUtils as ContractArtifact, | ||||
|     OrderValidationUtils: OrderValidationUtils as ContractArtifact, | ||||
| }; | ||||
|   | ||||
| @@ -4,8 +4,5 @@ | ||||
|  * ----------------------------------------------------------------------------- | ||||
|  */ | ||||
| export * from '../generated-wrappers/dev_utils'; | ||||
| export * from '../generated-wrappers/eth_balance_checker'; | ||||
| export * from '../generated-wrappers/lib_asset_data'; | ||||
| export * from '../generated-wrappers/lib_transaction_decoder'; | ||||
| export * from '../generated-wrappers/order_transfer_simulation_utils'; | ||||
| export * from '../generated-wrappers/order_validation_utils'; | ||||
|   | ||||
							
								
								
									
										21
									
								
								contracts/dev-utils/test/artifacts.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								contracts/dev-utils/test/artifacts.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| /* | ||||
|  * ----------------------------------------------------------------------------- | ||||
|  * Warning: This file is auto-generated by contracts-gen. Don't edit manually. | ||||
|  * ----------------------------------------------------------------------------- | ||||
|  */ | ||||
| import { ContractArtifact } from 'ethereum-types'; | ||||
|  | ||||
| import * as DevUtils from '../test/generated-artifacts/DevUtils.json'; | ||||
| import * as EthBalanceChecker from '../test/generated-artifacts/EthBalanceChecker.json'; | ||||
| import * as LibAssetData from '../test/generated-artifacts/LibAssetData.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'; | ||||
| export const artifacts = { | ||||
|     DevUtils: DevUtils as ContractArtifact, | ||||
|     EthBalanceChecker: EthBalanceChecker as ContractArtifact, | ||||
|     LibAssetData: LibAssetData as ContractArtifact, | ||||
|     LibTransactionDecoder: LibTransactionDecoder as ContractArtifact, | ||||
|     OrderTransferSimulationUtils: OrderTransferSimulationUtils as ContractArtifact, | ||||
|     OrderValidationUtils: OrderValidationUtils as ContractArtifact, | ||||
| }; | ||||
| @@ -1,651 +0,0 @@ | ||||
| import { | ||||
|     artifacts as proxyArtifacts, | ||||
|     ERC20ProxyContract, | ||||
|     ERC20Wrapper, | ||||
|     ERC721ProxyContract, | ||||
|     ERC721Wrapper, | ||||
|     MultiAssetProxyContract, | ||||
| } from '@0x/contracts-asset-proxy'; | ||||
| import { DummyERC20TokenContract } from '@0x/contracts-erc20'; | ||||
| import { DummyERC721TokenContract } from '@0x/contracts-erc721'; | ||||
| import { artifacts as exchangeArtifacts, ExchangeContract, ExchangeWrapper } from '@0x/contracts-exchange'; | ||||
| import { | ||||
|     chaiSetup, | ||||
|     constants, | ||||
|     OrderFactory, | ||||
|     OrderStatus, | ||||
|     provider, | ||||
|     txDefaults, | ||||
|     web3Wrapper, | ||||
| } from '@0x/contracts-test-utils'; | ||||
| import { BlockchainLifecycle } from '@0x/dev-utils'; | ||||
| import { assetDataUtils, orderHashUtils } from '@0x/order-utils'; | ||||
| import { OrderTransferResults, SignedOrder } from '@0x/types'; | ||||
| import { BigNumber, providerUtils } from '@0x/utils'; | ||||
| import * as chai from 'chai'; | ||||
|  | ||||
| import { artifacts, DevUtilsContract } from '../src'; | ||||
|  | ||||
| chaiSetup.configure(); | ||||
| const expect = chai.expect; | ||||
| const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); | ||||
|  | ||||
| describe('OrderValidationUtils/OrderTransferSimulatorUtils', () => { | ||||
|     let makerAddress: string; | ||||
|     let takerAddress: string; | ||||
|     let owner: string; | ||||
|     let erc20AssetData: string; | ||||
|     let erc20AssetData2: string; | ||||
|     let erc721AssetData: string; | ||||
|     let feeAssetData: string; | ||||
|  | ||||
|     let erc20Token: DummyERC20TokenContract; | ||||
|     let erc20Token2: DummyERC20TokenContract; | ||||
|     let feeErc20Token: DummyERC20TokenContract; | ||||
|     let erc721Token: DummyERC721TokenContract; | ||||
|     let exchange: ExchangeContract; | ||||
|     let devUtils: DevUtilsContract; | ||||
|     let erc20Proxy: ERC20ProxyContract; | ||||
|     let erc721Proxy: ERC721ProxyContract; | ||||
|     let multiAssetProxy: MultiAssetProxyContract; | ||||
|  | ||||
|     let signedOrder: SignedOrder; | ||||
|     let orderFactory: OrderFactory; | ||||
|  | ||||
|     const tokenId = new BigNumber(123456789); | ||||
|  | ||||
|     before(async () => { | ||||
|         await blockchainLifecycle.startAsync(); | ||||
|     }); | ||||
|     after(async () => { | ||||
|         await blockchainLifecycle.revertAsync(); | ||||
|     }); | ||||
|  | ||||
|     before(async () => { | ||||
|         const accounts = await web3Wrapper.getAvailableAddressesAsync(); | ||||
|         const usedAddresses = ([owner, makerAddress, takerAddress] = accounts.slice(0, 3)); | ||||
|         const chainId = await providerUtils.getChainIdAsync(provider); | ||||
|  | ||||
|         const erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner); | ||||
|         const erc721Wrapper = new ERC721Wrapper(provider, usedAddresses, owner); | ||||
|  | ||||
|         const numDummyErc20ToDeploy = 3; | ||||
|         [erc20Token, erc20Token2, feeErc20Token] = await erc20Wrapper.deployDummyTokensAsync( | ||||
|             numDummyErc20ToDeploy, | ||||
|             constants.DUMMY_TOKEN_DECIMALS, | ||||
|         ); | ||||
|         erc20Proxy = await erc20Wrapper.deployProxyAsync(); | ||||
|  | ||||
|         [erc721Token] = await erc721Wrapper.deployDummyTokensAsync(); | ||||
|         erc721Proxy = await erc721Wrapper.deployProxyAsync(); | ||||
|  | ||||
|         feeAssetData = assetDataUtils.encodeERC20AssetData(feeErc20Token.address); | ||||
|         exchange = await ExchangeContract.deployFrom0xArtifactAsync( | ||||
|             exchangeArtifacts.Exchange, | ||||
|             provider, | ||||
|             txDefaults, | ||||
|             {}, | ||||
|             new BigNumber(chainId), | ||||
|         ); | ||||
|  | ||||
|         multiAssetProxy = await MultiAssetProxyContract.deployFrom0xArtifactAsync( | ||||
|             proxyArtifacts.MultiAssetProxy, | ||||
|             provider, | ||||
|             txDefaults, | ||||
|             artifacts, | ||||
|         ); | ||||
|         const exchangeWrapper = new ExchangeWrapper(exchange); | ||||
|         await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner); | ||||
|         await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.address, owner); | ||||
|         await exchangeWrapper.registerAssetProxyAsync(multiAssetProxy.address, owner); | ||||
|         await erc20Proxy.addAuthorizedAddress.awaitTransactionSuccessAsync(exchange.address, { from: owner }); | ||||
|         await erc721Proxy.addAuthorizedAddress.awaitTransactionSuccessAsync(exchange.address, { from: owner }); | ||||
|  | ||||
|         devUtils = await DevUtilsContract.deployFrom0xArtifactAsync( | ||||
|             artifacts.DevUtils, | ||||
|             provider, | ||||
|             txDefaults, | ||||
|             artifacts, | ||||
|             exchange.address, | ||||
|         ); | ||||
|  | ||||
|         erc20AssetData = assetDataUtils.encodeERC20AssetData(erc20Token.address); | ||||
|         erc20AssetData2 = assetDataUtils.encodeERC20AssetData(erc20Token2.address); | ||||
|         erc721AssetData = assetDataUtils.encodeERC721AssetData(erc721Token.address, tokenId); | ||||
|         const defaultOrderParams = { | ||||
|             ...constants.STATIC_ORDER_PARAMS, | ||||
|             makerAddress, | ||||
|             feeRecipientAddress: constants.NULL_ADDRESS, | ||||
|             makerAssetData: erc20AssetData, | ||||
|             takerAssetData: erc20AssetData2, | ||||
|             makerFeeAssetData: feeAssetData, | ||||
|             takerFeeAssetData: feeAssetData, | ||||
|             exchangeAddress: exchange.address, | ||||
|             chainId, | ||||
|         }; | ||||
|         const privateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)]; | ||||
|         orderFactory = new OrderFactory(privateKey, defaultOrderParams); | ||||
|     }); | ||||
|  | ||||
|     beforeEach(async () => { | ||||
|         await blockchainLifecycle.startAsync(); | ||||
|     }); | ||||
|     afterEach(async () => { | ||||
|         await blockchainLifecycle.revertAsync(); | ||||
|     }); | ||||
|  | ||||
|     describe('getTransferableAssetAmount', () => { | ||||
|         it('should return the balance when balance < allowance', async () => { | ||||
|             const balance = new BigNumber(123); | ||||
|             const allowance = new BigNumber(456); | ||||
|             await erc20Token.setBalance.awaitTransactionSuccessAsync(makerAddress, balance); | ||||
|             await erc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, allowance, { | ||||
|                 from: makerAddress, | ||||
|             }); | ||||
|             const transferableAmount = await devUtils.getTransferableAssetAmount.callAsync( | ||||
|                 makerAddress, | ||||
|                 erc20AssetData, | ||||
|             ); | ||||
|             expect(transferableAmount).to.bignumber.equal(balance); | ||||
|         }); | ||||
|         it('should return the allowance when allowance < balance', async () => { | ||||
|             const balance = new BigNumber(456); | ||||
|             const allowance = new BigNumber(123); | ||||
|             await erc20Token.setBalance.awaitTransactionSuccessAsync(makerAddress, balance); | ||||
|             await erc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, allowance, { | ||||
|                 from: makerAddress, | ||||
|             }); | ||||
|             const transferableAmount = await devUtils.getTransferableAssetAmount.callAsync( | ||||
|                 makerAddress, | ||||
|                 erc20AssetData, | ||||
|             ); | ||||
|             expect(transferableAmount).to.bignumber.equal(allowance); | ||||
|         }); | ||||
|         it('should return the correct transferable amount for multiAssetData', async () => { | ||||
|             const multiAssetData = assetDataUtils.encodeMultiAssetData( | ||||
|                 [new BigNumber(1), new BigNumber(1)], | ||||
|                 [erc20AssetData, erc20AssetData2], | ||||
|             ); | ||||
|             const transferableAmount1 = new BigNumber(10); | ||||
|             const transferableAmount2 = new BigNumber(5); | ||||
|             await erc20Token.setBalance.awaitTransactionSuccessAsync(makerAddress, transferableAmount1); | ||||
|             await erc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, transferableAmount1, { | ||||
|                 from: makerAddress, | ||||
|             }); | ||||
|             await erc20Token2.setBalance.awaitTransactionSuccessAsync(makerAddress, transferableAmount2); | ||||
|             await erc20Token2.approve.awaitTransactionSuccessAsync(erc20Proxy.address, transferableAmount2, { | ||||
|                 from: makerAddress, | ||||
|             }); | ||||
|             const transferableAmount = await devUtils.getTransferableAssetAmount.callAsync( | ||||
|                 makerAddress, | ||||
|                 multiAssetData, | ||||
|             ); | ||||
|             expect(transferableAmount).to.bignumber.equal(transferableAmount2); | ||||
|         }); | ||||
|     }); | ||||
|     describe('getOrderRelevantState', () => { | ||||
|         beforeEach(async () => { | ||||
|             signedOrder = await orderFactory.newSignedOrderAsync(); | ||||
|         }); | ||||
|         it('should return the correct orderInfo when the order is valid', async () => { | ||||
|             const [orderInfo] = await devUtils.getOrderRelevantState.callAsync(signedOrder, signedOrder.signature); | ||||
|             expect(orderInfo.orderHash).to.equal(orderHashUtils.getOrderHashHex(signedOrder)); | ||||
|             expect(orderInfo.orderStatus).to.equal(OrderStatus.Fillable); | ||||
|             expect(orderInfo.orderTakerAssetFilledAmount).to.bignumber.equal(constants.ZERO_AMOUNT); | ||||
|         }); | ||||
|         it('should return isValidSignature=true when the signature is valid', async () => { | ||||
|             const [, , isValidSignature] = await devUtils.getOrderRelevantState.callAsync( | ||||
|                 signedOrder, | ||||
|                 signedOrder.signature, | ||||
|             ); | ||||
|             expect(isValidSignature).to.equal(true); | ||||
|         }); | ||||
|         it('should return isValidSignature=false when the signature is invalid', async () => { | ||||
|             const invalidSignature = '0x01'; | ||||
|             const [, , isValidSignature] = await devUtils.getOrderRelevantState.callAsync( | ||||
|                 signedOrder, | ||||
|                 invalidSignature, | ||||
|             ); | ||||
|             expect(isValidSignature).to.equal(false); | ||||
|         }); | ||||
|         it('should return a fillableTakerAssetAmount of 0 when balances or allowances are insufficient', async () => { | ||||
|             const [, fillableTakerAssetAmount] = await devUtils.getOrderRelevantState.callAsync( | ||||
|                 signedOrder, | ||||
|                 signedOrder.signature, | ||||
|             ); | ||||
|             expect(fillableTakerAssetAmount).to.bignumber.equal(constants.ZERO_AMOUNT); | ||||
|         }); | ||||
|         it('should return a fillableTakerAssetAmount of 0 when fee balances/allowances are insufficient', async () => { | ||||
|             await erc20Token.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerAssetAmount); | ||||
|             await erc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerAssetAmount, { | ||||
|                 from: makerAddress, | ||||
|             }); | ||||
|             const [, fillableTakerAssetAmount] = await devUtils.getOrderRelevantState.callAsync( | ||||
|                 signedOrder, | ||||
|                 signedOrder.signature, | ||||
|             ); | ||||
|             expect(fillableTakerAssetAmount).to.bignumber.equal(constants.ZERO_AMOUNT); | ||||
|         }); | ||||
|         it('should return a fillableTakerAssetAmount of 0 when balances/allowances of one asset within a multiAssetData are insufficient', async () => { | ||||
|             const multiAssetData = assetDataUtils.encodeMultiAssetData( | ||||
|                 [new BigNumber(1), new BigNumber(1)], | ||||
|                 [erc20AssetData, erc20AssetData2], | ||||
|             ); | ||||
|             signedOrder = await orderFactory.newSignedOrderAsync({ makerAssetData: multiAssetData }); | ||||
|             await erc20Token.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerAssetAmount); | ||||
|             await erc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerAssetAmount, { | ||||
|                 from: makerAddress, | ||||
|             }); | ||||
|             const [, fillableTakerAssetAmount] = await devUtils.getOrderRelevantState.callAsync( | ||||
|                 signedOrder, | ||||
|                 signedOrder.signature, | ||||
|             ); | ||||
|             expect(fillableTakerAssetAmount).to.bignumber.equal(constants.ZERO_AMOUNT); | ||||
|         }); | ||||
|         it('should return the correct fillableTakerAssetAmount when fee balances/allowances are partially sufficient', async () => { | ||||
|             await erc20Token.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerAssetAmount); | ||||
|             await erc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerAssetAmount, { | ||||
|                 from: makerAddress, | ||||
|             }); | ||||
|             const divisor = 4; | ||||
|             await feeErc20Token.setBalance.awaitTransactionSuccessAsync( | ||||
|                 makerAddress, | ||||
|                 signedOrder.makerFee.dividedToIntegerBy(divisor), | ||||
|             ); | ||||
|             await feeErc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerFee, { | ||||
|                 from: makerAddress, | ||||
|             }); | ||||
|             const [, fillableTakerAssetAmount] = await devUtils.getOrderRelevantState.callAsync( | ||||
|                 signedOrder, | ||||
|                 signedOrder.signature, | ||||
|             ); | ||||
|             expect(fillableTakerAssetAmount).to.bignumber.equal( | ||||
|                 signedOrder.takerAssetAmount.dividedToIntegerBy(divisor), | ||||
|             ); | ||||
|         }); | ||||
|         it('should return the correct fillableTakerAssetAmount when non-fee balances/allowances are partially sufficient', async () => { | ||||
|             const divisor = 4; | ||||
|             await erc20Token.setBalance.awaitTransactionSuccessAsync( | ||||
|                 makerAddress, | ||||
|                 signedOrder.makerAssetAmount.dividedToIntegerBy(divisor), | ||||
|             ); | ||||
|             await erc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerAssetAmount, { | ||||
|                 from: makerAddress, | ||||
|             }); | ||||
|             await feeErc20Token.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerFee); | ||||
|             await feeErc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerFee, { | ||||
|                 from: makerAddress, | ||||
|             }); | ||||
|             const [, fillableTakerAssetAmount] = await devUtils.getOrderRelevantState.callAsync( | ||||
|                 signedOrder, | ||||
|                 signedOrder.signature, | ||||
|             ); | ||||
|             expect(fillableTakerAssetAmount).to.bignumber.equal( | ||||
|                 signedOrder.takerAssetAmount.dividedToIntegerBy(divisor), | ||||
|             ); | ||||
|         }); | ||||
|         it('should return the correct fillableTakerAssetAmount when balances/allowances of one asset within a multiAssetData are partially sufficient', async () => { | ||||
|             const multiAssetData = assetDataUtils.encodeMultiAssetData( | ||||
|                 [new BigNumber(1), new BigNumber(1)], | ||||
|                 [erc20AssetData, erc20AssetData2], | ||||
|             ); | ||||
|             signedOrder = await orderFactory.newSignedOrderAsync({ makerAssetData: multiAssetData }); | ||||
|             await erc20Token.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerAssetAmount); | ||||
|             await erc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerAssetAmount, { | ||||
|                 from: makerAddress, | ||||
|             }); | ||||
|             await feeErc20Token.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerFee); | ||||
|             await feeErc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerFee, { | ||||
|                 from: makerAddress, | ||||
|             }); | ||||
|             const divisor = 4; | ||||
|             await erc20Token2.setBalance.awaitTransactionSuccessAsync( | ||||
|                 makerAddress, | ||||
|                 signedOrder.makerAssetAmount.dividedToIntegerBy(divisor), | ||||
|             ); | ||||
|             await erc20Token2.approve.awaitTransactionSuccessAsync( | ||||
|                 erc20Proxy.address, | ||||
|                 signedOrder.makerAssetAmount.dividedToIntegerBy(divisor), | ||||
|                 { | ||||
|                     from: makerAddress, | ||||
|                 }, | ||||
|             ); | ||||
|             const [, fillableTakerAssetAmount] = await devUtils.getOrderRelevantState.callAsync( | ||||
|                 signedOrder, | ||||
|                 signedOrder.signature, | ||||
|             ); | ||||
|             expect(fillableTakerAssetAmount).to.bignumber.equal( | ||||
|                 signedOrder.takerAssetAmount.dividedToIntegerBy(divisor), | ||||
|             ); | ||||
|         }); | ||||
|         it('should return a fillableTakerAssetAmount of 0 when non-fee balances/allowances are insufficient', async () => { | ||||
|             await feeErc20Token.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerFee); | ||||
|             await feeErc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerFee, { | ||||
|                 from: makerAddress, | ||||
|             }); | ||||
|             const [, fillableTakerAssetAmount] = await devUtils.getOrderRelevantState.callAsync( | ||||
|                 signedOrder, | ||||
|                 signedOrder.signature, | ||||
|             ); | ||||
|             expect(fillableTakerAssetAmount).to.bignumber.equal(constants.ZERO_AMOUNT); | ||||
|         }); | ||||
|         it('should return a fillableTakerAssetAmount equal to the takerAssetAmount when the order is unfilled and balances/allowances are sufficient', async () => { | ||||
|             await erc20Token.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerAssetAmount); | ||||
|             await erc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerAssetAmount, { | ||||
|                 from: makerAddress, | ||||
|             }); | ||||
|             await feeErc20Token.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerFee); | ||||
|             await feeErc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerFee, { | ||||
|                 from: makerAddress, | ||||
|             }); | ||||
|             const [, fillableTakerAssetAmount] = await devUtils.getOrderRelevantState.callAsync( | ||||
|                 signedOrder, | ||||
|                 signedOrder.signature, | ||||
|             ); | ||||
|             expect(fillableTakerAssetAmount).to.bignumber.equal(signedOrder.takerAssetAmount); | ||||
|         }); | ||||
|         it('should return the correct fillableTakerAssetAmount when balances/allowances are partially sufficient and makerAsset=makerFeeAsset', async () => { | ||||
|             signedOrder = await orderFactory.newSignedOrderAsync({ | ||||
|                 makerAssetData: feeAssetData, | ||||
|                 makerAssetAmount: new BigNumber(10), | ||||
|                 takerAssetAmount: new BigNumber(20), | ||||
|                 makerFee: new BigNumber(40), | ||||
|             }); | ||||
|             const transferableMakerAssetAmount = new BigNumber(10); | ||||
|             await feeErc20Token.setBalance.awaitTransactionSuccessAsync(makerAddress, transferableMakerAssetAmount); | ||||
|             await feeErc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, transferableMakerAssetAmount, { | ||||
|                 from: makerAddress, | ||||
|             }); | ||||
|             const expectedFillableTakerAssetAmount = transferableMakerAssetAmount | ||||
|                 .times(signedOrder.takerAssetAmount) | ||||
|                 .dividedToIntegerBy(signedOrder.makerAssetAmount.plus(signedOrder.makerFee)); | ||||
|             const [, fillableTakerAssetAmount] = await devUtils.getOrderRelevantState.callAsync( | ||||
|                 signedOrder, | ||||
|                 signedOrder.signature, | ||||
|             ); | ||||
|             expect(fillableTakerAssetAmount).to.bignumber.equal(expectedFillableTakerAssetAmount); | ||||
|         }); | ||||
|         it('should return the correct fillabeTakerassetAmount when makerAsset balances/allowances are sufficient and there are no maker fees', async () => { | ||||
|             signedOrder = await orderFactory.newSignedOrderAsync({ makerFee: constants.ZERO_AMOUNT }); | ||||
|             await erc20Token.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerAssetAmount); | ||||
|             await erc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerAssetAmount, { | ||||
|                 from: makerAddress, | ||||
|             }); | ||||
|             const [, fillableTakerAssetAmount] = await devUtils.getOrderRelevantState.callAsync( | ||||
|                 signedOrder, | ||||
|                 signedOrder.signature, | ||||
|             ); | ||||
|             expect(fillableTakerAssetAmount).to.bignumber.equal(signedOrder.takerAssetAmount); | ||||
|         }); | ||||
|         it('should return a fillableTakerAssetAmount when the remaining takerAssetAmount is less than the transferable amount', async () => { | ||||
|             await erc20Token.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerAssetAmount); | ||||
|             await erc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerAssetAmount, { | ||||
|                 from: makerAddress, | ||||
|             }); | ||||
|             await feeErc20Token.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerFee); | ||||
|             await feeErc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerFee, { | ||||
|                 from: makerAddress, | ||||
|             }); | ||||
|             await erc20Token2.setBalance.awaitTransactionSuccessAsync(takerAddress, signedOrder.takerAssetAmount); | ||||
|             await erc20Token2.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.takerAssetAmount, { | ||||
|                 from: takerAddress, | ||||
|             }); | ||||
|             await feeErc20Token.setBalance.awaitTransactionSuccessAsync(takerAddress, signedOrder.takerFee); | ||||
|  | ||||
|             await feeErc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.takerFee, { | ||||
|                 from: takerAddress, | ||||
|             }); | ||||
|             const takerAssetFillAmount = signedOrder.takerAssetAmount.dividedToIntegerBy(4); | ||||
|             await exchange.fillOrder.awaitTransactionSuccessAsync( | ||||
|                 signedOrder, | ||||
|                 takerAssetFillAmount, | ||||
|                 signedOrder.signature, | ||||
|                 { from: takerAddress }, | ||||
|             ); | ||||
|             const [, fillableTakerAssetAmount] = await devUtils.getOrderRelevantState.callAsync( | ||||
|                 signedOrder, | ||||
|                 signedOrder.signature, | ||||
|             ); | ||||
|             expect(fillableTakerAssetAmount).to.bignumber.equal( | ||||
|                 signedOrder.takerAssetAmount.minus(takerAssetFillAmount), | ||||
|             ); | ||||
|         }); | ||||
|         it('should return correct info even when there are no fees specified', async () => { | ||||
|             signedOrder = await orderFactory.newSignedOrderAsync({ | ||||
|                 makerFee: new BigNumber(0), | ||||
|                 takerFee: new BigNumber(0), | ||||
|                 makerFeeAssetData: '0x', | ||||
|                 takerFeeAssetData: '0x', | ||||
|             }); | ||||
|             await erc20Token.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerAssetAmount); | ||||
|             await erc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerAssetAmount, { | ||||
|                 from: makerAddress, | ||||
|             }); | ||||
|             const [ | ||||
|                 orderInfo, | ||||
|                 fillableTakerAssetAmount, | ||||
|                 isValidSignature, | ||||
|             ] = await devUtils.getOrderRelevantState.callAsync(signedOrder, signedOrder.signature); | ||||
|             expect(orderInfo.orderHash).to.equal(orderHashUtils.getOrderHashHex(signedOrder)); | ||||
|             expect(orderInfo.orderStatus).to.equal(OrderStatus.Fillable); | ||||
|             expect(orderInfo.orderTakerAssetFilledAmount).to.bignumber.equal(constants.ZERO_AMOUNT); | ||||
|             expect(fillableTakerAssetAmount).to.bignumber.equal(signedOrder.takerAssetAmount); | ||||
|             expect(isValidSignature).to.equal(true); | ||||
|         }); | ||||
|     }); | ||||
|     describe('getOrderRelevantStates', async () => { | ||||
|         it('should return the correct information for multiple orders', async () => { | ||||
|             signedOrder = await orderFactory.newSignedOrderAsync(); | ||||
|             await erc20Token.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerAssetAmount); | ||||
|             await erc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerAssetAmount, { | ||||
|                 from: makerAddress, | ||||
|             }); | ||||
|             await feeErc20Token.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerFee); | ||||
|             await feeErc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerFee, { | ||||
|                 from: makerAddress, | ||||
|             }); | ||||
|             const signedOrder2 = await orderFactory.newSignedOrderAsync({ makerAssetData: erc721AssetData }); | ||||
|             const invalidSignature = '0x01'; | ||||
|             await exchange.cancelOrder.awaitTransactionSuccessAsync(signedOrder2, { from: makerAddress }); | ||||
|             const [ | ||||
|                 ordersInfo, | ||||
|                 fillableTakerAssetAmounts, | ||||
|                 isValidSignature, | ||||
|             ] = await devUtils.getOrderRelevantStates.callAsync( | ||||
|                 [signedOrder, signedOrder2], | ||||
|                 [signedOrder.signature, invalidSignature], | ||||
|             ); | ||||
|             expect(ordersInfo[0].orderHash).to.equal(orderHashUtils.getOrderHashHex(signedOrder)); | ||||
|             expect(ordersInfo[1].orderHash).to.equal(orderHashUtils.getOrderHashHex(signedOrder2)); | ||||
|             expect(ordersInfo[0].orderStatus).to.equal(OrderStatus.Fillable); | ||||
|             expect(ordersInfo[1].orderStatus).to.equal(OrderStatus.Cancelled); | ||||
|             expect(ordersInfo[0].orderTakerAssetFilledAmount).to.bignumber.equal(constants.ZERO_AMOUNT); | ||||
|             expect(ordersInfo[1].orderTakerAssetFilledAmount).to.bignumber.equal(constants.ZERO_AMOUNT); | ||||
|             expect(fillableTakerAssetAmounts[0]).to.bignumber.equal(signedOrder.takerAssetAmount); | ||||
|             expect(fillableTakerAssetAmounts[1]).to.bignumber.equal(constants.ZERO_AMOUNT); | ||||
|             expect(isValidSignature[0]).to.equal(true); | ||||
|             expect(isValidSignature[1]).to.equal(false); | ||||
|         }); | ||||
|     }); | ||||
|     describe('getSimulatedOrderTransferResults', () => { | ||||
|         beforeEach(async () => { | ||||
|             signedOrder = await orderFactory.newSignedOrderAsync(); | ||||
|         }); | ||||
|         it('should return TakerAssetDataFailed if the takerAsset transfer fails', async () => { | ||||
|             const orderTransferResults = await devUtils.getSimulatedOrderTransferResults.callAsync( | ||||
|                 signedOrder, | ||||
|                 takerAddress, | ||||
|                 signedOrder.takerAssetAmount, | ||||
|             ); | ||||
|             expect(orderTransferResults).to.equal(OrderTransferResults.TakerAssetDataFailed); | ||||
|         }); | ||||
|         it('should return MakerAssetDataFailed if the makerAsset transfer fails', async () => { | ||||
|             await erc20Token2.setBalance.awaitTransactionSuccessAsync(takerAddress, signedOrder.takerAssetAmount, { | ||||
|                 from: owner, | ||||
|             }); | ||||
|             await erc20Token2.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.takerAssetAmount, { | ||||
|                 from: takerAddress, | ||||
|             }); | ||||
|             const orderTransferResults = await devUtils.getSimulatedOrderTransferResults.callAsync( | ||||
|                 signedOrder, | ||||
|                 takerAddress, | ||||
|                 signedOrder.takerAssetAmount, | ||||
|             ); | ||||
|             expect(orderTransferResults).to.equal(OrderTransferResults.MakerAssetDataFailed); | ||||
|         }); | ||||
|         it('should return TakerFeeAssetDataFailed if the takerFeeAsset transfer fails', async () => { | ||||
|             await erc20Token2.setBalance.awaitTransactionSuccessAsync(takerAddress, signedOrder.takerAssetAmount, { | ||||
|                 from: owner, | ||||
|             }); | ||||
|             await erc20Token2.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.takerAssetAmount, { | ||||
|                 from: takerAddress, | ||||
|             }); | ||||
|             await erc20Token.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerAssetAmount, { | ||||
|                 from: owner, | ||||
|             }); | ||||
|             await erc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerAssetAmount, { | ||||
|                 from: makerAddress, | ||||
|             }); | ||||
|             const orderTransferResults = await devUtils.getSimulatedOrderTransferResults.callAsync( | ||||
|                 signedOrder, | ||||
|                 takerAddress, | ||||
|                 signedOrder.takerAssetAmount, | ||||
|             ); | ||||
|             expect(orderTransferResults).to.equal(OrderTransferResults.TakerFeeAssetDataFailed); | ||||
|         }); | ||||
|         it('should return MakerFeeAssetDataFailed if the makerFeeAsset transfer fails', async () => { | ||||
|             await erc20Token2.setBalance.awaitTransactionSuccessAsync(takerAddress, signedOrder.takerAssetAmount, { | ||||
|                 from: owner, | ||||
|             }); | ||||
|             await erc20Token2.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.takerAssetAmount, { | ||||
|                 from: takerAddress, | ||||
|             }); | ||||
|             await erc20Token.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerAssetAmount, { | ||||
|                 from: owner, | ||||
|             }); | ||||
|             await erc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerAssetAmount, { | ||||
|                 from: makerAddress, | ||||
|             }); | ||||
|             await feeErc20Token.setBalance.awaitTransactionSuccessAsync(takerAddress, signedOrder.takerFee, { | ||||
|                 from: owner, | ||||
|             }); | ||||
|             await feeErc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.takerFee, { | ||||
|                 from: takerAddress, | ||||
|             }); | ||||
|             const orderTransferResults = await devUtils.getSimulatedOrderTransferResults.callAsync( | ||||
|                 signedOrder, | ||||
|                 takerAddress, | ||||
|                 signedOrder.takerAssetAmount, | ||||
|             ); | ||||
|             expect(orderTransferResults).to.equal(OrderTransferResults.MakerFeeAssetDataFailed); | ||||
|         }); | ||||
|         it('should return TransfersSuccessful if all transfers succeed', async () => { | ||||
|             await erc20Token2.setBalance.awaitTransactionSuccessAsync(takerAddress, signedOrder.takerAssetAmount, { | ||||
|                 from: owner, | ||||
|             }); | ||||
|             await erc20Token2.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.takerAssetAmount, { | ||||
|                 from: takerAddress, | ||||
|             }); | ||||
|             await erc20Token.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerAssetAmount, { | ||||
|                 from: owner, | ||||
|             }); | ||||
|             await erc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerAssetAmount, { | ||||
|                 from: makerAddress, | ||||
|             }); | ||||
|             await feeErc20Token.setBalance.awaitTransactionSuccessAsync(takerAddress, signedOrder.takerFee, { | ||||
|                 from: owner, | ||||
|             }); | ||||
|             await feeErc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.takerFee, { | ||||
|                 from: takerAddress, | ||||
|             }); | ||||
|             await feeErc20Token.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerFee, { | ||||
|                 from: owner, | ||||
|             }); | ||||
|             await feeErc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerFee, { | ||||
|                 from: makerAddress, | ||||
|             }); | ||||
|             const orderTransferResults = await devUtils.getSimulatedOrderTransferResults.callAsync( | ||||
|                 signedOrder, | ||||
|                 takerAddress, | ||||
|                 signedOrder.takerAssetAmount, | ||||
|             ); | ||||
|             expect(orderTransferResults).to.equal(OrderTransferResults.TransfersSuccessful); | ||||
|         }); | ||||
|         it('should return TransfersSuccessful for a partial fill when taker has ample assets for the fill but not for the whole order', async () => { | ||||
|             await erc20Token2.setBalance.awaitTransactionSuccessAsync( | ||||
|                 takerAddress, | ||||
|                 signedOrder.takerAssetAmount.dividedBy(2), | ||||
|                 { | ||||
|                     from: owner, | ||||
|                 }, | ||||
|             ); | ||||
|             await erc20Token2.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.takerAssetAmount, { | ||||
|                 from: takerAddress, | ||||
|             }); | ||||
|             await erc20Token.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerAssetAmount, { | ||||
|                 from: owner, | ||||
|             }); | ||||
|             await erc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerAssetAmount, { | ||||
|                 from: makerAddress, | ||||
|             }); | ||||
|             await feeErc20Token.setBalance.awaitTransactionSuccessAsync(takerAddress, signedOrder.takerFee, { | ||||
|                 from: owner, | ||||
|             }); | ||||
|             await feeErc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.takerFee, { | ||||
|                 from: takerAddress, | ||||
|             }); | ||||
|             await feeErc20Token.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerFee, { | ||||
|                 from: owner, | ||||
|             }); | ||||
|             await feeErc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerFee, { | ||||
|                 from: makerAddress, | ||||
|             }); | ||||
|             const orderTransferResults = await devUtils.getSimulatedOrderTransferResults.callAsync( | ||||
|                 signedOrder, | ||||
|                 takerAddress, | ||||
|                 signedOrder.takerAssetAmount.dividedBy(2), | ||||
|             ); | ||||
|             expect(orderTransferResults).to.equal(OrderTransferResults.TransfersSuccessful); | ||||
|         }); | ||||
|     }); | ||||
|     describe('getSimulatedOrdersTransferResults', async () => { | ||||
|         it('should simulate the transfers of each order independently from one another', async () => { | ||||
|             // Set balances and allowances to exactly enough to fill a single order | ||||
|             await erc20Token2.setBalance.awaitTransactionSuccessAsync(takerAddress, signedOrder.takerAssetAmount, { | ||||
|                 from: owner, | ||||
|             }); | ||||
|             await erc20Token2.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.takerAssetAmount, { | ||||
|                 from: takerAddress, | ||||
|             }); | ||||
|             await erc20Token.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerAssetAmount, { | ||||
|                 from: owner, | ||||
|             }); | ||||
|             await erc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerAssetAmount, { | ||||
|                 from: makerAddress, | ||||
|             }); | ||||
|             await feeErc20Token.setBalance.awaitTransactionSuccessAsync(takerAddress, signedOrder.takerFee, { | ||||
|                 from: owner, | ||||
|             }); | ||||
|             await feeErc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.takerFee, { | ||||
|                 from: takerAddress, | ||||
|             }); | ||||
|             await feeErc20Token.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerFee, { | ||||
|                 from: owner, | ||||
|             }); | ||||
|             await feeErc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerFee, { | ||||
|                 from: makerAddress, | ||||
|             }); | ||||
|             const [ | ||||
|                 orderTransferResults1, | ||||
|                 orderTransferResults2, | ||||
|             ] = await devUtils.getSimulatedOrdersTransferResults.callAsync( | ||||
|                 [signedOrder, signedOrder], | ||||
|                 [takerAddress, takerAddress], | ||||
|                 [signedOrder.takerAssetAmount, signedOrder.takerAssetAmount], | ||||
|             ); | ||||
|             expect(orderTransferResults1).to.equal(OrderTransferResults.TransfersSuccessful); | ||||
|             expect(orderTransferResults2).to.equal(OrderTransferResults.TransfersSuccessful); | ||||
|         }); | ||||
|     }); | ||||
| }); | ||||
| // tslint:disable:max-file-line-count | ||||
							
								
								
									
										11
									
								
								contracts/dev-utils/test/wrappers.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								contracts/dev-utils/test/wrappers.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| /* | ||||
|  * ----------------------------------------------------------------------------- | ||||
|  * Warning: This file is auto-generated by contracts-gen. Don't edit manually. | ||||
|  * ----------------------------------------------------------------------------- | ||||
|  */ | ||||
| export * from '../test/generated-wrappers/dev_utils'; | ||||
| export * from '../test/generated-wrappers/eth_balance_checker'; | ||||
| export * from '../test/generated-wrappers/lib_asset_data'; | ||||
| 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'; | ||||
| @@ -4,11 +4,14 @@ | ||||
|     "include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"], | ||||
|     "files": [ | ||||
|         "generated-artifacts/DevUtils.json", | ||||
|         "generated-artifacts/EthBalanceChecker.json", | ||||
|         "generated-artifacts/LibAssetData.json", | ||||
|         "generated-artifacts/LibTransactionDecoder.json", | ||||
|         "generated-artifacts/OrderTransferSimulationUtils.json", | ||||
|         "generated-artifacts/OrderValidationUtils.json" | ||||
|         "test/generated-artifacts/DevUtils.json", | ||||
|         "test/generated-artifacts/EthBalanceChecker.json", | ||||
|         "test/generated-artifacts/LibAssetData.json", | ||||
|         "test/generated-artifacts/LibTransactionDecoder.json", | ||||
|         "test/generated-artifacts/OrderTransferSimulationUtils.json", | ||||
|         "test/generated-artifacts/OrderValidationUtils.json" | ||||
|     ], | ||||
|     "exclude": ["./deploy/solc/solc_bin"] | ||||
| } | ||||
|   | ||||
							
								
								
									
										10
									
								
								contracts/erc1155/.npmignore
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								contracts/erc1155/.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 | ||||
| @@ -1,10 +1,33 @@ | ||||
| [ | ||||
|     { | ||||
|         "version": "1.2.0-beta.2", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils", | ||||
|                 "pr": 2330 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1574030254 | ||||
|     }, | ||||
|     { | ||||
|         "version": "1.2.0-beta.1", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1573159180 | ||||
|     }, | ||||
|     { | ||||
|         "version": "1.2.0-beta.0", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Add `mintKnownFungibleTokensAsync()`, `isNonFungibleItemAsync()`, `isFungibleItemAsync()`, `getOwnerOfAsync()`, `getBalanceAsync()` to `Erc1155Wrapper`.", | ||||
|                 "pr": 1819 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Replaced `SafeMath` with `LibSafeMath`", | ||||
|                 "pr": 2254 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1570135330 | ||||
|   | ||||
| @@ -5,9 +5,18 @@ Edit the package's CHANGELOG.json file only. | ||||
|  | ||||
| CHANGELOG | ||||
|  | ||||
| ## v1.2.0-beta.2 - _November 17, 2019_ | ||||
|  | ||||
|     * Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils (#2330) | ||||
|  | ||||
| ## v1.2.0-beta.1 - _November 7, 2019_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v1.2.0-beta.0 - _October 3, 2019_ | ||||
|  | ||||
|     * Add `mintKnownFungibleTokensAsync()`, `isNonFungibleItemAsync()`, `isFungibleItemAsync()`, `getOwnerOfAsync()`, `getBalanceAsync()` to `Erc1155Wrapper`. (#1819) | ||||
|     * Replaced `SafeMath` with `LibSafeMath` (#2254) | ||||
|  | ||||
| ## v1.1.15 - _September 17, 2019_ | ||||
|  | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| { | ||||
|     "artifactsDir": "./generated-artifacts", | ||||
|     "artifactsDir": "./test/generated-artifacts", | ||||
|     "contractsDir": "./contracts", | ||||
|     "useDockerisedSolc": false, | ||||
|     "isOfflineMode": false, | ||||
|   | ||||
| @@ -18,7 +18,7 @@ | ||||
|  | ||||
| pragma solidity ^0.5.9; | ||||
|  | ||||
| import "@0x/contracts-utils/contracts/src/SafeMath.sol"; | ||||
| import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; | ||||
| import "@0x/contracts-utils/contracts/src/LibAddress.sol"; | ||||
| import "./interfaces/IERC1155.sol"; | ||||
| import "./interfaces/IERC1155Receiver.sol"; | ||||
| @@ -26,11 +26,11 @@ import "./MixinNonFungibleToken.sol"; | ||||
|  | ||||
|  | ||||
| contract ERC1155 is | ||||
|     SafeMath, | ||||
|     IERC1155, | ||||
|     MixinNonFungibleToken | ||||
| { | ||||
|     using LibAddress for address; | ||||
|     using LibSafeMath for uint256; | ||||
|  | ||||
|     // selectors for receiver callbacks | ||||
|     bytes4 constant public ERC1155_RECEIVED       = 0xf23a6e61; | ||||
| @@ -88,11 +88,11 @@ contract ERC1155 is | ||||
|             nfOwners[id] = to; | ||||
|             // You could keep balance of NF type in base type id like so: | ||||
|             // uint256 baseType = getNonFungibleBaseType(_id); | ||||
|             // balances[baseType][_from] = balances[baseType][_from]._safeSub(_value); | ||||
|             // balances[baseType][_to]   = balances[baseType][_to]._safeAdd(_value); | ||||
|             // balances[baseType][_from] = balances[baseType][_from].safeSub(_value); | ||||
|             // balances[baseType][_to]   = balances[baseType][_to].safeAdd(_value); | ||||
|         } else { | ||||
|             balances[id][from] = _safeSub(balances[id][from], value); | ||||
|             balances[id][to] = _safeAdd(balances[id][to], value); | ||||
|             balances[id][from] = balances[id][from].safeSub(value); | ||||
|             balances[id][to] = balances[id][to].safeAdd(value); | ||||
|         } | ||||
|         emit TransferSingle(msg.sender, from, to, id, value); | ||||
|  | ||||
| @@ -170,8 +170,8 @@ contract ERC1155 is | ||||
|                 ); | ||||
|                 nfOwners[id] = to; | ||||
|             } else { | ||||
|                 balances[id][from] = _safeSub(balances[id][from], value); | ||||
|                 balances[id][to] = _safeAdd(balances[id][to], value); | ||||
|                 balances[id][from] = balances[id][from].safeSub(value); | ||||
|                 balances[id][to] = balances[id][to].safeAdd(value); | ||||
|             } | ||||
|         } | ||||
|         emit TransferBatch(msg.sender, from, to, ids, values); | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| pragma solidity ^0.5.9; | ||||
|  | ||||
| import "@0x/contracts-utils/contracts/src/SafeMath.sol"; | ||||
| import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; | ||||
| import "./ERC1155.sol"; | ||||
| import "./interfaces/IERC1155Mintable.sol"; | ||||
|  | ||||
| @@ -11,6 +11,7 @@ contract ERC1155Mintable is | ||||
|     IERC1155Mintable, | ||||
|     ERC1155 | ||||
| { | ||||
|     using LibSafeMath for uint256; | ||||
|  | ||||
|     /// token nonce | ||||
|     uint256 internal nonce; | ||||
| @@ -37,7 +38,7 @@ contract ERC1155Mintable is | ||||
|     ) | ||||
|         external | ||||
|         returns (uint256 type_) | ||||
|     {  | ||||
|     { | ||||
|         // Store the type in the upper 128 bits | ||||
|         type_ = (++nonce << 128); | ||||
|  | ||||
| @@ -114,7 +115,7 @@ contract ERC1155Mintable is | ||||
|             uint256 quantity = quantities[i]; | ||||
|  | ||||
|             // Grant the items to the caller | ||||
|             balances[id][dst] = _safeAdd(quantity, balances[id][dst]); | ||||
|             balances[id][dst] = quantity.safeAdd(balances[id][dst]); | ||||
|  | ||||
|             // Emit the Transfer/Mint event. | ||||
|             // the 0x0 source address implies a mint | ||||
| @@ -172,7 +173,7 @@ contract ERC1155Mintable is | ||||
|             nfOwners[id] = dst; | ||||
|  | ||||
|             // You could use base-type id to store NF type balances if you wish. | ||||
|             // balances[_type][dst] = quantity._safeAdd(balances[_type][dst]); | ||||
|             // balances[_type][dst] = quantity.safeAdd(balances[_type][dst]); | ||||
|  | ||||
|             emit TransferSingle(msg.sender, address(0x0), dst, id, 1); | ||||
|  | ||||
| @@ -194,6 +195,6 @@ contract ERC1155Mintable is | ||||
|  | ||||
|         // record the `maxIndex` of this nft type | ||||
|         // this allows us to mint more nft's of this type in a subsequent call. | ||||
|         maxIndex[type_] = _safeAdd(to.length, maxIndex[type_]); | ||||
|         maxIndex[type_] = to.length.safeAdd(maxIndex[type_]); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "name": "@0x/contracts-erc1155", | ||||
|     "version": "1.2.0-beta.0", | ||||
|     "version": "1.2.0-beta.2", | ||||
|     "engines": { | ||||
|         "node": ">=6.12" | ||||
|     }, | ||||
| @@ -12,7 +12,7 @@ | ||||
|     "scripts": { | ||||
|         "build": "yarn pre_build && tsc -b", | ||||
|         "build:ci": "yarn build", | ||||
|         "pre_build": "run-s compile contracts:gen generate_contract_wrappers", | ||||
|         "pre_build": "run-s compile contracts:gen generate_contract_wrappers contracts:copy", | ||||
|         "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", | ||||
| @@ -21,21 +21,23 @@ | ||||
|         "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 generated-artifacts generated-wrappers", | ||||
|         "generate_contract_wrappers": "abi-gen --abis  ${npm_package_config_abis} --output generated-wrappers --backend ethers", | ||||
|         "lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts", | ||||
|         "fix": "tslint --fix --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts", | ||||
|         "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", | ||||
|         "fix": "tslint --fix --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", | ||||
|         "contracts:gen": "contracts-gen generate", | ||||
|         "contracts:copy": "contracts-gen copy", | ||||
|         "lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol", | ||||
|         "compile:truffle": "truffle compile" | ||||
|     }, | ||||
|     "config": { | ||||
|         "abis": "./generated-artifacts/@(DummyERC1155Receiver|ERC1155|ERC1155Mintable|IERC1155|IERC1155Mintable|IERC1155Receiver|MixinNonFungibleToken).json", | ||||
|         "publicInterfaceContracts": "ERC1155,ERC1155Mintable,IERC1155Receiver,DummyERC1155Receiver", | ||||
|         "abis": "./test/generated-artifacts/@(DummyERC1155Receiver|ERC1155|ERC1155Mintable|IERC1155|IERC1155Mintable|IERC1155Receiver|MixinNonFungibleToken).json", | ||||
|         "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually." | ||||
|     }, | ||||
|     "repository": { | ||||
| @@ -48,11 +50,13 @@ | ||||
|     }, | ||||
|     "homepage": "https://github.com/0xProject/0x-monorepo/contracts/tokens/README.md", | ||||
|     "devDependencies": { | ||||
|         "@0x/abi-gen": "^4.3.0-beta.0", | ||||
|         "@0x/contracts-gen": "^1.1.0-beta.0", | ||||
|         "@0x/dev-utils": "^2.4.0-beta.0", | ||||
|         "@0x/sol-compiler": "^3.2.0-beta.0", | ||||
|         "@0x/tslint-config": "^3.0.1", | ||||
|         "@0x/abi-gen": "^4.4.0-beta.2", | ||||
|         "@0x/contracts-gen": "^1.1.0-beta.2", | ||||
|         "@0x/contracts-utils": "^3.3.0-beta.2", | ||||
|         "@0x/dev-utils": "^2.4.0-beta.2", | ||||
|         "@0x/sol-compiler": "^3.2.0-beta.2", | ||||
|         "@0x/tslint-config": "^3.1.0-beta.2", | ||||
|         "@0x/types": "^2.5.0-beta.2", | ||||
|         "@types/lodash": "4.14.104", | ||||
|         "@types/mocha": "^5.2.7", | ||||
|         "@types/node": "*", | ||||
| @@ -70,14 +74,12 @@ | ||||
|         "typescript": "3.0.1" | ||||
|     }, | ||||
|     "dependencies": { | ||||
|         "@0x/base-contract": "^5.5.0-beta.0", | ||||
|         "@0x/contracts-test-utils": "^3.2.0-beta.0", | ||||
|         "@0x/contracts-utils": "^3.3.0-beta.0", | ||||
|         "@0x/types": "^2.5.0-beta.0", | ||||
|         "@0x/typescript-typings": "^4.4.0-beta.0", | ||||
|         "@0x/utils": "^4.6.0-beta.0", | ||||
|         "@0x/web3-wrapper": "^6.1.0-beta.0", | ||||
|         "ethereum-types": "^2.2.0-beta.0", | ||||
|         "@0x/base-contract": "^5.5.0-beta.2", | ||||
|         "@0x/contracts-test-utils": "^3.2.0-beta.2", | ||||
|         "@0x/typescript-typings": "^4.4.0-beta.2", | ||||
|         "@0x/utils": "^4.6.0-beta.2", | ||||
|         "@0x/web3-wrapper": "^6.1.0-beta.2", | ||||
|         "ethereum-types": "^2.2.0-beta.2", | ||||
|         "lodash": "^4.17.11" | ||||
|     }, | ||||
|     "publishConfig": { | ||||
|   | ||||
| @@ -8,16 +8,10 @@ import { ContractArtifact } from 'ethereum-types'; | ||||
| import * as DummyERC1155Receiver from '../generated-artifacts/DummyERC1155Receiver.json'; | ||||
| import * as ERC1155 from '../generated-artifacts/ERC1155.json'; | ||||
| import * as ERC1155Mintable from '../generated-artifacts/ERC1155Mintable.json'; | ||||
| import * as IERC1155 from '../generated-artifacts/IERC1155.json'; | ||||
| import * as IERC1155Mintable from '../generated-artifacts/IERC1155Mintable.json'; | ||||
| import * as IERC1155Receiver from '../generated-artifacts/IERC1155Receiver.json'; | ||||
| import * as MixinNonFungibleToken from '../generated-artifacts/MixinNonFungibleToken.json'; | ||||
| export const artifacts = { | ||||
|     ERC1155: ERC1155 as ContractArtifact, | ||||
|     ERC1155Mintable: ERC1155Mintable as ContractArtifact, | ||||
|     MixinNonFungibleToken: MixinNonFungibleToken as ContractArtifact, | ||||
|     IERC1155: IERC1155 as ContractArtifact, | ||||
|     IERC1155Mintable: IERC1155Mintable as ContractArtifact, | ||||
|     IERC1155Receiver: IERC1155Receiver as ContractArtifact, | ||||
|     DummyERC1155Receiver: DummyERC1155Receiver as ContractArtifact, | ||||
| }; | ||||
|   | ||||
| @@ -1,11 +1,13 @@ | ||||
| import { constants, LogDecoder } from '@0x/contracts-test-utils'; | ||||
| import { LogDecoder } from '@0x/contracts-test-utils'; | ||||
| import { BigNumber } from '@0x/utils'; | ||||
| import { Web3Wrapper } from '@0x/web3-wrapper'; | ||||
| import * as chai from 'chai'; | ||||
| import { LogWithDecodedArgs, Provider, TransactionReceiptWithDecodedLogs } from 'ethereum-types'; | ||||
| import * as _ from 'lodash'; | ||||
| 
 | ||||
| import { artifacts, ERC1155MintableContract, ERC1155TransferSingleEventArgs } from '../../src'; | ||||
| import { ERC1155MintableContract, ERC1155TransferSingleEventArgs } from './wrappers'; | ||||
| 
 | ||||
| import { artifacts } from './artifacts'; | ||||
| 
 | ||||
| const expect = chai.expect; | ||||
| 
 | ||||
| @@ -25,7 +27,7 @@ export class Erc1155Wrapper { | ||||
|         return this._erc1155Contract; | ||||
|     } | ||||
|     public async getBalancesAsync(owners: string[], tokens: BigNumber[]): Promise<BigNumber[]> { | ||||
|         const balances = await this._erc1155Contract.balanceOfBatch.callAsync(owners, tokens); | ||||
|         const balances = await this._erc1155Contract.balanceOfBatch(owners, tokens).callAsync(); | ||||
|         return balances; | ||||
|     } | ||||
|     public async safeTransferFromAsync( | ||||
| @@ -39,7 +41,7 @@ export class Erc1155Wrapper { | ||||
|         const spender = delegatedSpender === undefined ? from : delegatedSpender; | ||||
|         const callbackDataHex = callbackData === undefined ? '0x' : callbackData; | ||||
|         const tx = await this._logDecoder.getTxWithDecodedLogsAsync( | ||||
|             await this._erc1155Contract.safeTransferFrom.sendTransactionAsync(from, to, token, value, callbackDataHex, { | ||||
|             await this._erc1155Contract.safeTransferFrom(from, to, token, value, callbackDataHex).sendTransactionAsync({ | ||||
|                 from: spender, | ||||
|             }), | ||||
|         ); | ||||
| @@ -56,14 +58,9 @@ export class Erc1155Wrapper { | ||||
|         const spender = delegatedSpender === undefined ? from : delegatedSpender; | ||||
|         const callbackDataHex = callbackData === undefined ? '0x' : callbackData; | ||||
|         const tx = await this._logDecoder.getTxWithDecodedLogsAsync( | ||||
|             await this._erc1155Contract.safeBatchTransferFrom.sendTransactionAsync( | ||||
|                 from, | ||||
|                 to, | ||||
|                 tokens, | ||||
|                 values, | ||||
|                 callbackDataHex, | ||||
|                 { from: spender }, | ||||
|             ), | ||||
|             await this._erc1155Contract | ||||
|                 .safeBatchTransferFrom(from, to, tokens, values, callbackDataHex) | ||||
|                 .sendTransactionAsync({ from: spender }), | ||||
|         ); | ||||
|         return tx; | ||||
|     } | ||||
| @@ -74,7 +71,7 @@ export class Erc1155Wrapper { | ||||
|         const tokenUri = 'dummyFungibleToken'; | ||||
|         const tokenIsNonFungible = false; | ||||
|         const tx = await this._logDecoder.getTxWithDecodedLogsAsync( | ||||
|             await this._erc1155Contract.create.sendTransactionAsync(tokenUri, tokenIsNonFungible, { | ||||
|             await this._erc1155Contract.create(tokenUri, tokenIsNonFungible).sendTransactionAsync({ | ||||
|                 from: this._contractOwner, | ||||
|             }), | ||||
|         ); | ||||
| @@ -95,31 +92,24 @@ export class Erc1155Wrapper { | ||||
|                 tokenAmountsAsArray.push(tokenAmounts); | ||||
|             }); | ||||
|         } | ||||
|         await this._erc1155Contract.mintFungible.awaitTransactionSuccessAsync( | ||||
|             tokenId, | ||||
|             beneficiaries, | ||||
|             tokenAmountsAsArray, | ||||
|             { from: this._contractOwner }, | ||||
|             constants.AWAIT_TRANSACTION_MINED_MS, | ||||
|         ); | ||||
|         await this._erc1155Contract | ||||
|             .mintFungible(tokenId, beneficiaries, tokenAmountsAsArray) | ||||
|             .awaitTransactionSuccessAsync({ from: this._contractOwner }); | ||||
|     } | ||||
|     public async mintNonFungibleTokensAsync(beneficiaries: string[]): Promise<[BigNumber, BigNumber[]]> { | ||||
|         const tokenUri = 'dummyNonFungibleToken'; | ||||
|         const tokenIsNonFungible = true; | ||||
|         const tx = await this._logDecoder.getTxWithDecodedLogsAsync( | ||||
|             await this._erc1155Contract.create.sendTransactionAsync(tokenUri, tokenIsNonFungible, { | ||||
|             await this._erc1155Contract.create(tokenUri, tokenIsNonFungible).sendTransactionAsync({ | ||||
|                 from: this._contractOwner, | ||||
|             }), | ||||
|         ); | ||||
|         // tslint:disable-next-line no-unnecessary-type-assertion
 | ||||
|         const createFungibleTokenLog = tx.logs[0] as LogWithDecodedArgs<ERC1155TransferSingleEventArgs>; | ||||
|         const token = createFungibleTokenLog.args.id; | ||||
|         await this._erc1155Contract.mintNonFungible.awaitTransactionSuccessAsync( | ||||
|             token, | ||||
|             beneficiaries, | ||||
|             { from: this._contractOwner }, | ||||
|             constants.AWAIT_TRANSACTION_MINED_MS, | ||||
|         ); | ||||
|         await this._erc1155Contract.mintNonFungible(token, beneficiaries).awaitTransactionSuccessAsync({ | ||||
|             from: this._contractOwner, | ||||
|         }); | ||||
|         const encodedNftIds: BigNumber[] = []; | ||||
|         const nftIdBegin = 1; | ||||
|         const nftIdEnd = beneficiaries.length + 1; | ||||
| @@ -136,14 +126,14 @@ export class Erc1155Wrapper { | ||||
|         isApproved: boolean, | ||||
|     ): Promise<TransactionReceiptWithDecodedLogs> { | ||||
|         const tx = await this._logDecoder.getTxWithDecodedLogsAsync( | ||||
|             await this._erc1155Contract.setApprovalForAll.sendTransactionAsync(beneficiary, isApproved, { | ||||
|             await this._erc1155Contract.setApprovalForAll(beneficiary, isApproved).sendTransactionAsync({ | ||||
|                 from: owner, | ||||
|             }), | ||||
|         ); | ||||
|         return tx; | ||||
|     } | ||||
|     public async isApprovedForAllAsync(owner: string, beneficiary: string): Promise<boolean> { | ||||
|         const isApprovedForAll = await this._erc1155Contract.isApprovedForAll.callAsync(owner, beneficiary); | ||||
|         const isApprovedForAll = await this._erc1155Contract.isApprovedForAll(owner, beneficiary).callAsync(); | ||||
|         return isApprovedForAll; | ||||
|     } | ||||
|     public async assertBalancesAsync( | ||||
| @@ -165,18 +155,18 @@ export class Erc1155Wrapper { | ||||
|         }); | ||||
|     } | ||||
|     public async isNonFungibleItemAsync(tokenId: BigNumber): Promise<boolean> { | ||||
|         return this._erc1155Contract.isNonFungibleItem.callAsync(tokenId); | ||||
|         return this._erc1155Contract.isNonFungibleItem(tokenId).callAsync(); | ||||
|     } | ||||
|     public async isFungibleItemAsync(tokenId: BigNumber): Promise<boolean> { | ||||
|         return !(await this.isNonFungibleItemAsync(tokenId)); | ||||
|     } | ||||
|     public async getOwnerOfAsync(tokenId: BigNumber): Promise<string> { | ||||
|         return this._erc1155Contract.ownerOf.callAsync(tokenId); | ||||
|         return this._erc1155Contract.ownerOf(tokenId).callAsync(); | ||||
|     } | ||||
|     /** | ||||
|      * @dev Get the balance of an ERC1155 token for a given owner and token ID. | ||||
|      */ | ||||
|     public async getBalanceAsync(ownerAddress: string, tokenId: BigNumber): Promise<BigNumber> { | ||||
|         return this._erc1155Contract.balanceOf.callAsync(ownerAddress, tokenId); | ||||
|         return this._erc1155Contract.balanceOf(ownerAddress, tokenId).callAsync(); | ||||
|     } | ||||
| } | ||||
| @@ -1,3 +1,3 @@ | ||||
| export * from './wrappers'; | ||||
| export * from './artifacts'; | ||||
| export { Erc1155Wrapper } from '../test/utils/erc1155_wrapper'; | ||||
| export { Erc1155Wrapper } from './erc1155_wrapper'; | ||||
|   | ||||
| @@ -6,7 +6,4 @@ | ||||
| export * from '../generated-wrappers/dummy_erc1155_receiver'; | ||||
| export * from '../generated-wrappers/erc1155'; | ||||
| export * from '../generated-wrappers/erc1155_mintable'; | ||||
| export * from '../generated-wrappers/i_erc1155_mintable'; | ||||
| export * from '../generated-wrappers/i_erc1155_receiver'; | ||||
| export * from '../generated-wrappers/ierc1155'; | ||||
| export * from '../generated-wrappers/mixin_non_fungible_token'; | ||||
|   | ||||
							
								
								
									
										23
									
								
								contracts/erc1155/test/artifacts.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								contracts/erc1155/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 DummyERC1155Receiver from '../test/generated-artifacts/DummyERC1155Receiver.json'; | ||||
| import * as ERC1155 from '../test/generated-artifacts/ERC1155.json'; | ||||
| import * as ERC1155Mintable from '../test/generated-artifacts/ERC1155Mintable.json'; | ||||
| import * as IERC1155 from '../test/generated-artifacts/IERC1155.json'; | ||||
| import * as IERC1155Mintable from '../test/generated-artifacts/IERC1155Mintable.json'; | ||||
| import * as IERC1155Receiver from '../test/generated-artifacts/IERC1155Receiver.json'; | ||||
| import * as MixinNonFungibleToken from '../test/generated-artifacts/MixinNonFungibleToken.json'; | ||||
| export const artifacts = { | ||||
|     ERC1155: ERC1155 as ContractArtifact, | ||||
|     ERC1155Mintable: ERC1155Mintable as ContractArtifact, | ||||
|     MixinNonFungibleToken: MixinNonFungibleToken as ContractArtifact, | ||||
|     IERC1155: IERC1155 as ContractArtifact, | ||||
|     IERC1155Mintable: IERC1155Mintable as ContractArtifact, | ||||
|     IERC1155Receiver: IERC1155Receiver as ContractArtifact, | ||||
|     DummyERC1155Receiver: DummyERC1155Receiver as ContractArtifact, | ||||
| }; | ||||
| @@ -6,21 +6,19 @@ import { | ||||
|     txDefaults, | ||||
|     web3Wrapper, | ||||
| } from '@0x/contracts-test-utils'; | ||||
| import { SafeMathRevertErrors } from '@0x/contracts-utils'; | ||||
| import { BlockchainLifecycle } from '@0x/dev-utils'; | ||||
| import { RevertReason } from '@0x/types'; | ||||
| import { BigNumber, SafeMathRevertErrors } from '@0x/utils'; | ||||
| import { BigNumber } from '@0x/utils'; | ||||
| import * as chai from 'chai'; | ||||
| import { LogWithDecodedArgs } from 'ethereum-types'; | ||||
| import * as _ from 'lodash'; | ||||
|  | ||||
| import { | ||||
|     artifacts, | ||||
|     DummyERC1155ReceiverBatchTokenReceivedEventArgs, | ||||
|     DummyERC1155ReceiverContract, | ||||
|     ERC1155MintableContract, | ||||
| } from '../src'; | ||||
| import { Erc1155Wrapper } from '../src/erc1155_wrapper'; | ||||
| import { ERC1155MintableContract } from '../src/wrappers'; | ||||
|  | ||||
| import { Erc1155Wrapper } from './utils/erc1155_wrapper'; | ||||
| import { artifacts } from './artifacts'; | ||||
| import { DummyERC1155ReceiverBatchTokenReceivedEventArgs, DummyERC1155ReceiverContract } from './wrappers'; | ||||
| chaiSetup.configure(); | ||||
| const expect = chai.expect; | ||||
| const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); | ||||
| @@ -179,14 +177,9 @@ describe('ERC1155Token', () => { | ||||
|                 valueToTransfer, | ||||
|             ); | ||||
|             // execute transfer | ||||
|             const tx = erc1155Contract.safeTransferFrom.sendTransactionAsync( | ||||
|                 spender, | ||||
|                 receiver, | ||||
|                 tokenToTransfer, | ||||
|                 valueToTransfer, | ||||
|                 receiverCallbackData, | ||||
|                 { from: spender }, | ||||
|             ); | ||||
|             const tx = erc1155Contract | ||||
|                 .safeTransferFrom(spender, receiver, tokenToTransfer, valueToTransfer, receiverCallbackData) | ||||
|                 .sendTransactionAsync({ from: spender }); | ||||
|             return expect(tx).to.revertWith(expectedError); | ||||
|         }); | ||||
|         it('should revert if callback reverts', async () => { | ||||
| @@ -196,19 +189,14 @@ describe('ERC1155Token', () => { | ||||
|             // set receiver to reject balances | ||||
|             const shouldRejectTransfer = true; | ||||
|             await web3Wrapper.awaitTransactionSuccessAsync( | ||||
|                 await erc1155Receiver.setRejectTransferFlag.sendTransactionAsync(shouldRejectTransfer), | ||||
|                 await erc1155Receiver.setRejectTransferFlag(shouldRejectTransfer).sendTransactionAsync(), | ||||
|                 constants.AWAIT_TRANSACTION_MINED_MS, | ||||
|             ); | ||||
|             // execute transfer | ||||
|             await expectTransactionFailedAsync( | ||||
|                 erc1155Contract.safeTransferFrom.sendTransactionAsync( | ||||
|                     spender, | ||||
|                     receiver, | ||||
|                     tokenToTransfer, | ||||
|                     valueToTransfer, | ||||
|                     receiverCallbackData, | ||||
|                     { from: spender }, | ||||
|                 ), | ||||
|                 erc1155Contract | ||||
|                     .safeTransferFrom(spender, receiver, tokenToTransfer, valueToTransfer, receiverCallbackData) | ||||
|                     .sendTransactionAsync({ from: spender }), | ||||
|                 RevertReason.TransferRejected, | ||||
|             ); | ||||
|         }); | ||||
| @@ -355,14 +343,9 @@ describe('ERC1155Token', () => { | ||||
|                 valuesToTransfer[0], | ||||
|             ); | ||||
|             // execute transfer | ||||
|             const tx = erc1155Contract.safeBatchTransferFrom.sendTransactionAsync( | ||||
|                 spender, | ||||
|                 receiver, | ||||
|                 tokensToTransfer, | ||||
|                 valuesToTransfer, | ||||
|                 receiverCallbackData, | ||||
|                 { from: spender }, | ||||
|             ); | ||||
|             const tx = erc1155Contract | ||||
|                 .safeBatchTransferFrom(spender, receiver, tokensToTransfer, valuesToTransfer, receiverCallbackData) | ||||
|                 .sendTransactionAsync({ from: spender }); | ||||
|             return expect(tx).to.revertWith(expectedError); | ||||
|         }); | ||||
|         it('should revert if callback reverts', async () => { | ||||
| @@ -372,19 +355,14 @@ describe('ERC1155Token', () => { | ||||
|             // set receiver to reject balances | ||||
|             const shouldRejectTransfer = true; | ||||
|             await web3Wrapper.awaitTransactionSuccessAsync( | ||||
|                 await erc1155Receiver.setRejectTransferFlag.sendTransactionAsync(shouldRejectTransfer), | ||||
|                 await erc1155Receiver.setRejectTransferFlag(shouldRejectTransfer).sendTransactionAsync(), | ||||
|                 constants.AWAIT_TRANSACTION_MINED_MS, | ||||
|             ); | ||||
|             // execute transfer | ||||
|             await expectTransactionFailedAsync( | ||||
|                 erc1155Contract.safeBatchTransferFrom.sendTransactionAsync( | ||||
|                     spender, | ||||
|                     receiver, | ||||
|                     tokensToTransfer, | ||||
|                     valuesToTransfer, | ||||
|                     receiverCallbackData, | ||||
|                     { from: spender }, | ||||
|                 ), | ||||
|                 erc1155Contract | ||||
|                     .safeBatchTransferFrom(spender, receiver, tokensToTransfer, valuesToTransfer, receiverCallbackData) | ||||
|                     .sendTransactionAsync({ from: spender }), | ||||
|                 RevertReason.TransferRejected, | ||||
|             ); | ||||
|         }); | ||||
| @@ -432,14 +410,9 @@ describe('ERC1155Token', () => { | ||||
|             await erc1155Wrapper.assertBalancesAsync(tokenHolders, [tokenToTransfer], expectedInitialBalances); | ||||
|             // execute transfer | ||||
|             await expectTransactionFailedAsync( | ||||
|                 erc1155Contract.safeTransferFrom.sendTransactionAsync( | ||||
|                     spender, | ||||
|                     receiver, | ||||
|                     tokenToTransfer, | ||||
|                     valueToTransfer, | ||||
|                     receiverCallbackData, | ||||
|                     { from: delegatedSpender }, | ||||
|                 ), | ||||
|                 erc1155Contract | ||||
|                     .safeTransferFrom(spender, receiver, tokenToTransfer, valueToTransfer, receiverCallbackData) | ||||
|                     .sendTransactionAsync({ from: delegatedSpender }), | ||||
|                 RevertReason.InsufficientAllowance, | ||||
|             ); | ||||
|         }); | ||||
| @@ -485,14 +458,9 @@ describe('ERC1155Token', () => { | ||||
|             await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); | ||||
|             // execute transfer | ||||
|             await expectTransactionFailedAsync( | ||||
|                 erc1155Contract.safeBatchTransferFrom.sendTransactionAsync( | ||||
|                     spender, | ||||
|                     receiver, | ||||
|                     tokensToTransfer, | ||||
|                     valuesToTransfer, | ||||
|                     receiverCallbackData, | ||||
|                     { from: delegatedSpender }, | ||||
|                 ), | ||||
|                 erc1155Contract | ||||
|                     .safeBatchTransferFrom(spender, receiver, tokensToTransfer, valuesToTransfer, receiverCallbackData) | ||||
|                     .sendTransactionAsync({ from: delegatedSpender }), | ||||
|                 RevertReason.InsufficientAllowance, | ||||
|             ); | ||||
|         }); | ||||
|   | ||||
							
								
								
									
										12
									
								
								contracts/erc1155/test/wrappers.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								contracts/erc1155/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/dummy_erc1155_receiver'; | ||||
| export * from '../test/generated-wrappers/erc1155'; | ||||
| export * from '../test/generated-wrappers/erc1155_mintable'; | ||||
| export * from '../test/generated-wrappers/i_erc1155_mintable'; | ||||
| export * from '../test/generated-wrappers/i_erc1155_receiver'; | ||||
| export * from '../test/generated-wrappers/ierc1155'; | ||||
| export * from '../test/generated-wrappers/mixin_non_fungible_token'; | ||||
| @@ -6,10 +6,14 @@ | ||||
|         "generated-artifacts/DummyERC1155Receiver.json", | ||||
|         "generated-artifacts/ERC1155.json", | ||||
|         "generated-artifacts/ERC1155Mintable.json", | ||||
|         "generated-artifacts/IERC1155.json", | ||||
|         "generated-artifacts/IERC1155Mintable.json", | ||||
|         "generated-artifacts/IERC1155Receiver.json", | ||||
|         "generated-artifacts/MixinNonFungibleToken.json" | ||||
|         "test/generated-artifacts/DummyERC1155Receiver.json", | ||||
|         "test/generated-artifacts/ERC1155.json", | ||||
|         "test/generated-artifacts/ERC1155Mintable.json", | ||||
|         "test/generated-artifacts/IERC1155.json", | ||||
|         "test/generated-artifacts/IERC1155Mintable.json", | ||||
|         "test/generated-artifacts/IERC1155Receiver.json", | ||||
|         "test/generated-artifacts/MixinNonFungibleToken.json" | ||||
|     ], | ||||
|     "exclude": ["./deploy/solc/solc_bin"] | ||||
| } | ||||
|   | ||||
							
								
								
									
										10
									
								
								contracts/erc20/.npmignore
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								contracts/erc20/.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 | ||||
| @@ -1,9 +1,33 @@ | ||||
| [ | ||||
|     { | ||||
|         "version": "2.3.0-beta.2", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils", | ||||
|                 "pr": 2330 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1574030254 | ||||
|     }, | ||||
|     { | ||||
|         "version": "2.3.0-beta.1", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Create `LibERC20Token`", | ||||
|                 "pr": 2309 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1573159180 | ||||
|     }, | ||||
|     { | ||||
|         "version": "2.3.0-beta.0", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Replaced `SafeMath` with `LibSafeMath`", | ||||
|                 "pr": 2254 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1570135330 | ||||
|   | ||||
| @@ -5,9 +5,18 @@ Edit the package's CHANGELOG.json file only. | ||||
|  | ||||
| CHANGELOG | ||||
|  | ||||
| ## v2.3.0-beta.2 - _November 17, 2019_ | ||||
|  | ||||
|     * Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils (#2330) | ||||
|  | ||||
| ## v2.3.0-beta.1 - _November 7, 2019_ | ||||
|  | ||||
|     * Create `LibERC20Token` (#2309) | ||||
|  | ||||
| ## v2.3.0-beta.0 - _October 3, 2019_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|     * Replaced `SafeMath` with `LibSafeMath` (#2254) | ||||
|  | ||||
| ## v2.2.14 - _September 17, 2019_ | ||||
|  | ||||
|   | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user