Compare commits
	
		
			1428 Commits
		
	
	
		
			@0x/sol-do
			...
			@0x/typesc
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | c60d1e50c5 | ||
|  | 501f5ad3de | ||
|  | 9fe6c196ad | ||
|  | 6d462b0598 | ||
|  | 3832c66ad0 | ||
|  | 57028069c0 | ||
|  | 8d84ac9cf8 | ||
|  | 17219d22c3 | ||
|  | bf4005b0ee | ||
|  | d8605ed91d | ||
|  | f18e2a09e6 | ||
|  | d5c0f5aa47 | ||
|  | 2825a201cd | ||
|  | 2d69afec86 | ||
|  | 851e4bfbea | ||
|  | c63745c2ce | ||
|  | 95f11f2d0e | ||
|  | 30417fbf24 | ||
|  | 06f095ca23 | ||
|  | 30141ca6cf | ||
|  | c4b69efdd1 | ||
|  | d810aff337 | ||
|  | 83532fdae7 | ||
|  | 043534dd56 | ||
|  | a90c808fb4 | ||
|  | a06c39df9f | ||
|  | 24c3aefb6f | ||
|  | 9544d317a0 | ||
|  | 506d27816e | ||
|  | f5a0c87fdc | ||
|  | 90541f0436 | ||
|  | 76cac53692 | ||
|  | 18366bd58d | ||
|  | 27c039d51c | ||
|  | 8465be2a03 | ||
|  | 7d6f49172d | ||
|  | d15f4de4ae | ||
|  | 4098238019 | ||
|  | 1356237ec9 | ||
|  | 35daecd5ae | ||
|  | bb87c8e7b5 | ||
|  | 48f7a24505 | ||
|  | 98c59091ab | ||
|  | 4ca08adcfa | ||
|  | 29bcc1b5b7 | ||
|  | 6e4186adbe | ||
|  | 38e540ad9f | ||
|  | 7762b7b665 | ||
|  | 82ac8e29e3 | ||
|  | e074335285 | ||
|  | 3adbe843da | ||
|  | d5c8c076dc | ||
|  | 1d68c4105a | ||
|  | 8077123e9f | ||
|  | 0ff8b12770 | ||
|  | 39a8c0f4e6 | ||
|  | 8c5e12d389 | ||
|  | 71660850af | ||
|  | b83043648e | ||
|  | b01de802cb | ||
|  | e954e9ca20 | ||
|  | 3f8639bd9c | ||
|  | 56c956df44 | ||
|  | c4b621e44d | ||
|  | 9a658bf932 | ||
|  | d6d506d1c5 | ||
|  | 2c8f7fac0e | ||
|  | 072ff65bf9 | ||
|  | aa198ad15f | ||
|  | 745da8e363 | ||
|  | be173a9970 | ||
|  | 8b2b500414 | ||
|  | 98d1f5405a | ||
|  | 03595dd1dd | ||
|  | 6da48be1a4 | ||
|  | 9b91d574f8 | ||
|  | 6ca8edbf19 | ||
|  | 579dba1473 | ||
|  | 1b5fa15c8c | ||
|  | 737ad586a5 | ||
|  | c051e11a49 | ||
|  | a5692690dc | ||
|  | 98106ca8a2 | ||
|  | 891d685951 | ||
|  | 991cbc9f4e | ||
|  | 8006e4fe3b | ||
|  | f17c6b0a83 | ||
|  | 57ca601be1 | ||
|  | b50e26dc2a | ||
|  | b728d13d8c | ||
|  | 1959d149f8 | ||
|  | 3e2e05caf2 | ||
|  | d6a4d67a14 | ||
|  | cf8d424b9b | ||
|  | a9f1237208 | ||
|  | 319b4dfd75 | ||
|  | d39fcd3475 | ||
|  | c7b7f57ab2 | ||
|  | a36a5366d3 | ||
|  | 87615025fe | ||
|  | 5b0fc813c4 | ||
|  | d21f978def | ||
|  | a9ecf7f1f3 | ||
|  | f5ad65bb8a | ||
|  | 88dcf6350d | ||
|  | 6cfc17de35 | ||
|  | a2d105593e | ||
|  | efd5eff22c | ||
|  | 9282684d93 | ||
|  | c9e03f7d42 | ||
|  | 690b31c9be | ||
|  | cb20f03a92 | ||
|  | 97eabc6c03 | ||
|  | f0e0f08e0c | ||
|  | 470643ee07 | ||
|  | 8ba38b9b29 | ||
|  | 9870f55d24 | ||
|  | 23b724dde4 | ||
|  | 3fa922dbab | ||
|  | aa7f082d56 | ||
|  | b178d025b5 | ||
|  | e333ab18c7 | ||
|  | b60db6ac72 | ||
|  | 96c8da9fdd | ||
|  | fca883a4aa | ||
|  | e60d43110d | ||
|  | b9b135cfa2 | ||
|  | f925c35344 | ||
|  | ca2e9bed27 | ||
|  | 5b77e2c8ac | ||
|  | 9e3331d018 | ||
|  | 4440075425 | ||
|  | 626948774b | ||
|  | 25cb1c1138 | ||
|  | 4a173deb27 | ||
|  | 245c87f026 | ||
|  | 22a6de48ae | ||
|  | a347c1e848 | ||
|  | e4ab832ced | ||
|  | d07005dcbe | ||
|  | dc06497cae | ||
|  | c1871b5bca | ||
|  | 410b9c50d3 | ||
|  | 1c42d0ab3c | ||
|  | 98698f702f | ||
|  | 4784131dca | ||
|  | 6eb28b792a | ||
|  | 57f5b12e24 | ||
|  | e5aaf68277 | ||
|  | b62486923f | ||
|  | 322a0a5967 | ||
|  | f30c2c4a23 | ||
|  | 44e5fa5b25 | ||
|  | 18a86ef234 | ||
|  | a6af3744e2 | ||
|  | 9b40164787 | ||
|  | 52e8cf1366 | ||
|  | 1b159f5ccc | ||
|  | 893ae35296 | ||
|  | 85e56706bf | ||
|  | b8b21cefe3 | ||
|  | 6d7bf12ade | ||
|  | 5266816dd6 | ||
|  | 0c5f0271c7 | ||
|  | b65fd06e95 | ||
|  | 7f51822bfc | ||
|  | 1acd8d9577 | ||
|  | 8aa302f6fc | ||
|  | f8af5879af | ||
|  | a7aa7feff4 | ||
|  | b6a96cea23 | ||
|  | 50b02a4a55 | ||
|  | 8a2b178e6f | ||
|  | 7f1afb57b0 | ||
|  | 0bc4b50818 | ||
|  | 91de2194eb | ||
|  | fef06908ec | ||
|  | a012eb0cae | ||
|  | 08c805a489 | ||
|  | 5b595dd080 | ||
|  | c29a22187c | ||
|  | 44f6d21e9b | ||
|  | ef04248191 | ||
|  | 1b47c473b4 | ||
|  | fe1fea9a2d | ||
|  | 970f77beb0 | ||
|  | 2587cd380f | ||
|  | 04eab19f15 | ||
|  | abb2b46ed3 | ||
|  | db241e8f90 | ||
|  | 5bbd57d236 | ||
|  | e9f0f4af86 | ||
|  | ae75aed55e | ||
|  | b359738037 | ||
|  | 5ce988957f | ||
|  | 2d77fce99d | ||
|  | 62663ed6d2 | ||
|  | 3965d8f8c6 | ||
|  | fd35249de8 | ||
|  | 156560ae22 | ||
|  | ee687a7dc4 | ||
|  | 1710f13242 | ||
|  | ef645e601c | ||
|  | 7de23c6af2 | ||
|  | 639026ea66 | ||
|  | 8ddcf88c01 | ||
|  | 3883297991 | ||
|  | 196cc4313f | ||
|  | 9dd8c61a2f | ||
|  | 6d20f0e987 | ||
|  | eac4520406 | ||
|  | e4126189df | ||
|  | aa4ee2c166 | ||
|  | c72a15b488 | ||
|  | 6a29654d7d | ||
|  | 3ad7728a0e | ||
|  | 14c4491b8c | ||
|  | 2eff213840 | ||
|  | 2bb9b9a8f7 | ||
|  | d064543108 | ||
|  | 0270777cfc | ||
|  | 86106713dd | ||
|  | d5bbbe802b | ||
|  | b43fa88606 | ||
|  | 54ac1c284b | ||
|  | d33080cf08 | ||
|  | b4b6d4d969 | ||
|  | 993f05d5ac | ||
|  | ac7f6aef9e | ||
|  | 7fb5ed0b42 | ||
|  | 52b0ba5b05 | ||
|  | a43b494302 | ||
|  | 527ec28915 | ||
|  | e267a0e855 | ||
|  | 0196ce18f3 | ||
|  | 7ef3c12722 | ||
|  | 38b94ec5f8 | ||
|  | fa65452e2b | ||
|  | da0f6b5e8f | ||
|  | b4929df1e6 | ||
|  | 03c59fdaf7 | ||
|  | f5ab1e6f86 | ||
|  | ada1de429c | ||
|  | a1aad2e55e | ||
|  | d548ddac0d | ||
|  | 58a5ab4550 | ||
|  | 6a8242a6ca | ||
|  | 46b8bfe338 | ||
|  | 102ca6b854 | ||
|  | 06b4d241af | ||
|  | 712b2569e6 | ||
|  | 294be37afc | ||
|  | b57c0a2ebb | ||
|  | 94909f1a0f | ||
|  | 9c47d22ff4 | ||
|  | e4b9d14f45 | ||
|  | 73f1aca4a1 | ||
|  | bbae6b3de2 | ||
|  | e5133a2dd9 | ||
|  | ef0096b7d9 | ||
|  | 29f4d6918a | ||
|  | 45c7653850 | ||
|  | 8bdd1d7680 | ||
|  | a1ed7183ea | ||
|  | 7b81af2cb4 | ||
|  | a70a3c9600 | ||
|  | a14ddbfac2 | ||
|  | e1c57cf0af | ||
|  | 522994262d | ||
|  | f681357eeb | ||
|  | f9b593da59 | ||
|  | a340c817c9 | ||
|  | cc67f732e1 | ||
|  | e2ee7e6837 | ||
|  | 49d223f344 | ||
|  | 314d1b9873 | ||
|  | 2a391bf947 | ||
|  | 7a33f68138 | ||
|  | 48d0b46e43 | ||
|  | 5fe9edce8c | ||
|  | 1c038e1f3c | ||
|  | a57dd427ca | ||
|  | 2253f214a6 | ||
|  | ad11dc2421 | ||
|  | bd3b200b30 | ||
|  | 0d259d13b9 | ||
|  | 6fd55b2f49 | ||
|  | 057aee8ad2 | ||
|  | f47feabb4a | ||
|  | eb784a4a7c | ||
|  | 5d30c957cb | ||
|  | 585adef75d | ||
|  | 2f07fcc81c | ||
|  | 1d55d12c8f | ||
|  | bca8c5eccc | ||
|  | f7462c9f2b | ||
|  | 549697dc47 | ||
|  | 2869dd3bac | ||
|  | 5a225795e1 | ||
|  | 877abeda63 | ||
|  | 768387fea9 | ||
|  | db97fe8164 | ||
|  | be1a70c461 | ||
|  | b631fc610b | ||
|  | 9b2672841d | ||
|  | 336e8bafb4 | ||
|  | 2ea354f748 | ||
|  | 2d125cdc20 | ||
|  | 0d441a829f | ||
|  | ee5cb6909c | ||
|  | 5258053dc8 | ||
|  | bb46f184ed | ||
|  | 7cc1304eca | ||
|  | 94738444de | ||
|  | 4705b15188 | ||
|  | de567da846 | ||
|  | 6641af2a58 | ||
|  | de9527ce2f | ||
|  | 16ebdfad9a | ||
|  | b70db37b4f | ||
|  | 3843c64c40 | ||
|  | 1d1dd4b6a2 | ||
|  | d3a9ace5fd | ||
|  | 778c57320c | ||
|  | f98f3660f9 | ||
|  | fd4141e1f3 | ||
|  | 97c107be3e | ||
|  | 2eada9db62 | ||
|  | e9362439c3 | ||
|  | a2419ab31d | ||
|  | e589f10e23 | ||
|  | 5d84d40a2c | ||
|  | 43d1d0b217 | ||
|  | 0f802d5a1b | ||
|  | 56efde6e34 | ||
|  | e224e6cde5 | ||
|  | e1d51bae73 | ||
|  | f9163ccc01 | ||
|  | 6353bf545d | ||
|  | 12f0797ace | ||
|  | c9de423fb8 | ||
|  | 2cd0990c65 | ||
|  | 6fd9308e1b | ||
|  | 1fc57baac1 | ||
|  | 2ed63970d4 | ||
|  | 7ba6c601e5 | ||
|  | cc43c5b28c | ||
|  | b7f25ee3b6 | ||
|  | 82afdda256 | ||
|  | be83789bee | ||
|  | 036c8fe920 | ||
|  | b7b125f623 | ||
|  | 060edf33bd | ||
|  | 656120cd1f | ||
|  | 34acd71835 | ||
|  | 7eb4bebac3 | ||
|  | f45ee486e9 | ||
|  | 3b28c9d5a7 | ||
|  | 2ed39cd18d | ||
|  | d8d791e4f0 | ||
|  | 89bd42de04 | ||
|  | 51b460d432 | ||
|  | 6410366f8b | ||
|  | 1c2f4906e6 | ||
|  | bed90fa8ec | ||
|  | 25787ea806 | ||
|  | 2a21d87193 | ||
|  | 7cee17887a | ||
|  | 0cc94bcf19 | ||
|  | a554ae904f | ||
|  | 9dcda6113d | ||
|  | 7d50117903 | ||
|  | 76c5517739 | ||
|  | b9d243e70e | ||
|  | d37679c129 | ||
|  | d01cfee455 | ||
|  | 182d360302 | ||
|  | 0d9069ecfe | ||
|  | 6488f91e6e | ||
|  | 70db4d8847 | ||
|  | faa0d83013 | ||
|  | 6f1f226ed0 | ||
|  | 1d6406bbd6 | ||
|  | 91cee9c648 | ||
|  | 6d83b2676e | ||
|  | c21bce9641 | ||
|  | 1d5c175316 | ||
|  | 2fdd4e9760 | ||
|  | abd479dc68 | ||
|  | 67ef17f929 | ||
|  | 35bf179b70 | ||
|  | 10c62c10aa | ||
|  | 8317628c61 | ||
|  | 30fee43928 | ||
|  | 494dc475c1 | ||
|  | 3a503c61b3 | ||
|  | 86a28f0d19 | ||
|  | 24af39d4a8 | ||
|  | 97773e3f64 | ||
|  | 1dc1218bfc | ||
|  | b458026358 | ||
|  | b30a33eef5 | ||
|  | 0e96a1c8ba | ||
|  | f477c0fcc2 | ||
|  | 2ad6dd1ee8 | ||
|  | 87cfe1a8c6 | ||
|  | d0c6d9cf2d | ||
|  | fc7f2e7fc6 | ||
|  | 49baafadc1 | ||
|  | 24e62feadf | ||
|  | 67079d96af | ||
|  | 5ac4c72f1a | ||
|  | deceed37f3 | ||
|  | 4bc84cd526 | ||
|  | 293c428186 | ||
|  | d1b004ffc1 | ||
|  | da83f75a13 | ||
|  | b5be162fa2 | ||
|  | 7e5e2241cb | ||
|  | c0cb78bb3f | ||
|  | eb6ad7d29d | ||
|  | 88e56356c4 | ||
|  | 356660ad4f | ||
|  | 7c3567f5e7 | ||
|  | e9eb3badd9 | ||
|  | 9bbbaadcf8 | ||
|  | 19f44fac1e | ||
|  | 0be2c250ef | ||
|  | b07fc95c81 | ||
|  | 20ba23fe5f | ||
|  | b78705120e | ||
|  | f601329a47 | ||
|  | 2b3e7e7ab7 | ||
|  | 8d5e28f099 | ||
|  | cb1dc92594 | ||
|  | 495bf08498 | ||
|  | a1a5bdce78 | ||
|  | f724212fd7 | ||
|  | 5ccbe167a1 | ||
|  | 2e357ffeab | ||
|  | af10f52acf | ||
|  | ed8a6bb97b | ||
|  | c774b98002 | ||
|  | 9a63bea763 | ||
|  | 0c6a6743ab | ||
|  | 1c37334b18 | ||
|  | 7f40665a0e | ||
|  | b10036444d | ||
|  | 0542c70d22 | ||
|  | f71484c9f0 | ||
|  | 2cf74a7a96 | ||
|  | 018bcf273f | ||
|  | 1a3da4b363 | ||
|  | 0999805b3a | ||
|  | 7b5e3dab17 | ||
|  | a09cd03ce6 | ||
|  | c1fc454d19 | ||
|  | 93c8284a96 | ||
|  | e5dcf9063d | ||
|  | cf35a8032d | ||
|  | 88736aa82b | ||
|  | 90ac5ec577 | ||
|  | d1eb414749 | ||
|  | f792d403e5 | ||
|  | e5706606a0 | ||
|  | 49725c8c33 | ||
|  | dfcc0c6d09 | ||
|  | d806701d28 | ||
|  | 3935e661fe | ||
|  | cb8cf1f107 | ||
|  | ea8669439f | ||
|  | 75a8b1c081 | ||
|  | 73144fa4d5 | ||
|  | a6b60f3230 | ||
|  | 48dfb3317a | ||
|  | b3b0496c49 | ||
|  | e880447714 | ||
|  | fd4d10e7a4 | ||
|  | 9974e10069 | ||
|  | 18b65a61ff | ||
|  | 02a1e17f50 | ||
|  | 9a3a302754 | ||
|  | d131c39e46 | ||
|  | 8231e7703e | ||
|  | 406a78a11a | ||
|  | fe01a150f0 | ||
|  | dd499591e9 | ||
|  | c0f1e5f17f | ||
|  | b888e48a30 | ||
|  | 8410ee9d2f | ||
|  | b7238c702b | ||
|  | a5996b37b2 | ||
|  | b20503c5a2 | ||
|  | d0869a8840 | ||
|  | c156bfc534 | ||
|  | 5f8e092c96 | ||
|  | 87c9f9af71 | ||
|  | 65e5ecf49d | ||
|  | 63f051a9d2 | ||
|  | 2c1393fb09 | ||
|  | dba0d8469d | ||
|  | 75e6c45285 | ||
|  | e64e0d7421 | ||
|  | 13d5a5e2ec | ||
|  | 3432083343 | ||
|  | df4282fb34 | ||
|  | 861aebb2e3 | ||
|  | cc7b8359b4 | ||
|  | dd0d848530 | ||
|  | 7f17033ce3 | ||
|  | 3a4e72bb08 | ||
|  | bf3751fd9e | ||
|  | 05eb646848 | ||
|  | 5fe231b689 | ||
|  | 5ee7c2f9dc | ||
|  | 2c970a0466 | ||
|  | c688b11c86 | ||
|  | 749c0354b3 | ||
|  | 415af90ae7 | ||
|  | 365cb161cf | ||
|  | a9857fa298 | ||
|  | 59ae8d4b86 | ||
|  | b81f6ba685 | ||
|  | 16c9d00494 | ||
|  | 1a833d9dfb | ||
|  | bde6278781 | ||
|  | e7c4d2171f | ||
|  | 3a096ff0b4 | ||
|  | 9feac6708a | ||
|  | aabca97b2d | ||
|  | 9fb933fd06 | ||
|  | df039f05c2 | ||
|  | d1bed5729d | ||
|  | c926a586d2 | ||
|  | b7397bbb8f | ||
|  | 9b957524a5 | ||
|  | 078b1af04e | ||
|  | 6827ebfb78 | ||
|  | 1d807abe8b | ||
|  | 2c15b3f9bd | ||
|  | 0d5e037081 | ||
|  | dbda3a04b2 | ||
|  | 98e5b26eb7 | ||
|  | cd1fc6a1f0 | ||
|  | 52ef745f7c | ||
|  | 961b09977f | ||
|  | df8419cd9e | ||
|  | 71acf2bfa7 | ||
|  | 1400ceb4e8 | ||
|  | 793e338dd3 | ||
|  | 020e7609c3 | ||
|  | b1c2f66126 | ||
|  | 8ef0a59b98 | ||
|  | 798fb183a5 | ||
|  | 6bb3992c2f | ||
|  | 830d6f726e | ||
|  | 8f8c16bd0e | ||
|  | 76c0708cf2 | ||
|  | 5e51233b49 | ||
|  | 890bfd18fa | ||
|  | 37cc948741 | ||
|  | edb923b8bb | ||
|  | 44753bb168 | ||
|  | 7b96fa8d76 | ||
|  | ca35eed955 | ||
|  | eb6637afd5 | ||
|  | a114bbb30e | ||
|  | 9d38bf731f | ||
|  | f32732db1c | ||
|  | f41a29ce55 | ||
|  | 2b1e0be4fc | ||
|  | 23dd711396 | ||
|  | 59369cea2a | ||
|  | e6b81a824d | ||
|  | 1dd216b566 | ||
|  | 27e2a76110 | ||
|  | 47da97137f | ||
|  | 2134537bc3 | ||
|  | 67f91269ee | ||
|  | 57338059e1 | ||
|  | c1ed836fda | ||
|  | cd147dbc41 | ||
|  | 0253bba83b | ||
|  | d845b318b9 | ||
|  | 4b970905cf | ||
|  | 907771f084 | ||
|  | 1724ecd4c3 | ||
|  | 74b9ad5536 | ||
|  | 4f1525fe27 | ||
|  | 4dc7956b56 | ||
|  | 453bf4d195 | ||
|  | 249948e787 | ||
|  | c0acc8dfdf | ||
|  | 00e87864b1 | ||
|  | 697e5df52d | ||
|  | ba3cd454ba | ||
|  | de26925c13 | ||
|  | 47e00ff1a7 | ||
|  | d106051ee3 | ||
|  | c939fe2287 | ||
|  | 41b372ffe6 | ||
|  | 5826825d11 | ||
|  | a765e47dca | ||
|  | de8b032df9 | ||
|  | f1b1eb3b58 | ||
|  | 1f334d29ae | ||
|  | 3279d2a803 | ||
|  | cd14d1ef0f | ||
|  | 9eb676fb46 | ||
|  | 6c82ebe956 | ||
|  | 3922d02910 | ||
|  | 6da70cfa0d | ||
|  | 15c8e06129 | ||
|  | 93506a4e27 | ||
|  | 508e927d63 | ||
|  | ee969261b4 | ||
|  | 2a5742c12d | ||
|  | 598d70c6dc | ||
|  | a49e47f34b | ||
|  | ad4d869137 | ||
|  | 4ef86e6128 | ||
|  | 470036f6cb | ||
|  | 835ab6ddd9 | ||
|  | b0b387013c | ||
|  | 3e6cae0ca0 | ||
|  | 93844343de | ||
|  | 42430290d5 | ||
|  | ce15b4c678 | ||
|  | 35f4e2fb4f | ||
|  | 501f6cbab9 | ||
|  | a724dd98a9 | ||
|  | d5249425af | ||
|  | 44c44a2b9c | ||
|  | eb1c48674a | ||
|  | b44ab72557 | ||
|  | e6a33dea0e | ||
|  | 217811d0af | ||
|  | ab3246cc71 | ||
|  | 829533d501 | ||
|  | 8881118a15 | ||
|  | 3f2be5b2da | ||
|  | 9f1904ad3d | ||
|  | 09843c3cf1 | ||
|  | 303279a766 | ||
|  | f560e7fa96 | ||
|  | c97c6d1fc2 | ||
|  | b53bf051ac | ||
|  | d5189e6143 | ||
|  | a934c71ccd | ||
|  | 5147b6e699 | ||
|  | 9294bf40a7 | ||
|  | a02f96c913 | ||
|  | b756e723ea | ||
|  | 8bc1d5fe3e | ||
|  | 180417b581 | ||
|  | 786655843b | ||
|  | 5e3eeed10f | ||
|  | 8a2df9cd1f | ||
|  | 74d9891e06 | ||
|  | e0ff859e0d | ||
|  | 2c7efd0b97 | ||
|  | 99a0835ecc | ||
|  | 0bb227a79b | ||
|  | 84e7357960 | ||
|  | 9d0b94305a | ||
|  | 8343105b54 | ||
|  | 38cad56bf9 | ||
|  | 8f291c19c3 | ||
|  | 9566188d6b | ||
|  | cae8c2013d | ||
|  | 9bc5efe958 | ||
|  | b36003896f | ||
|  | 4d2ba9f1e6 | ||
|  | 56184c6f4f | ||
|  | 1f64f9eae6 | ||
|  | 7aeeaae015 | ||
|  | 03142d82bc | ||
|  | 78805b1c39 | ||
|  | e1a5ba9864 | ||
|  | bc0140ef3a | ||
|  | 36b76550e0 | ||
|  | 1f2e94b585 | ||
|  | e2a2f932f1 | ||
|  | 6ca2f7e3ac | ||
|  | f3309d3651 | ||
|  | 0b1d955a9f | ||
|  | fb75fa4e9a | ||
|  | 0ba8690120 | ||
|  | cafa3c827c | ||
|  | bbacce2986 | ||
|  | ead2d26025 | ||
|  | 7d89449f2d | ||
|  | b3d1b6c499 | ||
|  | 7d85e61cc5 | ||
|  | 362a8c8fc5 | ||
|  | 6041fb0445 | ||
|  | b2a7e0536e | ||
|  | 2d39454ce1 | ||
|  | 16de8bf26c | ||
|  | bb7cecd7c1 | ||
|  | 8e41cc7651 | ||
|  | 55238b9669 | ||
|  | 316ef69074 | ||
|  | 8c839b5c22 | ||
|  | f98e1d75f4 | ||
|  | c57d17dc58 | ||
|  | 938f4d2d9d | ||
|  | 307c38bd16 | ||
|  | 202dcfb4c5 | ||
|  | 8dd74bcf82 | ||
|  | 07acdc26ff | ||
|  | de307bf25a | ||
|  | b6c4f533d2 | ||
|  | cbf41e6ade | ||
|  | b1d98a4183 | ||
|  | 30db88d27b | ||
|  | fc9d5dee5e | ||
|  | bb0ada3f59 | ||
|  | 804256075e | ||
|  | 79f28f121b | ||
|  | 717a19a08e | ||
|  | 9c8716da09 | ||
|  | 8293784629 | ||
|  | a17f123608 | ||
|  | 561fe9c3ea | ||
|  | e645aa1ee5 | ||
|  | 7f86d2c5fa | ||
|  | fae14a755f | ||
|  | 1c14948f8a | ||
|  | 6a902eff56 | ||
|  | c6192ea953 | ||
|  | 36cf4ad304 | ||
|  | bcfabf18bc | ||
|  | f15693af1d | ||
|  | 64e42d18e2 | ||
|  | e2a76c621b | ||
|  | 19f6a8dcfe | ||
|  | 3c4cfe8aee | ||
|  | 43173c1aac | ||
|  | 95b284d648 | ||
|  | 9787cf8296 | ||
|  | 93b57445b6 | ||
|  | c4ca72cf22 | ||
|  | 13d2cca2bc | ||
|  | 7fe8eac511 | ||
|  | c062458188 | ||
|  | 3517dd2741 | ||
|  | 7407890deb | ||
|  | e9a4b0758b | ||
|  | abf076fc05 | ||
|  | c344625d0d | ||
|  | 14630465dd | ||
|  | a497ddfad2 | ||
|  | 34f6facdee | ||
|  | c3bff31cc4 | ||
|  | e4475c08e8 | ||
|  | 75a4d129f7 | ||
|  | c659477358 | ||
|  | 43f38d02ad | ||
|  | 6b8bc55c74 | ||
|  | 0c53e2fe46 | ||
|  | edef3bc30e | ||
|  | 0c7f09b832 | ||
|  | 34d075ce8c | ||
|  | 8c06d660ea | ||
|  | 748566b4fb | ||
|  | fb38867e78 | ||
|  | a2613625c6 | ||
|  | 89f1d54ebc | ||
|  | 740913fa20 | ||
|  | fd2a240c9f | ||
|  | 96bef08ac2 | ||
|  | 1698519a6a | ||
|  | d8372f73bc | ||
|  | fb6e8a4608 | ||
|  | a3f6160898 | ||
|  | 66f175b659 | ||
|  | 755ef35955 | ||
|  | b5d6156ffa | ||
|  | 8dd8cf8673 | ||
|  | 9e46099ced | ||
|  | 9f4fe259f9 | ||
|  | 3c169388e2 | ||
|  | b9e75769a3 | ||
|  | 17a9edd8c3 | ||
|  | 090b83a237 | ||
|  | 7796c88be3 | ||
|  | e5ee794895 | ||
|  | 2b572cc28f | ||
|  | 88544ae0ef | ||
|  | 146d56be84 | ||
|  | 1934dddcbe | ||
|  | f1c51bd0db | ||
|  | d91fc59a28 | ||
|  | f8025feda2 | ||
|  | c9f0c46017 | ||
|  | 5879aeac52 | ||
|  | c73ae579d3 | ||
|  | 3da55ad836 | ||
|  | 26bfcccedc | ||
|  | af6243afb0 | ||
|  | 673a341626 | ||
|  | a1aee7111a | ||
|  | 688209e272 | ||
|  | 116945047b | ||
|  | 1b8a9e16e2 | ||
|  | 7ff7e9d2e7 | ||
|  | 15c0d622c9 | ||
|  | 25087f3c92 | ||
|  | 34be9830af | ||
|  | 0fad6a6ec1 | ||
|  | 02599c0df8 | ||
|  | 430d068d78 | ||
|  | f09cadb7b3 | ||
|  | c366a4bd83 | ||
|  | 22c8a25a26 | ||
|  | 4c78b7d4bb | ||
|  | 8402d211bf | ||
|  | cc3be9448a | ||
|  | 7ac30c5153 | ||
|  | 64bc99101c | ||
|  | 09b5018e65 | ||
|  | 1dae1d244c | ||
|  | 2da996f493 | ||
|  | c5d4559300 | ||
|  | 434d027133 | ||
|  | f66212ce23 | ||
|  | 6b4e632101 | ||
|  | 0134b2874b | ||
|  | e2308aabed | ||
|  | 36fac3532c | ||
|  | 327c6e8ac2 | ||
|  | e9d49d96a6 | ||
|  | 929bb86a54 | ||
|  | f58e28d1be | ||
|  | cdabe21e7a | ||
|  | a7520eeaa8 | ||
|  | 070147db52 | ||
|  | 55436510b6 | ||
|  | 1aec5e455d | ||
|  | dc31294440 | ||
|  | d3b8070fd6 | ||
|  | 26e4d66163 | ||
|  | 7cfceebeb8 | ||
|  | 0e2616f16b | ||
|  | ccce7e001e | ||
|  | e91ba07f14 | ||
|  | fb7b51d91b | ||
|  | 88d055c3db | ||
|  | 3afce213c0 | ||
|  | 45f229c531 | ||
|  | d6772b4a0a | ||
|  | 5016d50c2b | ||
|  | 24eaf93db8 | ||
|  | 2e519b534d | ||
|  | 31c2b36039 | ||
|  | 245956c658 | ||
|  | 0df360c5e8 | ||
|  | 9b786df828 | ||
|  | ae859fa01e | ||
|  | 7eb64eb3dc | ||
|  | f45014f75b | ||
|  | 74a5c8c23c | ||
|  | 28e781db15 | ||
|  | 6ca9d4ee78 | ||
|  | 52dcd998c4 | ||
|  | a8cd168345 | ||
|  | b05a2a90d0 | ||
|  | 242715240b | ||
|  | 65f17fd76e | ||
|  | 58ee4447a1 | ||
|  | d153ac0951 | ||
|  | 2e97cfa5e5 | ||
|  | 7d5276ad11 | ||
|  | 2251e5e418 | ||
|  | e4257fb6c7 | ||
|  | f22b03fdb5 | ||
|  | dd4541c825 | ||
|  | 98f77394ed | ||
|  | fc18db10be | ||
|  | 9382e2e8c7 | ||
|  | a3b2dbf8e2 | ||
|  | 6df190edbb | ||
|  | 5b0b8a9717 | ||
|  | a8ddbe4127 | ||
|  | 6e1fdda182 | ||
|  | ca33090793 | ||
|  | e34b390c18 | ||
|  | 370df0d495 | ||
|  | d4e300d0a4 | ||
|  | c83864af9c | ||
|  | 14fe3045dc | ||
|  | 5d54e6c951 | ||
|  | 921e78c9e2 | ||
|  | b1778825cb | ||
|  | cc8d5ac93a | ||
|  | 1d0dce7366 | ||
|  | ae454b0892 | ||
|  | a2234b745c | ||
|  | 3dd8dac146 | ||
|  | 6752fc9fe5 | ||
|  | 0d05411cd2 | ||
|  | 7ce65e3cfe | ||
|  | ea1501abd1 | ||
|  | ca28b8f93e | ||
|  | 566e74310a | ||
|  | c18e8ba242 | ||
|  | 1f3f0dce11 | ||
|  | b73008d83d | ||
|  | 10a8291391 | ||
|  | ab094ab174 | ||
|  | 29a82f8471 | ||
|  | 8adfa52ae3 | ||
|  | 18485dd456 | ||
|  | c318b849fe | ||
|  | e3aa76cd09 | ||
|  | de897d2ebf | ||
|  | 08118ec36f | ||
|  | f757a9de52 | ||
|  | 6d502b6898 | ||
|  | 0eff19f0ff | ||
|  | b6dfc791d4 | ||
|  | 7002dc63bd | ||
|  | 7eedfc201a | ||
|  | ac38390241 | ||
|  | 3156f602dd | ||
|  | ad25942731 | ||
|  | fddbfc2d32 | ||
|  | 8c9bdadf66 | ||
|  | 6345faa4a9 | ||
|  | 4711ce5532 | ||
|  | 293510c087 | ||
|  | a179a6892c | ||
|  | afb310e90a | ||
|  | 51391b7f0e | ||
|  | 264b1d69d9 | ||
|  | 884b1add8e | ||
|  | 8c05a92a1e | ||
|  | f791cd3a37 | ||
|  | 4600a656d1 | ||
|  | d03f13a729 | ||
|  | 5a088690b2 | ||
|  | 8d26f58dfa | ||
|  | a3cdb63ae1 | ||
|  | 9d5b23acd3 | ||
|  | 41e04c0178 | ||
|  | abaa0cf3d0 | ||
|  | 8670fbe2ae | ||
|  | 898213bb85 | ||
|  | c30d59d5d3 | ||
|  | c54d69e5ae | ||
|  | 38a1f08413 | ||
|  | e2bd80253b | ||
|  | 039cc6e28b | ||
|  | 1030c96eec | ||
|  | 0851c5ac8e | ||
|  | 92d112083e | ||
|  | 1e462f5cc0 | ||
|  | d974ee169a | ||
|  | 7fb87d4039 | ||
|  | fc5963fa3d | ||
|  | cfa362321d | ||
|  | 72c7157138 | ||
|  | 2f91a12f19 | ||
|  | abe72b7745 | ||
|  | e7df9d1754 | ||
|  | d3ab2b077a | ||
|  | 467a11f4b4 | ||
|  | 6cb8c1df42 | ||
|  | 3915c7e8f2 | ||
|  | 5ba0e0dc54 | ||
|  | 9a35e2db77 | ||
|  | e204a6d1d0 | ||
|  | 47ab2a1b1d | ||
|  | 6fc38292f2 | ||
|  | 89d8df3385 | ||
|  | 9c7df2b41e | ||
|  | 46f6816511 | ||
|  | 858ccfa934 | ||
|  | b4a3218b13 | ||
|  | 92a4556956 | ||
|  | bd42c33daa | ||
|  | e1796a9f0f | ||
|  | 8c5c81fe70 | ||
|  | bf8fae2025 | ||
|  | 7f2b715ceb | ||
|  | 974189045a | ||
|  | 77feaec444 | ||
|  | e5b6921de9 | ||
|  | 3ca3a2820d | ||
|  | 9f4933e33d | ||
|  | 3cf48a831b | ||
|  | 930b742663 | ||
|  | d3870fed1c | ||
|  | 99e242affd | ||
|  | 9792246970 | ||
|  | 020b953166 | ||
|  | 52aa8e914a | ||
|  | e01eadaecd | ||
|  | 61fc32b7c0 | ||
|  | a9c8207bb0 | ||
|  | eac4f172fe | ||
|  | d6271426fd | ||
|  | 7e59110049 | ||
|  | 8cf4fb9adc | ||
|  | f044f364cb | ||
|  | 4d39892a11 | ||
|  | bf1ebe8e53 | ||
|  | 77b4f32274 | ||
|  | b2ada13a21 | ||
|  | 03fced81f5 | ||
|  | f9292a8fb8 | ||
|  | 065f46a020 | ||
|  | 6efb7027b5 | ||
|  | f4f922acb5 | ||
|  | 4a4d2e7079 | ||
|  | 1634c90179 | ||
|  | 9b5ba6806f | ||
|  | 4afca6ca8d | ||
|  | 90d1decb87 | ||
|  | 1d8cb1b107 | ||
|  | 65e3d9873d | ||
|  | 50b22c673e | ||
|  | 4ef8b7f733 | ||
|  | e0ec26255b | ||
|  | ffa32f7610 | ||
|  | 1c1d257bd9 | ||
|  | 5611cb91a0 | ||
|  | e0cff4b74e | ||
|  | c1985e6986 | ||
|  | 416b1aee98 | ||
|  | 7bb9d8b03a | ||
|  | 0473c82029 | ||
|  | 63bd1a4a22 | ||
|  | 5a64759c83 | ||
|  | 0df68a6e06 | ||
|  | 29eff3b515 | ||
|  | 073976de10 | ||
|  | 1fe159f432 | ||
|  | adad7f4e3f | ||
|  | 378710533e | ||
|  | d966848ef8 | ||
|  | d6d613ca37 | ||
|  | 1a385de367 | ||
|  | 73eb56c072 | ||
|  | 9651941cce | ||
|  | 29be79814f | ||
|  | 1ea220f44f | ||
|  | 6cf11554de | ||
|  | f289b3112b | ||
|  | c61df50167 | ||
|  | df5ec33330 | ||
|  | 6384518ee1 | ||
|  | 87bf940f89 | ||
|  | 53db047a4e | ||
|  | dabef47ce7 | ||
|  | 4de1d69282 | ||
|  | 015c35f2b2 | ||
|  | 5a491b2624 | ||
|  | 3d95817dbe | ||
|  | 96ab74dea4 | ||
|  | f937a0b038 | ||
|  | da38285046 | ||
|  | d3db2dcfbb | ||
|  | c788db785b | ||
|  | 6df41d2562 | ||
|  | 74fb43998e | ||
|  | c1f8eabd12 | ||
|  | 2f5a1eebe0 | ||
|  | 4791c120fe | ||
|  | f6d445b553 | ||
|  | db3dd4ae5a | ||
|  | d6ba03916a | ||
|  | 4734acbe61 | ||
|  | 527256b416 | ||
|  | 7a0dc7a364 | ||
|  | 7f88e8ad6e | ||
|  | c7324121ed | ||
|  | 588ca3a315 | ||
|  | eb9b2f355e | ||
|  | cf6144599d | ||
|  | c23bb5e589 | ||
|  | 0eb5c825a5 | ||
|  | 5dfb65b084 | ||
|  | ddbe2acbf5 | ||
|  | 2ff3735adc | ||
|  | c2752d5931 | ||
|  | 309dd7f300 | ||
|  | 33df11b755 | ||
|  | bd5babf65d | ||
|  | 3c07cbde47 | ||
|  | dee5ff852d | ||
|  | 073930004d | ||
|  | 01574c5a87 | ||
|  | 3a49369e68 | ||
|  | 42f7b7cc19 | ||
|  | 5f8ebc3601 | ||
|  | 2e5645108b | ||
|  | d73f7beb2f | ||
|  | 4f6f126952 | ||
|  | 0099cdd6ad | ||
|  | 2b7114b704 | ||
|  | 2041d0d000 | ||
|  | 698f313b73 | ||
|  | 1940458306 | ||
|  | 983def2bbd | ||
|  | 9213bf47ae | ||
|  | f01743e27c | ||
|  | 9be58972a0 | ||
|  | a1a6c3e40c | ||
|  | a2b19a1b9d | ||
|  | 4d1a942e79 | ||
|  | eb4afa8f2c | ||
|  | 468bbea44d | ||
|  | b75aa02b0d | ||
|  | a39f93bcff | ||
|  | e229d2d59f | ||
|  | 3d58dc2a50 | ||
|  | 0395188aed | ||
|  | 4e6dd1b213 | ||
|  | a46b13967a | ||
|  | e916daf5fd | ||
|  | fad9dae9bb | ||
|  | 83bd5f5561 | ||
|  | 0ddb9f8923 | ||
|  | 03ea97734c | ||
|  | b7adf59ed5 | ||
|  | 666b992c51 | ||
|  | 56d5e9c889 | ||
|  | aa36ebf4f2 | ||
|  | de60123ec7 | ||
|  | cf3790c2f8 | ||
|  | b7bac3abf6 | ||
|  | f4551dd1e5 | ||
|  | b3da4bb5b7 | ||
|  | 6e4b6929d2 | ||
|  | a0602c8863 | ||
|  | 55246c5d87 | ||
|  | 81ee577407 | ||
|  | 55e1045000 | ||
|  | fc96df63fd | ||
|  | 9b787a6bc2 | ||
|  | 201dc7c28d | ||
|  | 5189fa6483 | ||
|  | 1992478cee | ||
|  | 5ad6b48289 | ||
|  | bbcf83b99d | ||
|  | 9ef55023f2 | ||
|  | f2f81b0f7b | ||
|  | c22ed861d1 | ||
|  | 39bed4d306 | ||
|  | 949946589f | ||
|  | 09d970f056 | ||
|  | 5813bb9ca8 | ||
|  | c48ad5c90f | ||
|  | 4fdc1b3e19 | ||
|  | dc372a43fe | ||
|  | 589b791cd7 | ||
|  | 564dbea126 | ||
|  | 1bc4bc613e | ||
|  | 11a25cb1ae | ||
|  | d6c1bf691c | ||
|  | e6443a2612 | ||
|  | d79714a3cf | ||
|  | 4bb1312cf1 | ||
|  | 4e2abcaefa | ||
|  | d463d4c46b | ||
|  | 435c81da98 | ||
|  | 4f818d55fa | ||
|  | c96a81e319 | ||
|  | 7cff9ba86a | ||
|  | 6ddaa6f52a | ||
|  | 238877b627 | ||
|  | 95e7999e45 | ||
|  | 2f464ee8f0 | ||
|  | 8fe9883b62 | ||
|  | de896f9159 | ||
|  | a2468e8129 | ||
|  | ee89f74afd | ||
|  | cd08c3e8fa | ||
|  | 9cc8933eec | ||
|  | 91c27ff972 | ||
|  | 07e3ba014c | ||
|  | 57ac0ca6e8 | ||
|  | 816368b1fe | ||
|  | 85ea291745 | ||
|  | 741fdfa52e | ||
|  | 348ec5bc3c | ||
|  | df9698ab1f | ||
|  | c1aead970a | ||
|  | 518f351235 | ||
|  | d79a07e2c4 | ||
|  | b636057251 | ||
|  | c692c8f055 | ||
|  | 930736060c | ||
|  | 1c8468d248 | ||
|  | 575842eab4 | ||
|  | f7f55cad43 | ||
|  | acd857a8c0 | ||
|  | 53ff248176 | ||
|  | 3de13967bc | ||
|  | aebb923c2d | ||
|  | 76d577a08d | ||
|  | 3fb34a2a83 | ||
|  | cdb938ea28 | ||
|  | 882dd4597e | ||
|  | 409efb8c67 | ||
|  | eaa4373a18 | ||
|  | d480f8d82a | ||
|  | 339fc9ff14 | ||
|  | 14167412e0 | ||
|  | 7c0f075d1f | ||
|  | f4aea76c6e | ||
|  | d263382365 | ||
|  | 2109ed8464 | ||
|  | d11444b983 | ||
|  | 0508a45681 | ||
|  | a5c0b95f8b | ||
|  | f1af12b3b9 | ||
|  | 9d257497bd | ||
|  | 79f40b4ce0 | ||
|  | 1ab62b7a80 | ||
|  | d2f10d5834 | ||
|  | c326ec9d1e | ||
|  | 26317d16ff | ||
|  | 79b8f85cdf | ||
|  | c84a0b8415 | ||
|  | be5336d074 | ||
|  | aecb2efad9 | ||
|  | 3654005c3d | ||
|  | d8fd61955c | ||
|  | 3381ab5093 | ||
|  | 8c2fa64c47 | ||
|  | 12ae9fced5 | ||
|  | e3bca7e7e7 | ||
|  | bca199e118 | ||
|  | 938ae5f27c | ||
|  | 8aa3b535f0 | ||
|  | f4bf4ee0f2 | ||
|  | 1c1ab3cd87 | ||
|  | f5c215fe65 | ||
|  | 9952de615a | ||
|  | e1c547be98 | ||
|  | 7cb6795d40 | ||
|  | a5f4478e20 | ||
|  | 94d0db2dba | ||
|  | 64c596c922 | ||
|  | e30b8999d4 | ||
|  | 2f0ee84b71 | ||
|  | c570478aaa | ||
|  | 051997acb0 | ||
|  | 51ef0e1e6d | ||
|  | ed0fcf2829 | ||
|  | 2ce94b73ad | ||
|  | ef96bff6ec | ||
|  | afc888f2ef | ||
|  | e823c2af9d | ||
|  | 18979f3f30 | ||
|  | 8bd29596c4 | ||
|  | 0cfcb6aa37 | ||
|  | 6b40812e6d | ||
|  | 8af253e9ab | ||
|  | 6763bce627 | ||
|  | 3217c1e11f | ||
|  | 6ce3e18831 | ||
|  | 3e461ac2e5 | ||
|  | 25e2baaea7 | ||
|  | 6696a714f0 | ||
|  | 46af2ffcea | ||
|  | e5b3a82112 | ||
|  | 9af51aaca1 | ||
|  | 3bacf09710 | ||
|  | 61bdbd2d74 | ||
|  | a1293f160f | ||
|  | 847503bff1 | ||
|  | 576242551f | ||
|  | fdb6bee65f | ||
|  | a2846faa61 | ||
|  | a32544b53a | ||
|  | 9b093dab0a | ||
|  | 84d433fa06 | ||
|  | e24b8947e0 | ||
|  | 7835c6e20c | ||
|  | d942c47f08 | ||
|  | fdaee1375c | ||
|  | d25a510291 | ||
|  | 0cb8586f68 | ||
|  | e42a0979bc | ||
|  | f1a78682aa | ||
|  | dc4bfde76d | ||
|  | e717625f86 | ||
|  | 41444e7ede | ||
|  | ac9247195b | ||
|  | fc2a59ceaa | ||
|  | 72f4b216c1 | ||
|  | d373f5488a | ||
|  | 24906138c7 | ||
|  | f4b3b69b2f | ||
|  | e80abad19a | ||
|  | c9c228ffdd | ||
|  | 6fc30d31bf | ||
|  | 0bcd47b394 | ||
|  | c24bb139dd | ||
|  | eb00ff05a8 | ||
|  | a7fe47f295 | ||
|  | 2a6f02c764 | ||
|  | 1b2ff1f9ae | ||
|  | 7de9a36d01 | ||
|  | cfa8796b18 | ||
|  | 3c88ede02c | ||
|  | a0223835b8 | ||
|  | ac18359410 | ||
|  | 8194e3d3c5 | ||
|  | 440c4fe9b9 | ||
|  | e54f5d563f | ||
|  | 5781ab5436 | ||
|  | f8009dbb27 | ||
|  | 15efe3ae31 | ||
|  | 991348bbbe | ||
|  | 233336ea16 | ||
|  | 20d8c1b51a | ||
|  | 06499f2155 | ||
|  | 5b1d9396d7 | ||
|  | 633c5d5938 | ||
|  | 2e846159a8 | ||
|  | 4408604c2d | ||
|  | 15db5c8059 | ||
|  | 53121b1dd4 | ||
|  | c36dff6354 | ||
|  | 94a91ed5c8 | ||
|  | 162a812189 | ||
|  | f06f0785f1 | ||
|  | 1aae68c614 | ||
|  | 703a0fde3c | ||
|  | abb71cd074 | ||
|  | 79cf9156eb | ||
|  | 3a6664282c | ||
|  | e00ac37cb2 | ||
|  | 6583ac9ba1 | ||
|  | 42963ea77d | ||
|  | 6231724f49 | ||
|  | 5b25eb4fbd | ||
|  | 565cc7b3c8 | ||
|  | 71dc2690aa | ||
|  | 3accd48ea8 | ||
|  | ed78bde359 | ||
|  | ff1a3ab307 | ||
|  | 26643a489b | ||
|  | 5955a541a3 | ||
|  | 995669cccd | ||
|  | 371dc347cc | ||
|  | 9a162e5d5c | ||
|  | 9319f362bb | ||
|  | 8305168bc4 | ||
|  | e8ecbe32ca | ||
|  | bc5c5050fb | ||
|  | 8a9b9c55ce | ||
|  | d40f343d2a | ||
|  | 4954d0a018 | ||
|  | 7232bef07b | ||
|  | 7277fb3d93 | ||
|  | 34e0345b29 | ||
|  | f094e9118c | ||
|  | 63e93d9253 | ||
|  | 2ec0d421f7 | ||
|  | 8ddc890e10 | ||
|  | 095c899913 | ||
|  | e0d6a3fd1d | ||
|  | 308ff15adc | ||
|  | c195629a77 | ||
|  | 6af5a67a17 | ||
|  | 0b38289703 | ||
|  | 041bf9b54e | ||
|  | 5a6cf2b690 | ||
|  | 2e44bb6085 | ||
|  | b8f056b82f | ||
|  | 259b463b73 | ||
|  | 4aae7348d1 | ||
|  | 665942a8c9 | ||
|  | dc9a26ae8a | ||
|  | 55f3322576 | ||
|  | 376f068719 | ||
|  | 3688956ee5 | ||
|  | 53b1037a33 | ||
|  | 2b5cd02bd9 | ||
|  | e5fed57b8b | ||
|  | a0b1f3efa2 | ||
|  | f7fb1225d2 | ||
|  | b380952ff9 | ||
|  | 2524e7eea3 | ||
|  | 32460f00f8 | ||
|  | d58d7f457d | ||
|  | 232a43f34f | ||
|  | 94f5a039d2 | ||
|  | 7a4ae74727 | ||
|  | 1295de4c78 | ||
|  | 77ed54f64d | ||
|  | e51b425200 | ||
|  | e6aff19a0c | ||
|  | bd06c7b343 | ||
|  | c096eae644 | ||
|  | f77823ee24 | ||
|  | 35f568e346 | ||
|  | 2d28fde24d | ||
|  | 92fe720ac3 | ||
|  | 74a9a13564 | ||
|  | 7aaef5d807 | ||
|  | 64b4158bad | ||
|  | 4bbaa6b41c | ||
|  | 964d8171dd | ||
|  | 5b1cbbf157 | ||
|  | db4c29a73c | ||
|  | 4f73008d95 | ||
|  | 1b73cb28f1 | ||
|  | 367c981642 | ||
|  | 3d30eb0748 | ||
|  | 34ffdad521 | ||
|  | 4f82c0c289 | ||
|  | fd68746dd7 | ||
|  | bec7d1265b | ||
|  | 620eb2a3be | ||
|  | e6971c45c8 | ||
|  | 961cd0825c | ||
|  | a1cb702ecb | ||
|  | befc14c980 | ||
|  | ff0ad53c11 | ||
|  | cf0e57d7ce | ||
|  | 9883e3ed2e | 
| @@ -28,7 +28,7 @@ jobs: | ||||
|                   name: yarn | ||||
|                   command: yarn --frozen-lockfile --ignore-engines install || yarn --frozen-lockfile --ignore-engines install | ||||
|             - setup_remote_docker | ||||
|             - run: yarn build:ci:no_website | ||||
|             - run: yarn build:ci | ||||
|             - run: yarn build:ts | ||||
|             - save_cache: | ||||
|                   key: repo-{{ .Environment.CIRCLE_SHA1 }} | ||||
| @@ -38,16 +38,6 @@ jobs: | ||||
|                   path: ~/repo/packages/abi-gen/test-cli/output | ||||
|             - store_artifacts: | ||||
|                   path: ~/repo/packages/abi-gen-wrappers/generated_docs | ||||
|     build-website: | ||||
|         resource_class: medium+ | ||||
|         docker: | ||||
|             - image: nikolaik/python-nodejs:python3.7-nodejs8 | ||||
|         working_directory: ~/repo | ||||
|         steps: | ||||
|             - restore_cache: | ||||
|                   keys: | ||||
|                       - repo-{{ .Environment.CIRCLE_SHA1 }} | ||||
|             - run: cd packages/website && yarn build:prod | ||||
|     test-contracts-ganache: | ||||
|         resource_class: medium+ | ||||
|         docker: | ||||
| @@ -57,19 +47,31 @@ 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 | ||||
|     test-contracts-geth: | ||||
|             - 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 | ||||
|     test-exchange-ganache-3.0: | ||||
|         resource_class: medium+ | ||||
|         docker: | ||||
|             - image: nikolaik/python-nodejs:python3.7-nodejs8 | ||||
|             - image: 0xorg/devnet | ||||
|         working_directory: ~/repo | ||||
|         steps: | ||||
|             - restore_cache: | ||||
|                   keys: | ||||
|                       - repo-{{ .Environment.CIRCLE_SHA1 }} | ||||
|             # HACK(albrow): we need to sleep 10 seconds to ensure the devnet is | ||||
|             # initialized | ||||
|             - run: sleep 10 && TEST_PROVIDER=geth 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 | ||||
|             - run: yarn wsrun test:circleci @0x/contracts-exchange | ||||
|     test-contracts-rest-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-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-extensions | ||||
|             # TODO(abandeali): Re-enable after this package is complete. | ||||
|             # - run: yarn wsrun test:circleci @0x/contracts-coordinator | ||||
|     test-publish: | ||||
|         resource_class: medium+ | ||||
|         docker: | ||||
| @@ -80,7 +82,9 @@ jobs: | ||||
|             - restore_cache: | ||||
|                   keys: | ||||
|                       - repo-{{ .Environment.CIRCLE_SHA1 }} | ||||
|             - run: yarn test:publish:circleci | ||||
|             - run:  | ||||
|                 command: yarn test:publish:circleci | ||||
|                 no_output_timeout: 1800 | ||||
|     test-doc-generation: | ||||
|         docker: | ||||
|             - image: nikolaik/python-nodejs:python3.7-nodejs8 | ||||
| @@ -89,7 +93,9 @@ jobs: | ||||
|             - restore_cache: | ||||
|                   keys: | ||||
|                       - repo-{{ .Environment.CIRCLE_SHA1 }} | ||||
|             - run: yarn test:generate_docs:circleci | ||||
|             - run: | ||||
|                 command: yarn test:generate_docs:circleci | ||||
|                 no_output_timeout: 1200 | ||||
|     test-rest: | ||||
|         docker: | ||||
|             - image: nikolaik/python-nodejs:python3.7-nodejs8 | ||||
| @@ -100,11 +106,13 @@ jobs: | ||||
|                       - repo-{{ .Environment.CIRCLE_SHA1 }} | ||||
|             - run: yarn wsrun test:circleci @0x/contracts-test-utils | ||||
|             - run: yarn wsrun test:circleci @0x/abi-gen | ||||
|             - run: yarn wsrun test:circleci @0x/asset-buyer | ||||
|             # TODO (xianny): Needs to be updated for 3.0 | ||||
|             # - run: yarn wsrun test:circleci @0x/asset-buyer | ||||
|             - run: yarn wsrun test:circleci @0x/contract-artifacts | ||||
|             - run: yarn wsrun test:circleci @0x/assert | ||||
|             - run: yarn wsrun test:circleci @0x/base-contract | ||||
|             - run: yarn wsrun test:circleci @0x/connect | ||||
|             # TODO (xianny): Needs to be updated for 3.0 | ||||
|             # - run: yarn wsrun test:circleci @0x/connect | ||||
|             - run: yarn wsrun test:circleci @0x/contract-wrappers | ||||
|             - run: yarn wsrun test:circleci @0x/dev-utils | ||||
|             - run: yarn wsrun test:circleci @0x/json-schemas | ||||
| @@ -292,6 +300,7 @@ jobs: | ||||
|                       ./install | ||||
|                       ./lint | ||||
|     static-tests: | ||||
|         resource_class: large | ||||
|         working_directory: ~/repo | ||||
|         docker: | ||||
|             - image: nikolaik/python-nodejs:python3.7-nodejs8 | ||||
| @@ -382,17 +391,12 @@ workflows: | ||||
|     main: | ||||
|         jobs: | ||||
|             - build | ||||
|             - build-website: | ||||
|             - test-exchange-ganache-3.0: | ||||
|                   requires: | ||||
|                       - build | ||||
|             - test-contracts-ganache: | ||||
|             - test-contracts-rest-ganache-3.0: | ||||
|                   requires: | ||||
|                       - build | ||||
|             # TODO(albrow): Tests always fail on Geth right now because our fork | ||||
|             # is outdated. Uncomment once we have updated our Geth fork. | ||||
|             # - test-contracts-geth: | ||||
|             #       requires: | ||||
|             #           - build | ||||
|             - test-rest: | ||||
|                   requires: | ||||
|                       - build | ||||
| @@ -407,13 +411,16 @@ workflows: | ||||
|                       - build | ||||
|             - submit-coverage: | ||||
|                   requires: | ||||
|                       - test-contracts-rest-ganache-3.0 | ||||
|                       - test-exchange-ganache-3.0 | ||||
|                       - test-rest | ||||
|                       - test-python | ||||
|             - static-tests-python: | ||||
|                   requires: | ||||
|                       - test-python | ||||
|             - test-python: | ||||
|                   requires: | ||||
|                       - build | ||||
|                       - static-tests | ||||
|             # - test-python: | ||||
|             #       requires: | ||||
|             #           - build | ||||
|             #           - test-rest | ||||
|             # - static-tests-python: | ||||
|             #       requires: | ||||
|             #           - test-python | ||||
|             # skip python tox run for now, as we don't yet have multiple test environments to support. | ||||
|             #- test-rest-python | ||||
|             # - test-rest-python | ||||
|   | ||||
							
								
								
									
										3
									
								
								.github/autolabeler.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.github/autolabeler.yml
									
									
									
									
										vendored
									
									
								
							| @@ -13,7 +13,6 @@ contracts: ['contracts'] | ||||
| @0x/instant: ['packages/instant'] | ||||
| @0x/abi-gen-templates: ['packages/abi-gen-templates'] | ||||
| @0x/abi-gen: ['packages/abi-gen'] | ||||
| @0x/website: ['packages/website'] | ||||
| @0x/sol-coverage: ['packages/sol-coverage'] | ||||
| @0x/sol-profiler: ['packages/sol-profiler'] | ||||
| @0x/sol-trace: ['packages/sol-trace'] | ||||
| @@ -33,7 +32,5 @@ contracts: ['contracts'] | ||||
| @0x/json-schemas: ['packages/json-schemas'] | ||||
| @0x/ethereum-types: ['ethereum-types'] | ||||
| @0x/connect: ['packages/connect'] | ||||
| @0x/fill-scenarios: ['packages/fill-scenarios'] | ||||
| @0x/dev-tools-pages: ['packages/dev-tools-pages'] | ||||
| @0x/testnet-faucets: ['packages/testnet-faucets'] | ||||
| @0x/monorepo-scripts: ['packages/monorepo-scripts'] | ||||
|   | ||||
							
								
								
									
										23
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										23
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -78,13 +78,11 @@ TODO.md | ||||
| # VSCode file | ||||
| .vscode | ||||
|  | ||||
| packages/website/public/bundle* | ||||
| packages/dev-tools-pages/public/bundle* | ||||
|  | ||||
| # server cli | ||||
| packages/testnet-faucets/server/ | ||||
|  | ||||
| # generated contract artifacts/ | ||||
| contracts/staking/generated-artifacts/ | ||||
| contracts/coordinator/generated-artifacts/ | ||||
| contracts/exchange/generated-artifacts/ | ||||
| contracts/asset-proxy/generated-artifacts/ | ||||
| @@ -100,8 +98,24 @@ contracts/dev-utils/generated-artifacts/ | ||||
| packages/sol-tracing-utils/test/fixtures/artifacts/ | ||||
| python-packages/contract_artifacts/src/zero_ex/contract_artifacts/artifacts/ | ||||
|  | ||||
| # generated truffle contract artifacts/ | ||||
| contracts/staking/build/ | ||||
| contracts/coordinator/build/ | ||||
| contracts/exchange/build/ | ||||
| contracts/asset-proxy/build/ | ||||
| contracts/multisig/build/ | ||||
| contracts/utils/build/ | ||||
| contracts/exchange-libs/build/ | ||||
| contracts/erc20/build/ | ||||
| contracts/erc721/build/ | ||||
| contracts/erc1155/build/ | ||||
| contracts/extensions/build/ | ||||
| contracts/exchange-forwarder/build/ | ||||
| contracts/dev-utils/build/ | ||||
|  | ||||
| # generated contract wrappers | ||||
| packages/python-contract-wrappers/generated/ | ||||
| contracts/staking/generated-wrappers/ | ||||
| contracts/coordinator/generated-wrappers/ | ||||
| contracts/exchange/generated-wrappers/ | ||||
| contracts/asset-proxy/generated-wrappers/ | ||||
| @@ -154,5 +168,4 @@ python-packages/json_schemas/src/zero_ex/json_schemas/schemas | ||||
| # Doc README copy | ||||
| packages/*/docs/README.md | ||||
|  | ||||
| # Tool MDX files authoritatively live on S3 | ||||
| packages/website/mdx/tools/* | ||||
| .DS_Store | ||||
|   | ||||
| @@ -1,5 +1,7 @@ | ||||
| lib | ||||
| .nyc_output | ||||
| /contracts/staking/generated-wrappers | ||||
| /contracts/staking/generated-artifacts | ||||
| /contracts/coordinator/generated-wrappers | ||||
| /contracts/coordinator/generated-artifacts | ||||
| /contracts/exchange/generated-wrappers | ||||
| @@ -24,11 +26,23 @@ lib | ||||
| /contracts/exchange-forwarder/generated-artifacts | ||||
| /contracts/dev-utils/generated-wrappers | ||||
| /contracts/dev-utils/generated-artifacts | ||||
| /contracts/staking/build/ | ||||
| /contracts/coordinator/build/ | ||||
| /contracts/exchange/build/ | ||||
| /contracts/asset-proxy/build/ | ||||
| /contracts/multisig/build/ | ||||
| /contracts/utils/build/ | ||||
| /contracts/exchange-libs/build/ | ||||
| /contracts/erc20/build/ | ||||
| /contracts/erc721/build/ | ||||
| /contracts/erc1155/build/ | ||||
| /contracts/extensions/build/ | ||||
| /contracts/exchange-forwarder/build/ | ||||
| /contracts/dev-utils/build/ | ||||
| /packages/abi-gen/test-cli/output | ||||
| /packages/json-schemas/schemas | ||||
| /python-packages/json_schemas/src/zero_ex/json_schemas/schemas | ||||
| /packages/sra-spec/public/ | ||||
| /packages/dev-tools-pages/ts/**/data.json | ||||
| package.json | ||||
| scripts/postpublish_utils.js | ||||
| packages/sol-coverage/test/fixtures/artifacts | ||||
| @@ -39,4 +53,3 @@ packages/abi-gen/test-cli/fixtures/artifacts/AbiGenDummy.json | ||||
| packages/abi-gen/test-cli/fixtures/artifacts/LibDummy.json | ||||
| packages/abi-gen/test-cli/fixtures/artifacts/TestLibDummy.json | ||||
| packages/*/docs | ||||
| packages/website/mdx/tools | ||||
|   | ||||
| @@ -7,7 +7,6 @@ | ||||
| # Website | ||||
| packages/asset-buyer/  @BMillman19 @fragosti @steveklebanoff | ||||
| packages/instant/  @BMillman19 @fragosti @steveklebanoff | ||||
| packages/website/  @BMillman19 @fragosti @fabioberger @steveklebanoff | ||||
|  | ||||
| # Dev tools & setup | ||||
| .circleci/ @LogvinovLeon | ||||
|   | ||||
| @@ -29,9 +29,9 @@ ALL PRs should be opened against `development`. | ||||
|  | ||||
| Branch names should be prefixed with `fix`, `feature` or `refactor`. | ||||
|  | ||||
| -   e.g `fix/broken-wiki-link` | ||||
| -   e.g `fix/missing-import` | ||||
| -   If the PR only edits a single package, add it's name too | ||||
|     -   e.g `fix/website/broken-wiki-link` | ||||
|     -   e.g `fix/subproviders/missing-import` | ||||
|  | ||||
| ### CHANGELOGs | ||||
|  | ||||
|   | ||||
| @@ -47,6 +47,7 @@ These packages are all under development. See [/contracts/README.md](/contracts/ | ||||
| | [`@0x/contracts-utils`](/contracts/utils)                           | [](https://www.npmjs.com/package/@0x/contracts-utils)                           | Generic libraries and utilities used throughout all of the contracts                                                                                                                                                                                  | | ||||
| | [`@0x/contracts-coordinator`](/contracts/coordinator)               | [](https://www.npmjs.com/package/@0x/contracts-coordinator)               | A contract that allows users to execute 0x transactions with permission from a Coordinator                                                                                                                                                            | | ||||
| | [`@0x/contracts-dev-utils`](/contracts/dev-utils)                   | [](https://www.npmjs.com/package/@0x/contracts-dev-utils)                   | A contract contains utility functions for developers (such as validating many orders using a single eth_call)                                                                                                                                         | | ||||
| | [`@0x/contracts-staking`](/contracts/staking)                       | [](https://www.npmjs.com/package/@0x/contracts-staking)                       | Implements the stake-based liquidity incentives defined by [`ZEIP-31`](https://github.com/0xProject/ZEIPs/issues/31)                                                                                                                                  | | ||||
|  | ||||
| ### TypeScript/Javascript Packages | ||||
|  | ||||
| @@ -92,7 +93,6 @@ These packages are all under development. See [/contracts/README.md](/contracts/ | ||||
| | [`@0x/assert`](/packages/assert)                         | [](https://www.npmjs.com/package/@0x/assert)                         | Type and schema assertions used by our packages                 | | ||||
| | [`@0x/base-contract`](/packages/base-contract)           | [](https://www.npmjs.com/package/@0x/base-contract)           | BaseContract used by auto-generated `abi-gen` wrapper contracts | | ||||
| | [`@0x/dev-utils`](/packages/dev-utils)                   | [](https://www.npmjs.com/package/@0x/dev-utils)                   | Dev utils to be shared across 0x packages                       | | ||||
| | [`@0x/fill-scenarios`](/packages/fill-scenarios)         | [](https://www.npmjs.com/package/@0x/fill-scenarios)         | 0x order fill scenario generator                                | | ||||
|  | ||||
| #### Private Packages | ||||
|  | ||||
| @@ -100,7 +100,6 @@ These packages are all under development. See [/contracts/README.md](/contracts/ | ||||
| | -------------------------------------------------- | -------------------------------------------------------------------------------- | | ||||
| | [`@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                 | | ||||
| | [`@0x/website`](/packages/website)                 | 0x website                                                                       | | ||||
|  | ||||
| ## Usage | ||||
|  | ||||
|   | ||||
							
								
								
									
										2
									
								
								contracts/asset-proxy/.solhintignore
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								contracts/asset-proxy/.solhintignore
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| # solhint can't parse `abi.decode` syntax. | ||||
| contracts/src/ERC1155Proxy.sol | ||||
| @@ -1,4 +1,43 @@ | ||||
| [ | ||||
|     { | ||||
|         "version": "2.3.0-beta.0", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Disallow the zero address from being made an authorized address in MixinAuthorizable, and created an archive directory that includes an old version of Ownable", | ||||
|                 "pr": 2019 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Remove `LibAssetProxyIds` contract", | ||||
|                 "pr": 2055 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Compile and export all contracts, artifacts, and wrappers by default", | ||||
|                 "pr": 2055 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Remove unused dependency on IAuthorizable in IAssetProxy", | ||||
|                 "pr": 1910 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Add `ERC20BridgeProxy`", | ||||
|                 "pr": 2220 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Add `Eth2DaiBridge`", | ||||
|                 "pr": 2221 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1570135330 | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1568744790, | ||||
|         "version": "2.2.8", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1567521715, | ||||
|         "version": "2.2.7", | ||||
| @@ -114,6 +153,18 @@ | ||||
|             { | ||||
|                 "note": "Update tests to use contract-built-in `awaitTransactionSuccessAsync`", | ||||
|                 "pr": 1797 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Make `ERC721Wrapper.setApprovalForAll()` take an owner address instead of a token ID", | ||||
|                 "pr": 1819 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Automatically set unlimited proxy allowances in `ERC721.setBalancesAndAllowancesAsync()`", | ||||
|                 "pr": 1819 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Add `setProxyAllowanceForAllAsync()` to `ERC1155ProxyWrapper`.", | ||||
|                 "pr": 1819 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1557507213 | ||||
|   | ||||
| @@ -5,6 +5,19 @@ Edit the package's CHANGELOG.json file only. | ||||
|  | ||||
| CHANGELOG | ||||
|  | ||||
| ## 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) | ||||
|     * Remove `LibAssetProxyIds` contract (#2055) | ||||
|     * Compile and export all contracts, artifacts, and wrappers by default (#2055) | ||||
|     * Remove unused dependency on IAuthorizable in IAssetProxy (#1910) | ||||
|     * Add `ERC20BridgeProxy` (#2220) | ||||
|     * Add `Eth2DaiBridge` (#2221) | ||||
|  | ||||
| ## v2.2.8 - _September 17, 2019_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v2.2.7 - _September 3, 2019_ | ||||
|  | ||||
|     * Dependencies updated | ||||
| @@ -54,6 +67,9 @@ CHANGELOG | ||||
| ## v2.1.2 - _May 10, 2019_ | ||||
|  | ||||
|     * Update tests to use contract-built-in `awaitTransactionSuccessAsync` (#1797) | ||||
|     * Make `ERC721Wrapper.setApprovalForAll()` take an owner address instead of a token ID (#1819) | ||||
|     * Automatically set unlimited proxy allowances in `ERC721.setBalancesAndAllowancesAsync()` (#1819) | ||||
|     * Add `setProxyAllowanceForAllAsync()` to `ERC1155ProxyWrapper`. (#1819) | ||||
|  | ||||
| ## v2.1.1 - _April 11, 2019_ | ||||
|  | ||||
|   | ||||
| @@ -22,17 +22,5 @@ | ||||
|                 ] | ||||
|             } | ||||
|         } | ||||
|     }, | ||||
|     "contracts": [ | ||||
|         "src/ERC1155Proxy.sol", | ||||
|         "src/ERC20Proxy.sol", | ||||
|         "src/ERC721Proxy.sol", | ||||
|         "src/MixinAuthorizable.sol", | ||||
|         "src/MultiAssetProxy.sol", | ||||
|         "src/StaticCallProxy.sol", | ||||
|         "src/interfaces/IAssetData.sol", | ||||
|         "src/interfaces/IAssetProxy.sol", | ||||
|         "src/interfaces/IAuthorizable.sol", | ||||
|         "test/TestStaticCallTarget.sol" | ||||
|     ] | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
| 
 | ||||
|   Copyright 2018 ZeroEx Intl. | ||||
|   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. | ||||
| @@ -16,16 +16,16 @@ | ||||
| 
 | ||||
| */ | ||||
| 
 | ||||
| pragma solidity ^0.5.5; | ||||
| pragma solidity ^0.5.9; | ||||
| 
 | ||||
| import "@0x/contracts-utils/contracts/src/Ownable.sol"; | ||||
| import "./mixins/MAssetProxyDispatcher.sol"; | ||||
| import "./interfaces/IAssetProxy.sol"; | ||||
| import "../archive/Ownable.sol"; | ||||
| import "../src/interfaces/IAssetProxy.sol"; | ||||
| import "../src/interfaces/IAssetProxyDispatcher.sol"; | ||||
| 
 | ||||
| 
 | ||||
| contract MixinAssetProxyDispatcher is | ||||
|     Ownable, | ||||
|     MAssetProxyDispatcher | ||||
|     IAssetProxyDispatcher | ||||
| { | ||||
|     // Mapping from Asset Proxy Id's to their respective Asset Proxy | ||||
|     mapping (bytes4 => address) public assetProxies; | ||||
| @@ -69,7 +69,7 @@ contract MixinAssetProxyDispatcher is | ||||
|     /// @param from Address to transfer token from. | ||||
|     /// @param to Address to transfer token to. | ||||
|     /// @param amount Amount of token to transfer. | ||||
|     function dispatchTransferFrom( | ||||
|     function _dispatchTransferFrom( | ||||
|         bytes memory assetData, | ||||
|         address from, | ||||
|         address to, | ||||
| @@ -84,7 +84,7 @@ contract MixinAssetProxyDispatcher is | ||||
|                 assetData.length > 3, | ||||
|                 "LENGTH_GREATER_THAN_3_REQUIRED" | ||||
|             ); | ||||
|              | ||||
| 
 | ||||
|             // Lookup assetProxy. We do not use `LibBytes.readBytes4` for gas efficiency reasons. | ||||
|             bytes4 assetProxyId; | ||||
|             assembly { | ||||
| @@ -100,10 +100,10 @@ contract MixinAssetProxyDispatcher is | ||||
|                 assetProxy != address(0), | ||||
|                 "ASSET_PROXY_DOES_NOT_EXIST" | ||||
|             ); | ||||
|              | ||||
| 
 | ||||
|             // We construct calldata for the `assetProxy.transferFrom` ABI. | ||||
|             // The layout of this calldata is in the table below. | ||||
|             //  | ||||
|             // | ||||
|             // | Area     | Offset | Length  | Contents                                    | | ||||
|             // | -------- |--------|---------|-------------------------------------------- | | ||||
|             // | Header   | 0      | 4       | function selector                           | | ||||
| @@ -127,12 +127,12 @@ contract MixinAssetProxyDispatcher is | ||||
|                 // `cdEnd` is the end of the calldata for `assetProxy.transferFrom`. | ||||
|                 let cdEnd := add(cdStart, add(132, dataAreaLength)) | ||||
| 
 | ||||
|                  | ||||
| 
 | ||||
|                 /////// Setup Header Area /////// | ||||
|                 // This area holds the 4-byte `transferFromSelector`. | ||||
|                 // bytes4(keccak256("transferFrom(bytes,address,address,uint256)")) = 0xa85e59e4 | ||||
|                 mstore(cdStart, 0xa85e59e400000000000000000000000000000000000000000000000000000000) | ||||
|                  | ||||
| 
 | ||||
|                 /////// Setup Params Area /////// | ||||
|                 // Each parameter is padded to 32-bytes. The entire Params Area is 128 bytes. | ||||
|                 // Notes: | ||||
| @@ -142,7 +142,7 @@ contract MixinAssetProxyDispatcher is | ||||
|                 mstore(add(cdStart, 36), and(from, 0xffffffffffffffffffffffffffffffffffffffff)) | ||||
|                 mstore(add(cdStart, 68), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) | ||||
|                 mstore(add(cdStart, 100), amount) | ||||
|                  | ||||
| 
 | ||||
|                 /////// Setup Data Area /////// | ||||
|                 // This area holds `assetData`. | ||||
|                 let dataArea := add(cdStart, 132) | ||||
| @@ -159,7 +159,7 @@ contract MixinAssetProxyDispatcher is | ||||
|                     assetProxy,             // call address of asset proxy | ||||
|                     0,                      // don't send any ETH | ||||
|                     cdStart,                // pointer to start of input | ||||
|                     sub(cdEnd, cdStart),    // length of input   | ||||
|                     sub(cdEnd, cdStart),    // length of input | ||||
|                     cdStart,                // write output over input | ||||
|                     512                     // reserve 512 bytes for output | ||||
|                 ) | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
| 
 | ||||
|   Copyright 2018 ZeroEx Intl. | ||||
|   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. | ||||
| @@ -16,15 +16,15 @@ | ||||
| 
 | ||||
| */ | ||||
| 
 | ||||
| pragma solidity ^0.5.5; | ||||
| pragma solidity ^0.5.9; | ||||
| 
 | ||||
| import "@0x/contracts-utils/contracts/src/Ownable.sol"; | ||||
| import "./mixins/MAuthorizable.sol"; | ||||
| import "../archive/Ownable.sol"; | ||||
| import "../src/interfaces/IAuthorizable.sol"; | ||||
| 
 | ||||
| 
 | ||||
| contract MixinAuthorizable is | ||||
|     Ownable, | ||||
|     MAuthorizable | ||||
|     IAuthorizable | ||||
| { | ||||
|     /// @dev Only authorized addresses can invoke functions with this modifier. | ||||
|     modifier onlyAuthorized { | ||||
							
								
								
									
										33
									
								
								contracts/asset-proxy/contracts/archive/Ownable.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								contracts/asset-proxy/contracts/archive/Ownable.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | ||||
| pragma solidity ^0.5.9; | ||||
|  | ||||
| import "@0x/contracts-utils/contracts/src/interfaces/IOwnable.sol"; | ||||
|  | ||||
|  | ||||
| contract Ownable is | ||||
|     IOwnable | ||||
| { | ||||
|     address public owner; | ||||
|  | ||||
|     constructor () | ||||
|         public | ||||
|     { | ||||
|         owner = msg.sender; | ||||
|     } | ||||
|  | ||||
|     modifier onlyOwner() { | ||||
|         require( | ||||
|             msg.sender == owner, | ||||
|             "ONLY_CONTRACT_OWNER" | ||||
|         ); | ||||
|         _; | ||||
|     } | ||||
|  | ||||
|     function transferOwnership(address newOwner) | ||||
|         public | ||||
|         onlyOwner | ||||
|     { | ||||
|         if (newOwner != address(0)) { | ||||
|             owner = newOwner; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|  | ||||
|   Copyright 2018 ZeroEx Intl. | ||||
|   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. | ||||
| @@ -21,7 +21,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-erc1155/contracts/src/interfaces/IERC1155.sol"; | ||||
| import "./MixinAuthorizable.sol"; | ||||
| import "../archive/MixinAuthorizable.sol"; | ||||
| import "./interfaces/IAssetProxy.sol"; | ||||
|  | ||||
|  | ||||
| @@ -69,9 +69,9 @@ contract ERC1155Proxy is | ||||
|         for (uint256 i = 0; i != length; i++) { | ||||
|             // We write the scaled values to an unused location in memory in order | ||||
|             // 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  | ||||
|             // 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] = _safeMul(values[i], amount); | ||||
|         } | ||||
|  | ||||
|         // Execute `safeBatchTransferFrom` call | ||||
|   | ||||
							
								
								
									
										126
									
								
								contracts/asset-proxy/contracts/src/ERC20BridgeProxy.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								contracts/asset-proxy/contracts/src/ERC20BridgeProxy.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,126 @@ | ||||
| /* | ||||
|  | ||||
|   Copyright 2019 ZeroEx Intl. | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
|  | ||||
| */ | ||||
|  | ||||
| pragma solidity ^0.5.9; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "@0x/contracts-utils/contracts/src/LibBytes.sol"; | ||||
| import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; | ||||
| import "@0x/contracts-utils/contracts/src/Authorizable.sol"; | ||||
| import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; | ||||
| import "./interfaces/IAssetProxy.sol"; | ||||
| import "./interfaces/IERC20Bridge.sol"; | ||||
|  | ||||
|  | ||||
| contract ERC20BridgeProxy is | ||||
|     IAssetProxy, | ||||
|     Authorizable | ||||
| { | ||||
|     using LibBytes for bytes; | ||||
|     using LibSafeMath for uint256; | ||||
|  | ||||
|     // @dev Id of this proxy. Also the result of a successful bridge call. | ||||
|     //      bytes4(keccak256("ERC20Bridge(address,address,bytes)")) | ||||
|     bytes4 constant private PROXY_ID = 0xdc1600f3; | ||||
|  | ||||
|     /// @dev Calls a bridge contract to transfer `amount` of ERC20 from `from` | ||||
|     ///      to `to`. Asserts that the balance of `to` has increased by `amount`. | ||||
|     /// @param assetData Abi-encoded data for this asset proxy encoded as: | ||||
|     ///          abi.encodeWithSelector( | ||||
|     ///             bytes4 PROXY_ID, | ||||
|     ///             address tokenAddress, | ||||
|     ///             address bridgeAddress, | ||||
|     ///             bytes bridgeData | ||||
|     ///          ) | ||||
|     /// @param from Address to transfer asset from. | ||||
|     /// @param to Address to transfer asset to. | ||||
|     /// @param amount Amount of asset to transfer. | ||||
|     function transferFrom( | ||||
|         bytes calldata assetData, | ||||
|         address from, | ||||
|         address to, | ||||
|         uint256 amount | ||||
|     ) | ||||
|         external | ||||
|         onlyAuthorized | ||||
|     { | ||||
|         // Extract asset data fields. | ||||
|         ( | ||||
|             address tokenAddress, | ||||
|             address bridgeAddress, | ||||
|             bytes memory bridgeData | ||||
|         ) = abi.decode( | ||||
|             assetData.sliceDestructive(4, assetData.length), | ||||
|             (address, address, bytes) | ||||
|         ); | ||||
|  | ||||
|         // Remember the balance of `to` before calling the bridge. | ||||
|         uint256 balanceBefore = balanceOf(tokenAddress, to); | ||||
|         // Call the bridge, who should transfer `amount` of `tokenAddress` to | ||||
|         // `to`. | ||||
|         bytes4 success = IERC20Bridge(bridgeAddress).withdrawTo( | ||||
|             tokenAddress, | ||||
|             from, | ||||
|             to, | ||||
|             amount, | ||||
|             bridgeData | ||||
|         ); | ||||
|         // Bridge must return the proxy ID to indicate success. | ||||
|         require(success == PROXY_ID, "BRIDGE_FAILED"); | ||||
|         // Ensure that the balance of `to` has increased by at least `amount`. | ||||
|         require( | ||||
|             balanceBefore.safeAdd(amount) <= balanceOf(tokenAddress, to), | ||||
|             "BRIDGE_UNDERPAY" | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     /// @dev Gets the proxy id associated with this asset proxy. | ||||
|     /// @return proxyId The proxy id. | ||||
|     function getProxyId() | ||||
|         external | ||||
|         pure | ||||
|         returns (bytes4 proxyId) | ||||
|     { | ||||
|         return PROXY_ID; | ||||
|     } | ||||
|  | ||||
|     /// @dev Retrieves the balance of `owner` for this asset. | ||||
|     /// @return balance The balance of the ERC20 token being transferred by this | ||||
|     ///         asset proxy. | ||||
|     function balanceOf(bytes calldata assetData, address owner) | ||||
|         external | ||||
|         view | ||||
|         returns (uint256 balance) | ||||
|     { | ||||
|         (address tokenAddress) = abi.decode( | ||||
|             assetData.sliceDestructive(4, assetData.length), | ||||
|             (address) | ||||
|         ); | ||||
|         return balanceOf(tokenAddress, owner); | ||||
|     } | ||||
|  | ||||
|     /// @dev Retrieves the balance of `owner` given an ERC20 address. | ||||
|     /// @return balance The balance of the ERC20 token for `owner`. | ||||
|     function balanceOf(address tokenAddress, address owner) | ||||
|         private | ||||
|         view | ||||
|         returns (uint256 balance) | ||||
|     { | ||||
|         return IERC20Token(tokenAddress).balanceOf(owner); | ||||
|     } | ||||
| } | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|  | ||||
|   Copyright 2018 ZeroEx Intl. | ||||
|   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. | ||||
| @@ -16,9 +16,9 @@ | ||||
|  | ||||
| */ | ||||
|  | ||||
| pragma solidity ^0.5.5; | ||||
| pragma solidity ^0.5.9; | ||||
|  | ||||
| import "./MixinAuthorizable.sol"; | ||||
| import "../archive/MixinAuthorizable.sol"; | ||||
|  | ||||
|  | ||||
| contract ERC20Proxy is | ||||
| @@ -26,9 +26,9 @@ contract ERC20Proxy is | ||||
| { | ||||
|     // Id of this proxy. | ||||
|     bytes4 constant internal PROXY_ID = bytes4(keccak256("ERC20Token(address)")); | ||||
|      | ||||
|  | ||||
|     // solhint-disable-next-line payable-fallback | ||||
|     function ()  | ||||
|     function () | ||||
|         external | ||||
|     { | ||||
|         assembly { | ||||
| @@ -117,13 +117,13 @@ contract ERC20Proxy is | ||||
|                 // * The "token address" is offset 32+4=36 bytes into "assetData" (tables 1 & 2). | ||||
|                 //   [tokenOffset = assetDataOffsetFromHeader + 36 = calldataload(4) + 4 + 36] | ||||
|                 let token := calldataload(add(calldataload(4), 40)) | ||||
|                  | ||||
|  | ||||
|                 /////// Setup Header Area /////// | ||||
|                 // This area holds the 4-byte `transferFrom` selector. | ||||
|                 // Any trailing data in transferFromSelector will be | ||||
|                 // overwritten in the next `mstore` call. | ||||
|                 mstore(0, 0x23b872dd00000000000000000000000000000000000000000000000000000000) | ||||
|                  | ||||
|  | ||||
|                 /////// Setup Params Area /////// | ||||
|                 // We copy the fields `from`, `to` and `amount` in bulk | ||||
|                 // from our own calldata to the new calldata. | ||||
| @@ -147,7 +147,7 @@ contract ERC20Proxy is | ||||
|                 // If the token does return data, we require that it is a single | ||||
|                 // nonzero 32 bytes value. | ||||
|                 // So the transfer succeeded if the call succeeded and either | ||||
|                 // returned nothing, or returned a non-zero 32 byte value.  | ||||
|                 // returned nothing, or returned a non-zero 32 byte value. | ||||
|                 success := and(success, or( | ||||
|                     iszero(returndatasize), | ||||
|                     and( | ||||
| @@ -158,7 +158,7 @@ contract ERC20Proxy is | ||||
|                 if success { | ||||
|                     return(0, 0) | ||||
|                 } | ||||
|                  | ||||
|  | ||||
|                 // Revert with `Error("TRANSFER_FAILED")` | ||||
|                 mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000) | ||||
|                 mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000) | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|  | ||||
|   Copyright 2018 ZeroEx Intl. | ||||
|   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. | ||||
| @@ -16,9 +16,9 @@ | ||||
|  | ||||
| */ | ||||
|  | ||||
| pragma solidity ^0.5.5; | ||||
| pragma solidity ^0.5.9; | ||||
|  | ||||
| import "./MixinAuthorizable.sol"; | ||||
| import "../archive/MixinAuthorizable.sol"; | ||||
|  | ||||
|  | ||||
| contract ERC721Proxy is | ||||
| @@ -28,7 +28,7 @@ contract ERC721Proxy is | ||||
|     bytes4 constant internal PROXY_ID = bytes4(keccak256("ERC721Token(address,uint256)")); | ||||
|  | ||||
|     // solhint-disable-next-line payable-fallback | ||||
|     function ()  | ||||
|     function () | ||||
|         external | ||||
|     { | ||||
|         assembly { | ||||
| @@ -93,10 +93,10 @@ contract ERC721Proxy is | ||||
|                 // | Params   |        | 2 * 32  | function parameters:                | | ||||
|                 // |          | 4      | 12 + 20 |   1. token address                  | | ||||
|                 // |          | 36     |         |   2. tokenId                        | | ||||
|                  | ||||
|  | ||||
|                 // We construct calldata for the `token.transferFrom` ABI. | ||||
|                 // The layout of this calldata is in the table below. | ||||
|                 //  | ||||
|                 // | ||||
|                 // | Area     | Offset | Length  | Contents                            | | ||||
|                 // |----------|--------|---------|-------------------------------------| | ||||
|                 // | Header   | 0      | 4       | function selector                   | | ||||
| @@ -121,7 +121,7 @@ contract ERC721Proxy is | ||||
|                 // Any trailing data in transferFromSelector will be | ||||
|                 // overwritten in the next `mstore` call. | ||||
|                 mstore(0, 0x23b872dd00000000000000000000000000000000000000000000000000000000) | ||||
|                  | ||||
|  | ||||
|                 /////// Setup Params Area /////// | ||||
|                 // We copy the fields `from` and `to` in bulk | ||||
|                 // from our own calldata to the new calldata. | ||||
| @@ -145,7 +145,7 @@ contract ERC721Proxy is | ||||
|                 if success { | ||||
|                     return(0, 0) | ||||
|                 } | ||||
|                  | ||||
|  | ||||
|                 // Revert with `Error("TRANSFER_FAILED")` | ||||
|                 mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000) | ||||
|                 mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000) | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|  | ||||
|   Copyright 2018 ZeroEx Intl. | ||||
|   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. | ||||
| @@ -16,10 +16,10 @@ | ||||
|  | ||||
| */ | ||||
|  | ||||
| pragma solidity ^0.5.5; | ||||
| pragma solidity ^0.5.9; | ||||
|  | ||||
| import "./MixinAssetProxyDispatcher.sol"; | ||||
| import "./MixinAuthorizable.sol"; | ||||
| import "../archive/MixinAssetProxyDispatcher.sol"; | ||||
| import "../archive/MixinAuthorizable.sol"; | ||||
|  | ||||
|  | ||||
| contract MultiAssetProxy is | ||||
| @@ -105,7 +105,7 @@ contract MultiAssetProxy is | ||||
|                 // |          | 36          |         |   2. offset to nestedAssetData (*)  | | ||||
|                 // | Data     |             |         | amounts:                            | | ||||
|                 // |          | 68          | 32      | amounts Length                      | | ||||
|                 // |          | 100         | a       | amounts Contents                    |  | ||||
|                 // |          | 100         | a       | amounts Contents                    | | ||||
|                 // |          |             |         | nestedAssetData:                    | | ||||
|                 // |          | 100 + a     | 32      | nestedAssetData Length              | | ||||
|                 // |          | 132 + a     | b       | nestedAssetData Contents (offsets)  | | ||||
| @@ -149,8 +149,8 @@ contract MultiAssetProxy is | ||||
|                 // + 32 (amounts offset) | ||||
|                 let nestedAssetDataOffset := calldataload(add(assetDataOffset, 68)) | ||||
|  | ||||
|                 // In order to find the start of the `amounts` contents, we must add:  | ||||
|                 // assetDataOffset  | ||||
|                 // In order to find the start of the `amounts` contents, we must add: | ||||
|                 // assetDataOffset | ||||
|                 // + 32 (assetData len) | ||||
|                 // + 4 (assetProxyId) | ||||
|                 // + amountsOffset | ||||
| @@ -160,8 +160,8 @@ contract MultiAssetProxy is | ||||
|                 // Load number of elements in `amounts` | ||||
|                 let amountsLen := calldataload(sub(amountsContentsStart, 32)) | ||||
|  | ||||
|                 // In order to find the start of the `nestedAssetData` contents, we must add:  | ||||
|                 // assetDataOffset  | ||||
|                 // In order to find the start of the `nestedAssetData` contents, we must add: | ||||
|                 // assetDataOffset | ||||
|                 // + 32 (assetData len) | ||||
|                 // + 4 (assetProxyId) | ||||
|                 // + nestedAssetDataOffset | ||||
| @@ -190,10 +190,10 @@ contract MultiAssetProxy is | ||||
|  | ||||
|                 // Overwrite existing offset to `assetData` with our own | ||||
|                 mstore(4, 128) | ||||
|                  | ||||
|  | ||||
|                 // Load `amount` | ||||
|                 let amount := calldataload(100) | ||||
|          | ||||
|  | ||||
|                 // Calculate number of bytes in `amounts` contents | ||||
|                 let amountsByteLen := mul(amountsLen, 32) | ||||
|  | ||||
| @@ -208,7 +208,7 @@ contract MultiAssetProxy is | ||||
|                     let amountsElement := calldataload(add(amountsContentsStart, i)) | ||||
|                     let totalAmount := mul(amountsElement, amount) | ||||
|  | ||||
|                     // Revert if `amount` != 0 and multiplication resulted in an overflow  | ||||
|                     // Revert if `amount` != 0 and multiplication resulted in an overflow | ||||
|                     if iszero(or( | ||||
|                         iszero(amount), | ||||
|                         eq(div(totalAmount, amount), amountsElement) | ||||
| @@ -228,7 +228,7 @@ contract MultiAssetProxy is | ||||
|                     let nestedAssetDataElementOffset := calldataload(add(nestedAssetDataContentsStart, i)) | ||||
|  | ||||
|                     // In order to find the start of the `nestedAssetData[i]` contents, we must add: | ||||
|                     // assetDataOffset  | ||||
|                     // assetDataOffset | ||||
|                     // + 32 (assetData len) | ||||
|                     // + 4 (assetProxyId) | ||||
|                     // + nestedAssetDataOffset | ||||
| @@ -274,7 +274,7 @@ contract MultiAssetProxy is | ||||
|                         mstore(164, assetProxies_slot) | ||||
|                         assetProxy := sload(keccak256(132, 64)) | ||||
|                     } | ||||
|                      | ||||
|  | ||||
|                     // Revert if AssetProxy with given id does not exist | ||||
|                     if iszero(assetProxy) { | ||||
|                         // Revert with `Error("ASSET_PROXY_DOES_NOT_EXIST")` | ||||
| @@ -284,7 +284,7 @@ contract MultiAssetProxy is | ||||
|                         mstore(96, 0) | ||||
|                         revert(0, 100) | ||||
|                     } | ||||
|      | ||||
|  | ||||
|                     // Copy `nestedAssetData[i]` from calldata to memory | ||||
|                     calldatacopy( | ||||
|                         132,                                // memory slot after `amounts[i]` | ||||
| @@ -298,7 +298,7 @@ contract MultiAssetProxy is | ||||
|                         assetProxy,                             // call address of asset proxy | ||||
|                         0,                                      // don't send any ETH | ||||
|                         0,                                      // pointer to start of input | ||||
|                         add(164, nestedAssetDataElementLen),    // length of input   | ||||
|                         add(164, nestedAssetDataElementLen),    // length of input | ||||
|                         0,                                      // write output over memory that won't be reused | ||||
|                         0                                       // don't copy output to memory | ||||
|                     ) | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|  | ||||
|   Copyright 2018 ZeroEx Intl. | ||||
|   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. | ||||
|   | ||||
							
								
								
									
										142
									
								
								contracts/asset-proxy/contracts/src/bridges/Eth2DaiBridge.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										142
									
								
								contracts/asset-proxy/contracts/src/bridges/Eth2DaiBridge.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,142 @@ | ||||
| /* | ||||
|  | ||||
|   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 "../interfaces/IERC20Bridge.sol"; | ||||
| import "../interfaces/IEth2Dai.sol"; | ||||
| import "../interfaces/IWallet.sol"; | ||||
|  | ||||
|  | ||||
| // solhint-disable space-after-comma | ||||
| contract Eth2DaiBridge is | ||||
|     IERC20Bridge, | ||||
|     IWallet | ||||
| { | ||||
|     /* Mainnet addresses */ | ||||
|     address constant public ETH2DAI_ADDRESS = 0x39755357759cE0d7f32dC8dC45414CCa409AE24e; | ||||
|  | ||||
|     /// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of | ||||
|     ///      `toTokenAddress` tokens by selling the entirety of the opposing asset | ||||
|     ///      (DAI or WETH) to the Eth2Dai contract, then transfers the bought | ||||
|     ///      tokens to `to`. | ||||
|     /// @param toTokenAddress The token to give to `to` (either DAI or WETH). | ||||
|     /// @param to The recipient of the bought tokens. | ||||
|     /// @param amount Minimum amount of `toTokenAddress` tokens to buy. | ||||
|     /// @param bridgeData The abi-encoeded "from" token address. | ||||
|     /// @return success The magic bytes if successful. | ||||
|     function withdrawTo( | ||||
|         address toTokenAddress, | ||||
|         address /* from */, | ||||
|         address to, | ||||
|         uint256 amount, | ||||
|         bytes calldata bridgeData | ||||
|     ) | ||||
|         external | ||||
|         returns (bytes4 success) | ||||
|     { | ||||
|         // Decode the bridge data to get the `fromTokenAddress`. | ||||
|         (address fromTokenAddress) = abi.decode(bridgeData, (address)); | ||||
|  | ||||
|         IEth2Dai exchange = _getEth2DaiContract(); | ||||
|         // Grant an allowance to the exchange to spend `fromTokenAddress` token. | ||||
|         IERC20Token(fromTokenAddress).approve(address(exchange), uint256(-1)); | ||||
|  | ||||
|         // Try to sell all of this contract's `fromTokenAddress` token balance. | ||||
|         uint256 boughtAmount = _getEth2DaiContract().sellAllAmount( | ||||
|             address(fromTokenAddress), | ||||
|             IERC20Token(fromTokenAddress).balanceOf(address(this)), | ||||
|             toTokenAddress, | ||||
|             amount | ||||
|         ); | ||||
|         // Transfer the converted `toToken`s to `to`. | ||||
|         _transferERC20Token(toTokenAddress, to, boughtAmount); | ||||
|         return BRIDGE_SUCCESS; | ||||
|     } | ||||
|  | ||||
|     /// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker | ||||
|     ///      and sign for itself in orders. Always succeeds. | ||||
|     /// @return magicValue Magic success bytes, always. | ||||
|     function isValidSignature( | ||||
|         bytes32, | ||||
|         bytes calldata | ||||
|     ) | ||||
|         external | ||||
|         view | ||||
|         returns (bytes4 magicValue) | ||||
|     { | ||||
|         return LEGACY_WALLET_MAGIC_VALUE; | ||||
|     } | ||||
|  | ||||
|     /// @dev Overridable way to get the eth2dai contract. | ||||
|     /// @return exchange The Eth2Dai exchange contract. | ||||
|     function _getEth2DaiContract() | ||||
|         internal | ||||
|         view | ||||
|         returns (IEth2Dai exchange) | ||||
|     { | ||||
|         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"); | ||||
|     } | ||||
| } | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|  | ||||
|   Copyright 2018 ZeroEx Intl. | ||||
|   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. | ||||
| @@ -17,7 +17,7 @@ | ||||
| */ | ||||
|  | ||||
| // solhint-disable | ||||
| pragma solidity ^0.5.5; | ||||
| pragma solidity ^0.5.9; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
|  | ||||
| @@ -26,33 +26,63 @@ pragma experimental ABIEncoderV2; | ||||
| // This argument is ABI encoded as one of the methods of this interface. | ||||
| interface IAssetData { | ||||
|  | ||||
|     /// @dev Function signature for encoding ERC20 assetData. | ||||
|     /// @param tokenAddress Address of ERC20Token contract. | ||||
|     function ERC20Token(address tokenAddress) | ||||
|         external; | ||||
|      | ||||
|  | ||||
|     /// @dev Function signature for encoding ERC721 assetData. | ||||
|     /// @param tokenAddress Address of ERC721 token contract. | ||||
|     /// @param tokenId Id of ERC721 token to be transferred. | ||||
|     function ERC721Token( | ||||
|         address tokenAddress, | ||||
|         uint256 tokenId | ||||
|     ) | ||||
|         external; | ||||
|  | ||||
|     /// @dev Function signature for encoding ERC1155 assetData. | ||||
|     /// @param tokenAddress Address of ERC1155 token contract. | ||||
|     /// @param tokenIds Array of ids of tokens to be transferred. | ||||
|     /// @param values Array of values that correspond to each token id to be transferred. | ||||
|     ///        Note that each value will be multiplied by the amount being filled in the order before transferring. | ||||
|     /// @param callbackData Extra data to be passed to receiver's `onERC1155Received` callback function. | ||||
|     function ERC1155Assets( | ||||
|         address tokenAddress, | ||||
|         uint256[] calldata tokenIds, | ||||
|         uint256[] calldata tokenValues, | ||||
|         uint256[] calldata values, | ||||
|         bytes calldata callbackData | ||||
|     ) | ||||
|         external; | ||||
|  | ||||
|     /// @dev Function signature for encoding MultiAsset assetData. | ||||
|     /// @param values Array of amounts that correspond to each asset to be transferred. | ||||
|     ///        Note that each value will be multiplied by the amount being filled in the order before transferring. | ||||
|     /// @param nestedAssetData Array of assetData fields that will be be dispatched to their correspnding AssetProxy contract. | ||||
|     function MultiAsset( | ||||
|         uint256[] calldata amounts, | ||||
|         uint256[] calldata values, | ||||
|         bytes[] calldata nestedAssetData | ||||
|     ) | ||||
|         external; | ||||
|  | ||||
|     /// @dev Function signature for encoding StaticCall assetData. | ||||
|     /// @param staticCallTargetAddress Address that will execute the staticcall. | ||||
|     /// @param staticCallData Data that will be executed via staticcall on the staticCallTargetAddress. | ||||
|     /// @param expectedReturnDataHash Keccak-256 hash of the expected staticcall return data. | ||||
|     function StaticCall( | ||||
|         address callTarget, | ||||
|         address staticCallTargetAddress, | ||||
|         bytes calldata staticCallData, | ||||
|         bytes32 callResultHash | ||||
|         bytes32 expectedReturnDataHash | ||||
|     ) | ||||
|         external; | ||||
|  | ||||
|     /// @dev Function signature for encoding ERC20Bridge assetData. | ||||
|     /// @param tokenAddress Address of token to transfer. | ||||
|     /// @param bridgeAddress Address of the bridge contract. | ||||
|     /// @param bridgeData Arbitrary data to be passed to the bridge contract. | ||||
|     function ERC20Bridge( | ||||
|         address tokenAddress, | ||||
|         address bridgeAddress, | ||||
|         bytes calldata bridgeData | ||||
|     ) | ||||
|         external; | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|  | ||||
|   Copyright 2018 ZeroEx Intl. | ||||
|   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. | ||||
| @@ -16,9 +16,7 @@ | ||||
|  | ||||
| */ | ||||
|  | ||||
| pragma solidity ^0.5.5; | ||||
|  | ||||
| import "./IAuthorizable.sol"; | ||||
| pragma solidity ^0.5.9; | ||||
|  | ||||
|  | ||||
| contract IAssetProxy { | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|  | ||||
|   Copyright 2018 ZeroEx Intl. | ||||
|   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. | ||||
| @@ -16,11 +16,17 @@ | ||||
|  | ||||
| */ | ||||
|  | ||||
| pragma solidity ^0.5.5; | ||||
| pragma solidity ^0.5.9; | ||||
|  | ||||
|  | ||||
| contract IAssetProxyDispatcher { | ||||
|  | ||||
|     // Logs registration of new asset proxy | ||||
|     event AssetProxyRegistered( | ||||
|         bytes4 id,              // Id of new registered AssetProxy. | ||||
|         address assetProxy      // Address of new registered AssetProxy. | ||||
|     ); | ||||
|  | ||||
|     /// @dev Registers an asset proxy to its asset proxy id. | ||||
|     ///      Once an asset proxy is registered, it cannot be unregistered. | ||||
|     /// @param assetProxy Address of new asset proxy to register. | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|  | ||||
|   Copyright 2018 ZeroEx Intl. | ||||
|   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. | ||||
| @@ -16,7 +16,7 @@ | ||||
|  | ||||
| */ | ||||
|  | ||||
| pragma solidity ^0.5.5; | ||||
| pragma solidity ^0.5.9; | ||||
|  | ||||
| import "@0x/contracts-utils/contracts/src/interfaces/IOwnable.sol"; | ||||
|  | ||||
| @@ -24,6 +24,18 @@ import "@0x/contracts-utils/contracts/src/interfaces/IOwnable.sol"; | ||||
| contract IAuthorizable is | ||||
|     IOwnable | ||||
| { | ||||
|     // Event logged when a new address is authorized. | ||||
|     event AuthorizedAddressAdded( | ||||
|         address indexed target, | ||||
|         address indexed caller | ||||
|     ); | ||||
|  | ||||
|     // Event logged when a currently authorized address is unauthorized. | ||||
|     event AuthorizedAddressRemoved( | ||||
|         address indexed target, | ||||
|         address indexed caller | ||||
|     ); | ||||
|  | ||||
|     /// @dev Authorizes an address. | ||||
|     /// @param target Address to authorize. | ||||
|     function addAuthorizedAddress(address target) | ||||
| @@ -42,7 +54,7 @@ contract IAuthorizable is | ||||
|         uint256 index | ||||
|     ) | ||||
|         external; | ||||
|      | ||||
|  | ||||
|     /// @dev Gets all authorized addresses. | ||||
|     /// @return Array of authorized addresses. | ||||
|     function getAuthorizedAddresses() | ||||
|   | ||||
| @@ -0,0 +1,43 @@ | ||||
| /* | ||||
|  | ||||
|   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; | ||||
|  | ||||
|  | ||||
| contract IERC20Bridge { | ||||
|  | ||||
|     // @dev Result of a successful bridge call. | ||||
|     bytes4 constant internal BRIDGE_SUCCESS = 0xdc1600f3; | ||||
|  | ||||
|     /// @dev Transfers `amount` of the ERC20 `tokenAddress` from `from` to `to`. | ||||
|     /// @param tokenAddress The address of the ERC20 token to transfer. | ||||
|     /// @param from Address to transfer asset from. | ||||
|     /// @param to Address to transfer asset to. | ||||
|     /// @param amount Amount of asset to transfer. | ||||
|     /// @param bridgeData Arbitrary asset data needed by the bridge contract. | ||||
|     /// @return success The magic bytes `0x37708e9b` if successful. | ||||
|     function withdrawTo( | ||||
|         address tokenAddress, | ||||
|         address from, | ||||
|         address to, | ||||
|         uint256 amount, | ||||
|         bytes calldata bridgeData | ||||
|     ) | ||||
|         external | ||||
|         returns (bytes4 success); | ||||
| } | ||||
							
								
								
									
										38
									
								
								contracts/asset-proxy/contracts/src/interfaces/IEth2Dai.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								contracts/asset-proxy/contracts/src/interfaces/IEth2Dai.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | ||||
| /* | ||||
|  | ||||
|   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 IEth2Dai { | ||||
|  | ||||
|     /// @dev Sell `sellAmount` of `fromToken` token and receive `toToken` token. | ||||
|     /// @param fromToken The token being sold. | ||||
|     /// @param sellAmount The amount of `fromToken` token being sold. | ||||
|     /// @param toToken The token being bought. | ||||
|     /// @param minFillAmount Minimum amount of `toToken` token to buy. | ||||
|     /// @return fillAmount Amount of `toToken` bought. | ||||
|     function sellAllAmount( | ||||
|         address fromToken, | ||||
|         uint256 sellAmount, | ||||
|         address toToken, | ||||
|         uint256 minFillAmount | ||||
|     ) | ||||
|         external | ||||
|         returns (uint256 fillAmount); | ||||
| } | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
| 
 | ||||
|   Copyright 2018 ZeroEx Intl. | ||||
|   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. | ||||
| @@ -16,23 +16,23 @@ | ||||
| 
 | ||||
| */ | ||||
| 
 | ||||
| pragma solidity ^0.5.5; | ||||
| pragma solidity ^0.5.9; | ||||
| pragma experimental ABIEncoderV2; | ||||
| 
 | ||||
| 
 | ||||
| contract IValidator { | ||||
| contract IWallet { | ||||
| 
 | ||||
|     /// @dev Verifies that a signature is valid. | ||||
|     bytes4 internal constant LEGACY_WALLET_MAGIC_VALUE = 0xb0671381; | ||||
| 
 | ||||
|     /// @dev Validates a hash with the `Wallet` signature type. | ||||
|     /// @param hash Message hash that is signed. | ||||
|     /// @param signerAddress Address that should have signed the given hash. | ||||
|     /// @param signature Proof of signing. | ||||
|     /// @return Magic bytes4 value if the signature is valid. | ||||
|     ///         Magic value is bytes4(keccak256("isValidValidatorSignature(address,bytes32,address,bytes)")) | ||||
|     /// @return magicValue `bytes4(0xb0671381)` if the signature check succeeds. | ||||
|     function isValidSignature( | ||||
|         bytes32 hash, | ||||
|         address signerAddress, | ||||
|         bytes calldata signature | ||||
|     ) | ||||
|         external | ||||
|         view | ||||
|         returns (bytes4); | ||||
|         returns (bytes4 magicValue); | ||||
| } | ||||
| @@ -1,40 +0,0 @@ | ||||
| /* | ||||
|  | ||||
|   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.5; | ||||
|  | ||||
|  | ||||
| contract LibAssetProxyIds { | ||||
|  | ||||
|     // AssetProxy Ids are equiavalent the first 4 bytes of the keccak256 hash of the function signature assigned to each AssetProxy. | ||||
|  | ||||
|     // ERC20Token(address) | ||||
|     bytes4 constant public ERC20_PROXY_ID = 0xf47261b0; | ||||
|  | ||||
|     // ERC721Token(address,uint256) | ||||
|     bytes4 constant public ERC721_PROXY_ID = 0x02571792; | ||||
|  | ||||
|     // ERC1155Assets(address,uint256[],uint256[],bytes) | ||||
|     bytes4 constant public ERC1155_PROXY_ID = 0xa7cb5fb7; | ||||
|  | ||||
|     // MultiAsset(uint256[],bytes[]) | ||||
|     bytes4 constant public MULTI_ASSET_PROXY_ID = 0x94cfcdd7; | ||||
|  | ||||
|     // StaticCall(address,bytes,bytes32) | ||||
|     bytes4 constant public STATIC_CALL_PROXY_ID = 0xc339d10a; | ||||
| } | ||||
| @@ -1,45 +0,0 @@ | ||||
| /* | ||||
|  | ||||
|   Copyright 2018 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.5; | ||||
|  | ||||
| import "../interfaces/IAssetProxyDispatcher.sol"; | ||||
|  | ||||
|  | ||||
| contract MAssetProxyDispatcher is | ||||
|     IAssetProxyDispatcher | ||||
| { | ||||
|     // Logs registration of new asset proxy | ||||
|     event AssetProxyRegistered( | ||||
|         bytes4 id,              // Id of new registered AssetProxy. | ||||
|         address assetProxy      // Address of new registered AssetProxy. | ||||
|     ); | ||||
|  | ||||
|     /// @dev Forwards arguments to assetProxy and calls `transferFrom`. Either succeeds or throws. | ||||
|     /// @param assetData Byte array encoded for the asset. | ||||
|     /// @param from Address to transfer token from. | ||||
|     /// @param to Address to transfer token to. | ||||
|     /// @param amount Amount of token to transfer. | ||||
|     function dispatchTransferFrom( | ||||
|         bytes memory assetData, | ||||
|         address from, | ||||
|         address to, | ||||
|         uint256 amount | ||||
|     ) | ||||
|         internal; | ||||
| } | ||||
| @@ -1,41 +0,0 @@ | ||||
| /* | ||||
|  | ||||
|   Copyright 2018 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.5; | ||||
|  | ||||
| import "../interfaces/IAuthorizable.sol"; | ||||
|  | ||||
|  | ||||
| contract MAuthorizable is | ||||
|     IAuthorizable | ||||
| { | ||||
|     // Event logged when a new address is authorized. | ||||
|     event AuthorizedAddressAdded( | ||||
|         address indexed target, | ||||
|         address indexed caller | ||||
|     ); | ||||
|  | ||||
|     // Event logged when a currently authorized address is unauthorized. | ||||
|     event AuthorizedAddressRemoved( | ||||
|         address indexed target, | ||||
|         address indexed caller | ||||
|     ); | ||||
|  | ||||
|     /// @dev Only authorized addresses can invoke functions with this modifier. | ||||
|     modifier onlyAuthorized { revert(); _; } | ||||
| } | ||||
							
								
								
									
										108
									
								
								contracts/asset-proxy/contracts/test/TestERC20Bridge.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								contracts/asset-proxy/contracts/test/TestERC20Bridge.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,108 @@ | ||||
| /* | ||||
|  | ||||
|   Copyright 2019 ZeroEx Intl. | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
|  | ||||
| */ | ||||
|  | ||||
| pragma solidity ^0.5.9; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "../src/interfaces/IERC20Bridge.sol"; | ||||
|  | ||||
|  | ||||
| /// @dev Test bridge token | ||||
| contract TestERC20BridgeToken { | ||||
|     mapping (address => uint256) private _balances; | ||||
|  | ||||
|     function addBalance(address owner, int256 amount) | ||||
|         external | ||||
|     { | ||||
|         setBalance(owner, uint256(int256(balanceOf(owner)) + amount)); | ||||
|     } | ||||
|  | ||||
|     function setBalance(address owner, uint256 balance) | ||||
|         public | ||||
|     { | ||||
|         _balances[owner] = balance; | ||||
|     } | ||||
|  | ||||
|     function balanceOf(address owner) | ||||
|         public | ||||
|         view | ||||
|         returns (uint256) | ||||
|     { | ||||
|         return _balances[owner]; | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
| /// @dev Test bridge contract. | ||||
| contract TestERC20Bridge is | ||||
|     IERC20Bridge | ||||
| { | ||||
|     TestERC20BridgeToken public testToken; | ||||
|  | ||||
|     event BridgeWithdrawTo( | ||||
|         address tokenAddress, | ||||
|         address from, | ||||
|         address to, | ||||
|         uint256 amount, | ||||
|         bytes bridgeData | ||||
|     ); | ||||
|  | ||||
|     constructor() public { | ||||
|         testToken = new TestERC20BridgeToken(); | ||||
|     } | ||||
|  | ||||
|     function setTestTokenBalance(address owner, uint256 balance) | ||||
|         external | ||||
|     { | ||||
|         testToken.setBalance(owner, balance); | ||||
|     } | ||||
|  | ||||
|     function withdrawTo( | ||||
|         address tokenAddress, | ||||
|         address from, | ||||
|         address to, | ||||
|         uint256 amount, | ||||
|         bytes calldata bridgeData | ||||
|     ) | ||||
|         external | ||||
|         returns (bytes4) | ||||
|     { | ||||
|         emit BridgeWithdrawTo( | ||||
|             tokenAddress, | ||||
|             from, | ||||
|             to, | ||||
|             amount, | ||||
|             bridgeData | ||||
|         ); | ||||
|         // Unpack the bridgeData. | ||||
|         ( | ||||
|             int256 transferAmount, | ||||
|             bytes memory revertData, | ||||
|             bytes memory returnData | ||||
|         ) = abi.decode(bridgeData, (int256, bytes, bytes)); | ||||
|  | ||||
|         // If `revertData` is set, revert. | ||||
|         if (revertData.length != 0) { | ||||
|             assembly { revert(add(revertData, 0x20), mload(revertData)) } | ||||
|         } | ||||
|         // Increase `to`'s balance by `transferAmount`. | ||||
|         TestERC20BridgeToken(tokenAddress).addBalance(to, transferAmount); | ||||
|         // Return `returnData`. | ||||
|         assembly { return(add(returnData, 0x20), mload(returnData)) } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										202
									
								
								contracts/asset-proxy/contracts/test/TestEth2DaiBridge.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										202
									
								
								contracts/asset-proxy/contracts/test/TestEth2DaiBridge.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,202 @@ | ||||
| /* | ||||
|  | ||||
|   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 "../src/bridges/Eth2DaiBridge.sol"; | ||||
| import "../src/interfaces/IEth2Dai.sol"; | ||||
|  | ||||
|  | ||||
| // solhint-disable no-simple-event-func-name | ||||
| contract TestEvents { | ||||
|  | ||||
|     event TokenTransfer( | ||||
|         address token, | ||||
|         address from, | ||||
|         address to, | ||||
|         uint256 amount | ||||
|     ); | ||||
|  | ||||
|     event TokenApprove( | ||||
|         address token, | ||||
|         address spender, | ||||
|         uint256 allowance | ||||
|     ); | ||||
|  | ||||
|     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(msg.sender, spender, allowance); | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
| /// @dev A minimalist ERC20 token. | ||||
| contract TestToken { | ||||
|  | ||||
|     mapping (address => uint256) public balances; | ||||
|     string private _nextTransferRevertReason; | ||||
|     bytes private _nextTransferReturnData; | ||||
|  | ||||
|     /// @dev Just calls `raiseTokenTransfer()` on the caller. | ||||
|     function transfer(address to, uint256 amount) | ||||
|         external | ||||
|         returns (bool) | ||||
|     { | ||||
|         TestEvents(msg.sender).raiseTokenTransfer(msg.sender, to, amount); | ||||
|         if (bytes(_nextTransferRevertReason).length != 0) { | ||||
|             revert(_nextTransferRevertReason); | ||||
|         } | ||||
|         bytes memory returnData = _nextTransferReturnData; | ||||
|         assembly { return(add(returnData, 0x20), mload(returnData)) } | ||||
|     } | ||||
|  | ||||
|     /// @dev Set the balance for `owner`. | ||||
|     function setBalance(address owner, uint256 balance) | ||||
|         external | ||||
|     { | ||||
|         balances[owner] = balance; | ||||
|     } | ||||
|  | ||||
|     /// @dev Set the behavior of the `transfer()` call. | ||||
|     function setTransferBehavior( | ||||
|         string calldata revertReason, | ||||
|         bytes calldata returnData | ||||
|     ) | ||||
|         external | ||||
|     { | ||||
|         _nextTransferRevertReason = revertReason; | ||||
|         _nextTransferReturnData = returnData; | ||||
|     } | ||||
|  | ||||
|     /// @dev Just calls `raiseTokenApprove()` on the caller. | ||||
|     function approve(address spender, uint256 allowance) | ||||
|         external | ||||
|         returns (bool) | ||||
|     { | ||||
|         TestEvents(msg.sender).raiseTokenApprove(spender, allowance); | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     /// @dev Retrieve the balance for `owner`. | ||||
|     function balanceOf(address owner) | ||||
|         external | ||||
|         view | ||||
|         returns (uint256) | ||||
|     { | ||||
|         return balances[owner]; | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
| /// @dev Eth2DaiBridge overridden to mock tokens and | ||||
| ///      implement IEth2Dai. | ||||
| contract TestEth2DaiBridge is | ||||
|     TestEvents, | ||||
|     IEth2Dai, | ||||
|     Eth2DaiBridge | ||||
| { | ||||
|     event SellAllAmount( | ||||
|         address sellToken, | ||||
|         uint256 sellTokenAmount, | ||||
|         address buyToken, | ||||
|         uint256 minimumFillAmount | ||||
|     ); | ||||
|  | ||||
|     mapping (address => TestToken)  public testTokens; | ||||
|     string private _nextRevertReason; | ||||
|     uint256 private _nextFillAmount; | ||||
|  | ||||
|     /// @dev Create a token and set this contract's balance. | ||||
|     function createToken(uint256 balance) | ||||
|         external | ||||
|         returns (address tokenAddress) | ||||
|     { | ||||
|         TestToken token = new TestToken(); | ||||
|         testTokens[address(token)] = token; | ||||
|         token.setBalance(address(this), balance); | ||||
|         return address(token); | ||||
|     } | ||||
|  | ||||
|     /// @dev Set the behavior for `IEth2Dai.sellAllAmount()`. | ||||
|     function setFillBehavior(string calldata revertReason, uint256 fillAmount) | ||||
|         external | ||||
|     { | ||||
|         _nextRevertReason = revertReason; | ||||
|         _nextFillAmount = fillAmount; | ||||
|     } | ||||
|  | ||||
|     /// @dev Set the behavior of a token's `transfer()`. | ||||
|     function setTransferBehavior( | ||||
|         address tokenAddress, | ||||
|         string calldata revertReason, | ||||
|         bytes calldata returnData | ||||
|     ) | ||||
|         external | ||||
|     { | ||||
|         testTokens[tokenAddress].setTransferBehavior(revertReason, returnData); | ||||
|     } | ||||
|  | ||||
|     /// @dev Implementation of `IEth2Dai.sellAllAmount()` | ||||
|     function sellAllAmount( | ||||
|         address sellTokenAddress, | ||||
|         uint256 sellTokenAmount, | ||||
|         address buyTokenAddress, | ||||
|         uint256 minimumFillAmount | ||||
|     ) | ||||
|         external | ||||
|         returns (uint256 fillAmount) | ||||
|     { | ||||
|         emit SellAllAmount( | ||||
|             sellTokenAddress, | ||||
|             sellTokenAmount, | ||||
|             buyTokenAddress, | ||||
|             minimumFillAmount | ||||
|         ); | ||||
|         if (bytes(_nextRevertReason).length != 0) { | ||||
|             revert(_nextRevertReason); | ||||
|         } | ||||
|         return _nextFillAmount; | ||||
|     } | ||||
|  | ||||
|     // @dev This contract will double as the Eth2Dai contract. | ||||
|     function _getEth2DaiContract() | ||||
|         internal | ||||
|         view | ||||
|         returns (IEth2Dai) | ||||
|     { | ||||
|         return IEth2Dai(address(this)); | ||||
|     } | ||||
| } | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|  | ||||
|   Copyright 2018 ZeroEx Intl. | ||||
|   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. | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "name": "@0x/contracts-asset-proxy", | ||||
|     "version": "2.2.7", | ||||
|     "version": "2.3.0-beta.0", | ||||
|     "engines": { | ||||
|         "node": ">=6.12" | ||||
|     }, | ||||
| @@ -12,7 +12,7 @@ | ||||
|     "scripts": { | ||||
|         "build": "yarn pre_build && tsc -b", | ||||
|         "build:ci": "yarn build", | ||||
|         "pre_build": "run-s compile generate_contract_wrappers", | ||||
|         "pre_build": "run-s compile 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", | ||||
| @@ -31,10 +31,11 @@ | ||||
|         "coverage:report:lcov": "istanbul report lcov", | ||||
|         "test:circleci": "yarn test", | ||||
|         "contracts:gen": "contracts-gen", | ||||
|         "lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol" | ||||
|         "lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol", | ||||
|         "compile:truffle": "truffle compile" | ||||
|     }, | ||||
|     "config": { | ||||
|         "abis": "./generated-artifacts/@(ERC1155Proxy|ERC20Proxy|ERC721Proxy|IAssetData|IAssetProxy|IAuthorizable|MixinAuthorizable|MultiAssetProxy|StaticCallProxy|TestStaticCallTarget).json", | ||||
|         "abis": "./generated-artifacts/@(ERC1155Proxy|ERC20BridgeProxy|ERC20Proxy|ERC721Proxy|Eth2DaiBridge|IAssetData|IAssetProxy|IAssetProxyDispatcher|IAuthorizable|IERC20Bridge|IEth2Dai|IWallet|MixinAssetProxyDispatcher|MixinAuthorizable|MultiAssetProxy|Ownable|StaticCallProxy|TestERC20Bridge|TestEth2DaiBridge|TestStaticCallTarget).json", | ||||
|         "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually." | ||||
|     }, | ||||
|     "repository": { | ||||
| @@ -47,11 +48,11 @@ | ||||
|     }, | ||||
|     "homepage": "https://github.com/0xProject/0x-monorepo/contracts/protocol/README.md", | ||||
|     "devDependencies": { | ||||
|         "@0x/abi-gen": "^4.2.0", | ||||
|         "@0x/contracts-gen": "^1.0.14", | ||||
|         "@0x/contracts-test-utils": "^3.1.15", | ||||
|         "@0x/dev-utils": "^2.3.2", | ||||
|         "@0x/sol-compiler": "^3.1.14", | ||||
|         "@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", | ||||
| @@ -65,21 +66,22 @@ | ||||
|         "npm-run-all": "^4.1.2", | ||||
|         "shx": "^0.2.2", | ||||
|         "solhint": "^1.4.1", | ||||
|         "truffle": "^5.0.32", | ||||
|         "tslint": "5.11.0", | ||||
|         "typescript": "3.0.1" | ||||
|     }, | ||||
|     "dependencies": { | ||||
|         "@0x/base-contract": "^5.3.3", | ||||
|         "@0x/contracts-erc1155": "^1.1.14", | ||||
|         "@0x/contracts-erc20": "^2.2.13", | ||||
|         "@0x/contracts-erc721": "^2.1.14", | ||||
|         "@0x/contracts-utils": "^3.2.3", | ||||
|         "@0x/order-utils": "^8.3.1", | ||||
|         "@0x/types": "^2.4.2", | ||||
|         "@0x/typescript-typings": "^4.2.5", | ||||
|         "@0x/utils": "^4.5.1", | ||||
|         "@0x/web3-wrapper": "^6.0.12", | ||||
|         "ethereum-types": "^2.1.5", | ||||
|         "@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", | ||||
|         "lodash": "^4.17.11" | ||||
|     }, | ||||
|   | ||||
| @@ -6,24 +6,44 @@ | ||||
| import { ContractArtifact } from 'ethereum-types'; | ||||
|  | ||||
| import * as ERC1155Proxy from '../generated-artifacts/ERC1155Proxy.json'; | ||||
| import * as ERC20BridgeProxy from '../generated-artifacts/ERC20BridgeProxy.json'; | ||||
| import * as ERC20Proxy from '../generated-artifacts/ERC20Proxy.json'; | ||||
| 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'; | ||||
| 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, | ||||
|     MixinAuthorizable: MixinAuthorizable as ContractArtifact, | ||||
|     MultiAssetProxy: MultiAssetProxy as ContractArtifact, | ||||
|     StaticCallProxy: StaticCallProxy 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, | ||||
|     TestStaticCallTarget: TestStaticCallTarget as ContractArtifact, | ||||
| }; | ||||
|   | ||||
| @@ -4,12 +4,22 @@ | ||||
|  * ----------------------------------------------------------------------------- | ||||
|  */ | ||||
| export * from '../generated-wrappers/erc1155_proxy'; | ||||
| export * from '../generated-wrappers/erc20_bridge_proxy'; | ||||
| export * from '../generated-wrappers/erc20_proxy'; | ||||
| 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'; | ||||
|   | ||||
| @@ -27,9 +27,11 @@ describe('Authorizable', () => { | ||||
|     before(async () => { | ||||
|         await blockchainLifecycle.startAsync(); | ||||
|     }); | ||||
|  | ||||
|     after(async () => { | ||||
|         await blockchainLifecycle.revertAsync(); | ||||
|     }); | ||||
|  | ||||
|     before(async () => { | ||||
|         const accounts = await web3Wrapper.getAvailableAddressesAsync(); | ||||
|         [owner, address, notOwner] = _.slice(accounts, 0, 3); | ||||
| @@ -40,19 +42,23 @@ describe('Authorizable', () => { | ||||
|             artifacts, | ||||
|         ); | ||||
|     }); | ||||
|  | ||||
|     beforeEach(async () => { | ||||
|         await blockchainLifecycle.startAsync(); | ||||
|     }); | ||||
|  | ||||
|     afterEach(async () => { | ||||
|         await blockchainLifecycle.revertAsync(); | ||||
|     }); | ||||
|  | ||||
|     describe('addAuthorizedAddress', () => { | ||||
|         it('should throw if not called by owner', async () => { | ||||
|             return expectTransactionFailedAsync( | ||||
|         it('should revert if not called by owner', async () => { | ||||
|             await expectTransactionFailedAsync( | ||||
|                 authorizable.addAuthorizedAddress.sendTransactionAsync(notOwner, { from: notOwner }), | ||||
|                 RevertReason.OnlyContractOwner, | ||||
|             ); | ||||
|         }); | ||||
|  | ||||
|         it('should allow owner to add an authorized address', async () => { | ||||
|             await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync( | ||||
|                 address, | ||||
| @@ -62,7 +68,8 @@ describe('Authorizable', () => { | ||||
|             const isAuthorized = await authorizable.authorized.callAsync(address); | ||||
|             expect(isAuthorized).to.be.true(); | ||||
|         }); | ||||
|         it('should throw if owner attempts to authorize a duplicate address', async () => { | ||||
|  | ||||
|         it('should revert if owner attempts to authorize a duplicate address', async () => { | ||||
|             await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync( | ||||
|                 address, | ||||
|                 { from: owner }, | ||||
| @@ -76,16 +83,14 @@ describe('Authorizable', () => { | ||||
|     }); | ||||
|  | ||||
|     describe('removeAuthorizedAddress', () => { | ||||
|         it('should throw if not called by owner', async () => { | ||||
|         it('should revert if not called by owner', async () => { | ||||
|             await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync( | ||||
|                 address, | ||||
|                 { from: owner }, | ||||
|                 constants.AWAIT_TRANSACTION_MINED_MS, | ||||
|             ); | ||||
|             return expectTransactionFailedAsync( | ||||
|                 authorizable.removeAuthorizedAddress.sendTransactionAsync(address, { | ||||
|                     from: notOwner, | ||||
|                 }), | ||||
|             await expectTransactionFailedAsync( | ||||
|                 authorizable.removeAuthorizedAddress.sendTransactionAsync(address, { from: notOwner }), | ||||
|                 RevertReason.OnlyContractOwner, | ||||
|             ); | ||||
|         }); | ||||
| @@ -105,7 +110,7 @@ describe('Authorizable', () => { | ||||
|             expect(isAuthorized).to.be.false(); | ||||
|         }); | ||||
|  | ||||
|         it('should throw if owner attempts to remove an address that is not authorized', async () => { | ||||
|         it('should revert if owner attempts to remove an address that is not authorized', async () => { | ||||
|             return expectTransactionFailedAsync( | ||||
|                 authorizable.removeAuthorizedAddress.sendTransactionAsync(address, { | ||||
|                     from: owner, | ||||
| @@ -116,21 +121,22 @@ describe('Authorizable', () => { | ||||
|     }); | ||||
|  | ||||
|     describe('removeAuthorizedAddressAtIndex', () => { | ||||
|         it('should throw if not called by owner', async () => { | ||||
|         it('should revert if not called by owner', async () => { | ||||
|             await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync( | ||||
|                 address, | ||||
|                 { from: owner }, | ||||
|                 constants.AWAIT_TRANSACTION_MINED_MS, | ||||
|             ); | ||||
|             const index = new BigNumber(0); | ||||
|             return expectTransactionFailedAsync( | ||||
|             await expectTransactionFailedAsync( | ||||
|                 authorizable.removeAuthorizedAddressAtIndex.sendTransactionAsync(address, index, { | ||||
|                     from: notOwner, | ||||
|                 }), | ||||
|                 RevertReason.OnlyContractOwner, | ||||
|             ); | ||||
|         }); | ||||
|         it('should throw if index is >= authorities.length', async () => { | ||||
|  | ||||
|         it('should revert if index is >= authorities.length', async () => { | ||||
|             await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync( | ||||
|                 address, | ||||
|                 { from: owner }, | ||||
| @@ -144,7 +150,8 @@ describe('Authorizable', () => { | ||||
|                 RevertReason.IndexOutOfBounds, | ||||
|             ); | ||||
|         }); | ||||
|         it('should throw if owner attempts to remove an address that is not authorized', async () => { | ||||
|  | ||||
|         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, { | ||||
| @@ -153,7 +160,8 @@ describe('Authorizable', () => { | ||||
|                 RevertReason.TargetNotAuthorized, | ||||
|             ); | ||||
|         }); | ||||
|         it('should throw if address at index does not match target', async () => { | ||||
|  | ||||
|         it('should revert if address at index does not match target', async () => { | ||||
|             const address1 = address; | ||||
|             const address2 = notOwner; | ||||
|             await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync( | ||||
| @@ -174,6 +182,7 @@ describe('Authorizable', () => { | ||||
|                 RevertReason.AuthorizedAddressMismatch, | ||||
|             ); | ||||
|         }); | ||||
|  | ||||
|         it('should allow owner to remove an authorized address', async () => { | ||||
|             await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync( | ||||
|                 address, | ||||
|   | ||||
| @@ -17,7 +17,7 @@ import { | ||||
| import { BlockchainLifecycle } from '@0x/dev-utils'; | ||||
| import { assetDataUtils } from '@0x/order-utils'; | ||||
| import { AssetProxyId, RevertReason } from '@0x/types'; | ||||
| import { BigNumber } from '@0x/utils'; | ||||
| import { BigNumber, SafeMathRevertErrors } from '@0x/utils'; | ||||
| import * as chai from 'chai'; | ||||
| import { LogWithDecodedArgs } from 'ethereum-types'; | ||||
| import * as ethUtil from 'ethereumjs-util'; | ||||
| @@ -1748,9 +1748,14 @@ describe('ERC1155Proxy', () => { | ||||
|                 nftNotOwnerBalance, | ||||
|             ]; | ||||
|             await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); | ||||
|             const expectedError = new SafeMathRevertErrors.Uint256BinOpError( | ||||
|                 SafeMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow, | ||||
|                 maxUintValue, | ||||
|                 valueMultiplier, | ||||
|             ); | ||||
|             // execute transfer | ||||
|             // note - this will overflow because we are trying to transfer `maxUintValue * 2` of the 2nd token | ||||
|             await expectTransactionFailedAsync( | ||||
|             await expect( | ||||
|                 erc1155ProxyWrapper.transferFromAsync( | ||||
|                     spender, | ||||
|                     receiver, | ||||
| @@ -1761,8 +1766,7 @@ describe('ERC1155Proxy', () => { | ||||
|                     receiverCallbackData, | ||||
|                     authorized, | ||||
|                 ), | ||||
|                 RevertReason.Uint256Overflow, | ||||
|             ); | ||||
|             ).to.revertWith(expectedError); | ||||
|         }); | ||||
|         it('should revert if transferring > 1 instances of a non-fungible token (valueMultiplier field >1)', async () => { | ||||
|             // setup test parameters | ||||
| @@ -1832,20 +1836,23 @@ describe('ERC1155Proxy', () => { | ||||
|             // check balances before transfer | ||||
|             const expectedInitialBalances = [spenderInitialFungibleBalance, receiverInitialFungibleBalance]; | ||||
|             await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); | ||||
|             // execute transfer | ||||
|             await expectTransactionFailedAsync( | ||||
|                 erc1155ProxyWrapper.transferFromAsync( | ||||
|                     spender, | ||||
|                     receiver, | ||||
|                     erc1155Contract.address, | ||||
|                     tokensToTransfer, | ||||
|                     valuesToTransfer, | ||||
|                     valueMultiplier, | ||||
|                     receiverCallbackData, | ||||
|                     authorized, | ||||
|                 ), | ||||
|                 RevertReason.Uint256Underflow, | ||||
|             const expectedError = new SafeMathRevertErrors.Uint256BinOpError( | ||||
|                 SafeMathRevertErrors.BinOpErrorCodes.SubtractionUnderflow, | ||||
|                 spenderInitialFungibleBalance, | ||||
|                 valuesToTransfer[0].times(valueMultiplier), | ||||
|             ); | ||||
|             // execute transfer | ||||
|             const tx = erc1155ProxyWrapper.transferFromAsync( | ||||
|                 spender, | ||||
|                 receiver, | ||||
|                 erc1155Contract.address, | ||||
|                 tokensToTransfer, | ||||
|                 valuesToTransfer, | ||||
|                 valueMultiplier, | ||||
|                 receiverCallbackData, | ||||
|                 authorized, | ||||
|             ); | ||||
|             return expect(tx).to.revertWith(expectedError); | ||||
|         }); | ||||
|         it('should revert if sender allowance is insufficient', async () => { | ||||
|             // dremove allowance for ERC1155 proxy | ||||
|   | ||||
							
								
								
									
										299
									
								
								contracts/asset-proxy/test/erc20bridge_proxy.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										299
									
								
								contracts/asset-proxy/test/erc20bridge_proxy.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,299 @@ | ||||
| import { | ||||
|     blockchainTests, | ||||
|     constants, | ||||
|     expect, | ||||
|     getRandomInteger, | ||||
|     hexLeftPad, | ||||
|     hexRightPad, | ||||
|     hexSlice, | ||||
|     Numberish, | ||||
|     randomAddress, | ||||
| } from '@0x/contracts-test-utils'; | ||||
| import { AssetProxyId } from '@0x/types'; | ||||
| import { AbiEncoder, AuthorizableRevertErrors, BigNumber, StringRevertError } from '@0x/utils'; | ||||
| import { DecodedLogs } from 'ethereum-types'; | ||||
| import * as _ from 'lodash'; | ||||
|  | ||||
| import { | ||||
|     artifacts, | ||||
|     ERC20BridgeProxyContract, | ||||
|     TestERC20BridgeBridgeWithdrawToEventArgs, | ||||
|     TestERC20BridgeContract, | ||||
| } from '../src'; | ||||
|  | ||||
| blockchainTests.resets('ERC20BridgeProxy unit tests', env => { | ||||
|     const PROXY_ID = AssetProxyId.ERC20Bridge; | ||||
|     const BRIDGE_SUCCESS_RETURN_DATA = hexRightPad(PROXY_ID); | ||||
|     let owner: string; | ||||
|     let badCaller: string; | ||||
|     let assetProxy: ERC20BridgeProxyContract; | ||||
|     let bridgeContract: TestERC20BridgeContract; | ||||
|     let testTokenAddress: string; | ||||
|  | ||||
|     before(async () => { | ||||
|         [owner, badCaller] = await env.getAccountAddressesAsync(); | ||||
|         assetProxy = await ERC20BridgeProxyContract.deployFrom0xArtifactAsync( | ||||
|             artifacts.ERC20BridgeProxy, | ||||
|             env.provider, | ||||
|             env.txDefaults, | ||||
|             artifacts, | ||||
|         ); | ||||
|         bridgeContract = await TestERC20BridgeContract.deployFrom0xArtifactAsync( | ||||
|             artifacts.TestERC20Bridge, | ||||
|             env.provider, | ||||
|             env.txDefaults, | ||||
|             artifacts, | ||||
|         ); | ||||
|         testTokenAddress = await bridgeContract.testToken.callAsync(); | ||||
|         await assetProxy.addAuthorizedAddress.awaitTransactionSuccessAsync(owner); | ||||
|     }); | ||||
|  | ||||
|     interface AssetDataOpts { | ||||
|         tokenAddress: string; | ||||
|         bridgeAddress: string; | ||||
|         bridgeData: BridgeDataOpts; | ||||
|     } | ||||
|  | ||||
|     interface BridgeDataOpts { | ||||
|         transferAmount: Numberish; | ||||
|         revertError?: string; | ||||
|         returnData: string; | ||||
|     } | ||||
|  | ||||
|     function createAssetData(opts?: Partial<AssetDataOpts>): AssetDataOpts { | ||||
|         return _.merge( | ||||
|             { | ||||
|                 tokenAddress: testTokenAddress, | ||||
|                 bridgeAddress: bridgeContract.address, | ||||
|                 bridgeData: createBridgeData(), | ||||
|             }, | ||||
|             opts, | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     function createBridgeData(opts?: Partial<BridgeDataOpts>): BridgeDataOpts { | ||||
|         return _.merge( | ||||
|             { | ||||
|                 transferAmount: constants.ZERO_AMOUNT, | ||||
|                 returnData: BRIDGE_SUCCESS_RETURN_DATA, | ||||
|             }, | ||||
|             opts, | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     function encodeAssetData(opts: AssetDataOpts): string { | ||||
|         const encoder = AbiEncoder.createMethod('ERC20BridgeProxy', [ | ||||
|             { name: 'tokenAddress', type: 'address' }, | ||||
|             { name: 'bridgeAddress', type: 'address' }, | ||||
|             { name: 'bridgeData', type: 'bytes' }, | ||||
|         ]); | ||||
|         return encoder.encode([opts.tokenAddress, opts.bridgeAddress, encodeBridgeData(opts.bridgeData)]); | ||||
|     } | ||||
|  | ||||
|     function encodeBridgeData(opts: BridgeDataOpts): string { | ||||
|         const encoder = AbiEncoder.create([ | ||||
|             { name: 'transferAmount', type: 'int256' }, | ||||
|             { name: 'revertData', type: 'bytes' }, | ||||
|             { name: 'returnData', type: 'bytes' }, | ||||
|         ]); | ||||
|         const revertErrorBytes = | ||||
|             opts.revertError !== undefined ? new StringRevertError(opts.revertError).encode() : '0x'; | ||||
|         return encoder.encode([new BigNumber(opts.transferAmount), revertErrorBytes, opts.returnData]); | ||||
|     } | ||||
|  | ||||
|     async function setTestTokenBalanceAsync(_owner: string, balance: Numberish): Promise<void> { | ||||
|         await bridgeContract.setTestTokenBalance.awaitTransactionSuccessAsync(_owner, new BigNumber(balance)); | ||||
|     } | ||||
|  | ||||
|     describe('transferFrom()', () => { | ||||
|         interface TransferFromOpts { | ||||
|             assetData: AssetDataOpts; | ||||
|             from: string; | ||||
|             to: string; | ||||
|             amount: Numberish; | ||||
|         } | ||||
|  | ||||
|         function createTransferFromOpts(opts?: Partial<TransferFromOpts>): TransferFromOpts { | ||||
|             const transferAmount = _.get(opts, ['amount'], getRandomInteger(1, 100e18)) as BigNumber; | ||||
|             return _.merge( | ||||
|                 { | ||||
|                     assetData: createAssetData({ | ||||
|                         bridgeData: createBridgeData({ | ||||
|                             transferAmount, | ||||
|                         }), | ||||
|                     }), | ||||
|                     from: randomAddress(), | ||||
|                     to: randomAddress(), | ||||
|                     amount: transferAmount, | ||||
|                 }, | ||||
|                 opts, | ||||
|             ); | ||||
|         } | ||||
|  | ||||
|         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 }, | ||||
|             ); | ||||
|             return (logs as any) as DecodedLogs; | ||||
|         } | ||||
|  | ||||
|         it('succeeds if the bridge succeeds and balance increases by `amount`', async () => { | ||||
|             const tx = transferFromAsync(); | ||||
|             return expect(tx).to.be.fulfilled(''); | ||||
|         }); | ||||
|  | ||||
|         it('succeeds if balance increases more than `amount`', async () => { | ||||
|             const amount = getRandomInteger(1, 100e18); | ||||
|             const tx = transferFromAsync({ | ||||
|                 amount, | ||||
|                 assetData: createAssetData({ | ||||
|                     bridgeData: createBridgeData({ | ||||
|                         transferAmount: amount.plus(1), | ||||
|                     }), | ||||
|                 }), | ||||
|             }); | ||||
|             return expect(tx).to.be.fulfilled(''); | ||||
|         }); | ||||
|  | ||||
|         it('passes the correct arguments to the bridge contract', async () => { | ||||
|             const opts = createTransferFromOpts(); | ||||
|             const logs = await transferFromAsync(opts); | ||||
|             expect(logs.length).to.eq(1); | ||||
|             const args = logs[0].args as TestERC20BridgeBridgeWithdrawToEventArgs; | ||||
|             expect(args.tokenAddress).to.eq(opts.assetData.tokenAddress); | ||||
|             expect(args.from).to.eq(opts.from); | ||||
|             expect(args.to).to.eq(opts.to); | ||||
|             expect(args.amount).to.bignumber.eq(opts.amount); | ||||
|             expect(args.bridgeData).to.eq(encodeBridgeData(opts.assetData.bridgeData)); | ||||
|         }); | ||||
|  | ||||
|         it('fails if not called by an authorized address', async () => { | ||||
|             const tx = transferFromAsync({}, badCaller); | ||||
|             return expect(tx).to.revertWith(new AuthorizableRevertErrors.SenderNotAuthorizedError(badCaller)); | ||||
|         }); | ||||
|  | ||||
|         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), | ||||
|             ); | ||||
|             return expect(tx).to.be.rejected(); | ||||
|         }); | ||||
|  | ||||
|         it('fails if bridge returns nothing', async () => { | ||||
|             const tx = transferFromAsync({ | ||||
|                 assetData: createAssetData({ | ||||
|                     bridgeData: createBridgeData({ | ||||
|                         returnData: '0x', | ||||
|                     }), | ||||
|                 }), | ||||
|             }); | ||||
|             // This will actually revert when the AP tries to decode the return | ||||
|             // value. | ||||
|             return expect(tx).to.be.rejected(); | ||||
|         }); | ||||
|  | ||||
|         it('fails if bridge returns true', async () => { | ||||
|             const tx = transferFromAsync({ | ||||
|                 assetData: createAssetData({ | ||||
|                     bridgeData: createBridgeData({ | ||||
|                         returnData: hexLeftPad('0x1'), | ||||
|                     }), | ||||
|                 }), | ||||
|             }); | ||||
|             // This will actually revert when the AP tries to decode the return | ||||
|             // value. | ||||
|             return expect(tx).to.be.rejected(); | ||||
|         }); | ||||
|  | ||||
|         it('fails if bridge returns 0x1', async () => { | ||||
|             const tx = transferFromAsync({ | ||||
|                 assetData: createAssetData({ | ||||
|                     bridgeData: createBridgeData({ | ||||
|                         returnData: hexRightPad('0x1'), | ||||
|                     }), | ||||
|                 }), | ||||
|             }); | ||||
|             return expect(tx).to.revertWith('BRIDGE_FAILED'); | ||||
|         }); | ||||
|  | ||||
|         it('fails if bridge is an EOA', async () => { | ||||
|             const tx = transferFromAsync({ | ||||
|                 assetData: createAssetData({ | ||||
|                     bridgeAddress: randomAddress(), | ||||
|                 }), | ||||
|             }); | ||||
|             // This will actually revert when the AP tries to decode the return | ||||
|             // value. | ||||
|             return expect(tx).to.be.rejected(); | ||||
|         }); | ||||
|  | ||||
|         it('fails if bridge reverts', async () => { | ||||
|             const revertError = 'FOOBAR'; | ||||
|             const tx = transferFromAsync({ | ||||
|                 assetData: createAssetData({ | ||||
|                     bridgeData: createBridgeData({ | ||||
|                         revertError, | ||||
|                     }), | ||||
|                 }), | ||||
|             }); | ||||
|             return expect(tx).to.revertWith(revertError); | ||||
|         }); | ||||
|  | ||||
|         it('fails if balance of `to` increases by less than `amount`', async () => { | ||||
|             const amount = getRandomInteger(1, 100e18); | ||||
|             const tx = transferFromAsync({ | ||||
|                 amount, | ||||
|                 assetData: createAssetData({ | ||||
|                     bridgeData: createBridgeData({ | ||||
|                         transferAmount: amount.minus(1), | ||||
|                     }), | ||||
|                 }), | ||||
|             }); | ||||
|             return expect(tx).to.revertWith('BRIDGE_UNDERPAY'); | ||||
|         }); | ||||
|  | ||||
|         it('fails if balance of `to` decreases', async () => { | ||||
|             const toAddress = randomAddress(); | ||||
|             await setTestTokenBalanceAsync(toAddress, 1e18); | ||||
|             const tx = transferFromAsync({ | ||||
|                 to: toAddress, | ||||
|                 assetData: createAssetData({ | ||||
|                     bridgeData: createBridgeData({ | ||||
|                         transferAmount: -1, | ||||
|                     }), | ||||
|                 }), | ||||
|             }); | ||||
|             return expect(tx).to.revertWith('BRIDGE_UNDERPAY'); | ||||
|         }); | ||||
|     }); | ||||
|  | ||||
|     describe('balanceOf()', () => { | ||||
|         it('retrieves the balance of the encoded token', async () => { | ||||
|             const _owner = randomAddress(); | ||||
|             const balance = getRandomInteger(1, 100e18); | ||||
|             await bridgeContract.setTestTokenBalance.awaitTransactionSuccessAsync(_owner, balance); | ||||
|             const assetData = createAssetData({ | ||||
|                 tokenAddress: testTokenAddress, | ||||
|             }); | ||||
|             const actualBalance = await assetProxy.balanceOf.callAsync(encodeAssetData(assetData), _owner); | ||||
|             expect(actualBalance).to.bignumber.eq(balance); | ||||
|         }); | ||||
|     }); | ||||
|  | ||||
|     describe('getProxyId()', () => { | ||||
|         it('returns the correct proxy ID', async () => { | ||||
|             const proxyId = await assetProxy.getProxyId.callAsync(); | ||||
|             expect(proxyId).to.eq(PROXY_ID); | ||||
|         }); | ||||
|     }); | ||||
| }); | ||||
							
								
								
									
										192
									
								
								contracts/asset-proxy/test/eth2dai_bridge.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										192
									
								
								contracts/asset-proxy/test/eth2dai_bridge.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,192 @@ | ||||
| import { | ||||
|     blockchainTests, | ||||
|     constants, | ||||
|     expect, | ||||
|     filterLogsToArguments, | ||||
|     getRandomInteger, | ||||
|     hexLeftPad, | ||||
|     hexRandom, | ||||
|     Numberish, | ||||
|     randomAddress, | ||||
|     TransactionHelper, | ||||
| } 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, | ||||
|     TestEth2DaiBridgeContract, | ||||
|     TestEth2DaiBridgeEvents, | ||||
|     TestEth2DaiBridgeSellAllAmountEventArgs, | ||||
|     TestEth2DaiBridgeTokenApproveEventArgs, | ||||
|     TestEth2DaiBridgeTokenTransferEventArgs, | ||||
| } from '../src'; | ||||
|  | ||||
| blockchainTests.resets('Eth2DaiBridge unit tests', env => { | ||||
|     const txHelper = new TransactionHelper(env.web3Wrapper, artifacts); | ||||
|     let testContract: TestEth2DaiBridgeContract; | ||||
|  | ||||
|     before(async () => { | ||||
|         testContract = await TestEth2DaiBridgeContract.deployFrom0xArtifactAsync( | ||||
|             artifacts.TestEth2DaiBridge, | ||||
|             env.provider, | ||||
|             env.txDefaults, | ||||
|             artifacts, | ||||
|         ); | ||||
|     }); | ||||
|  | ||||
|     describe('isValidSignature()', () => { | ||||
|         it('returns success bytes', async () => { | ||||
|             const LEGACY_WALLET_MAGIC_VALUE = '0xb0671381'; | ||||
|             const result = await testContract.isValidSignature.callAsync(hexRandom(), hexRandom(_.random(0, 32))); | ||||
|             expect(result).to.eq(LEGACY_WALLET_MAGIC_VALUE); | ||||
|         }); | ||||
|     }); | ||||
|  | ||||
|     describe('withdrawTo()', () => { | ||||
|         interface WithdrawToOpts { | ||||
|             toTokenAddress?: string; | ||||
|             fromTokenAddress?: string; | ||||
|             toAddress: string; | ||||
|             amount: Numberish; | ||||
|             fromTokenBalance: Numberish; | ||||
|             revertReason: string; | ||||
|             fillAmount: Numberish; | ||||
|             toTokentransferRevertReason: string; | ||||
|             toTokenTransferReturnData: string; | ||||
|         } | ||||
|  | ||||
|         interface WithdrawToResult { | ||||
|             opts: WithdrawToOpts; | ||||
|             result: string; | ||||
|             logs: DecodedLogs; | ||||
|         } | ||||
|  | ||||
|         function createWithdrawToOpts(opts?: Partial<WithdrawToOpts>): WithdrawToOpts { | ||||
|             return { | ||||
|                 toAddress: randomAddress(), | ||||
|                 amount: getRandomInteger(1, 100e18), | ||||
|                 revertReason: '', | ||||
|                 fillAmount: getRandomInteger(1, 100e18), | ||||
|                 fromTokenBalance: getRandomInteger(1, 100e18), | ||||
|                 toTokentransferRevertReason: '', | ||||
|                 toTokenTransferReturnData: hexLeftPad(1), | ||||
|                 ...opts, | ||||
|             }; | ||||
|         } | ||||
|  | ||||
|         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), | ||||
|             ); | ||||
|             // Create tokens and balances. | ||||
|             if (_opts.fromTokenAddress === undefined) { | ||||
|                 [_opts.fromTokenAddress] = await txHelper.getResultAndReceiptAsync( | ||||
|                     testContract.createToken, | ||||
|                     new BigNumber(_opts.fromTokenBalance), | ||||
|                 ); | ||||
|             } | ||||
|             if (_opts.toTokenAddress === undefined) { | ||||
|                 [_opts.toTokenAddress] = await txHelper.getResultAndReceiptAsync( | ||||
|                     testContract.createToken, | ||||
|                     constants.ZERO_AMOUNT, | ||||
|                 ); | ||||
|             } | ||||
|             // 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, | ||||
|                 // "to" token address | ||||
|                 _opts.toTokenAddress, | ||||
|                 // Random from address. | ||||
|                 randomAddress(), | ||||
|                 // To address. | ||||
|                 _opts.toAddress, | ||||
|                 new BigNumber(_opts.amount), | ||||
|                 // ABI-encode the "from" token address as the bridge data. | ||||
|                 hexLeftPad(_opts.fromTokenAddress as string), | ||||
|             ); | ||||
|             return { | ||||
|                 opts: _opts, | ||||
|                 result, | ||||
|                 logs: (logs as any) as DecodedLogs, | ||||
|             }; | ||||
|         } | ||||
|  | ||||
|         it('returns magic bytes on success', async () => { | ||||
|             const BRIDGE_SUCCESS_RETURN_DATA = AssetProxyId.ERC20Bridge; | ||||
|             const { result } = await withdrawToAsync(); | ||||
|             expect(result).to.eq(BRIDGE_SUCCESS_RETURN_DATA); | ||||
|         }); | ||||
|  | ||||
|         it('calls `Eth2Dai.sellAllAmount()`', async () => { | ||||
|             const { opts, logs } = await withdrawToAsync(); | ||||
|             const transfers = filterLogsToArguments<TestEth2DaiBridgeSellAllAmountEventArgs>( | ||||
|                 logs, | ||||
|                 TestEth2DaiBridgeEvents.SellAllAmount, | ||||
|             ); | ||||
|             expect(transfers.length).to.eq(1); | ||||
|             expect(transfers[0].sellToken).to.eq(opts.fromTokenAddress); | ||||
|             expect(transfers[0].buyToken).to.eq(opts.toTokenAddress); | ||||
|             expect(transfers[0].sellTokenAmount).to.bignumber.eq(opts.fromTokenBalance); | ||||
|             expect(transfers[0].minimumFillAmount).to.bignumber.eq(opts.amount); | ||||
|         }); | ||||
|  | ||||
|         it('sets an unlimited allowance on the `fromTokenAddress` token', async () => { | ||||
|             const { opts, logs } = await withdrawToAsync(); | ||||
|             const approvals = filterLogsToArguments<TestEth2DaiBridgeTokenApproveEventArgs>( | ||||
|                 logs, | ||||
|                 TestEth2DaiBridgeEvents.TokenApprove, | ||||
|             ); | ||||
|             expect(approvals.length).to.eq(1); | ||||
|             expect(approvals[0].token).to.eq(opts.fromTokenAddress); | ||||
|             expect(approvals[0].spender).to.eq(testContract.address); | ||||
|             expect(approvals[0].allowance).to.bignumber.eq(constants.MAX_UINT256); | ||||
|         }); | ||||
|  | ||||
|         it('transfers filled amount to `to`', async () => { | ||||
|             const { opts, logs } = await withdrawToAsync(); | ||||
|             const transfers = filterLogsToArguments<TestEth2DaiBridgeTokenTransferEventArgs>( | ||||
|                 logs, | ||||
|                 TestEth2DaiBridgeEvents.TokenTransfer, | ||||
|             ); | ||||
|             expect(transfers.length).to.eq(1); | ||||
|             expect(transfers[0].token).to.eq(opts.toTokenAddress); | ||||
|             expect(transfers[0].from).to.eq(testContract.address); | ||||
|             expect(transfers[0].to).to.eq(opts.toAddress); | ||||
|             expect(transfers[0].amount).to.bignumber.eq(opts.fillAmount); | ||||
|         }); | ||||
|  | ||||
|         it('fails if `Eth2Dai.sellAllAmount()` reverts', async () => { | ||||
|             const opts = createWithdrawToOpts({ revertReason: 'FOOBAR' }); | ||||
|             const tx = withdrawToAsync(opts); | ||||
|             return expect(tx).to.revertWith(opts.revertReason); | ||||
|         }); | ||||
|  | ||||
|         it('fails if `toTokenAddress.transfer()` reverts', async () => { | ||||
|             const opts = createWithdrawToOpts({ toTokentransferRevertReason: 'FOOBAR' }); | ||||
|             const tx = withdrawToAsync(opts); | ||||
|             return expect(tx).to.revertWith(opts.toTokentransferRevertReason); | ||||
|         }); | ||||
|  | ||||
|         it('fails if `toTokenAddress.transfer()` returns falsey', async () => { | ||||
|             const opts = createWithdrawToOpts({ toTokenTransferReturnData: hexLeftPad(0) }); | ||||
|             const tx = withdrawToAsync(opts); | ||||
|             return expect(tx).to.revertWith('ERC20_TRANSFER_FAILED'); | ||||
|         }); | ||||
|  | ||||
|         it('succeeds if `toTokenAddress.transfer()` returns truthy', async () => { | ||||
|             await withdrawToAsync({ toTokenTransferReturnData: hexLeftPad(100) }); | ||||
|         }); | ||||
|     }); | ||||
| }); | ||||
| @@ -679,7 +679,14 @@ describe('Asset Transfer Proxies', () => { | ||||
|                 // Verify pre-condition | ||||
|                 const ownerFromAsset = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId); | ||||
|                 expect(ownerFromAsset).to.be.equal(fromAddress); | ||||
|                 // Remove transfer approval for fromAddress. | ||||
|                 // Remove blanket transfer approval for fromAddress. | ||||
|                 await erc721TokenA.setApprovalForAll.awaitTransactionSuccessAsync( | ||||
|                     erc721Proxy.address, | ||||
|                     false, | ||||
|                     { from: fromAddress }, | ||||
|                     constants.AWAIT_TRANSACTION_MINED_MS, | ||||
|                 ); | ||||
|                 // Remove token transfer approval for fromAddress. | ||||
|                 await erc721TokenA.approve.awaitTransactionSuccessAsync( | ||||
|                     constants.NULL_ADDRESS, | ||||
|                     erc721AFromTokenId, | ||||
|   | ||||
| @@ -43,7 +43,13 @@ describe('StaticCallProxy', () => { | ||||
|             txDefaults, | ||||
|             artifacts, | ||||
|         ); | ||||
|         staticCallProxy = new IAssetProxyContract(staticCallProxyWithoutTransferFrom.address, provider, txDefaults); | ||||
|         staticCallProxy = new IAssetProxyContract( | ||||
|             staticCallProxyWithoutTransferFrom.address, | ||||
|             provider, | ||||
|             txDefaults, | ||||
|             {}, | ||||
|             StaticCallProxyContract.deployedBytecode, | ||||
|         ); | ||||
|         staticCallTarget = await TestStaticCallTargetContract.deployFrom0xArtifactAsync( | ||||
|             artifacts.TestStaticCallTarget, | ||||
|             provider, | ||||
|   | ||||
| @@ -336,6 +336,22 @@ export class ERC1155ProxyWrapper { | ||||
|         }; | ||||
|         return holdingsByOwner; | ||||
|     } | ||||
|     /** | ||||
|      * @dev Set the approval for the proxy on behalf of `userAddress` . | ||||
|      * @param userAddress owner of ERC1155 tokens. | ||||
|      * @param contractAddress address of ERC1155 contract. | ||||
|      * @param isApproved Whether to approve the proxy for all or not. | ||||
|      */ | ||||
|     public async setProxyAllowanceForAllAsync( | ||||
|         userAddress: string, | ||||
|         contractAddress: string, | ||||
|         isApproved: boolean, | ||||
|     ): Promise<void> { | ||||
|         this._validateProxyContractExistsOrThrow(); | ||||
|         const tokenWrapper = this.getContractWrapper(contractAddress); | ||||
|         const operator = (this._proxyContract as ERC1155ProxyContract).address; | ||||
|         await tokenWrapper.setApprovalForAllAsync(userAddress, operator, isApproved); | ||||
|     } | ||||
|     /** | ||||
|      * @dev Checks if proxy is approved to transfer tokens on behalf of `userAddress`. | ||||
|      * @param userAddress owner of ERC1155 tokens. | ||||
|   | ||||
| @@ -71,7 +71,7 @@ export class ERC721Wrapper { | ||||
|                     } | ||||
|                     this._initialTokenIdsByOwner[tokenOwnerAddress][dummyTokenContract.address].push(tokenId); | ||||
|  | ||||
|                     await this.approveProxyAsync(dummyTokenContract.address, tokenId); | ||||
|                     await this.approveProxyForAllAsync(dummyTokenContract.address, tokenOwnerAddress, true); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| @@ -86,14 +86,17 @@ export class ERC721Wrapper { | ||||
|         const proxyAddress = (this._proxyContract as ERC721ProxyContract).address; | ||||
|         await this.approveAsync(proxyAddress, tokenAddress, tokenId); | ||||
|     } | ||||
|     public async approveProxyForAllAsync(tokenAddress: string, tokenId: BigNumber, isApproved: boolean): Promise<void> { | ||||
|     public async approveProxyForAllAsync( | ||||
|         tokenAddress: string, | ||||
|         ownerAddress: string, | ||||
|         isApproved: boolean, | ||||
|     ): Promise<void> { | ||||
|         const tokenContract = this._getTokenContractFromAssetData(tokenAddress); | ||||
|         const tokenOwner = await this.ownerOfAsync(tokenAddress, tokenId); | ||||
|         const proxyAddress = (this._proxyContract as ERC721ProxyContract).address; | ||||
|         await tokenContract.setApprovalForAll.awaitTransactionSuccessAsync( | ||||
|             proxyAddress, | ||||
|             isApproved, | ||||
|             { from: tokenOwner }, | ||||
|             { from: ownerAddress }, | ||||
|             constants.AWAIT_TRANSACTION_MINED_MS, | ||||
|         ); | ||||
|     } | ||||
|   | ||||
							
								
								
									
										96
									
								
								contracts/asset-proxy/truffle-config.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								contracts/asset-proxy/truffle-config.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,96 @@ | ||||
| /** | ||||
|  * Use this file to configure your truffle project. It's seeded with some | ||||
|  * common settings for different networks and features like migrations, | ||||
|  * compilation and testing. Uncomment the ones you need or modify | ||||
|  * them to suit your project as necessary. | ||||
|  * | ||||
|  * More information about configuration can be found at: | ||||
|  * | ||||
|  * truffleframework.com/docs/advanced/configuration | ||||
|  * | ||||
|  * To deploy via Infura you'll need a wallet provider (like truffle-hdwallet-provider) | ||||
|  * to sign your transactions before they're sent to a remote public node. Infura accounts | ||||
|  * are available for free at: infura.io/register. | ||||
|  * | ||||
|  * You'll also need a mnemonic - the twelve word phrase the wallet uses to generate | ||||
|  * public/private key pairs. If you're publishing your code to GitHub make sure you load this | ||||
|  * phrase from a file you've .gitignored so it doesn't accidentally become public. | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| // const HDWalletProvider = require('truffle-hdwallet-provider'); | ||||
| // const infuraKey = "fj4jll3k....."; | ||||
| // | ||||
| // const fs = require('fs'); | ||||
| // const mnemonic = fs.readFileSync(".secret").toString().trim(); | ||||
|  | ||||
| module.exports = { | ||||
|     /** | ||||
|      * Networks define how you connect to your ethereum client and let you set the | ||||
|      * defaults web3 uses to send transactions. If you don't specify one truffle | ||||
|      * will spin up a development blockchain for you on port 9545 when you | ||||
|      * run `develop` or `test`. You can ask a truffle command to use a specific | ||||
|      * network from the command line, e.g | ||||
|      * | ||||
|      * $ truffle test --network <network-name> | ||||
|      */ | ||||
|  | ||||
|     networks: { | ||||
|         // Useful for testing. The `development` name is special - truffle uses it by default | ||||
|         // if it's defined here and no other network is specified at the command line. | ||||
|         // You should run a client (like ganache-cli, geth or parity) in a separate terminal | ||||
|         // tab if you use this network and you must also set the `host`, `port` and `network_id` | ||||
|         // options below to some value. | ||||
|         // | ||||
|         // development: { | ||||
|         //  host: "127.0.0.1",     // Localhost (default: none) | ||||
|         //  port: 8545,            // Standard Ethereum port (default: none) | ||||
|         //  network_id: "*",       // Any network (default: none) | ||||
|         // }, | ||||
|         // Another network with more advanced options... | ||||
|         // advanced: { | ||||
|         // port: 8777,             // Custom port | ||||
|         // network_id: 1342,       // Custom network | ||||
|         // gas: 8500000,           // Gas sent with each transaction (default: ~6700000) | ||||
|         // gasPrice: 20000000000,  // 20 gwei (in wei) (default: 100 gwei) | ||||
|         // from: <address>,        // Account to send txs from (default: accounts[0]) | ||||
|         // websockets: true        // Enable EventEmitter interface for web3 (default: false) | ||||
|         // }, | ||||
|         // Useful for deploying to a public network. | ||||
|         // NB: It's important to wrap the provider as a function. | ||||
|         // ropsten: { | ||||
|         // provider: () => new HDWalletProvider(mnemonic, `https://ropsten.infura.io/v3/YOUR-PROJECT-ID`), | ||||
|         // network_id: 3,       // Ropsten's id | ||||
|         // gas: 5500000,        // Ropsten has a lower block limit than mainnet | ||||
|         // confirmations: 2,    // # of confs to wait between deployments. (default: 0) | ||||
|         // timeoutBlocks: 200,  // # of blocks before a deployment times out  (minimum/default: 50) | ||||
|         // skipDryRun: true     // Skip dry run before migrations? (default: false for public nets ) | ||||
|         // }, | ||||
|         // Useful for private networks | ||||
|         // private: { | ||||
|         // provider: () => new HDWalletProvider(mnemonic, `https://network.io`), | ||||
|         // network_id: 2111,   // This network is yours, in the cloud. | ||||
|         // production: true    // Treats this network as if it was a public net. (default: false) | ||||
|         // } | ||||
|     }, | ||||
|  | ||||
|     // Set default mocha options here, use special reporters etc. | ||||
|     mocha: { | ||||
|         // timeout: 100000 | ||||
|     }, | ||||
|  | ||||
|     // Configure your compilers | ||||
|     compilers: { | ||||
|         solc: { | ||||
|             version: '0.5.9', | ||||
|             settings: { | ||||
|                 evmVersion: 'constantinople', | ||||
|                 optimizer: { | ||||
|                     enabled: true, | ||||
|                     runs: 1000000, | ||||
|                     details: { yul: true, deduplicate: true, cse: true, constantOptimizer: true }, | ||||
|                 }, | ||||
|             }, | ||||
|         }, | ||||
|     }, | ||||
| }; | ||||
| @@ -4,14 +4,24 @@ | ||||
|     "include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"], | ||||
|     "files": [ | ||||
|         "generated-artifacts/ERC1155Proxy.json", | ||||
|         "generated-artifacts/ERC20BridgeProxy.json", | ||||
|         "generated-artifacts/ERC20Proxy.json", | ||||
|         "generated-artifacts/ERC721Proxy.json", | ||||
|         "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" | ||||
|     ], | ||||
|     "exclude": ["./deploy/solc/solc_bin"] | ||||
|   | ||||
							
								
								
									
										2
									
								
								contracts/coordinator/.solhintignore
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								contracts/coordinator/.solhintignore
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| # solhint can't parse `abi.decode` syntax. | ||||
| contracts/src/MixinCoordinatorApprovalVerifier.sol | ||||
| @@ -1,4 +1,59 @@ | ||||
| [ | ||||
|     { | ||||
|         "version": "2.1.0-beta.0", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Add chainId to domain separator", | ||||
|                 "pr": 1742 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Inherit Exchange domain constants from `exchange-libs` to reduce code duplication", | ||||
|                 "pr": 1742 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Update domain separator", | ||||
|                 "pr": 1742 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Refactor contract to use new ITransactions interface", | ||||
|                 "pr": 1753 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Add verifyingContractIfExists arg to LibEIP712CoordinatorDomain constructor", | ||||
|                 "pr": 1753 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Remove LibZeroExTransaction contract", | ||||
|                 "pr": 1753 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Update tests for arbitrary fee tokens (ZEIP-28).", | ||||
|                 "pr": 1819 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Update for new `marketXOrders` consolidation.", | ||||
|                 "pr": 2042 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Use built in selectors instead of hard coded constants", | ||||
|                 "pr": 2055 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Compile and export all contracts, artifacts, and wrappers by default", | ||||
|                 "pr": 2055 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1570135330 | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1568744790, | ||||
|         "version": "2.0.13", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1567521715, | ||||
|         "version": "2.0.12", | ||||
|   | ||||
| @@ -5,6 +5,23 @@ Edit the package's CHANGELOG.json file only. | ||||
|  | ||||
| CHANGELOG | ||||
|  | ||||
| ## v2.1.0-beta.0 - _October 3, 2019_ | ||||
|  | ||||
|     * Add chainId to domain separator (#1742) | ||||
|     * Inherit Exchange domain constants from `exchange-libs` to reduce code duplication (#1742) | ||||
|     * Update domain separator (#1742) | ||||
|     * Refactor contract to use new ITransactions interface (#1753) | ||||
|     * Add verifyingContractIfExists arg to LibEIP712CoordinatorDomain constructor (#1753) | ||||
|     * Remove LibZeroExTransaction contract (#1753) | ||||
|     * Update tests for arbitrary fee tokens (ZEIP-28). (#1819) | ||||
|     * Update for new `marketXOrders` consolidation. (#2042) | ||||
|     * Use built in selectors instead of hard coded constants (#2055) | ||||
|     * Compile and export all contracts, artifacts, and wrappers by default (#2055) | ||||
|  | ||||
| ## v2.0.13 - _September 17, 2019_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v2.0.12 - _September 3, 2019_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|   | ||||
| @@ -21,6 +21,5 @@ | ||||
|                 ] | ||||
|             } | ||||
|         } | ||||
|     }, | ||||
|     "contracts": ["src/Coordinator.sol", "src/registry/CoordinatorRegistry.sol"] | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|  | ||||
|   Copyright 2018 ZeroEx Intl. | ||||
|   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. | ||||
| @@ -16,10 +16,12 @@ | ||||
|  | ||||
| */ | ||||
|  | ||||
| pragma solidity ^0.5.5; | ||||
| pragma experimental "ABIEncoderV2"; | ||||
| pragma solidity ^0.5.9; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "@0x/contracts-exchange-libs/contracts/src/LibEIP712ExchangeDomain.sol"; | ||||
| import "./libs/LibConstants.sol"; | ||||
| import "./libs/LibEIP712CoordinatorDomain.sol"; | ||||
| import "./MixinSignatureValidator.sol"; | ||||
| import "./MixinCoordinatorApprovalVerifier.sol"; | ||||
| import "./MixinCoordinatorCore.sol"; | ||||
| @@ -32,8 +34,12 @@ contract Coordinator is | ||||
|     MixinCoordinatorApprovalVerifier, | ||||
|     MixinCoordinatorCore | ||||
| { | ||||
|     constructor (address _exchange) | ||||
|     /// @param exchange Address of the 0x Exchange contract. | ||||
|     /// @param chainId Chain ID of the network this contract is deployed on. | ||||
|     constructor (address exchange, uint256 chainId) | ||||
|         public | ||||
|         LibConstants(_exchange) | ||||
|         LibConstants(exchange) | ||||
|         LibEIP712CoordinatorDomain(chainId, address(0)) | ||||
|         LibEIP712ExchangeDomain(chainId, exchange) | ||||
|     {} | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|  | ||||
|   Copyright 2018 ZeroEx Intl. | ||||
|   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. | ||||
| @@ -16,26 +16,25 @@ | ||||
|  | ||||
| */ | ||||
|  | ||||
| pragma solidity ^0.5.5; | ||||
| pragma experimental "ABIEncoderV2"; | ||||
| pragma solidity ^0.5.9; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "@0x/contracts-exchange-libs/contracts/src/LibExchangeSelectors.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-exchange/contracts/src/interfaces/IExchange.sol"; | ||||
| import "./libs/LibCoordinatorApproval.sol"; | ||||
| import "./libs/LibZeroExTransaction.sol"; | ||||
| import "./mixins/MSignatureValidator.sol"; | ||||
| import "./mixins/MCoordinatorApprovalVerifier.sol"; | ||||
| import "./interfaces/ICoordinatorSignatureValidator.sol"; | ||||
| import "./interfaces/ICoordinatorApprovalVerifier.sol"; | ||||
|  | ||||
|  | ||||
| // solhint-disable avoid-tx-origin | ||||
| contract MixinCoordinatorApprovalVerifier is | ||||
|     LibExchangeSelectors, | ||||
|     LibCoordinatorApproval, | ||||
|     LibZeroExTransaction, | ||||
|     MSignatureValidator, | ||||
|     MCoordinatorApprovalVerifier | ||||
|     ICoordinatorSignatureValidator, | ||||
|     ICoordinatorApprovalVerifier | ||||
| { | ||||
|     using LibBytes for bytes; | ||||
|     using LibAddressArray for address[]; | ||||
| @@ -63,7 +62,7 @@ contract MixinCoordinatorApprovalVerifier is | ||||
|         // No approval is required for non-fill methods | ||||
|         if (orders.length > 0) { | ||||
|             // Revert if approval is invalid for transaction orders | ||||
|             assertValidTransactionOrdersApproval( | ||||
|             _assertValidTransactionOrdersApproval( | ||||
|                 transaction, | ||||
|                 orders, | ||||
|                 txOrigin, | ||||
| @@ -84,9 +83,9 @@ contract MixinCoordinatorApprovalVerifier is | ||||
|     { | ||||
|         bytes4 selector = data.readBytes4(0); | ||||
|         if ( | ||||
|             selector == FILL_ORDER_SELECTOR || | ||||
|             selector == FILL_ORDER_NO_THROW_SELECTOR || | ||||
|             selector == FILL_OR_KILL_ORDER_SELECTOR | ||||
|             selector == IExchange(address(0)).fillOrder.selector || | ||||
|             selector == IExchange(address(0)).fillOrderNoThrow.selector || | ||||
|             selector == IExchange(address(0)).fillOrKillOrder.selector | ||||
|         ) { | ||||
|             // Decode single order | ||||
|             (LibOrder.Order memory order) = abi.decode( | ||||
| @@ -96,13 +95,11 @@ contract MixinCoordinatorApprovalVerifier is | ||||
|             orders = new LibOrder.Order[](1); | ||||
|             orders[0] = order; | ||||
|         } else if ( | ||||
|             selector == BATCH_FILL_ORDERS_SELECTOR || | ||||
|             selector == BATCH_FILL_ORDERS_NO_THROW_SELECTOR || | ||||
|             selector == BATCH_FILL_OR_KILL_ORDERS_SELECTOR || | ||||
|             selector == MARKET_BUY_ORDERS_SELECTOR || | ||||
|             selector == MARKET_BUY_ORDERS_NO_THROW_SELECTOR || | ||||
|             selector == MARKET_SELL_ORDERS_SELECTOR || | ||||
|             selector == MARKET_SELL_ORDERS_NO_THROW_SELECTOR | ||||
|             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 | ||||
|         ) { | ||||
|             // Decode all orders | ||||
|             // solhint-disable indent | ||||
| @@ -110,7 +107,7 @@ contract MixinCoordinatorApprovalVerifier is | ||||
|                 data.slice(4, data.length), | ||||
|                 (LibOrder.Order[]) | ||||
|             ); | ||||
|         } else if (selector == MATCH_ORDERS_SELECTOR) { | ||||
|         } else if (selector == IExchange(address(0)).matchOrders.selector) { | ||||
|             // Decode left and right orders | ||||
|             (LibOrder.Order memory leftOrder, LibOrder.Order memory rightOrder) = abi.decode( | ||||
|                 data.slice(4, data.length), | ||||
| @@ -132,7 +129,7 @@ contract MixinCoordinatorApprovalVerifier is | ||||
|     /// @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( | ||||
|     function _assertValidTransactionOrdersApproval( | ||||
|         LibZeroExTransaction.ZeroExTransaction memory transaction, | ||||
|         LibOrder.Order[] memory orders, | ||||
|         address txOrigin, | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|  | ||||
|   Copyright 2018 ZeroEx Intl. | ||||
|   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. | ||||
| @@ -16,18 +16,18 @@ | ||||
|  | ||||
| */ | ||||
|  | ||||
| pragma solidity ^0.5.5; | ||||
| pragma experimental "ABIEncoderV2"; | ||||
| pragma solidity ^0.5.9; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "./libs/LibZeroExTransaction.sol"; | ||||
| import "@0x/contracts-exchange-libs/contracts/src/LibZeroExTransaction.sol"; | ||||
| import "./libs/LibConstants.sol"; | ||||
| import "./mixins/MCoordinatorApprovalVerifier.sol"; | ||||
| import "./interfaces/ICoordinatorCore.sol"; | ||||
| import "./interfaces/ICoordinatorApprovalVerifier.sol"; | ||||
|  | ||||
|  | ||||
| contract MixinCoordinatorCore is | ||||
|     LibConstants, | ||||
|     MCoordinatorApprovalVerifier, | ||||
|     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. | ||||
| @@ -55,11 +55,6 @@ contract MixinCoordinatorCore is | ||||
|         ); | ||||
|  | ||||
|         // Execute the transaction | ||||
|         EXCHANGE.executeTransaction( | ||||
|             transaction.salt, | ||||
|             transaction.signerAddress, | ||||
|             transaction.data, | ||||
|             transactionSignature | ||||
|         ); | ||||
|         EXCHANGE.executeTransaction(transaction, transactionSignature); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|  | ||||
|   Copyright 2018 ZeroEx Intl. | ||||
|   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. | ||||
| @@ -16,14 +16,14 @@ | ||||
|  | ||||
| */ | ||||
|  | ||||
| pragma solidity ^0.5.5; | ||||
| pragma solidity ^0.5.9; | ||||
|  | ||||
| import "@0x/contracts-utils/contracts/src/LibBytes.sol"; | ||||
| import "./mixins/MSignatureValidator.sol"; | ||||
| import "./interfaces/ICoordinatorSignatureValidator.sol"; | ||||
|  | ||||
|  | ||||
| contract MixinSignatureValidator is | ||||
|     MSignatureValidator | ||||
|     ICoordinatorSignatureValidator | ||||
| { | ||||
|     using LibBytes for bytes; | ||||
|  | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|  | ||||
|   Copyright 2018 ZeroEx Intl. | ||||
|   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. | ||||
| @@ -16,11 +16,11 @@ | ||||
|  | ||||
| */ | ||||
|  | ||||
| pragma solidity ^0.5.5; | ||||
| pragma experimental "ABIEncoderV2"; | ||||
| pragma solidity ^0.5.9; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; | ||||
| import "../libs/LibZeroExTransaction.sol"; | ||||
| import "@0x/contracts-exchange-libs/contracts/src/LibZeroExTransaction.sol"; | ||||
|  | ||||
|  | ||||
| contract ICoordinatorApprovalVerifier { | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|  | ||||
|   Copyright 2018 ZeroEx Intl. | ||||
|   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. | ||||
| @@ -16,10 +16,10 @@ | ||||
|  | ||||
| */ | ||||
|  | ||||
| pragma solidity ^0.5.5; | ||||
| pragma experimental "ABIEncoderV2"; | ||||
| pragma solidity ^0.5.9; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "../libs/LibZeroExTransaction.sol"; | ||||
| import "@0x/contracts-exchange-libs/contracts/src/LibZeroExTransaction.sol"; | ||||
|  | ||||
|  | ||||
| contract ICoordinatorCore { | ||||
|   | ||||
| @@ -0,0 +1,45 @@ | ||||
| /* | ||||
|  | ||||
|   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; | ||||
|  | ||||
|  | ||||
| contract ICoordinatorSignatureValidator { | ||||
|  | ||||
|    // Allowed signature types. | ||||
|     enum SignatureType { | ||||
|         Illegal,                // 0x00, default value | ||||
|         Invalid,                // 0x01 | ||||
|         EIP712,                 // 0x02 | ||||
|         EthSign,                // 0x03 | ||||
|         Wallet,                 // 0x04 | ||||
|         Validator,              // 0x05 | ||||
|         PreSigned,              // 0x06 | ||||
|         OrderValidator,         // 0x07 | ||||
|         WalletOrderValidator,   // 0x08 | ||||
|         NSignatureTypes         // 0x09, 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. | ||||
|     function getSignerAddress(bytes32 hash, bytes memory signature) | ||||
|         public | ||||
|         pure | ||||
|         returns (address signerAddress); | ||||
| } | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|  | ||||
|   Copyright 2018 ZeroEx Intl. | ||||
|   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. | ||||
| @@ -16,19 +16,21 @@ | ||||
|  | ||||
| */ | ||||
|  | ||||
| pragma solidity ^0.5.5; | ||||
| pragma solidity ^0.5.9; | ||||
|  | ||||
| import "../interfaces/ITransactions.sol"; | ||||
| import "@0x/contracts-exchange/contracts/src/interfaces/ITransactions.sol"; | ||||
|  | ||||
|  | ||||
| // solhint-disable var-name-mixedcase | ||||
| contract LibConstants { | ||||
|  | ||||
|      // solhint-disable-next-line var-name-mixedcase | ||||
|     // The 0x Exchange contract. | ||||
|     ITransactions internal EXCHANGE; | ||||
|  | ||||
|     constructor (address _exchange) | ||||
|     /// @param exchange Address of the 0x Exchange contract. | ||||
|     constructor (address exchange) | ||||
|         public | ||||
|     { | ||||
|         EXCHANGE = ITransactions(_exchange); | ||||
|         EXCHANGE = ITransactions(exchange); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|  | ||||
|   Copyright 2018 ZeroEx Intl. | ||||
|   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. | ||||
| @@ -16,14 +16,14 @@ | ||||
|  | ||||
| */ | ||||
|  | ||||
| pragma solidity ^0.5.5; | ||||
| pragma experimental "ABIEncoderV2"; | ||||
| pragma solidity ^0.5.9; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "./LibEIP712Domain.sol"; | ||||
| import "./LibEIP712CoordinatorDomain.sol"; | ||||
|  | ||||
|  | ||||
| contract LibCoordinatorApproval is | ||||
|     LibEIP712Domain | ||||
|     LibEIP712CoordinatorDomain | ||||
| { | ||||
|     // Hash for the EIP712 Coordinator approval message | ||||
|     // keccak256(abi.encodePacked( | ||||
| @@ -34,7 +34,7 @@ contract LibCoordinatorApproval is | ||||
|     //     "uint256 approvalExpirationTimeSeconds", | ||||
|     //     ")" | ||||
|     // )); | ||||
|     bytes32 constant internal EIP712_COORDINATOR_APPROVAL_SCHEMA_HASH = 0x2fbcdbaa76bc7589916958ae919dfbef04d23f6bbf26de6ff317b32c6cc01e05; | ||||
|     bytes32 constant public EIP712_COORDINATOR_APPROVAL_SCHEMA_HASH = 0x2fbcdbaa76bc7589916958ae919dfbef04d23f6bbf26de6ff317b32c6cc01e05; | ||||
|  | ||||
|     struct CoordinatorApproval { | ||||
|         address txOrigin;                       // Required signer of Ethereum transaction that is submitting approval. | ||||
| @@ -51,14 +51,14 @@ contract LibCoordinatorApproval is | ||||
|         view | ||||
|         returns (bytes32 approvalHash) | ||||
|     { | ||||
|         approvalHash = hashEIP712CoordinatorMessage(hashCoordinatorApproval(approval)); | ||||
|         approvalHash = _hashEIP712CoordinatorMessage(_hashCoordinatorApproval(approval)); | ||||
|         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. | ||||
|     function hashCoordinatorApproval(CoordinatorApproval memory approval) | ||||
|     function _hashCoordinatorApproval(CoordinatorApproval memory approval) | ||||
|         internal | ||||
|         pure | ||||
|         returns (bytes32 result) | ||||
|   | ||||
| @@ -0,0 +1,66 @@ | ||||
| /* | ||||
|  | ||||
|   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; | ||||
|  | ||||
| import "@0x/contracts-utils/contracts/src/LibEIP712.sol"; | ||||
|  | ||||
|  | ||||
| contract LibEIP712CoordinatorDomain is | ||||
|     LibEIP712 | ||||
| { | ||||
|  | ||||
|     // 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"; | ||||
|  | ||||
|     // Hash of the EIP712 Domain Separator data for the Coordinator | ||||
|     // solhint-disable-next-line var-name-mixedcase | ||||
|     bytes32 public EIP712_COORDINATOR_DOMAIN_HASH; | ||||
|  | ||||
|     /// @param chainId Chain ID of the network this contract is deployed on. | ||||
|     /// @param verifyingContractAddressIfExists Address of the verifying contract (null if the address of this contract) | ||||
|     constructor ( | ||||
|         uint256 chainId, | ||||
|         address verifyingContractAddressIfExists | ||||
|     ) | ||||
|         public | ||||
|     { | ||||
|         address verifyingContractAddress = verifyingContractAddressIfExists == address(0) ? address(this) : verifyingContractAddressIfExists; | ||||
|         EIP712_COORDINATOR_DOMAIN_HASH = LibEIP712.hashEIP712Domain( | ||||
|             EIP712_COORDINATOR_DOMAIN_NAME, | ||||
|             EIP712_COORDINATOR_DOMAIN_VERSION, | ||||
|             chainId, | ||||
|             verifyingContractAddress | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     /// @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. | ||||
|     function _hashEIP712CoordinatorMessage(bytes32 hashStruct) | ||||
|         internal | ||||
|         view | ||||
|         returns (bytes32 result) | ||||
|     { | ||||
|         return LibEIP712.hashEIP712Message(EIP712_COORDINATOR_DOMAIN_HASH, hashStruct); | ||||
|     } | ||||
| } | ||||
| @@ -1,131 +0,0 @@ | ||||
| /* | ||||
|  | ||||
|   Copyright 2018 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.5; | ||||
|  | ||||
| import "./LibConstants.sol"; | ||||
|  | ||||
|  | ||||
| contract LibEIP712Domain is | ||||
|     LibConstants | ||||
| { | ||||
|  | ||||
|     // EIP191 header for EIP712 prefix | ||||
|     string constant internal EIP191_HEADER = "\x19\x01"; | ||||
|  | ||||
|     // EIP712 Domain Name value for the Coordinator | ||||
|     string constant internal EIP712_COORDINATOR_DOMAIN_NAME = "0x Protocol Coordinator"; | ||||
|  | ||||
|     // EIP712 Domain Version value for the Coordinator | ||||
|     string constant internal EIP712_COORDINATOR_DOMAIN_VERSION = "1.0.0"; | ||||
|  | ||||
|     // EIP712 Domain Name value for the Exchange | ||||
|     string constant internal EIP712_EXCHANGE_DOMAIN_NAME = "0x Protocol"; | ||||
|  | ||||
|     // EIP712 Domain Version value for the Exchange | ||||
|     string constant internal EIP712_EXCHANGE_DOMAIN_VERSION = "2"; | ||||
|  | ||||
|     // Hash of the EIP712 Domain Separator Schema | ||||
|     bytes32 constant internal EIP712_DOMAIN_SEPARATOR_SCHEMA_HASH = keccak256(abi.encodePacked( | ||||
|         "EIP712Domain(", | ||||
|         "string name,", | ||||
|         "string version,", | ||||
|         "address verifyingContract", | ||||
|         ")" | ||||
|     )); | ||||
|  | ||||
|     // Hash of the EIP712 Domain Separator data for the Coordinator | ||||
|     // solhint-disable-next-line var-name-mixedcase | ||||
|     bytes32 public EIP712_COORDINATOR_DOMAIN_HASH; | ||||
|  | ||||
|     // Hash of the EIP712 Domain Separator data for the Exchange | ||||
|     // solhint-disable-next-line var-name-mixedcase | ||||
|     bytes32 public EIP712_EXCHANGE_DOMAIN_HASH; | ||||
|  | ||||
|     constructor () | ||||
|         public | ||||
|     { | ||||
|         EIP712_COORDINATOR_DOMAIN_HASH = keccak256(abi.encodePacked( | ||||
|             EIP712_DOMAIN_SEPARATOR_SCHEMA_HASH, | ||||
|             keccak256(bytes(EIP712_COORDINATOR_DOMAIN_NAME)), | ||||
|             keccak256(bytes(EIP712_COORDINATOR_DOMAIN_VERSION)), | ||||
|             uint256(address(this)) | ||||
|         )); | ||||
|  | ||||
|         EIP712_EXCHANGE_DOMAIN_HASH = keccak256(abi.encodePacked( | ||||
|             EIP712_DOMAIN_SEPARATOR_SCHEMA_HASH, | ||||
|             keccak256(bytes(EIP712_EXCHANGE_DOMAIN_NAME)), | ||||
|             keccak256(bytes(EIP712_EXCHANGE_DOMAIN_VERSION)), | ||||
|             uint256(address(EXCHANGE)) | ||||
|         )); | ||||
|     } | ||||
|  | ||||
|     /// @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. | ||||
|     function hashEIP712CoordinatorMessage(bytes32 hashStruct) | ||||
|         internal | ||||
|         view | ||||
|         returns (bytes32 result) | ||||
|     { | ||||
|         return hashEIP712Message(EIP712_COORDINATOR_DOMAIN_HASH, hashStruct); | ||||
|     } | ||||
|  | ||||
|     /// @dev Calculates EIP712 encoding for a hash struct in the EIP712 domain | ||||
|     ///      of the Exchange contract. | ||||
|     /// @param hashStruct The EIP712 hash struct. | ||||
|     /// @return EIP712 hash applied to the Exchange EIP712 Domain. | ||||
|     function hashEIP712ExchangeMessage(bytes32 hashStruct) | ||||
|         internal | ||||
|         view | ||||
|         returns (bytes32 result) | ||||
|     { | ||||
|         return hashEIP712Message(EIP712_EXCHANGE_DOMAIN_HASH, hashStruct); | ||||
|     } | ||||
|  | ||||
|     /// @dev Calculates EIP712 encoding for a hash struct with a given domain hash. | ||||
|     /// @param eip712DomainHash Hash of the domain domain separator data. | ||||
|     /// @param hashStruct The EIP712 hash struct. | ||||
|     /// @return EIP712 hash applied to the Exchange EIP712 Domain. | ||||
|     function hashEIP712Message(bytes32 eip712DomainHash, bytes32 hashStruct) | ||||
|         internal | ||||
|         pure | ||||
|         returns (bytes32 result) | ||||
|     { | ||||
|         // Assembly for more efficient computing: | ||||
|         // keccak256(abi.encodePacked( | ||||
|         //     EIP191_HEADER, | ||||
|         //     EIP712_DOMAIN_HASH, | ||||
|         //     hashStruct | ||||
|         // )); | ||||
|  | ||||
|         assembly { | ||||
|             // Load free memory pointer | ||||
|             let memPtr := mload(64) | ||||
|  | ||||
|             mstore(memPtr, 0x1901000000000000000000000000000000000000000000000000000000000000)  // EIP191 header | ||||
|             mstore(add(memPtr, 2), eip712DomainHash)                                            // EIP712 domain hash | ||||
|             mstore(add(memPtr, 34), hashStruct)                                                 // Hash of struct | ||||
|  | ||||
|             // Compute hash | ||||
|             result := keccak256(memPtr, 66) | ||||
|         } | ||||
|         return result; | ||||
|     } | ||||
| } | ||||
| @@ -1,95 +0,0 @@ | ||||
| /* | ||||
|  | ||||
|   Copyright 2018 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.5; | ||||
| pragma experimental "ABIEncoderV2"; | ||||
|  | ||||
| import "./LibEIP712Domain.sol"; | ||||
|  | ||||
|  | ||||
| contract LibZeroExTransaction is | ||||
|     LibEIP712Domain | ||||
| { | ||||
|     // Hash for the EIP712 0x transaction schema | ||||
|     // keccak256(abi.encodePacked( | ||||
|     //    "ZeroExTransaction(", | ||||
|     //    "uint256 salt,", | ||||
|     //    "address signerAddress,", | ||||
|     //    "bytes data", | ||||
|     //    ")" | ||||
|     // )); | ||||
|     bytes32 constant internal EIP712_ZEROEX_TRANSACTION_SCHEMA_HASH = 0x213c6f636f3ea94e701c0adf9b2624aa45a6c694f9a292c094f9a81c24b5df4c; | ||||
|  | ||||
|     struct ZeroExTransaction { | ||||
|         uint256 salt;           // Arbitrary number to ensure uniqueness of transaction hash. | ||||
|         address signerAddress;  // Address of transaction signer. | ||||
|         bytes data;             // AbiV2 encoded calldata. | ||||
|     } | ||||
|  | ||||
|     /// @dev Calculates the EIP712 hash of a 0x transaction using the domain separator of the Exchange contract. | ||||
|     /// @param transaction 0x transaction containing salt, signerAddress, and data. | ||||
|     /// @return EIP712 hash of the transaction with the domain separator of this contract. | ||||
|     function getTransactionHash(ZeroExTransaction memory transaction) | ||||
|         public | ||||
|         view | ||||
|         returns (bytes32 transactionHash) | ||||
|     { | ||||
|         // Hash the transaction with the domain separator of the Exchange contract. | ||||
|         transactionHash = hashEIP712ExchangeMessage(hashZeroExTransaction(transaction)); | ||||
|         return transactionHash; | ||||
|     } | ||||
|  | ||||
|     /// @dev Calculates EIP712 hash of the 0x transaction with no domain separator. | ||||
|     /// @param transaction 0x transaction containing salt, signerAddress, and data. | ||||
|     /// @return EIP712 hash of the transaction with no domain separator. | ||||
|     function hashZeroExTransaction(ZeroExTransaction memory transaction) | ||||
|         internal | ||||
|         pure | ||||
|         returns (bytes32 result) | ||||
|     { | ||||
|         bytes32 schemaHash = EIP712_ZEROEX_TRANSACTION_SCHEMA_HASH; | ||||
|         bytes memory data = transaction.data; | ||||
|         uint256 salt = transaction.salt; | ||||
|         address signerAddress = transaction.signerAddress; | ||||
|  | ||||
|         // Assembly for more efficiently computing: | ||||
|         // keccak256(abi.encodePacked( | ||||
|         //     EIP712_ZEROEX_TRANSACTION_SCHEMA_HASH, | ||||
|         //     transaction.salt, | ||||
|         //     uint256(transaction.signerAddress), | ||||
|         //     keccak256(transaction.data) | ||||
|         // )); | ||||
|  | ||||
|         assembly { | ||||
|             // Compute hash of data | ||||
|             let dataHash := keccak256(add(data, 32), mload(data)) | ||||
|  | ||||
|             // Load free memory pointer | ||||
|             let memPtr := mload(64) | ||||
|  | ||||
|             mstore(memPtr, schemaHash)                                                               // hash of schema | ||||
|             mstore(add(memPtr, 32), salt)                                                            // salt | ||||
|             mstore(add(memPtr, 64), and(signerAddress, 0xffffffffffffffffffffffffffffffffffffffff))  // signerAddress | ||||
|             mstore(add(memPtr, 96), dataHash)                                                        // hash of data | ||||
|  | ||||
|             // Compute hash | ||||
|             result := keccak256(memPtr, 128) | ||||
|         } | ||||
|         return result; | ||||
|     } | ||||
| } | ||||
| @@ -1,46 +0,0 @@ | ||||
| /* | ||||
|  | ||||
|   Copyright 2018 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.5; | ||||
| pragma experimental "ABIEncoderV2"; | ||||
|  | ||||
| import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; | ||||
| import "../interfaces/ICoordinatorApprovalVerifier.sol"; | ||||
|  | ||||
|  | ||||
| contract MCoordinatorApprovalVerifier is | ||||
|     ICoordinatorApprovalVerifier | ||||
| { | ||||
|     /// @dev Validates that the feeRecipients of a batch of order have approved a 0x transaction. | ||||
|     /// @param transaction 0x transaction containing salt, signerAddress, and data. | ||||
|     /// @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; | ||||
| } | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|  | ||||
|   Copyright 2018 ZeroEx Intl. | ||||
|   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. | ||||
| @@ -16,7 +16,7 @@ | ||||
|  | ||||
| */ | ||||
|  | ||||
| pragma solidity ^0.5.5; | ||||
| pragma solidity ^0.5.9; | ||||
|  | ||||
| import "./MixinCoordinatorRegistryCore.sol"; | ||||
|  | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|  | ||||
|   Copyright 2018 ZeroEx Intl. | ||||
|   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. | ||||
| @@ -16,7 +16,7 @@ | ||||
|  | ||||
| */ | ||||
|  | ||||
| pragma solidity ^0.5.5; | ||||
| pragma solidity ^0.5.9; | ||||
|  | ||||
| import "./interfaces/ICoordinatorRegistryCore.sol"; | ||||
|  | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|  | ||||
|   Copyright 2018 ZeroEx Intl. | ||||
|   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. | ||||
| @@ -16,7 +16,7 @@ | ||||
|  | ||||
| */ | ||||
|  | ||||
| pragma solidity ^0.5.5; | ||||
| pragma solidity ^0.5.9; | ||||
|  | ||||
|  | ||||
| // solhint-disable no-empty-blocks | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "name": "@0x/contracts-coordinator", | ||||
|     "version": "2.0.12", | ||||
|     "version": "2.1.0-beta.0", | ||||
|     "engines": { | ||||
|         "node": ">=6.12" | ||||
|     }, | ||||
| @@ -12,7 +12,7 @@ | ||||
|     "scripts": { | ||||
|         "build": "yarn pre_build && tsc -b", | ||||
|         "build:ci": "yarn build", | ||||
|         "pre_build": "run-s compile generate_contract_wrappers", | ||||
|         "pre_build": "run-s compile 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", | ||||
| @@ -31,7 +31,8 @@ | ||||
|         "coverage:report:lcov": "istanbul report lcov", | ||||
|         "test:circleci": "yarn test", | ||||
|         "contracts:gen": "contracts-gen", | ||||
|         "lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol" | ||||
|         "lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol", | ||||
|         "compile:truffle": "truffle compile" | ||||
|     }, | ||||
|     "config": { | ||||
|         "abis": "./generated-artifacts/@(Coordinator|CoordinatorRegistry).json", | ||||
| @@ -47,11 +48,11 @@ | ||||
|     }, | ||||
|     "homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md", | ||||
|     "devDependencies": { | ||||
|         "@0x/abi-gen": "^4.2.0", | ||||
|         "@0x/contracts-gen": "^1.0.14", | ||||
|         "@0x/contracts-test-utils": "^3.1.15", | ||||
|         "@0x/dev-utils": "^2.3.2", | ||||
|         "@0x/sol-compiler": "^3.1.14", | ||||
|         "@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", | ||||
| @@ -65,22 +66,23 @@ | ||||
|         "npm-run-all": "^4.1.2", | ||||
|         "shx": "^0.2.2", | ||||
|         "solhint": "^1.4.1", | ||||
|         "truffle": "^5.0.32", | ||||
|         "tslint": "5.11.0", | ||||
|         "typescript": "3.0.1" | ||||
|     }, | ||||
|     "dependencies": { | ||||
|         "@0x/base-contract": "^5.3.3", | ||||
|         "@0x/contracts-asset-proxy": "^2.2.7", | ||||
|         "@0x/contracts-erc20": "^2.2.13", | ||||
|         "@0x/contracts-exchange": "^2.1.13", | ||||
|         "@0x/contracts-exchange-libs": "^3.0.7", | ||||
|         "@0x/contracts-utils": "^3.2.3", | ||||
|         "@0x/order-utils": "^8.3.1", | ||||
|         "@0x/types": "^2.4.2", | ||||
|         "@0x/typescript-typings": "^4.2.5", | ||||
|         "@0x/utils": "^4.5.1", | ||||
|         "@0x/web3-wrapper": "^6.0.12", | ||||
|         "ethereum-types": "^2.1.5", | ||||
|         "@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" | ||||
|     }, | ||||
|   | ||||
| @@ -2,14 +2,17 @@ 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 as devConstants, | ||||
|     constants, | ||||
|     expectTransactionFailedAsync, | ||||
|     getLatestBlockTimestampAsync, | ||||
|     OrderFactory, | ||||
| @@ -20,12 +23,12 @@ import { | ||||
| } from '@0x/contracts-test-utils'; | ||||
| import { BlockchainLifecycle } from '@0x/dev-utils'; | ||||
| import { assetDataUtils, orderHashUtils } from '@0x/order-utils'; | ||||
| import { RevertReason, SignedOrder } from '@0x/types'; | ||||
| import { BigNumber } from '@0x/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, constants, CoordinatorContract, exchangeDataEncoder } from '../src'; | ||||
| import { ApprovalFactory, artifacts, CoordinatorContract } from '../src'; | ||||
|  | ||||
| chaiSetup.configure(); | ||||
| const expect = chai.expect; | ||||
| @@ -33,6 +36,7 @@ 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; | ||||
| @@ -41,7 +45,7 @@ describe('Coordinator tests', () => { | ||||
|     let erc20Proxy: ERC20ProxyContract; | ||||
|     let erc20TokenA: DummyERC20TokenContract; | ||||
|     let erc20TokenB: DummyERC20TokenContract; | ||||
|     let zrxToken: DummyERC20TokenContract; | ||||
|     let makerFeeToken: DummyERC20TokenContract; | ||||
|     let coordinatorContract: CoordinatorContract; | ||||
|     let exchange: ExchangeContract; | ||||
|  | ||||
| @@ -58,15 +62,16 @@ describe('Coordinator tests', () => { | ||||
|         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, zrxToken] = await erc20Wrapper.deployDummyTokensAsync( | ||||
|         [erc20TokenA, erc20TokenB, makerFeeToken] = await erc20Wrapper.deployDummyTokensAsync( | ||||
|             numDummyErc20ToDeploy, | ||||
|             devConstants.DUMMY_TOKEN_DECIMALS, | ||||
|             constants.DUMMY_TOKEN_DECIMALS, | ||||
|         ); | ||||
|         await erc20Wrapper.setBalancesAndAllowancesAsync(); | ||||
|  | ||||
| @@ -74,18 +79,17 @@ describe('Coordinator tests', () => { | ||||
|             exchangeArtifacts.Exchange, | ||||
|             provider, | ||||
|             txDefaults, | ||||
|             artifacts, | ||||
|             assetDataUtils.encodeERC20AssetData(zrxToken.address), | ||||
|             new BigNumber(chainId), | ||||
|         ); | ||||
|  | ||||
|         await web3Wrapper.awaitTransactionSuccessAsync( | ||||
|             await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, { from: owner }), | ||||
|             devConstants.AWAIT_TRANSACTION_MINED_MS, | ||||
|             constants.AWAIT_TRANSACTION_MINED_MS, | ||||
|         ); | ||||
|  | ||||
|         await web3Wrapper.awaitTransactionSuccessAsync( | ||||
|             await exchange.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, { from: owner }), | ||||
|             devConstants.AWAIT_TRANSACTION_MINED_MS, | ||||
|             constants.AWAIT_TRANSACTION_MINED_MS, | ||||
|         ); | ||||
|  | ||||
|         coordinatorContract = await CoordinatorContract.deployFrom0xArtifactAsync( | ||||
| @@ -94,24 +98,28 @@ describe('Coordinator tests', () => { | ||||
|             txDefaults, | ||||
|             artifacts, | ||||
|             exchange.address, | ||||
|             new BigNumber(chainId), | ||||
|         ); | ||||
|  | ||||
|         // Configure order defaults | ||||
|         const defaultOrderParams = { | ||||
|             ...devConstants.STATIC_ORDER_PARAMS, | ||||
|             exchangeAddress: exchange.address, | ||||
|             ...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 = devConstants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)]; | ||||
|         const takerPrivateKey = devConstants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(takerAddress)]; | ||||
|         const feeRecipientPrivateKey = devConstants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(feeRecipientAddress)]; | ||||
|         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); | ||||
|         takerTransactionFactory = new TransactionFactory(takerPrivateKey, exchange.address); | ||||
|         makerTransactionFactory = new TransactionFactory(makerPrivateKey, exchange.address, chainId); | ||||
|         takerTransactionFactory = new TransactionFactory(takerPrivateKey, exchange.address, chainId); | ||||
|         approvalFactory = new ApprovalFactory(feeRecipientPrivateKey, coordinatorContract.address); | ||||
|     }); | ||||
|     beforeEach(async () => { | ||||
| @@ -122,11 +130,11 @@ describe('Coordinator tests', () => { | ||||
|     }); | ||||
|  | ||||
|     describe('single order fills', () => { | ||||
|         for (const fnName of constants.SINGLE_FILL_FN_NAMES) { | ||||
|         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 = takerTransactionFactory.newSignedTransaction(data); | ||||
|                 const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const currentTimestamp = await getLatestBlockTimestampAsync(); | ||||
|                 const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); | ||||
|                 const approval = approvalFactory.newSignedApproval( | ||||
| @@ -143,7 +151,7 @@ describe('Coordinator tests', () => { | ||||
|                         [approval.signature], | ||||
|                         { from: takerAddress }, | ||||
|                     ), | ||||
|                     devConstants.AWAIT_TRANSACTION_MINED_MS, | ||||
|                     constants.AWAIT_TRANSACTION_MINED_MS, | ||||
|                 ); | ||||
|                 const fillLogs = transactionReceipt.logs.filter( | ||||
|                     log => (log as LogWithDecodedArgs<ExchangeFillEventArgs>).event === 'Fill', | ||||
| @@ -165,7 +173,7 @@ describe('Coordinator tests', () => { | ||||
|             it(`${fnName} should fill the order if called by approver`, async () => { | ||||
|                 const orders = [await orderFactory.newSignedOrderAsync()]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = takerTransactionFactory.newSignedTransaction(data); | ||||
|                 const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const transactionReceipt = await web3Wrapper.awaitTransactionSuccessAsync( | ||||
|                     await coordinatorContract.executeTransaction.sendTransactionAsync( | ||||
|                         transaction, | ||||
| @@ -175,7 +183,7 @@ describe('Coordinator tests', () => { | ||||
|                         [], | ||||
|                         { from: feeRecipientAddress }, | ||||
|                     ), | ||||
|                     devConstants.AWAIT_TRANSACTION_MINED_MS, | ||||
|                     constants.AWAIT_TRANSACTION_MINED_MS, | ||||
|                 ); | ||||
|                 const fillLogs = transactionReceipt.logs.filter( | ||||
|                     log => (log as LogWithDecodedArgs<ExchangeFillEventArgs>).event === 'Fill', | ||||
| @@ -197,7 +205,7 @@ describe('Coordinator tests', () => { | ||||
|             it(`${fnName} should revert with no approval signature`, async () => { | ||||
|                 const orders = [await orderFactory.newSignedOrderAsync()]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = takerTransactionFactory.newSignedTransaction(data); | ||||
|                 const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 await expectTransactionFailedAsync( | ||||
|                     coordinatorContract.executeTransaction.sendTransactionAsync( | ||||
|                         transaction, | ||||
| @@ -207,7 +215,7 @@ describe('Coordinator tests', () => { | ||||
|                         [], | ||||
|                         { | ||||
|                             from: takerAddress, | ||||
|                             gas: devConstants.MAX_EXECUTE_TRANSACTION_GAS, | ||||
|                             gas: constants.MAX_EXECUTE_TRANSACTION_GAS, | ||||
|                         }, | ||||
|                     ), | ||||
|                     RevertReason.InvalidApprovalSignature, | ||||
| @@ -216,7 +224,7 @@ describe('Coordinator tests', () => { | ||||
|             it(`${fnName} should revert with an invalid approval signature`, async () => { | ||||
|                 const orders = [await orderFactory.newSignedOrderAsync()]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = takerTransactionFactory.newSignedTransaction(data); | ||||
|                 const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const currentTimestamp = await getLatestBlockTimestampAsync(); | ||||
|                 const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); | ||||
|                 const approval = approvalFactory.newSignedApproval( | ||||
| @@ -240,7 +248,7 @@ describe('Coordinator tests', () => { | ||||
|             it(`${fnName} should revert with an expired approval`, async () => { | ||||
|                 const orders = [await orderFactory.newSignedOrderAsync()]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = takerTransactionFactory.newSignedTransaction(data); | ||||
|                 const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const currentTimestamp = await getLatestBlockTimestampAsync(); | ||||
|                 const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).minus(constants.TIME_BUFFER); | ||||
|                 const approval = approvalFactory.newSignedApproval( | ||||
| @@ -263,7 +271,7 @@ describe('Coordinator tests', () => { | ||||
|             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 = takerTransactionFactory.newSignedTransaction(data); | ||||
|                 const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const currentTimestamp = await getLatestBlockTimestampAsync(); | ||||
|                 const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); | ||||
|                 const approval = approvalFactory.newSignedApproval( | ||||
| @@ -286,11 +294,11 @@ describe('Coordinator tests', () => { | ||||
|         } | ||||
|     }); | ||||
|     describe('batch order fills', () => { | ||||
|         for (const fnName of [...constants.MARKET_FILL_FN_NAMES, ...constants.BATCH_FILL_FN_NAMES]) { | ||||
|         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 = takerTransactionFactory.newSignedTransaction(data); | ||||
|                 const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const currentTimestamp = await getLatestBlockTimestampAsync(); | ||||
|                 const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); | ||||
|                 const approval = approvalFactory.newSignedApproval( | ||||
| @@ -305,9 +313,9 @@ describe('Coordinator tests', () => { | ||||
|                         transaction.signature, | ||||
|                         [approvalExpirationTimeSeconds], | ||||
|                         [approval.signature], | ||||
|                         { from: takerAddress, gas: devConstants.MAX_EXECUTE_TRANSACTION_GAS }, | ||||
|                         { from: takerAddress, gas: constants.MAX_EXECUTE_TRANSACTION_GAS }, | ||||
|                     ), | ||||
|                     devConstants.AWAIT_TRANSACTION_MINED_MS, | ||||
|                     constants.AWAIT_TRANSACTION_MINED_MS, | ||||
|                 ); | ||||
|                 const fillLogs = transactionReceipt.logs.filter( | ||||
|                     log => (log as LogWithDecodedArgs<ExchangeFillEventArgs>).event === 'Fill', | ||||
| @@ -331,7 +339,7 @@ describe('Coordinator tests', () => { | ||||
|             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 = takerTransactionFactory.newSignedTransaction(data); | ||||
|                 const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const transactionReceipt = await web3Wrapper.awaitTransactionSuccessAsync( | ||||
|                     await coordinatorContract.executeTransaction.sendTransactionAsync( | ||||
|                         transaction, | ||||
| @@ -339,9 +347,9 @@ describe('Coordinator tests', () => { | ||||
|                         transaction.signature, | ||||
|                         [], | ||||
|                         [], | ||||
|                         { from: feeRecipientAddress, gas: devConstants.MAX_EXECUTE_TRANSACTION_GAS }, | ||||
|                         { from: feeRecipientAddress, gas: constants.MAX_EXECUTE_TRANSACTION_GAS }, | ||||
|                     ), | ||||
|                     devConstants.AWAIT_TRANSACTION_MINED_MS, | ||||
|                     constants.AWAIT_TRANSACTION_MINED_MS, | ||||
|                 ); | ||||
|                 const fillLogs = transactionReceipt.logs.filter( | ||||
|                     log => (log as LogWithDecodedArgs<ExchangeFillEventArgs>).event === 'Fill', | ||||
| @@ -365,7 +373,7 @@ describe('Coordinator tests', () => { | ||||
|             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 = takerTransactionFactory.newSignedTransaction(data); | ||||
|                 const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const currentTimestamp = await getLatestBlockTimestampAsync(); | ||||
|                 const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); | ||||
|                 const approval = approvalFactory.newSignedApproval( | ||||
| @@ -389,7 +397,7 @@ describe('Coordinator tests', () => { | ||||
|             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 = takerTransactionFactory.newSignedTransaction(data); | ||||
|                 const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const currentTimestamp = await getLatestBlockTimestampAsync(); | ||||
|                 const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).minus(constants.TIME_BUFFER); | ||||
|                 const approval = approvalFactory.newSignedApproval( | ||||
| @@ -412,7 +420,7 @@ describe('Coordinator tests', () => { | ||||
|             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 = takerTransactionFactory.newSignedTransaction(data); | ||||
|                 const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const currentTimestamp = await getLatestBlockTimestampAsync(); | ||||
|                 const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); | ||||
|                 const approval = approvalFactory.newSignedApproval( | ||||
| @@ -437,8 +445,8 @@ describe('Coordinator tests', () => { | ||||
|     describe('cancels', () => { | ||||
|         it('cancelOrder call should be successful without an approval', async () => { | ||||
|             const orders = [await orderFactory.newSignedOrderAsync()]; | ||||
|             const data = exchangeDataEncoder.encodeOrdersToExchangeData(constants.CANCEL_ORDER, orders); | ||||
|             const transaction = makerTransactionFactory.newSignedTransaction(data); | ||||
|             const data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.CancelOrder, orders); | ||||
|             const transaction = await makerTransactionFactory.newSignedTransactionAsync({ data }); | ||||
|             const transactionReceipt = await web3Wrapper.awaitTransactionSuccessAsync( | ||||
|                 await coordinatorContract.executeTransaction.sendTransactionAsync( | ||||
|                     transaction, | ||||
| @@ -465,8 +473,8 @@ describe('Coordinator tests', () => { | ||||
|         }); | ||||
|         it('batchCancelOrders call should be successful without an approval', async () => { | ||||
|             const orders = [await orderFactory.newSignedOrderAsync(), await orderFactory.newSignedOrderAsync()]; | ||||
|             const data = exchangeDataEncoder.encodeOrdersToExchangeData(constants.BATCH_CANCEL_ORDERS, orders); | ||||
|             const transaction = makerTransactionFactory.newSignedTransaction(data); | ||||
|             const data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.BatchCancelOrders, orders); | ||||
|             const transaction = await makerTransactionFactory.newSignedTransactionAsync({ data }); | ||||
|             const transactionReceipt = await web3Wrapper.awaitTransactionSuccessAsync( | ||||
|                 await coordinatorContract.executeTransaction.sendTransactionAsync( | ||||
|                     transaction, | ||||
| @@ -494,9 +502,9 @@ describe('Coordinator tests', () => { | ||||
|             }); | ||||
|         }); | ||||
|         it('cancelOrdersUpTo call should be successful without an approval', async () => { | ||||
|             const orders: SignedOrder[] = []; | ||||
|             const data = exchangeDataEncoder.encodeOrdersToExchangeData(constants.CANCEL_ORDERS_UP_TO, orders); | ||||
|             const transaction = makerTransactionFactory.newSignedTransaction(data); | ||||
|             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, | ||||
| @@ -515,8 +523,8 @@ describe('Coordinator tests', () => { | ||||
|             expect(cancelLogs.length).to.eq(1); | ||||
|             const cancelLogArgs = (cancelLogs[0] as LogWithDecodedArgs<ExchangeCancelUpToEventArgs>).args; | ||||
|             expect(cancelLogArgs.makerAddress).to.eq(makerAddress); | ||||
|             expect(cancelLogArgs.senderAddress).to.eq(coordinatorContract.address); | ||||
|             expect(cancelLogArgs.orderEpoch).to.bignumber.eq(new BigNumber(1)); | ||||
|             expect(cancelLogArgs.orderSenderAddress).to.eq(coordinatorContract.address); | ||||
|             expect(cancelLogArgs.orderEpoch).to.bignumber.eq(targetEpoch.plus(1)); | ||||
|         }); | ||||
|     }); | ||||
| }); | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| import { addressUtils, chaiSetup, constants, provider, txDefaults, web3Wrapper } from '@0x/contracts-test-utils'; | ||||
| 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 } from '@0x/utils'; | ||||
| import { BigNumber, providerUtils } from '@0x/utils'; | ||||
| import * as chai from 'chai'; | ||||
|  | ||||
| import { artifacts, CoordinatorContract, hashUtils } from '../src'; | ||||
| @@ -12,7 +12,8 @@ const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); | ||||
|  | ||||
| describe('Libs tests', () => { | ||||
|     let coordinatorContract: CoordinatorContract; | ||||
|     const exchangeAddress = addressUtils.generatePseudoRandomAddress(); | ||||
|     let chainId: number; | ||||
|     const exchangeAddress = randomAddress(); | ||||
|  | ||||
|     before(async () => { | ||||
|         await blockchainLifecycle.startAsync(); | ||||
| @@ -21,12 +22,14 @@ describe('Libs tests', () => { | ||||
|         await blockchainLifecycle.revertAsync(); | ||||
|     }); | ||||
|     before(async () => { | ||||
|         chainId = await providerUtils.getChainIdAsync(provider); | ||||
|         coordinatorContract = await CoordinatorContract.deployFrom0xArtifactAsync( | ||||
|             artifacts.Coordinator, | ||||
|             provider, | ||||
|             txDefaults, | ||||
|             artifacts, | ||||
|             exchangeAddress, | ||||
|             new BigNumber(chainId), | ||||
|         ); | ||||
|     }); | ||||
|     beforeEach(async () => { | ||||
| @@ -39,10 +42,14 @@ describe('Libs tests', () => { | ||||
|     describe('getTransactionHash', () => { | ||||
|         it('should return the correct transaction hash', async () => { | ||||
|             const tx = { | ||||
|                 verifyingContractAddress: exchangeAddress, | ||||
|                 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); | ||||
| @@ -53,11 +60,15 @@ describe('Libs tests', () => { | ||||
|     describe('getApprovalHash', () => { | ||||
|         it('should return the correct approval hash', async () => { | ||||
|             const signedTx = { | ||||
|                 verifyingContractAddress: exchangeAddress, | ||||
|                 salt: new BigNumber(0), | ||||
|                 expirationTimeSeconds: new BigNumber(0), | ||||
|                 signerAddress: constants.NULL_ADDRESS, | ||||
|                 data: '0x1234', | ||||
|                 signature: '0x5678', | ||||
|                 domain: { | ||||
|                     verifyingContract: exchangeAddress, | ||||
|                     chainId, | ||||
|                 }, | ||||
|             }; | ||||
|             const approvalExpirationTimeSeconds = new BigNumber(0); | ||||
|             const txOrigin = constants.NULL_ADDRESS; | ||||
|   | ||||
| @@ -1,10 +1,11 @@ | ||||
| import { constants as exchangeConstants, exchangeDataEncoder, ExchangeFunctionName } from '@0x/contracts-exchange'; | ||||
| import { | ||||
|     addressUtils, | ||||
|     chaiSetup, | ||||
|     constants as devConstants, | ||||
|     constants, | ||||
|     expectContractCallFailedAsync, | ||||
|     getLatestBlockTimestampAsync, | ||||
|     provider, | ||||
|     randomAddress, | ||||
|     TransactionFactory, | ||||
|     txDefaults, | ||||
|     web3Wrapper, | ||||
| @@ -12,17 +13,18 @@ import { | ||||
| import { BlockchainLifecycle } from '@0x/dev-utils'; | ||||
| import { transactionHashUtils } from '@0x/order-utils'; | ||||
| import { RevertReason, SignatureType, SignedOrder } from '@0x/types'; | ||||
| import { BigNumber } from '@0x/utils'; | ||||
| import { BigNumber, LibBytesRevertErrors, providerUtils } from '@0x/utils'; | ||||
| import * as chai from 'chai'; | ||||
| import * as ethUtil from 'ethereumjs-util'; | ||||
|  | ||||
| import { ApprovalFactory, artifacts, constants, CoordinatorContract, exchangeDataEncoder } from '../src'; | ||||
| import { ApprovalFactory, artifacts, CoordinatorContract } from '../src'; | ||||
|  | ||||
| chaiSetup.configure(); | ||||
| const expect = chai.expect; | ||||
| const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); | ||||
|  | ||||
| describe('Mixins tests', () => { | ||||
|     let chainId: number; | ||||
|     let transactionSignerAddress: string; | ||||
|     let approvalSignerAddress1: string; | ||||
|     let approvalSignerAddress2: string; | ||||
| @@ -31,7 +33,7 @@ describe('Mixins tests', () => { | ||||
|     let approvalFactory1: ApprovalFactory; | ||||
|     let approvalFactory2: ApprovalFactory; | ||||
|     let defaultOrder: SignedOrder; | ||||
|     const exchangeAddress = addressUtils.generatePseudoRandomAddress(); | ||||
|     const exchangeAddress = randomAddress(); | ||||
|  | ||||
|     before(async () => { | ||||
|         await blockchainLifecycle.startAsync(); | ||||
| @@ -40,36 +42,40 @@ describe('Mixins tests', () => { | ||||
|         await blockchainLifecycle.revertAsync(); | ||||
|     }); | ||||
|     before(async () => { | ||||
|         chainId = await providerUtils.getChainIdAsync(provider); | ||||
|         mixins = await CoordinatorContract.deployFrom0xArtifactAsync( | ||||
|             artifacts.Coordinator, | ||||
|             provider, | ||||
|             txDefaults, | ||||
|             artifacts, | ||||
|             exchangeAddress, | ||||
|             new BigNumber(chainId), | ||||
|         ); | ||||
|         const accounts = await web3Wrapper.getAvailableAddressesAsync(); | ||||
|         [transactionSignerAddress, approvalSignerAddress1, approvalSignerAddress2] = accounts.slice(0, 3); | ||||
|         defaultOrder = { | ||||
|             exchangeAddress: devConstants.NULL_ADDRESS, | ||||
|             makerAddress: devConstants.NULL_ADDRESS, | ||||
|             takerAddress: devConstants.NULL_ADDRESS, | ||||
|             makerAddress: constants.NULL_ADDRESS, | ||||
|             takerAddress: constants.NULL_ADDRESS, | ||||
|             senderAddress: mixins.address, | ||||
|             feeRecipientAddress: approvalSignerAddress1, | ||||
|             makerAssetData: devConstants.NULL_BYTES, | ||||
|             takerAssetData: devConstants.NULL_BYTES, | ||||
|             makerAssetAmount: devConstants.ZERO_AMOUNT, | ||||
|             takerAssetAmount: devConstants.ZERO_AMOUNT, | ||||
|             makerFee: devConstants.ZERO_AMOUNT, | ||||
|             takerFee: devConstants.ZERO_AMOUNT, | ||||
|             expirationTimeSeconds: devConstants.ZERO_AMOUNT, | ||||
|             salt: devConstants.ZERO_AMOUNT, | ||||
|             signature: devConstants.NULL_BYTES, | ||||
|             makerAssetData: constants.NULL_BYTES, | ||||
|             takerAssetData: constants.NULL_BYTES, | ||||
|             makerAssetAmount: constants.ZERO_AMOUNT, | ||||
|             takerAssetAmount: constants.ZERO_AMOUNT, | ||||
|             makerFee: constants.ZERO_AMOUNT, | ||||
|             takerFee: constants.ZERO_AMOUNT, | ||||
|             makerFeeAssetData: constants.NULL_BYTES, | ||||
|             takerFeeAssetData: constants.NULL_BYTES, | ||||
|             expirationTimeSeconds: constants.ZERO_AMOUNT, | ||||
|             salt: constants.ZERO_AMOUNT, | ||||
|             signature: constants.NULL_BYTES, | ||||
|             exchangeAddress: constants.NULL_ADDRESS, | ||||
|             chainId, | ||||
|         }; | ||||
|         const transactionSignerPrivateKey = | ||||
|             devConstants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(transactionSignerAddress)]; | ||||
|         const approvalSignerPrivateKey1 = devConstants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(approvalSignerAddress1)]; | ||||
|         const approvalSignerPrivateKey2 = devConstants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(approvalSignerAddress2)]; | ||||
|         transactionFactory = new TransactionFactory(transactionSignerPrivateKey, exchangeAddress); | ||||
|         const transactionSignerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(transactionSignerAddress)]; | ||||
|         const approvalSignerPrivateKey1 = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(approvalSignerAddress1)]; | ||||
|         const approvalSignerPrivateKey2 = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(approvalSignerAddress2)]; | ||||
|         transactionFactory = new TransactionFactory(transactionSignerPrivateKey, exchangeAddress, chainId); | ||||
|         approvalFactory1 = new ApprovalFactory(approvalSignerPrivateKey1, mixins.address); | ||||
|         approvalFactory2 = new ApprovalFactory(approvalSignerPrivateKey2, mixins.address); | ||||
|     }); | ||||
| @@ -82,101 +88,105 @@ describe('Mixins tests', () => { | ||||
|  | ||||
|     describe('getSignerAddress', () => { | ||||
|         it('should return the correct address using the EthSign signature type', async () => { | ||||
|             const data = devConstants.NULL_BYTES; | ||||
|             const transaction = transactionFactory.newSignedTransaction(data, SignatureType.EthSign); | ||||
|             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); | ||||
|             expect(transaction.signerAddress).to.eq(signerAddress); | ||||
|         }); | ||||
|         it('should return the correct address using the EIP712 signature type', async () => { | ||||
|             const data = devConstants.NULL_BYTES; | ||||
|             const transaction = transactionFactory.newSignedTransaction(data, SignatureType.EIP712); | ||||
|             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); | ||||
|             expect(transaction.signerAddress).to.eq(signerAddress); | ||||
|         }); | ||||
|         it('should revert with with the Illegal signature type', async () => { | ||||
|             const data = devConstants.NULL_BYTES; | ||||
|             const transaction = transactionFactory.newSignedTransaction(data); | ||||
|             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}`; | ||||
|             const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); | ||||
|             expectContractCallFailedAsync( | ||||
|                 mixins.getSignerAddress.callAsync(transactionHash, transaction.signature), | ||||
|             expect(mixins.getSignerAddress.callAsync(transactionHash, transaction.signature)).to.be.rejectedWith( | ||||
|                 RevertReason.SignatureIllegal, | ||||
|             ); | ||||
|         }); | ||||
|         it('should revert with with the Invalid signature type', async () => { | ||||
|             const data = devConstants.NULL_BYTES; | ||||
|             const transaction = transactionFactory.newSignedTransaction(data); | ||||
|             const data = constants.NULL_BYTES; | ||||
|             const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|             const invalidSignatureByte = ethUtil.toBuffer(SignatureType.Invalid).toString('hex'); | ||||
|             transaction.signature = `0x${invalidSignatureByte}`; | ||||
|             const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); | ||||
|             expectContractCallFailedAsync( | ||||
|                 mixins.getSignerAddress.callAsync(transactionHash, transaction.signature), | ||||
|             expect(mixins.getSignerAddress.callAsync(transactionHash, transaction.signature)).to.be.rejectedWith( | ||||
|                 RevertReason.SignatureInvalid, | ||||
|             ); | ||||
|         }); | ||||
|         it("should revert with with a signature type that doesn't exist", async () => { | ||||
|             const data = devConstants.NULL_BYTES; | ||||
|             const transaction = transactionFactory.newSignedTransaction(data); | ||||
|             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}`; | ||||
|             const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); | ||||
|             expectContractCallFailedAsync( | ||||
|                 mixins.getSignerAddress.callAsync(transactionHash, transaction.signature), | ||||
|             expect(mixins.getSignerAddress.callAsync(transactionHash, transaction.signature)).to.be.rejectedWith( | ||||
|                 RevertReason.SignatureUnsupported, | ||||
|             ); | ||||
|         }); | ||||
|     }); | ||||
|  | ||||
|     describe('decodeOrdersFromFillData', () => { | ||||
|         for (const fnName of constants.SINGLE_FILL_FN_NAMES) { | ||||
|         for (const fnName of exchangeConstants.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 decodedSignedOrders = decodedOrders.map(order => ({ | ||||
|                     ...order, | ||||
|                     exchangeAddress: devConstants.NULL_ADDRESS, | ||||
|                     signature: devConstants.NULL_BYTES, | ||||
|                     signature: constants.NULL_BYTES, | ||||
|                     exchangeAddress: constants.NULL_ADDRESS, | ||||
|                     chainId, | ||||
|                 })); | ||||
|                 expect(orders).to.deep.eq(decodedSignedOrders); | ||||
|             }); | ||||
|         } | ||||
|         for (const fnName of constants.BATCH_FILL_FN_NAMES) { | ||||
|         for (const fnName of exchangeConstants.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 decodedSignedOrders = decodedOrders.map(order => ({ | ||||
|                     ...order, | ||||
|                     exchangeAddress: devConstants.NULL_ADDRESS, | ||||
|                     signature: devConstants.NULL_BYTES, | ||||
|                     signature: constants.NULL_BYTES, | ||||
|                     exchangeAddress: constants.NULL_ADDRESS, | ||||
|                     chainId, | ||||
|                 })); | ||||
|                 expect(orders).to.deep.eq(decodedSignedOrders); | ||||
|             }); | ||||
|         } | ||||
|         for (const fnName of constants.MARKET_FILL_FN_NAMES) { | ||||
|         for (const fnName of exchangeConstants.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 decodedSignedOrders = decodedOrders.map(order => ({ | ||||
|                     ...order, | ||||
|                     exchangeAddress: devConstants.NULL_ADDRESS, | ||||
|                     signature: devConstants.NULL_BYTES, | ||||
|                     signature: constants.NULL_BYTES, | ||||
|                     exchangeAddress: constants.NULL_ADDRESS, | ||||
|                     chainId, | ||||
|                 })); | ||||
|                 expect(orders).to.deep.eq(decodedSignedOrders); | ||||
|             }); | ||||
|         } | ||||
|         for (const fnName of [constants.CANCEL_ORDER, constants.BATCH_CANCEL_ORDERS, constants.CANCEL_ORDERS_UP_TO]) { | ||||
|         for (const fnName of [ | ||||
|             ExchangeFunctionName.CancelOrder, | ||||
|             ExchangeFunctionName.BatchCancelOrders, | ||||
|             ExchangeFunctionName.CancelOrdersUpTo, | ||||
|         ]) { | ||||
|             it(`should correctly decode the orders for ${fnName} data`, async () => { | ||||
|                 const orders = [defaultOrder, defaultOrder]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
| @@ -193,19 +203,21 @@ describe('Mixins tests', () => { | ||||
|         }); | ||||
|         it('should revert if data is less than 4 bytes long', async () => { | ||||
|             const data = '0x010203'; | ||||
|             await expectContractCallFailedAsync( | ||||
|                 mixins.decodeOrdersFromFillData.callAsync(data), | ||||
|                 RevertReason.LibBytesGreaterOrEqualTo4LengthRequired, | ||||
|             const expectedError = new LibBytesRevertErrors.InvalidByteOperationError( | ||||
|                 LibBytesRevertErrors.InvalidByteOperationErrorCodes.LengthGreaterThanOrEqualsFourRequired, | ||||
|                 new BigNumber(3), // the length of data | ||||
|                 new BigNumber(4), | ||||
|             ); | ||||
|             return expect(mixins.decodeOrdersFromFillData.callAsync(data)).to.revertWith(expectedError); | ||||
|         }); | ||||
|     }); | ||||
|  | ||||
|     describe('Single order approvals', () => { | ||||
|         for (const fnName of constants.SINGLE_FILL_FN_NAMES) { | ||||
|         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 () => { | ||||
|                 const orders = [defaultOrder]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = transactionFactory.newSignedTransaction(data); | ||||
|                 const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const currentTimestamp = await getLatestBlockTimestampAsync(); | ||||
|                 const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); | ||||
|                 const approval = approvalFactory1.newSignedApproval( | ||||
| @@ -225,11 +237,11 @@ describe('Mixins tests', () => { | ||||
|             it(`Should be successful: function=${fnName}, caller=tx_signer, senderAddress=[null], approval_sig=[approver1], expiration=[valid]`, async () => { | ||||
|                 const order = { | ||||
|                     ...defaultOrder, | ||||
|                     senderAddress: devConstants.NULL_ADDRESS, | ||||
|                     senderAddress: constants.NULL_ADDRESS, | ||||
|                 }; | ||||
|                 const orders = [order]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = transactionFactory.newSignedTransaction(data); | ||||
|                 const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const currentTimestamp = await getLatestBlockTimestampAsync(); | ||||
|                 const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); | ||||
|                 const approval = approvalFactory1.newSignedApproval( | ||||
| @@ -249,7 +261,7 @@ describe('Mixins tests', () => { | ||||
|             it(`Should be successful: function=${fnName}, caller=approver1, senderAddress=[verifier], approval_sig=[], expiration=[]`, async () => { | ||||
|                 const orders = [defaultOrder]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = transactionFactory.newSignedTransaction(data); | ||||
|                 const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 await mixins.assertValidCoordinatorApprovals.callAsync( | ||||
|                     transaction, | ||||
|                     approvalSignerAddress1, | ||||
| @@ -264,7 +276,7 @@ describe('Mixins tests', () => { | ||||
|             it(`Should be successful: function=${fnName}, caller=approver1, senderAddress=[verifier], approval_sig=[approver1], expiration=[invalid]`, async () => { | ||||
|                 const orders = [defaultOrder]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = transactionFactory.newSignedTransaction(data); | ||||
|                 const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const currentTimestamp = await getLatestBlockTimestampAsync(); | ||||
|                 const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); | ||||
|                 const approval = approvalFactory1.newSignedApproval( | ||||
| @@ -284,7 +296,7 @@ describe('Mixins tests', () => { | ||||
|             it(`Should be successful: function=${fnName}, caller=approver1, senderAddress=[verifier], approval_sig=[], expiration=[]`, async () => { | ||||
|                 const orders = [defaultOrder]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = transactionFactory.newSignedTransaction(data); | ||||
|                 const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 await mixins.assertValidCoordinatorApprovals.callAsync( | ||||
|                     transaction, | ||||
|                     approvalSignerAddress1, | ||||
| @@ -299,7 +311,7 @@ describe('Mixins tests', () => { | ||||
|             it(`Should revert: function=${fnName}, caller=tx_signer, senderAddress=[verifier], approval_sig=[invalid], expiration=[valid]`, async () => { | ||||
|                 const orders = [defaultOrder]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = transactionFactory.newSignedTransaction(data); | ||||
|                 const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const currentTimestamp = await getLatestBlockTimestampAsync(); | ||||
|                 const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); | ||||
|                 const approval = approvalFactory1.newSignedApproval( | ||||
| @@ -323,7 +335,7 @@ describe('Mixins tests', () => { | ||||
|             it(`Should revert: function=${fnName}, caller=tx_signer, senderAddress=[verifier], approval_sig=[approver1], expiration=[invalid]`, async () => { | ||||
|                 const orders = [defaultOrder]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = transactionFactory.newSignedTransaction(data); | ||||
|                 const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const currentTimestamp = await getLatestBlockTimestampAsync(); | ||||
|                 const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).minus(constants.TIME_BUFFER); | ||||
|                 const approval = approvalFactory1.newSignedApproval( | ||||
| @@ -346,7 +358,7 @@ describe('Mixins tests', () => { | ||||
|             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 = transactionFactory.newSignedTransaction(data); | ||||
|                 const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const currentTimestamp = await getLatestBlockTimestampAsync(); | ||||
|                 const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); | ||||
|                 const approval = approvalFactory1.newSignedApproval( | ||||
| @@ -370,14 +382,14 @@ describe('Mixins tests', () => { | ||||
|     }); | ||||
|     describe('Batch order approvals', () => { | ||||
|         for (const fnName of [ | ||||
|             ...constants.BATCH_FILL_FN_NAMES, | ||||
|             ...constants.MARKET_FILL_FN_NAMES, | ||||
|             constants.MATCH_ORDERS, | ||||
|             ...exchangeConstants.BATCH_FILL_FN_NAMES, | ||||
|             ...exchangeConstants.MARKET_FILL_FN_NAMES, | ||||
|             ExchangeFunctionName.MatchOrders, | ||||
|         ]) { | ||||
|             it(`Should be successful: function=${fnName} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1,approver1], approval_sig=[approver1], expiration=[valid]`, async () => { | ||||
|                 const orders = [defaultOrder, defaultOrder]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = transactionFactory.newSignedTransaction(data); | ||||
|                 const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const currentTimestamp = await getLatestBlockTimestampAsync(); | ||||
|                 const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); | ||||
|                 const approval = approvalFactory1.newSignedApproval( | ||||
| @@ -397,10 +409,10 @@ describe('Mixins tests', () => { | ||||
|             it(`Should be successful: function=${fnName} caller=tx_signer, senderAddress=[null,null], feeRecipient=[approver1,approver1], approval_sig=[approver1], expiration=[valid]`, async () => { | ||||
|                 const orders = [defaultOrder, defaultOrder].map(order => ({ | ||||
|                     ...order, | ||||
|                     senderAddress: devConstants.NULL_ADDRESS, | ||||
|                     senderAddress: constants.NULL_ADDRESS, | ||||
|                 })); | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = transactionFactory.newSignedTransaction(data); | ||||
|                 const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const currentTimestamp = await getLatestBlockTimestampAsync(); | ||||
|                 const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); | ||||
|                 const approval = approvalFactory1.newSignedApproval( | ||||
| @@ -420,10 +432,10 @@ describe('Mixins tests', () => { | ||||
|             it(`Should be successful: function=${fnName} caller=tx_signer, senderAddress=[null,null], feeRecipient=[approver1,approver1], approval_sig=[], expiration=[]`, async () => { | ||||
|                 const orders = [defaultOrder, defaultOrder].map(order => ({ | ||||
|                     ...order, | ||||
|                     senderAddress: devConstants.NULL_ADDRESS, | ||||
|                     senderAddress: constants.NULL_ADDRESS, | ||||
|                 })); | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = transactionFactory.newSignedTransaction(data); | ||||
|                 const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 await mixins.assertValidCoordinatorApprovals.callAsync( | ||||
|                     transaction, | ||||
|                     transactionSignerAddress, | ||||
| @@ -434,9 +446,9 @@ describe('Mixins tests', () => { | ||||
|                 ); | ||||
|             }); | ||||
|             it(`Should be successful: function=${fnName} caller=tx_signer, senderAddress=[verifier,null], feeRecipient=[approver1,approver1], approval_sig=[approver1], expiration=[valid]`, async () => { | ||||
|                 const orders = [defaultOrder, { ...defaultOrder, senderAddress: devConstants.NULL_ADDRESS }]; | ||||
|                 const orders = [defaultOrder, { ...defaultOrder, senderAddress: constants.NULL_ADDRESS }]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = transactionFactory.newSignedTransaction(data); | ||||
|                 const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const currentTimestamp = await getLatestBlockTimestampAsync(); | ||||
|                 const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); | ||||
|                 const approval = approvalFactory1.newSignedApproval( | ||||
| @@ -456,7 +468,7 @@ describe('Mixins tests', () => { | ||||
|             it(`Should be successful: function=${fnName} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1,approver2], approval_sig=[approver1,approver2], expiration=[valid,valid]`, async () => { | ||||
|                 const orders = [defaultOrder, { ...defaultOrder, feeRecipientAddress: approvalSignerAddress2 }]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = transactionFactory.newSignedTransaction(data); | ||||
|                 const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const currentTimestamp = await getLatestBlockTimestampAsync(); | ||||
|                 const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); | ||||
|                 const approval1 = approvalFactory1.newSignedApproval( | ||||
| @@ -481,7 +493,7 @@ describe('Mixins tests', () => { | ||||
|             it(`Should be successful: function=${fnName} caller=approver1, senderAddress=[verifier,verifier], feeRecipient=[approver1,approver1], approval_sig=[], expiration=[]`, async () => { | ||||
|                 const orders = [defaultOrder, defaultOrder]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = transactionFactory.newSignedTransaction(data); | ||||
|                 const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 await mixins.assertValidCoordinatorApprovals.callAsync( | ||||
|                     transaction, | ||||
|                     approvalSignerAddress1, | ||||
| @@ -494,7 +506,7 @@ describe('Mixins tests', () => { | ||||
|             it(`Should revert: function=${fnName} caller=approver1, senderAddress=[verifier,verifier], feeRecipient=[approver1,approver2], approval_sig=[approver2], expiration=[valid]`, async () => { | ||||
|                 const orders = [defaultOrder, { ...defaultOrder, feeRecipientAddress: approvalSignerAddress2 }]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = transactionFactory.newSignedTransaction(data); | ||||
|                 const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const currentTimestamp = await getLatestBlockTimestampAsync(); | ||||
|                 const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); | ||||
|                 const approval2 = approvalFactory2.newSignedApproval( | ||||
| @@ -517,7 +529,7 @@ describe('Mixins tests', () => { | ||||
|             it(`Should revert: function=${fnName} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver1], approval_sig=[], expiration=[]`, async () => { | ||||
|                 const orders = [defaultOrder, defaultOrder]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = transactionFactory.newSignedTransaction(data); | ||||
|                 const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 expectContractCallFailedAsync( | ||||
|                     mixins.assertValidCoordinatorApprovals.callAsync( | ||||
|                         transaction, | ||||
| @@ -533,7 +545,7 @@ describe('Mixins tests', () => { | ||||
|             it(`Should revert: function=${fnName} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver1], approval_sig=[invalid], expiration=[valid]`, async () => { | ||||
|                 const orders = [defaultOrder, defaultOrder]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = transactionFactory.newSignedTransaction(data); | ||||
|                 const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const currentTimestamp = await getLatestBlockTimestampAsync(); | ||||
|                 const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); | ||||
|                 const approval = approvalFactory1.newSignedApproval( | ||||
| @@ -557,7 +569,7 @@ describe('Mixins tests', () => { | ||||
|             it(`Should revert: function=${fnName} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver2], approval_sig=[valid,invalid], expiration=[valid,valid]`, async () => { | ||||
|                 const orders = [defaultOrder, { ...defaultOrder, feeRecipientAddress: approvalSignerAddress2 }]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = transactionFactory.newSignedTransaction(data); | ||||
|                 const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const currentTimestamp = await getLatestBlockTimestampAsync(); | ||||
|                 const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); | ||||
|                 const approval1 = approvalFactory1.newSignedApproval( | ||||
| @@ -586,7 +598,7 @@ describe('Mixins tests', () => { | ||||
|             it(`Should revert: function=${fnName} caller=approver1, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver2], approval_sig=[invalid], expiration=[valid]`, async () => { | ||||
|                 const orders = [defaultOrder, { ...defaultOrder, feeRecipientAddress: approvalSignerAddress2 }]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = transactionFactory.newSignedTransaction(data); | ||||
|                 const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const currentTimestamp = await getLatestBlockTimestampAsync(); | ||||
|                 const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); | ||||
|                 const approval2 = approvalFactory2.newSignedApproval( | ||||
| @@ -610,7 +622,7 @@ describe('Mixins tests', () => { | ||||
|             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 = transactionFactory.newSignedTransaction(data); | ||||
|                 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); | ||||
| @@ -639,7 +651,7 @@ describe('Mixins tests', () => { | ||||
|             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 = transactionFactory.newSignedTransaction(data); | ||||
|                 const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const currentTimestamp = await getLatestBlockTimestampAsync(); | ||||
|                 const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).minus(constants.TIME_BUFFER); | ||||
|                 const approval2 = approvalFactory2.newSignedApproval( | ||||
| @@ -662,7 +674,7 @@ describe('Mixins tests', () => { | ||||
|             it(`Should revert: function=${fnName} caller=approver2, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver1], approval_sig=[valid], expiration=[valid]`, async () => { | ||||
|                 const orders = [defaultOrder, defaultOrder]; | ||||
|                 const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); | ||||
|                 const transaction = transactionFactory.newSignedTransaction(data); | ||||
|                 const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|                 const currentTimestamp = await getLatestBlockTimestampAsync(); | ||||
|                 const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); | ||||
|                 const approval1 = approvalFactory1.newSignedApproval( | ||||
| @@ -687,8 +699,8 @@ describe('Mixins tests', () => { | ||||
|     describe('cancels', () => { | ||||
|         it('should allow the tx signer to call `cancelOrder` without approval', async () => { | ||||
|             const orders = [defaultOrder]; | ||||
|             const data = exchangeDataEncoder.encodeOrdersToExchangeData(constants.CANCEL_ORDER, orders); | ||||
|             const transaction = transactionFactory.newSignedTransaction(data); | ||||
|             const data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.CancelOrder, orders); | ||||
|             const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|             await mixins.assertValidCoordinatorApprovals.callAsync( | ||||
|                 transaction, | ||||
|                 transactionSignerAddress, | ||||
| @@ -700,8 +712,8 @@ describe('Mixins tests', () => { | ||||
|         }); | ||||
|         it('should allow the tx signer to call `batchCancelOrders` without approval', async () => { | ||||
|             const orders = [defaultOrder, defaultOrder]; | ||||
|             const data = exchangeDataEncoder.encodeOrdersToExchangeData(constants.BATCH_CANCEL_ORDERS, orders); | ||||
|             const transaction = transactionFactory.newSignedTransaction(data); | ||||
|             const data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.BatchCancelOrders, orders); | ||||
|             const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|             await mixins.assertValidCoordinatorApprovals.callAsync( | ||||
|                 transaction, | ||||
|                 transactionSignerAddress, | ||||
| @@ -712,9 +724,8 @@ describe('Mixins tests', () => { | ||||
|             ); | ||||
|         }); | ||||
|         it('should allow the tx signer to call `cancelOrdersUpTo` without approval', async () => { | ||||
|             const orders: SignedOrder[] = []; | ||||
|             const data = exchangeDataEncoder.encodeOrdersToExchangeData(constants.CANCEL_ORDERS_UP_TO, orders); | ||||
|             const transaction = transactionFactory.newSignedTransaction(data); | ||||
|             const data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.CancelOrdersUpTo); | ||||
|             const transaction = await transactionFactory.newSignedTransactionAsync({ data }); | ||||
|             await mixins.assertValidCoordinatorApprovals.callAsync( | ||||
|                 transaction, | ||||
|                 transactionSignerAddress, | ||||
|   | ||||
| @@ -9,9 +9,9 @@ export class ApprovalFactory { | ||||
|     private readonly _privateKey: Buffer; | ||||
|     private readonly _verifyingContractAddress: string; | ||||
|  | ||||
|     constructor(privateKey: Buffer, verifyingContractAddress: string) { | ||||
|     constructor(privateKey: Buffer, verifyingContract: string) { | ||||
|         this._privateKey = privateKey; | ||||
|         this._verifyingContractAddress = verifyingContractAddress; | ||||
|         this._verifyingContractAddress = verifyingContract; | ||||
|     } | ||||
|  | ||||
|     public newSignedApproval( | ||||
|   | ||||
| @@ -1,12 +0,0 @@ | ||||
| import { BigNumber } from '@0x/utils'; | ||||
|  | ||||
| export const constants = { | ||||
|     SINGLE_FILL_FN_NAMES: ['fillOrder', 'fillOrKillOrder', 'fillOrderNoThrow'], | ||||
|     BATCH_FILL_FN_NAMES: ['batchFillOrders', 'batchFillOrKillOrders', 'batchFillOrdersNoThrow'], | ||||
|     MARKET_FILL_FN_NAMES: ['marketBuyOrders', 'marketBuyOrdersNoThrow', 'marketSellOrders', 'marketSellOrdersNoThrow'], | ||||
|     MATCH_ORDERS: 'matchOrders', | ||||
|     CANCEL_ORDER: 'cancelOrder', | ||||
|     BATCH_CANCEL_ORDERS: 'batchCancelOrders', | ||||
|     CANCEL_ORDERS_UP_TO: 'cancelOrdersUpTo', | ||||
|     TIME_BUFFER: new BigNumber(1000), | ||||
| }; | ||||
| @@ -1,47 +0,0 @@ | ||||
| import { IExchangeContract } from '@0x/contracts-exchange'; | ||||
| import { constants as devConstants, provider } from '@0x/contracts-test-utils'; | ||||
| import { SignedOrder } from '@0x/types'; | ||||
|  | ||||
| import { constants } from './index'; | ||||
|  | ||||
| export const exchangeDataEncoder = { | ||||
|     encodeOrdersToExchangeData(fnName: string, orders: SignedOrder[]): string { | ||||
|         const exchangeInstance = new IExchangeContract(devConstants.NULL_ADDRESS, provider); | ||||
|         let data; | ||||
|         if (constants.SINGLE_FILL_FN_NAMES.indexOf(fnName) !== -1) { | ||||
|             data = (exchangeInstance as any)[fnName].getABIEncodedTransactionData( | ||||
|                 orders[0], | ||||
|                 orders[0].takerAssetAmount, | ||||
|                 orders[0].signature, | ||||
|             ); | ||||
|         } else if (constants.BATCH_FILL_FN_NAMES.indexOf(fnName) !== -1) { | ||||
|             data = (exchangeInstance as any)[fnName].getABIEncodedTransactionData( | ||||
|                 orders, | ||||
|                 orders.map(order => order.takerAssetAmount), | ||||
|                 orders.map(order => order.signature), | ||||
|             ); | ||||
|         } else if (constants.MARKET_FILL_FN_NAMES.indexOf(fnName) !== -1) { | ||||
|             data = (exchangeInstance as any)[fnName].getABIEncodedTransactionData( | ||||
|                 orders, | ||||
|                 orders.map(order => order.takerAssetAmount).reduce((prev, curr) => prev.plus(curr)), | ||||
|                 orders.map(order => order.signature), | ||||
|             ); | ||||
|         } else if (fnName === constants.MATCH_ORDERS) { | ||||
|             data = exchangeInstance.matchOrders.getABIEncodedTransactionData( | ||||
|                 orders[0], | ||||
|                 orders[1], | ||||
|                 orders[0].signature, | ||||
|                 orders[1].signature, | ||||
|             ); | ||||
|         } else if (fnName === constants.CANCEL_ORDER) { | ||||
|             data = exchangeInstance.cancelOrder.getABIEncodedTransactionData(orders[0]); | ||||
|         } else if (fnName === constants.BATCH_CANCEL_ORDERS) { | ||||
|             data = exchangeInstance.batchCancelOrders.getABIEncodedTransactionData(orders); | ||||
|         } else if (fnName === constants.CANCEL_ORDERS_UP_TO) { | ||||
|             data = exchangeInstance.cancelOrdersUpTo.getABIEncodedTransactionData(devConstants.ZERO_AMOUNT); | ||||
|         } else { | ||||
|             throw new Error(`Error: ${fnName} not a supported function`); | ||||
|         } | ||||
|         return data; | ||||
|     }, | ||||
| }; | ||||
| @@ -6,13 +6,13 @@ import * as _ from 'lodash'; | ||||
| export const hashUtils = { | ||||
|     getApprovalHashBuffer( | ||||
|         transaction: SignedZeroExTransaction, | ||||
|         verifyingContractAddress: string, | ||||
|         verifyingContract: string, | ||||
|         txOrigin: string, | ||||
|         approvalExpirationTimeSeconds: BigNumber, | ||||
|     ): Buffer { | ||||
|         const typedData = eip712Utils.createCoordinatorApprovalTypedData( | ||||
|             transaction, | ||||
|             verifyingContractAddress, | ||||
|             verifyingContract, | ||||
|             txOrigin, | ||||
|             approvalExpirationTimeSeconds, | ||||
|         ); | ||||
| @@ -21,12 +21,12 @@ export const hashUtils = { | ||||
|     }, | ||||
|     getApprovalHashHex( | ||||
|         transaction: SignedZeroExTransaction, | ||||
|         verifyingContractAddress: string, | ||||
|         verifyingContract: string, | ||||
|         txOrigin: string, | ||||
|         approvalExpirationTimeSeconds: BigNumber, | ||||
|     ): string { | ||||
|         const hashHex = `0x${hashUtils | ||||
|             .getApprovalHashBuffer(transaction, verifyingContractAddress, txOrigin, approvalExpirationTimeSeconds) | ||||
|             .getApprovalHashBuffer(transaction, verifyingContract, txOrigin, approvalExpirationTimeSeconds) | ||||
|             .toString('hex')}`; | ||||
|         return hashHex; | ||||
|     }, | ||||
|   | ||||
| @@ -1,5 +1,3 @@ | ||||
| export { hashUtils } from './hash_utils'; | ||||
| export { ApprovalFactory } from './approval_factory'; | ||||
| export { constants } from './constants'; | ||||
| export { exchangeDataEncoder } from './exchange_data_encoder'; | ||||
| export * from './types'; | ||||
|   | ||||
							
								
								
									
										96
									
								
								contracts/coordinator/truffle-config.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								contracts/coordinator/truffle-config.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,96 @@ | ||||
| /** | ||||
|  * Use this file to configure your truffle project. It's seeded with some | ||||
|  * common settings for different networks and features like migrations, | ||||
|  * compilation and testing. Uncomment the ones you need or modify | ||||
|  * them to suit your project as necessary. | ||||
|  * | ||||
|  * More information about configuration can be found at: | ||||
|  * | ||||
|  * truffleframework.com/docs/advanced/configuration | ||||
|  * | ||||
|  * To deploy via Infura you'll need a wallet provider (like truffle-hdwallet-provider) | ||||
|  * to sign your transactions before they're sent to a remote public node. Infura accounts | ||||
|  * are available for free at: infura.io/register. | ||||
|  * | ||||
|  * You'll also need a mnemonic - the twelve word phrase the wallet uses to generate | ||||
|  * public/private key pairs. If you're publishing your code to GitHub make sure you load this | ||||
|  * phrase from a file you've .gitignored so it doesn't accidentally become public. | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| // const HDWalletProvider = require('truffle-hdwallet-provider'); | ||||
| // const infuraKey = "fj4jll3k....."; | ||||
| // | ||||
| // const fs = require('fs'); | ||||
| // const mnemonic = fs.readFileSync(".secret").toString().trim(); | ||||
|  | ||||
| module.exports = { | ||||
|     /** | ||||
|      * Networks define how you connect to your ethereum client and let you set the | ||||
|      * defaults web3 uses to send transactions. If you don't specify one truffle | ||||
|      * will spin up a development blockchain for you on port 9545 when you | ||||
|      * run `develop` or `test`. You can ask a truffle command to use a specific | ||||
|      * network from the command line, e.g | ||||
|      * | ||||
|      * $ truffle test --network <network-name> | ||||
|      */ | ||||
|  | ||||
|     networks: { | ||||
|         // Useful for testing. The `development` name is special - truffle uses it by default | ||||
|         // if it's defined here and no other network is specified at the command line. | ||||
|         // You should run a client (like ganache-cli, geth or parity) in a separate terminal | ||||
|         // tab if you use this network and you must also set the `host`, `port` and `network_id` | ||||
|         // options below to some value. | ||||
|         // | ||||
|         // development: { | ||||
|         //  host: "127.0.0.1",     // Localhost (default: none) | ||||
|         //  port: 8545,            // Standard Ethereum port (default: none) | ||||
|         //  network_id: "*",       // Any network (default: none) | ||||
|         // }, | ||||
|         // Another network with more advanced options... | ||||
|         // advanced: { | ||||
|         // port: 8777,             // Custom port | ||||
|         // network_id: 1342,       // Custom network | ||||
|         // gas: 8500000,           // Gas sent with each transaction (default: ~6700000) | ||||
|         // gasPrice: 20000000000,  // 20 gwei (in wei) (default: 100 gwei) | ||||
|         // from: <address>,        // Account to send txs from (default: accounts[0]) | ||||
|         // websockets: true        // Enable EventEmitter interface for web3 (default: false) | ||||
|         // }, | ||||
|         // Useful for deploying to a public network. | ||||
|         // NB: It's important to wrap the provider as a function. | ||||
|         // ropsten: { | ||||
|         // provider: () => new HDWalletProvider(mnemonic, `https://ropsten.infura.io/v3/YOUR-PROJECT-ID`), | ||||
|         // network_id: 3,       // Ropsten's id | ||||
|         // gas: 5500000,        // Ropsten has a lower block limit than mainnet | ||||
|         // confirmations: 2,    // # of confs to wait between deployments. (default: 0) | ||||
|         // timeoutBlocks: 200,  // # of blocks before a deployment times out  (minimum/default: 50) | ||||
|         // skipDryRun: true     // Skip dry run before migrations? (default: false for public nets ) | ||||
|         // }, | ||||
|         // Useful for private networks | ||||
|         // private: { | ||||
|         // provider: () => new HDWalletProvider(mnemonic, `https://network.io`), | ||||
|         // network_id: 2111,   // This network is yours, in the cloud. | ||||
|         // production: true    // Treats this network as if it was a public net. (default: false) | ||||
|         // } | ||||
|     }, | ||||
|  | ||||
|     // Set default mocha options here, use special reporters etc. | ||||
|     mocha: { | ||||
|         // timeout: 100000 | ||||
|     }, | ||||
|  | ||||
|     // Configure your compilers | ||||
|     compilers: { | ||||
|         solc: { | ||||
|             version: '0.5.9', | ||||
|             settings: { | ||||
|                 evmVersion: 'constantinople', | ||||
|                 optimizer: { | ||||
|                     enabled: true, | ||||
|                     runs: 1000000, | ||||
|                     details: { yul: true, deduplicate: true, cse: true, constantOptimizer: true }, | ||||
|                 }, | ||||
|             }, | ||||
|         }, | ||||
|     }, | ||||
| }; | ||||
| @@ -1,4 +1,35 @@ | ||||
| [ | ||||
|     { | ||||
|         "version": "0.1.0-beta.0", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Use built in selectors instead of hard coded constants", | ||||
|                 "pr": 2055 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Compile and export all contracts, artifacts, and wrappers by default", | ||||
|                 "pr": 2055 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Add `marketBuy/SellOrdersNoThrow` and `marketBuy/SellOrdersFillOrKill` to `LibTransactionDecoder`.", | ||||
|                 "pr": 2075 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "`run_mocha` package script runs with `UNLIMITED_CONTRACT_SIZE=true` environment variable.", | ||||
|                 "pr": 2075 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1570135330 | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1568744790, | ||||
|         "version": "0.0.10", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1567521715, | ||||
|         "version": "0.0.9", | ||||
| @@ -107,6 +138,14 @@ | ||||
|             { | ||||
|                 "note": "Add support for StaticCallProxy", | ||||
|                 "pr": 1863 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Add `OrderTransferSimulationUtils` contract for simulating order transfers on-chain", | ||||
|                 "pr": 1868 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Updated to use the new rich error pattern from @0x/contracts-exchange", | ||||
|                 "pr": 1913 | ||||
|             } | ||||
|         ] | ||||
|     } | ||||
|   | ||||
| @@ -5,6 +5,17 @@ Edit the package's CHANGELOG.json file only. | ||||
|  | ||||
| CHANGELOG | ||||
|  | ||||
| ## v0.1.0-beta.0 - _October 3, 2019_ | ||||
|  | ||||
|     * Use built in selectors instead of hard coded constants (#2055) | ||||
|     * Compile and export all contracts, artifacts, and wrappers by default (#2055) | ||||
|     * Add `marketBuy/SellOrdersNoThrow` and `marketBuy/SellOrdersFillOrKill` to `LibTransactionDecoder`. (#2075) | ||||
|     * `run_mocha` package script runs with `UNLIMITED_CONTRACT_SIZE=true` environment variable. (#2075) | ||||
|  | ||||
| ## v0.0.10 - _September 17, 2019_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v0.0.9 - _September 3, 2019_ | ||||
|  | ||||
|     * Dependencies updated | ||||
| @@ -49,3 +60,5 @@ CHANGELOG | ||||
|     * Refactor `LibAssetData` balance/allowance checks to never revert (#1848) | ||||
|     * Refactor `OrderValidationUtils` to calculate `fillableTakerAssetAmount` (#1848) | ||||
|     * Add support for StaticCallProxy (#1863) | ||||
|     * Add `OrderTransferSimulationUtils` contract for simulating order transfers on-chain (#1868) | ||||
|     * Updated to use the new rich error pattern from @0x/contracts-exchange (#1913) | ||||
|   | ||||
| @@ -7,7 +7,7 @@ | ||||
|         "evmVersion": "constantinople", | ||||
|         "optimizer": { | ||||
|             "enabled": true, | ||||
|             "runs": 1000000, | ||||
|             "runs": 10000, | ||||
|             "details": { "yul": true, "deduplicate": true, "cse": true, "constantOptimizer": true } | ||||
|         }, | ||||
|         "outputSelection": { | ||||
| @@ -22,11 +22,5 @@ | ||||
|                 ] | ||||
|             } | ||||
|         } | ||||
|     }, | ||||
|     "contracts": [ | ||||
|         "src/DevUtils.sol", | ||||
|         "src/LibAssetData.sol", | ||||
|         "src/LibTransactionDecoder.sol", | ||||
|         "src/EthBalanceChecker.sol" | ||||
|     ] | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|  | ||||
|   Copyright 2018 ZeroEx Intl. | ||||
|   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. | ||||
| @@ -20,6 +20,7 @@ pragma solidity ^0.5.5; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "./OrderValidationUtils.sol"; | ||||
| import "./OrderTransferSimulationUtils.sol"; | ||||
| import "./LibTransactionDecoder.sol"; | ||||
| import "./EthBalanceChecker.sol"; | ||||
|  | ||||
| @@ -28,10 +29,12 @@ import "./EthBalanceChecker.sol"; | ||||
| contract DevUtils is | ||||
|     OrderValidationUtils, | ||||
|     LibTransactionDecoder, | ||||
|     EthBalanceChecker | ||||
|     EthBalanceChecker, | ||||
|     OrderTransferSimulationUtils | ||||
| { | ||||
|     constructor (address _exchange, bytes memory _zrxAssetData) | ||||
|     constructor (address _exchange) | ||||
|         public | ||||
|         OrderValidationUtils(_exchange, _zrxAssetData) | ||||
|         OrderValidationUtils(_exchange) | ||||
|         OrderTransferSimulationUtils(_exchange) | ||||
|     {} | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|  | ||||
|   Copyright 2018 ZeroEx Intl. | ||||
|   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. | ||||
|   | ||||
| @@ -20,32 +20,19 @@ pragma solidity ^0.5.5; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "@0x/contracts-utils/contracts/src/LibBytes.sol"; | ||||
| import "@0x/contracts-asset-proxy/contracts/src/libs/LibAssetProxyIds.sol"; | ||||
| import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol"; | ||||
| import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetData.sol"; | ||||
| import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetProxy.sol"; | ||||
| import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; | ||||
| import "@0x/contracts-erc721/contracts/src/interfaces/IERC721Token.sol"; | ||||
| import "@0x/contracts-erc1155/contracts/src/interfaces/IERC1155.sol"; | ||||
|  | ||||
|  | ||||
| contract LibAssetData is | ||||
|     LibAssetProxyIds | ||||
| { | ||||
| contract LibAssetData { | ||||
|  | ||||
|     // 2^256 - 1 | ||||
|     uint256 constant internal _MAX_UINT256 = uint256(-1); | ||||
|  | ||||
|     // ERC20 selectors | ||||
|     bytes4 constant internal _ERC20_BALANCE_OF_SELECTOR = 0x70a08231; | ||||
|     bytes4 constant internal _ERC20_ALLOWANCE_SELECTOR = 0xdd62ed3e; | ||||
|  | ||||
|     // ERC721 selectors | ||||
|     bytes4 constant internal _ERC721_OWNER_OF_SELECTOR = 0x6352211e; | ||||
|     bytes4 constant internal _ERC721_IS_APPROVED_FOR_ALL_SELECTOR = 0xe985e9c5; | ||||
|     bytes4 constant internal _ERC721_GET_APPROVED_SELECTOR = 0x081812fc; | ||||
|  | ||||
|     // ERC1155 selectors | ||||
|     bytes4 constant internal _ERC1155_BALANCE_OF_SELECTOR = 0x00fdd58e; | ||||
|     bytes4 constant internal _ERC1155_IS_APPROVED_FOR_ALL_SELECTOR = 0xe985e9c5; | ||||
|  | ||||
|     // `transferFrom` selector for all AssetProxy contracts | ||||
|     bytes4 constant internal _ASSET_PROXY_TRANSFER_FROM_SELECTOR = 0xa85e59e4; | ||||
|  | ||||
|     using LibBytes for bytes; | ||||
|  | ||||
|     // solhint-disable var-name-mixedcase | ||||
| @@ -60,10 +47,10 @@ contract LibAssetData is | ||||
|         public | ||||
|     { | ||||
|         _EXCHANGE = IExchange(_exchange); | ||||
|         _ERC20_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(ERC20_PROXY_ID); | ||||
|         _ERC721_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(ERC721_PROXY_ID); | ||||
|         _ERC1155_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(ERC1155_PROXY_ID); | ||||
|         _STATIC_CALL_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(STATIC_CALL_PROXY_ID); | ||||
|         _ERC20_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(IAssetData(address(0)).ERC20Token.selector); | ||||
|         _ERC721_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(IAssetData(address(0)).ERC721Token.selector); | ||||
|         _ERC1155_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(IAssetData(address(0)).ERC1155Assets.selector); | ||||
|         _STATIC_CALL_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(IAssetData(address(0)).StaticCall.selector); | ||||
|     } | ||||
|  | ||||
|     /// @dev Returns the owner's balance of the assets(s) specified in | ||||
| @@ -81,23 +68,33 @@ contract LibAssetData is | ||||
|         // Get id of AssetProxy contract | ||||
|         bytes4 assetProxyId = assetData.readBytes4(0); | ||||
|  | ||||
|         if (assetProxyId == ERC20_PROXY_ID) { | ||||
|         if (assetProxyId == IAssetData(address(0)).ERC20Token.selector) { | ||||
|             // Get ERC20 token address | ||||
|             address tokenAddress = assetData.readAddress(16); | ||||
|  | ||||
|             // Encode data for `balanceOf(ownerAddress)` | ||||
|             bytes memory balanceOfData = abi.encodeWithSelector(_ERC20_BALANCE_OF_SELECTOR, ownerAddress); | ||||
|             bytes memory balanceOfData = abi.encodeWithSelector( | ||||
|                 IERC20Token(address(0)).balanceOf.selector, | ||||
|                 ownerAddress | ||||
|             ); | ||||
|  | ||||
|             // Query balance | ||||
|             (bool success, bytes memory returnData) = tokenAddress.staticcall(balanceOfData); | ||||
|             balance = success && returnData.length == 32 ? returnData.readUint256(0) : 0; | ||||
|         } else if (assetProxyId == ERC721_PROXY_ID) { | ||||
|         } else if (assetProxyId == IAssetData(address(0)).ERC721Token.selector) { | ||||
|             // Get ERC721 token address and id | ||||
|             (, address tokenAddress, uint256 tokenId) = decodeERC721AssetData(assetData); | ||||
|  | ||||
|             // Check if id is owned by ownerAddress | ||||
|             balance = getERC721TokenOwner(tokenAddress, tokenId) == ownerAddress ? 1 : 0; | ||||
|         } else if (assetProxyId == ERC1155_PROXY_ID) { | ||||
|             bytes memory ownerOfCalldata = abi.encodeWithSelector( | ||||
|                 IERC721Token(address(0)).ownerOf.selector, | ||||
|                 tokenId | ||||
|             ); | ||||
|  | ||||
|             (bool success, bytes memory returnData) = tokenAddress.staticcall(ownerOfCalldata); | ||||
|             address currentOwnerAddress = (success && returnData.length == 32) ? returnData.readAddress(12) : address(0); | ||||
|             balance = currentOwnerAddress == ownerAddress ? 1 : 0; | ||||
|         } else if (assetProxyId == IAssetData(address(0)).ERC1155Assets.selector) { | ||||
|             // Get ERC1155 token address, array of ids, and array of values | ||||
|             (, address tokenAddress, uint256[] memory tokenIds, uint256[] memory tokenValues,) = decodeERC1155AssetData(assetData); | ||||
|  | ||||
| @@ -105,7 +102,7 @@ contract LibAssetData is | ||||
|             for (uint256 i = 0; i != length; i++) { | ||||
|                 // Encode data for `balanceOf(ownerAddress, tokenIds[i]) | ||||
|                 bytes memory balanceOfData = abi.encodeWithSelector( | ||||
|                     _ERC1155_BALANCE_OF_SELECTOR, | ||||
|                     IERC1155(address(0)).balanceOf.selector, | ||||
|                     ownerAddress, | ||||
|                     tokenIds[i] | ||||
|                 ); | ||||
| @@ -120,10 +117,10 @@ contract LibAssetData is | ||||
|                     balance = scaledBalance; | ||||
|                 } | ||||
|             } | ||||
|         } else if (assetProxyId == STATIC_CALL_PROXY_ID) { | ||||
|         } else if (assetProxyId == IAssetData(address(0)).StaticCall.selector) { | ||||
|             // Encode data for `staticCallProxy.transferFrom(assetData,...)` | ||||
|             bytes memory transferFromData = abi.encodeWithSelector( | ||||
|                 _ASSET_PROXY_TRANSFER_FROM_SELECTOR, | ||||
|                 IAssetProxy(address(0)).transferFrom.selector, | ||||
|                 assetData, | ||||
|                 address(0),  // `from` address is not used | ||||
|                 address(0),  // `to` address is not used | ||||
| @@ -135,7 +132,7 @@ contract LibAssetData is | ||||
|  | ||||
|             // Success means that the staticcall can be made an unlimited amount of times | ||||
|             balance = success ? _MAX_UINT256 : 0; | ||||
|         } else if (assetProxyId == MULTI_ASSET_PROXY_ID) { | ||||
|         } else if (assetProxyId == IAssetData(address(0)).MultiAsset.selector) { | ||||
|             // Get array of values and array of assetDatas | ||||
|             (, uint256[] memory assetAmounts, bytes[] memory nestedAssetData) = decodeMultiAssetData(assetData); | ||||
|  | ||||
| @@ -190,7 +187,7 @@ contract LibAssetData is | ||||
|         // Get id of AssetProxy contract | ||||
|         bytes4 assetProxyId = assetData.readBytes4(0); | ||||
|  | ||||
|         if (assetProxyId == MULTI_ASSET_PROXY_ID) { | ||||
|         if (assetProxyId == IAssetData(address(0)).MultiAsset.selector) { | ||||
|             // Get array of values and array of assetDatas | ||||
|             (, uint256[] memory amounts, bytes[] memory nestedAssetData) = decodeMultiAssetData(assetData); | ||||
|  | ||||
| @@ -208,13 +205,13 @@ contract LibAssetData is | ||||
|             return allowance; | ||||
|         } | ||||
|  | ||||
|         if (assetProxyId == ERC20_PROXY_ID) { | ||||
|         if (assetProxyId == IAssetData(address(0)).ERC20Token.selector) { | ||||
|             // Get ERC20 token address | ||||
|             address tokenAddress = assetData.readAddress(16); | ||||
|  | ||||
|             // Encode data for `allowance(ownerAddress, _ERC20_PROXY_ADDRESS)` | ||||
|             bytes memory allowanceData = abi.encodeWithSelector( | ||||
|                 _ERC20_ALLOWANCE_SELECTOR, | ||||
|                 IERC20Token(address(0)).allowance.selector, | ||||
|                 ownerAddress, | ||||
|                 _ERC20_PROXY_ADDRESS | ||||
|             ); | ||||
| @@ -222,13 +219,13 @@ contract LibAssetData is | ||||
|             // Query allowance | ||||
|             (bool success, bytes memory returnData) = tokenAddress.staticcall(allowanceData); | ||||
|             allowance = success && returnData.length == 32 ? returnData.readUint256(0) : 0; | ||||
|         } else if (assetProxyId == ERC721_PROXY_ID) { | ||||
|         } else if (assetProxyId == IAssetData(address(0)).ERC721Token.selector) { | ||||
|             // Get ERC721 token address and id | ||||
|             (, address tokenAddress, uint256 tokenId) = decodeERC721AssetData(assetData); | ||||
|  | ||||
|             // Encode data for `isApprovedForAll(ownerAddress, _ERC721_PROXY_ADDRESS)` | ||||
|             bytes memory isApprovedForAllData = abi.encodeWithSelector( | ||||
|                 _ERC721_IS_APPROVED_FOR_ALL_SELECTOR, | ||||
|                 IERC721Token(address(0)).isApprovedForAll.selector, | ||||
|                 ownerAddress, | ||||
|                 _ERC721_PROXY_ADDRESS | ||||
|             ); | ||||
| @@ -238,7 +235,7 @@ contract LibAssetData is | ||||
|             // If not approved for all, call `getApproved(tokenId)` | ||||
|             if (!success || returnData.length != 32 || returnData.readUint256(0) != 1) { | ||||
|                 // Encode data for `getApproved(tokenId)` | ||||
|                 bytes memory getApprovedData = abi.encodeWithSelector(_ERC721_GET_APPROVED_SELECTOR, tokenId); | ||||
|                 bytes memory getApprovedData = abi.encodeWithSelector(IERC721Token(address(0)).getApproved.selector, tokenId); | ||||
|                 (success, returnData) = tokenAddress.staticcall(getApprovedData); | ||||
|  | ||||
|                 // Allowance is 1 if successful and the approved address is the ERC721Proxy | ||||
| @@ -247,13 +244,13 @@ contract LibAssetData is | ||||
|                 // Allowance is 2^256 - 1 if `isApprovedForAll` returned true | ||||
|                 allowance = _MAX_UINT256; | ||||
|             } | ||||
|         } else if (assetProxyId == ERC1155_PROXY_ID) { | ||||
|         } else if (assetProxyId == IAssetData(address(0)).ERC1155Assets.selector) { | ||||
|             // Get ERC1155 token address | ||||
|             (, address tokenAddress, , , ) = decodeERC1155AssetData(assetData); | ||||
|  | ||||
|             // Encode data for `isApprovedForAll(ownerAddress, _ERC1155_PROXY_ADDRESS)` | ||||
|             bytes memory isApprovedForAllData = abi.encodeWithSelector( | ||||
|                 _ERC1155_IS_APPROVED_FOR_ALL_SELECTOR, | ||||
|                 IERC1155(address(0)).isApprovedForAll.selector, | ||||
|                 ownerAddress, | ||||
|                 _ERC1155_PROXY_ADDRESS | ||||
|             ); | ||||
| @@ -261,7 +258,7 @@ contract LibAssetData is | ||||
|             // Query allowance | ||||
|             (bool success, bytes memory returnData) = tokenAddress.staticcall(isApprovedForAllData); | ||||
|             allowance = success && returnData.length == 32 && returnData.readUint256(0) == 1 ? _MAX_UINT256 : 0; | ||||
|         } else if (assetProxyId == STATIC_CALL_PROXY_ID) { | ||||
|         } else if (assetProxyId == IAssetData(address(0)).StaticCall.selector) { | ||||
|             // The StaticCallProxy does not require any approvals | ||||
|             allowance = _MAX_UINT256; | ||||
|         } | ||||
| @@ -327,7 +324,7 @@ contract LibAssetData is | ||||
|         pure | ||||
|         returns (bytes memory assetData) | ||||
|     { | ||||
|         assetData = abi.encodeWithSelector(ERC20_PROXY_ID, tokenAddress); | ||||
|         assetData = abi.encodeWithSelector(IAssetData(address(0)).ERC20Token.selector, tokenAddress); | ||||
|         return assetData; | ||||
|     } | ||||
|  | ||||
| @@ -346,7 +343,7 @@ contract LibAssetData is | ||||
|         assetProxyId = assetData.readBytes4(0); | ||||
|  | ||||
|         require( | ||||
|             assetProxyId == ERC20_PROXY_ID, | ||||
|             assetProxyId == IAssetData(address(0)).ERC20Token.selector, | ||||
|             "WRONG_PROXY_ID" | ||||
|         ); | ||||
|  | ||||
| @@ -364,7 +361,7 @@ contract LibAssetData is | ||||
|         returns (bytes memory assetData) | ||||
|     { | ||||
|         assetData = abi.encodeWithSelector( | ||||
|             ERC721_PROXY_ID, | ||||
|             IAssetData(address(0)).ERC721Token.selector, | ||||
|             tokenAddress, | ||||
|             tokenId | ||||
|         ); | ||||
| @@ -388,7 +385,7 @@ contract LibAssetData is | ||||
|         assetProxyId = assetData.readBytes4(0); | ||||
|  | ||||
|         require( | ||||
|             assetProxyId == ERC721_PROXY_ID, | ||||
|             assetProxyId == IAssetData(address(0)).ERC721Token.selector, | ||||
|             "WRONG_PROXY_ID" | ||||
|         ); | ||||
|  | ||||
| @@ -414,7 +411,7 @@ contract LibAssetData is | ||||
|         returns (bytes memory assetData) | ||||
|     { | ||||
|         assetData = abi.encodeWithSelector( | ||||
|             ERC1155_PROXY_ID, | ||||
|             IAssetData(address(0)).ERC1155Assets.selector, | ||||
|             tokenAddress, | ||||
|             tokenIds, | ||||
|             tokenValues, | ||||
| @@ -446,7 +443,7 @@ contract LibAssetData is | ||||
|         assetProxyId = assetData.readBytes4(0); | ||||
|  | ||||
|         require( | ||||
|             assetProxyId == ERC1155_PROXY_ID, | ||||
|             assetProxyId == IAssetData(address(0)).ERC1155Assets.selector, | ||||
|             "WRONG_PROXY_ID" | ||||
|         ); | ||||
|  | ||||
| @@ -482,7 +479,7 @@ contract LibAssetData is | ||||
|         returns (bytes memory assetData) | ||||
|     { | ||||
|         assetData = abi.encodeWithSelector( | ||||
|             MULTI_ASSET_PROXY_ID, | ||||
|             IAssetData(address(0)).MultiAsset.selector, | ||||
|             amounts, | ||||
|             nestedAssetData | ||||
|         ); | ||||
| @@ -507,7 +504,7 @@ contract LibAssetData is | ||||
|         assetProxyId = assetData.readBytes4(0); | ||||
|  | ||||
|         require( | ||||
|             assetProxyId == MULTI_ASSET_PROXY_ID, | ||||
|             assetProxyId == IAssetData(address(0)).MultiAsset.selector, | ||||
|             "WRONG_PROXY_ID" | ||||
|         ); | ||||
|  | ||||
| @@ -518,24 +515,4 @@ contract LibAssetData is | ||||
|         ); | ||||
|         // solhint-enable indent | ||||
|     } | ||||
|  | ||||
|     /// @dev Calls `asset.ownerOf(tokenId)`, but returns a null owner instead of reverting on an unowned asset. | ||||
|     /// @param tokenAddress Address of ERC721 asset. | ||||
|     /// @param tokenId The identifier for the specific NFT. | ||||
|     /// @return Owner of tokenId or null address if unowned. | ||||
|     function getERC721TokenOwner(address tokenAddress, uint256 tokenId) | ||||
|         public | ||||
|         view | ||||
|         returns (address ownerAddress) | ||||
|     { | ||||
|         bytes memory ownerOfCalldata = abi.encodeWithSelector( | ||||
|             _ERC721_OWNER_OF_SELECTOR, | ||||
|             tokenId | ||||
|         ); | ||||
|  | ||||
|         (bool success, bytes memory returnData) = tokenAddress.staticcall(ownerOfCalldata); | ||||
|  | ||||
|         ownerAddress = (success && returnData.length == 32) ? returnData.readAddress(12) : address(0); | ||||
|         return ownerAddress; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -19,14 +19,13 @@ | ||||
| pragma solidity ^0.5.5; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "@0x/contracts-exchange-libs/contracts/src/LibExchangeSelectors.sol"; | ||||
| import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol"; | ||||
| import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; | ||||
| import "@0x/contracts-utils/contracts/src/LibBytes.sol"; | ||||
|  | ||||
|  | ||||
| contract LibTransactionDecoder is | ||||
|     LibExchangeSelectors | ||||
| { | ||||
| contract LibTransactionDecoder { | ||||
|  | ||||
|     using LibBytes for bytes; | ||||
|  | ||||
|     /// @dev Decodes the call data for an Exchange contract method call. | ||||
| @@ -47,72 +46,68 @@ contract LibTransactionDecoder is | ||||
|     { | ||||
|         bytes4 functionSelector = transactionData.readBytes4(0); | ||||
|  | ||||
|         if (functionSelector == BATCH_CANCEL_ORDERS_SELECTOR) { | ||||
|         if (functionSelector == IExchange(address(0)).batchCancelOrders.selector) { | ||||
|             functionName = "batchCancelOrders"; | ||||
|         } else if (functionSelector == BATCH_FILL_ORDERS_SELECTOR) { | ||||
|         } else if (functionSelector == IExchange(address(0)).batchFillOrders.selector) { | ||||
|             functionName = "batchFillOrders"; | ||||
|         } else if (functionSelector == BATCH_FILL_ORDERS_NO_THROW_SELECTOR) { | ||||
|         } else if (functionSelector == IExchange(address(0)).batchFillOrdersNoThrow.selector) { | ||||
|             functionName = "batchFillOrdersNoThrow"; | ||||
|         } else if (functionSelector == BATCH_FILL_OR_KILL_ORDERS_SELECTOR) { | ||||
|         } else if (functionSelector == IExchange(address(0)).batchFillOrKillOrders.selector) { | ||||
|             functionName = "batchFillOrKillOrders"; | ||||
|         } else if (functionSelector == CANCEL_ORDER_SELECTOR) { | ||||
|         } else if (functionSelector == IExchange(address(0)).cancelOrder.selector) { | ||||
|             functionName = "cancelOrder"; | ||||
|         } else if (functionSelector == FILL_ORDER_SELECTOR) { | ||||
|         } else if (functionSelector == IExchange(address(0)).fillOrder.selector) { | ||||
|             functionName = "fillOrder"; | ||||
|         } else if (functionSelector == FILL_ORDER_NO_THROW_SELECTOR) { | ||||
|             functionName = "fillOrderNoThrow"; | ||||
|         } else if (functionSelector == FILL_OR_KILL_ORDER_SELECTOR) { | ||||
|         } else if (functionSelector == IExchange(address(0)).fillOrKillOrder.selector) { | ||||
|             functionName = "fillOrKillOrder"; | ||||
|         } else if (functionSelector == MARKET_BUY_ORDERS_SELECTOR) { | ||||
|             functionName = "marketBuyOrders"; | ||||
|         } else if (functionSelector == MARKET_BUY_ORDERS_NO_THROW_SELECTOR) { | ||||
|         } else if (functionSelector == IExchange(address(0)).marketBuyOrdersNoThrow.selector) { | ||||
|             functionName = "marketBuyOrdersNoThrow"; | ||||
|         } else if (functionSelector == MARKET_SELL_ORDERS_SELECTOR) { | ||||
|             functionName = "marketSellOrders"; | ||||
|         } else if (functionSelector == MARKET_SELL_ORDERS_NO_THROW_SELECTOR) { | ||||
|         } else if (functionSelector == IExchange(address(0)).marketSellOrdersNoThrow.selector) { | ||||
|             functionName = "marketSellOrdersNoThrow"; | ||||
|         } else if (functionSelector == MATCH_ORDERS_SELECTOR) { | ||||
|         } else if (functionSelector == IExchange(address(0)).marketBuyOrdersFillOrKill.selector) { | ||||
|             functionName = "marketBuyOrdersFillOrKill"; | ||||
|         } else if (functionSelector == IExchange(address(0)).marketSellOrdersFillOrKill.selector) { | ||||
|             functionName = "marketSellOrdersFillOrKill"; | ||||
|         } else if (functionSelector == IExchange(address(0)).matchOrders.selector) { | ||||
|             functionName = "matchOrders"; | ||||
|         } else if ( | ||||
|             functionSelector == CANCEL_ORDERS_UP_TO_SELECTOR || | ||||
|             functionSelector == EXECUTE_TRANSACTION_SELECTOR | ||||
|             // TODO: add new noThrow cancel functions when https://github.com/0xProject/ZEIPs/issues/35 is merged. | ||||
|             functionSelector == IExchange(address(0)).cancelOrdersUpTo.selector || | ||||
|             functionSelector == IExchange(address(0)).executeTransaction.selector | ||||
|         ) { | ||||
|             revert("UNIMPLEMENTED"); | ||||
|         } else { | ||||
|             revert("UNKNOWN_FUNCTION_SELECTOR"); | ||||
|         } | ||||
|  | ||||
|         if (functionSelector == BATCH_CANCEL_ORDERS_SELECTOR) { | ||||
|         if (functionSelector == IExchange(address(0)).batchCancelOrders.selector) { | ||||
|             // solhint-disable-next-line indent | ||||
|             orders = abi.decode(transactionData.slice(4, transactionData.length), (LibOrder.Order[])); | ||||
|             takerAssetFillAmounts = new uint256[](0); | ||||
|             signatures = new bytes[](0); | ||||
|         } else if ( | ||||
|             functionSelector == BATCH_FILL_OR_KILL_ORDERS_SELECTOR || | ||||
|             functionSelector == BATCH_FILL_ORDERS_NO_THROW_SELECTOR || | ||||
|             functionSelector == BATCH_FILL_ORDERS_SELECTOR | ||||
|             functionSelector == IExchange(address(0)).batchFillOrKillOrders.selector || | ||||
|             functionSelector == IExchange(address(0)).batchFillOrders.selector || | ||||
|             functionSelector == IExchange(address(0)).batchFillOrdersNoThrow.selector | ||||
|         ) { | ||||
|             (orders, takerAssetFillAmounts, signatures) = _makeReturnValuesForBatchFill(transactionData); | ||||
|         } else if (functionSelector == CANCEL_ORDER_SELECTOR) { | ||||
|         } else if (functionSelector == IExchange(address(0)).cancelOrder.selector) { | ||||
|             orders = new LibOrder.Order[](1); | ||||
|             orders[0] = abi.decode(transactionData.slice(4, transactionData.length), (LibOrder.Order)); | ||||
|             takerAssetFillAmounts = new uint256[](0); | ||||
|             signatures = new bytes[](0); | ||||
|         } else if ( | ||||
|             functionSelector == FILL_OR_KILL_ORDER_SELECTOR || | ||||
|             functionSelector == FILL_ORDER_SELECTOR || | ||||
|             functionSelector == FILL_ORDER_NO_THROW_SELECTOR | ||||
|             functionSelector == IExchange(address(0)).fillOrKillOrder.selector || | ||||
|             functionSelector == IExchange(address(0)).fillOrder.selector | ||||
|         ) { | ||||
|             (orders, takerAssetFillAmounts, signatures) = _makeReturnValuesForSingleOrderFill(transactionData); | ||||
|         } else if ( | ||||
|             functionSelector == MARKET_BUY_ORDERS_SELECTOR || | ||||
|             functionSelector == MARKET_BUY_ORDERS_NO_THROW_SELECTOR || | ||||
|             functionSelector == MARKET_SELL_ORDERS_SELECTOR || | ||||
|             functionSelector == MARKET_SELL_ORDERS_NO_THROW_SELECTOR | ||||
|             functionSelector == IExchange(address(0)).marketBuyOrdersNoThrow.selector || | ||||
|             functionSelector == IExchange(address(0)).marketSellOrdersNoThrow.selector || | ||||
|             functionSelector == IExchange(address(0)).marketBuyOrdersFillOrKill.selector || | ||||
|             functionSelector == IExchange(address(0)).marketSellOrdersFillOrKill.selector | ||||
|         ) { | ||||
|             (orders, takerAssetFillAmounts, signatures) = _makeReturnValuesForMarketFill(transactionData); | ||||
|         } else if (functionSelector == MATCH_ORDERS_SELECTOR) { | ||||
|         } else if (functionSelector == IExchange(address(0)).matchOrders.selector) { | ||||
|             ( | ||||
|                 LibOrder.Order memory leftOrder, | ||||
|                 LibOrder.Order memory rightOrder, | ||||
|   | ||||
| @@ -0,0 +1,160 @@ | ||||
| /* | ||||
|  | ||||
|   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.5; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
|  | ||||
| import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol"; | ||||
| import "@0x/contracts-exchange/contracts/src/libs/LibExchangeRichErrorDecoder.sol"; | ||||
| import "@0x/contracts-exchange-libs/contracts/src/LibExchangeRichErrors.sol"; | ||||
| import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; | ||||
| import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol"; | ||||
| import "@0x/contracts-utils/contracts/src/LibBytes.sol"; | ||||
|  | ||||
|  | ||||
| contract OrderTransferSimulationUtils is | ||||
|     LibExchangeRichErrorDecoder | ||||
| { | ||||
|     using LibBytes for bytes; | ||||
|  | ||||
|     enum OrderTransferResults { | ||||
|         TakerAssetDataFailed,     // Transfer of takerAsset failed | ||||
|         MakerAssetDataFailed,     // Transfer of makerAsset failed | ||||
|         TakerFeeAssetDataFailed,  // Transfer of takerFeeAsset failed | ||||
|         MakerFeeAssetDataFailed,  // Transfer of makerFeeAsset failed | ||||
|         TransfersSuccessful       // All transfers in the order were successful | ||||
|     } | ||||
|  | ||||
|     // keccak256(abi.encodeWithSignature("Error(string)", "TRANSFERS_SUCCESSFUL")); | ||||
|     bytes32 constant internal _TRANSFERS_SUCCESSFUL_RESULT_HASH = 0xf43f26ea5a94b478394a975e856464913dc1a8a1ca70939d974aa7c238aa0ce0; | ||||
|  | ||||
|     // solhint-disable var-name-mixedcase | ||||
|     IExchange internal _EXCHANGE; | ||||
|     // solhint-enable var-name-mixedcase | ||||
|  | ||||
|     constructor (address _exchange) | ||||
|         public | ||||
|     { | ||||
|         _EXCHANGE = IExchange(_exchange); | ||||
|     } | ||||
|  | ||||
|     /// @dev Simulates all of the transfers within an order and returns the index of the first failed transfer. | ||||
|     /// @param order The order to simulate transfers for. | ||||
|     /// @param takerAddress The address of the taker that will fill the order. | ||||
|     /// @param takerAssetFillAmount The amount of takerAsset that the taker wished to fill. | ||||
|     /// @return The index of the first failed transfer (or 4 if all transfers are successful). | ||||
|     function getSimulatedOrderTransferResults( | ||||
|         LibOrder.Order memory order, | ||||
|         address takerAddress, | ||||
|         uint256 takerAssetFillAmount | ||||
|     ) | ||||
|         public | ||||
|         returns (OrderTransferResults orderTransferResults) | ||||
|     { | ||||
|         LibFillResults.FillResults memory fillResults = LibFillResults.calculateFillResults( | ||||
|             order, | ||||
|             takerAssetFillAmount, | ||||
|             _EXCHANGE.protocolFeeMultiplier(), | ||||
|             tx.gasprice | ||||
|         ); | ||||
|  | ||||
|         // Create input arrays | ||||
|         bytes[] memory assetData = new bytes[](4); | ||||
|         address[] memory fromAddresses = new address[](4); | ||||
|         address[] memory toAddresses = new address[](4); | ||||
|         uint256[] memory amounts = new uint256[](4); | ||||
|  | ||||
|         // Transfer `takerAsset` from taker to maker | ||||
|         assetData[0] = order.takerAssetData; | ||||
|         fromAddresses[0] = takerAddress; | ||||
|         toAddresses[0] = order.makerAddress; | ||||
|         amounts[0] = takerAssetFillAmount; | ||||
|  | ||||
|         // Transfer `makerAsset` from maker to taker | ||||
|         assetData[1] = order.makerAssetData; | ||||
|         fromAddresses[1] = order.makerAddress; | ||||
|         toAddresses[1] = takerAddress; | ||||
|         amounts[1] = fillResults.makerAssetFilledAmount; | ||||
|  | ||||
|         // Transfer `takerFeeAsset` from taker to feeRecipient | ||||
|         assetData[2] = order.takerFeeAssetData; | ||||
|         fromAddresses[2] = takerAddress; | ||||
|         toAddresses[2] = order.feeRecipientAddress; | ||||
|         amounts[2] = fillResults.takerFeePaid; | ||||
|  | ||||
|         // Transfer `makerFeeAsset` from maker to feeRecipient | ||||
|         assetData[3] = order.makerFeeAssetData; | ||||
|         fromAddresses[3] = order.makerAddress; | ||||
|         toAddresses[3] = order.feeRecipientAddress; | ||||
|         amounts[3] = fillResults.makerFeePaid; | ||||
|  | ||||
|         // Encode data for `simulateDispatchTransferFromCalls(assetData, fromAddresses, toAddresses, amounts)` | ||||
|         bytes memory simulateDispatchTransferFromCallsData = abi.encodeWithSelector( | ||||
|             IExchange(address(0)).simulateDispatchTransferFromCalls.selector, | ||||
|             assetData, | ||||
|             fromAddresses, | ||||
|             toAddresses, | ||||
|             amounts | ||||
|         ); | ||||
|  | ||||
|         // Perform call and catch revert | ||||
|         (, bytes memory returnData) = address(_EXCHANGE).call(simulateDispatchTransferFromCallsData); | ||||
|  | ||||
|         bytes4 selector = returnData.readBytes4(0); | ||||
|         if (selector == LibExchangeRichErrors.AssetProxyDispatchErrorSelector()) { | ||||
|             // Decode AssetProxyDispatchError and return index of failed transfer | ||||
|             (, bytes32 failedTransferIndex,) = decodeAssetProxyDispatchError(returnData); | ||||
|             return OrderTransferResults(uint8(uint256(failedTransferIndex))); | ||||
|         } else if (selector == LibExchangeRichErrors.AssetProxyTransferErrorSelector()) { | ||||
|             // Decode AssetProxyTransferError and return index of failed transfer | ||||
|             (bytes32 failedTransferIndex, ,) = decodeAssetProxyTransferError(returnData); | ||||
|             return OrderTransferResults(uint8(uint256(failedTransferIndex))); | ||||
|         } else if (keccak256(returnData) == _TRANSFERS_SUCCESSFUL_RESULT_HASH) { | ||||
|             // All transfers were successful | ||||
|             return OrderTransferResults.TransfersSuccessful; | ||||
|         } else { | ||||
|             revert("UNKNOWN_RETURN_DATA"); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// @dev Simulates all of the transfers for each given order and returns the indices of each first failed transfer. | ||||
|     /// @param orders Array of orders to individually simulate transfers for. | ||||
|     /// @param takerAddresses Array of addresses of takers that will fill each order. | ||||
|     /// @param takerAssetFillAmounts Array of amounts of takerAsset that will be filled for each order. | ||||
|     /// @return The indices of the first failed transfer (or 4 if all transfers are successful) for each order. | ||||
|     function getSimulatedOrdersTransferResults( | ||||
|         LibOrder.Order[] memory orders, | ||||
|         address[] memory takerAddresses, | ||||
|         uint256[] memory takerAssetFillAmounts | ||||
|     ) | ||||
|         public | ||||
|         returns (OrderTransferResults[] memory orderTransferResults) | ||||
|     { | ||||
|         uint256 length = orders.length; | ||||
|         orderTransferResults = new OrderTransferResults[](length); | ||||
|         for (uint256 i = 0; i != length; i++) { | ||||
|             orderTransferResults[i] = getSimulatedOrderTransferResults( | ||||
|                 orders[i], | ||||
|                 takerAddresses[i], | ||||
|                 takerAssetFillAmounts[i] | ||||
|             ); | ||||
|         } | ||||
|         return orderTransferResults; | ||||
|     } | ||||
| } | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|  | ||||
|   Copyright 2018 ZeroEx Intl. | ||||
|   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. | ||||
| @@ -23,25 +23,20 @@ import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol"; | ||||
| import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; | ||||
| import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol"; | ||||
| import "@0x/contracts-utils/contracts/src/LibBytes.sol"; | ||||
| import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; | ||||
| import "./LibAssetData.sol"; | ||||
|  | ||||
|  | ||||
| contract OrderValidationUtils is | ||||
|     LibAssetData, | ||||
|     LibMath | ||||
|     LibAssetData | ||||
| { | ||||
|     using LibBytes for bytes; | ||||
|     using LibSafeMath for uint256; | ||||
|  | ||||
|     // solhint-disable var-name-mixedcase | ||||
|     bytes internal _ZRX_ASSET_DATA; | ||||
|     // solhint-enable var-name-mixedcase | ||||
|  | ||||
|     constructor (address _exchange, bytes memory _zrxAssetData) | ||||
|     constructor (address _exchange) | ||||
|         public | ||||
|         LibAssetData(_exchange) | ||||
|     { | ||||
|         _ZRX_ASSET_DATA = _zrxAssetData; | ||||
|     } | ||||
|     {} | ||||
|  | ||||
|     /// @dev Fetches all order-relevant information needed to validate if the supplied order is fillable. | ||||
|     /// @param order The order structure. | ||||
| @@ -67,9 +62,8 @@ contract OrderValidationUtils is | ||||
|  | ||||
|         // Validate the maker's signature | ||||
|         address makerAddress = order.makerAddress; | ||||
|         isValidSignature = _EXCHANGE.isValidSignature( | ||||
|             orderInfo.orderHash, | ||||
|             makerAddress, | ||||
|         isValidSignature = _EXCHANGE.isValidOrderSignature( | ||||
|             order, | ||||
|             signature | ||||
|         ); | ||||
|  | ||||
| @@ -79,26 +73,22 @@ contract OrderValidationUtils is | ||||
|         // Assign to stack variables to reduce redundant mloads/sloads | ||||
|         uint256 takerAssetAmount = order.takerAssetAmount; | ||||
|         uint256 makerFee = order.makerFee; | ||||
|         bytes memory zrxAssetData = _ZRX_ASSET_DATA; | ||||
|      | ||||
|  | ||||
|         // Get the amount of `takerAsset` that is transferable to maker given the transferability of `makerAsset`, `makerFeeAsset`, | ||||
|         // and the total amounts specified in the order | ||||
|         uint256 transferableTakerAssetAmount; | ||||
|         if (order.makerAssetData.equals(zrxAssetData)) { | ||||
|         if (order.makerAssetData.equals(order.makerFeeAssetData)) { | ||||
|             // If `makerAsset` equals `makerFeeAsset`, the % that can be filled is | ||||
|             // transferableMakerAssetAmount / (makerAssetAmount + makerFee) | ||||
|             transferableTakerAssetAmount = getPartialAmountFloor( | ||||
|             transferableTakerAssetAmount = LibMath.getPartialAmountFloor( | ||||
|                 transferableMakerAssetAmount, | ||||
|                 safeAdd(order.makerAssetAmount, makerFee), | ||||
|                 order.makerAssetAmount.safeAdd(makerFee), | ||||
|                 takerAssetAmount | ||||
|             ); | ||||
|         } else { | ||||
|             // Get the transferable amount of the `makerFeeAsset` | ||||
|             uint256 transferableMakerFeeAssetAmount = getTransferableAssetAmount(makerAddress, zrxAssetData); | ||||
|  | ||||
|             // If `makerFee` is 0, the % that can be filled is (transferableMakerAssetAmount / makerAssetAmount) | ||||
|             if (makerFee == 0) { | ||||
|                 transferableTakerAssetAmount = getPartialAmountFloor( | ||||
|                 transferableTakerAssetAmount = LibMath.getPartialAmountFloor( | ||||
|                     transferableMakerAssetAmount, | ||||
|                     order.makerAssetAmount, | ||||
|                     takerAssetAmount | ||||
| @@ -107,23 +97,26 @@ contract OrderValidationUtils is | ||||
|             // If `makerAsset` does not equal `makerFeeAsset`, the % that can be filled is the lower of | ||||
|             // (transferableMakerAssetAmount / makerAssetAmount) and (transferableMakerAssetFeeAmount / makerFee) | ||||
|             } else { | ||||
|                 uint256 transferableMakerToTakerAmount = getPartialAmountFloor( | ||||
|                 // Get the transferable amount of the `makerFeeAsset` | ||||
|                 uint256 transferableMakerFeeAssetAmount = getTransferableAssetAmount(makerAddress, order.makerFeeAssetData); | ||||
|  | ||||
|                 uint256 transferableMakerToTakerAmount = LibMath.getPartialAmountFloor( | ||||
|                     transferableMakerAssetAmount, | ||||
|                     order.makerAssetAmount, | ||||
|                     takerAssetAmount | ||||
|                 ); | ||||
|                 uint256 transferableMakerFeeToTakerAmount = getPartialAmountFloor( | ||||
|                 uint256 transferableMakerFeeToTakerAmount = LibMath.getPartialAmountFloor( | ||||
|                     transferableMakerFeeAssetAmount, | ||||
|                     makerFee, | ||||
|                     takerAssetAmount | ||||
|                 ); | ||||
|                 transferableTakerAssetAmount = min256(transferableMakerToTakerAmount, transferableMakerFeeToTakerAmount); | ||||
|                 transferableTakerAssetAmount = LibSafeMath.min256(transferableMakerToTakerAmount, transferableMakerFeeToTakerAmount); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // `fillableTakerAssetAmount` is the lower of the order's remaining `takerAssetAmount` and the `transferableTakerAssetAmount` | ||||
|         fillableTakerAssetAmount = min256( | ||||
|             safeSub(takerAssetAmount, orderInfo.orderTakerAssetFilledAmount), | ||||
|         fillableTakerAssetAmount = LibSafeMath.min256( | ||||
|             takerAssetAmount.safeSub(orderInfo.orderTakerAssetFilledAmount), | ||||
|             transferableTakerAssetAmount | ||||
|         ); | ||||
|  | ||||
| @@ -170,7 +163,7 @@ contract OrderValidationUtils is | ||||
|     /// @return The amount of the asset tranferable by the owner. | ||||
|     /// NOTE: If the `assetData` encodes data for multiple assets, the `transferableAssetAmount` | ||||
|     /// will represent the amount of times the entire `assetData` can be transferred. To calculate | ||||
|     /// the total individual transferable amounts, this scaled `transferableAmount` must be multiplied by  | ||||
|     /// the total individual transferable amounts, this scaled `transferableAmount` must be multiplied by | ||||
|     /// the individual asset amounts located within the `assetData`. | ||||
|     function getTransferableAssetAmount(address ownerAddress, bytes memory assetData) | ||||
|         public | ||||
| @@ -178,7 +171,7 @@ contract OrderValidationUtils is | ||||
|         returns (uint256 transferableAssetAmount) | ||||
|     { | ||||
|         (uint256 balance, uint256 allowance) = getBalanceAndAssetProxyAllowance(ownerAddress, assetData); | ||||
|         transferableAssetAmount = min256(balance, allowance); | ||||
|         transferableAssetAmount = LibSafeMath.min256(balance, allowance); | ||||
|         return transferableAssetAmount; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "name": "@0x/contracts-dev-utils", | ||||
|     "version": "0.0.9", | ||||
|     "version": "0.1.0-beta.0", | ||||
|     "engines": { | ||||
|         "node": ">=6.12" | ||||
|     }, | ||||
| @@ -12,13 +12,13 @@ | ||||
|     "scripts": { | ||||
|         "build": "yarn pre_build && tsc -b", | ||||
|         "build:ci": "yarn build", | ||||
|         "pre_build": "run-s compile generate_contract_wrappers", | ||||
|         "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": "mocha --require source-map-support/register --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit", | ||||
|         "run_mocha": "UNLIMITED_CONTRACT_SIZE=true 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", | ||||
| @@ -31,10 +31,12 @@ | ||||
|         "coverage:report:lcov": "istanbul report lcov", | ||||
|         "test:circleci": "yarn test", | ||||
|         "contracts:gen": "contracts-gen", | ||||
|         "lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol" | ||||
|         "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", | ||||
|         "compile:truffle": "truffle compile" | ||||
|     }, | ||||
|     "config": { | ||||
|         "abis": "./generated-artifacts/@(DevUtils|LibAssetData|LibTransactionDecoder|EthBalanceChecker).json", | ||||
|         "abis": "./generated-artifacts/@(DevUtils|EthBalanceChecker|LibAssetData|LibTransactionDecoder|OrderTransferSimulationUtils|OrderValidationUtils).json", | ||||
|         "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually." | ||||
|     }, | ||||
|     "repository": { | ||||
| @@ -47,11 +49,11 @@ | ||||
|     }, | ||||
|     "homepage": "https://github.com/0xProject/0x-monorepo/contracts/dev-utils/README.md", | ||||
|     "devDependencies": { | ||||
|         "@0x/abi-gen": "^4.2.0", | ||||
|         "@0x/contracts-gen": "^1.0.14", | ||||
|         "@0x/contracts-test-utils": "^3.1.15", | ||||
|         "@0x/dev-utils": "^2.3.2", | ||||
|         "@0x/sol-compiler": "^3.1.14", | ||||
|         "@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", | ||||
| @@ -65,24 +67,25 @@ | ||||
|         "npm-run-all": "^4.1.2", | ||||
|         "shx": "^0.2.2", | ||||
|         "solhint": "^1.4.1", | ||||
|         "truffle": "^5.0.32", | ||||
|         "tslint": "5.11.0", | ||||
|         "typescript": "3.0.1" | ||||
|     }, | ||||
|     "dependencies": { | ||||
|         "@0x/base-contract": "^5.3.3", | ||||
|         "@0x/contracts-asset-proxy": "^2.2.7", | ||||
|         "@0x/contracts-erc1155": "^1.1.14", | ||||
|         "@0x/contracts-erc20": "^2.2.13", | ||||
|         "@0x/contracts-erc721": "^2.1.14", | ||||
|         "@0x/contracts-exchange": "^2.1.13", | ||||
|         "@0x/contracts-exchange-libs": "^3.0.7", | ||||
|         "@0x/contracts-utils": "^3.2.3", | ||||
|         "@0x/order-utils": "^8.3.1", | ||||
|         "@0x/types": "^2.4.2", | ||||
|         "@0x/typescript-typings": "^4.2.5", | ||||
|         "@0x/utils": "^4.5.1", | ||||
|         "@0x/web3-wrapper": "^6.0.12", | ||||
|         "ethereum-types": "^2.1.5", | ||||
|         "@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" | ||||
|     }, | ||||
|     "publishConfig": { | ||||
|   | ||||
| @@ -6,10 +6,16 @@ | ||||
| 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, | ||||
|     LibTransactionDecoder: LibTransactionDecoder as ContractArtifact, | ||||
|     EthBalanceChecker: EthBalanceChecker as ContractArtifact, | ||||
|     LibAssetData: LibAssetData as ContractArtifact, | ||||
|     LibTransactionDecoder: LibTransactionDecoder as ContractArtifact, | ||||
|     OrderTransferSimulationUtils: OrderTransferSimulationUtils as ContractArtifact, | ||||
|     OrderValidationUtils: OrderValidationUtils as ContractArtifact, | ||||
| }; | ||||
|   | ||||
| @@ -4,5 +4,8 @@ | ||||
|  * ----------------------------------------------------------------------------- | ||||
|  */ | ||||
| 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'; | ||||
|   | ||||
| @@ -22,7 +22,7 @@ import { chaiSetup, constants, LogDecoder, provider, txDefaults, web3Wrapper } f | ||||
| import { BlockchainLifecycle } from '@0x/dev-utils'; | ||||
| import { assetDataUtils } from '@0x/order-utils'; | ||||
| import { AssetProxyId } from '@0x/types'; | ||||
| import { BigNumber } from '@0x/utils'; | ||||
| import { BigNumber, providerUtils } from '@0x/utils'; | ||||
| import * as ethUtil from 'ethereumjs-util'; | ||||
|  | ||||
| import { artifacts, LibAssetDataContract } from '../src'; | ||||
| @@ -87,13 +87,13 @@ describe('LibAssetData', () => { | ||||
|  | ||||
|     before(async () => { | ||||
|         await blockchainLifecycle.startAsync(); | ||||
|  | ||||
|         const chainId = await providerUtils.getChainIdAsync(provider); | ||||
|         exchange = await ExchangeContract.deployFrom0xArtifactAsync( | ||||
|             exchangeArtifacts.Exchange, | ||||
|             provider, | ||||
|             txDefaults, | ||||
|             artifacts, | ||||
|             constants.NULL_BYTES, | ||||
|             {}, | ||||
|             new BigNumber(chainId), | ||||
|         ); | ||||
|  | ||||
|         erc20Proxy = await ERC20ProxyContract.deployFrom0xArtifactAsync( | ||||
| @@ -476,20 +476,6 @@ describe('LibAssetData', () => { | ||||
|         }); | ||||
|     }); | ||||
|  | ||||
|     describe('getERC721TokenOwner', async () => { | ||||
|         it('should return the null address when tokenId is not owned', async () => { | ||||
|             const nonexistentTokenId = new BigNumber(1234567890); | ||||
|             expect( | ||||
|                 await libAssetData.getERC721TokenOwner.callAsync(erc721Token.address, nonexistentTokenId), | ||||
|             ).to.be.equal(constants.NULL_ADDRESS); | ||||
|         }); | ||||
|         it('should return the owner address when tokenId is owned', async () => { | ||||
|             expect( | ||||
|                 await libAssetData.getERC721TokenOwner.callAsync(erc721Token.address, firstERC721TokenId), | ||||
|             ).to.be.equal(tokenOwnerAddress); | ||||
|         }); | ||||
|     }); | ||||
|  | ||||
|     describe('getBalanceAndAllowance', () => { | ||||
|         it('should query balance and allowance together, from asset data', async () => { | ||||
|             const allowance = new BigNumber(1); | ||||
|   | ||||
| @@ -23,6 +23,8 @@ const order = { | ||||
|     salt: new BigNumber('66097384406870180066678463045003379626790660770396923976862707230261946348951'), | ||||
|     makerAssetData: '0xf47261b000000000000000000000000034d402f14d58e001d8efbe6585051bf9706aa064', | ||||
|     takerAssetData: '0xf47261b000000000000000000000000025b8fe1de9daf8ba351890744ff28cf7dfa8f5e3', | ||||
|     makerFeeAssetData: '0xf47261b000000000000000000000000034d402f14d58e001d8efbe6585051bf9706aa064', | ||||
|     takerFeeAssetData: '0xf47261b000000000000000000000000025b8fe1de9daf8ba351890744ff28cf7dfa8f5e3', | ||||
| }; | ||||
| const takerAssetFillAmount = new BigNumber('100000000000000000000'); | ||||
| const signature = | ||||
| @@ -80,7 +82,7 @@ describe('LibTransactionDecoder', () => { | ||||
|         ]); | ||||
|     }); | ||||
|  | ||||
|     for (const func of ['fillOrder', 'fillOrderNoThrow', 'fillOrKillOrder']) { | ||||
|     for (const func of ['fillOrder', 'fillOrKillOrder']) { | ||||
|         const input = (exchangeInterface as any)[func].getABIEncodedTransactionData( | ||||
|             order, | ||||
|             takerAssetFillAmount, | ||||
| @@ -96,7 +98,12 @@ describe('LibTransactionDecoder', () => { | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     for (const func of ['marketBuyOrders', 'marketBuyOrdersNoThrow', 'marketSellOrders', 'marketSellOrdersNoThrow']) { | ||||
|     for (const func of [ | ||||
|         'marketBuyOrdersNoThrow', | ||||
|         'marketSellOrdersNoThrow', | ||||
|         'marketBuyOrdersFillOrKill', | ||||
|         'marketSellOrdersFillOrKill', | ||||
|     ]) { | ||||
|         const input = (exchangeInterface as any)[func].getABIEncodedTransactionData( | ||||
|             [order, order], | ||||
|             takerAssetFillAmount, | ||||
| @@ -123,6 +130,8 @@ describe('LibTransactionDecoder', () => { | ||||
|             takerAssetAmount: order.makerAssetAmount, | ||||
|             makerFee: order.takerFee, | ||||
|             takerFee: order.makerFee, | ||||
|             makerFeeAssetData: order.takerFeeAssetData, | ||||
|             takerFeeAssetData: order.makerFeeAssetData, | ||||
|         }; | ||||
|         const input = exchangeInterface.matchOrders.getABIEncodedTransactionData( | ||||
|             order, | ||||
|   | ||||
| @@ -20,8 +20,8 @@ import { | ||||
| } from '@0x/contracts-test-utils'; | ||||
| import { BlockchainLifecycle } from '@0x/dev-utils'; | ||||
| import { assetDataUtils, orderHashUtils } from '@0x/order-utils'; | ||||
| import { SignedOrder } from '@0x/types'; | ||||
| import { BigNumber } from '@0x/utils'; | ||||
| import { OrderTransferResults, SignedOrder } from '@0x/types'; | ||||
| import { BigNumber, providerUtils } from '@0x/utils'; | ||||
| import * as chai from 'chai'; | ||||
|  | ||||
| import { artifacts, DevUtilsContract } from '../src'; | ||||
| @@ -30,18 +30,18 @@ chaiSetup.configure(); | ||||
| const expect = chai.expect; | ||||
| const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); | ||||
|  | ||||
| describe('OrderValidationUtils', () => { | ||||
| describe('OrderValidationUtils/OrderTransferSimulatorUtils', () => { | ||||
|     let makerAddress: string; | ||||
|     let takerAddress: string; | ||||
|     let owner: string; | ||||
|     let erc20AssetData: string; | ||||
|     let erc20AssetData2: string; | ||||
|     let erc721AssetData: string; | ||||
|     let zrxAssetData: string; | ||||
|     let feeAssetData: string; | ||||
|  | ||||
|     let erc20Token: DummyERC20TokenContract; | ||||
|     let erc20Token2: DummyERC20TokenContract; | ||||
|     let zrxToken: DummyERC20TokenContract; | ||||
|     let feeErc20Token: DummyERC20TokenContract; | ||||
|     let erc721Token: DummyERC721TokenContract; | ||||
|     let exchange: ExchangeContract; | ||||
|     let devUtils: DevUtilsContract; | ||||
| @@ -64,12 +64,13 @@ describe('OrderValidationUtils', () => { | ||||
|     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, zrxToken, erc20Token2] = await erc20Wrapper.deployDummyTokensAsync( | ||||
|         [erc20Token, erc20Token2, feeErc20Token] = await erc20Wrapper.deployDummyTokensAsync( | ||||
|             numDummyErc20ToDeploy, | ||||
|             constants.DUMMY_TOKEN_DECIMALS, | ||||
|         ); | ||||
| @@ -78,13 +79,13 @@ describe('OrderValidationUtils', () => { | ||||
|         [erc721Token] = await erc721Wrapper.deployDummyTokensAsync(); | ||||
|         erc721Proxy = await erc721Wrapper.deployProxyAsync(); | ||||
|  | ||||
|         zrxAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address); | ||||
|         feeAssetData = assetDataUtils.encodeERC20AssetData(feeErc20Token.address); | ||||
|         exchange = await ExchangeContract.deployFrom0xArtifactAsync( | ||||
|             exchangeArtifacts.Exchange, | ||||
|             provider, | ||||
|             txDefaults, | ||||
|             artifacts, | ||||
|             zrxAssetData, | ||||
|             {}, | ||||
|             new BigNumber(chainId), | ||||
|         ); | ||||
|  | ||||
|         multiAssetProxy = await MultiAssetProxyContract.deployFrom0xArtifactAsync( | ||||
| @@ -93,7 +94,7 @@ describe('OrderValidationUtils', () => { | ||||
|             txDefaults, | ||||
|             artifacts, | ||||
|         ); | ||||
|         const exchangeWrapper = new ExchangeWrapper(exchange, provider); | ||||
|         const exchangeWrapper = new ExchangeWrapper(exchange); | ||||
|         await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner); | ||||
|         await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.address, owner); | ||||
|         await exchangeWrapper.registerAssetProxyAsync(multiAssetProxy.address, owner); | ||||
| @@ -106,7 +107,6 @@ describe('OrderValidationUtils', () => { | ||||
|             txDefaults, | ||||
|             artifacts, | ||||
|             exchange.address, | ||||
|             zrxAssetData, | ||||
|         ); | ||||
|  | ||||
|         erc20AssetData = assetDataUtils.encodeERC20AssetData(erc20Token.address); | ||||
| @@ -114,11 +114,14 @@ describe('OrderValidationUtils', () => { | ||||
|         erc721AssetData = assetDataUtils.encodeERC721AssetData(erc721Token.address, tokenId); | ||||
|         const defaultOrderParams = { | ||||
|             ...constants.STATIC_ORDER_PARAMS, | ||||
|             exchangeAddress: exchange.address, | ||||
|             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); | ||||
| @@ -245,11 +248,11 @@ describe('OrderValidationUtils', () => { | ||||
|                 from: makerAddress, | ||||
|             }); | ||||
|             const divisor = 4; | ||||
|             await zrxToken.setBalance.awaitTransactionSuccessAsync( | ||||
|             await feeErc20Token.setBalance.awaitTransactionSuccessAsync( | ||||
|                 makerAddress, | ||||
|                 signedOrder.makerFee.dividedToIntegerBy(divisor), | ||||
|             ); | ||||
|             await zrxToken.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerFee, { | ||||
|             await feeErc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerFee, { | ||||
|                 from: makerAddress, | ||||
|             }); | ||||
|             const [, fillableTakerAssetAmount] = await devUtils.getOrderRelevantState.callAsync( | ||||
| @@ -269,8 +272,8 @@ describe('OrderValidationUtils', () => { | ||||
|             await erc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerAssetAmount, { | ||||
|                 from: makerAddress, | ||||
|             }); | ||||
|             await zrxToken.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerFee); | ||||
|             await zrxToken.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerFee, { | ||||
|             await feeErc20Token.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerFee); | ||||
|             await feeErc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerFee, { | ||||
|                 from: makerAddress, | ||||
|             }); | ||||
|             const [, fillableTakerAssetAmount] = await devUtils.getOrderRelevantState.callAsync( | ||||
| @@ -291,8 +294,8 @@ describe('OrderValidationUtils', () => { | ||||
|             await erc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerAssetAmount, { | ||||
|                 from: makerAddress, | ||||
|             }); | ||||
|             await zrxToken.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerFee); | ||||
|             await zrxToken.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerFee, { | ||||
|             await feeErc20Token.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerFee); | ||||
|             await feeErc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerFee, { | ||||
|                 from: makerAddress, | ||||
|             }); | ||||
|             const divisor = 4; | ||||
| @@ -316,8 +319,8 @@ describe('OrderValidationUtils', () => { | ||||
|             ); | ||||
|         }); | ||||
|         it('should return a fillableTakerAssetAmount of 0 when non-fee balances/allowances are insufficient', async () => { | ||||
|             await zrxToken.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerFee); | ||||
|             await zrxToken.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerFee, { | ||||
|             await feeErc20Token.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerFee); | ||||
|             await feeErc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerFee, { | ||||
|                 from: makerAddress, | ||||
|             }); | ||||
|             const [, fillableTakerAssetAmount] = await devUtils.getOrderRelevantState.callAsync( | ||||
| @@ -331,8 +334,8 @@ describe('OrderValidationUtils', () => { | ||||
|             await erc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerAssetAmount, { | ||||
|                 from: makerAddress, | ||||
|             }); | ||||
|             await zrxToken.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerFee); | ||||
|             await zrxToken.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerFee, { | ||||
|             await feeErc20Token.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerFee); | ||||
|             await feeErc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerFee, { | ||||
|                 from: makerAddress, | ||||
|             }); | ||||
|             const [, fillableTakerAssetAmount] = await devUtils.getOrderRelevantState.callAsync( | ||||
| @@ -343,14 +346,14 @@ describe('OrderValidationUtils', () => { | ||||
|         }); | ||||
|         it('should return the correct fillableTakerAssetAmount when balances/allowances are partially sufficient and makerAsset=makerFeeAsset', async () => { | ||||
|             signedOrder = await orderFactory.newSignedOrderAsync({ | ||||
|                 makerAssetData: zrxAssetData, | ||||
|                 makerAssetData: feeAssetData, | ||||
|                 makerAssetAmount: new BigNumber(10), | ||||
|                 takerAssetAmount: new BigNumber(20), | ||||
|                 makerFee: new BigNumber(40), | ||||
|             }); | ||||
|             const transferableMakerAssetAmount = new BigNumber(10); | ||||
|             await zrxToken.setBalance.awaitTransactionSuccessAsync(makerAddress, transferableMakerAssetAmount); | ||||
|             await zrxToken.approve.awaitTransactionSuccessAsync(erc20Proxy.address, transferableMakerAssetAmount, { | ||||
|             await feeErc20Token.setBalance.awaitTransactionSuccessAsync(makerAddress, transferableMakerAssetAmount); | ||||
|             await feeErc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, transferableMakerAssetAmount, { | ||||
|                 from: makerAddress, | ||||
|             }); | ||||
|             const expectedFillableTakerAssetAmount = transferableMakerAssetAmount | ||||
| @@ -379,17 +382,17 @@ describe('OrderValidationUtils', () => { | ||||
|             await erc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerAssetAmount, { | ||||
|                 from: makerAddress, | ||||
|             }); | ||||
|             await zrxToken.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerFee); | ||||
|             await zrxToken.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerFee, { | ||||
|             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 zrxToken.setBalance.awaitTransactionSuccessAsync(takerAddress, signedOrder.takerFee); | ||||
|             await feeErc20Token.setBalance.awaitTransactionSuccessAsync(takerAddress, signedOrder.takerFee); | ||||
|  | ||||
|             await zrxToken.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.takerFee, { | ||||
|             await feeErc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.takerFee, { | ||||
|                 from: takerAddress, | ||||
|             }); | ||||
|             const takerAssetFillAmount = signedOrder.takerAssetAmount.dividedToIntegerBy(4); | ||||
| @@ -407,15 +410,38 @@ describe('OrderValidationUtils', () => { | ||||
|                 signedOrder.takerAssetAmount.minus(takerAssetFillAmount), | ||||
|             ); | ||||
|         }); | ||||
|     }); | ||||
|     describe('getOrderRelevantStates', async () => { | ||||
|         it('should return the correct information for multiple orders', async () => { | ||||
|         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, | ||||
|             }); | ||||
|             await zrxToken.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerFee); | ||||
|             await zrxToken.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerFee, { | ||||
|             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 }); | ||||
| @@ -441,5 +467,185 @@ describe('OrderValidationUtils', () => { | ||||
|             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 | ||||
|   | ||||
							
								
								
									
										96
									
								
								contracts/dev-utils/truffle-config.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								contracts/dev-utils/truffle-config.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,96 @@ | ||||
| /** | ||||
|  * Use this file to configure your truffle project. It's seeded with some | ||||
|  * common settings for different networks and features like migrations, | ||||
|  * compilation and testing. Uncomment the ones you need or modify | ||||
|  * them to suit your project as necessary. | ||||
|  * | ||||
|  * More information about configuration can be found at: | ||||
|  * | ||||
|  * truffleframework.com/docs/advanced/configuration | ||||
|  * | ||||
|  * To deploy via Infura you'll need a wallet provider (like truffle-hdwallet-provider) | ||||
|  * to sign your transactions before they're sent to a remote public node. Infura accounts | ||||
|  * are available for free at: infura.io/register. | ||||
|  * | ||||
|  * You'll also need a mnemonic - the twelve word phrase the wallet uses to generate | ||||
|  * public/private key pairs. If you're publishing your code to GitHub make sure you load this | ||||
|  * phrase from a file you've .gitignored so it doesn't accidentally become public. | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| // const HDWalletProvider = require('truffle-hdwallet-provider'); | ||||
| // const infuraKey = "fj4jll3k....."; | ||||
| // | ||||
| // const fs = require('fs'); | ||||
| // const mnemonic = fs.readFileSync(".secret").toString().trim(); | ||||
|  | ||||
| module.exports = { | ||||
|     /** | ||||
|      * Networks define how you connect to your ethereum client and let you set the | ||||
|      * defaults web3 uses to send transactions. If you don't specify one truffle | ||||
|      * will spin up a development blockchain for you on port 9545 when you | ||||
|      * run `develop` or `test`. You can ask a truffle command to use a specific | ||||
|      * network from the command line, e.g | ||||
|      * | ||||
|      * $ truffle test --network <network-name> | ||||
|      */ | ||||
|  | ||||
|     networks: { | ||||
|         // Useful for testing. The `development` name is special - truffle uses it by default | ||||
|         // if it's defined here and no other network is specified at the command line. | ||||
|         // You should run a client (like ganache-cli, geth or parity) in a separate terminal | ||||
|         // tab if you use this network and you must also set the `host`, `port` and `network_id` | ||||
|         // options below to some value. | ||||
|         // | ||||
|         // development: { | ||||
|         //  host: "127.0.0.1",     // Localhost (default: none) | ||||
|         //  port: 8545,            // Standard Ethereum port (default: none) | ||||
|         //  network_id: "*",       // Any network (default: none) | ||||
|         // }, | ||||
|         // Another network with more advanced options... | ||||
|         // advanced: { | ||||
|         // port: 8777,             // Custom port | ||||
|         // network_id: 1342,       // Custom network | ||||
|         // gas: 8500000,           // Gas sent with each transaction (default: ~6700000) | ||||
|         // gasPrice: 20000000000,  // 20 gwei (in wei) (default: 100 gwei) | ||||
|         // from: <address>,        // Account to send txs from (default: accounts[0]) | ||||
|         // websockets: true        // Enable EventEmitter interface for web3 (default: false) | ||||
|         // }, | ||||
|         // Useful for deploying to a public network. | ||||
|         // NB: It's important to wrap the provider as a function. | ||||
|         // ropsten: { | ||||
|         // provider: () => new HDWalletProvider(mnemonic, `https://ropsten.infura.io/v3/YOUR-PROJECT-ID`), | ||||
|         // network_id: 3,       // Ropsten's id | ||||
|         // gas: 5500000,        // Ropsten has a lower block limit than mainnet | ||||
|         // confirmations: 2,    // # of confs to wait between deployments. (default: 0) | ||||
|         // timeoutBlocks: 200,  // # of blocks before a deployment times out  (minimum/default: 50) | ||||
|         // skipDryRun: true     // Skip dry run before migrations? (default: false for public nets ) | ||||
|         // }, | ||||
|         // Useful for private networks | ||||
|         // private: { | ||||
|         // provider: () => new HDWalletProvider(mnemonic, `https://network.io`), | ||||
|         // network_id: 2111,   // This network is yours, in the cloud. | ||||
|         // production: true    // Treats this network as if it was a public net. (default: false) | ||||
|         // } | ||||
|     }, | ||||
|  | ||||
|     // Set default mocha options here, use special reporters etc. | ||||
|     mocha: { | ||||
|         // timeout: 100000 | ||||
|     }, | ||||
|  | ||||
|     // Configure your compilers | ||||
|     compilers: { | ||||
|         solc: { | ||||
|             version: '0.5.9', | ||||
|             settings: { | ||||
|                 evmVersion: 'constantinople', | ||||
|                 optimizer: { | ||||
|                     enabled: true, | ||||
|                     runs: 1000000, | ||||
|                     details: { yul: true, deduplicate: true, cse: true, constantOptimizer: true }, | ||||
|                 }, | ||||
|             }, | ||||
|         }, | ||||
|     }, | ||||
| }; | ||||
| @@ -4,9 +4,11 @@ | ||||
|     "include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"], | ||||
|     "files": [ | ||||
|         "generated-artifacts/DevUtils.json", | ||||
|         "generated-artifacts/EthBalanceChecker.json", | ||||
|         "generated-artifacts/LibAssetData.json", | ||||
|         "generated-artifacts/LibTransactionDecoder.json", | ||||
|         "generated-artifacts/EthBalanceChecker.json" | ||||
|         "generated-artifacts/OrderTransferSimulationUtils.json", | ||||
|         "generated-artifacts/OrderValidationUtils.json" | ||||
|     ], | ||||
|     "exclude": ["./deploy/solc/solc_bin"] | ||||
| } | ||||
|   | ||||
| @@ -1,4 +1,23 @@ | ||||
| [ | ||||
|     { | ||||
|         "version": "1.2.0-beta.0", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Add `mintKnownFungibleTokensAsync()`, `isNonFungibleItemAsync()`, `isFungibleItemAsync()`, `getOwnerOfAsync()`, `getBalanceAsync()` to `Erc1155Wrapper`.", | ||||
|                 "pr": 1819 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1570135330 | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1568744790, | ||||
|         "version": "1.1.15", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1567521715, | ||||
|         "version": "1.1.14", | ||||
|   | ||||
| @@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only. | ||||
|  | ||||
| CHANGELOG | ||||
|  | ||||
| ## v1.2.0-beta.0 - _October 3, 2019_ | ||||
|  | ||||
|     * Add `mintKnownFungibleTokensAsync()`, `isNonFungibleItemAsync()`, `isFungibleItemAsync()`, `getOwnerOfAsync()`, `getBalanceAsync()` to `Erc1155Wrapper`. (#1819) | ||||
|  | ||||
| ## v1.1.15 - _September 17, 2019_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v1.1.14 - _September 3, 2019_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|   | ||||
| @@ -1,10 +1,15 @@ | ||||
| { | ||||
|     "artifactsDir": "generated-artifacts", | ||||
|     "contractsDir": "contracts", | ||||
|     "artifactsDir": "./generated-artifacts", | ||||
|     "contractsDir": "./contracts", | ||||
|     "useDockerisedSolc": false, | ||||
|     "isOfflineMode": false, | ||||
|     "compilerSettings": { | ||||
|         "evmVersion": "constantinople", | ||||
|         "optimizer": { "enabled": true, "runs": 1000000 }, | ||||
|         "optimizer": { | ||||
|             "enabled": true, | ||||
|             "runs": 1000000, | ||||
|             "details": { "yul": true, "deduplicate": true, "cse": true, "constantOptimizer": true } | ||||
|         }, | ||||
|         "outputSelection": { | ||||
|             "*": { | ||||
|                 "*": [ | ||||
| @@ -17,15 +22,5 @@ | ||||
|                 ] | ||||
|             } | ||||
|         } | ||||
|     }, | ||||
|     "contracts": [ | ||||
|         "src/ERC1155.sol", | ||||
|         "src/ERC1155Mintable.sol", | ||||
|         "src/MixinNonFungibleToken.sol", | ||||
|         "src/interfaces/IERC1155.sol", | ||||
|         "src/interfaces/IERC1155Mintable.sol", | ||||
|         "src/interfaces/IERC1155Receiver.sol", | ||||
|         "src/mixins/MNonFungibleToken.sol", | ||||
|         "test/DummyERC1155Receiver.sol" | ||||
|     ] | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|  | ||||
|   Copyright 2018 ZeroEx Intl. | ||||
|   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. | ||||
| @@ -16,10 +16,10 @@ | ||||
|  | ||||
| */ | ||||
|  | ||||
| pragma solidity ^0.5.5; | ||||
| pragma solidity ^0.5.9; | ||||
|  | ||||
| import "@0x/contracts-utils/contracts/src/SafeMath.sol"; | ||||
| import "@0x/contracts-utils/contracts/src/Address.sol"; | ||||
| import "@0x/contracts-utils/contracts/src/LibAddress.sol"; | ||||
| import "./interfaces/IERC1155.sol"; | ||||
| import "./interfaces/IERC1155Receiver.sol"; | ||||
| import "./MixinNonFungibleToken.sol"; | ||||
| @@ -30,7 +30,7 @@ contract ERC1155 is | ||||
|     IERC1155, | ||||
|     MixinNonFungibleToken | ||||
| { | ||||
|     using Address for address; | ||||
|     using LibAddress for address; | ||||
|  | ||||
|     // 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] = _safeSub(balances[id][from], value); | ||||
|             balances[id][to] = _safeAdd(balances[id][to], 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] = _safeSub(balances[id][from], value); | ||||
|                 balances[id][to] = _safeAdd(balances[id][to], value); | ||||
|             } | ||||
|         } | ||||
|         emit TransferBatch(msg.sender, from, to, ids, values); | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| pragma solidity ^0.5.5; | ||||
| pragma solidity ^0.5.9; | ||||
|  | ||||
| import "@0x/contracts-utils/contracts/src/SafeMath.sol"; | ||||
| import "./ERC1155.sol"; | ||||
| @@ -114,7 +114,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] = _safeAdd(quantity, balances[id][dst]); | ||||
|  | ||||
|             // Emit the Transfer/Mint event. | ||||
|             // the 0x0 source address implies a mint | ||||
| @@ -172,7 +172,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 +194,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_] = _safeAdd(to.length, maxIndex[type_]); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|  | ||||
|   Copyright 2018 ZeroEx Intl. | ||||
|   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. | ||||
| @@ -16,14 +16,10 @@ | ||||
|  | ||||
| */ | ||||
|  | ||||
| pragma solidity ^0.5.5; | ||||
|  | ||||
| import "./mixins/MNonFungibleToken.sol"; | ||||
| pragma solidity ^0.5.9; | ||||
|  | ||||
|  | ||||
| contract MixinNonFungibleToken is | ||||
|     MNonFungibleToken | ||||
| { | ||||
| contract MixinNonFungibleToken { | ||||
|     /// Use a split bit implementation. | ||||
|     /// Store the type in the upper 128 bits.. | ||||
|     uint256 constant internal TYPE_MASK = uint256(uint128(~0)) << 128; | ||||
|   | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user