Compare commits
	
		
			1583 Commits
		
	
	
		
			@0x/contra
			...
			protocol@1
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 1776dbef44 | ||
|  | 089718df33 | ||
|  | 7500ac36de | ||
|  | f347f4392c | ||
|  | 10af74e616 | ||
|  | cfb2392ac7 | ||
|  | 5a2447bef3 | ||
|  | bf1b5c4257 | ||
|  | 10916205ab | ||
|  | 69f8fd39f7 | ||
|  | 0cc2cdd16e | ||
|  | d207a4267e | ||
|  | e846ed2f34 | ||
|  | b04455c36f | ||
|  | d06f6c8b4d | ||
|  | a689e98b0f | ||
|  | 6f72a8e8e3 | ||
|  | 422f83fc99 | ||
|  | b6597df84f | ||
|  | c9b1aac8a5 | ||
|  | 87f4189e93 | ||
|  | 390e1b8510 | ||
|  | 5645e87aca | ||
|  | 0daa988996 | ||
|  | b4d6f74d7b | ||
|  | 2163cb221b | ||
|  | 4575300016 | ||
|  | 82341c3b9d | ||
|  | f89c2d2fed | ||
|  | 09419a7909 | ||
|  | 1fa093be64 | ||
|  | 8e9f358a02 | ||
|  | 0a2e8fc224 | ||
|  | 5653ee8f86 | ||
|  | d180d5325d | ||
|  | d249042b47 | ||
|  | d3a6f79015 | ||
|  | 8c9dc96e5d | ||
|  | fc0edba46b | ||
|  | 37dc99181e | ||
|  | 6efb9f532b | ||
|  | 9b7d88e136 | ||
|  | e51e1f1674 | ||
|  | 036a263267 | ||
|  | 1fb44a55b4 | ||
|  | d738eede0e | ||
|  | a99c916100 | ||
|  | 2abb00b5e2 | ||
|  | ef723e6f36 | ||
|  | 1fc139886e | ||
|  | 2be10bc72f | ||
|  | abdc02f066 | ||
|  | b7ef5473cd | ||
|  | e43cdda22f | ||
|  | 416f2ec24c | ||
|  | 4f7fe66d74 | ||
|  | eb394383d8 | ||
|  | 92e681f21b | ||
|  | 3f65dd6049 | ||
|  | 4425c316a3 | ||
|  | 9058839645 | ||
|  | 46a7a2e620 | ||
|  | b35dccd43d | ||
|  | 08e0c2ebb9 | ||
|  | 8aa313a437 | ||
|  | 8e9699c340 | ||
|  | 939b708e63 | ||
|  | 1617e3fc44 | ||
|  | e0d705703d | ||
|  | 01a6d933ca | ||
|  | 9b9f0b91d7 | ||
|  | 0d0fef841d | ||
|  | 17adfbea32 | ||
|  | 80594622b2 | ||
|  | 0dba5a5a3a | ||
|  | 4dae8de1b6 | ||
|  | 0046bb26d8 | ||
|  | fe935f787c | ||
|  | 1b527ffcd8 | ||
|  | 9f5324d9c3 | ||
|  | 3647392a04 | ||
|  | 1d49662c58 | ||
|  | 6324b08b4d | ||
|  | fe73b63aaa | ||
|  | 192d0b17d9 | ||
|  | aa74d04083 | ||
|  | d586f5727d | ||
|  | 98fc79a085 | ||
|  | c12a10b96e | ||
|  | d3d4a08f91 | ||
|  | 9ce090c8cd | ||
|  | 980d60deb8 | ||
|  | d6d79e51e7 | ||
|  | 3ef5de93bb | ||
|  | ab7dc33ca4 | ||
|  | 14dcee5bb6 | ||
|  | 9856e78609 | ||
|  | 2801b066b3 | ||
|  | 5bc8b13fc3 | ||
|  | 36dba8f5be | ||
|  | ee2c069889 | ||
|  | 6ca14ed7b2 | ||
|  | a5babb9a34 | ||
|  | 661cc4669d | ||
|  | 553ba5c868 | ||
|  | d03d2f254d | ||
|  | feb91a04b0 | ||
|  | 4d63f33aba | ||
|  | b72b8b5ffd | ||
|  | f7cb7a0f51 | ||
|  | 9fcb28f5d8 | ||
|  | 982173471c | ||
|  | e77958425f | ||
|  | 6af4d71573 | ||
|  | ee985240fb | ||
|  | 2aadbda527 | ||
|  | 297c73abcc | ||
|  | 4c9e1b21ec | ||
|  | 41685d1545 | ||
|  | b9c25112ed | ||
|  | f0738fc122 | ||
|  | 42baf504b7 | ||
|  | 56038d122f | ||
|  | c4446b6c0e | ||
|  | eaed2958c3 | ||
|  | a045a3afb8 | ||
|  | 1cc59ab1ab | ||
|  | 2c6a714b71 | ||
|  | d8c97d6720 | ||
|  | d6bc702550 | ||
|  | 2838cb9420 | ||
|  | b10cfc50d3 | ||
|  | 2e6317b01e | ||
|  | 50e99e6eac | ||
|  | 8f2f4554eb | ||
|  | 67d9678a3a | ||
|  | f70341fb48 | ||
|  | 14cd24ea47 | ||
|  | 78328056d7 | ||
|  | 0045a60b0f | ||
|  | e4e71c76e1 | ||
|  | ca8127545f | ||
|  | 7b709089ce | ||
|  | 190f7e45f2 | ||
|  | 0dcc3a6fc3 | ||
|  | c2e8cae293 | ||
|  | 83da7caab4 | ||
|  | fd69a0c273 | ||
|  | 9b131199ad | ||
|  | f5c486050b | ||
|  | 1f41fe6a20 | ||
|  | 7f4080e0a2 | ||
|  | db76da58d7 | ||
|  | cf8fc0ff8e | ||
|  | 2d16f83e37 | ||
|  | 4057bdab91 | ||
|  | 1cd10f0ac9 | ||
|  | 68f87b2432 | ||
|  | 69bafc3bcd | ||
|  | 2c44b06b7b | ||
|  | 0233f00b4e | ||
|  | fedb53187d | ||
|  | 6774d2f588 | ||
|  | cf740b74f5 | ||
|  | 177c00463a | ||
|  | 49b0e32129 | ||
|  | 938fc94756 | ||
|  | 1561d91c2b | ||
|  | 9a28e51f51 | ||
|  | f55eaa867b | ||
|  | 6b2856424a | ||
|  | da757c4700 | ||
|  | 75e6654884 | ||
|  | 87308e7693 | ||
|  | d5eef93a76 | ||
|  | a7f23a982e | ||
|  | 9eadc5fc28 | ||
|  | 92ad1a612e | ||
|  | 09413c0e12 | ||
|  | 23788b41d5 | ||
|  | ccf999a495 | ||
|  | aa1016ee5f | ||
|  | 423ef57344 | ||
|  | c18149e82f | ||
|  | d14aebf724 | ||
|  | ba719a9631 | ||
|  | d36034d958 | ||
|  | 7750c57620 | ||
|  | 4d027e11d1 | ||
|  | 470e9a4697 | ||
|  | 7c51412e2f | ||
|  | b3d1f3cd10 | ||
|  | 389bb77439 | ||
|  | 4327885a00 | ||
|  | 0aef0afbbb | ||
|  | fa4c3a4f5f | ||
|  | 1d7c527c5c | ||
|  | cbe3135e4b | ||
|  | 955ad49711 | ||
|  | 8d6f6e76e0 | ||
|  | 9337115650 | ||
|  | fa45a44fe4 | ||
|  | c9c7ac8559 | ||
|  | c881723578 | ||
|  | c9c30d3a76 | ||
|  | 73dfdb5b69 | ||
|  | e638268f94 | ||
|  | 0bfd765481 | ||
|  | 1f12893735 | ||
|  | dd3d9337c4 | ||
|  | 904214f4a8 | ||
|  | 64c090c4b4 | ||
|  | e24474f152 | ||
|  | 29fa408256 | ||
|  | 1b94cc68af | ||
|  | f5b4bb3035 | ||
|  | afd880f28c | ||
|  | cd14cdd168 | ||
|  | c8ff53a75f | ||
|  | 6d08add20b | ||
|  | 29f9c725e3 | ||
|  | a83453f07f | ||
|  | ae365ce92c | ||
|  | 77a592e891 | ||
|  | 9a1df67d6b | ||
|  | 4b91411faf | ||
|  | 622a542d57 | ||
|  | cba53a9a50 | ||
|  | e186f27f63 | ||
|  | 4cd767ecb8 | ||
|  | f6e85aedf1 | ||
|  | b3ee294ba5 | ||
|  | 1c242def93 | ||
|  | f0fe6f2f69 | ||
|  | f86d555e49 | ||
|  | b0f2c40463 | ||
|  | 87be6fbb8a | ||
|  | 9141a9d2c8 | ||
|  | 7f75de347e | ||
|  | 329f7761c3 | ||
|  | 0d8e83cd75 | ||
|  | e5d60b8077 | ||
|  | ae2fe55efa | ||
|  | 6073607d3e | ||
|  | 389ebb5df8 | ||
|  | fd9655e9d4 | ||
|  | 6480aaa189 | ||
|  | 38969bb0a8 | ||
|  | 1847ab93af | ||
|  | c1177416f5 | ||
|  | 4fdd203211 | ||
|  | 4bc11776d7 | ||
|  | eb12eac5f3 | ||
|  | 5f5b951998 | ||
|  | 8e90547604 | ||
|  | fbea74d7ff | ||
|  | dcea16bc13 | ||
|  | d59a074bd7 | ||
|  | 39cc4f4dbf | ||
|  | 85bcf87af8 | ||
|  | a0fe1c610f | ||
|  | 5d21af1a0a | ||
|  | f6edbd210c | ||
|  | e084807a8f | ||
|  | 1c7d512829 | ||
|  | df0e0866e4 | ||
|  | 9e6efc3676 | ||
|  | 3aef29dace | ||
|  | 9a16e00577 | ||
|  | 84e4819e6e | ||
|  | 25dd6bc79a | ||
|  | 5d2cdb00c2 | ||
|  | 0f701f42d3 | ||
|  | 3e3e82d3f7 | ||
|  | c57bf86273 | ||
|  | f470d282ee | ||
|  | b8a2526da5 | ||
|  | 97575bbde9 | ||
|  | e5ed8b2c81 | ||
|  | 61fbae3ae2 | ||
|  | 5c2255c841 | ||
|  | e036dee6c5 | ||
|  | 8583aab241 | ||
|  | 5d05b62821 | ||
|  | 0063e8178f | ||
|  | ec6e5dd517 | ||
|  | 9d08fefa1c | ||
|  | 2fdca24d4e | ||
|  | 42ec0b144e | ||
|  | 3f6ce78b46 | ||
|  | c1300c1068 | ||
|  | 9a641cfab6 | ||
|  | 60345d4465 | ||
|  | 11dfea47a6 | ||
|  | 55e9dd39a2 | ||
|  | 1993929bed | ||
|  | e1d81de517 | ||
|  | a6b3a21635 | ||
|  | fd59cdc2db | ||
|  | 98e11b5189 | ||
|  | 3bebc7cd62 | ||
|  | 56dab6ae8c | ||
|  | 285f98e9e9 | ||
|  | 8ae9f59f20 | ||
|  | 4c341c5ca3 | ||
|  | a3c912c2af | ||
|  | 5e72eb9af9 | ||
|  | 9b08b73c06 | ||
|  | 76c7eb7c3e | ||
|  | 9b2e5a3adb | ||
|  | 813d703d12 | ||
|  | 83005d0f3d | ||
|  | d07ffd2688 | ||
|  | 4170f970d0 | ||
|  | dcde12dd70 | ||
|  | 84a60ec982 | ||
|  | 9615570dc6 | ||
|  | 880a9c3da0 | ||
|  | c44bd9d42d | ||
|  | 90b441330b | ||
|  | e12ed1eddf | ||
|  | ac94023ab3 | ||
|  | 281e6acca5 | ||
|  | 2f1b520409 | ||
|  | 21b4eb3d26 | ||
|  | 644f6c7d28 | ||
|  | 0647b9e4f8 | ||
|  | 82d42eeede | ||
|  | 6ef4d95043 | ||
|  | 6044140f86 | ||
|  | 4da1ef0f56 | ||
|  | 8c668a3918 | ||
|  | f1ff1cde39 | ||
|  | 1668a24e31 | ||
|  | 4b7c376d96 | ||
|  | bb4a9c656c | ||
|  | 6ab07b6304 | ||
|  | 8903f1ab01 | ||
|  | 415535612a | ||
|  | 5248a135c3 | ||
|  | 602290925c | ||
|  | 01813746e8 | ||
|  | 7d668d8801 | ||
|  | 797a00a33a | ||
|  | 4b3d98f43c | ||
|  | 9ff77c1cd5 | ||
|  | 18a8351671 | ||
|  | 9a994dfcd3 | ||
|  | b7adc5a889 | ||
|  | 10b0d7f363 | ||
|  | e2c905a15f | ||
|  | 8589ba728c | ||
|  | 43512fd07a | ||
|  | c090608d99 | ||
|  | 89817428ed | ||
|  | fce3664258 | ||
|  | aa522fe49b | ||
|  | c03653ebd7 | ||
|  | ae08f77381 | ||
|  | 73a07e512d | ||
|  | 7cff09f40a | ||
|  | a6d690f10a | ||
|  | d7cff52e75 | ||
|  | cf1f29a37d | ||
|  | 9af22110b4 | ||
|  | 2c187c7e85 | ||
|  | d46756ae2e | ||
|  | d9a16ed1f9 | ||
|  | 57a1120997 | ||
|  | 0945d4cef2 | ||
|  | 8f6f7ad453 | ||
|  | bb4fad37fa | ||
|  | d06daf2957 | ||
|  | 34314960ef | ||
|  | 832ba737ec | ||
|  | 6950fdbebb | ||
|  | 1849b1bb9a | ||
|  | a883139220 | ||
|  | bb2c26cb94 | ||
|  | ba09a0b2bf | ||
|  | b2d54f0238 | ||
|  | 4a3096495b | ||
|  | 23f6e9e53c | ||
|  | d7dbc0576d | ||
|  | 15fb00e958 | ||
|  | 1d9295cc94 | ||
|  | 79f36cf6fb | ||
|  | 6ce4458a5d | ||
|  | fad6e65c07 | ||
|  | 840c85373e | ||
|  | 0479bb5fe1 | ||
|  | 9ecc31ed54 | ||
|  | eb29abd36c | ||
|  | d202e01522 | ||
|  | e838a6801b | ||
|  | 7439871aa0 | ||
|  | 317f2138c5 | ||
|  | e5834f1901 | ||
|  | 5063446f93 | ||
|  | 0caf495a1a | ||
|  | a20de0fc69 | ||
|  | 9aa0065d2d | ||
|  | c24855e627 | ||
|  | 6bb72dd775 | ||
|  | 77d1ed257c | ||
|  | 5d265360c4 | ||
|  | c9097f6e8b | ||
|  | d3df985a42 | ||
|  | 7267420874 | ||
|  | 17e81432f1 | ||
|  | 57c767c3b1 | ||
|  | dbb1c88ad9 | ||
|  | 254b850a8b | ||
|  | e2242e5955 | ||
|  | 7a0255fee7 | ||
|  | ec6522cfbf | ||
|  | 1bf96e91bb | ||
|  | eb733cc58f | ||
|  | d9fdcf813b | ||
|  | 88bd1c9cea | ||
|  | 9e759e82b4 | ||
|  | da433854ac | ||
|  | ed3524e0d7 | ||
|  | 20e23bf3f6 | ||
|  | be4f85690e | ||
|  | e061dfa59b | ||
|  | cb4f42dfea | ||
|  | 9727f0cebe | ||
|  | 68656b4a4d | ||
|  | aae46bef84 | ||
|  | a0bb36954e | ||
|  | 4f32f3174f | ||
|  | b84107d142 | ||
|  | b46eeadc64 | ||
|  | 692231c2ea | ||
|  | 3a1becc3e4 | ||
|  | 3653e2d7f9 | ||
|  | 65def38d98 | ||
|  | 859c36cb10 | ||
|  | 3e34386812 | ||
|  | a35af11981 | ||
|  | 59eabec71e | ||
|  | bf4c7e7d50 | ||
|  | fd098ca4df | ||
|  | c360f8d8fd | ||
|  | b358559421 | ||
|  | df5aad8e8e | ||
|  | 8dbf79db59 | ||
|  | 1839608e84 | ||
|  | 6e3e795b8b | ||
|  | d9c410a7e3 | ||
|  | 609727afe8 | ||
|  | 8a5c74c0b4 | ||
|  | cd93f3b07e | ||
|  | 8397b12de6 | ||
|  | 3f85acec3a | ||
|  | d6a9e3d600 | ||
|  | 361569ac2f | ||
|  | 719664c145 | ||
|  | f800d6c24c | ||
|  | a9a81bcafb | ||
|  | 4280307a15 | ||
|  | 7b57d3ae51 | ||
|  | 8a8a5bbda0 | ||
|  | 76987c8db1 | ||
|  | 6f8971cc42 | ||
|  | 71ab882143 | ||
|  | 5a4961c8d9 | ||
|  | 4c4fb99d87 | ||
|  | 872abf09e9 | ||
|  | f10bfe7d04 | ||
|  | a74d8deff3 | ||
|  | 835ee4e8de | ||
|  | 63ec42303f | ||
|  | f789aebddc | ||
|  | efd83be779 | ||
|  | 603bc1d51c | ||
|  | 32a930a7fc | ||
|  | f464bf68d7 | ||
|  | ebdc4fb509 | ||
|  | 7580719586 | ||
|  | aba9db2be7 | ||
|  | a6680411c8 | ||
|  | 0d0e87de94 | ||
|  | ccf2000c09 | ||
|  | 3eb2e0f56a | ||
|  | d07c7d5b69 | ||
|  | adf6684c29 | ||
|  | 9bf889aa30 | ||
|  | e81c88564e | ||
|  | 901d400d62 | ||
|  | 289474e2ce | ||
|  | 407ca21168 | ||
|  | 5c68fc24d2 | ||
|  | 548800e0a9 | ||
|  | bde3d6dc6a | ||
|  | 56550a6acc | ||
|  | e51b83accc | ||
|  | d5ae971f1c | ||
|  | 5a2f5f9a42 | ||
|  | 75a3b70cef | ||
|  | 803cf65ba1 | ||
|  | 5d3947b838 | ||
|  | 4397a59008 | ||
|  | 966d54c935 | ||
|  | 234ddb495d | ||
|  | a744acc7bc | ||
|  | 27c624633c | ||
|  | 7ef75101b4 | ||
|  | 6f8aace00d | ||
|  | 6c264b2f18 | ||
|  | df055e1958 | ||
|  | 70d2117470 | ||
|  | 2c173ccaf3 | ||
|  | d2f4a0c5f3 | ||
|  | 0d6021e5e3 | ||
|  | bb04726e7f | ||
|  | 220ca370c2 | ||
|  | 63af4e3e98 | ||
|  | 9754e12d82 | ||
|  | d72ebed246 | ||
|  | 587fc71058 | ||
|  | 7d34e09a12 | ||
|  | 7d15baad0f | ||
|  | 1e6476ada7 | ||
|  | 1d6ca5f6b5 | ||
|  | fb249f02fc | ||
|  | fdf04ef275 | ||
|  | b0f5f634f2 | ||
|  | 6ee0108565 | ||
|  | c73097e688 | ||
|  | a2d42b07b5 | ||
|  | f9a794af93 | ||
|  | a2643674ca | ||
|  | c00ce9daac | ||
|  | c68b5d7844 | ||
|  | 09ed106d4c | ||
|  | a6b92fc658 | ||
|  | 4be4a1a30b | ||
|  | 9bede5d331 | ||
|  | b50d4aee6d | ||
|  | 55bc367bd6 | ||
|  | 7a59b7eafe | ||
|  | 9e59d41e44 | ||
|  | 475e6c7bca | ||
|  | dbc5a5293e | ||
|  | f4bd2bd0d8 | ||
|  | f1782a83ba | ||
|  | cbade0d558 | ||
|  | fe0c26387c | ||
|  | c03a014740 | ||
|  | 84e6d788aa | ||
|  | cd296b8767 | ||
|  | 5946d32a7d | ||
|  | 842dd8572b | ||
|  | 33e260f9db | ||
|  | c44f8d0060 | ||
|  | 411548a33e | ||
|  | 9a17ce1383 | ||
|  | 2b120d0669 | ||
|  | 6d877d5242 | ||
|  | e4abd690e7 | ||
|  | 2a194384b6 | ||
|  | 1e069e6f8a | ||
|  | a019bb913d | ||
|  | 9ce73931f7 | ||
|  | 97020df178 | ||
|  | dfb7b3de8f | ||
|  | 9e152912fe | ||
|  | b2c2f1e1aa | ||
|  | 629c7d8e92 | ||
|  | 62f24d4356 | ||
|  | ae281c33ca | ||
|  | 5d034dd106 | ||
|  | c1f8df0eca | ||
|  | 76dda9eeda | ||
|  | a9b84a92ac | ||
|  | 0f7e881899 | ||
|  | 6045f777ab | ||
|  | 5a15044ead | ||
|  | a69d76e487 | ||
|  | 3adfcdffa8 | ||
|  | 164a5d44d9 | ||
|  | 70ddab0231 | ||
|  | 7bf009fbf6 | ||
|  | 525bc8197b | ||
|  | 24397c51a8 | ||
|  | 06b3464756 | ||
|  | bbaa90bd9a | ||
|  | 5c683cbc0f | ||
|  | 95345f18bc | ||
|  | 4c3fbe83ac | ||
|  | 7caa43d02c | ||
|  | 3d4c03c9df | ||
|  | 22e1ed35d3 | ||
|  | dabe6fd793 | ||
|  | 3cc639c8d0 | ||
|  | 22c8e0b6db | ||
|  | f3ca4293bc | ||
|  | db3e076d03 | ||
|  | 1a6759820a | ||
|  | 61c5e7b948 | ||
|  | 5fd78ef32f | ||
|  | 14ff9b827c | ||
|  | 598dc2cd71 | ||
|  | 08e1c5109f | ||
|  | 6f7a843742 | ||
|  | c9c9615bb5 | ||
|  | f98609686d | ||
|  | 5b8bbc34e8 | ||
|  | 49cb00a9ab | ||
|  | 74b240fb88 | ||
|  | 514f9d2621 | ||
|  | fa78d1092a | ||
|  | 297342092b | ||
|  | 076f263a86 | ||
|  | 0c56207abc | ||
|  | 23953d8a5a | ||
|  | c6919eb25a | ||
|  | d509604b52 | ||
|  | a74a3450eb | ||
|  | 72c5399b9d | ||
|  | b29196b983 | ||
|  | ce76a7033d | ||
|  | 3f4bb933d1 | ||
|  | 501b7b9b65 | ||
|  | c0ea88e864 | ||
|  | 48f8bea460 | ||
|  | f4e5b6e38d | ||
|  | 477cb0a48d | ||
|  | d6bc0a3368 | ||
|  | e544a804c2 | ||
|  | 96e0ad7899 | ||
|  | 5a1fee5d31 | ||
|  | 3557a5e5a9 | ||
|  | 0bd43d5265 | ||
|  | 8fd7c1b386 | ||
|  | 50068750f5 | ||
|  | a7a905de4c | ||
|  | f283108586 | ||
|  | 9afe05095a | ||
|  | 3dab892978 | ||
|  | e40ddb800e | ||
|  | 72a74e7c66 | ||
|  | e8ae64673f | ||
|  | 2451f419c8 | ||
|  | 2394eb62aa | ||
|  | f9078bb1c3 | ||
|  | bf25c81f1c | ||
|  | 03ecc530c3 | ||
|  | d52b1d24d0 | ||
|  | 5083fab06a | ||
|  | 1249bf9ccc | ||
|  | 681f6b3f07 | ||
|  | d3ca1fe96b | ||
|  | 9e4f5815e4 | ||
|  | c3c27eaedc | ||
|  | 4bf6a23d23 | ||
|  | aaaf0d02de | ||
|  | 825cc4d035 | ||
|  | c2d44e5c10 | ||
|  | 0efd0860c8 | ||
|  | a890a06664 | ||
|  | 5befb87071 | ||
|  | 12ba4c373a | ||
|  | 7fd25be02e | ||
|  | aa688c4a92 | ||
|  | fb437551c9 | ||
|  | 6fa1de7889 | ||
|  | 7a42df9a65 | ||
|  | 15a508f3ea | ||
|  | b3c20ff909 | ||
|  | 682c07cb73 | ||
|  | 602605ab4b | ||
|  | 0eff2548d5 | ||
|  | 93ee681204 | ||
|  | d7bea98075 | ||
|  | 437a3b048d | ||
|  | f55a9454b5 | ||
|  | 3b03ad0db4 | ||
|  | 27d679e1f1 | ||
|  | 1e16d59c23 | ||
|  | 1e7c9bbb1f | ||
|  | edda1edc50 | ||
|  | d1eb6279b4 | ||
|  | 4ace79d947 | ||
|  | e5eee96487 | ||
|  | 907adf9145 | ||
|  | c046fe6220 | ||
|  | 84bf20de41 | ||
|  | f5a6f74d9a | ||
|  | 7c7fc51ccf | ||
|  | fa22f6de0d | ||
|  | 4f41214af2 | ||
|  | 607b7169bc | ||
|  | 1253490a38 | ||
|  | 0a37a588e8 | ||
|  | 23ee108089 | ||
|  | 64feeeea75 | ||
|  | 2ebef23b8c | ||
|  | cc9f43ba3b | ||
|  | 5f1c139176 | ||
|  | 9eea7de340 | ||
|  | 4480f84efa | ||
|  | 5a8b8afff1 | ||
|  | 67c95bc0b7 | ||
|  | e70ec02be8 | ||
|  | db81a94adb | ||
|  | 475b608338 | ||
|  | 27e36b112e | ||
|  | f698721484 | ||
|  | 0c08353b2c | ||
|  | a074b49732 | ||
|  | 43b75c7953 | ||
|  | 84a78eafc4 | ||
|  | 3c1ab889dd | ||
|  | 012fff46f6 | ||
|  | 6307ebc3a2 | ||
|  | 88d7e73eba | ||
|  | 9653eb9e70 | ||
|  | ad337271d3 | ||
|  | 7591e99316 | ||
|  | ca20df4752 | ||
|  | 841e4ee666 | ||
|  | e2ee3414ea | ||
|  | 5306cc03e9 | ||
|  | 85f5d32de2 | ||
|  | ab698cec14 | ||
|  | b463a39bfa | ||
|  | 018e25345b | ||
|  | b60fa8a7d7 | ||
|  | 048d8dee60 | ||
|  | 927fe2b58b | ||
|  | 89948b360c | ||
|  | 561b60a24d | ||
|  | 4f82543bdf | ||
|  | 3133c509f9 | ||
|  | 426c15692d | ||
|  | 8c87a77faa | ||
|  | d2018f07a2 | ||
|  | d2e57d8163 | ||
|  | 7403c0255a | ||
|  | 75dcd687e2 | ||
|  | afd4805421 | ||
|  | 6aa582d140 | ||
|  | 534d92fa00 | ||
|  | 37aae134ab | ||
|  | 36bd8f68c9 | ||
|  | c3ad42221e | ||
|  | 602ac1f626 | ||
|  | 3126795efe | ||
|  | dbcb221a59 | ||
|  | 6bbc179f52 | ||
|  | 48e7a391c8 | ||
|  | 2334e64d0c | ||
|  | 14f920ee84 | ||
|  | e10a81023a | ||
|  | f4709ed1cb | ||
|  | e2e14a977a | ||
|  | 866f958a10 | ||
|  | 717db99b38 | ||
|  | 02006118c7 | ||
|  | 9816019bc5 | ||
|  | 9c821dbfc3 | ||
|  | af1b890423 | ||
|  | 673835d2de | ||
|  | 500b57e935 | ||
|  | 3f7d0580c1 | ||
|  | a71c356bba | ||
|  | c3a95b7fb1 | ||
|  | f01540fb35 | ||
|  | 689a8881c2 | ||
|  | 99f5be8378 | ||
|  | 8de0282d92 | ||
|  | f99804d56a | ||
|  | f13d27b749 | ||
|  | 465fd59cbc | ||
|  | 5fdabe6612 | ||
|  | 861871134b | ||
|  | c246d98093 | ||
|  | 02076dba1b | ||
|  | 7b136a5ad8 | ||
|  | 0c4a67fa35 | ||
|  | 668aeb77f7 | ||
|  | 135ae392d5 | ||
|  | 88ba04307c | ||
|  | e4b8000a48 | ||
|  | b9df108314 | ||
|  | 6106185bf6 | ||
|  | 3a3e289864 | ||
|  | 6558632f10 | ||
|  | 376ee6bdff | ||
|  | fc5d759131 | ||
|  | 7c16bb3df8 | ||
|  | 5df74d35d0 | ||
|  | 72fc0c845a | ||
|  | b995715a2c | ||
|  | 857b5c97b0 | ||
|  | 178d9c280a | ||
|  | 2416deba25 | ||
|  | 0ce6243653 | ||
|  | 40dc10729b | ||
|  | 0571244e9e | ||
|  | 3213131cad | ||
|  | 61bf93aac2 | ||
|  | a9d0cec6d1 | ||
|  | b5e3f0b90c | ||
|  | 61f1fe42b0 | ||
|  | 1cfdc49021 | ||
|  | c4d58277cf | ||
|  | 9ac66c2130 | ||
|  | 6366163006 | ||
|  | 85fde8f9a5 | ||
|  | a03d0800b0 | ||
|  | 9cb21006a7 | ||
|  | 649202f1c4 | ||
|  | b798556774 | ||
|  | 03bc15fbdf | ||
|  | b2dfd8740c | ||
|  | 3182c12b4d | ||
|  | f783625d60 | ||
|  | 891aa8e8bf | ||
|  | 4b508d255d | ||
|  | 1cad43bf5d | ||
|  | a0cd727832 | ||
|  | ab90e15015 | ||
|  | 52cbddf054 | ||
|  | db98ff8cb7 | ||
|  | 1d8dd2f89c | ||
|  | 0ae1c926d3 | ||
|  | 1fcab58e2f | ||
|  | a8cbd1a16c | ||
|  | 3aaa0ad6b2 | ||
|  | e34bc77157 | ||
|  | 088b331f19 | ||
|  | 56f2dec441 | ||
|  | ac8b08d3cf | ||
|  | c4ead689a9 | ||
|  | 07ab10b000 | ||
|  | c969a8652a | ||
|  | fb21ca5404 | ||
|  | bbfa9c34ab | ||
|  | 7161bbe836 | ||
|  | ef65aa5bf6 | ||
|  | 2cf31f05a1 | ||
|  | 2b1a1ba0db | ||
|  | 05b25c6229 | ||
|  | 2db52c6983 | ||
|  | 4803e2f68c | ||
|  | 7030572f1d | ||
|  | 6e2eb9c5bb | ||
|  | eb27e260e0 | ||
|  | c72aa653e8 | ||
|  | 4d04b72674 | ||
|  | e3b92d2c8b | ||
|  | 4aa5a89cd7 | ||
|  | c6b9ea5723 | ||
|  | 2dc0bff1ea | ||
|  | 408e66e8b4 | ||
|  | 40fe12a86b | ||
|  | 1adb56f092 | ||
|  | 629d48c766 | ||
|  | c8886febb9 | ||
|  | efe598c8fd | ||
|  | 32218ce25e | ||
|  | f7ae697475 | ||
|  | 6e954385ce | ||
|  | f8df89b506 | ||
|  | a3ff406461 | ||
|  | 221de054f4 | ||
|  | 98e6aa4bac | ||
|  | 199808dc44 | ||
|  | 5d8e35fb68 | ||
|  | 36546480b1 | ||
|  | cd9e408ea3 | ||
|  | 7698f21517 | ||
|  | 10724e5745 | ||
|  | dde76a4dbb | ||
|  | 86ff5c53bb | ||
|  | efef5f122f | ||
|  | 83c942ad8c | ||
|  | 31e90e314c | ||
|  | 33caae705e | ||
|  | 961273a2ff | ||
|  | 46e512a27c | ||
|  | 290a04a0ad | ||
|  | 12ff4ec438 | ||
|  | 1c15ecacb0 | ||
|  | c6d738ed0c | ||
|  | f089f5d87f | ||
|  | 78e3cd39d1 | ||
|  | 1588c1f362 | ||
|  | a35d1b8a9d | ||
|  | 32923ec7e1 | ||
|  | 5a3bd716ad | ||
|  | 84862f15c1 | ||
|  | 9e42dce5c4 | ||
|  | a360109013 | ||
|  | 68d6b3a033 | ||
|  | 733c3046bc | ||
|  | 23d4b6bf1c | ||
|  | 39bd0c5459 | ||
|  | c13ffb2072 | ||
|  | 38bcab1f86 | ||
|  | a24f01c90f | ||
|  | 708e34602b | ||
|  | d60c8ddd5a | ||
|  | eea63292f0 | ||
|  | a97342a594 | ||
|  | 00f55be83e | ||
|  | 90ed283b20 | ||
|  | 61272961a8 | ||
|  | 507690f9db | ||
|  | 90ad5eb6c4 | ||
|  | 7bc9701c81 | ||
|  | a7d502a501 | ||
|  | fbe99b41f8 | ||
|  | 66e2d93e9c | ||
|  | 4672c72fef | ||
|  | ac6b03cd4a | ||
|  | d7de191947 | ||
|  | de7f1fc207 | ||
|  | 99de5a3814 | ||
|  | 4cf566cad8 | ||
|  | 6138955f93 | ||
|  | a57cf68ee4 | ||
|  | 20edcd1ae5 | ||
|  | 5333befd89 | ||
|  | 235e406620 | ||
|  | 5f570b772d | ||
|  | f2507cb94a | ||
|  | f84b375cde | ||
|  | 32d11d1ba5 | ||
|  | 5c9b6eb078 | ||
|  | f53a512e70 | ||
|  | ec08715090 | ||
|  | 79e0a9ef37 | ||
|  | 1ce8a33937 | ||
|  | b3053dfb91 | ||
|  | 3da05f2812 | ||
|  | 0ba79b060d | ||
|  | c4bcc26e29 | ||
|  | 630108ccb6 | ||
|  | 1ab33aa132 | ||
|  | ee456ea6e7 | ||
|  | e7541ac2af | ||
|  | d34d46b7fd | ||
|  | 08ae43aad3 | ||
|  | eb141075c7 | ||
|  | bd3387a408 | ||
|  | e1a48e80e1 | ||
|  | bf899d40a0 | ||
|  | dc66f1b886 | ||
|  | 3753b1a7d0 | ||
|  | 05c5acdb15 | ||
|  | ca63bcc9b0 | ||
|  | 3733d503db | ||
|  | ab28e42c22 | ||
|  | 7e53b4f834 | ||
|  | 3bb60fee19 | ||
|  | 9f7840e12b | ||
|  | f41e13b574 | ||
|  | 4049143630 | ||
|  | 705f46717f | ||
|  | a6cf8ae0b6 | ||
|  | dba6972281 | ||
|  | 52d36f5a8b | ||
|  | 889b58a914 | ||
|  | 43810835d7 | ||
|  | 4b9867f167 | ||
|  | e9c91e59bd | ||
|  | d8844f6970 | ||
|  | 1cdc6e7184 | ||
|  | 36ad373f03 | ||
|  | 78dfb6d525 | ||
|  | 79254de7bc | ||
|  | 1d6aef5cd6 | ||
|  | f9d02c9e27 | ||
|  | 228246089e | ||
|  | b6319ba3d8 | ||
|  | 2636384ead | ||
|  | 0425f76284 | ||
|  | d93e72f56a | ||
|  | 195d543ce3 | ||
|  | 9cda9f69cd | ||
|  | 7b0a1c3630 | ||
|  | a8f3a47240 | ||
|  | db0f3a8780 | ||
|  | 514db24ceb | ||
|  | e738743c89 | ||
|  | f471e1a8a3 | ||
|  | a2f0d5eedf | ||
|  | 2f9b894d71 | ||
|  | bab34c2d21 | ||
|  | a68421b0f8 | ||
|  | e9b0ac8820 | ||
|  | 4f78f55c2a | ||
|  | 156093127b | ||
|  | 47d91bb4e0 | ||
|  | cc31445189 | ||
|  | af78238507 | ||
|  | b30f87f50c | ||
|  | 3cd03ed0f1 | ||
|  | e7ad7c3af7 | ||
|  | 7e8b56eef4 | ||
|  | 458a014e6d | ||
|  | 9b6703398e | ||
|  | 71700e69af | ||
|  | 14d6330b40 | ||
|  | d31d646ecc | ||
|  | 270d7a3f19 | ||
|  | e078f3d479 | ||
|  | 6aa8f17ed5 | ||
|  | 8e73ae3614 | ||
|  | 89117beda2 | ||
|  | e27e6baabe | ||
|  | 15ce90c0ec | ||
|  | 39e157499d | ||
|  | d22c0641fb | ||
|  | 82806b6fcb | ||
|  | fe293d91ee | ||
|  | 7842bb4cad | ||
|  | 6f7e156f49 | ||
|  | 0d19cac487 | ||
|  | f30dfcc572 | ||
|  | 3df39d8cfe | ||
|  | ece93fed78 | ||
|  | 3a2c6ae9d6 | ||
|  | 2ed71b36b6 | ||
|  | ae9c301795 | ||
|  | 68206ffb6e | ||
|  | 25a3c18bfe | ||
|  | d28476e9f7 | ||
|  | 7cd30610f9 | ||
|  | ceb90989d0 | ||
|  | bb39d63d37 | ||
|  | 213709d020 | ||
|  | d0e9081852 | ||
|  | 71cde281b9 | ||
|  | c03f1586e6 | ||
|  | 10aceb164d | ||
|  | 34f516a417 | ||
|  | 5dd686f22f | ||
|  | 5f47ad3363 | ||
|  | e166e9762a | ||
|  | 341c5782e5 | ||
|  | d5180d3ebc | ||
|  | 2c73bbd689 | ||
|  | b10522479c | ||
|  | 2b39ae4800 | ||
|  | 788bdba8cd | ||
|  | 222fd5d822 | ||
|  | eedfc64a8c | ||
|  | 78170b26e9 | ||
|  | f966b6f4df | ||
|  | 053b55fbbf | ||
|  | 84a55a2d84 | ||
|  | 498a50b229 | ||
|  | 766888ec41 | ||
|  | 466d962c07 | ||
|  | ae2a6fb685 | ||
|  | 5afe2616a4 | ||
|  | 72c869649a | ||
|  | 34138fc3b5 | ||
|  | f67d2b96ac | ||
|  | d877d3686c | ||
|  | 8260615b4e | ||
|  | c3f6d48966 | ||
|  | 02f979bc74 | ||
|  | de1c71aacc | ||
|  | ca2aa72e0f | ||
|  | 9a16f5736e | ||
|  | 82774df715 | ||
|  | 314f53c0b3 | ||
|  | 6553ee0130 | ||
|  | d7918ea047 | ||
|  | 4aa9c85503 | ||
|  | f172591059 | ||
|  | dfa7e30e42 | ||
|  | 3fe2013398 | ||
|  | 391d501ce6 | ||
|  | 9edaa3a64e | ||
|  | 6e4e313792 | ||
|  | e6dcf92ec8 | ||
|  | f359de2cac | ||
|  | 2d29014091 | ||
|  | 0450e430f1 | ||
|  | b6700af6a8 | ||
|  | bcee7546ae | ||
|  | 4dac620156 | ||
|  | 74d9df2fb0 | ||
|  | 9d1615fa23 | ||
|  | b1b9949e72 | ||
|  | 957ef5ab77 | ||
|  | 07a681c77e | ||
|  | 145ec8ede1 | ||
|  | 5f5a158060 | ||
|  | 3e99c95791 | ||
|  | 4f83521be8 | ||
|  | aae93bb6a7 | ||
|  | b5eb1c9ee8 | ||
|  | 9d3755db36 | ||
|  | 762e0aec2d | ||
|  | ff9c9241d8 | ||
|  | 5c1ffe7fc8 | ||
|  | b1c3c60def | ||
|  | 8763713596 | ||
|  | 3e823cc9e3 | ||
|  | 1c84709db3 | ||
|  | 9150d6bd2a | ||
|  | 10f29b66b8 | ||
|  | 259aec52a9 | ||
|  | 6554bf9f08 | ||
|  | d8558f5956 | ||
|  | 18bc701e8b | ||
|  | a47795fd3f | ||
|  | a55e8b268c | ||
|  | e8106f04b5 | ||
|  | bdc1dbf08a | ||
|  | 06eeb2088b | ||
|  | 7da9ec2c75 | ||
|  | 297ff10c14 | ||
|  | 1305f4314d | ||
|  | 55474c0599 | ||
|  | 687c79ae81 | ||
|  | 829a353b14 | ||
|  | aced474dc5 | ||
|  | 7c08d5f198 | ||
|  | c546787994 | ||
|  | 31fa530845 | ||
|  | 120714ecfc | ||
|  | 615874d2ec | ||
|  | 67b195c942 | ||
|  | 75689cee96 | ||
|  | 8ba77e95a4 | ||
|  | 7967a8416c | ||
|  | 934fbca860 | ||
|  | e78c8038c7 | ||
|  | f64a42ebb5 | ||
|  | 9164cff234 | ||
|  | 017f98e87e | ||
|  | f33d8670aa | ||
|  | e79db7de89 | ||
|  | 845a42e73a | ||
|  | e58c25aa18 | ||
|  | 8ec44b63b1 | ||
|  | 41907936a1 | ||
|  | 406d2cefc5 | ||
|  | 41cdbc0ec4 | ||
|  | c6ec261c5c | ||
|  | a2db1a3275 | ||
|  | 1e8f2f0e83 | ||
|  | 8491abe142 | ||
|  | d4302538bf | ||
|  | c34e3765ef | ||
|  | 1f86bc06ef | ||
|  | 7e892fac2d | ||
|  | 23789b0692 | ||
|  | 89adbe4127 | ||
|  | 11940fb98e | ||
|  | 13ae335811 | ||
|  | b2dc6ad2fa | ||
|  | 85ca926fd0 | ||
|  | 676698a59b | ||
|  | 22408ecd58 | ||
|  | d36acc7ec7 | ||
|  | a5a68acfec | ||
|  | 7431651666 | ||
|  | 4f91bfd907 | ||
|  | 8d2086870b | ||
|  | 1511ef1a98 | ||
|  | 4e030ce1e8 | ||
|  | 2507ad274b | ||
|  | fb1c149eb9 | ||
|  | d4662f428a | ||
|  | 73c779c13a | ||
|  | b8cc164af1 | ||
|  | 64a391b5f8 | ||
|  | 21a202dd16 | ||
|  | 187dd2fdc3 | ||
|  | c18f3f0b33 | ||
|  | 7162935028 | ||
|  | 9215a73b6c | ||
|  | edd840794c | ||
|  | c30a6eb1aa | ||
|  | 233642af29 | ||
|  | 7dffd0a03e | ||
|  | f7bc3ff49d | ||
|  | 53aabe3cdb | ||
|  | 09b8d7cfc9 | ||
|  | 1512afc7e6 | ||
|  | dde0c76112 | ||
|  | f14b6f2ba2 | ||
|  | 4fced276c4 | ||
|  | 7590471d62 | ||
|  | 0b6bcf6739 | ||
|  | 3a5ce86ed9 | ||
|  | 7b298939e2 | ||
|  | f1f6aa7d80 | ||
|  | 7ce7dd7252 | ||
|  | 01aa556ede | ||
|  | 48ad39c1c7 | ||
|  | 9cab034448 | ||
|  | 0d7a22634c | ||
|  | 3e3bc5c06d | ||
|  | 2a81e468c7 | ||
|  | 0ba67a363e | ||
|  | deae846864 | ||
|  | 3a0d48ad77 | ||
|  | 81d4803b4d | ||
|  | e936c7c507 | ||
|  | ad868af96e | ||
|  | cd14a45414 | ||
|  | f7cd7110ea | ||
|  | 44262bf747 | ||
|  | 0fbbabe208 | ||
|  | b39189fde3 | ||
|  | 18fc1d78f4 | ||
|  | d44a91d10b | ||
|  | 5e9829b2d8 | ||
|  | 2176deae36 | ||
|  | 7c5035aa39 | ||
|  | 5707993995 | ||
|  | f81697527c | ||
|  | 967eff4c58 | ||
|  | d5d07dd34e | ||
|  | b91cc3781d | ||
|  | 87ed0071c4 | ||
|  | 0fed48630c | ||
|  | 7b3e7c98ac | ||
|  | 09f44b0375 | ||
|  | ebfa62637e | ||
|  | cb2cc05cac | ||
|  | f9c9131d81 | ||
|  | 1be9a1cbc7 | ||
|  | b7fda8ecf0 | ||
|  | db16392821 | ||
|  | 7127f541c3 | ||
|  | 32793cc008 | ||
|  | fbaf55cb25 | ||
|  | b8d51fc4e8 | ||
|  | 0c6e05d220 | ||
|  | 4066c17a0f | ||
|  | 429f2bb8dd | ||
|  | 112f4fc4f0 | ||
|  | ecfbd6280f | ||
|  | bf84409839 | ||
|  | a7ce72cae0 | ||
|  | 28402ff7d8 | ||
|  | e1d213d1a3 | ||
|  | c610dd96f5 | ||
|  | 2ba3818b65 | ||
|  | 0e1a5a375a | ||
|  | cfc3daeb65 | ||
|  | 6359f1950e | ||
|  | d2f581853d | ||
|  | 030cb285da | ||
|  | af45409959 | ||
|  | d9a9bc35e3 | ||
|  | c911c3352c | ||
|  | 654abbac25 | ||
|  | 46d5f42c9d | ||
|  | 1509da1215 | ||
|  | 98a99d96aa | ||
|  | d62d81af17 | ||
|  | dba67eb927 | ||
|  | 548c30d6a0 | ||
|  | 1b8b9186a8 | ||
|  | a8cfcfb371 | ||
|  | f7a414bc29 | ||
|  | e05cd1d66b | ||
|  | 511cd90c44 | ||
|  | 8fb2d8da88 | ||
|  | 2fce332ed7 | ||
|  | b23f1eb145 | ||
|  | f694072b5a | ||
|  | 10de266e0f | ||
|  | 71811ed04f | ||
|  | e9638ef95e | ||
|  | 5226bb5596 | ||
|  | b9984b6df4 | ||
|  | 9c11835fee | ||
|  | d9e13d6b99 | ||
|  | dede076835 | ||
|  | c929782e0d | ||
|  | a43c7e36f8 | ||
|  | b95cec9c32 | ||
|  | 9a7d9abe3c | ||
|  | c77b620453 | ||
|  | b348084e2a | ||
|  | ff1811ef90 | ||
|  | 39cf4a7576 | ||
|  | 21b67625a6 | ||
|  | fb0311e675 | ||
|  | 8a14b4afff | ||
|  | e42701599a | ||
|  | 352b1b43f2 | ||
|  | 2922ebd095 | ||
|  | a9e72085dd | ||
|  | ed3d194c90 | ||
|  | 125c53827b | ||
|  | 38781807cd | ||
|  | c046943269 | ||
|  | fe36cd86bb | ||
|  | 401410089c | ||
|  | fa23337519 | ||
|  | ae5421f76e | ||
|  | a2e2b429d5 | ||
|  | ac852b23b3 | ||
|  | e12389a002 | ||
|  | da18e42d2a | ||
|  | 93bdaba8ee | ||
|  | 4cb08a61d5 | ||
|  | 133692ca92 | ||
|  | 4bcc4b3cf8 | ||
|  | 4eb20ca4b6 | ||
|  | 69f7343be5 | ||
|  | 19b28a58d6 | ||
|  | 3c33a93b9c | ||
|  | f2e16dfb21 | ||
|  | 0f689e8051 | ||
|  | 5b44e6ef64 | ||
|  | 49e4ade66f | ||
|  | 3bae27d039 | ||
|  | a77f0c606d | ||
|  | f1de64dcaf | ||
|  | feb672c3cd | ||
|  | a90b463a7d | ||
|  | 5f5f25c978 | ||
|  | 351ea8bc1c | ||
|  | b34edcbf87 | ||
|  | 160519e1fe | ||
|  | 44d626e12e | ||
|  | efb9dc51c9 | ||
|  | deb51434fd | ||
|  | 501070bfb0 | ||
|  | 712958d8c8 | ||
|  | 4d8d944fe5 | ||
|  | 0042e42160 | ||
|  | 85509ea251 | ||
|  | 6063854d06 | ||
|  | 456f8a90b1 | ||
|  | 980246d07a | ||
|  | 141c30b173 | ||
|  | 22f9b03fce | ||
|  | be2db504b9 | ||
|  | cac6f5234f | ||
|  | eb6b32b6ee | ||
|  | 07acc9529e | ||
|  | f7f0152573 | ||
|  | 153533f1d5 | ||
|  | 11622c586a | ||
|  | 7396bb508a | ||
|  | 7df6530f3a | ||
|  | 80787456fa | ||
|  | 4446ac1ca3 | ||
|  | 220039ab00 | ||
|  | 12f2250ab5 | ||
|  | 0c33aa16a1 | ||
|  | 72908b02fe | ||
|  | 223aa04424 | ||
|  | e53248cca6 | ||
|  | c11d661b39 | ||
|  | 4212a08337 | ||
|  | c0553fa9eb | ||
|  | 7f26fafed7 | ||
|  | 3e9309c003 | ||
|  | 1017707475 | ||
|  | e8ff5da209 | ||
|  | 03ed3ac1b0 | ||
|  | 2c97208e74 | ||
|  | a458e81f8d | ||
|  | 83289bc801 | ||
|  | ba2ac6a7b5 | ||
|  | 245b6da577 | ||
|  | 8875f924b0 | ||
|  | ad7868ebe1 | ||
|  | 5effc6ec90 | ||
|  | 4cc9ceabd2 | ||
|  | 464c918134 | ||
|  | 2456adcb68 | ||
|  | 45bc967f30 | ||
|  | d6d4d29257 | ||
|  | 33fdfdc8c0 | ||
|  | 80c8712b2a | ||
|  | 957e3eb93c | ||
|  | 110e1afa8e | ||
|  | 1da8f68871 | ||
|  | 513ddb4cca | ||
|  | 3bdfcb8542 | ||
|  | aee758eca2 | ||
|  | 47ef7fffce | ||
|  | 58d6256607 | ||
|  | b854fcdb72 | ||
|  | 27ca75d94f | ||
|  | bb15f78af0 | ||
|  | ccc9e18132 | ||
|  | d55108ab60 | ||
|  | 84adbcb683 | ||
|  | 0cb5e4553b | ||
|  | 264407b707 | ||
|  | eb5ec58453 | ||
|  | 39c2a757be | ||
|  | 8cdc05f582 | ||
|  | 5f4778c852 | ||
|  | 70add44fc1 | ||
|  | fa617d2e9d | ||
|  | 3c795d365d | ||
|  | 93872ad7a3 | ||
|  | 227676c150 | ||
|  | 5f23833b43 | ||
|  | 121d51b414 | ||
|  | 0e196a59d9 | ||
|  | 63bfd23310 | ||
|  | aadcf8fed0 | ||
|  | 37390e03b4 | ||
|  | 98fc780ade | ||
|  | 1670b21123 | ||
|  | 5602aacbd2 | ||
|  | 6ddbea207f | ||
|  | 261bced822 | ||
|  | a80d1f861c | ||
|  | c541340ef5 | ||
|  | 434af0ae64 | ||
|  | c6379ca1d4 | ||
|  | cdbcada49b | ||
|  | 282930cb9b | ||
|  | b09c751942 | ||
|  | b2047b90b3 | ||
|  | 0c8aec30bd | ||
|  | fafaa3e69b | ||
|  | d19bb3de8d | ||
|  | 481136166c | ||
|  | 4df81a0b9e | ||
|  | da1e9c2d97 | ||
|  | 4b5a02c246 | ||
|  | 0e1572cfd7 | ||
|  | 343caa1ff6 | ||
|  | 403fb3826d | ||
|  | 3cdccb7b4e | ||
|  | d9be78cdb4 | ||
|  | 16dc8255e1 | ||
|  | 2086bfff25 | ||
|  | b9a68c0b8e | ||
|  | 74647f0e88 | ||
|  | 6e29c8bea9 | ||
|  | b36373ab81 | ||
|  | dc437aacf1 | ||
|  | e19dae9b28 | ||
|  | 424cbd4831 | ||
|  | 350feed993 | ||
|  | 7ca4aa0ff4 | ||
|  | bf00e67245 | ||
|  | c5a6e49681 | ||
|  | a509af2875 | ||
|  | 1f789bf396 | ||
|  | 0ccbc7d3d2 | ||
|  | f3c6f26f85 | ||
|  | 338c358df2 | ||
|  | 4bdaa48303 | ||
|  | 36267746da | ||
|  | 7775541eed | ||
|  | 5029be4c83 | ||
|  | 277dbacf68 | ||
|  | 0fdfb03f3c | ||
|  | 17d81bf014 | ||
|  | 568e9be07e | ||
|  | 99b0a95f8a | ||
|  | 0fdd31892a | ||
|  | 7a682604f9 | ||
|  | ce96e35d7d | ||
|  | b7fb5394a7 | ||
|  | aaa62beca7 | ||
|  | 2b58a7242b | ||
|  | 5ed919df79 | ||
|  | baf6372179 | ||
|  | 1a9063a55b | ||
|  | 87999f402f | ||
|  | 109d466260 | ||
|  | 37597eca75 | ||
|  | 5fd767b739 | ||
|  | 0e7a473116 | ||
|  | 05bf55dca8 | ||
|  | cc12ad8d86 | ||
|  | 847a7f470c | ||
|  | 95bebd6d1d | ||
|  | 8179a964ea | ||
|  | d0805d4bbb | ||
|  | f901c401b7 | ||
|  | 6ccadcb928 | ||
|  | 58b6c25d5c | ||
|  | 9cbab26202 | ||
|  | 74bcb468ca | ||
|  | 07a6ba88f4 | ||
|  | 49dff49993 | ||
|  | 68207aac80 | ||
|  | 64652b2ff0 | ||
|  | 659e8991de | ||
|  | 9f495b6dc9 | ||
|  | d8498134ad | ||
|  | 17b2320b0d | ||
|  | 36c457f483 | ||
|  | b8ec7f5e26 | ||
|  | dbc5c0d5d8 | ||
|  | fa886aa849 | ||
|  | 32e1ae2b18 | ||
|  | 61f03b0ea2 | ||
|  | c47825a820 | ||
|  | 2d7cb63c7b | ||
|  | c3d4c13936 | ||
|  | 3f51b9322f | ||
|  | b604e2bd4e | ||
|  | bcd92473d1 | ||
|  | 6f5bf9d146 | ||
|  | 490094939f | ||
|  | d0d7d2772f | ||
|  | 59091896b4 | ||
|  | 3eb1429a25 | ||
|  | bc7504c469 | ||
|  | 99dc4b8e07 | ||
|  | 807904bb86 | ||
|  | 7b8c8348f4 | ||
|  | 9c5ac26170 | ||
|  | 5db065644c | ||
|  | 0cc3a99169 | ||
|  | 2b1545145b | ||
|  | 49b7c9c8a4 | ||
|  | 114119f7c8 | ||
|  | b4ef866c10 | ||
|  | 15f75a08d5 | ||
|  | 29f9c5473d | ||
|  | ea1528aea6 | ||
|  | 18ce19a84d | ||
|  | b0fd78d68d | ||
|  | 8186d6277e | ||
|  | 599af2b1a9 | ||
|  | 82de5adbe9 | ||
|  | 82b0f85258 | ||
|  | cded58c30d | ||
|  | da17b49b81 | ||
|  | 4728cdfa7c | ||
|  | d97b30dcee | ||
|  | fa8e8ad52d | ||
|  | 7495ac8111 | ||
|  | 08619e2c06 | ||
|  | 5d4bbd5b37 | ||
|  | 9d2aef5006 | ||
|  | bcc3e5ebb0 | ||
|  | e5df51a83a | ||
|  | 97fb843f01 | ||
|  | 8afb044877 | ||
|  | 7f869868c9 | ||
|  | 31275228ac | ||
|  | 7181be8768 | ||
|  | 3b446e887a | ||
|  | 431196c391 | ||
|  | 9608d8fb46 | ||
|  | d574ca1628 | ||
|  | 8be60e2ff5 | ||
|  | 3c0fd540b1 | ||
|  | 23a7dc9a8a | ||
|  | f97e6892b6 | ||
|  | 7742901e5c | ||
|  | de68cb25d0 | ||
|  | 77d7afe505 | ||
|  | 68fb6c2c27 | ||
|  | a47c031ad1 | ||
|  | 817049456c | ||
|  | e1a061789f | ||
|  | 28573ba772 | ||
|  | 880b9413f6 | ||
|  | 9a7c4b21a9 | ||
|  | ac56038eca | ||
|  | 4dd2fb6903 | ||
|  | 0baec61f06 | ||
|  | d4751788d1 | ||
|  | ae68c061d1 | ||
|  | b0387245f0 | ||
|  | c2d06a4a23 | ||
|  | 270108abb7 | ||
|  | e76c33232d | ||
|  | 90cb86911a | ||
|  | f56839ec6b | 
| @@ -1,429 +1,315 @@ | ||||
| version: 2 | ||||
| version: 2.1 | ||||
|  | ||||
| parameters: | ||||
|     cache_version: | ||||
|         type: string | ||||
|         default: v5 | ||||
|  | ||||
| jobs: | ||||
|     build: | ||||
|         resource_class: medium+ | ||||
|         resource_class: xlarge | ||||
|         docker: | ||||
|             - image: nikolaik/python-nodejs:python3.7-nodejs8 | ||||
|             - image: node:16 | ||||
|         environment: | ||||
|             CONTRACTS_COMMIT_HASH: '9ed05f5' | ||||
|         working_directory: ~/repo | ||||
|             NODE_OPTIONS: '--max-old-space-size=16384' | ||||
|         steps: | ||||
|             - checkout | ||||
|             - run: git submodule update --init --recursive | ||||
|             - run: echo 'export PATH=$HOME/CIRCLE_PROJECT_REPONAME/node_modules/.bin:$PATH' >> $BASH_ENV | ||||
|             # HACK(feuGeneA): commented out this hack as we're changing | ||||
|             # from a circleci-maintained container to a different | ||||
|             # container, and this hack may not apply anymore, as | ||||
|             # suggested by the non-existance of `/home/circleci/.bashrc` | ||||
|             # when running the command below. | ||||
|             # - run: | ||||
|             #       # HACK(albrow): Without this, yarn commands will sometimes | ||||
|             #       # fail with a "permission denied" error. | ||||
|             #       name: Set npm path | ||||
|             #       command: npm set prefix=/home/circleci/npm && echo 'export PATH=$HOME/circleci/npm/bin:$PATH' >> /home/circleci/.bashrc | ||||
|             - restore_cache: | ||||
|                   keys: | ||||
|                       - lib-{{ .Environment.CIRCLE_SHA1 }}-feat/NerveMixinArbitrum | ||||
|             - restore_cache: | ||||
|                   keys: | ||||
|                       - cache-{{ checksum "yarn.lock" }}-<< pipeline.parameters.cache_version >> | ||||
|             - run: | ||||
|                   name: install-yarn | ||||
|                   command: npm install --force --global yarn@1.17.0 | ||||
|                   command: npm install --force --global yarn@1.22.0 | ||||
|             - run: | ||||
|                   name: yarn | ||||
|                   command: yarn --frozen-lockfile --ignore-engines install || yarn --frozen-lockfile --ignore-engines install | ||||
|             - setup_remote_docker | ||||
|             - run: yarn build:ci | ||||
|             - run: yarn build:ts | ||||
|             - save_cache: | ||||
|                   key: repo-{{ .Environment.CIRCLE_SHA1 }} | ||||
|                   key: cache-{{ checksum "yarn.lock" }}-<< pipeline.parameters.cache_version >> | ||||
|                   paths: | ||||
|                       - ~/repo | ||||
|                       - ~/project/node_modules | ||||
|                       - ~/.cache/yarn | ||||
|             - save_cache: | ||||
|                   key: lib-{{ .Environment.CIRCLE_SHA1 }}-<< pipeline.parameters.cache_version >> | ||||
|                   paths: | ||||
|                       - ~/project/contracts/erc20/generated-artifacts/ | ||||
|                       - ~/project/contracts/erc20/generated-wrappers/ | ||||
|                       - ~/project/contracts/erc20/lib/ | ||||
|                       - ~/project/contracts/erc20/node_modules | ||||
|                       - ~/project/contracts/erc20/test/generated-artifacts/ | ||||
|                       - ~/project/contracts/erc20/test/generated-wrappers/ | ||||
|                       - ~/project/contracts/test-utils/lib/ | ||||
|                       - ~/project/contracts/test-utils/node_modules | ||||
|                       - ~/project/contracts/treasury/generated-artifacts/ | ||||
|                       - ~/project/contracts/treasury/generated-wrappers/ | ||||
|                       - ~/project/contracts/treasury/lib/ | ||||
|                       - ~/project/contracts/treasury/node_modules | ||||
|                       - ~/project/contracts/treasury/test/generated-artifacts/ | ||||
|                       - ~/project/contracts/treasury/test/generated-wrappers/ | ||||
|                       - ~/project/contracts/utils/generated-artifacts/ | ||||
|                       - ~/project/contracts/utils/generated-wrappers/ | ||||
|                       - ~/project/contracts/utils/lib/ | ||||
|                       - ~/project/contracts/utils/node_modules | ||||
|                       - ~/project/contracts/utils/test/generated-artifacts/ | ||||
|                       - ~/project/contracts/utils/test/generated-wrappers/ | ||||
|                       - ~/project/contracts/zero-ex/generated-artifacts/ | ||||
|                       - ~/project/contracts/zero-ex/generated-wrappers/ | ||||
|                       - ~/project/contracts/zero-ex/lib/ | ||||
|                       - ~/project/contracts/zero-ex/node_modules | ||||
|                       - ~/project/contracts/zero-ex/test/generated-artifacts/ | ||||
|                       - ~/project/contracts/zero-ex/test/generated-wrappers/ | ||||
|                       - ~/project/packages/asset-swapper/node_modules | ||||
|                       - ~/project/packages/contract-addresses/lib/ | ||||
|                       - ~/project/packages/contract-addresses/node_modules | ||||
|                       - ~/project/packages/contract-artifacts/lib/ | ||||
|                       - ~/project/packages/contract-artifacts/node_modules | ||||
|                       - ~/project/packages/contract-wrappers/lib/ | ||||
|                       - ~/project/packages/contract-wrappers/node_modules | ||||
|                       - ~/project/packages/protocol-utils/lib/ | ||||
|                       - ~/project/packages/protocol-utils/node_modules | ||||
|             - store_artifacts: | ||||
|                   path: ~/repo/packages/abi-gen/test-cli/output | ||||
|             - store_artifacts: | ||||
|                   path: ~/repo/packages/contract-wrappers/generated_docs | ||||
|     test-contracts-ganache: | ||||
|         resource_class: medium+ | ||||
|     test-exchange-ganache: | ||||
|         resource_class: xlarge | ||||
|         docker: | ||||
|             - image: nikolaik/python-nodejs:python3.7-nodejs8 | ||||
|         working_directory: ~/repo | ||||
|             - image: node:16 | ||||
|         steps: | ||||
|             - checkout | ||||
|             - 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-staking | ||||
|     test-exchange-ganache-3.0: | ||||
|         resource_class: medium+ | ||||
|         docker: | ||||
|             - image: nikolaik/python-nodejs:python3.7-nodejs8 | ||||
|         working_directory: ~/repo | ||||
|         steps: | ||||
|                       - cache-{{ checksum "yarn.lock" }}-<< pipeline.parameters.cache_version >> | ||||
|             - restore_cache: | ||||
|                   keys: | ||||
|                       - repo-{{ .Environment.CIRCLE_SHA1 }} | ||||
|             - run: yarn wsrun test:circleci @0x/contracts-exchange | ||||
|     test-integrations-ganache-3.0: | ||||
|         resource_class: medium+ | ||||
|                       - lib-{{ .Environment.CIRCLE_SHA1 }}-<< pipeline.parameters.cache_version >> | ||||
|             - run: yarn wsrun -p @0x/contracts-exchange -m --serial -c test:circleci | ||||
|     test-integrations-ganache: | ||||
|         resource_class: xlarge | ||||
|         docker: | ||||
|             - image: nikolaik/python-nodejs:python3.7-nodejs8 | ||||
|         working_directory: ~/repo | ||||
|             - image: node:16 | ||||
|         steps: | ||||
|             - checkout | ||||
|             - restore_cache: | ||||
|                   keys: | ||||
|                       - repo-{{ .Environment.CIRCLE_SHA1 }} | ||||
|             - run: yarn wsrun test:circleci @0x/contracts-integrations | ||||
|     test-contracts-rest-ganache-3.0: | ||||
|         resource_class: medium+ | ||||
|         docker: | ||||
|             - image: nikolaik/python-nodejs:python3.7-nodejs8 | ||||
|         working_directory: ~/repo | ||||
|         steps: | ||||
|                       - cache-{{ checksum "yarn.lock" }}-<< pipeline.parameters.cache_version >> | ||||
|             - 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-staking @0x/contracts-coordinator @0x/contracts-erc20-bridge-sampler | ||||
|             # TODO(dorothy-zbornak): Re-enable after updating this package for | ||||
|             # 3.0. At that time, also remove exclusion from monorepo | ||||
|             # package.json's test script. | ||||
|             # - run: yarn wsrun test:circleci @0x/contracts-extensions | ||||
|                       - lib-{{ .Environment.CIRCLE_SHA1 }}-<< pipeline.parameters.cache_version >> | ||||
|             - run: yarn wsrun -p @0x/contracts-integrations -m --serial -c test:circleci | ||||
|     test-contracts-staking-ganache: | ||||
|         resource_class: xlarge | ||||
|         docker: | ||||
|             - image: node:16 | ||||
|         steps: | ||||
|             - checkout | ||||
|             - restore_cache: | ||||
|                   keys: | ||||
|                       - cache-{{ checksum "yarn.lock" }}-<< pipeline.parameters.cache_version >> | ||||
|                       - lib-{{ .Environment.CIRCLE_SHA1 }}-<< pipeline.parameters.cache_version >> | ||||
|             - run: yarn wsrun -p @0x/contracts-staking -m --serial -c test:circleci | ||||
|     test-contracts-extra-ganache: | ||||
|         resource_class: xlarge | ||||
|         docker: | ||||
|             - image: node:16 | ||||
|         steps: | ||||
|             - checkout | ||||
|             - restore_cache: | ||||
|                   keys: | ||||
|                       - cache-{{ checksum "yarn.lock" }} | ||||
|             - restore_cache: | ||||
|                   keys: | ||||
|                       - lib-{{ .Environment.CIRCLE_SHA1 }}-<< pipeline.parameters.cache_version >> | ||||
|             - run: yarn wsrun -p @0x/contracts-exchange-forwarder -p @0x/contracts-coordinator -m --serial -c test:circleci | ||||
|     test-contracts-rest-ganache: | ||||
|         resource_class: xlarge | ||||
|         docker: | ||||
|             - image: node:16 | ||||
|         steps: | ||||
|             - checkout | ||||
|             - run: | | ||||
|                   git diff --name-only development >> changed.txt | ||||
|                   if ! grep -q \.sol changed.txt; then | ||||
|                     circleci-agent step halt | ||||
|                   fi | ||||
|             - restore_cache: | ||||
|                   keys: | ||||
|                       - cache-{{ checksum "yarn.lock" }}-<< pipeline.parameters.cache_version >> | ||||
|             - restore_cache: | ||||
|                   keys: | ||||
|                       - lib-{{ .Environment.CIRCLE_SHA1 }}-<< pipeline.parameters.cache_version >> | ||||
|             - run: | | ||||
|                   yarn wsrun \ | ||||
|                     -p @0x/contracts-multisig \ | ||||
|                     -p @0x/contracts-utils \ | ||||
|                     -p @0x/contracts-exchange-libs \ | ||||
|                     -p @0x/contracts-erc20 \ | ||||
|                     -p @0x/contracts-erc721 \ | ||||
|                     -p @0x/contracts-erc1155 \ | ||||
|                     -p @0x/contracts-asset-proxy \ | ||||
|                     -p @0x/contracts-broker \ | ||||
|                     -p @0x/contracts-zero-ex \ | ||||
|                     -m --serial -c test:circleci | ||||
|     test-foundry: | ||||
|         resource_class: xlarge | ||||
|         docker: | ||||
|             - image: ghcr.io/foundry-rs/foundry:latest | ||||
|         steps: | ||||
|             - checkout | ||||
|             - run: | | ||||
|                   git diff --name-only development >> changed.txt | ||||
|                   cat changed.txt | ||||
|                   if ! grep -q \.sol changed.txt; then | ||||
|                     circleci-agent step halt | ||||
|                   fi | ||||
|             - restore_cache: | ||||
|                   keys: | ||||
|                       - cache-{{ checksum "yarn.lock" }}-<< pipeline.parameters.cache_version >> | ||||
|             - restore_cache: | ||||
|                   keys: | ||||
|                       - lib-{{ .Environment.CIRCLE_SHA1 }}-<< pipeline.parameters.cache_version >> | ||||
|             - run: git submodule update --init --recursive | ||||
|             - run: | ||||
|                   command: forge test | ||||
|                   working_directory: ~/project/contracts/zero-ex | ||||
|     test-publish: | ||||
|         resource_class: medium+ | ||||
|         resource_class: large | ||||
|         environment: | ||||
|             NODE_OPTIONS: '--max-old-space-size=6442' | ||||
|         docker: | ||||
|             - image: nikolaik/python-nodejs:python3.7-nodejs8 | ||||
|             - image: node:16 | ||||
|             - image: 0xorg/verdaccio | ||||
|         working_directory: ~/repo | ||||
|         steps: | ||||
|             - checkout | ||||
|             - run: | | ||||
|                   git diff --name-only development >> changed.txt | ||||
|                   cat changed.txt | ||||
|                   if ! grep -q packages/ changed.txt; then | ||||
|                     circleci-agent step halt | ||||
|                   fi | ||||
|             - restore_cache: | ||||
|                   keys: | ||||
|                       - repo-{{ .Environment.CIRCLE_SHA1 }} | ||||
|                       - cache-{{ checksum "yarn.lock" }}-<< pipeline.parameters.cache_version >> | ||||
|             - restore_cache: | ||||
|                   keys: | ||||
|                       - lib-{{ .Environment.CIRCLE_SHA1 }}-<< pipeline.parameters.cache_version >> | ||||
|             - run: | ||||
|                   command: yarn test:publish:circleci | ||||
|                   no_output_timeout: 1800 | ||||
|             - store_artifacts: | ||||
|                   path: ~/.npm/_logs | ||||
|     test-doc-generation: | ||||
|         docker: | ||||
|             - image: nikolaik/python-nodejs:python3.7-nodejs8 | ||||
|         working_directory: ~/repo | ||||
|             - image: node:16 | ||||
|         steps: | ||||
|             - checkout | ||||
|             - restore_cache: | ||||
|                   keys: | ||||
|                       - repo-{{ .Environment.CIRCLE_SHA1 }} | ||||
|                       - cache-{{ checksum "yarn.lock" }}-<< pipeline.parameters.cache_version >> | ||||
|             - restore_cache: | ||||
|                   keys: | ||||
|                       - lib-{{ .Environment.CIRCLE_SHA1 }}-<< pipeline.parameters.cache_version >> | ||||
|             - run: | ||||
|                   command: yarn test:generate_docs:circleci | ||||
|                   no_output_timeout: 1200 | ||||
|     test-rest: | ||||
|         docker: | ||||
|             - image: nikolaik/python-nodejs:python3.7-nodejs8 | ||||
|         working_directory: ~/repo | ||||
|             - image: node:16 | ||||
|         environment: | ||||
|             RUST_ROUTER: 'true' | ||||
|         steps: | ||||
|             - checkout | ||||
|             - restore_cache: | ||||
|                   keys: | ||||
|                       - 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-swapper | ||||
|             - 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 | ||||
|             - run: yarn wsrun test:circleci @0x/contract-wrappers-test | ||||
|             - run: yarn wsrun test:circleci @0x/dev-utils | ||||
|             - run: yarn wsrun test:circleci @0x/json-schemas | ||||
|             - run: yarn wsrun test:circleci @0x/order-utils | ||||
|             - run: yarn wsrun test:circleci @0x/orderbook | ||||
|             - run: yarn wsrun test:circleci @0x/sol-compiler | ||||
|             - run: yarn wsrun test:circleci @0x/sol-tracing-utils | ||||
|             - run: yarn wsrun test:circleci @0x/sol-doc | ||||
|             - run: yarn wsrun test:circleci @0x/subproviders | ||||
|             - run: yarn wsrun test:circleci @0x/web3-wrapper | ||||
|             - run: yarn wsrun test:circleci @0x/utils | ||||
|             - run: yarn wsrun test:circleci @0x/instant | ||||
|                       - cache-{{ checksum "yarn.lock" }}-<< pipeline.parameters.cache_version >> | ||||
|             - restore_cache: | ||||
|                   keys: | ||||
|                       - lib-{{ .Environment.CIRCLE_SHA1 }}-<< pipeline.parameters.cache_version >> | ||||
|             - run: yarn wsrun -p @0x/contracts-test-utils -m --serial -c test:circleci | ||||
|             - run: yarn wsrun -p @0x/contract-addresses -m --serial -c test:circleci | ||||
|             - run: yarn wsrun -p @0x/contract-artifacts -m --serial -c test:circleci | ||||
|             - run: yarn wsrun -p @0x/contract-wrappers-test -m --serial -c test:circleci | ||||
|             - run: yarn wsrun -p @0x/order-utils -m --serial -c test:circleci | ||||
|             - save_cache: | ||||
|                   key: coverage-abi-gen-{{ .Environment.CIRCLE_SHA1 }} | ||||
|                   paths: | ||||
|                       - ~/repo/packages/abi-gen/coverage/lcov.info | ||||
|             - save_cache: | ||||
|                   key: coverage-assert-{{ .Environment.CIRCLE_SHA1 }} | ||||
|                   paths: | ||||
|                       - ~/repo/packages/assert/coverage/lcov.info | ||||
|             - save_cache: | ||||
|                   key: coverage-asset-swapper-{{ .Environment.CIRCLE_SHA1 }} | ||||
|                   paths: | ||||
|                       - ~/repo/packages/asset-swapper/coverage/lcov.info | ||||
|             - save_cache: | ||||
|                   key: coverage-base-contract-{{ .Environment.CIRCLE_SHA1 }} | ||||
|                   paths: | ||||
|                       - ~/repo/packages/base-contract/coverage/lcov.info | ||||
|             - save_cache: | ||||
|                   key: coverage-connect-{{ .Environment.CIRCLE_SHA1 }} | ||||
|                   paths: | ||||
|                       - ~/repo/packages/connect/coverage/lcov.info | ||||
|             - save_cache: | ||||
|                   key: coverage-contract-wrappers-test-{{ .Environment.CIRCLE_SHA1 }} | ||||
|                   key: coverage-contract-wrappers-test-{{ checksum "yarn.lock" }} | ||||
|                   paths: | ||||
|                       - ~/repo/packages/contract-wrappers-test/coverage/lcov.info | ||||
|             - save_cache: | ||||
|                   key: coverage-dev-utils-{{ .Environment.CIRCLE_SHA1 }} | ||||
|                   paths: | ||||
|                       - ~/repo/packages/dev-utils/coverage/lcov.info | ||||
|             - save_cache: | ||||
|                   key: coverage-json-schemas-{{ .Environment.CIRCLE_SHA1 }} | ||||
|                   paths: | ||||
|                       - ~/repo/packages/json-schemas/coverage/lcov.info | ||||
|             - save_cache: | ||||
|                   key: coverage-order-utils-{{ .Environment.CIRCLE_SHA1 }} | ||||
|                   key: coverage-order-utils-{{ checksum "yarn.lock" }} | ||||
|                   paths: | ||||
|                       - ~/repo/packages/order-utils/coverage/lcov.info | ||||
|             - save_cache: | ||||
|                   key: coverage-sol-compiler-{{ .Environment.CIRCLE_SHA1 }} | ||||
|                   paths: | ||||
|                       - ~/repo/packages/sol-compiler/coverage/lcov.info | ||||
|             - save_cache: | ||||
|                   key: coverage-sol-tracing-utils-{{ .Environment.CIRCLE_SHA1 }} | ||||
|                   paths: | ||||
|                       - ~/repo/packages/sol-tracing-utils/coverage/lcov.info | ||||
|             - save_cache: | ||||
|                   key: coverage-sol-doc-{{ .Environment.CIRCLE_SHA1 }} | ||||
|                   paths: | ||||
|                       - ~/repo/packages/sol-doc/coverage/lcov.info | ||||
|             - save_cache: | ||||
|                   key: coverage-subproviders-{{ .Environment.CIRCLE_SHA1 }} | ||||
|                   paths: | ||||
|                       - ~/repo/packages/subproviders/coverage/lcov.info | ||||
|             - save_cache: | ||||
|                   key: coverage-web3-wrapper-{{ .Environment.CIRCLE_SHA1 }} | ||||
|                   key: coverage-web3-wrapper-{{ checksum "yarn.lock" }} | ||||
|                   paths: | ||||
|                       - ~/repo/packages/web3-wrapper/coverage/lcov.info | ||||
|     test-python: | ||||
|         working_directory: ~/repo | ||||
|         docker: | ||||
|             - image: nikolaik/python-nodejs:python3.7-nodejs8 | ||||
|             - image: 0xorg/ganache-cli:6.0.0 | ||||
|             - image: 0xorg/mesh:0xV3 | ||||
|               environment: | ||||
|                   ETHEREUM_RPC_URL: 'http://localhost:8545' | ||||
|                   ETHEREUM_CHAIN_ID: '1337' | ||||
|                   VERBOSITY: 5 | ||||
|                   BLOCK_POLLING_INTERVAL: '50ms' | ||||
|                   ETHEREUM_RPC_MAX_REQUESTS_PER_24_HR_UTC: '1778000' | ||||
|               command: | | ||||
|                   sh -c "waitForGanache () { until printf 'POST /\r\nContent-Length: 26\r\n\r\n{\"method\":\"net_listening\"}' | nc localhost 8545 | grep true; do continue; done }; waitForGanache && ./mesh" | ||||
|             - image: 0xorg/launch-kit-backend:v3 | ||||
|               environment: | ||||
|                   RPC_URL: 'http://localhost:8545' | ||||
|                   CHAIN_ID: 1337 | ||||
|                   WHITELIST_ALL_TOKENS: True | ||||
|                   FEE_RECIPIENT: '0x0000000000000000000000000000000000000001' | ||||
|                   MAKER_FEE_UNIT_AMOUNT: 0 | ||||
|                   TAKER_FEE_UNIT_AMOUNT: 0 | ||||
|                   MESH_ENDPOINT: 'ws://localhost:60557' | ||||
|               command: | | ||||
|                   sh -c "waitForMesh () { sleep 30; }; waitForMesh && node_modules/.bin/forever ts/lib/index.js" | ||||
|         steps: | ||||
|             - checkout | ||||
|             - restore_cache: | ||||
|                   key: installed-py-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }} | ||||
|             - restore_cache: | ||||
|                   keys: | ||||
|                       - repo-{{ .Environment.CIRCLE_SHA1 }} | ||||
|             - run: | ||||
|                   command: | | ||||
|                       cd python-packages | ||||
|                       python -m ensurepip | ||||
|                       ./pre_install | ||||
|                       ./install | ||||
|             - save_cache: | ||||
|                   key: installed-py-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }} | ||||
|                   paths: | ||||
|                       - '/usr/local/bin' | ||||
|                       - '/usr/local/lib/python3.7/site-packages' | ||||
|             - run: | ||||
|                   command: | | ||||
|                       cd python-packages | ||||
|                       ./parallel coverage run setup.py test | ||||
|                       ./build_docs | ||||
|             - run: | ||||
|                   command: | | ||||
|                       # copy generated wrappers into contract_wrappers/build, | ||||
|                       # JUST so CircleCI will persist them as build artifacts. | ||||
|                       cd python-packages/contract_wrappers/src/zero_ex | ||||
|                       for i in contract_wrappers/[^__]*/; do mkdir -p ../../build/$i; cp $i/__init__.py ../../build/$i; done | ||||
|             - save_cache: | ||||
|                   key: coverage-python-contract-addresses-{{ .Environment.CIRCLE_SHA1 }} | ||||
|                   paths: | ||||
|                       - ~/repo/python-packages/contract_addresses/.coverage | ||||
|             - save_cache: | ||||
|                   key: coverage-python-contract-artifacts-{{ .Environment.CIRCLE_SHA1 }} | ||||
|                   paths: | ||||
|                       - ~/repo/python-packages/contract_artifacts/.coverage | ||||
|             - save_cache: | ||||
|                   key: coverage-python-contract-demo-{{ .Environment.CIRCLE_SHA1 }} | ||||
|                   paths: | ||||
|                       - ~/repo/python-packages/contract_demo/.coverage | ||||
|             - save_cache: | ||||
|                   key: coverage-python-json-schemas-{{ .Environment.CIRCLE_SHA1 }} | ||||
|                   paths: | ||||
|                       - ~/repo/python-packages/json_schemas/.coverage | ||||
|             - save_cache: | ||||
|                   key: coverage-python-order-utils-{{ .Environment.CIRCLE_SHA1 }} | ||||
|                   paths: | ||||
|                       - ~/repo/python-packages/order_utils/.coverage | ||||
|             - save_cache: | ||||
|                   key: coverage-python-sra-client-{{ .Environment.CIRCLE_SHA1 }} | ||||
|                   paths: | ||||
|                       - ~/repo/python-packages/sra_client/.coverage | ||||
|             - store_artifacts: | ||||
|                   path: ~/repo/python-packages/contract_addresses/build | ||||
|             - store_artifacts: | ||||
|                   path: ~/repo/python-packages/contract_artifacts/build | ||||
|             - store_artifacts: | ||||
|                   path: ~/repo/python-packages/contract_wrappers/build | ||||
|             - store_artifacts: | ||||
|                   path: ~/repo/python-packages/json_schemas/build | ||||
|             - store_artifacts: | ||||
|                   path: ~/repo/python-packages/middlewares/build | ||||
|             - store_artifacts: | ||||
|                   path: ~/repo/python-packages/order_utils/build | ||||
|             - store_artifacts: | ||||
|                   path: ~/repo/python-packages/sra_client/build | ||||
|     test-rest-python: | ||||
|         working_directory: ~/repo | ||||
|         docker: | ||||
|             - image: nikolaik/python-nodejs:python3.7-nodejs8 | ||||
|         steps: | ||||
|             - checkout | ||||
|             - restore_cache: | ||||
|                   key: installed-py-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }} | ||||
|             - run: | ||||
|                   command: | | ||||
|                       cd python-packages/order_utils | ||||
|                       python -m ensurepip | ||||
|                       python -m pip install . | ||||
|             - save_cache: | ||||
|                   key: installed-py-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }} | ||||
|                   paths: | ||||
|                       - '/usr/local/bin' | ||||
|                       - '/usr/local/lib/python3.7/site-packages' | ||||
|                       - '.eggs' | ||||
|                       - '.mypy_cache' | ||||
|                       - '.pytest_cache' | ||||
|                       - '.tox' | ||||
|             - run: | ||||
|                   command: | | ||||
|                       cd python-packages/order_utils | ||||
|                       tox | ||||
|     static-tests-python: | ||||
|         working_directory: ~/repo | ||||
|         docker: | ||||
|             - image: nikolaik/python-nodejs:python3.7-nodejs8 | ||||
|         steps: | ||||
|             - checkout | ||||
|             - restore_cache: | ||||
|                   key: installed-py-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }} | ||||
|             - restore_cache: | ||||
|                   keys: | ||||
|                       - repo-{{ .Environment.CIRCLE_SHA1 }} | ||||
|             - run: | ||||
|                   command: | | ||||
|                       python -m ensurepip | ||||
|                       cd python-packages | ||||
|                       ./pre_install | ||||
|                       ./install | ||||
|                       ./lint | ||||
|     static-tests: | ||||
|         resource_class: large | ||||
|         working_directory: ~/repo | ||||
|         docker: | ||||
|             - image: nikolaik/python-nodejs:python3.7-nodejs8 | ||||
|             - image: node:16 | ||||
|         steps: | ||||
|             - checkout | ||||
|             - restore_cache: | ||||
|                   keys: | ||||
|                       - repo-{{ .Environment.CIRCLE_SHA1 }} | ||||
|             - run: yarn lerna run lint | ||||
|             - run: yarn prettier:ci | ||||
|             - run: yarn deps_versions:ci | ||||
|             - run: yarn diff_md_docs:ci | ||||
|             - run: cd packages/0x.js && yarn build:umd:prod | ||||
|             - run: yarn bundlewatch | ||||
|                       - cache-{{ checksum "yarn.lock" }}-<< pipeline.parameters.cache_version >> | ||||
|             - restore_cache: | ||||
|                   keys: | ||||
|                       - lib-{{ .Environment.CIRCLE_SHA1 }}-<< pipeline.parameters.cache_version >> | ||||
|             - run: | ||||
|                   command: yarn lerna run lint | ||||
|             - run: | ||||
|                   command: yarn prettier:ci | ||||
|             - run: | ||||
|                   command: yarn deps_versions:ci | ||||
|             - run: | ||||
|                   command: yarn diff_md_docs:ci | ||||
|     submit-coverage: | ||||
|         docker: | ||||
|             - image: nikolaik/python-nodejs:python3.7-nodejs8 | ||||
|         working_directory: ~/repo | ||||
|             - image: node:16 | ||||
|         steps: | ||||
|             - restore_cache: | ||||
|                   keys: | ||||
|                       - repo-{{ .Environment.CIRCLE_SHA1 }} | ||||
|                       - cache-{{ checksum "yarn.lock" }}-<< pipeline.parameters.cache_version >> | ||||
|             - restore_cache: | ||||
|                   keys: | ||||
|                       - coverage-abi-gen-{{ .Environment.CIRCLE_SHA1 }} | ||||
|                       - lib-{{ .Environment.CIRCLE_SHA1 }}-<< pipeline.parameters.cache_version >> | ||||
|             - restore_cache: | ||||
|                   keys: | ||||
|                       - coverage-assert-{{ .Environment.CIRCLE_SHA1 }} | ||||
|                       - coverage-contract-wrappers-test-{{ checksum "yarn.lock" }} | ||||
|             - restore_cache: | ||||
|                   keys: | ||||
|                       - coverage-asset-swapper-{{ .Environment.CIRCLE_SHA1 }} | ||||
|                       - coverage-order-utils-{{ checksum "yarn.lock" }} | ||||
|             - restore_cache: | ||||
|                   keys: | ||||
|                       - coverage-base-contract-{{ .Environment.CIRCLE_SHA1 }} | ||||
|             - restore_cache: | ||||
|                   keys: | ||||
|                       - coverage-connect-{{ .Environment.CIRCLE_SHA1 }} | ||||
|             - restore_cache: | ||||
|                   keys: | ||||
|                       - coverage-contract-wrappers-test-{{ .Environment.CIRCLE_SHA1 }} | ||||
|             - restore_cache: | ||||
|                   keys: | ||||
|                       - coverage-dev-utils-{{ .Environment.CIRCLE_SHA1 }} | ||||
|             - restore_cache: | ||||
|                   keys: | ||||
|                       - coverage-json-schemas-{{ .Environment.CIRCLE_SHA1 }} | ||||
|             - restore_cache: | ||||
|                   keys: | ||||
|                       - coverage-order-utils-{{ .Environment.CIRCLE_SHA1 }} | ||||
|             - restore_cache: | ||||
|                   keys: | ||||
|                       - coverage-sol-compiler-{{ .Environment.CIRCLE_SHA1 }} | ||||
|             - restore_cache: | ||||
|                   keys: | ||||
|                       - coverage-sol-tracing-utils-{{ .Environment.CIRCLE_SHA1 }} | ||||
|             - restore_cache: | ||||
|                   keys: | ||||
|                       - coverage-sol-doc-{{ .Environment.CIRCLE_SHA1 }} | ||||
|             - restore_cache: | ||||
|                   keys: | ||||
|                       - coverage-subproviders-{{ .Environment.CIRCLE_SHA1 }} | ||||
|             - restore_cache: | ||||
|                   keys: | ||||
|                       - coverage-web3-wrapper-{{ .Environment.CIRCLE_SHA1 }} | ||||
|             - restore_cache: | ||||
|                   keys: | ||||
|                       - coverage-contracts-{{ .Environment.CIRCLE_SHA1 }} | ||||
|             - restore_cache: | ||||
|                   keys: | ||||
|                       - coverage-python-json-schemas-{{ .Environment.CIRCLE_SHA1 }} | ||||
|             - restore_cache: | ||||
|                   keys: | ||||
|                       - coverage-python-contract-addresses-{{ .Environment.CIRCLE_SHA1 }} | ||||
|             - restore_cache: | ||||
|                   keys: | ||||
|                       - coverage-python-contract-artifacts-{{ .Environment.CIRCLE_SHA1 }} | ||||
|             - restore_cache: | ||||
|                   keys: | ||||
|                       - coverage-python-contract-demo-{{ .Environment.CIRCLE_SHA1 }} | ||||
|             - restore_cache: | ||||
|                   keys: | ||||
|                       - coverage-python-sra-client-{{ .Environment.CIRCLE_SHA1 }} | ||||
|             - restore_cache: | ||||
|                   keys: | ||||
|                       - coverage-python-order-utils-{{ .Environment.CIRCLE_SHA1 }} | ||||
|                       - coverage-contracts-{{ checksum "yarn.lock" }} | ||||
|             - run: yarn report_coverage | ||||
| workflows: | ||||
|     version: 2 | ||||
|     main: | ||||
|         jobs: | ||||
|             - build | ||||
|             - test-exchange-ganache-3.0: | ||||
|             # Disabled until we begin actively developing on these packages again. | ||||
|             # - test-exchange-ganache: | ||||
|             #       requires: | ||||
|             #           - build | ||||
|             # - test-integrations-ganache: | ||||
|             #       requires: | ||||
|             #           - build | ||||
|             # - test-contracts-staking-ganache: | ||||
|             #       requires: | ||||
|             #           - build | ||||
|             # - test-contracts-extra-ganache: | ||||
|             #       requires: | ||||
|             #           - build | ||||
|             - test-foundry: | ||||
|                   requires: | ||||
|                       - build | ||||
|             - test-integrations-ganache-3.0: | ||||
|                   requires: | ||||
|                       - build | ||||
|             - test-contracts-rest-ganache-3.0: | ||||
|             - test-contracts-rest-ganache: | ||||
|                   requires: | ||||
|                       - build | ||||
|             - test-rest: | ||||
| @@ -438,17 +324,14 @@ workflows: | ||||
|             - test-doc-generation: | ||||
|                   requires: | ||||
|                       - build | ||||
|             - submit-coverage: | ||||
|                   requires: | ||||
|                       - test-contracts-rest-ganache-3.0 | ||||
|                       - test-exchange-ganache-3.0 | ||||
|                       - test-rest | ||||
|                       - static-tests | ||||
|             - test-python: | ||||
|                   requires: | ||||
|                       - build | ||||
|             - static-tests-python: | ||||
|                   requires: | ||||
|                       - build | ||||
|             # skip python tox run for now, as we don't yet have multiple test environments to support. | ||||
|             # - test-rest-python | ||||
|             # Disabled until this repo has a coveralls API key | ||||
|             # - submit-coverage: | ||||
|             #       requires: | ||||
|             #           # Disabled until we begin actively developing on these packages again. | ||||
|             #           # - test-exchange-ganache | ||||
|             #           # - test-integrations-ganache | ||||
|             #           # - test-contracts-staking-ganache | ||||
|             #           # - test-contracts-extra-ganache | ||||
|             #           - test-contracts-rest-ganache | ||||
|             #           - test-rest | ||||
|             #           - static-tests | ||||
|   | ||||
							
								
								
									
										4
									
								
								.gitattributes
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.gitattributes
									
									
									
									
										vendored
									
									
								
							| @@ -2,7 +2,3 @@ | ||||
|  | ||||
| # Automatically collapse generated files in GitHub. | ||||
| *.svg linguist-generated=true | ||||
| packages/contract-artifacts/artifacts/*json linguist-generated=true | ||||
| packages/abi-gen-wrappers/src/generated-wrappers/*.ts linguist-generated=true | ||||
| packages/contract-wrappers/src/generated-wrappers/*.ts linguist-generated=true | ||||
|  | ||||
|   | ||||
							
								
								
									
										27
									
								
								.github/autolabeler.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										27
									
								
								.github/autolabeler.yml
									
									
									
									
										vendored
									
									
								
							| @@ -1,33 +1,6 @@ | ||||
| python: ['python-packages'] | ||||
| contracts: ['contracts'] | ||||
| @0x/sol-doc: ['packages/sol-doc'] | ||||
| @0x/sol-resolver: ['packages/sol-resolver'] | ||||
| @0x/contracts-gen: ['packages/contracts-gen'] | ||||
| @0x/sra-spec: ['packages/sra-spec'] | ||||
| @0x/subproviders: ['packages/subproviders'] | ||||
| @0x/contract-addresses: ['packages/contract-addresses'] | ||||
| @0x/migrations: ['packages/migrations'] | ||||
| @0x/web3-wrapper: ['packages/web3-wrapper'] | ||||
| @0x/sol-compiler: ['packages/sol-compiler'] | ||||
| @0x/types: ['packages/types'] | ||||
| @0x/instant: ['packages/instant'] | ||||
| @0x/abi-gen-templates: ['packages/abi-gen-templates'] | ||||
| @0x/abi-gen: ['packages/abi-gen'] | ||||
| @0x/sol-coverage: ['packages/sol-coverage'] | ||||
| @0x/sol-profiler: ['packages/sol-profiler'] | ||||
| @0x/sol-trace: ['packages/sol-trace'] | ||||
| @0x/sol-tracing-utils: ['packages/sol-tracing-utils'] | ||||
| @0x/utils: ['packages/utils'] | ||||
| @0x/tslint-config: ['packages/tslint-config'] | ||||
| @0x/asset-swapper: ['packages/asset-swapper'] | ||||
| @0x/order-utils: ['packages/order-utils'] | ||||
| @0x/assert: ['packages/assert'] | ||||
| @0x/base-contract: ['packages/base-contract'] | ||||
| @0x/typescript-typings: ['packages/typescript-typings'] | ||||
| 0x.js: ['packages/0x.js'] | ||||
| @0x/contract-artifacts: ['packages/contract-artifacts'] | ||||
| @0x/dev-utils: ['packages/dev-utils'] | ||||
| @0x/contract-wrappers: ['packages/contract-wrappers'] | ||||
| @0x/json-schemas: ['packages/json-schemas'] | ||||
| @0x/ethereum-types: ['ethereum-types'] | ||||
| @0x/connect: ['packages/connect'] | ||||
|   | ||||
							
								
								
									
										53
									
								
								.github/workflows/publish.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								.github/workflows/publish.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,53 @@ | ||||
| name: publish | ||||
|  | ||||
| on: | ||||
|   workflow_dispatch: | ||||
|       inputs: | ||||
|           ci_status: | ||||
|               description: 'required CI status' | ||||
|               default: 'success' | ||||
|               required: true | ||||
|           prerelease: | ||||
|               description: 'prerelease name' | ||||
|               required: false | ||||
|  | ||||
| jobs: | ||||
|     publish: | ||||
|         runs-on: ubuntu-latest | ||||
|         steps: | ||||
|             - name: 'check successful status' | ||||
|               run: | | ||||
|                   REF_STATUS=$(curl -s \ | ||||
|                   'https://api.github.com/repos/${{ github.repository }}/commits/${{ github.ref }}/status' \ | ||||
|                   | jq .state) | ||||
|                   [[ "${REF_STATUS}" == '"${{ github.event.inputs.ci_status }}"' ]] || \ | ||||
|                   (echo "::error ::${{ github.ref }} does not have a successful CI status" && false) | ||||
|             - uses: actions/checkout@v2 | ||||
|               with: | ||||
|                 ref: ${{ github.ref }} | ||||
|                 fetch-depth: 0 | ||||
|             - uses: actions/setup-node@v1 | ||||
|               with: | ||||
|                 node-version: 16 | ||||
|             - uses: actions/setup-python@v2 | ||||
|             - name: 'configure git' | ||||
|               run: | | ||||
|                   git config --global user.email "github-actions@github.com" | ||||
|                   git config --global user.name "Github Actions" | ||||
|             - name: 'install dependencies' | ||||
|               run: | | ||||
|                   yarn -D | ||||
|             - name: 'build and publish' | ||||
|               run: | | ||||
|                   echo '//registry.npmjs.org/:_authToken=${NPM_TOKEN}' > .npmrc | ||||
|                   npm run run:publish:gha | ||||
|               env: | ||||
|                   NPM_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }} | ||||
|                   GITHUB_TOKEN: ${{ github.token }} | ||||
|                   PUBLISH_PRERELEASE: ${{ github.event.inputs.prerelease }} | ||||
|             - name: 'merge into main branch' | ||||
|               if: github.event.inputs.prerelease == '' # unless it's a prerelease | ||||
|               run: | | ||||
|                   git checkout main && \ | ||||
|                   git merge ${{ github.ref }} && \ | ||||
|                   git push | ||||
							
								
								
									
										34
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										34
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -75,8 +75,9 @@ generated_docs/ | ||||
|  | ||||
| TODO.md | ||||
|  | ||||
| # VSCode file | ||||
| # IDE file | ||||
| .vscode | ||||
| .idea | ||||
|  | ||||
| # generated contract artifacts/ | ||||
| contracts/broker/generated-artifacts/ | ||||
| @@ -111,8 +112,10 @@ contracts/exchange-forwarder/generated-artifacts/ | ||||
| contracts/exchange-forwarder/test/generated-artifacts/ | ||||
| contracts/dev-utils/generated-artifacts/ | ||||
| contracts/dev-utils/test/generated-artifacts/ | ||||
| packages/sol-tracing-utils/test/fixtures/artifacts/ | ||||
| python-packages/contract_artifacts/src/zero_ex/contract_artifacts/artifacts/ | ||||
| contracts/zero-ex/generated-artifacts/ | ||||
| contracts/zero-ex/test/generated-artifacts/ | ||||
| contracts/treasury/generated-artifacts/ | ||||
| contracts/treasury/test/generated-artifacts/ | ||||
|  | ||||
| # generated truffle contract artifacts/ | ||||
| contracts/broker/build/ | ||||
| @@ -165,24 +168,19 @@ contracts/exchange-forwarder/generated-wrappers/ | ||||
| contracts/exchange-forwarder/test/generated-wrappers/ | ||||
| contracts/dev-utils/generated-wrappers/ | ||||
| contracts/dev-utils/test/generated-wrappers/ | ||||
| python-packages/contract_wrappers/src/zero_ex/contract_wrappers/*/__init__.py | ||||
| contracts/zero-ex/generated-wrappers/ | ||||
| contracts/zero-ex/test/generated-wrappers/ | ||||
| contracts/treasury/generated-wrappers/ | ||||
| contracts/treasury/test/generated-wrappers/ | ||||
|  | ||||
| # solc-bin in sol-compiler | ||||
| packages/sol-compiler/solc_bin/ | ||||
| # foundry artifacts | ||||
| contracts/zero-ex/foundry-artifacts/ | ||||
|  | ||||
| # python stuff | ||||
| .eggs | ||||
| .mypy_cache | ||||
| .tox | ||||
| python-packages/*/build | ||||
| python-packages/*/dist | ||||
| __pycache__ | ||||
| python-packages/*/src/*.egg-info | ||||
| python-packages/*/.coverage | ||||
| # foundry cache  | ||||
| contracts/zero-ex/foundry-cache/ | ||||
|  | ||||
| # python keeps package-local copies of json schemas and contract addresses | ||||
| python-packages/json_schemas/src/zero_ex/json_schemas/schemas | ||||
| python-packages/contract_addresses/src/zero_ex/contract_addresses/addresses.json | ||||
| # typechain wrappers | ||||
| contracts/zero-ex/typechain-wrappers/ | ||||
|  | ||||
| # Doc README copy | ||||
| packages/*/docs/README.md | ||||
|   | ||||
							
								
								
									
										3
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| [submodule "contracts/zero-ex/contracts/deps/forge-std"] | ||||
| 	path = contracts/zero-ex/contracts/deps/forge-std | ||||
| 	url = https://github.com/foundry-rs/forge-std | ||||
| @@ -40,10 +40,6 @@ lib | ||||
| /contracts/erc20/test/generated-wrappers | ||||
| /contracts/erc20/generated-artifacts | ||||
| /contracts/erc20/test/generated-artifacts | ||||
| /contracts/erc20-bridge-sampler/generated-wrappers | ||||
| /contracts/erc20-bridge-sampler/test/generated-wrappers | ||||
| /contracts/erc20-bridge-sampler/generated-artifacts | ||||
| /contracts/erc20-bridge-sampler/test/generated-artifacts | ||||
| /contracts/erc721/generated-wrappers | ||||
| /contracts/erc721/test/generated-wrappers | ||||
| /contracts/erc721/generated-artifacts | ||||
| @@ -64,6 +60,14 @@ lib | ||||
| /contracts/dev-utils/test/generated-wrappers | ||||
| /contracts/dev-utils/generated-artifacts | ||||
| /contracts/dev-utils/test/generated-artifacts | ||||
| /contracts/zero-ex/generated-wrappers | ||||
| /contracts/zero-ex/test/generated-wrappers | ||||
| /contracts/zero-ex/generated-artifacts | ||||
| /contracts/zero-ex/test/generated-artifacts | ||||
| /contracts/treasury/generated-wrappers | ||||
| /contracts/treasury/test/generated-wrappers | ||||
| /contracts/treasury/generated-artifacts | ||||
| /contracts/treasury/test/generated-artifacts | ||||
| /contracts/staking/build/ | ||||
| /contracts/coordinator/build/ | ||||
| /contracts/exchange/build/ | ||||
| @@ -76,19 +80,8 @@ lib | ||||
| /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/asset-swapper/ | ||||
| /packages/contract-wrappers/src/generated-wrappers/ | ||||
| package.json | ||||
| scripts/postpublish_utils.js | ||||
| packages/sol-coverage/test/fixtures/artifacts | ||||
| .pytest_cache | ||||
| .mypy_cache | ||||
| .tox | ||||
| packages/abi-gen/test-cli/fixtures/artifacts/AbiGenDummy.json | ||||
| packages/abi-gen/test-cli/fixtures/artifacts/LibDummy.json | ||||
| packages/abi-gen/test-cli/fixtures/artifacts/TestLibDummy.json | ||||
| packages/*/docs | ||||
| *.sol | ||||
| docs/ | ||||
|   | ||||
							
								
								
									
										16
									
								
								.prettierrc
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								.prettierrc
									
									
									
									
									
								
							| @@ -2,5 +2,19 @@ | ||||
|     "printWidth": 120, | ||||
|     "tabWidth": 4, | ||||
|     "singleQuote": true, | ||||
|     "trailingComma": "all" | ||||
|     "trailingComma": "all", | ||||
|     "bracketSpacing": true, | ||||
|     "arrowParens": "avoid", | ||||
|     "overrides": [ | ||||
|         { | ||||
|           "files": "**/*.sol", | ||||
|           "options": { | ||||
|             "printWidth": 120, | ||||
|             "tabWidth": 4, | ||||
|             "useTabs": false, | ||||
|             "singleQuote": false, | ||||
|             "bracketSpacing": false | ||||
|           } | ||||
|         } | ||||
|       ] | ||||
| } | ||||
|   | ||||
							
								
								
									
										23
									
								
								.readthedocs.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								.readthedocs.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| # Read the Docs configuration file | ||||
| # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details | ||||
|  | ||||
| # Required | ||||
| version: 2 | ||||
|  | ||||
| # Build documentation in the docs/ directory with Sphinx | ||||
| sphinx: | ||||
|   configuration: docs/conf.py | ||||
|  | ||||
| # Build documentation with MkDocs | ||||
| #mkdocs: | ||||
| #  configuration: mkdocs.yml | ||||
|  | ||||
| # Optionally build your docs in additional formats such as PDF | ||||
| #formats: | ||||
| #  - pdf | ||||
|  | ||||
| # Optionally set the version of Python and requirements required to build your docs | ||||
| python: | ||||
|   version: 3.7 | ||||
|   install: | ||||
|     - requirements: docs/requirements.txt | ||||
							
								
								
									
										38
									
								
								CODEOWNERS
									
									
									
									
									
								
							
							
						
						
									
										38
									
								
								CODEOWNERS
									
									
									
									
									
								
							| @@ -1,38 +1,20 @@ | ||||
| # See https://help.github.com/articles/about-codeowners/ | ||||
|  | ||||
| # for more info about CODEOWNERS file | ||||
|  | ||||
| # It uses the same pattern rule for gitignore file | ||||
|  | ||||
| # https://git-scm.com/docs/gitignore#_pattern_format | ||||
|  | ||||
| # Website | ||||
| packages/asset-swapper/  @BMillman19 @fragosti @dave4506 | ||||
| packages/instant/  @BMillman19 @fragosti @dave4506 | ||||
| packages/asset-swapper/ @dekz @dextracker @kyu-c | ||||
|  | ||||
| # Dev tools & setup | ||||
| .circleci/ @LogvinovLeon | ||||
| packages/abi-gen/ @feuGeneA | ||||
| packages/base-contract/ @xianny | ||||
| packages/connect/ @fragosti  | ||||
| packages/abi-gen-templates/ @feuGeneA @xianny | ||||
| packages/contract-addresses/ @abandeali1 | ||||
| packages/contract-artifacts/ @abandeali1 | ||||
| packages/dev-utils/ @LogvinovLeon @fabioberger | ||||
| packages/devnet/ @albrow | ||||
| packages/ethereum-types/ @LogvinovLeon | ||||
| packages/monorepo-scripts/ @fabioberger | ||||
| packages/order-utils/ @fabioberger @LogvinovLeon  | ||||
| packages/python-contract-wrappers/ @feuGeneA | ||||
| packages/sol-compiler/ @LogvinovLeon | ||||
| packages/sol-coverage/ @LogvinovLeon | ||||
| packages/sol-profiler/ @LogvinovLeon | ||||
| packages/sol-trace/ @LogvinovLeon | ||||
| packages/sol-tracing-utils/ @LogvinovLeon | ||||
| packages/sol-resolver/ @LogvinovLeon | ||||
| packages/subproviders/ @fabioberger @dekz | ||||
| packages/verdaccio/ @albrow | ||||
| packages/web3-wrapper/ @LogvinovLeon @fabioberger | ||||
| python-packages/ @feuGeneA | ||||
| packages/utils/ @hysz | ||||
|  | ||||
| .circleci/ @dekz | ||||
| packages/contract-addresses/ @dekz @dextracker @kyu-c | ||||
| packages/contract-artifacts/ @dekz | ||||
| packages/protocol-utils/ @dekz | ||||
|  | ||||
| # Protocol/smart contracts | ||||
| contracts/ @abandeali1 @hysz | ||||
|  | ||||
| contracts/ @dekz @dextracker | ||||
|   | ||||
| @@ -4,9 +4,9 @@ We welcome contributions from anyone on the internet and are grateful for even t | ||||
|  | ||||
| ### Getting started | ||||
|  | ||||
| 1.  Fork `0xproject/0x-monorepo` | ||||
| 1.  Fork `0xproject/0x-tools` | ||||
| 2.  Clone your fork | ||||
| 3.  Follow the [installation & build steps](https://github.com/0xProject/0x-monorepo#install-dependencies) in the repo's top-level README. | ||||
| 3.  Follow the [installation & build steps](https://github.com/0xProject/0x-tools#install-dependencies) in the repo's top-level README. | ||||
| 4.  Setup the recommended [Development Tooling](#development-tooling). | ||||
| 5.  Open a PR with the `[WIP]` flag against the `development` branch and describe the change you are intending to undertake in the PR description. (see [our branch naming conventions](#branch-structure)) | ||||
|  | ||||
| @@ -59,11 +59,11 @@ We strongly recommend you use the [VSCode](https://code.visualstudio.com/) text | ||||
|  | ||||
| #### Linter | ||||
|  | ||||
| We use [TSLint](https://palantir.github.io/tslint/) with [custom configs](https://github.com/0xProject/0x-monorepo/tree/development/packages/tslint-config) to keep our code-style consistent. | ||||
| We use [TSLint](https://palantir.github.io/tslint/) with [custom configs](https://github.com/0xProject/0x-tools/tree/development/packages/tslint-config) to keep our code-style consistent. | ||||
|  | ||||
| Use `yarn:lint` to lint the entire monorepo, and `PKG={PACKAGE_NAME} yarn lint` to lint a specific package. | ||||
|  | ||||
| If you want to change a rule, or add a custom rule, please make these changes to our [tslint-config](https://github.com/0xProject/0x-monorepo/tree/development/packages/tslint-config) package. All other packages have it as a dependency. | ||||
| If you want to change a rule, or add a custom rule, please make these changes to our [tslint-config](https://github.com/0xProject/0x-tools/tree/development/packages/tslint-config) package. All other packages have it as a dependency. | ||||
|  | ||||
| Integrate it into your text editor: | ||||
|  | ||||
| @@ -94,12 +94,12 @@ A few of our coding conventions are not yet enforced by the linter/auto-formatte | ||||
|  | ||||
| ### Fix `submit-coverage` CI failure | ||||
|  | ||||
| If you simply fork the repo and then create a PR from it, your PR will fail the `submit-coverage` check on CI. This is because the 0x CircleCI configuration sets the `COVERALLS_REPO_TOKEN` environment variable to the token for `0xProject/0x-monorepo`, but when running the check against your fork the token needs to match your repo's name `your-username/0x-monorepo`. | ||||
| If you simply fork the repo and then create a PR from it, your PR will fail the `submit-coverage` check on CI. This is because the 0x CircleCI configuration sets the `COVERALLS_REPO_TOKEN` environment variable to the token for `0xProject/0x-tools`, but when running the check against your fork the token needs to match your repo's name `your-username/0x-tools`. | ||||
|  | ||||
| To facilitate this check, after creating your fork, but before creating the branch for your PR, do the following: | ||||
|  | ||||
| 1.  Log in to [coveralls.io](https://coveralls.io/), go to `Add Repos`, and enable your fork. Then go to the settings for that repo, and copy the `Repo Token` identifier. | ||||
| 2.  Log in to [CircleCI](https://circleci.com/login), go to `Add Projects`, click the `Set Up Project` button corresponding to your fork, and then click `Start Building`. (Aside from step 3 below, no actual set up is needed, since it will use the `.circleci/config.yml` file in 0x-monorepo, so you can ignore all of the instruction/explanation given on the page with the `Start Building` button.) | ||||
| 2.  Log in to [CircleCI](https://circleci.com/login), go to `Add Projects`, click the `Set Up Project` button corresponding to your fork, and then click `Start Building`. (Aside from step 3 below, no actual set up is needed, since it will use the `.circleci/config.yml` file in 0x-tools, so you can ignore all of the instruction/explanation given on the page with the `Start Building` button.) | ||||
| 3.  In CircleCI, configure your project to add an environment variable, with name `COVERALLS_REPO_TOKEN`, and for the value paste in the `Repo Token` you copied in step 1. | ||||
|  | ||||
| Now, when you push to your branch, CircleCI will automatically run all of the checks in your own instance, and the coverage check will work since it has the proper `Repo Token`, and the PR will magically refer to your own checks rather than running them in the 0x CircleCI instance. | ||||
|   | ||||
| @@ -49,7 +49,6 @@ | ||||
| | Package | Version | | ||||
| | ------: | :------ | | ||||
|  | ||||
|  | ||||
| <!-- For example: | ||||
| |             `0x.js` | 2.0.4   | | ||||
| | `Exchange Contract` | v2      | | ||||
|   | ||||
							
								
								
									
										2
									
								
								LICENSE
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								LICENSE
									
									
									
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| Copyright 2017 ZeroEx Intl. | ||||
| Copyright 2020 ZeroEx Labs | ||||
|  | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
|   | ||||
							
								
								
									
										103
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										103
									
								
								README.md
									
									
									
									
									
								
							| @@ -2,101 +2,42 @@ | ||||
|  | ||||
| --- | ||||
|  | ||||
| [0x][website-url] is an open protocol that facilitates trustless, low friction exchange of Ethereum-based assets. For more information on how it works, check out the [0x protocol specification](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md). | ||||
| [0x][website-url] is an open protocol that facilitates trustless, low friction exchange of Ethereum-based assets. For more information on how it works, check out the [0x protocol specification](https://protocol.0x.org/). | ||||
|  | ||||
| This repository is a monorepo including the 0x protocol smart contracts and numerous developer tools. Each public sub-package is independently published to NPM. | ||||
|  | ||||
| [website-url]: https://0x.org | ||||
|  | ||||
| [](https://circleci.com/gh/0xProject/0x-monorepo) | ||||
| [](https://circleci.com/gh/0xProject/protocool) | ||||
| [](https://coveralls.io/github/0xProject/0x-monorepo?branch=development) | ||||
| [](https://discordapp.com/invite/d3FTX3M) | ||||
| [](https://opensource.org/licenses/Apache-2.0) | ||||
|  | ||||
| ## Packages | ||||
|  | ||||
| Visit our [developer portal](https://0x.org/docs/tools/order-utils) for a comprehensive list of core & community maintained packages. All packages maintained with this monorepo are listed below. | ||||
|  | ||||
| ### Python Packages | ||||
|  | ||||
| | Package                                                        | Version                                                                                                             | Description                                                                                       | | ||||
| | -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | | ||||
| | [`0x-contract-addresses`](/python-packages/contract_addresses) | [](https://pypi.org/project/0x-contract-addresses/) | A tiny utility library for getting known deployed contract addresses for a particular network     | | ||||
| | [`0x-contract-artifacts`](/python-packages/contract_artifacts) | [](https://pypi.org/project/0x-contract-artifacts/) | 0x smart contract compilation artifacts                                                           | | ||||
| | [`0x-contract-wrappers`](/python-packages/contract_wrappers)   | [](https://pypi.org/project/0x-contract-wrappers/)   | 0x smart contract wrappers                                                                        | | ||||
| | [`0x-json-schemas`](/python-packages/json_schemas)             | [](https://pypi.org/project/0x-json-schemas/)             | 0x-related JSON schemas                                                                           | | ||||
| | [`0x-order-utils`](/python-packages/order_utils)               | [](https://pypi.org/project/0x-order-utils/)               | A set of utilities for generating, parsing, signing and validating 0x orders                      | | ||||
| | [`0x-sra-client`](/python-packages/sra_client)                 | [](https://pypi.org/project/0x-sra-client/)                 | A Python client for interacting with servers conforming to the Standard Relayer API specification | | ||||
| Visit our [developer portal](https://0x.org/docs/) for a comprehensive list of core & community maintained packages. All packages maintained with this monorepo are listed below. | ||||
|  | ||||
| ### Solidity Packages | ||||
|  | ||||
| These packages are all under development. See [/contracts/README.md](/contracts/README.md) for a list of deployed packages. | ||||
|  | ||||
| | Package                                                             | Version                                                                                                                                     | Description                                                                                                                                                                                                                                           | | ||||
| | ------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ||||
| | [`@0x/contracts-asset-proxy`](/contracts/asset-proxy)               | [](https://www.npmjs.com/package/@0x/contracts-asset-proxy)               | [`AssetProxy`](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#assetproxy) contracts used within the protocol                                                                                               | | ||||
| | [`@0x/contracts-erc20`](/contracts/erc20)                           | [](https://www.npmjs.com/package/@0x/contracts-erc20)                           | Implementations of various ERC20 tokens                                                                                                                                                                                                               | | ||||
| | [`@0x/contracts-erc721`](/contracts/erc721)                         | [](https://www.npmjs.com/package/@0x/contracts-erc721)                         | Implementations of various ERC721 tokens                                                                                                                                                                                                              | | ||||
| | [`@0x/contracts-erc1155`](/contracts/erc1155)                       | [](https://www.npmjs.com/package/@0x/contracts-erc1155)                       | Implementations of various ERC1155 tokens                                                                                                                                                                                                             | | ||||
| | [`@0x/contracts-exchange`](/contracts/exchange)                     | [](https://www.npmjs.com/package/@0x/contracts-exchange)                     | The [`Exchange`](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#exchange) contract used for settling trades within the protocol                                                                            | | ||||
| | [`@0x/contracts-exchange-forwarder`](/contracts/exchange-forwarder) | [](https://www.npmjs.com/package/@0x/contracts-exchange-forwarder) | A [`Forwarder`](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/forwarder-specification.md) contract used to simplify UX for interacting with the protocol                                                                      | | ||||
| | [`@0x/contracts-exchange-libs`](/contracts/exchange-libs)           | [](https://www.npmjs.com/package/@0x/contracts-exchange-libs)           | Protocol specific libraries used within the [`Exchange`](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#exchange) contract                                                                                 | | ||||
| | [`@0x/contracts-extensions`](/contracts/extensions)                 | [](https://www.npmjs.com/package/@0x/contracts-extensions)                 | Contracts that interact with and extend the functionality of the core protocol                                                                                                                                                                        | | ||||
| | [`@0x/contracts-multisig`](/contracts/multisig)                     | [](https://www.npmjs.com/package/@0x/contracts-multisig)                     | Various implementations of multisignature wallets, including the [`AssetProxyOwner`](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#assetproxyowner) contract that has permissions to upgrade the protocol | | ||||
| | [`@0x/contracts-test-utils`](/contracts/test-utils)                 | [](https://www.npmjs.com/package/@0x/contracts-test-utils)                 | TypeScript/Javascript shared utilities used for testing 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)                                                                                                                                  | | ||||
| | Package                                             | Version                                                                                                                     | Description                                                          | | ||||
| | --------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | | ||||
| | [`@0x/contracts-zero-ex`](/contracts/zero-ex)       | [](https://www.npmjs.com/package/@0x/contracts-zero-ex)       | The contracts used for settling trades within the protocol           | | ||||
| | [`@0x/contracts-erc20`](/contracts/erc20)           | [](https://www.npmjs.com/package/@0x/contracts-erc20)           | Implementations of various ERC20 tokens                              | | ||||
| | [`@0x/contracts-test-utils`](/contracts/test-utils) | [](https://www.npmjs.com/package/@0x/contracts-test-utils) | TypeScript/Javascript shared utilities used for testing contracts    | | ||||
| | [`@0x/contracts-utils`](/contracts/utils)           | [](https://www.npmjs.com/package/@0x/contracts-utils)           | Generic libraries and utilities used throughout all of the contracts | | ||||
|  | ||||
| ### TypeScript/Javascript Packages | ||||
|  | ||||
| #### 0x-specific packages | ||||
|  | ||||
| | Package                                                  | Version                                                                                                                 | Description                                                                                       | | ||||
| | -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | | ||||
| | [`0x.js`](/packages/0x.js)                               | [](https://www.npmjs.com/package/0x.js)                                   | An aggregate package combining many smaller utility packages for interacting with the 0x protocol | | ||||
| | [`@0x/contract-addresses`](/packages/contract-addresses) | [](https://www.npmjs.com/package/@0x/contract-addresses) | A tiny utility library for getting known deployed contract addresses for a particular network.    | | ||||
| | [`@0x/contract-wrappers`](/packages/contract-wrappers)   | [](https://www.npmjs.com/package/@0x/contract-wrappers)   | JS/TS wrappers for interacting with the 0x smart contracts                                        | | ||||
| | [`@0x/order-utils`](/packages/order-utils)               | [](https://www.npmjs.com/package/@0x/order-utils)               | A set of utilities for generating, parsing, signing and validating 0x orders                      | | ||||
| | [`@0x/json-schemas`](/packages/json-schemas)             | [](https://www.npmjs.com/package/@0x/json-schemas)             | 0x-related JSON schemas                                                                           |  | | ||||
| | [`@0x/migrations`](/packages/migrations)                 | [](https://www.npmjs.com/package/@0x/migrations)                 | Migration tool for deploying 0x smart contracts on private testnets                               | | ||||
| | [`@0x/contract-artifacts`](/packages/contract-artifacts) | [](https://www.npmjs.com/package/@0x/contract-artifacts) | 0x smart contract compilation artifacts                                                           |  | | ||||
| | [`@0x/sra-spec`](/packages/sra-spec)                     | [](https://www.npmjs.com/package/@0x/sra-spec)                     | OpenAPI specification for the Standard Relayer API                                                | | ||||
| | [`@0x/connect`](/packages/connect)                       | [](https://www.npmjs.com/package/@0x/connect)                       | An HTTP/WS client for interacting with the Standard Relayer API                                   | | ||||
| | [`@0x/asset-swapper`](/packages/asset-swapper)           | [](https://www.npmjs.com/package/@0x/asset-swapper)           | Convenience package for discovering and performing swaps for any ERC20 Assets                     | | ||||
|  | ||||
| #### Ethereum tooling | ||||
|  | ||||
| | Package                                      | Version                                                                                                     | Description                                                                                                                                                                             | | ||||
| | -------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ||||
| | [`@0x/web3-wrapper`](/packages/web3-wrapper) | [](https://www.npmjs.com/package/@0x/web3-wrapper) | An Ethereum JSON RPC client                                                                                                                                                             | | ||||
| | [`@0x/sol-compiler`](/packages/sol-compiler) | [](https://www.npmjs.com/package/@0x/sol-compiler) | A wrapper around solc-js that adds smart re-compilation, ability to compile an entire project, Solidity version specific compilation, standard input description support and much more. | | ||||
| | [`@0x/sol-coverage`](/packages/sol-coverage) | [](https://www.npmjs.com/package/@0x/sol-coverage) | A solidity test coverage tool                                                                                                                                                           | | ||||
| | [`@0x/sol-profiler`](/packages/sol-profiler) | [](https://www.npmjs.com/package/@0x/sol-profiler) | A solidity gas cost profiler                                                                                                                                                            | | ||||
| | [`@0x/sol-trace`](/packages/sol-trace)       | [](https://www.npmjs.com/package/@0x/sol-trace)       | A solidity stack trace tool                                                                                                                                                             | | ||||
| | [`@0x/sol-resolver`](/packages/sol-resolver) | [](https://www.npmjs.com/package/@0x/sol-resolver) | Import resolver for smart contracts dependencies                                                                                                                                        | | ||||
| | [`@0x/subproviders`](/packages/subproviders) | [](https://www.npmjs.com/package/@0x/subproviders) | Web3 provider middlewares (e.g. LedgerSubprovider)                                                                                                                                      | | ||||
| | [`@0x/sol-doc`](/packages/sol-doc)           | [](https://www.npmjs.com/package/@0x/sol-doc)           | Solidity documentation generator                                                                                                                                                        | | ||||
|  | ||||
| #### Utilities | ||||
|  | ||||
| | Package                                                  | Version                                                                                                                 | Description                                                     | | ||||
| | -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------- | | ||||
| | [`@0x/abi-gen`](/packages/abi-gen)                       | [](https://www.npmjs.com/package/@0x/abi-gen)                       | Tool to generate TS wrappers from smart contract ABIs           | | ||||
| | [`@0x/tslint-config`](/packages/tslint-config)           | [](https://www.npmjs.com/package/@0x/tslint-config)           | Custom TSLint rules used by the 0x core team                    | | ||||
| | [`@0x/types`](/packages/types)                           | [](https://www.npmjs.com/package/@0x/types)                           | Shared type declarations                                        | | ||||
| | [`@0x/typescript-typings`](/packages/typescript-typings) | [](https://www.npmjs.com/package/@0x/typescript-typings) | Repository of types for external packages                       | | ||||
| | [`@0x/utils`](/packages/utils)                           | [](https://www.npmjs.com/package/@0x/utils)                           | Shared utilities                                                | | ||||
| | [`@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                       | | ||||
|  | ||||
| #### Private Packages | ||||
|  | ||||
| | Package                            | Description                                                                      | | ||||
| | ---------------------------------- | -------------------------------------------------------------------------------- | | ||||
| | [`@0x/instant`](/packages/instant) | A free and flexible way to offer simple crypto purchasing in any app or website. | | ||||
| | Package                                                  | Version                                                                                                                 | Description                                                                                    | | ||||
| | -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | | ||||
| | [`@0x/protocol-utils`](/packages/protocol-utils)         | [](https://www.npmjs.com/package/@0x/protocol-utils)         | A set of utilities for generating, parsing, signing and validating 0x orders                   | | ||||
| | [`@0x/contract-addresses`](/packages/contract-addresses) | [](https://www.npmjs.com/package/@0x/contract-addresses) | A tiny utility library for getting known deployed contract addresses for a particular network. | | ||||
| | [`@0x/contract-wrappers`](/packages/contract-wrappers)   | [](https://www.npmjs.com/package/@0x/contract-wrappers)   | JS/TS wrappers for interacting with the 0x smart contracts                                     | | ||||
| | [`@0x/contract-artifacts`](/packages/contract-artifacts) | [](https://www.npmjs.com/package/@0x/contract-artifacts) | 0x smart contract compilation artifacts                                                        |  | | ||||
|  | ||||
| ## Usage | ||||
|  | ||||
| @@ -129,8 +70,6 @@ Then install dependencies | ||||
| yarn install | ||||
| ``` | ||||
|  | ||||
| You will also need to have Python 3 installed, in order to build and run the tests of `abi-gen`'s command-line interface, which is integrated with the yarn build, yarn test, and yarn lint commands described below. More specifically, your local pip should resolve to the Python 3 version of pip, not a Python 2.x version. | ||||
|  | ||||
| ### Build | ||||
|  | ||||
| To build all packages: | ||||
| @@ -142,7 +81,7 @@ yarn build | ||||
| To build a specific package: | ||||
|  | ||||
| ```bash | ||||
| PKG=@0x/web3-wrapper yarn build | ||||
| PKG=@0x/protocol-utils yarn build | ||||
| ``` | ||||
|  | ||||
| To build all contracts packages: | ||||
| @@ -165,7 +104,7 @@ To watch a specific package and all it's dependent packages: | ||||
| PKG=[NPM_PACKAGE_NAME] yarn watch | ||||
|  | ||||
| e.g | ||||
| PKG=@0x/web3-wrapper yarn watch | ||||
| PKG=@0x/protocol-utils yarn watch | ||||
| ``` | ||||
|  | ||||
| ### Clean | ||||
| @@ -179,7 +118,7 @@ yarn clean | ||||
| Clean a specific package | ||||
|  | ||||
| ```bash | ||||
| PKG=0x.js yarn clean | ||||
| PKG=@0x/protocol-utils yarn clean | ||||
| ``` | ||||
|  | ||||
| ### Rebuild | ||||
| @@ -193,7 +132,7 @@ yarn rebuild | ||||
| To re-build (clean & build) a specific package & it's deps: | ||||
|  | ||||
| ```bash | ||||
| PKG=0x.js yarn rebuild | ||||
| PKG=@0x/protocol-utils yarn rebuild | ||||
| ``` | ||||
|  | ||||
| ### Lint | ||||
| @@ -207,7 +146,7 @@ yarn lint | ||||
| Lint a specific package: | ||||
|  | ||||
| ```bash | ||||
| PKG=0x.js yarn lint | ||||
| PKG=@0x/protocol-utils yarn lint | ||||
| ``` | ||||
|  | ||||
| ### Run Tests | ||||
| @@ -221,7 +160,7 @@ yarn test | ||||
| Run a specific package's test: | ||||
|  | ||||
| ```bash | ||||
| PKG=@0x/web3-wrapper yarn test | ||||
| PKG=@0x/protocol-utils yarn test | ||||
| ``` | ||||
|  | ||||
| Run all contracts packages tests: | ||||
|   | ||||
| @@ -1,16 +1,3 @@ | ||||
| #### Deployed Contract Packages | ||||
|  | ||||
| | Contract        | Package                                                             | Version                                                                          | Git Tag                                                                                                                                | | ||||
| | --------------- | ------------------------------------------------------------------- | -------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | | ||||
| | AssetProxyOwner | [`@0x/contracts-multisig`](/contracts/multisig)                     | [v1.0.2](https://www.npmjs.com/package/@0x/contracts-multisig/v/1.0.2)           | [@0x/contracts-multisig@1.0.2](https://github.com/0xProject/0x-monorepo/releases/tag/@0x/contracts-multisig@1.0.2)                     | | ||||
| | ERC20Proxy      | [`@0x/contracts-asset-proxy`](/contracts/asset-proxy)               | [v1.0.1](https://www.npmjs.com/package/@0x/contracts-asset-proxy/v/1.0.1)        | [@0x/contracts-asset-proxy@1.0.1](https://github.com/0xProject/0x-monorepo/releases/tag/@0x/contracts-asset-proxy@1.0.1)               | | ||||
| | ERC721Proxy     | [`@0x/contracts-asset-proxy`](/contracts/asset-proxy)               | [v1.0.1](https://www.npmjs.com/package/@0x/contracts-asset-proxy/v/1.0.1)        | [@0x/contracts-asset-proxy@1.0.1](https://github.com/0xProject/0x-monorepo/releases/tag/@0x/contracts-asset-proxy@1.0.1)               | | ||||
| | Exchange        | [`@0x/contracts-exchange`](/contracts/exchange)                     | [v1.0.1](https://www.npmjs.com/package/@0x/contracts-exchange/v/1.0.1)           | [@0x/contracts-exchange@1.0.1](https://github.com/0xProject/0x-monorepo/releases/tag/@0x/contracts-exchange@1.0.1)                     | | ||||
| | DutchAuction    | [`@0x/contracts-extensions`](/contracts/extensions)                 | [v1.0.2](https://www.npmjs.com/package/@0x/contracts-extensions/v/1.0.2)         | [@0x/contracts-extensions@1.0.2](https://github.com/0xProject/0x-monorepo/releases/tag/@0x/contracts-extensions@1.0.2)                 | | ||||
| | Forwarder       | [`@0x/contracts-exchange-forwarder`](/contracts/exchange-forwarder) | [v1.0.1](https://www.npmjs.com/package/@0x/contracts-exchange-forwarder/v/1.0.1) | [@0x/contracts-exchange-forwarder@1.0.1](https://github.com/0xProject/0x-monorepo/releases/tag/@0x/contracts-exchange-forwarder@1.0.1) | | ||||
| | MultiAssetProxy | [`@0x/contracts-asset-proxy`](/contracts/asset-proxy)               | [v1.0.1](https://www.npmjs.com/package/@0x/contracts-asset-proxy/v/1.0.1)        | [@0x/contracts-asset-proxy@1.0.1](https://github.com/0xProject/0x-monorepo/releases/tag/@0x/contracts-asset-proxy@1.0.1)               | | ||||
| | ZRXToken        | [`@0x/contracts-erc20`](/contracts/erc20)                           | [v1.0.1](https://www.npmjs.com/package/@0x/contracts-erc20/v/1.0.1)              | [@0x/contracts-erc20@1.0.1](https://github.com/0xProject/0x-monorepo/releases/tag/@0x/contracts-erc20@1.0.1)                           | | ||||
|  | ||||
| #### Development | ||||
|  | ||||
| Building solidity files will update the contract artifact in `{package-name}/generated-artifacts/{contract}.json`, but does not automatically update the `contract-artifacts` or `contract-wrappers` packages, which are generated from the artifact JSON. See `contract-artifacts/README.md` for instructions on updating these packages. | ||||
|   | ||||
| @@ -1,48 +0,0 @@ | ||||
| # Contracts testing options | ||||
|  | ||||
| ## Revert stack traces | ||||
|  | ||||
| If you want to see helpful stack traces (incl. line number, code snippet) for smart contract reverts, run the tests with: | ||||
|  | ||||
| ``` | ||||
| yarn test:trace | ||||
| ``` | ||||
|  | ||||
| **Note:** This currently slows down the test runs and is therefore not enabled by default. | ||||
|  | ||||
| ## Backing Ethereum node | ||||
|  | ||||
| By default, our tests run against an in-process [Ganache](https://github.com/trufflesuite/ganache-core) instance. In order to run the tests against [Geth](https://github.com/ethereum/go-ethereum), first follow the instructions in the README for the devnet package to start the devnet Geth node. Then run: | ||||
|  | ||||
| ```bash | ||||
| TEST_PROVIDER=geth yarn test | ||||
| ``` | ||||
|  | ||||
| ## Code coverage | ||||
|  | ||||
| In order to see the Solidity code coverage output generated by `@0x/sol-coverage`, run: | ||||
|  | ||||
| ``` | ||||
| yarn test:coverage | ||||
| ``` | ||||
|  | ||||
| ## Gas profiler | ||||
|  | ||||
| In order to profile the gas costs for a specific smart contract call/transaction, you can run the tests in `profiler` mode. | ||||
|  | ||||
| **Note:** Traces emitted by ganache have incorrect gas costs so we recommend using Geth for profiling. | ||||
|  | ||||
| ``` | ||||
| TEST_PROVIDER=geth yarn test:profiler | ||||
| ``` | ||||
|  | ||||
| You'll see a warning that you need to explicitly enable and disable the profiler before and after the block of code you want to profile. | ||||
|  | ||||
| ```typescript | ||||
| import { profiler } from './utils/profiler'; | ||||
| profiler.start(); | ||||
| // Some call to a smart contract | ||||
| profiler.stop(); | ||||
| ``` | ||||
|  | ||||
| Without explicitly starting and stopping the profiler, the profiler output will be too busy, and therefore unusable. | ||||
| @@ -1,2 +0,0 @@ | ||||
| # solhint can't parse `abi.decode` syntax. | ||||
| contracts/src/ERC1155Proxy.sol | ||||
| @@ -1,524 +0,0 @@ | ||||
| [ | ||||
|     { | ||||
|         "timestamp": 1582677073, | ||||
|         "version": "3.2.3", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1582623685, | ||||
|         "version": "3.2.2", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1581748629, | ||||
|         "version": "3.2.1", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "version": "3.2.0", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Add more types and functions to `IDydx`", | ||||
|                 "pr": 2466 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Rename `DydxBrigeAction.accountId` to `DydxBridgeAction.accountIdx`", | ||||
|                 "pr": 2466 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Fix broken tests.", | ||||
|                 "pr": 2462 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Remove dependency on `@0x/contracts-dev-utils`", | ||||
|                 "pr": 2462 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Add asset data decoding functions", | ||||
|                 "pr": 2462 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Add `setOperators()` to `IDydx`", | ||||
|                 "pr": "TODO" | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1581204851 | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1580988106, | ||||
|         "version": "3.1.3", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1580811564, | ||||
|         "version": "3.1.2", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1579682890, | ||||
|         "version": "3.1.1", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "version": "3.1.0", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Integration tests for DydxBridge with ERC20BridgeProxy.", | ||||
|                 "pr": 2401 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Fix `UniswapBridge` token -> token transfer call.", | ||||
|                 "pr": 2412 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Fix `KyberBridge` incorrect `minConversionRate` calculation.", | ||||
|                 "pr": 2412 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1578272714 | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1576540892, | ||||
|         "version": "3.0.2", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1575931811, | ||||
|         "version": "3.0.1", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "version": "3.0.0", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Implement `KyberBridge`.", | ||||
|                 "pr": 2352 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils", | ||||
|                 "pr": 2330 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "ERC20Wrapper and ERC1155ProxyWrapper constructors now require an instance of DevUtilsContract", | ||||
|                 "pr": 2034 | ||||
|             }, | ||||
|             { | ||||
|                 "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 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Add `UniswapBridge`", | ||||
|                 "pr": 2233 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Replaced `SafeMath` with `LibSafeMath`", | ||||
|                 "pr": 2254 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1575296764 | ||||
|     }, | ||||
|     { | ||||
|         "version": "2.3.0-beta.4", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Implement `KyberBridge`.", | ||||
|                 "pr": 2352 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Implement `DydxBridge`.", | ||||
|                 "pr": 2365 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1575290197 | ||||
|     }, | ||||
|     { | ||||
|         "version": "2.3.0-beta.3", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1574238768 | ||||
|     }, | ||||
|     { | ||||
|         "version": "2.3.0-beta.2", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils", | ||||
|                 "pr": 2330 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1574030254 | ||||
|     }, | ||||
|     { | ||||
|         "version": "2.3.0-beta.1", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "ERC20Wrapper and ERC1155ProxyWrapper constructors now require an instance of DevUtilsContract", | ||||
|                 "pr": 2034 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1573159180 | ||||
|     }, | ||||
|     { | ||||
|         "version": "2.3.0-beta.0", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "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 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Add `UniswapBridge`", | ||||
|                 "pr": 2233 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Replaced `SafeMath` with `LibSafeMath`", | ||||
|                 "pr": 2254 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1570135330 | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1568744790, | ||||
|         "version": "2.2.8", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1567521715, | ||||
|         "version": "2.2.7", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1566446343, | ||||
|         "version": "2.2.6", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1565296576, | ||||
|         "version": "2.2.5", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "version": "2.2.4", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Updated calls to <contract wrapper>.deployFrom0xArtifactAsync to include artifact dependencies.", | ||||
|                 "pr": 1995 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1564607468 | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1563957393, | ||||
|         "version": "2.2.3", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1563193019, | ||||
|         "version": "2.2.2", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1563047529, | ||||
|         "version": "2.2.1", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "version": "2.2.0", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Add `LibAssetProxyIds` contract", | ||||
|                 "pr": 1835 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Updated ERC1155 Asset Proxy. Less optimization. More explicit handling of edge cases.", | ||||
|                 "pr": 1852 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Implement StaticCallProxy", | ||||
|                 "pr": 1863 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1563006338 | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1558712885, | ||||
|         "version": "2.1.5", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1557961111, | ||||
|         "version": "2.1.4", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1557799313, | ||||
|         "version": "2.1.3", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "version": "2.1.2", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "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 | ||||
|     }, | ||||
|     { | ||||
|         "version": "2.1.1", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1554997931 | ||||
|     }, | ||||
|     { | ||||
|         "version": "2.1.0", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Run Web3ProviderEngine without excess block polling", | ||||
|                 "pr": 1695 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1553183790 | ||||
|     }, | ||||
|     { | ||||
|         "version": "2.0.0", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Do not reexport external dependencies", | ||||
|                 "pr": 1682 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Add ERC1155Proxy", | ||||
|                 "pr": 1661 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Bumped solidity version to ^0.5.5", | ||||
|                 "pr": 1701 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Integration testing for ERC1155Proxy", | ||||
|                 "pr": 1673 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1553091633 | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1551479279, | ||||
|         "version": "1.0.9", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1551299797, | ||||
|         "version": "1.0.8", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1551220833, | ||||
|         "version": "1.0.7", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1551130135, | ||||
|         "version": "1.0.6", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1549733923, | ||||
|         "version": "1.0.5", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "version": "1.0.4", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1549547375 | ||||
|     }, | ||||
|     { | ||||
|         "version": "1.0.3", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Fake publish to enable pinning" | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1549504360 | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1549452781, | ||||
|         "version": "1.0.2", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1549373905, | ||||
|         "version": "1.0.1", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "version": "1.0.0", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Move all AssetProxy contracts out of contracts-protocol to new package", | ||||
|                 "pr": 1539 | ||||
|             } | ||||
|         ] | ||||
|     } | ||||
| ] | ||||
| @@ -1,207 +0,0 @@ | ||||
| <!-- | ||||
| changelogUtils.file is auto-generated using the monorepo-scripts package. Don't edit directly. | ||||
| Edit the package's CHANGELOG.json file only. | ||||
| --> | ||||
|  | ||||
| CHANGELOG | ||||
|  | ||||
| ## v3.2.3 - _February 26, 2020_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v3.2.2 - _February 25, 2020_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v3.2.1 - _February 15, 2020_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v3.2.0 - _February 8, 2020_ | ||||
|  | ||||
|     * Add more types and functions to `IDydx` (#2466) | ||||
|     * Rename `DydxBrigeAction.accountId` to `DydxBridgeAction.accountIdx` (#2466) | ||||
|     * Fix broken tests. (#2462) | ||||
|     * Remove dependency on `@0x/contracts-dev-utils` (#2462) | ||||
|     * Add asset data decoding functions (#2462) | ||||
|     * Add `setOperators()` to `IDydx` (#TODO) | ||||
|  | ||||
| ## v3.1.3 - _February 6, 2020_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v3.1.2 - _February 4, 2020_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v3.1.1 - _January 22, 2020_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v3.1.0 - _January 6, 2020_ | ||||
|  | ||||
|     * Integration tests for DydxBridge with ERC20BridgeProxy. (#2401) | ||||
|     * Fix `UniswapBridge` token -> token transfer call. (#2412) | ||||
|     * Fix `KyberBridge` incorrect `minConversionRate` calculation. (#2412) | ||||
|  | ||||
| ## v3.0.2 - _December 17, 2019_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v3.0.1 - _December 9, 2019_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v3.0.0 - _December 2, 2019_ | ||||
|  | ||||
|     * Implement `KyberBridge`. (#2352) | ||||
|     * Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils (#2330) | ||||
|     * ERC20Wrapper and ERC1155ProxyWrapper constructors now require an instance of DevUtilsContract (#2034) | ||||
|     * 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) | ||||
|     * Add `UniswapBridge` (#2233) | ||||
|     * Replaced `SafeMath` with `LibSafeMath` (#2254) | ||||
|  | ||||
| ## v2.3.0-beta.4 - _December 2, 2019_ | ||||
|  | ||||
|     * Implement `KyberBridge`. (#2352) | ||||
|     * Implement `DydxBridge`. (#2365) | ||||
|  | ||||
| ## v2.3.0-beta.3 - _November 20, 2019_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v2.3.0-beta.2 - _November 17, 2019_ | ||||
|  | ||||
|     * Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils (#2330) | ||||
|  | ||||
| ## v2.3.0-beta.1 - _November 7, 2019_ | ||||
|  | ||||
|     * ERC20Wrapper and ERC1155ProxyWrapper constructors now require an instance of DevUtilsContract (#2034) | ||||
|  | ||||
| ## v2.3.0-beta.0 - _October 3, 2019_ | ||||
|  | ||||
|     * Disallow the zero address from being made an authorized address in MixinAuthorizable, and created an archive directory that includes an old version of Ownable (#2019) | ||||
|     * 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) | ||||
|     * Add `UniswapBridge` (#2233) | ||||
|     * Replaced `SafeMath` with `LibSafeMath` (#2254) | ||||
|  | ||||
| ## v2.2.8 - _September 17, 2019_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v2.2.7 - _September 3, 2019_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v2.2.6 - _August 22, 2019_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v2.2.5 - _August 8, 2019_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v2.2.4 - _July 31, 2019_ | ||||
|  | ||||
|     * Updated calls to <contract wrapper>.deployFrom0xArtifactAsync to include artifact dependencies. (#1995) | ||||
|  | ||||
| ## v2.2.3 - _July 24, 2019_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v2.2.2 - _July 15, 2019_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v2.2.1 - _July 13, 2019_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v2.2.0 - _July 13, 2019_ | ||||
|  | ||||
|     * Add `LibAssetProxyIds` contract (#1835) | ||||
|     * Updated ERC1155 Asset Proxy. Less optimization. More explicit handling of edge cases. (#1852) | ||||
|     * Implement StaticCallProxy (#1863) | ||||
|  | ||||
| ## v2.1.5 - _May 24, 2019_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v2.1.4 - _May 15, 2019_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v2.1.3 - _May 14, 2019_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## 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_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v2.1.0 - _March 21, 2019_ | ||||
|  | ||||
|     * Run Web3ProviderEngine without excess block polling (#1695) | ||||
|  | ||||
| ## v2.0.0 - _March 20, 2019_ | ||||
|  | ||||
|     * Do not reexport external dependencies (#1682) | ||||
|     * Add ERC1155Proxy (#1661) | ||||
|     * Bumped solidity version to ^0.5.5 (#1701) | ||||
|     * Integration testing for ERC1155Proxy (#1673) | ||||
|  | ||||
| ## v1.0.9 - _March 1, 2019_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v1.0.8 - _February 27, 2019_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v1.0.7 - _February 26, 2019_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v1.0.6 - _February 25, 2019_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v1.0.5 - _February 9, 2019_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v1.0.4 - _February 7, 2019_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v1.0.3 - _February 7, 2019_ | ||||
|  | ||||
|     * Fake publish to enable pinning | ||||
|  | ||||
| ## v1.0.2 - _February 6, 2019_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v1.0.1 - _February 5, 2019_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v1.0.0 - _Invalid date_ | ||||
|  | ||||
|     * Move all AssetProxy contracts out of contracts-protocol to new package (#1539) | ||||
| @@ -1,47 +0,0 @@ | ||||
| [ | ||||
|     { | ||||
|         "name": "MultiAssetProxy", | ||||
|         "version": "1.0.0", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Add MultiAssetProxy implementation", | ||||
|                 "pr": 1224, | ||||
|                 "networks": { | ||||
|                     "3": "0xab8fbd189c569ccdee3a4d929bb7f557be4028f6", | ||||
|                     "4": "0xb34cde0ad3a83d04abebc0b66e75196f22216621", | ||||
|                     "42": "0xf6313a772c222f51c28f2304c0703b8cf5428fd8" | ||||
|                 } | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "name": "ERC20Proxy", | ||||
|         "version": "1.0.0", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "protocol v2 deploy", | ||||
|                 "networks": { | ||||
|                     "1": "0x2240dab907db71e64d3e0dba4800c83b5c502d4e", | ||||
|                     "3": "0xb1408f4c245a23c31b98d2c626777d4c0d766caa", | ||||
|                     "4": "0x3e809c563c15a295e832e37053798ddc8d6c8dab", | ||||
|                     "42": "0xf1ec01d6236d3cd881a0bf0130ea25fe4234003e" | ||||
|                 } | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "name": "ERC721Proxy", | ||||
|         "version": "1.0.0", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "protocol v2 deploy", | ||||
|                 "networks": { | ||||
|                     "1": "0x208e41fb445f1bb1b6780d58356e81405f3e6127", | ||||
|                     "3": "0xe654aac058bfbf9f83fcaee7793311dd82f6ddb4", | ||||
|                     "4": "0x8e1ff02637cb5e39f2fa36c14706aa348b065b09", | ||||
|                     "42": "0x2a9127c745688a165106c11cd4d647d2220af821" | ||||
|                 } | ||||
|             } | ||||
|         ] | ||||
|     } | ||||
| ] | ||||
| @@ -1,73 +0,0 @@ | ||||
| ## AssetProxy | ||||
|  | ||||
| This package contains the implementations of all of the [`AssetProxy`](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#assetproxy) contracts available within the 0x protocol. These contracts are responsible for decoding the `assetData` sent to them and performing the actual transfer of assets. Addresses of the deployed contracts can be found in this 0x [guide](https://0x.org/docs/guides/0x-cheat-sheet) or the [DEPLOYS](./DEPLOYS.json) file within this package. | ||||
|  | ||||
| ## Installation | ||||
|  | ||||
| **Install** | ||||
|  | ||||
| ```bash | ||||
| npm install @0x/contracts-asset-proxy --save | ||||
| ``` | ||||
|  | ||||
| ## Bug bounty | ||||
|  | ||||
| A bug bounty for the 2.0.0 contracts is ongoing! Instructions can be found [here](https://0x.org/docs/guides/bug-bounty-program). | ||||
|  | ||||
| ## Contributing | ||||
|  | ||||
| We strongly recommend that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository. | ||||
|  | ||||
| For proposals regarding the 0x protocol's smart contract architecture, message format, or additional functionality, go to the [0x Improvement Proposals (ZEIPs)](https://github.com/0xProject/ZEIPs) repository and follow the contribution guidelines provided therein. | ||||
|  | ||||
| Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started. | ||||
|  | ||||
| ### Install Dependencies | ||||
|  | ||||
| If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them: | ||||
|  | ||||
| ```bash | ||||
| yarn config set workspaces-experimental true | ||||
| ``` | ||||
|  | ||||
| Then install dependencies | ||||
|  | ||||
| ```bash | ||||
| yarn install | ||||
| ``` | ||||
|  | ||||
| ### Build | ||||
|  | ||||
| To build this package and all other monorepo packages that it depends on, run the following from the monorepo root directory: | ||||
|  | ||||
| ```bash | ||||
| PKG=@0x/contracts-asset-proxy yarn build | ||||
| ``` | ||||
|  | ||||
| Or continuously rebuild on change: | ||||
|  | ||||
| ```bash | ||||
| PKG=@0x/contracts-asset-proxy yarn watch | ||||
| ``` | ||||
|  | ||||
| ### Clean | ||||
|  | ||||
| ```bash | ||||
| yarn clean | ||||
| ``` | ||||
|  | ||||
| ### Lint | ||||
|  | ||||
| ```bash | ||||
| yarn lint | ||||
| ``` | ||||
|  | ||||
| ### Run Tests | ||||
|  | ||||
| ```bash | ||||
| yarn test | ||||
| ``` | ||||
|  | ||||
| #### Testing options | ||||
|  | ||||
| Contracts testing options like coverage, profiling, revert traces or backing node choosing - are described [here](../TESTING.md). | ||||
| @@ -1,27 +0,0 @@ | ||||
| { | ||||
|     "artifactsDir": "./test/generated-artifacts", | ||||
|     "contractsDir": "./contracts", | ||||
|     "useDockerisedSolc": false, | ||||
|     "isOfflineMode": false, | ||||
|     "shouldSaveStandardInput": true, | ||||
|     "compilerSettings": { | ||||
|         "evmVersion": "istanbul", | ||||
|         "optimizer": { | ||||
|             "enabled": true, | ||||
|             "runs": 1000000, | ||||
|             "details": { "yul": true, "deduplicate": true, "cse": true, "constantOptimizer": true } | ||||
|         }, | ||||
|         "outputSelection": { | ||||
|             "*": { | ||||
|                 "*": [ | ||||
|                     "abi", | ||||
|                     "devdoc", | ||||
|                     "evm.bytecode.object", | ||||
|                     "evm.bytecode.sourceMap", | ||||
|                     "evm.deployedBytecode.object", | ||||
|                     "evm.deployedBytecode.sourceMap" | ||||
|                 ] | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,172 +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.9; | ||||
|  | ||||
| import "../archive/Ownable.sol"; | ||||
| import "../src/interfaces/IAssetProxy.sol"; | ||||
| import "../src/interfaces/IAssetProxyDispatcher.sol"; | ||||
|  | ||||
|  | ||||
| contract MixinAssetProxyDispatcher is | ||||
|     Ownable, | ||||
|     IAssetProxyDispatcher | ||||
| { | ||||
|     // Mapping from Asset Proxy Id's to their respective Asset Proxy | ||||
|     mapping (bytes4 => address) public assetProxies; | ||||
|  | ||||
|     /// @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. | ||||
|     function registerAssetProxy(address assetProxy) | ||||
|         external | ||||
|         onlyOwner | ||||
|     { | ||||
|         // Ensure that no asset proxy exists with current id. | ||||
|         bytes4 assetProxyId = IAssetProxy(assetProxy).getProxyId(); | ||||
|         address currentAssetProxy = assetProxies[assetProxyId]; | ||||
|         require( | ||||
|             currentAssetProxy == address(0), | ||||
|             "ASSET_PROXY_ALREADY_EXISTS" | ||||
|         ); | ||||
|  | ||||
|         // Add asset proxy and log registration. | ||||
|         assetProxies[assetProxyId] = assetProxy; | ||||
|         emit AssetProxyRegistered( | ||||
|             assetProxyId, | ||||
|             assetProxy | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     /// @dev Gets an asset proxy. | ||||
|     /// @param assetProxyId Id of the asset proxy. | ||||
|     /// @return The asset proxy registered to assetProxyId. Returns 0x0 if no proxy is registered. | ||||
|     function getAssetProxy(bytes4 assetProxyId) | ||||
|         external | ||||
|         view | ||||
|         returns (address) | ||||
|     { | ||||
|         return assetProxies[assetProxyId]; | ||||
|     } | ||||
|  | ||||
|     /// @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 | ||||
|     { | ||||
|         // Do nothing if no amount should be transferred. | ||||
|         if (amount > 0 && from != to) { | ||||
|             // Ensure assetData length is valid | ||||
|             require( | ||||
|                 assetData.length > 3, | ||||
|                 "LENGTH_GREATER_THAN_3_REQUIRED" | ||||
|             ); | ||||
|  | ||||
|             // Lookup assetProxy. We do not use `LibBytes.readBytes4` for gas efficiency reasons. | ||||
|             bytes4 assetProxyId; | ||||
|             assembly { | ||||
|                 assetProxyId := and(mload( | ||||
|                     add(assetData, 32)), | ||||
|                     0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 | ||||
|                 ) | ||||
|             } | ||||
|             address assetProxy = assetProxies[assetProxyId]; | ||||
|  | ||||
|             // Ensure that assetProxy exists | ||||
|             require( | ||||
|                 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                           | | ||||
|             // | Params   |        | 4 * 32  | function parameters:                        | | ||||
|             // |          | 4      |         |   1. offset to assetData (*)                | | ||||
|             // |          | 36     |         |   2. from                                   | | ||||
|             // |          | 68     |         |   3. to                                     | | ||||
|             // |          | 100    |         |   4. amount                                 | | ||||
|             // | Data     |        |         | assetData:                                  | | ||||
|             // |          | 132    | 32      | assetData Length                            | | ||||
|             // |          | 164    | **      | assetData Contents                          | | ||||
|  | ||||
|             assembly { | ||||
|                 /////// Setup State /////// | ||||
|                 // `cdStart` is the start of the calldata for `assetProxy.transferFrom` (equal to free memory ptr). | ||||
|                 let cdStart := mload(64) | ||||
|                 // `dataAreaLength` is the total number of words needed to store `assetData` | ||||
|                 //  As-per the ABI spec, this value is padded up to the nearest multiple of 32, | ||||
|                 //  and includes 32-bytes for length. | ||||
|                 let dataAreaLength := and(add(mload(assetData), 63), 0xFFFFFFFFFFFE0) | ||||
|                 // `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: | ||||
|                 //   1. The offset to `assetData` is the length of the Params Area (128 bytes). | ||||
|                 //   2. A 20-byte mask is applied to addresses to zero-out the unused bytes. | ||||
|                 mstore(add(cdStart, 4), 128) | ||||
|                 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) | ||||
|                 // solhint-disable-next-line no-empty-blocks | ||||
|                 for {} lt(dataArea, cdEnd) {} { | ||||
|                     mstore(dataArea, mload(assetData)) | ||||
|                     dataArea := add(dataArea, 32) | ||||
|                     assetData := add(assetData, 32) | ||||
|                 } | ||||
|  | ||||
|                 /////// Call `assetProxy.transferFrom` using the constructed calldata /////// | ||||
|                 let success := call( | ||||
|                     gas,                    // forward all gas | ||||
|                     assetProxy,             // call address of asset proxy | ||||
|                     0,                      // don't send any ETH | ||||
|                     cdStart,                // pointer to start of input | ||||
|                     sub(cdEnd, cdStart),    // length of input | ||||
|                     cdStart,                // write output over input | ||||
|                     512                     // reserve 512 bytes for output | ||||
|                 ) | ||||
|                 if iszero(success) { | ||||
|                     revert(cdStart, returndatasize()) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,117 +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.9; | ||||
|  | ||||
| import "../archive/Ownable.sol"; | ||||
| import "../src/interfaces/IAuthorizable.sol"; | ||||
|  | ||||
|  | ||||
| contract MixinAuthorizable is | ||||
|     Ownable, | ||||
|     IAuthorizable | ||||
| { | ||||
|     /// @dev Only authorized addresses can invoke functions with this modifier. | ||||
|     modifier onlyAuthorized { | ||||
|         require( | ||||
|             authorized[msg.sender], | ||||
|             "SENDER_NOT_AUTHORIZED" | ||||
|         ); | ||||
|         _; | ||||
|     } | ||||
|  | ||||
|     mapping (address => bool) public authorized; | ||||
|     address[] public authorities; | ||||
|  | ||||
|     /// @dev Authorizes an address. | ||||
|     /// @param target Address to authorize. | ||||
|     function addAuthorizedAddress(address target) | ||||
|         external | ||||
|         onlyOwner | ||||
|     { | ||||
|         require( | ||||
|             !authorized[target], | ||||
|             "TARGET_ALREADY_AUTHORIZED" | ||||
|         ); | ||||
|  | ||||
|         authorized[target] = true; | ||||
|         authorities.push(target); | ||||
|         emit AuthorizedAddressAdded(target, msg.sender); | ||||
|     } | ||||
|  | ||||
|     /// @dev Removes authorizion of an address. | ||||
|     /// @param target Address to remove authorization from. | ||||
|     function removeAuthorizedAddress(address target) | ||||
|         external | ||||
|         onlyOwner | ||||
|     { | ||||
|         require( | ||||
|             authorized[target], | ||||
|             "TARGET_NOT_AUTHORIZED" | ||||
|         ); | ||||
|  | ||||
|         delete authorized[target]; | ||||
|         for (uint256 i = 0; i < authorities.length; i++) { | ||||
|             if (authorities[i] == target) { | ||||
|                 authorities[i] = authorities[authorities.length - 1]; | ||||
|                 authorities.length -= 1; | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|         emit AuthorizedAddressRemoved(target, msg.sender); | ||||
|     } | ||||
|  | ||||
|     /// @dev Removes authorizion of an address. | ||||
|     /// @param target Address to remove authorization from. | ||||
|     /// @param index Index of target in authorities array. | ||||
|     function removeAuthorizedAddressAtIndex( | ||||
|         address target, | ||||
|         uint256 index | ||||
|     ) | ||||
|         external | ||||
|         onlyOwner | ||||
|     { | ||||
|         require( | ||||
|             authorized[target], | ||||
|             "TARGET_NOT_AUTHORIZED" | ||||
|         ); | ||||
|         require( | ||||
|             index < authorities.length, | ||||
|             "INDEX_OUT_OF_BOUNDS" | ||||
|         ); | ||||
|         require( | ||||
|             authorities[index] == target, | ||||
|             "AUTHORIZED_ADDRESS_MISMATCH" | ||||
|         ); | ||||
|  | ||||
|         delete authorized[target]; | ||||
|         authorities[index] = authorities[authorities.length - 1]; | ||||
|         authorities.length -= 1; | ||||
|         emit AuthorizedAddressRemoved(target, msg.sender); | ||||
|     } | ||||
|  | ||||
|     /// @dev Gets all authorized addresses. | ||||
|     /// @return Array of authorized addresses. | ||||
|     function getAuthorizedAddresses() | ||||
|         external | ||||
|         view | ||||
|         returns (address[] memory) | ||||
|     { | ||||
|         return authorities; | ||||
|     } | ||||
| } | ||||
| @@ -1,33 +0,0 @@ | ||||
| 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,97 +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.9; | ||||
|  | ||||
| import "@0x/contracts-utils/contracts/src/LibBytes.sol"; | ||||
| import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; | ||||
| import "@0x/contracts-erc1155/contracts/src/interfaces/IERC1155.sol"; | ||||
| import "../archive/MixinAuthorizable.sol"; | ||||
| import "./interfaces/IAssetProxy.sol"; | ||||
|  | ||||
|  | ||||
| contract ERC1155Proxy is | ||||
|     MixinAuthorizable, | ||||
|     IAssetProxy | ||||
| { | ||||
|     using LibBytes for bytes; | ||||
|     using LibSafeMath for uint256; | ||||
|  | ||||
|     // Id of this proxy. | ||||
|     bytes4 constant internal PROXY_ID = bytes4(keccak256("ERC1155Assets(address,uint256[],uint256[],bytes)")); | ||||
|  | ||||
|     /// @dev Transfers batch of ERC1155 assets. Either succeeds or throws. | ||||
|     /// @param assetData Byte array encoded with ERC1155 token address, array of ids, array of values, and callback data. | ||||
|     /// @param from Address to transfer assets from. | ||||
|     /// @param to Address to transfer assets to. | ||||
|     /// @param amount Amount that will be multiplied with each element of `assetData.values` to scale the | ||||
|     ///        values that will be transferred. | ||||
|     function transferFrom( | ||||
|         bytes calldata assetData, | ||||
|         address from, | ||||
|         address to, | ||||
|         uint256 amount | ||||
|     ) | ||||
|         external | ||||
|         onlyAuthorized | ||||
|     { | ||||
|         // Decode params from `assetData` | ||||
|         // solhint-disable indent | ||||
|         ( | ||||
|             address erc1155TokenAddress, | ||||
|             uint256[] memory ids, | ||||
|             uint256[] memory values, | ||||
|             bytes memory data | ||||
|         ) = abi.decode( | ||||
|             assetData.sliceDestructive(4, assetData.length), | ||||
|             (address, uint256[], uint256[], bytes) | ||||
|         ); | ||||
|         // solhint-enable indent | ||||
|  | ||||
|         // Scale values up by `amount` | ||||
|         uint256 length = values.length; | ||||
|         uint256[] memory scaledValues = new uint256[](length); | ||||
|         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 | ||||
|             // same location in the ABI encoded calldata. | ||||
|             scaledValues[i] = values[i].safeMul(amount); | ||||
|         } | ||||
|  | ||||
|         // Execute `safeBatchTransferFrom` call | ||||
|         // Either succeeds or throws | ||||
|         IERC1155(erc1155TokenAddress).safeBatchTransferFrom( | ||||
|             from, | ||||
|             to, | ||||
|             ids, | ||||
|             scaledValues, | ||||
|             data | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     /// @dev Gets the proxy id associated with the proxy address. | ||||
|     /// @return Proxy id. | ||||
|     function getProxyId() | ||||
|         external | ||||
|         pure | ||||
|         returns (bytes4) | ||||
|     { | ||||
|         return PROXY_ID; | ||||
|     } | ||||
| } | ||||
| @@ -1,126 +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.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).bridgeTransferFrom( | ||||
|             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,184 +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.9; | ||||
|  | ||||
| import "../archive/MixinAuthorizable.sol"; | ||||
|  | ||||
|  | ||||
| contract ERC20Proxy is | ||||
|     MixinAuthorizable | ||||
| { | ||||
|     // Id of this proxy. | ||||
|     bytes4 constant internal PROXY_ID = bytes4(keccak256("ERC20Token(address)")); | ||||
|  | ||||
|     // solhint-disable-next-line payable-fallback | ||||
|     function () | ||||
|         external | ||||
|     { | ||||
|         assembly { | ||||
|             // The first 4 bytes of calldata holds the function selector | ||||
|             let selector := and(calldataload(0), 0xffffffff00000000000000000000000000000000000000000000000000000000) | ||||
|  | ||||
|             // `transferFrom` will be called with the following parameters: | ||||
|             // assetData Encoded byte array. | ||||
|             // from Address to transfer asset from. | ||||
|             // to Address to transfer asset to. | ||||
|             // amount Amount of asset to transfer. | ||||
|             // bytes4(keccak256("transferFrom(bytes,address,address,uint256)")) = 0xa85e59e4 | ||||
|             if eq(selector, 0xa85e59e400000000000000000000000000000000000000000000000000000000) { | ||||
|  | ||||
|                 // To lookup a value in a mapping, we load from the storage location keccak256(k, p), | ||||
|                 // where k is the key left padded to 32 bytes and p is the storage slot | ||||
|                 let start := mload(64) | ||||
|                 mstore(start, and(caller, 0xffffffffffffffffffffffffffffffffffffffff)) | ||||
|                 mstore(add(start, 32), authorized_slot) | ||||
|  | ||||
|                 // Revert if authorized[msg.sender] == false | ||||
|                 if iszero(sload(keccak256(start, 64))) { | ||||
|                     // Revert with `Error("SENDER_NOT_AUTHORIZED")` | ||||
|                     mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000) | ||||
|                     mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000) | ||||
|                     mstore(64, 0x0000001553454e4445525f4e4f545f415554484f52495a454400000000000000) | ||||
|                     mstore(96, 0) | ||||
|                     revert(0, 100) | ||||
|                 } | ||||
|  | ||||
|                 // `transferFrom`. | ||||
|                 // The function is marked `external`, so no abi decodeding is done for | ||||
|                 // us. Instead, we expect the `calldata` memory to contain the | ||||
|                 // following: | ||||
|                 // | ||||
|                 // | Area     | Offset | Length  | Contents                            | | ||||
|                 // |----------|--------|---------|-------------------------------------| | ||||
|                 // | Header   | 0      | 4       | function selector                   | | ||||
|                 // | Params   |        | 4 * 32  | function parameters:                | | ||||
|                 // |          | 4      |         |   1. offset to assetData (*)        | | ||||
|                 // |          | 36     |         |   2. from                           | | ||||
|                 // |          | 68     |         |   3. to                             | | ||||
|                 // |          | 100    |         |   4. amount                         | | ||||
|                 // | Data     |        |         | assetData:                          | | ||||
|                 // |          | 132    | 32      | assetData Length                    | | ||||
|                 // |          | 164    | **      | assetData Contents                  | | ||||
|                 // | ||||
|                 // (*): offset is computed from start of function parameters, so offset | ||||
|                 //      by an additional 4 bytes in the calldata. | ||||
|                 // | ||||
|                 // (**): see table below to compute length of assetData Contents | ||||
|                 // | ||||
|                 // WARNING: The ABIv2 specification allows additional padding between | ||||
|                 //          the Params and Data section. This will result in a larger | ||||
|                 //          offset to assetData. | ||||
|  | ||||
|                 // Asset data itself is encoded as follows: | ||||
|                 // | ||||
|                 // | Area     | Offset | Length  | Contents                            | | ||||
|                 // |----------|--------|---------|-------------------------------------| | ||||
|                 // | Header   | 0      | 4       | function selector                   | | ||||
|                 // | Params   |        | 1 * 32  | function parameters:                | | ||||
|                 // |          | 4      | 12 + 20 |   1. token address                  | | ||||
|  | ||||
|                 // 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                   | | ||||
|                 // | Params   |        | 3 * 32  | function parameters:                | | ||||
|                 // |          | 4      |         |   1. from                           | | ||||
|                 // |          | 36     |         |   2. to                             | | ||||
|                 // |          | 68     |         |   3. amount                         | | ||||
|  | ||||
|                 /////// Read token address from calldata /////// | ||||
|                 // * The token address is stored in `assetData`. | ||||
|                 // | ||||
|                 // * The "offset to assetData" is stored at offset 4 in the calldata (table 1). | ||||
|                 //   [assetDataOffsetFromParams = calldataload(4)] | ||||
|                 // | ||||
|                 // * Notes that the "offset to assetData" is relative to the "Params" area of calldata; | ||||
|                 //   add 4 bytes to account for the length of the "Header" area (table 1). | ||||
|                 //   [assetDataOffsetFromHeader = assetDataOffsetFromParams + 4] | ||||
|                 // | ||||
|                 // * 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. | ||||
|                 calldatacopy(4, 36, 96) | ||||
|  | ||||
|                 /////// Call `token.transferFrom` using the calldata /////// | ||||
|                 let success := call( | ||||
|                     gas,            // forward all gas | ||||
|                     token,          // call address of token contract | ||||
|                     0,              // don't send any ETH | ||||
|                     0,              // pointer to start of input | ||||
|                     100,            // length of input | ||||
|                     0,              // write output over input | ||||
|                     32              // output size should be 32 bytes | ||||
|                 ) | ||||
|  | ||||
|                 /////// 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 | ||||
|                 // nonzero 32 bytes value. | ||||
|                 // So the transfer succeeded if the call succeeded and either | ||||
|                 // returned nothing, or returned a non-zero 32 byte value. | ||||
|                 success := and(success, or( | ||||
|                     iszero(returndatasize), | ||||
|                     and( | ||||
|                         eq(returndatasize, 32), | ||||
|                         gt(mload(0), 0) | ||||
|                     ) | ||||
|                 )) | ||||
|                 if success { | ||||
|                     return(0, 0) | ||||
|                 } | ||||
|  | ||||
|                 // Revert with `Error("TRANSFER_FAILED")` | ||||
|                 mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000) | ||||
|                 mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000) | ||||
|                 mstore(64, 0x0000000f5452414e534645525f4641494c454400000000000000000000000000) | ||||
|                 mstore(96, 0) | ||||
|                 revert(0, 100) | ||||
|             } | ||||
|  | ||||
|             // Revert if undefined function is called | ||||
|             revert(0, 0) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// @dev Gets the proxy id associated with the proxy address. | ||||
|     /// @return Proxy id. | ||||
|     function getProxyId() | ||||
|         external | ||||
|         pure | ||||
|         returns (bytes4) | ||||
|     { | ||||
|         return PROXY_ID; | ||||
|     } | ||||
| } | ||||
| @@ -1,171 +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.9; | ||||
|  | ||||
| import "../archive/MixinAuthorizable.sol"; | ||||
|  | ||||
|  | ||||
| contract ERC721Proxy is | ||||
|     MixinAuthorizable | ||||
| { | ||||
|     // Id of this proxy. | ||||
|     bytes4 constant internal PROXY_ID = bytes4(keccak256("ERC721Token(address,uint256)")); | ||||
|  | ||||
|     // solhint-disable-next-line payable-fallback | ||||
|     function () | ||||
|         external | ||||
|     { | ||||
|         assembly { | ||||
|             // The first 4 bytes of calldata holds the function selector | ||||
|             let selector := and(calldataload(0), 0xffffffff00000000000000000000000000000000000000000000000000000000) | ||||
|  | ||||
|             // `transferFrom` will be called with the following parameters: | ||||
|             // assetData Encoded byte array. | ||||
|             // from Address to transfer asset from. | ||||
|             // to Address to transfer asset to. | ||||
|             // amount Amount of asset to transfer. | ||||
|             // bytes4(keccak256("transferFrom(bytes,address,address,uint256)")) = 0xa85e59e4 | ||||
|             if eq(selector, 0xa85e59e400000000000000000000000000000000000000000000000000000000) { | ||||
|  | ||||
|                 // To lookup a value in a mapping, we load from the storage location keccak256(k, p), | ||||
|                 // where k is the key left padded to 32 bytes and p is the storage slot | ||||
|                 let start := mload(64) | ||||
|                 mstore(start, and(caller, 0xffffffffffffffffffffffffffffffffffffffff)) | ||||
|                 mstore(add(start, 32), authorized_slot) | ||||
|  | ||||
|                 // Revert if authorized[msg.sender] == false | ||||
|                 if iszero(sload(keccak256(start, 64))) { | ||||
|                     // Revert with `Error("SENDER_NOT_AUTHORIZED")` | ||||
|                     mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000) | ||||
|                     mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000) | ||||
|                     mstore(64, 0x0000001553454e4445525f4e4f545f415554484f52495a454400000000000000) | ||||
|                     mstore(96, 0) | ||||
|                     revert(0, 100) | ||||
|                 } | ||||
|  | ||||
|                 // `transferFrom`. | ||||
|                 // The function is marked `external`, so no abi decodeding is done for | ||||
|                 // us. Instead, we expect the `calldata` memory to contain the | ||||
|                 // following: | ||||
|                 // | ||||
|                 // | Area     | Offset | Length  | Contents                            | | ||||
|                 // |----------|--------|---------|-------------------------------------| | ||||
|                 // | Header   | 0      | 4       | function selector                   | | ||||
|                 // | Params   |        | 4 * 32  | function parameters:                | | ||||
|                 // |          | 4      |         |   1. offset to assetData (*)        | | ||||
|                 // |          | 36     |         |   2. from                           | | ||||
|                 // |          | 68     |         |   3. to                             | | ||||
|                 // |          | 100    |         |   4. amount                         | | ||||
|                 // | Data     |        |         | assetData:                          | | ||||
|                 // |          | 132    | 32      | assetData Length                    | | ||||
|                 // |          | 164    | **      | assetData Contents                  | | ||||
|                 // | ||||
|                 // (*): offset is computed from start of function parameters, so offset | ||||
|                 //      by an additional 4 bytes in the calldata. | ||||
|                 // | ||||
|                 // (**): see table below to compute length of assetData Contents | ||||
|                 // | ||||
|                 // WARNING: The ABIv2 specification allows additional padding between | ||||
|                 //          the Params and Data section. This will result in a larger | ||||
|                 //          offset to assetData. | ||||
|  | ||||
|                 // Asset data itself is encoded as follows: | ||||
|                 // | ||||
|                 // | Area     | Offset | Length  | Contents                            | | ||||
|                 // |----------|--------|---------|-------------------------------------| | ||||
|                 // | Header   | 0      | 4       | function selector                   | | ||||
|                 // | 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                   | | ||||
|                 // | Params   |        | 3 * 32  | function parameters:                | | ||||
|                 // |          | 4      |         |   1. from                           | | ||||
|                 // |          | 36     |         |   2. to                             | | ||||
|                 // |          | 68     |         |   3. tokenId                        | | ||||
|  | ||||
|                 // There exists only 1 of each token. | ||||
|                 // require(amount == 1, "INVALID_AMOUNT") | ||||
|                 if sub(calldataload(100), 1) { | ||||
|                     // Revert with `Error("INVALID_AMOUNT")` | ||||
|                     mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000) | ||||
|                     mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000) | ||||
|                     mstore(64, 0x0000000e494e56414c49445f414d4f554e540000000000000000000000000000) | ||||
|                     mstore(96, 0) | ||||
|                     revert(0, 100) | ||||
|                 } | ||||
|  | ||||
|                 /////// 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` and `to` in bulk | ||||
|                 // from our own calldata to the new calldata. | ||||
|                 calldatacopy(4, 36, 64) | ||||
|  | ||||
|                 // Copy `tokenId` field from our own calldata to the new calldata. | ||||
|                 let assetDataOffset := calldataload(4) | ||||
|                 calldatacopy(68, add(assetDataOffset, 72), 32) | ||||
|  | ||||
|                 /////// Call `token.transferFrom` using the calldata /////// | ||||
|                 let token := calldataload(add(assetDataOffset, 40)) | ||||
|                 let success := call( | ||||
|                     gas,            // forward all gas | ||||
|                     token,          // call address of token contract | ||||
|                     0,              // don't send any ETH | ||||
|                     0,              // pointer to start of input | ||||
|                     100,            // length of input | ||||
|                     0,              // write output to null | ||||
|                     0               // output size is 0 bytes | ||||
|                 ) | ||||
|                 if success { | ||||
|                     return(0, 0) | ||||
|                 } | ||||
|  | ||||
|                 // Revert with `Error("TRANSFER_FAILED")` | ||||
|                 mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000) | ||||
|                 mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000) | ||||
|                 mstore(64, 0x0000000f5452414e534645525f4641494c454400000000000000000000000000) | ||||
|                 mstore(96, 0) | ||||
|                 revert(0, 100) | ||||
|             } | ||||
|  | ||||
|             // Revert if undefined function is called | ||||
|             revert(0, 0) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// @dev Gets the proxy id associated with the proxy address. | ||||
|     /// @return Proxy id. | ||||
|     function getProxyId() | ||||
|         external | ||||
|         pure | ||||
|         returns (bytes4) | ||||
|     { | ||||
|         return PROXY_ID; | ||||
|     } | ||||
| } | ||||
| @@ -1,335 +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.9; | ||||
|  | ||||
| import "../archive/MixinAssetProxyDispatcher.sol"; | ||||
| import "../archive/MixinAuthorizable.sol"; | ||||
|  | ||||
|  | ||||
| contract MultiAssetProxy is | ||||
|     MixinAssetProxyDispatcher, | ||||
|     MixinAuthorizable | ||||
| { | ||||
|     // Id of this proxy. | ||||
|     bytes4 constant internal PROXY_ID = bytes4(keccak256("MultiAsset(uint256[],bytes[])")); | ||||
|  | ||||
|     // solhint-disable-next-line payable-fallback | ||||
|     function () | ||||
|         external | ||||
|     { | ||||
|         // NOTE: The below assembly assumes that clients do some input validation and that the input is properly encoded according to the AbiV2 specification. | ||||
|         // It is technically possible for inputs with very large lengths and offsets to cause overflows. However, this would make the calldata prohibitively | ||||
|         // expensive and we therefore do not check for overflows in these scenarios. | ||||
|         assembly { | ||||
|             // The first 4 bytes of calldata holds the function selector | ||||
|             let selector := and(calldataload(0), 0xffffffff00000000000000000000000000000000000000000000000000000000) | ||||
|  | ||||
|             // `transferFrom` will be called with the following parameters: | ||||
|             // assetData Encoded byte array. | ||||
|             // from Address to transfer asset from. | ||||
|             // to Address to transfer asset to. | ||||
|             // amount Amount of asset to transfer. | ||||
|             // bytes4(keccak256("transferFrom(bytes,address,address,uint256)")) = 0xa85e59e4 | ||||
|             if eq(selector, 0xa85e59e400000000000000000000000000000000000000000000000000000000) { | ||||
|  | ||||
|                 // To lookup a value in a mapping, we load from the storage location keccak256(k, p), | ||||
|                 // where k is the key left padded to 32 bytes and p is the storage slot | ||||
|                 mstore(0, caller) | ||||
|                 mstore(32, authorized_slot) | ||||
|  | ||||
|                 // Revert if authorized[msg.sender] == false | ||||
|                 if iszero(sload(keccak256(0, 64))) { | ||||
|                     // Revert with `Error("SENDER_NOT_AUTHORIZED")` | ||||
|                     mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000) | ||||
|                     mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000) | ||||
|                     mstore(64, 0x0000001553454e4445525f4e4f545f415554484f52495a454400000000000000) | ||||
|                     mstore(96, 0) | ||||
|                     revert(0, 100) | ||||
|                 } | ||||
|  | ||||
|                 // `transferFrom`. | ||||
|                 // The function is marked `external`, so no abi decoding is done for | ||||
|                 // us. Instead, we expect the `calldata` memory to contain the | ||||
|                 // following: | ||||
|                 // | ||||
|                 // | Area     | Offset | Length  | Contents                            | | ||||
|                 // |----------|--------|---------|-------------------------------------| | ||||
|                 // | Header   | 0      | 4       | function selector                   | | ||||
|                 // | Params   |        | 4 * 32  | function parameters:                | | ||||
|                 // |          | 4      |         |   1. offset to assetData (*)        | | ||||
|                 // |          | 36     |         |   2. from                           | | ||||
|                 // |          | 68     |         |   3. to                             | | ||||
|                 // |          | 100    |         |   4. amount                         | | ||||
|                 // | Data     |        |         | assetData:                          | | ||||
|                 // |          | 132    | 32      | assetData Length                    | | ||||
|                 // |          | 164    | **      | assetData Contents                  | | ||||
|                 // | ||||
|                 // (*): offset is computed from start of function parameters, so offset | ||||
|                 //      by an additional 4 bytes in the calldata. | ||||
|                 // | ||||
|                 // (**): see table below to compute length of assetData Contents | ||||
|                 // | ||||
|                 // WARNING: The ABIv2 specification allows additional padding between | ||||
|                 //          the Params and Data section. This will result in a larger | ||||
|                 //          offset to assetData. | ||||
|  | ||||
|                 // Load offset to `assetData` | ||||
|                 let assetDataOffset := add(calldataload(4), 4) | ||||
|  | ||||
|                 // Load length in bytes of `assetData` | ||||
|                 let assetDataLength := calldataload(assetDataOffset) | ||||
|  | ||||
|                 // Asset data itself is encoded as follows: | ||||
|                 // | ||||
|                 // | Area     | Offset      | Length  | Contents                            | | ||||
|                 // |----------|-------------|---------|-------------------------------------| | ||||
|                 // | Header   | 0           | 4       | assetProxyId                        | | ||||
|                 // | Params   |             | 2 * 32  | function parameters:                | | ||||
|                 // |          | 4           |         |   1. offset to amounts (*)          | | ||||
|                 // |          | 36          |         |   2. offset to nestedAssetData (*)  | | ||||
|                 // | Data     |             |         | amounts:                            | | ||||
|                 // |          | 68          | 32      | amounts Length                      | | ||||
|                 // |          | 100         | a       | amounts Contents                    | | ||||
|                 // |          |             |         | nestedAssetData:                    | | ||||
|                 // |          | 100 + a     | 32      | nestedAssetData Length              | | ||||
|                 // |          | 132 + a     | b       | nestedAssetData Contents (offsets)  | | ||||
|                 // |          | 132 + a + b |         | nestedAssetData[0, ..., len]        | | ||||
|  | ||||
|                 // Assert that the length of asset data: | ||||
|                 // 1. Must be at least 68 bytes (see table above) | ||||
|                 // 2. Must be a multiple of 32 (excluding the 4-byte selector) | ||||
|                 if or(lt(assetDataLength, 68), mod(sub(assetDataLength, 4), 32)) { | ||||
|                     // Revert with `Error("INVALID_ASSET_DATA_LENGTH")` | ||||
|                     mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000) | ||||
|                     mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000) | ||||
|                     mstore(64, 0x00000019494e56414c49445f41535345545f444154415f4c454e475448000000) | ||||
|                     mstore(96, 0) | ||||
|                     revert(0, 100) | ||||
|                 } | ||||
|  | ||||
|                 // End of asset data in calldata | ||||
|                 // assetDataOffset | ||||
|                 // + 32 (assetData len) | ||||
|                 let assetDataEnd := add(assetDataOffset, add(assetDataLength, 32)) | ||||
|                 if gt(assetDataEnd, calldatasize()) { | ||||
|                     // Revert with `Error("INVALID_ASSET_DATA_END")` | ||||
|                     mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000) | ||||
|                     mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000) | ||||
|                     mstore(64, 0x00000016494e56414c49445f41535345545f444154415f454e44000000000000) | ||||
|                     mstore(96, 0) | ||||
|                     revert(0, 100) | ||||
|                 } | ||||
|  | ||||
|                 // In order to find the offset to `amounts`, we must add: | ||||
|                 // assetDataOffset | ||||
|                 // + 32 (assetData len) | ||||
|                 // + 4 (assetProxyId) | ||||
|                 let amountsOffset := calldataload(add(assetDataOffset, 36)) | ||||
|  | ||||
|                 // In order to find the offset to `nestedAssetData`, we must add: | ||||
|                 // assetDataOffset | ||||
|                 // + 32 (assetData len) | ||||
|                 // + 4 (assetProxyId) | ||||
|                 // + 32 (amounts offset) | ||||
|                 let nestedAssetDataOffset := calldataload(add(assetDataOffset, 68)) | ||||
|  | ||||
|                 // In order to find the start of the `amounts` contents, we must add: | ||||
|                 // assetDataOffset | ||||
|                 // + 32 (assetData len) | ||||
|                 // + 4 (assetProxyId) | ||||
|                 // + amountsOffset | ||||
|                 // + 32 (amounts len) | ||||
|                 let amountsContentsStart := add(assetDataOffset, add(amountsOffset, 68)) | ||||
|  | ||||
|                 // 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 | ||||
|                 // + 32 (assetData len) | ||||
|                 // + 4 (assetProxyId) | ||||
|                 // + nestedAssetDataOffset | ||||
|                 // + 32 (nestedAssetData len) | ||||
|                 let nestedAssetDataContentsStart := add(assetDataOffset, add(nestedAssetDataOffset, 68)) | ||||
|  | ||||
|                 // Load number of elements in `nestedAssetData` | ||||
|                 let nestedAssetDataLen := calldataload(sub(nestedAssetDataContentsStart, 32)) | ||||
|  | ||||
|                 // Revert if number of elements in `amounts` differs from number of elements in `nestedAssetData` | ||||
|                 if sub(amountsLen, nestedAssetDataLen) { | ||||
|                     // Revert with `Error("LENGTH_MISMATCH")` | ||||
|                     mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000) | ||||
|                     mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000) | ||||
|                     mstore(64, 0x0000000f4c454e4754485f4d49534d4154434800000000000000000000000000) | ||||
|                     mstore(96, 0) | ||||
|                     revert(0, 100) | ||||
|                 } | ||||
|  | ||||
|                 // Copy `transferFrom` selector, offset to `assetData`, `from`, and `to` from calldata to memory | ||||
|                 calldatacopy( | ||||
|                     0,   // memory can safely be overwritten from beginning | ||||
|                     0,   // start of calldata | ||||
|                     100  // length of selector (4) and 3 params (32 * 3) | ||||
|                 ) | ||||
|  | ||||
|                 // 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) | ||||
|  | ||||
|                 // Initialize `assetProxyId` and `assetProxy` to 0 | ||||
|                 let assetProxyId := 0 | ||||
|                 let assetProxy := 0 | ||||
|  | ||||
|                 // Loop through `amounts` and `nestedAssetData`, calling `transferFrom` for each respective element | ||||
|                 for {let i := 0} lt(i, amountsByteLen) {i := add(i, 32)} { | ||||
|  | ||||
|                     // Calculate the total amount | ||||
|                     let amountsElement := calldataload(add(amountsContentsStart, i)) | ||||
|                     let totalAmount := mul(amountsElement, amount) | ||||
|  | ||||
|                     // Revert if `amount` != 0 and multiplication resulted in an overflow | ||||
|                     if iszero(or( | ||||
|                         iszero(amount), | ||||
|                         eq(div(totalAmount, amount), amountsElement) | ||||
|                     )) { | ||||
|                         // Revert with `Error("UINT256_OVERFLOW")` | ||||
|                         mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000) | ||||
|                         mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000) | ||||
|                         mstore(64, 0x0000001055494e543235365f4f564552464c4f57000000000000000000000000) | ||||
|                         mstore(96, 0) | ||||
|                         revert(0, 100) | ||||
|                     } | ||||
|  | ||||
|                     // Write `totalAmount` to memory | ||||
|                     mstore(100, totalAmount) | ||||
|  | ||||
|                     // Load offset to `nestedAssetData[i]` | ||||
|                     let nestedAssetDataElementOffset := calldataload(add(nestedAssetDataContentsStart, i)) | ||||
|  | ||||
|                     // In order to find the start of the `nestedAssetData[i]` contents, we must add: | ||||
|                     // assetDataOffset | ||||
|                     // + 32 (assetData len) | ||||
|                     // + 4 (assetProxyId) | ||||
|                     // + nestedAssetDataOffset | ||||
|                     // + 32 (nestedAssetData len) | ||||
|                     // + nestedAssetDataElementOffset | ||||
|                     // + 32 (nestedAssetDataElement len) | ||||
|                     let nestedAssetDataElementContentsStart := add( | ||||
|                         assetDataOffset, | ||||
|                         add( | ||||
|                             nestedAssetDataOffset, | ||||
|                             add(nestedAssetDataElementOffset, 100) | ||||
|                         ) | ||||
|                     ) | ||||
|  | ||||
|                     // Load length of `nestedAssetData[i]` | ||||
|                     let nestedAssetDataElementLenStart := sub(nestedAssetDataElementContentsStart, 32) | ||||
|                     let nestedAssetDataElementLen := calldataload(nestedAssetDataElementLenStart) | ||||
|  | ||||
|                     // Revert if the `nestedAssetData` does not contain a 4 byte `assetProxyId` | ||||
|                     if lt(nestedAssetDataElementLen, 4) { | ||||
|                         // Revert with `Error("LENGTH_GREATER_THAN_3_REQUIRED")` | ||||
|                         mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000) | ||||
|                         mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000) | ||||
|                         mstore(64, 0x0000001e4c454e4754485f475245415445525f5448414e5f335f524551554952) | ||||
|                         mstore(96, 0x4544000000000000000000000000000000000000000000000000000000000000) | ||||
|                         revert(0, 100) | ||||
|                     } | ||||
|  | ||||
|                     // Load AssetProxy id | ||||
|                     let currentAssetProxyId := and( | ||||
|                         calldataload(nestedAssetDataElementContentsStart), | ||||
|                         0xffffffff00000000000000000000000000000000000000000000000000000000 | ||||
|                     ) | ||||
|  | ||||
|                     // Only load `assetProxy` if `currentAssetProxyId` does not equal `assetProxyId` | ||||
|                     // We do not need to check if `currentAssetProxyId` is 0 since `assetProxy` is also initialized to 0 | ||||
|                     if sub(currentAssetProxyId, assetProxyId) { | ||||
|                         // Update `assetProxyId` | ||||
|                         assetProxyId := currentAssetProxyId | ||||
|                         // To lookup a value in a mapping, we load from the storage location keccak256(k, p), | ||||
|                         // where k is the key left padded to 32 bytes and p is the storage slot | ||||
|                         mstore(132, assetProxyId) | ||||
|                         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")` | ||||
|                         mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000) | ||||
|                         mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000) | ||||
|                         mstore(64, 0x0000001a41535345545f50524f58595f444f45535f4e4f545f45584953540000) | ||||
|                         mstore(96, 0) | ||||
|                         revert(0, 100) | ||||
|                     } | ||||
|  | ||||
|                     // Copy `nestedAssetData[i]` from calldata to memory | ||||
|                     calldatacopy( | ||||
|                         132,                                // memory slot after `amounts[i]` | ||||
|                         nestedAssetDataElementLenStart,     // location of `nestedAssetData[i]` in calldata | ||||
|                         add(nestedAssetDataElementLen, 32)  // `nestedAssetData[i].length` plus 32 byte length | ||||
|                     ) | ||||
|  | ||||
|                     // call `assetProxy.transferFrom` | ||||
|                     let success := call( | ||||
|                         gas,                                    // forward all gas | ||||
|                         assetProxy,                             // call address of asset proxy | ||||
|                         0,                                      // don't send any ETH | ||||
|                         0,                                      // pointer to start 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 | ||||
|                     ) | ||||
|  | ||||
|                     // Revert with reason given by AssetProxy if `transferFrom` call failed | ||||
|                     if iszero(success) { | ||||
|                         returndatacopy( | ||||
|                             0,                // copy to memory at 0 | ||||
|                             0,                // copy from return data at 0 | ||||
|                             returndatasize()  // copy all return data | ||||
|                         ) | ||||
|                         revert(0, returndatasize()) | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 // Return if no `transferFrom` calls reverted | ||||
|                 return(0, 0) | ||||
|             } | ||||
|  | ||||
|             // Revert if undefined function is called | ||||
|             revert(0, 0) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// @dev Gets the proxy id associated with the proxy address. | ||||
|     /// @return Proxy id. | ||||
|     function getProxyId() | ||||
|         external | ||||
|         pure | ||||
|         returns (bytes4) | ||||
|     { | ||||
|         return PROXY_ID; | ||||
|     } | ||||
| } | ||||
| @@ -1,83 +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.9; | ||||
|  | ||||
| import "@0x/contracts-utils/contracts/src/LibBytes.sol"; | ||||
|  | ||||
|  | ||||
| // solhint-disable no-unused-vars | ||||
| contract StaticCallProxy { | ||||
|  | ||||
|     using LibBytes for bytes; | ||||
|  | ||||
|     // Id of this proxy. | ||||
|     bytes4 constant internal PROXY_ID = bytes4(keccak256("StaticCall(address,bytes,bytes32)")); | ||||
|  | ||||
|     /// @dev Makes a staticcall to a target address and verifies that the data returned matches the expected return data. | ||||
|     /// @param assetData Byte array encoded with staticCallTarget, staticCallData, and expectedCallResultHash | ||||
|     /// @param from This value is ignored. | ||||
|     /// @param to This value is ignored. | ||||
|     /// @param amount This value is ignored. | ||||
|     function transferFrom( | ||||
|         bytes calldata assetData, | ||||
|         address from, | ||||
|         address to, | ||||
|         uint256 amount | ||||
|     ) | ||||
|         external | ||||
|         view | ||||
|     { | ||||
|         // Decode params from `assetData` | ||||
|         ( | ||||
|             address staticCallTarget, | ||||
|             bytes memory staticCallData, | ||||
|             bytes32 expectedReturnDataHash | ||||
|         ) = abi.decode( | ||||
|             assetData.sliceDestructive(4, assetData.length), | ||||
|             (address, bytes, bytes32) | ||||
|         ); | ||||
|  | ||||
|         // Execute staticcall | ||||
|         (bool success, bytes memory returnData) = staticCallTarget.staticcall(staticCallData); | ||||
|  | ||||
|         // Revert with returned data if staticcall is unsuccessful | ||||
|         if (!success) { | ||||
|             assembly { | ||||
|                 revert(add(returnData, 32), mload(returnData)) | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Revert if hash of return data is not as expected | ||||
|         bytes32 returnDataHash = keccak256(returnData); | ||||
|         require( | ||||
|             expectedReturnDataHash == returnDataHash, | ||||
|             "UNEXPECTED_STATIC_CALL_RESULT" | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     /// @dev Gets the proxy id associated with the proxy address. | ||||
|     /// @return Proxy id. | ||||
|     function getProxyId() | ||||
|         external | ||||
|         pure | ||||
|         returns (bytes4) | ||||
|     { | ||||
|         return PROXY_ID; | ||||
|     } | ||||
| } | ||||
| @@ -1,75 +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.9; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "../interfaces/IERC20Bridge.sol"; | ||||
| import "../interfaces/IChai.sol"; | ||||
| import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; | ||||
| import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; | ||||
|  | ||||
|  | ||||
| // solhint-disable space-after-comma | ||||
| contract ChaiBridge is | ||||
|     IERC20Bridge, | ||||
|     DeploymentConstants | ||||
| { | ||||
|     /// @dev Withdraws `amount` of `from` address's Dai from the Chai contract. | ||||
|     ///      Transfers `amount` of Dai to `to` address. | ||||
|     /// @param from Address to transfer asset from. | ||||
|     /// @param to Address to transfer asset to. | ||||
|     /// @param amount Amount of asset to transfer. | ||||
|     /// @return success The magic bytes `0x37708e9b` if successful. | ||||
|     function bridgeTransferFrom( | ||||
|         address /* tokenAddress */, | ||||
|         address from, | ||||
|         address to, | ||||
|         uint256 amount, | ||||
|         bytes calldata /* bridgeData */ | ||||
|     ) | ||||
|         external | ||||
|         returns (bytes4 success) | ||||
|     { | ||||
|         // Ensure that only the `ERC20BridgeProxy` can call this function. | ||||
|         require( | ||||
|             msg.sender == _getERC20BridgeProxyAddress(), | ||||
|             "ChaiBridge/ONLY_CALLABLE_BY_ERC20_BRIDGE_PROXY" | ||||
|         ); | ||||
|  | ||||
|         // Withdraw `from` address's Dai. | ||||
|         // NOTE: This contract must be approved to spend Chai on behalf of `from`. | ||||
|         bytes memory drawCalldata = abi.encodeWithSelector( | ||||
|             IChai(address(0)).draw.selector, | ||||
|             from, | ||||
|             amount | ||||
|         ); | ||||
|  | ||||
|         (bool success,) = _getChaiAddress().call(drawCalldata); | ||||
|         require( | ||||
|             success, | ||||
|             "ChaiBridge/DRAW_DAI_FAILED" | ||||
|         ); | ||||
|  | ||||
|         // Transfer Dai to `to` | ||||
|         // This will never fail if the `draw` call was successful | ||||
|         IERC20Token(_getDaiAddress()).transfer(to, amount); | ||||
|  | ||||
|         return BRIDGE_SUCCESS; | ||||
|     } | ||||
| } | ||||
| @@ -1,108 +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.9; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; | ||||
| import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol"; | ||||
| import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol"; | ||||
| import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; | ||||
| import "../interfaces/IERC20Bridge.sol"; | ||||
| import "../interfaces/ICurve.sol"; | ||||
|  | ||||
|  | ||||
| // solhint-disable not-rely-on-time | ||||
| // solhint-disable space-after-comma | ||||
| contract CurveBridge is | ||||
|     IERC20Bridge, | ||||
|     IWallet, | ||||
|     DeploymentConstants | ||||
| { | ||||
|     /// @dev Callback for `ICurve`. Tries to buy `amount` of | ||||
|     ///      `toTokenAddress` tokens by selling the entirety of the opposing asset | ||||
|     ///      (DAI, USDC) to the Curve contract, then transfers the bought | ||||
|     ///      tokens to `to`. | ||||
|     /// @param toTokenAddress The token to give to `to` (i.e DAI, USDC, USDT). | ||||
|     /// @param to The recipient of the bought tokens. | ||||
|     /// @param amount Minimum amount of `toTokenAddress` tokens to buy. | ||||
|     /// @param bridgeData The abi-encoeded "from" token address. | ||||
|     /// @return success The magic bytes if successful. | ||||
|     function bridgeTransferFrom( | ||||
|         address toTokenAddress, | ||||
|         address /* from */, | ||||
|         address to, | ||||
|         uint256 amount, | ||||
|         bytes calldata bridgeData | ||||
|     ) | ||||
|         external | ||||
|         returns (bytes4 success) | ||||
|     { | ||||
|         // Decode the bridge data to get the Curve metadata. | ||||
|         (address curveAddress, int128 fromCoinIdx, int128 toCoinIdx, int128 version) = abi.decode(bridgeData, (address, int128, int128, int128)); | ||||
|         ICurve exchange = ICurve(curveAddress); | ||||
|  | ||||
|         address fromTokenAddress = exchange.underlying_coins(fromCoinIdx); | ||||
|         require(toTokenAddress != fromTokenAddress, "CurveBridge/INVALID_PAIR"); | ||||
|         // Grant an allowance to the exchange to spend `fromTokenAddress` token. | ||||
|         LibERC20Token.approve(fromTokenAddress, address(exchange), uint256(-1)); | ||||
|  | ||||
|         // Try to sell all of this contract's `fromTokenAddress` token balance. | ||||
|         if (version == 0) { | ||||
|             exchange.exchange_underlying( | ||||
|                 fromCoinIdx, | ||||
|                 toCoinIdx, | ||||
|                 // dx | ||||
|                 IERC20Token(fromTokenAddress).balanceOf(address(this)), | ||||
|                 // min dy | ||||
|                 amount, | ||||
|                 // expires | ||||
|                 block.timestamp + 1 | ||||
|             ); | ||||
|         } else { | ||||
|             exchange.exchange_underlying( | ||||
|                 fromCoinIdx, | ||||
|                 toCoinIdx, | ||||
|                 // dx | ||||
|                 IERC20Token(fromTokenAddress).balanceOf(address(this)), | ||||
|                 // min dy | ||||
|                 amount | ||||
|             ); | ||||
|         } | ||||
|  | ||||
|         uint256 toTokenBalance = IERC20Token(toTokenAddress).balanceOf(address(this)); | ||||
|         // Transfer the converted `toToken`s to `to`. | ||||
|         LibERC20Token.transfer(toTokenAddress, to, toTokenBalance); | ||||
|         return BRIDGE_SUCCESS; | ||||
|     } | ||||
|  | ||||
|     /// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker | ||||
|     ///      and sign for itself in orders. Always succeeds. | ||||
|     /// @return magicValue Magic success bytes, always. | ||||
|     function isValidSignature( | ||||
|         bytes32, | ||||
|         bytes calldata | ||||
|     ) | ||||
|         external | ||||
|         view | ||||
|         returns (bytes4 magicValue) | ||||
|     { | ||||
|         return LEGACY_WALLET_MAGIC_VALUE; | ||||
|     } | ||||
| } | ||||
| @@ -1,241 +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.9; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; | ||||
| import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; | ||||
| import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol"; | ||||
| import "../interfaces/IERC20Bridge.sol"; | ||||
| import "../interfaces/IDydxBridge.sol"; | ||||
| import "../interfaces/IDydx.sol"; | ||||
|  | ||||
|  | ||||
| contract DydxBridge is | ||||
|     IERC20Bridge, | ||||
|     IDydxBridge, | ||||
|     DeploymentConstants | ||||
| { | ||||
|  | ||||
|     using LibSafeMath for uint256; | ||||
|  | ||||
|     /// @dev Callback for `IERC20Bridge`. Deposits or withdraws tokens from a dydx account. | ||||
|     ///      Notes: | ||||
|     ///         1. This bridge must be set as an operator of the input dydx account. | ||||
|     ///         2. This function may only be called in the context of the 0x Exchange. | ||||
|     ///         3. The maker or taker of the 0x order must be the dydx account owner. | ||||
|     ///         4. Deposits into dydx are made from the `from` address. | ||||
|     ///         5. Withdrawals from dydx are made to the `to` address. | ||||
|     ///         6. Calling this function must always withdraw at least `amount`, | ||||
|     ///            otherwise the `ERC20Bridge` will revert. | ||||
|     /// @param from The sender of the tokens and owner of the dydx account. | ||||
|     /// @param to The recipient of the tokens. | ||||
|     /// @param amount Minimum amount of `toTokenAddress` tokens to deposit or withdraw. | ||||
|     /// @param encodedBridgeData An abi-encoded `BridgeData` struct. | ||||
|     /// @return success The magic bytes if successful. | ||||
|     function bridgeTransferFrom( | ||||
|         address, | ||||
|         address from, | ||||
|         address to, | ||||
|         uint256 amount, | ||||
|         bytes calldata encodedBridgeData | ||||
|     ) | ||||
|         external | ||||
|         returns (bytes4 success) | ||||
|     { | ||||
|         // Ensure that only the `ERC20BridgeProxy` can call this function. | ||||
|         require( | ||||
|             msg.sender == _getERC20BridgeProxyAddress(), | ||||
|             "DydxBridge/ONLY_CALLABLE_BY_ERC20_BRIDGE_PROXY" | ||||
|         ); | ||||
|  | ||||
|         // Decode bridge data. | ||||
|         (BridgeData memory bridgeData) = abi.decode(encodedBridgeData, (BridgeData)); | ||||
|  | ||||
|         // The dydx accounts are owned by the `from` address. | ||||
|         IDydx.AccountInfo[] memory accounts = _createAccounts(from, bridgeData); | ||||
|  | ||||
|         // Create dydx actions to run on the dydx accounts. | ||||
|         IDydx.ActionArgs[] memory actions = _createActions( | ||||
|             from, | ||||
|             to, | ||||
|             amount, | ||||
|             bridgeData | ||||
|         ); | ||||
|  | ||||
|         // Run operation. This will revert on failure. | ||||
|         IDydx(_getDydxAddress()).operate(accounts, actions); | ||||
|         return BRIDGE_SUCCESS; | ||||
|     } | ||||
|  | ||||
|     /// @dev Creates an array of accounts for dydx to operate on. | ||||
|     ///      All accounts must belong to the same owner. | ||||
|     /// @param accountOwner Owner of the dydx account. | ||||
|     /// @param bridgeData A `BridgeData` struct. | ||||
|     function _createAccounts( | ||||
|         address accountOwner, | ||||
|         BridgeData memory bridgeData | ||||
|     ) | ||||
|         internal | ||||
|         returns (IDydx.AccountInfo[] memory accounts) | ||||
|     { | ||||
|         uint256[] memory accountNumbers = bridgeData.accountNumbers; | ||||
|         uint256 nAccounts = accountNumbers.length; | ||||
|         accounts = new IDydx.AccountInfo[](nAccounts); | ||||
|         for (uint256 i = 0; i < nAccounts; ++i) { | ||||
|             accounts[i] = IDydx.AccountInfo({ | ||||
|                 owner: accountOwner, | ||||
|                 number: accountNumbers[i] | ||||
|             }); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// @dev Creates an array of actions to carry out on dydx. | ||||
|     /// @param depositFrom Deposit value from this address (owner of the dydx account). | ||||
|     /// @param withdrawTo Withdraw value to this address. | ||||
|     /// @param amount The amount of value available to operate on. | ||||
|     /// @param bridgeData A `BridgeData` struct. | ||||
|     function _createActions( | ||||
|         address depositFrom, | ||||
|         address withdrawTo, | ||||
|         uint256 amount, | ||||
|         BridgeData memory bridgeData | ||||
|     ) | ||||
|         internal | ||||
|         returns (IDydx.ActionArgs[] memory actions) | ||||
|     { | ||||
|         BridgeAction[] memory bridgeActions = bridgeData.actions; | ||||
|         uint256 nBridgeActions = bridgeActions.length; | ||||
|         actions = new IDydx.ActionArgs[](nBridgeActions); | ||||
|         for (uint256 i = 0; i < nBridgeActions; ++i) { | ||||
|             // Cache current bridge action. | ||||
|             BridgeAction memory bridgeAction = bridgeActions[i]; | ||||
|  | ||||
|             // Scale amount, if conversion rate is set. | ||||
|             uint256 scaledAmount; | ||||
|             if (bridgeAction.conversionRateDenominator > 0) { | ||||
|                 scaledAmount = LibMath.safeGetPartialAmountFloor( | ||||
|                     bridgeAction.conversionRateNumerator, | ||||
|                     bridgeAction.conversionRateDenominator, | ||||
|                     amount | ||||
|                 ); | ||||
|             } else { | ||||
|                 scaledAmount = amount; | ||||
|             } | ||||
|  | ||||
|             // Construct dydx action. | ||||
|             if (bridgeAction.actionType == BridgeActionType.Deposit) { | ||||
|                 // Deposit tokens from the account owner into their dydx account. | ||||
|                 actions[i] = _createDepositAction( | ||||
|                     depositFrom, | ||||
|                     scaledAmount, | ||||
|                     bridgeAction | ||||
|                 ); | ||||
|             } else if (bridgeAction.actionType == BridgeActionType.Withdraw) { | ||||
|                 // Withdraw tokens from dydx to the `otherAccount`. | ||||
|                 actions[i] = _createWithdrawAction( | ||||
|                     withdrawTo, | ||||
|                     scaledAmount, | ||||
|                     bridgeAction | ||||
|                 ); | ||||
|             } else { | ||||
|                 // If all values in the `Action` enum are handled then this | ||||
|                 // revert is unreachable: Solidity will revert when casting | ||||
|                 // from `uint8` to `Action`. | ||||
|                 revert("DydxBridge/UNRECOGNIZED_BRIDGE_ACTION"); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// @dev Returns a dydx `DepositAction`. | ||||
|     /// @param depositFrom Deposit tokens from this address who is also the account owner. | ||||
|     /// @param amount of tokens to deposit. | ||||
|     /// @param bridgeAction A `BridgeAction` struct. | ||||
|     /// @return depositAction The encoded dydx action. | ||||
|     function _createDepositAction( | ||||
|         address depositFrom, | ||||
|         uint256 amount, | ||||
|         BridgeAction memory bridgeAction | ||||
|     ) | ||||
|         internal | ||||
|         pure | ||||
|         returns ( | ||||
|             IDydx.ActionArgs memory depositAction | ||||
|         ) | ||||
|     { | ||||
|         // Create dydx amount. | ||||
|         IDydx.AssetAmount memory dydxAmount = IDydx.AssetAmount({ | ||||
|             sign: true,                                 // true if positive. | ||||
|             denomination: IDydx.AssetDenomination.Wei,  // Wei => actual token amount held in account. | ||||
|             ref: IDydx.AssetReference.Delta,                // Delta => a relative amount. | ||||
|             value: amount                               // amount to deposit. | ||||
|         }); | ||||
|  | ||||
|         // Create dydx deposit action. | ||||
|         depositAction = IDydx.ActionArgs({ | ||||
|             actionType: IDydx.ActionType.Deposit,           // deposit tokens. | ||||
|             amount: dydxAmount,                             // amount to deposit. | ||||
|             accountIdx: bridgeAction.accountIdx,             // index in the `accounts` when calling `operate`. | ||||
|             primaryMarketId: bridgeAction.marketId,         // indicates which token to deposit. | ||||
|             otherAddress: depositFrom,                      // deposit from the account owner. | ||||
|             // unused parameters | ||||
|             secondaryMarketId: 0, | ||||
|             otherAccountIdx: 0, | ||||
|             data: hex'' | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     /// @dev Returns a dydx `WithdrawAction`. | ||||
|     /// @param withdrawTo Withdraw tokens to this address. | ||||
|     /// @param amount of tokens to withdraw. | ||||
|     /// @param bridgeAction A `BridgeAction` struct. | ||||
|     /// @return withdrawAction The encoded dydx action. | ||||
|     function _createWithdrawAction( | ||||
|         address withdrawTo, | ||||
|         uint256 amount, | ||||
|         BridgeAction memory bridgeAction | ||||
|     ) | ||||
|         internal | ||||
|         pure | ||||
|         returns ( | ||||
|             IDydx.ActionArgs memory withdrawAction | ||||
|         ) | ||||
|     { | ||||
|         // Create dydx amount. | ||||
|         IDydx.AssetAmount memory amountToWithdraw = IDydx.AssetAmount({ | ||||
|             sign: false,                                    // false if negative. | ||||
|             denomination: IDydx.AssetDenomination.Wei,      // Wei => actual token amount held in account. | ||||
|             ref: IDydx.AssetReference.Delta,                // Delta => a relative amount. | ||||
|             value: amount                                   // amount to withdraw. | ||||
|         }); | ||||
|  | ||||
|         // Create withdraw action. | ||||
|         withdrawAction = IDydx.ActionArgs({ | ||||
|             actionType: IDydx.ActionType.Withdraw,          // withdraw tokens. | ||||
|             amount: amountToWithdraw,                       // amount to withdraw. | ||||
|             accountIdx: bridgeAction.accountIdx,            // index in the `accounts` when calling `operate`. | ||||
|             primaryMarketId: bridgeAction.marketId,         // indicates which token to withdraw. | ||||
|             otherAddress: withdrawTo,                       // withdraw tokens to this address. | ||||
|             // unused parameters | ||||
|             secondaryMarketId: 0, | ||||
|             otherAccountIdx: 0, | ||||
|             data: hex'' | ||||
|         }); | ||||
|     } | ||||
| } | ||||
| @@ -1,87 +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.9; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; | ||||
| import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol"; | ||||
| import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol"; | ||||
| import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; | ||||
| import "../interfaces/IERC20Bridge.sol"; | ||||
| import "../interfaces/IEth2Dai.sol"; | ||||
|  | ||||
|  | ||||
| // solhint-disable space-after-comma | ||||
| contract Eth2DaiBridge is | ||||
|     IERC20Bridge, | ||||
|     IWallet, | ||||
|     DeploymentConstants | ||||
| { | ||||
|     /// @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 bridgeTransferFrom( | ||||
|         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 = IEth2Dai(_getEth2DaiAddress()); | ||||
|         // Grant an allowance to the exchange to spend `fromTokenAddress` token. | ||||
|         LibERC20Token.approve(fromTokenAddress, address(exchange), uint256(-1)); | ||||
|  | ||||
|         // Try to sell all of this contract's `fromTokenAddress` token balance. | ||||
|         uint256 boughtAmount = exchange.sellAllAmount( | ||||
|             fromTokenAddress, | ||||
|             IERC20Token(fromTokenAddress).balanceOf(address(this)), | ||||
|             toTokenAddress, | ||||
|             amount | ||||
|         ); | ||||
|         // Transfer the converted `toToken`s to `to`. | ||||
|         LibERC20Token.transfer(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; | ||||
|     } | ||||
| } | ||||
| @@ -1,162 +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.9; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; | ||||
| import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol"; | ||||
| import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol"; | ||||
| import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol"; | ||||
| import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; | ||||
| import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; | ||||
| import "../interfaces/IERC20Bridge.sol"; | ||||
| import "../interfaces/IKyberNetworkProxy.sol"; | ||||
|  | ||||
|  | ||||
| // solhint-disable space-after-comma | ||||
| contract KyberBridge is | ||||
|     IERC20Bridge, | ||||
|     IWallet, | ||||
|     DeploymentConstants | ||||
| { | ||||
|     using LibSafeMath for uint256; | ||||
|  | ||||
|     // @dev Structure used internally to get around stack limits. | ||||
|     struct TradeState { | ||||
|         IKyberNetworkProxy kyber; | ||||
|         IEtherToken weth; | ||||
|         address fromTokenAddress; | ||||
|         uint256 fromTokenBalance; | ||||
|         uint256 payableAmount; | ||||
|         uint256 conversionRate; | ||||
|     } | ||||
|  | ||||
|     /// @dev Kyber ETH pseudo-address. | ||||
|     address constant public KYBER_ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; | ||||
|     /// @dev `bridgeTransferFrom()` failure result. | ||||
|     bytes4 constant private BRIDGE_FAILED = 0x0; | ||||
|     /// @dev Precision of Kyber rates. | ||||
|     uint256 constant private KYBER_RATE_BASE = 10 ** 18; | ||||
|  | ||||
|     // solhint-disable no-empty-blocks | ||||
|     /// @dev Payable fallback to receive ETH from Kyber. | ||||
|     function () | ||||
|         external | ||||
|         payable | ||||
|     {} | ||||
|  | ||||
|     /// @dev Callback for `IKyberBridge`. Tries to buy `amount` of | ||||
|     ///      `toTokenAddress` tokens by selling the entirety of the opposing asset | ||||
|     ///      to the `KyberNetworkProxy` contract, then transfers the bought | ||||
|     ///      tokens to `to`. | ||||
|     /// @param toTokenAddress The token to give to `to`. | ||||
|     /// @param to The recipient of the bought tokens. | ||||
|     /// @param amount Minimum amount of `toTokenAddress` tokens to buy. | ||||
|     /// @param bridgeData The abi-encoeded "from" token address. | ||||
|     /// @return success The magic bytes if successful. | ||||
|     function bridgeTransferFrom( | ||||
|         address toTokenAddress, | ||||
|         address /* from */, | ||||
|         address to, | ||||
|         uint256 amount, | ||||
|         bytes calldata bridgeData | ||||
|     ) | ||||
|         external | ||||
|         returns (bytes4 success) | ||||
|     { | ||||
|         TradeState memory state; | ||||
|         state.kyber = IKyberNetworkProxy(_getKyberNetworkProxyAddress()); | ||||
|         state.weth = IEtherToken(_getWethAddress()); | ||||
|         // Decode the bridge data to get the `fromTokenAddress`. | ||||
|         (state.fromTokenAddress) = abi.decode(bridgeData, (address)); | ||||
|         // Query the balance of "from" tokens. | ||||
|         state.fromTokenBalance = IERC20Token(state.fromTokenAddress).balanceOf(address(this)); | ||||
|         if (state.fromTokenBalance == 0) { | ||||
|             // Return failure if no input tokens. | ||||
|             return BRIDGE_FAILED; | ||||
|         } | ||||
|         // Compute the conversion rate, expressed in 18 decimals. | ||||
|         // The sequential notation is to get around stack limits. | ||||
|         state.conversionRate = KYBER_RATE_BASE; | ||||
|         state.conversionRate = state.conversionRate.safeMul(amount); | ||||
|         state.conversionRate = state.conversionRate.safeMul( | ||||
|             10 ** uint256(LibERC20Token.decimals(state.fromTokenAddress)) | ||||
|         ); | ||||
|         state.conversionRate = state.conversionRate.safeDiv(state.fromTokenBalance); | ||||
|         state.conversionRate = state.conversionRate.safeDiv( | ||||
|             10 ** uint256(LibERC20Token.decimals(toTokenAddress)) | ||||
|         ); | ||||
|         if (state.fromTokenAddress == toTokenAddress) { | ||||
|             // Just transfer the tokens if they're the same. | ||||
|             LibERC20Token.transfer(state.fromTokenAddress, to, state.fromTokenBalance); | ||||
|             return BRIDGE_SUCCESS; | ||||
|         } else if (state.fromTokenAddress != address(state.weth)) { | ||||
|             // If the input token is not WETH, grant an allowance to the exchange | ||||
|             // to spend them. | ||||
|             LibERC20Token.approve(state.fromTokenAddress, address(state.kyber), uint256(-1)); | ||||
|         } else { | ||||
|             // If the input token is WETH, unwrap it and attach it to the call. | ||||
|             state.fromTokenAddress = KYBER_ETH_ADDRESS; | ||||
|             state.payableAmount = state.fromTokenBalance; | ||||
|             state.weth.withdraw(state.fromTokenBalance); | ||||
|         } | ||||
|         bool isToTokenWeth = toTokenAddress == address(state.weth); | ||||
|  | ||||
|         // Try to sell all of this contract's input token balance through | ||||
|         // `KyberNetworkProxy.trade()`. | ||||
|         uint256 boughtAmount = state.kyber.trade.value(state.payableAmount)( | ||||
|             // Input token. | ||||
|             state.fromTokenAddress, | ||||
|             // Sell amount. | ||||
|             state.fromTokenBalance, | ||||
|             // Output token. | ||||
|             isToTokenWeth ? KYBER_ETH_ADDRESS : toTokenAddress, | ||||
|             // Transfer to this contract if converting to ETH, otherwise | ||||
|             // transfer directly to the recipient. | ||||
|             isToTokenWeth ? address(uint160(address(this))) : address(uint160(to)), | ||||
|             // Buy as much as possible. | ||||
|             uint256(-1), | ||||
|             // Compute the minimum conversion rate, which is expressed in units with | ||||
|             // 18 decimal places. | ||||
|             state.conversionRate, | ||||
|             // No affiliate address. | ||||
|             address(0) | ||||
|         ); | ||||
|         // Wrap ETH output and transfer to recipient. | ||||
|         if (isToTokenWeth) { | ||||
|             state.weth.deposit.value(boughtAmount)(); | ||||
|             state.weth.transfer(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; | ||||
|     } | ||||
| } | ||||
| @@ -1,200 +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.9; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; | ||||
| import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol"; | ||||
| import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol"; | ||||
| import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol"; | ||||
| import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; | ||||
| import "../interfaces/IUniswapExchangeFactory.sol"; | ||||
| import "../interfaces/IUniswapExchange.sol"; | ||||
| import "../interfaces/IERC20Bridge.sol"; | ||||
|  | ||||
|  | ||||
| // solhint-disable space-after-comma | ||||
| // solhint-disable not-rely-on-time | ||||
| contract UniswapBridge is | ||||
|     IERC20Bridge, | ||||
|     IWallet, | ||||
|     DeploymentConstants | ||||
| { | ||||
|     // Struct to hold `bridgeTransferFrom()` local variables in memory and to avoid | ||||
|     // stack overflows. | ||||
|     struct WithdrawToState { | ||||
|         IUniswapExchange exchange; | ||||
|         uint256 fromTokenBalance; | ||||
|         IEtherToken weth; | ||||
|     } | ||||
|  | ||||
|     // solhint-disable no-empty-blocks | ||||
|     /// @dev Payable fallback to receive ETH from uniswap. | ||||
|     function () | ||||
|         external | ||||
|         payable | ||||
|     {} | ||||
|  | ||||
|     /// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of | ||||
|     ///      `toTokenAddress` tokens by selling the entirety of the `fromTokenAddress` | ||||
|     ///      token encoded in the bridge data. | ||||
|     /// @param toTokenAddress The token to buy and transfer to `to`. | ||||
|     /// @param to The recipient of the bought tokens. | ||||
|     /// @param amount Minimum amount of `toTokenAddress` tokens to buy. | ||||
|     /// @param bridgeData The abi-encoded "from" token address. | ||||
|     /// @return success The magic bytes if successful. | ||||
|     function bridgeTransferFrom( | ||||
|         address toTokenAddress, | ||||
|         address /* from */, | ||||
|         address to, | ||||
|         uint256 amount, | ||||
|         bytes calldata bridgeData | ||||
|     ) | ||||
|         external | ||||
|         returns (bytes4 success) | ||||
|     { | ||||
|         // State memory object to avoid stack overflows. | ||||
|         WithdrawToState memory state; | ||||
|         // Decode the bridge data to get the `fromTokenAddress`. | ||||
|         (address fromTokenAddress) = abi.decode(bridgeData, (address)); | ||||
|  | ||||
|         // Just transfer the tokens if they're the same. | ||||
|         if (fromTokenAddress == toTokenAddress) { | ||||
|             LibERC20Token.transfer(fromTokenAddress, to, amount); | ||||
|             return BRIDGE_SUCCESS; | ||||
|         } | ||||
|  | ||||
|         // Get the exchange for the token pair. | ||||
|         state.exchange = _getUniswapExchangeForTokenPair( | ||||
|             fromTokenAddress, | ||||
|             toTokenAddress | ||||
|         ); | ||||
|         // Get our balance of `fromTokenAddress` token. | ||||
|         state.fromTokenBalance = IERC20Token(fromTokenAddress).balanceOf(address(this)); | ||||
|         // Get the weth contract. | ||||
|         state.weth = IEtherToken(_getWethAddress()); | ||||
|  | ||||
|         // Convert from WETH to a token. | ||||
|         if (fromTokenAddress == address(state.weth)) { | ||||
|             // Unwrap the WETH. | ||||
|             state.weth.withdraw(state.fromTokenBalance); | ||||
|             // Buy as much of `toTokenAddress` token with ETH as possible and | ||||
|             // transfer it to `to`. | ||||
|             state.exchange.ethToTokenTransferInput.value(state.fromTokenBalance)( | ||||
|                 // Minimum buy amount. | ||||
|                 amount, | ||||
|                 // Expires after this block. | ||||
|                 block.timestamp, | ||||
|                 // Recipient is `to`. | ||||
|                 to | ||||
|             ); | ||||
|  | ||||
|         // Convert from a token to WETH. | ||||
|         } else if (toTokenAddress == address(state.weth)) { | ||||
|             // Grant the exchange an allowance. | ||||
|             _grantExchangeAllowance(state.exchange, fromTokenAddress); | ||||
|             // Buy as much ETH with `fromTokenAddress` token as possible. | ||||
|             uint256 ethBought = state.exchange.tokenToEthSwapInput( | ||||
|                 // Sell all tokens we hold. | ||||
|                 state.fromTokenBalance, | ||||
|                 // Minimum buy amount. | ||||
|                 amount, | ||||
|                 // Expires after this block. | ||||
|                 block.timestamp | ||||
|             ); | ||||
|             // Wrap the ETH. | ||||
|             state.weth.deposit.value(ethBought)(); | ||||
|             // Transfer the WETH to `to`. | ||||
|             IEtherToken(toTokenAddress).transfer(to, ethBought); | ||||
|  | ||||
|         // Convert from one token to another. | ||||
|         } else { | ||||
|             // Grant the exchange an allowance. | ||||
|             _grantExchangeAllowance(state.exchange, fromTokenAddress); | ||||
|             // Buy as much `toTokenAddress` token with `fromTokenAddress` token | ||||
|             // and transfer it to `to`. | ||||
|             state.exchange.tokenToTokenTransferInput( | ||||
|                 // Sell all tokens we hold. | ||||
|                 state.fromTokenBalance, | ||||
|                 // Minimum buy amount. | ||||
|                 amount, | ||||
|                 // Must buy at least 1 intermediate ETH. | ||||
|                 1, | ||||
|                 // Expires after this block. | ||||
|                 block.timestamp, | ||||
|                 // Recipient is `to`. | ||||
|                 to, | ||||
|                 // Convert to `toTokenAddress`. | ||||
|                 toTokenAddress | ||||
|             ); | ||||
|         } | ||||
|         return BRIDGE_SUCCESS; | ||||
|     } | ||||
|  | ||||
|     /// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker | ||||
|     ///      and sign for itself in orders. Always succeeds. | ||||
|     /// @return magicValue Success bytes, always. | ||||
|     function isValidSignature( | ||||
|         bytes32, | ||||
|         bytes calldata | ||||
|     ) | ||||
|         external | ||||
|         view | ||||
|         returns (bytes4 magicValue) | ||||
|     { | ||||
|         return LEGACY_WALLET_MAGIC_VALUE; | ||||
|     } | ||||
|  | ||||
|     /// @dev Grants an unlimited allowance to the exchange for its token | ||||
|     ///      on behalf of this contract. | ||||
|     /// @param exchange The Uniswap token exchange. | ||||
|     /// @param tokenAddress The token address for the exchange. | ||||
|     function _grantExchangeAllowance(IUniswapExchange exchange, address tokenAddress) | ||||
|         private | ||||
|     { | ||||
|         LibERC20Token.approve(tokenAddress, address(exchange), uint256(-1)); | ||||
|     } | ||||
|  | ||||
|     /// @dev Retrieves the uniswap exchange for a given token pair. | ||||
|     ///      In the case of a WETH-token exchange, this will be the non-WETH token. | ||||
|     ///      In th ecase of a token-token exchange, this will be the first token. | ||||
|     /// @param fromTokenAddress The address of the token we are converting from. | ||||
|     /// @param toTokenAddress The address of the token we are converting to. | ||||
|     /// @return exchange The uniswap exchange. | ||||
|     function _getUniswapExchangeForTokenPair( | ||||
|         address fromTokenAddress, | ||||
|         address toTokenAddress | ||||
|     ) | ||||
|         private | ||||
|         view | ||||
|         returns (IUniswapExchange exchange) | ||||
|     { | ||||
|         address exchangeTokenAddress = fromTokenAddress; | ||||
|         // Whichever isn't WETH is the exchange token. | ||||
|         if (fromTokenAddress == _getWethAddress()) { | ||||
|             exchangeTokenAddress = toTokenAddress; | ||||
|         } | ||||
|         exchange = IUniswapExchange( | ||||
|             IUniswapExchangeFactory(_getUniswapExchangeFactoryAddress()) | ||||
|             .getExchange(exchangeTokenAddress) | ||||
|         ); | ||||
|         require(address(exchange) != address(0), "NO_UNISWAP_EXCHANGE_FOR_TOKEN"); | ||||
|         return exchange; | ||||
|     } | ||||
| } | ||||
| @@ -1,88 +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. | ||||
|  | ||||
| */ | ||||
|  | ||||
| // solhint-disable | ||||
| pragma solidity ^0.5.9; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
|  | ||||
| // @dev Interface of the asset proxy's assetData. | ||||
| // The asset proxies take an ABI encoded `bytes assetData` as argument. | ||||
| // 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 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 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 staticCallTargetAddress, | ||||
|         bytes calldata staticCallData, | ||||
|         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,43 +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.9; | ||||
|  | ||||
|  | ||||
| contract IAssetProxy { | ||||
|  | ||||
|     /// @dev Transfers assets. Either succeeds or throws. | ||||
|     /// @param assetData Byte array encoded for the respective asset proxy. | ||||
|     /// @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; | ||||
|      | ||||
|     /// @dev Gets the proxy id associated with the proxy address. | ||||
|     /// @return Proxy id. | ||||
|     function getProxyId() | ||||
|         external | ||||
|         pure | ||||
|         returns (bytes4); | ||||
| } | ||||
| @@ -1,43 +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.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. | ||||
|     function registerAssetProxy(address assetProxy) | ||||
|         external; | ||||
|  | ||||
|     /// @dev Gets an asset proxy. | ||||
|     /// @param assetProxyId Id of the asset proxy. | ||||
|     /// @return The asset proxy registered to assetProxyId. Returns 0x0 if no proxy is registered. | ||||
|     function getAssetProxy(bytes4 assetProxyId) | ||||
|         external | ||||
|         view | ||||
|         returns (address); | ||||
| } | ||||
| @@ -1,64 +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.9; | ||||
|  | ||||
| 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) | ||||
|         external; | ||||
|  | ||||
|     /// @dev Removes authorizion of an address. | ||||
|     /// @param target Address to remove authorization from. | ||||
|     function removeAuthorizedAddress(address target) | ||||
|         external; | ||||
|  | ||||
|     /// @dev Removes authorizion of an address. | ||||
|     /// @param target Address to remove authorization from. | ||||
|     /// @param index Index of target in authorities array. | ||||
|     function removeAuthorizedAddressAtIndex( | ||||
|         address target, | ||||
|         uint256 index | ||||
|     ) | ||||
|         external; | ||||
|  | ||||
|     /// @dev Gets all authorized addresses. | ||||
|     /// @return Array of authorized addresses. | ||||
|     function getAuthorizedAddresses() | ||||
|         external | ||||
|         view | ||||
|         returns (address[] memory); | ||||
| } | ||||
| @@ -1,66 +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.9; | ||||
|  | ||||
| import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; | ||||
|  | ||||
|  | ||||
| contract PotLike { | ||||
|     function chi() external returns (uint256); | ||||
|     function rho() external returns (uint256); | ||||
|     function drip() external returns (uint256); | ||||
|     function join(uint256) external; | ||||
|     function exit(uint256) external; | ||||
| } | ||||
|  | ||||
|  | ||||
| // The actual Chai contract can be found here: https://github.com/dapphub/chai | ||||
| contract IChai is | ||||
|     IERC20Token | ||||
| { | ||||
|     /// @dev Withdraws Dai owned by `src` | ||||
|     /// @param src Address that owns Dai. | ||||
|     /// @param wad Amount of Dai to withdraw. | ||||
|     function draw( | ||||
|         address src, | ||||
|         uint256 wad | ||||
|     ) | ||||
|         external; | ||||
|  | ||||
|     /// @dev Queries Dai balance of Chai holder. | ||||
|     /// @param usr Address of Chai holder. | ||||
|     /// @return Dai balance. | ||||
|     function dai(address usr) | ||||
|         external | ||||
|         returns (uint256); | ||||
|  | ||||
|     /// @dev Queries the Pot contract used by the Chai contract. | ||||
|     function pot() | ||||
|         external | ||||
|         returns (PotLike); | ||||
|  | ||||
|     /// @dev Deposits Dai in exchange for Chai | ||||
|     /// @param dst Address to receive Chai. | ||||
|     /// @param wad Amount of Dai to deposit. | ||||
|     function join( | ||||
|         address dst, | ||||
|         uint256 wad | ||||
|     ) | ||||
|         external; | ||||
| } | ||||
| @@ -1,87 +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.9; | ||||
|  | ||||
|  | ||||
| // solhint-disable func-name-mixedcase | ||||
| interface ICurve { | ||||
|  | ||||
|     /// @dev Sell `sellAmount` of `fromToken` token and receive `toToken` token. | ||||
|     ///      This function exists on early versions of Curve (USDC/DAI) | ||||
|     /// @param i The token index being sold. | ||||
|     /// @param j The token index being bought. | ||||
|     /// @param sellAmount The amount of token being bought. | ||||
|     /// @param minBuyAmount The minimum buy amount of the token being bought. | ||||
|     /// @param deadline The time in seconds when this operation should expire. | ||||
|     function exchange_underlying( | ||||
|         int128 i, | ||||
|         int128 j, | ||||
|         uint256 sellAmount, | ||||
|         uint256 minBuyAmount, | ||||
|         uint256 deadline | ||||
|     ) | ||||
|         external; | ||||
|  | ||||
|     /// @dev Sell `sellAmount` of `fromToken` token and receive `toToken` token. | ||||
|     ///      This function exists on later versions of Curve (USDC/DAI/USDT) | ||||
|     /// @param i The token index being sold. | ||||
|     /// @param j The token index being bought. | ||||
|     /// @param sellAmount The amount of token being bought. | ||||
|     /// @param minBuyAmount The minimum buy amount of the token being bought. | ||||
|     function exchange_underlying( | ||||
|         int128 i, | ||||
|         int128 j, | ||||
|         uint256 sellAmount, | ||||
|         uint256 minBuyAmount | ||||
|     ) | ||||
|         external; | ||||
|  | ||||
|     /// @dev Get the amount of `toToken` by selling `sellAmount` of `fromToken` | ||||
|     /// @param i The token index being sold. | ||||
|     /// @param j The token index being bought. | ||||
|     /// @param sellAmount The amount of token being bought. | ||||
|     function get_dy_underlying( | ||||
|         int128 i, | ||||
|         int128 j, | ||||
|         uint256 sellAmount | ||||
|     ) | ||||
|         external | ||||
|         returns (uint256 dy); | ||||
|  | ||||
|     /// @dev Get the amount of `fromToken` by buying `buyAmount` of `toToken` | ||||
|     ///      This function exists on later versions of Curve (USDC/DAI/USDT) | ||||
|     /// @param i The token index being sold. | ||||
|     /// @param j The token index being bought. | ||||
|     /// @param buyAmount The amount of token being bought. | ||||
|     function get_dx_underlying( | ||||
|         int128 i, | ||||
|         int128 j, | ||||
|         uint256 buyAmount | ||||
|     ) | ||||
|         external | ||||
|         returns (uint256 dx); | ||||
|  | ||||
|     /// @dev Get the underlying token address from the token index | ||||
|     /// @param i The token index. | ||||
|     function underlying_coins( | ||||
|         int128 i | ||||
|     ) | ||||
|         external | ||||
|         returns (address tokenAddress); | ||||
| } | ||||
| @@ -1,192 +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.9; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
|  | ||||
| interface IDydx { | ||||
|  | ||||
|     /// @dev Represents the unique key that specifies an account | ||||
|     struct AccountInfo { | ||||
|         address owner;  // The address that owns the account | ||||
|         uint256 number; // A nonce that allows a single address to control many accounts | ||||
|     } | ||||
|  | ||||
|     enum ActionType { | ||||
|         Deposit,   // supply tokens | ||||
|         Withdraw,  // borrow tokens | ||||
|         Transfer,  // transfer balance between accounts | ||||
|         Buy,       // buy an amount of some token (externally) | ||||
|         Sell,      // sell an amount of some token (externally) | ||||
|         Trade,     // trade tokens against another account | ||||
|         Liquidate, // liquidate an undercollateralized or expiring account | ||||
|         Vaporize,  // use excess tokens to zero-out a completely negative account | ||||
|         Call       // send arbitrary data to an address | ||||
|     } | ||||
|  | ||||
|     /// @dev Arguments that are passed to Solo in an ordered list as part of a single operation. | ||||
|     /// Each ActionArgs has an actionType which specifies which action struct that this data will be | ||||
|     /// parsed into before being processed. | ||||
|     struct ActionArgs { | ||||
|         ActionType actionType; | ||||
|         uint256 accountIdx; | ||||
|         AssetAmount amount; | ||||
|         uint256 primaryMarketId; | ||||
|         uint256 secondaryMarketId; | ||||
|         address otherAddress; | ||||
|         uint256 otherAccountIdx; | ||||
|         bytes data; | ||||
|     } | ||||
|  | ||||
|     enum AssetDenomination { | ||||
|         Wei, // the amount is denominated in wei | ||||
|         Par  // the amount is denominated in par | ||||
|     } | ||||
|  | ||||
|     enum AssetReference { | ||||
|         Delta, // the amount is given as a delta from the current value | ||||
|         Target // the amount is given as an exact number to end up at | ||||
|     } | ||||
|  | ||||
|     struct AssetAmount { | ||||
|         bool sign; // true if positive | ||||
|         AssetDenomination denomination; | ||||
|         AssetReference ref; | ||||
|         uint256 value; | ||||
|     } | ||||
|  | ||||
|     struct D256 { | ||||
|         uint256 value; | ||||
|     } | ||||
|  | ||||
|     struct Value { | ||||
|         uint256 value; | ||||
|     } | ||||
|  | ||||
|     struct Price { | ||||
|         uint256 value; | ||||
|     } | ||||
|  | ||||
|     struct OperatorArg { | ||||
|         address operator; | ||||
|         bool trusted; | ||||
|     } | ||||
|  | ||||
|     /// @dev The global risk parameters that govern the health and security of the system | ||||
|     struct RiskParams { | ||||
|         // Required ratio of over-collateralization | ||||
|         D256 marginRatio; | ||||
|         // Percentage penalty incurred by liquidated accounts | ||||
|         D256 liquidationSpread; | ||||
|         // Percentage of the borrower's interest fee that gets passed to the suppliers | ||||
|         D256 earningsRate; | ||||
|         // The minimum absolute borrow value of an account | ||||
|         // There must be sufficient incentivize to liquidate undercollateralized accounts | ||||
|         Value minBorrowedValue; | ||||
|     } | ||||
|  | ||||
|     /// @dev The main entry-point to Solo that allows users and contracts to manage accounts. | ||||
|     ///      Take one or more actions on one or more accounts. The msg.sender must be the owner or | ||||
|     ///      operator of all accounts except for those being liquidated, vaporized, or traded with. | ||||
|     ///      One call to operate() is considered a singular "operation". Account collateralization is | ||||
|     ///      ensured only after the completion of the entire operation. | ||||
|     /// @param  accounts  A list of all accounts that will be used in this operation. Cannot contain | ||||
|     ///                   duplicates. In each action, the relevant account will be referred-to by its | ||||
|     ///                   index in the list. | ||||
|     /// @param  actions   An ordered list of all actions that will be taken in this operation. The | ||||
|     ///                   actions will be processed in order. | ||||
|     function operate( | ||||
|         AccountInfo[] calldata accounts, | ||||
|         ActionArgs[] calldata actions | ||||
|     ) | ||||
|         external; | ||||
|  | ||||
|     // @dev Approves/disapproves any number of operators. An operator is an external address that has the | ||||
|     //      same permissions to manipulate an account as the owner of the account. Operators are simply | ||||
|     //      addresses and therefore may either be externally-owned Ethereum accounts OR smart contracts. | ||||
|     //      Operators are also able to act as AutoTrader contracts on behalf of the account owner if the | ||||
|     //      operator is a smart contract and implements the IAutoTrader interface. | ||||
|     // @param args A list of OperatorArgs which have an address and a boolean. The boolean value | ||||
|     //        denotes whether to approve (true) or revoke approval (false) for that address. | ||||
|     function setOperators(OperatorArg[] calldata args) external; | ||||
|  | ||||
|     /// @dev Return true if a particular address is approved as an operator for an owner's accounts. | ||||
|     ///      Approved operators can act on the accounts of the owner as if it were the operator's own. | ||||
|     /// @param owner The owner of the accounts | ||||
|     /// @param operator The possible operator | ||||
|     /// @return isLocalOperator True if operator is approved for owner's accounts | ||||
|     function getIsLocalOperator( | ||||
|         address owner, | ||||
|         address operator | ||||
|     ) | ||||
|         external | ||||
|         view | ||||
|         returns (bool isLocalOperator); | ||||
|  | ||||
|     /// @dev Get the ERC20 token address for a market. | ||||
|     /// @param marketId The market to query | ||||
|     /// @return tokenAddress The token address | ||||
|     function getMarketTokenAddress( | ||||
|         uint256 marketId | ||||
|     ) | ||||
|         external | ||||
|         view | ||||
|         returns (address tokenAddress); | ||||
|  | ||||
|     /// @dev Get all risk parameters in a single struct. | ||||
|     /// @return riskParams All global risk parameters | ||||
|     function getRiskParams() | ||||
|         external | ||||
|         view | ||||
|         returns (RiskParams memory riskParams); | ||||
|  | ||||
|     /// @dev Get the price of the token for a market. | ||||
|     /// @param marketId The market to query | ||||
|     /// @return price The price of each atomic unit of the token | ||||
|     function getMarketPrice( | ||||
|         uint256 marketId | ||||
|     ) | ||||
|         external | ||||
|         view | ||||
|         returns (Price memory price); | ||||
|  | ||||
|     /// @dev Get the margin premium for a market. A margin premium makes it so that any positions that | ||||
|     ///      include the market require a higher collateralization to avoid being liquidated. | ||||
|     /// @param  marketId  The market to query | ||||
|     /// @return premium The market's margin premium | ||||
|     function getMarketMarginPremium(uint256 marketId) | ||||
|         external | ||||
|         view | ||||
|         returns (D256 memory premium); | ||||
|  | ||||
|     /// @dev Get the total supplied and total borrowed values of an account adjusted by the marginPremium | ||||
|     ///      of each market. Supplied values are divided by (1 + marginPremium) for each market and | ||||
|     ///      borrowed values are multiplied by (1 + marginPremium) for each market. Comparing these | ||||
|     ///      adjusted values gives the margin-ratio of the account which will be compared to the global | ||||
|     ///      margin-ratio when determining if the account can be liquidated. | ||||
|     /// @param account The account to query | ||||
|     /// @return supplyValue The supplied value of the account (adjusted for marginPremium) | ||||
|     /// @return borrowValue The borrowed value of the account (adjusted for marginPremium) | ||||
|     function getAdjustedAccountValues( | ||||
|         AccountInfo calldata account | ||||
|     ) | ||||
|         external | ||||
|         view | ||||
|         returns (Value memory supplyValue, Value memory borrowValue); | ||||
| } | ||||
| @@ -1,42 +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.9; | ||||
|  | ||||
|  | ||||
| interface IDydxBridge { | ||||
|  | ||||
|     /// @dev This is the subset of `IDydx.ActionType` that are supported by the bridge. | ||||
|     enum BridgeActionType { | ||||
|         Deposit,                    // Deposit tokens into dydx account. | ||||
|         Withdraw                    // Withdraw tokens from dydx account. | ||||
|     } | ||||
|  | ||||
|     struct BridgeAction { | ||||
|         BridgeActionType actionType;            // Action to run on dydx account. | ||||
|         uint256 accountIdx;                     // Index in `BridgeData.accountNumbers` for this action. | ||||
|         uint256 marketId;                       // Market to operate on. | ||||
|         uint256 conversionRateNumerator;        // Optional. If set, transfer amount is scaled by (conversionRateNumerator/conversionRateDenominator). | ||||
|         uint256 conversionRateDenominator;      // Optional. If set, transfer amount is scaled by (conversionRateNumerator/conversionRateDenominator). | ||||
|     } | ||||
|  | ||||
|     struct BridgeData { | ||||
|         uint256[] accountNumbers;               // Account number used to identify the owner's specific account. | ||||
|         BridgeAction[] actions;                 // Actions to carry out on the owner's accounts. | ||||
|     } | ||||
| } | ||||
| @@ -1,43 +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.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 bridgeTransferFrom( | ||||
|         address tokenAddress, | ||||
|         address from, | ||||
|         address to, | ||||
|         uint256 amount, | ||||
|         bytes calldata bridgeData | ||||
|     ) | ||||
|         external | ||||
|         returns (bytes4 success); | ||||
| } | ||||
| @@ -1,38 +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.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,46 +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.9; | ||||
|  | ||||
|  | ||||
| interface IKyberNetworkProxy { | ||||
|  | ||||
|     /// @dev Sells `sellTokenAddress` tokens for `buyTokenAddress` tokens. | ||||
|     /// @param sellTokenAddress Token to sell. | ||||
|     /// @param sellAmount Amount of tokens to sell. | ||||
|     /// @param buyTokenAddress Token to buy. | ||||
|     /// @param recipientAddress Address to send bought tokens to. | ||||
|     /// @param maxBuyTokenAmount A limit on the amount of tokens to buy. | ||||
|     /// @param minConversionRate The minimal conversion rate. If actual rate | ||||
|     ///        is lower, trade is canceled. | ||||
|     /// @param walletId The wallet ID to send part of the fees | ||||
|     /// @return boughtAmount Amount of tokens bought. | ||||
|     function trade( | ||||
|         address sellTokenAddress, | ||||
|         uint256 sellAmount, | ||||
|         address buyTokenAddress, | ||||
|         address payable recipientAddress, | ||||
|         uint256 maxBuyTokenAmount, | ||||
|         uint256 minConversionRate, | ||||
|         address walletId | ||||
|     ) | ||||
|         external | ||||
|         payable | ||||
|         returns(uint256 boughtAmount); | ||||
| } | ||||
| @@ -1,70 +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.9; | ||||
|  | ||||
|  | ||||
| interface IUniswapExchange { | ||||
|  | ||||
|     /// @dev Buys at least `minTokensBought` tokens with ETH and transfer them | ||||
|     ///      to `recipient`. | ||||
|     /// @param minTokensBought The minimum number of tokens to buy. | ||||
|     /// @param deadline Time when this order expires. | ||||
|     /// @param recipient Who to transfer the tokens to. | ||||
|     /// @return tokensBought Amount of tokens bought. | ||||
|     function ethToTokenTransferInput( | ||||
|         uint256 minTokensBought, | ||||
|         uint256 deadline, | ||||
|         address recipient | ||||
|     ) | ||||
|         external | ||||
|         payable | ||||
|         returns (uint256 tokensBought); | ||||
|  | ||||
|     /// @dev Buys at least `minEthBought` ETH with tokens. | ||||
|     /// @param tokensSold Amount of tokens to sell. | ||||
|     /// @param minEthBought The minimum amount of ETH to buy. | ||||
|     /// @param deadline Time when this order expires. | ||||
|     /// @return ethBought Amount of tokens bought. | ||||
|     function tokenToEthSwapInput( | ||||
|         uint256 tokensSold, | ||||
|         uint256 minEthBought, | ||||
|         uint256 deadline | ||||
|     ) | ||||
|         external | ||||
|         returns (uint256 ethBought); | ||||
|  | ||||
|     /// @dev Buys at least `minTokensBought` tokens with the exchange token | ||||
|     ///      and transfer them to `recipient`. | ||||
|     /// @param minTokensBought The minimum number of tokens to buy. | ||||
|     /// @param minEthBought The minimum amount of intermediate ETH to buy. | ||||
|     /// @param deadline Time when this order expires. | ||||
|     /// @param recipient Who to transfer the tokens to. | ||||
|     /// @param toTokenAddress The token being bought. | ||||
|     /// @return tokensBought Amount of tokens bought. | ||||
|     function tokenToTokenTransferInput( | ||||
|         uint256 tokensSold, | ||||
|         uint256 minTokensBought, | ||||
|         uint256 minEthBought, | ||||
|         uint256 deadline, | ||||
|         address recipient, | ||||
|         address toTokenAddress | ||||
|     ) | ||||
|         external | ||||
|         returns (uint256 tokensBought); | ||||
| } | ||||
| @@ -1,32 +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.9; | ||||
|  | ||||
| import "./IUniswapExchange.sol"; | ||||
|  | ||||
|  | ||||
| interface IUniswapExchangeFactory { | ||||
|  | ||||
|     /// @dev Get the exchange for a token. | ||||
|     /// @param tokenAddress The address of the token contract. | ||||
|     function getExchange(address tokenAddress) | ||||
|         external | ||||
|         view | ||||
|         returns (address); | ||||
| } | ||||
| @@ -1,80 +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.9; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "../src/bridges/ChaiBridge.sol"; | ||||
| import "@0x/contracts-erc20/contracts/src/ERC20Token.sol"; | ||||
|  | ||||
|  | ||||
| contract TestChaiDai is | ||||
|     ERC20Token | ||||
| { | ||||
|     address private constant ALWAYS_REVERT_ADDRESS = address(1); | ||||
|  | ||||
|     function draw( | ||||
|         address from, | ||||
|         uint256 amount | ||||
|     ) | ||||
|         external | ||||
|     { | ||||
|         if (from == ALWAYS_REVERT_ADDRESS) { | ||||
|             revert(); | ||||
|         } | ||||
|         balances[msg.sender] += amount; | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
| contract TestChaiBridge is | ||||
|     ChaiBridge | ||||
| { | ||||
|     address public testChaiDai; | ||||
|     address private constant ALWAYS_REVERT_ADDRESS = address(1); | ||||
|  | ||||
|     constructor() | ||||
|         public | ||||
|     { | ||||
|         testChaiDai = address(new TestChaiDai()); | ||||
|     } | ||||
|  | ||||
|     function _getDaiAddress() | ||||
|         internal | ||||
|         view | ||||
|         returns (address) | ||||
|     { | ||||
|         return testChaiDai; | ||||
|     } | ||||
|  | ||||
|     function _getChaiAddress() | ||||
|         internal | ||||
|         view | ||||
|         returns (address) | ||||
|     { | ||||
|         return testChaiDai; | ||||
|     } | ||||
|  | ||||
|     function _getERC20BridgeProxyAddress() | ||||
|         internal | ||||
|         view | ||||
|         returns (address) | ||||
|     { | ||||
|         return msg.sender == ALWAYS_REVERT_ADDRESS ? address(0) : msg.sender; | ||||
|     } | ||||
| } | ||||
| @@ -1,246 +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.9; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; | ||||
| import "../src/bridges/DydxBridge.sol"; | ||||
|  | ||||
|  | ||||
| // solhint-disable no-empty-blocks | ||||
| contract TestDydxBridgeToken { | ||||
|  | ||||
|     uint256 private constant INIT_HOLDER_BALANCE = 10 * 10**18; // 10 tokens | ||||
|     mapping (address => uint256) private _balances; | ||||
|  | ||||
|     /// @dev Sets initial balance of token holders. | ||||
|     constructor(address[] memory holders) | ||||
|         public | ||||
|     { | ||||
|         for (uint256 i = 0; i != holders.length; ++i) { | ||||
|             _balances[holders[i]] = INIT_HOLDER_BALANCE; | ||||
|         } | ||||
|         _balances[msg.sender] = INIT_HOLDER_BALANCE; | ||||
|     } | ||||
|  | ||||
|     /// @dev Basic transferFrom implementation. | ||||
|     function transferFrom(address from, address to, uint256 amount) | ||||
|         external | ||||
|         returns (bool) | ||||
|     { | ||||
|         if (_balances[from] < amount || _balances[to] + amount < _balances[to]) { | ||||
|             return false; | ||||
|         } | ||||
|         _balances[from] -= amount; | ||||
|         _balances[to] += amount; | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     /// @dev Returns balance of `holder`. | ||||
|     function balanceOf(address holder) | ||||
|         external | ||||
|         view | ||||
|         returns (uint256) | ||||
|     { | ||||
|         return _balances[holder]; | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
| // solhint-disable space-after-comma | ||||
| contract TestDydxBridge is | ||||
|     IDydx, | ||||
|     DydxBridge | ||||
| { | ||||
|  | ||||
|     address private constant ALWAYS_REVERT_ADDRESS = address(1); | ||||
|     address private _testTokenAddress; | ||||
|     bool private _shouldRevertOnOperate; | ||||
|  | ||||
|     event OperateAccount( | ||||
|         address owner, | ||||
|         uint256 number | ||||
|     ); | ||||
|  | ||||
|     event OperateAction( | ||||
|         ActionType actionType, | ||||
|         uint256 accountIdx, | ||||
|         bool amountSign, | ||||
|         AssetDenomination amountDenomination, | ||||
|         AssetReference amountRef, | ||||
|         uint256 amountValue, | ||||
|         uint256 primaryMarketId, | ||||
|         uint256 secondaryMarketId, | ||||
|         address otherAddress, | ||||
|         uint256 otherAccountId, | ||||
|         bytes data | ||||
|     ); | ||||
|  | ||||
|     constructor(address[] memory holders) | ||||
|         public | ||||
|     { | ||||
|         // Deploy a test token. This represents the asset being deposited/withdrawn from dydx. | ||||
|         _testTokenAddress = address(new TestDydxBridgeToken(holders)); | ||||
|     } | ||||
|  | ||||
|     /// @dev Simulates `operate` in dydx contract. | ||||
|     ///      Emits events so that arguments can be validated client-side. | ||||
|     function operate( | ||||
|         AccountInfo[] calldata accounts, | ||||
|         ActionArgs[] calldata actions | ||||
|     ) | ||||
|         external | ||||
|     { | ||||
|         if (_shouldRevertOnOperate) { | ||||
|             revert("TestDydxBridge/SHOULD_REVERT_ON_OPERATE"); | ||||
|         } | ||||
|  | ||||
|         for (uint i = 0; i < accounts.length; ++i) { | ||||
|             emit OperateAccount( | ||||
|                 accounts[i].owner, | ||||
|                 accounts[i].number | ||||
|             ); | ||||
|         } | ||||
|  | ||||
|         for (uint i = 0; i < actions.length; ++i) { | ||||
|             emit OperateAction( | ||||
|                 actions[i].actionType, | ||||
|                 actions[i].accountIdx, | ||||
|                 actions[i].amount.sign, | ||||
|                 actions[i].amount.denomination, | ||||
|                 actions[i].amount.ref, | ||||
|                 actions[i].amount.value, | ||||
|                 actions[i].primaryMarketId, | ||||
|                 actions[i].secondaryMarketId, | ||||
|                 actions[i].otherAddress, | ||||
|                 actions[i].otherAccountIdx, | ||||
|                 actions[i].data | ||||
|             ); | ||||
|  | ||||
|             if (actions[i].actionType == IDydx.ActionType.Withdraw) { | ||||
|                 require( | ||||
|                     IERC20Token(_testTokenAddress).transferFrom( | ||||
|                         address(this), | ||||
|                         actions[i].otherAddress, | ||||
|                         actions[i].amount.value | ||||
|                     ), | ||||
|                     "TestDydxBridge/WITHDRAW_FAILED" | ||||
|                 ); | ||||
|             } else if (actions[i].actionType == IDydx.ActionType.Deposit) { | ||||
|                 require( | ||||
|                     IERC20Token(_testTokenAddress).transferFrom( | ||||
|                         actions[i].otherAddress, | ||||
|                         address(this), | ||||
|                         actions[i].amount.value | ||||
|                     ), | ||||
|                     "TestDydxBridge/DEPOSIT_FAILED" | ||||
|                 ); | ||||
|             } else { | ||||
|                 revert("TestDydxBridge/UNSUPPORTED_ACTION"); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// @dev If `true` then subsequent calls to `operate` will revert. | ||||
|     function setRevertOnOperate(bool shouldRevert) | ||||
|         external | ||||
|     { | ||||
|         _shouldRevertOnOperate = shouldRevert; | ||||
|     } | ||||
|  | ||||
|     /// @dev Returns test token. | ||||
|     function getTestToken() | ||||
|         external | ||||
|         returns (address) | ||||
|     { | ||||
|         return _testTokenAddress; | ||||
|     } | ||||
|  | ||||
|     /// @dev Unused. | ||||
|     function setOperators(OperatorArg[] calldata args) external {} | ||||
|  | ||||
|     /// @dev Unused. | ||||
|     function getIsLocalOperator( | ||||
|         address owner, | ||||
|         address operator | ||||
|     ) | ||||
|         external | ||||
|         view | ||||
|         returns (bool isLocalOperator) | ||||
|     {} | ||||
|  | ||||
|     /// @dev Unused. | ||||
|     function getMarketTokenAddress( | ||||
|         uint256 marketId | ||||
|     ) | ||||
|         external | ||||
|         view | ||||
|         returns (address tokenAddress) | ||||
|     {} | ||||
|  | ||||
|     /// @dev Unused. | ||||
|     function getRiskParams() | ||||
|         external | ||||
|         view | ||||
|         returns (RiskParams memory riskParams) | ||||
|     {} | ||||
|  | ||||
|     /// @dev Unsused. | ||||
|     function getMarketPrice( | ||||
|         uint256 marketId | ||||
|     ) | ||||
|         external | ||||
|         view | ||||
|         returns (Price memory price) | ||||
|     {} | ||||
|  | ||||
|     /// @dev Unsused | ||||
|     function getMarketMarginPremium(uint256 marketId) | ||||
|         external | ||||
|         view | ||||
|         returns (IDydx.D256 memory premium) | ||||
|     {} | ||||
|  | ||||
|     /// @dev Unused. | ||||
|     function getAdjustedAccountValues( | ||||
|         AccountInfo calldata account | ||||
|     ) | ||||
|         external | ||||
|         view | ||||
|         returns (Value memory supplyValue, Value memory borrowValue) | ||||
|     {} | ||||
|  | ||||
|     /// @dev overrides `_getDydxAddress()` from `DeploymentConstants` to return this address. | ||||
|     function _getDydxAddress() | ||||
|         internal | ||||
|         view | ||||
|         returns (address) | ||||
|     { | ||||
|         return address(this); | ||||
|     } | ||||
|  | ||||
|     /// @dev overrides `_getERC20BridgeProxyAddress()` from `DeploymentConstants` for testing. | ||||
|     function _getERC20BridgeProxyAddress() | ||||
|         internal | ||||
|         view | ||||
|         returns (address) | ||||
|     { | ||||
|         return msg.sender == ALWAYS_REVERT_ADDRESS ? address(0) : msg.sender; | ||||
|     } | ||||
| } | ||||
| @@ -1,108 +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.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 bridgeTransferFrom( | ||||
|         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)) } | ||||
|     } | ||||
| } | ||||
| @@ -1,202 +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.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 _getEth2DaiAddress() | ||||
|         internal | ||||
|         view | ||||
|         returns (address) | ||||
|     { | ||||
|         return address(this); | ||||
|     } | ||||
| } | ||||
| @@ -1,324 +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.9; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; | ||||
| import "../src/bridges/KyberBridge.sol"; | ||||
| import "../src/interfaces/IKyberNetworkProxy.sol"; | ||||
|  | ||||
|  | ||||
| // solhint-disable no-simple-event-func-name | ||||
| interface ITestContract { | ||||
|  | ||||
|     function wethWithdraw( | ||||
|         address payable ownerAddress, | ||||
|         uint256 amount | ||||
|     ) | ||||
|         external; | ||||
|  | ||||
|     function wethDeposit( | ||||
|         address ownerAddress | ||||
|     ) | ||||
|         external | ||||
|         payable; | ||||
|  | ||||
|     function tokenTransfer( | ||||
|         address ownerAddress, | ||||
|         address recipientAddress, | ||||
|         uint256 amount | ||||
|     ) | ||||
|         external | ||||
|         returns (bool success); | ||||
|  | ||||
|     function tokenApprove( | ||||
|         address ownerAddress, | ||||
|         address spenderAddress, | ||||
|         uint256 allowance | ||||
|     ) | ||||
|         external | ||||
|         returns (bool success); | ||||
|  | ||||
|     function tokenBalanceOf( | ||||
|         address ownerAddress | ||||
|     ) | ||||
|         external | ||||
|         view | ||||
|         returns (uint256 balance); | ||||
| } | ||||
|  | ||||
|  | ||||
| /// @dev A minimalist ERC20/WETH token. | ||||
| contract TestToken { | ||||
|  | ||||
|     uint8 public decimals; | ||||
|     ITestContract private _testContract; | ||||
|  | ||||
|     constructor(uint8 decimals_) public { | ||||
|         decimals = decimals_; | ||||
|         _testContract = ITestContract(msg.sender); | ||||
|     } | ||||
|  | ||||
|     function approve(address spender, uint256 allowance) | ||||
|         external | ||||
|         returns (bool) | ||||
|     { | ||||
|         return _testContract.tokenApprove( | ||||
|             msg.sender, | ||||
|             spender, | ||||
|             allowance | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     function transfer(address recipient, uint256 amount) | ||||
|         external | ||||
|         returns (bool) | ||||
|     { | ||||
|         return _testContract.tokenTransfer( | ||||
|             msg.sender, | ||||
|             recipient, | ||||
|             amount | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     function withdraw(uint256 amount) | ||||
|         external | ||||
|     { | ||||
|         return _testContract.wethWithdraw(msg.sender, amount); | ||||
|     } | ||||
|  | ||||
|     function deposit() | ||||
|         external | ||||
|         payable | ||||
|     { | ||||
|         return _testContract.wethDeposit.value(msg.value)(msg.sender); | ||||
|     } | ||||
|  | ||||
|     function balanceOf(address owner) | ||||
|         external | ||||
|         view | ||||
|         returns (uint256) | ||||
|     { | ||||
|         return _testContract.tokenBalanceOf(owner); | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
| /// @dev KyberBridge overridden to mock tokens and implement IKyberBridge. | ||||
| contract TestKyberBridge is | ||||
|     KyberBridge, | ||||
|     ITestContract, | ||||
|     IKyberNetworkProxy | ||||
| { | ||||
|     event KyberBridgeTrade( | ||||
|         uint256 msgValue, | ||||
|         address sellTokenAddress, | ||||
|         uint256 sellAmount, | ||||
|         address buyTokenAddress, | ||||
|         address payable recipientAddress, | ||||
|         uint256 maxBuyTokenAmount, | ||||
|         uint256 minConversionRate, | ||||
|         address walletId | ||||
|     ); | ||||
|  | ||||
|     event KyberBridgeWethWithdraw( | ||||
|         address ownerAddress, | ||||
|         uint256 amount | ||||
|     ); | ||||
|  | ||||
|     event KyberBridgeWethDeposit( | ||||
|         uint256 msgValue, | ||||
|         address ownerAddress, | ||||
|         uint256 amount | ||||
|     ); | ||||
|  | ||||
|     event KyberBridgeTokenApprove( | ||||
|         address tokenAddress, | ||||
|         address ownerAddress, | ||||
|         address spenderAddress, | ||||
|         uint256 allowance | ||||
|     ); | ||||
|  | ||||
|     event KyberBridgeTokenTransfer( | ||||
|         address tokenAddress, | ||||
|         address ownerAddress, | ||||
|         address recipientAddress, | ||||
|         uint256 amount | ||||
|     ); | ||||
|  | ||||
|     IEtherToken public weth; | ||||
|     mapping (address => mapping (address => uint256)) private _tokenBalances; | ||||
|     uint256 private _nextFillAmount; | ||||
|  | ||||
|     constructor() public { | ||||
|         weth = IEtherToken(address(new TestToken(18))); | ||||
|     } | ||||
|  | ||||
|     /// @dev Implementation of `IKyberNetworkProxy.trade()` | ||||
|     function trade( | ||||
|         address sellTokenAddress, | ||||
|         uint256 sellAmount, | ||||
|         address buyTokenAddress, | ||||
|         address payable recipientAddress, | ||||
|         uint256 maxBuyTokenAmount, | ||||
|         uint256 minConversionRate, | ||||
|         address walletId | ||||
|     ) | ||||
|         external | ||||
|         payable | ||||
|         returns(uint256 boughtAmount) | ||||
|     { | ||||
|         emit KyberBridgeTrade( | ||||
|             msg.value, | ||||
|             sellTokenAddress, | ||||
|             sellAmount, | ||||
|             buyTokenAddress, | ||||
|             recipientAddress, | ||||
|             maxBuyTokenAmount, | ||||
|             minConversionRate, | ||||
|             walletId | ||||
|         ); | ||||
|         return _nextFillAmount; | ||||
|     } | ||||
|  | ||||
|     function createToken(uint8 decimals) | ||||
|         external | ||||
|         returns (address tokenAddress) | ||||
|     { | ||||
|         return address(new TestToken(decimals)); | ||||
|     } | ||||
|  | ||||
|     function setNextFillAmount(uint256 amount) | ||||
|         external | ||||
|         payable | ||||
|     { | ||||
|         if (msg.value != 0) { | ||||
|             require(amount == msg.value, "VALUE_AMOUNT_MISMATCH"); | ||||
|             grantTokensTo(address(weth), address(this), msg.value); | ||||
|         } | ||||
|         _nextFillAmount = amount; | ||||
|     } | ||||
|  | ||||
|     function wethDeposit( | ||||
|         address ownerAddress | ||||
|     ) | ||||
|         external | ||||
|         payable | ||||
|     { | ||||
|         require(msg.sender == address(weth), "ONLY_WETH"); | ||||
|         grantTokensTo(address(weth), ownerAddress, msg.value); | ||||
|         emit KyberBridgeWethDeposit( | ||||
|             msg.value, | ||||
|             ownerAddress, | ||||
|             msg.value | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     function wethWithdraw( | ||||
|         address payable ownerAddress, | ||||
|         uint256 amount | ||||
|     ) | ||||
|         external | ||||
|     { | ||||
|         require(msg.sender == address(weth), "ONLY_WETH"); | ||||
|         _tokenBalances[address(weth)][ownerAddress] -= amount; | ||||
|         ownerAddress.transfer(amount); | ||||
|         emit KyberBridgeWethWithdraw( | ||||
|             ownerAddress, | ||||
|             amount | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     function tokenApprove( | ||||
|         address ownerAddress, | ||||
|         address spenderAddress, | ||||
|         uint256 allowance | ||||
|     ) | ||||
|         external | ||||
|         returns (bool success) | ||||
|     { | ||||
|         emit KyberBridgeTokenApprove( | ||||
|             msg.sender, | ||||
|             ownerAddress, | ||||
|             spenderAddress, | ||||
|             allowance | ||||
|         ); | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     function tokenTransfer( | ||||
|         address ownerAddress, | ||||
|         address recipientAddress, | ||||
|         uint256 amount | ||||
|     ) | ||||
|         external | ||||
|         returns (bool success) | ||||
|     { | ||||
|         _tokenBalances[msg.sender][ownerAddress] -= amount; | ||||
|         _tokenBalances[msg.sender][recipientAddress] += amount; | ||||
|         emit KyberBridgeTokenTransfer( | ||||
|             msg.sender, | ||||
|             ownerAddress, | ||||
|             recipientAddress, | ||||
|             amount | ||||
|         ); | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     function tokenBalanceOf( | ||||
|         address ownerAddress | ||||
|     ) | ||||
|         external | ||||
|         view | ||||
|         returns (uint256 balance) | ||||
|     { | ||||
|         return _tokenBalances[msg.sender][ownerAddress]; | ||||
|     } | ||||
|  | ||||
|     function grantTokensTo(address tokenAddress, address ownerAddress, uint256 amount) | ||||
|         public | ||||
|         payable | ||||
|     { | ||||
|         _tokenBalances[tokenAddress][ownerAddress] += amount; | ||||
|         if (tokenAddress != address(weth)) { | ||||
|             // Send back ether if not WETH. | ||||
|             msg.sender.transfer(msg.value); | ||||
|         } else { | ||||
|             require(msg.value == amount, "VALUE_AMOUNT_MISMATCH"); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // @dev overridden to point to this contract. | ||||
|     function _getKyberNetworkProxyAddress() | ||||
|         internal | ||||
|         view | ||||
|         returns (address) | ||||
|     { | ||||
|         return address(this); | ||||
|     } | ||||
|  | ||||
|     // @dev overridden to point to test WETH. | ||||
|     function _getWethAddress() | ||||
|         internal | ||||
|         view | ||||
|         returns (address) | ||||
|     { | ||||
|         return address(weth); | ||||
|     } | ||||
| } | ||||
| @@ -1,82 +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.9; | ||||
|  | ||||
| import "@0x/contracts-utils/contracts/src/LibBytes.sol"; | ||||
|  | ||||
|  | ||||
| contract TestStaticCallTarget { | ||||
|  | ||||
|     using LibBytes for bytes; | ||||
|  | ||||
|     uint256 internal _state; | ||||
|   | ||||
|     function updateState() | ||||
|         external | ||||
|     { | ||||
|         _state++; | ||||
|     } | ||||
|  | ||||
|     function assertEvenNumber(uint256 target) | ||||
|         external | ||||
|         pure | ||||
|     { | ||||
|         require( | ||||
|             target % 2 == 0, | ||||
|             "TARGET_NOT_EVEN" | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     function isOddNumber(uint256 target) | ||||
|         external | ||||
|         pure | ||||
|         returns (bool isOdd) | ||||
|     { | ||||
|         isOdd = target % 2 == 1; | ||||
|         return isOdd; | ||||
|     } | ||||
|  | ||||
|     function noInputFunction() | ||||
|         external | ||||
|         pure | ||||
|     { | ||||
|         assert(msg.data.length == 4 && msg.data.readBytes4(0) == bytes4(keccak256("noInputFunction()"))); | ||||
|     } | ||||
|  | ||||
|     function dynamicInputFunction(bytes calldata a) | ||||
|         external | ||||
|         pure | ||||
|     { | ||||
|         bytes memory abiEncodedData = abi.encodeWithSignature("dynamicInputFunction(bytes)", a); | ||||
|         assert(msg.data.equals(abiEncodedData)); | ||||
|     } | ||||
|  | ||||
|     function returnComplexType(uint256 a, uint256 b) | ||||
|         external | ||||
|         view | ||||
|         returns (bytes memory result) | ||||
|     { | ||||
|         result = abi.encodePacked( | ||||
|             address(this), | ||||
|             a, | ||||
|             b | ||||
|         ); | ||||
|         return result; | ||||
|     } | ||||
| } | ||||
| @@ -1,432 +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.9; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; | ||||
| import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; | ||||
| import "../src/bridges/UniswapBridge.sol"; | ||||
| import "../src/interfaces/IUniswapExchangeFactory.sol"; | ||||
| import "../src/interfaces/IUniswapExchange.sol"; | ||||
|  | ||||
|  | ||||
| // solhint-disable no-simple-event-func-name | ||||
| contract TestEventsRaiser { | ||||
|  | ||||
|     event TokenTransfer( | ||||
|         address token, | ||||
|         address from, | ||||
|         address to, | ||||
|         uint256 amount | ||||
|     ); | ||||
|  | ||||
|     event TokenApprove( | ||||
|         address spender, | ||||
|         uint256 allowance | ||||
|     ); | ||||
|  | ||||
|     event WethDeposit( | ||||
|         uint256 amount | ||||
|     ); | ||||
|  | ||||
|     event WethWithdraw( | ||||
|         uint256 amount | ||||
|     ); | ||||
|  | ||||
|     event EthToTokenTransferInput( | ||||
|         address exchange, | ||||
|         uint256 minTokensBought, | ||||
|         uint256 deadline, | ||||
|         address recipient | ||||
|     ); | ||||
|  | ||||
|     event TokenToEthSwapInput( | ||||
|         address exchange, | ||||
|         uint256 tokensSold, | ||||
|         uint256 minEthBought, | ||||
|         uint256 deadline | ||||
|     ); | ||||
|  | ||||
|     event TokenToTokenTransferInput( | ||||
|         address exchange, | ||||
|         uint256 tokensSold, | ||||
|         uint256 minTokensBought, | ||||
|         uint256 minEthBought, | ||||
|         uint256 deadline, | ||||
|         address recipient, | ||||
|         address toTokenAddress | ||||
|     ); | ||||
|  | ||||
|     function raiseEthToTokenTransferInput( | ||||
|         uint256 minTokensBought, | ||||
|         uint256 deadline, | ||||
|         address recipient | ||||
|     ) | ||||
|         external | ||||
|     { | ||||
|         emit EthToTokenTransferInput( | ||||
|             msg.sender, | ||||
|             minTokensBought, | ||||
|             deadline, | ||||
|             recipient | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     function raiseTokenToEthSwapInput( | ||||
|         uint256 tokensSold, | ||||
|         uint256 minEthBought, | ||||
|         uint256 deadline | ||||
|     ) | ||||
|         external | ||||
|     { | ||||
|         emit TokenToEthSwapInput( | ||||
|             msg.sender, | ||||
|             tokensSold, | ||||
|             minEthBought, | ||||
|             deadline | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     function raiseTokenToTokenTransferInput( | ||||
|         uint256 tokensSold, | ||||
|         uint256 minTokensBought, | ||||
|         uint256 minEthBought, | ||||
|         uint256 deadline, | ||||
|         address recipient, | ||||
|         address toTokenAddress | ||||
|     ) | ||||
|         external | ||||
|     { | ||||
|         emit TokenToTokenTransferInput( | ||||
|             msg.sender, | ||||
|             tokensSold, | ||||
|             minTokensBought, | ||||
|             minEthBought, | ||||
|             deadline, | ||||
|             recipient, | ||||
|             toTokenAddress | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     function raiseTokenTransfer( | ||||
|         address from, | ||||
|         address to, | ||||
|         uint256 amount | ||||
|     ) | ||||
|         external | ||||
|     { | ||||
|         emit TokenTransfer( | ||||
|             msg.sender, | ||||
|             from, | ||||
|             to, | ||||
|             amount | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     function raiseTokenApprove(address spender, uint256 allowance) | ||||
|         external | ||||
|     { | ||||
|         emit TokenApprove(spender, allowance); | ||||
|     } | ||||
|  | ||||
|     function raiseWethDeposit(uint256 amount) | ||||
|         external | ||||
|     { | ||||
|         emit WethDeposit(amount); | ||||
|     } | ||||
|  | ||||
|     function raiseWethWithdraw(uint256 amount) | ||||
|         external | ||||
|     { | ||||
|         emit WethWithdraw(amount); | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
| /// @dev A minimalist ERC20/WETH token. | ||||
| contract TestToken { | ||||
|  | ||||
|     using LibSafeMath for uint256; | ||||
|  | ||||
|     mapping (address => uint256) public balances; | ||||
|     string private _nextRevertReason; | ||||
|  | ||||
|     /// @dev Set the balance for `owner`. | ||||
|     function setBalance(address owner) | ||||
|         external | ||||
|         payable | ||||
|     { | ||||
|         balances[owner] = msg.value; | ||||
|     } | ||||
|  | ||||
|     /// @dev Set the revert reason for `transfer()`, | ||||
|     ///      `deposit()`, and `withdraw()`. | ||||
|     function setRevertReason(string calldata reason) | ||||
|         external | ||||
|     { | ||||
|         _nextRevertReason = reason; | ||||
|     } | ||||
|  | ||||
|     /// @dev Just calls `raiseTokenTransfer()` on the caller. | ||||
|     function transfer(address to, uint256 amount) | ||||
|         external | ||||
|         returns (bool) | ||||
|     { | ||||
|         _revertIfReasonExists(); | ||||
|         TestEventsRaiser(msg.sender).raiseTokenTransfer(msg.sender, to, amount); | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     /// @dev Just calls `raiseTokenApprove()` on the caller. | ||||
|     function approve(address spender, uint256 allowance) | ||||
|         external | ||||
|         returns (bool) | ||||
|     { | ||||
|         TestEventsRaiser(msg.sender).raiseTokenApprove(spender, allowance); | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     /// @dev `IWETH.deposit()` that increases balances and calls | ||||
|     ///     `raiseWethDeposit()` on the caller. | ||||
|     function deposit() | ||||
|         external | ||||
|         payable | ||||
|     { | ||||
|         _revertIfReasonExists(); | ||||
|         balances[msg.sender] += balances[msg.sender].safeAdd(msg.value); | ||||
|         TestEventsRaiser(msg.sender).raiseWethDeposit(msg.value); | ||||
|     } | ||||
|  | ||||
|     /// @dev `IWETH.withdraw()` that just reduces balances and calls | ||||
|     ///       `raiseWethWithdraw()` on the caller. | ||||
|     function withdraw(uint256 amount) | ||||
|         external | ||||
|     { | ||||
|         _revertIfReasonExists(); | ||||
|         balances[msg.sender] = balances[msg.sender].safeSub(amount); | ||||
|         msg.sender.transfer(amount); | ||||
|         TestEventsRaiser(msg.sender).raiseWethWithdraw(amount); | ||||
|     } | ||||
|  | ||||
|     /// @dev Retrieve the balance for `owner`. | ||||
|     function balanceOf(address owner) | ||||
|         external | ||||
|         view | ||||
|         returns (uint256) | ||||
|     { | ||||
|         return balances[owner]; | ||||
|     } | ||||
|  | ||||
|     function _revertIfReasonExists() | ||||
|         private | ||||
|         view | ||||
|     { | ||||
|         if (bytes(_nextRevertReason).length != 0) { | ||||
|             revert(_nextRevertReason); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
| contract TestExchange is | ||||
|     IUniswapExchange | ||||
| { | ||||
|     address public tokenAddress; | ||||
|     string private _nextRevertReason; | ||||
|  | ||||
|     constructor(address _tokenAddress) public { | ||||
|         tokenAddress = _tokenAddress; | ||||
|     } | ||||
|  | ||||
|     function setFillBehavior( | ||||
|         string calldata revertReason | ||||
|     ) | ||||
|         external | ||||
|         payable | ||||
|     { | ||||
|         _nextRevertReason = revertReason; | ||||
|     } | ||||
|  | ||||
|     function ethToTokenTransferInput( | ||||
|         uint256 minTokensBought, | ||||
|         uint256 deadline, | ||||
|         address recipient | ||||
|     ) | ||||
|         external | ||||
|         payable | ||||
|         returns (uint256 tokensBought) | ||||
|     { | ||||
|         TestEventsRaiser(msg.sender).raiseEthToTokenTransferInput( | ||||
|             minTokensBought, | ||||
|             deadline, | ||||
|             recipient | ||||
|         ); | ||||
|         _revertIfReasonExists(); | ||||
|         return address(this).balance; | ||||
|     } | ||||
|  | ||||
|     function tokenToEthSwapInput( | ||||
|         uint256 tokensSold, | ||||
|         uint256 minEthBought, | ||||
|         uint256 deadline | ||||
|     ) | ||||
|         external | ||||
|         returns (uint256 ethBought) | ||||
|     { | ||||
|         TestEventsRaiser(msg.sender).raiseTokenToEthSwapInput( | ||||
|             tokensSold, | ||||
|             minEthBought, | ||||
|             deadline | ||||
|         ); | ||||
|         _revertIfReasonExists(); | ||||
|         uint256 fillAmount = address(this).balance; | ||||
|         msg.sender.transfer(fillAmount); | ||||
|         return fillAmount; | ||||
|     } | ||||
|  | ||||
|     function tokenToTokenTransferInput( | ||||
|         uint256 tokensSold, | ||||
|         uint256 minTokensBought, | ||||
|         uint256 minEthBought, | ||||
|         uint256 deadline, | ||||
|         address recipient, | ||||
|         address toTokenAddress | ||||
|     ) | ||||
|         external | ||||
|         returns (uint256 tokensBought) | ||||
|     { | ||||
|         TestEventsRaiser(msg.sender).raiseTokenToTokenTransferInput( | ||||
|             tokensSold, | ||||
|             minTokensBought, | ||||
|             minEthBought, | ||||
|             deadline, | ||||
|             recipient, | ||||
|             toTokenAddress | ||||
|         ); | ||||
|         _revertIfReasonExists(); | ||||
|         return address(this).balance; | ||||
|     } | ||||
|  | ||||
|     function toTokenAddress() | ||||
|         external | ||||
|         view | ||||
|         returns (address _tokenAddress) | ||||
|     { | ||||
|         return tokenAddress; | ||||
|     } | ||||
|  | ||||
|     function _revertIfReasonExists() | ||||
|         private | ||||
|         view | ||||
|     { | ||||
|         if (bytes(_nextRevertReason).length != 0) { | ||||
|             revert(_nextRevertReason); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
| /// @dev UniswapBridge overridden to mock tokens and implement IUniswapExchangeFactory. | ||||
| contract TestUniswapBridge is | ||||
|     IUniswapExchangeFactory, | ||||
|     TestEventsRaiser, | ||||
|     UniswapBridge | ||||
| { | ||||
|     TestToken public wethToken; | ||||
|     // Token address to TestToken instance. | ||||
|     mapping (address => TestToken) private _testTokens; | ||||
|     // Token address to TestExchange instance. | ||||
|     mapping (address => TestExchange) private _testExchanges; | ||||
|  | ||||
|     constructor() public { | ||||
|         wethToken = new TestToken(); | ||||
|         _testTokens[address(wethToken)] = wethToken; | ||||
|     } | ||||
|  | ||||
|     /// @dev Sets the balance of this contract for an existing token. | ||||
|     ///      The wei attached will be the balance. | ||||
|     function setTokenBalance(address tokenAddress) | ||||
|         external | ||||
|         payable | ||||
|     { | ||||
|         TestToken token = _testTokens[tokenAddress]; | ||||
|         token.deposit.value(msg.value)(); | ||||
|     } | ||||
|  | ||||
|     /// @dev Sets the revert reason for an existing token. | ||||
|     function setTokenRevertReason(address tokenAddress, string calldata revertReason) | ||||
|         external | ||||
|     { | ||||
|         TestToken token = _testTokens[tokenAddress]; | ||||
|         token.setRevertReason(revertReason); | ||||
|     } | ||||
|  | ||||
|     /// @dev Create a token and exchange (if they don't exist) for a new token | ||||
|     ///      and sets the exchange revert and fill behavior. The wei attached | ||||
|     ///      will be the fill amount for the exchange. | ||||
|     /// @param tokenAddress The token address. If zero, one will be created. | ||||
|     /// @param revertReason The revert reason for exchange operations. | ||||
|     function createTokenAndExchange( | ||||
|         address tokenAddress, | ||||
|         string calldata revertReason | ||||
|     ) | ||||
|         external | ||||
|         payable | ||||
|         returns (TestToken token, TestExchange exchange) | ||||
|     { | ||||
|         token = TestToken(tokenAddress); | ||||
|         if (tokenAddress == address(0)) { | ||||
|             token = new TestToken(); | ||||
|         } | ||||
|         _testTokens[address(token)] = token; | ||||
|         exchange = _testExchanges[address(token)]; | ||||
|         if (address(exchange) == address(0)) { | ||||
|             _testExchanges[address(token)] = exchange = new TestExchange(address(token)); | ||||
|         } | ||||
|         exchange.setFillBehavior.value(msg.value)(revertReason); | ||||
|         return (token, exchange); | ||||
|     } | ||||
|  | ||||
|     /// @dev `IUniswapExchangeFactory.getExchange` | ||||
|     function getExchange(address tokenAddress) | ||||
|         external | ||||
|         view | ||||
|         returns (address) | ||||
|     { | ||||
|         return address(_testExchanges[tokenAddress]); | ||||
|     } | ||||
|  | ||||
|     // @dev Use `wethToken`. | ||||
|     function _getWethAddress() | ||||
|         internal | ||||
|         view | ||||
|         returns (address) | ||||
|     { | ||||
|         return address(wethToken); | ||||
|     } | ||||
|  | ||||
|     // @dev This contract will double as the Uniswap contract. | ||||
|     function _getUniswapExchangeFactoryAddress() | ||||
|         internal | ||||
|         view | ||||
|         returns (address) | ||||
|     { | ||||
|         return address(this); | ||||
|     } | ||||
| } | ||||
| @@ -1,97 +0,0 @@ | ||||
| { | ||||
|     "name": "@0x/contracts-asset-proxy", | ||||
|     "version": "3.2.3", | ||||
|     "engines": { | ||||
|         "node": ">=6.12" | ||||
|     }, | ||||
|     "description": "Smart contract components of 0x protocol", | ||||
|     "main": "lib/src/index.js", | ||||
|     "directories": { | ||||
|         "test": "test" | ||||
|     }, | ||||
|     "scripts": { | ||||
|         "build": "yarn pre_build && tsc -b", | ||||
|         "build:ci": "yarn build", | ||||
|         "pre_build": "run-s compile contracts:gen generate_contract_wrappers contracts:copy", | ||||
|         "test": "yarn run_mocha", | ||||
|         "rebuild_and_test": "run-s build test", | ||||
|         "test:coverage": "SOLIDITY_COVERAGE=true run-s build run_mocha coverage:report:text coverage:report:lcov", | ||||
|         "test:profiler": "SOLIDITY_PROFILER=true run-s build run_mocha profiler:report:html", | ||||
|         "test:trace": "SOLIDITY_REVERT_TRACE=true run-s build run_mocha", | ||||
|         "run_mocha": "mocha --require source-map-support/register --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit", | ||||
|         "compile": "sol-compiler", | ||||
|         "watch": "sol-compiler -w", | ||||
|         "clean": "shx rm -rf lib test/generated-artifacts test/generated-wrappers generated-artifacts generated-wrappers", | ||||
|         "generate_contract_wrappers": "abi-gen --debug --abis  ${npm_package_config_abis} --output test/generated-wrappers --backend ethers", | ||||
|         "lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./test/generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts", | ||||
|         "fix": "tslint --fix --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./test/generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts", | ||||
|         "coverage:report:text": "istanbul report text", | ||||
|         "coverage:report:html": "istanbul report html && open coverage/index.html", | ||||
|         "profiler:report:html": "istanbul report html && open coverage/index.html", | ||||
|         "coverage:report:lcov": "istanbul report lcov", | ||||
|         "test:circleci": "yarn test", | ||||
|         "contracts:gen": "contracts-gen generate", | ||||
|         "contracts:copy": "contracts-gen copy", | ||||
|         "lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol", | ||||
|         "compile:truffle": "truffle compile", | ||||
|         "docs:md": "ts-doc-gen --sourceDir='$PROJECT_FILES' --output=$MD_FILE_DIR --fileExtension=mdx --tsconfig=./typedoc-tsconfig.json", | ||||
|         "docs:json": "typedoc --excludePrivate --excludeExternals --excludeProtected --ignoreCompilerErrors --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES" | ||||
|     }, | ||||
|     "config": { | ||||
|         "abis": "./test/generated-artifacts/@(ChaiBridge|CurveBridge|DydxBridge|ERC1155Proxy|ERC20BridgeProxy|ERC20Proxy|ERC721Proxy|Eth2DaiBridge|IAssetData|IAssetProxy|IAssetProxyDispatcher|IAuthorizable|IChai|ICurve|IDydx|IDydxBridge|IERC20Bridge|IEth2Dai|IKyberNetworkProxy|IUniswapExchange|IUniswapExchangeFactory|KyberBridge|MixinAssetProxyDispatcher|MixinAuthorizable|MultiAssetProxy|Ownable|StaticCallProxy|TestChaiBridge|TestDydxBridge|TestERC20Bridge|TestEth2DaiBridge|TestKyberBridge|TestStaticCallTarget|TestUniswapBridge|UniswapBridge).json", | ||||
|         "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually." | ||||
|     }, | ||||
|     "repository": { | ||||
|         "type": "git", | ||||
|         "url": "https://github.com/0xProject/0x-monorepo.git" | ||||
|     }, | ||||
|     "license": "Apache-2.0", | ||||
|     "bugs": { | ||||
|         "url": "https://github.com/0xProject/0x-monorepo/issues" | ||||
|     }, | ||||
|     "homepage": "https://github.com/0xProject/0x-monorepo/contracts/protocol/README.md", | ||||
|     "devDependencies": { | ||||
|         "@0x/abi-gen": "^5.2.2", | ||||
|         "@0x/contracts-gen": "^2.0.8", | ||||
|         "@0x/contracts-test-utils": "^5.3.0", | ||||
|         "@0x/contracts-utils": "^4.4.1", | ||||
|         "@0x/dev-utils": "^3.2.1", | ||||
|         "@0x/sol-compiler": "^4.0.8", | ||||
|         "@0x/ts-doc-gen": "^0.0.22", | ||||
|         "@0x/tslint-config": "^4.0.0", | ||||
|         "@types/lodash": "4.14.104", | ||||
|         "@types/mocha": "^5.2.7", | ||||
|         "@types/node": "*", | ||||
|         "chai": "^4.0.1", | ||||
|         "chai-as-promised": "^7.1.0", | ||||
|         "chai-bignumber": "^3.0.0", | ||||
|         "dirty-chai": "^2.0.1", | ||||
|         "ethereumjs-util": "^5.1.1", | ||||
|         "make-promises-safe": "^1.1.0", | ||||
|         "mocha": "^6.2.0", | ||||
|         "npm-run-all": "^4.1.2", | ||||
|         "shx": "^0.2.2", | ||||
|         "solhint": "^1.4.1", | ||||
|         "truffle": "^5.0.32", | ||||
|         "tslint": "5.11.0", | ||||
|         "typedoc": "^0.15.0", | ||||
|         "typescript": "3.0.1" | ||||
|     }, | ||||
|     "dependencies": { | ||||
|         "@0x/base-contract": "^6.2.1", | ||||
|         "@0x/contracts-erc1155": "^2.1.3", | ||||
|         "@0x/contracts-erc20": "^3.1.3", | ||||
|         "@0x/contracts-erc721": "^3.1.3", | ||||
|         "@0x/contracts-exchange-libs": "^4.3.3", | ||||
|         "@0x/order-utils": "^10.2.2", | ||||
|         "@0x/types": "^3.1.2", | ||||
|         "@0x/typescript-typings": "^5.0.2", | ||||
|         "@0x/utils": "^5.4.1", | ||||
|         "@0x/web3-wrapper": "^7.0.7", | ||||
|         "ethereum-types": "^3.1.0", | ||||
|         "lodash": "^4.17.11" | ||||
|     }, | ||||
|     "publishConfig": { | ||||
|         "access": "public" | ||||
|     } | ||||
| } | ||||
| @@ -1,79 +0,0 @@ | ||||
| /* | ||||
|  * ----------------------------------------------------------------------------- | ||||
|  * Warning: This file is auto-generated by contracts-gen. Don't edit manually. | ||||
|  * ----------------------------------------------------------------------------- | ||||
|  */ | ||||
| import { ContractArtifact } from 'ethereum-types'; | ||||
|  | ||||
| import * as ChaiBridge from '../generated-artifacts/ChaiBridge.json'; | ||||
| import * as CurveBridge from '../generated-artifacts/CurveBridge.json'; | ||||
| import * as DydxBridge from '../generated-artifacts/DydxBridge.json'; | ||||
| import * as ERC1155Proxy from '../generated-artifacts/ERC1155Proxy.json'; | ||||
| import * as ERC20BridgeProxy from '../generated-artifacts/ERC20BridgeProxy.json'; | ||||
| 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 IChai from '../generated-artifacts/IChai.json'; | ||||
| import * as ICurve from '../generated-artifacts/ICurve.json'; | ||||
| import * as IDydx from '../generated-artifacts/IDydx.json'; | ||||
| import * as IDydxBridge from '../generated-artifacts/IDydxBridge.json'; | ||||
| import * as IERC20Bridge from '../generated-artifacts/IERC20Bridge.json'; | ||||
| import * as IEth2Dai from '../generated-artifacts/IEth2Dai.json'; | ||||
| import * as IKyberNetworkProxy from '../generated-artifacts/IKyberNetworkProxy.json'; | ||||
| import * as IUniswapExchange from '../generated-artifacts/IUniswapExchange.json'; | ||||
| import * as IUniswapExchangeFactory from '../generated-artifacts/IUniswapExchangeFactory.json'; | ||||
| import * as KyberBridge from '../generated-artifacts/KyberBridge.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 TestChaiBridge from '../generated-artifacts/TestChaiBridge.json'; | ||||
| import * as TestDydxBridge from '../generated-artifacts/TestDydxBridge.json'; | ||||
| import * as TestERC20Bridge from '../generated-artifacts/TestERC20Bridge.json'; | ||||
| import * as TestEth2DaiBridge from '../generated-artifacts/TestEth2DaiBridge.json'; | ||||
| import * as TestKyberBridge from '../generated-artifacts/TestKyberBridge.json'; | ||||
| import * as TestStaticCallTarget from '../generated-artifacts/TestStaticCallTarget.json'; | ||||
| import * as TestUniswapBridge from '../generated-artifacts/TestUniswapBridge.json'; | ||||
| import * as UniswapBridge from '../generated-artifacts/UniswapBridge.json'; | ||||
| export const artifacts = { | ||||
|     MixinAssetProxyDispatcher: MixinAssetProxyDispatcher as ContractArtifact, | ||||
|     MixinAuthorizable: MixinAuthorizable as ContractArtifact, | ||||
|     Ownable: Ownable as ContractArtifact, | ||||
|     ERC1155Proxy: ERC1155Proxy as ContractArtifact, | ||||
|     ERC20BridgeProxy: ERC20BridgeProxy as ContractArtifact, | ||||
|     ERC20Proxy: ERC20Proxy as ContractArtifact, | ||||
|     ERC721Proxy: ERC721Proxy as ContractArtifact, | ||||
|     MultiAssetProxy: MultiAssetProxy as ContractArtifact, | ||||
|     StaticCallProxy: StaticCallProxy as ContractArtifact, | ||||
|     ChaiBridge: ChaiBridge as ContractArtifact, | ||||
|     CurveBridge: CurveBridge as ContractArtifact, | ||||
|     DydxBridge: DydxBridge as ContractArtifact, | ||||
|     Eth2DaiBridge: Eth2DaiBridge as ContractArtifact, | ||||
|     KyberBridge: KyberBridge as ContractArtifact, | ||||
|     UniswapBridge: UniswapBridge as ContractArtifact, | ||||
|     IAssetData: IAssetData as ContractArtifact, | ||||
|     IAssetProxy: IAssetProxy as ContractArtifact, | ||||
|     IAssetProxyDispatcher: IAssetProxyDispatcher as ContractArtifact, | ||||
|     IAuthorizable: IAuthorizable as ContractArtifact, | ||||
|     IChai: IChai as ContractArtifact, | ||||
|     ICurve: ICurve as ContractArtifact, | ||||
|     IDydx: IDydx as ContractArtifact, | ||||
|     IDydxBridge: IDydxBridge as ContractArtifact, | ||||
|     IERC20Bridge: IERC20Bridge as ContractArtifact, | ||||
|     IEth2Dai: IEth2Dai as ContractArtifact, | ||||
|     IKyberNetworkProxy: IKyberNetworkProxy as ContractArtifact, | ||||
|     IUniswapExchange: IUniswapExchange as ContractArtifact, | ||||
|     IUniswapExchangeFactory: IUniswapExchangeFactory as ContractArtifact, | ||||
|     TestChaiBridge: TestChaiBridge as ContractArtifact, | ||||
|     TestDydxBridge: TestDydxBridge as ContractArtifact, | ||||
|     TestERC20Bridge: TestERC20Bridge as ContractArtifact, | ||||
|     TestEth2DaiBridge: TestEth2DaiBridge as ContractArtifact, | ||||
|     TestKyberBridge: TestKyberBridge as ContractArtifact, | ||||
|     TestStaticCallTarget: TestStaticCallTarget as ContractArtifact, | ||||
|     TestUniswapBridge: TestUniswapBridge as ContractArtifact, | ||||
| }; | ||||
| @@ -1,112 +0,0 @@ | ||||
| import { AssetProxyId } from '@0x/types'; | ||||
| import { BigNumber, hexUtils } from '@0x/utils'; | ||||
|  | ||||
| import { IAssetDataContract } from './wrappers'; | ||||
|  | ||||
| const assetDataIface = new IAssetDataContract('0x0000000000000000000000000000000000000000', { isEIP1193: true } as any); | ||||
|  | ||||
| /** | ||||
|  * Get the proxy ID from encoded asset data. | ||||
|  */ | ||||
| export function getAssetDataProxyId(encoded: string): AssetProxyId { | ||||
|     // tslint:disable-next-line: no-unnecessary-type-assertion | ||||
|     return hexUtils.slice(encoded, 0, 4) as AssetProxyId; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Decode ERC20 asset data. | ||||
|  */ | ||||
| export function decodeERC20AssetData(encoded: string): string { | ||||
|     return assetDataIface.getABIDecodedTransactionData<string>('ERC20Token', encoded); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Decode ERC721 asset data. | ||||
|  */ | ||||
| export function decodeERC721AssetData(encoded: string): [string, BigNumber] { | ||||
|     return assetDataIface.getABIDecodedTransactionData<[string, BigNumber]>('ERC721Token', encoded); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Decode ERC1155 asset data. | ||||
|  */ | ||||
| export function decodeERC1155AssetData(encoded: string): [string, BigNumber[], BigNumber[], string] { | ||||
|     return assetDataIface.getABIDecodedTransactionData<[string, BigNumber[], BigNumber[], string]>( | ||||
|         'ERC1155Assets', | ||||
|         encoded, | ||||
|     ); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Decode MultiAsset asset data. | ||||
|  */ | ||||
| export function decodeMultiAssetData(encoded: string): [BigNumber[], string[]] { | ||||
|     return assetDataIface.getABIDecodedTransactionData<[BigNumber[], string[]]>('MultiAsset', encoded); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Decode StaticCall asset data. | ||||
|  */ | ||||
| export function decodeStaticCallAssetData(encoded: string): [string, string, string] { | ||||
|     return assetDataIface.getABIDecodedTransactionData<[string, string, string]>('StaticCall', encoded); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Decode ERC20Bridge asset data. | ||||
|  */ | ||||
| export function decodeERC20BridgeAssetData(encoded: string): [string, string, string] { | ||||
|     return assetDataIface.getABIDecodedTransactionData<[string, string, string]>('ERC20Bridge', encoded); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Encode ERC20 asset data. | ||||
|  */ | ||||
| export function encodeERC20AssetData(tokenAddress: string): string { | ||||
|     return assetDataIface.ERC20Token(tokenAddress).getABIEncodedTransactionData(); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Encode ERC721 asset data. | ||||
|  */ | ||||
| export function encodeERC721AssetData(tokenAddress: string, tokenId: BigNumber): string { | ||||
|     return assetDataIface.ERC721Token(tokenAddress, tokenId).getABIEncodedTransactionData(); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Encode ERC1155 asset data. | ||||
|  */ | ||||
| export function encodeERC1155AssetData( | ||||
|     tokenAddress: string, | ||||
|     tokenIds: BigNumber[], | ||||
|     values: BigNumber[], | ||||
|     callbackData: string, | ||||
| ): string { | ||||
|     return assetDataIface.ERC1155Assets(tokenAddress, tokenIds, values, callbackData).getABIEncodedTransactionData(); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Encode MultiAsset asset data. | ||||
|  */ | ||||
| export function encodeMultiAssetData(values: BigNumber[], nestedAssetData: string[]): string { | ||||
|     return assetDataIface.MultiAsset(values, nestedAssetData).getABIEncodedTransactionData(); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Encode StaticCall asset data. | ||||
|  */ | ||||
| export function encodeStaticCallAssetData( | ||||
|     staticCallTargetAddress: string, | ||||
|     staticCallData: string, | ||||
|     expectedReturnDataHash: string, | ||||
| ): string { | ||||
|     return assetDataIface | ||||
|         .StaticCall(staticCallTargetAddress, staticCallData, expectedReturnDataHash) | ||||
|         .getABIEncodedTransactionData(); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Encode ERC20Bridge asset data. | ||||
|  */ | ||||
| export function encodeERC20BridgeAssetData(tokenAddress: string, bridgeAddress: string, bridgeData: string): string { | ||||
|     return assetDataIface.ERC20Bridge(tokenAddress, bridgeAddress, bridgeData).getABIEncodedTransactionData(); | ||||
| } | ||||
| @@ -1,40 +0,0 @@ | ||||
| import { AbiEncoder, BigNumber } from '@0x/utils'; | ||||
|  | ||||
| export enum DydxBridgeActionType { | ||||
|     Deposit, | ||||
|     Withdraw, | ||||
| } | ||||
|  | ||||
| export interface DydxBridgeAction { | ||||
|     actionType: DydxBridgeActionType; | ||||
|     accountIdx: BigNumber; | ||||
|     marketId: BigNumber; | ||||
|     conversionRateNumerator: BigNumber; | ||||
|     conversionRateDenominator: BigNumber; | ||||
| } | ||||
|  | ||||
| export interface DydxBridgeData { | ||||
|     accountNumbers: BigNumber[]; | ||||
|     actions: DydxBridgeAction[]; | ||||
| } | ||||
|  | ||||
| export const dydxBridgeDataEncoder = AbiEncoder.create([ | ||||
|     { | ||||
|         name: 'bridgeData', | ||||
|         type: 'tuple', | ||||
|         components: [ | ||||
|             { name: 'accountNumbers', type: 'uint256[]' }, | ||||
|             { | ||||
|                 name: 'actions', | ||||
|                 type: 'tuple[]', | ||||
|                 components: [ | ||||
|                     { name: 'actionType', type: 'uint8' }, | ||||
|                     { name: 'accountIdx', type: 'uint256' }, | ||||
|                     { name: 'marketId', type: 'uint256' }, | ||||
|                     { name: 'conversionRateNumerator', type: 'uint256' }, | ||||
|                     { name: 'conversionRateDenominator', type: 'uint256' }, | ||||
|                 ], | ||||
|             }, | ||||
|         ], | ||||
|     }, | ||||
| ]); | ||||
| @@ -1,410 +0,0 @@ | ||||
| import { artifacts as erc1155Artifacts, ERC1155MintableContract, Erc1155Wrapper } from '@0x/contracts-erc1155'; | ||||
| import { | ||||
|     constants, | ||||
|     ERC1155FungibleHoldingsByOwner, | ||||
|     ERC1155HoldingsByOwner, | ||||
|     ERC1155NonFungibleHoldingsByOwner, | ||||
|     LogDecoder, | ||||
|     txDefaults, | ||||
| } from '@0x/contracts-test-utils'; | ||||
| import { BigNumber } from '@0x/utils'; | ||||
| import { Web3Wrapper } from '@0x/web3-wrapper'; | ||||
| import { Provider, TransactionReceiptWithDecodedLogs } from 'ethereum-types'; | ||||
| import * as _ from 'lodash'; | ||||
|  | ||||
| import { artifacts } from './artifacts'; | ||||
|  | ||||
| import { ERC1155ProxyContract, IAssetDataContract, IAssetProxyContract } from './wrappers'; | ||||
|  | ||||
| export class ERC1155ProxyWrapper { | ||||
|     private readonly _tokenOwnerAddresses: string[]; | ||||
|     private readonly _fungibleTokenIds: string[]; | ||||
|     private readonly _nonFungibleTokenIds: string[]; | ||||
|     private readonly _nfts: Array<{ id: BigNumber; tokenId: BigNumber }>; | ||||
|     private readonly _contractOwnerAddress: string; | ||||
|     private readonly _web3Wrapper: Web3Wrapper; | ||||
|     private readonly _provider: Provider; | ||||
|     private readonly _logDecoder: LogDecoder; | ||||
|     private readonly _dummyTokenWrappers: Erc1155Wrapper[]; | ||||
|     private readonly _assetProxyInterface: IAssetProxyContract; | ||||
|     private readonly _assetDataInterface: IAssetDataContract; | ||||
|     private _proxyContract?: ERC1155ProxyContract; | ||||
|     private _proxyIdIfExists?: string; | ||||
|     private _initialTokenIdsByOwner: ERC1155HoldingsByOwner = { fungible: {}, nonFungible: {} }; | ||||
|  | ||||
|     constructor(provider: Provider, tokenOwnerAddresses: string[], contractOwnerAddress: string) { | ||||
|         this._web3Wrapper = new Web3Wrapper(provider); | ||||
|         this._provider = provider; | ||||
|         const allArtifacts = _.merge(artifacts, erc1155Artifacts); | ||||
|         this._logDecoder = new LogDecoder(this._web3Wrapper, allArtifacts); | ||||
|         this._dummyTokenWrappers = []; | ||||
|         this._assetProxyInterface = new IAssetProxyContract(constants.NULL_ADDRESS, provider); | ||||
|         this._assetDataInterface = new IAssetDataContract(constants.NULL_ADDRESS, provider); | ||||
|         this._tokenOwnerAddresses = tokenOwnerAddresses; | ||||
|         this._contractOwnerAddress = contractOwnerAddress; | ||||
|         this._fungibleTokenIds = []; | ||||
|         this._nonFungibleTokenIds = []; | ||||
|         this._nfts = []; | ||||
|     } | ||||
|     /** | ||||
|      * @dev Deploys dummy ERC1155 contracts | ||||
|      * @return An array of ERC1155 wrappers; one for each deployed contract. | ||||
|      */ | ||||
|     public async deployDummyContractsAsync(): Promise<Erc1155Wrapper[]> { | ||||
|         // tslint:disable-next-line:no-unused-variable | ||||
|         for (const i of _.times(constants.NUM_DUMMY_ERC1155_CONTRACTS_TO_DEPLOY)) { | ||||
|             const erc1155Contract = await ERC1155MintableContract.deployFrom0xArtifactAsync( | ||||
|                 erc1155Artifacts.ERC1155Mintable, | ||||
|                 this._provider, | ||||
|                 txDefaults, | ||||
|                 artifacts, | ||||
|             ); | ||||
|             const erc1155Wrapper = new Erc1155Wrapper(erc1155Contract, this._contractOwnerAddress); | ||||
|             this._dummyTokenWrappers.push(erc1155Wrapper); | ||||
|         } | ||||
|         return this._dummyTokenWrappers; | ||||
|     } | ||||
|     /** | ||||
|      * @dev Deploys the ERC1155 proxy | ||||
|      * @return Deployed ERC1155 proxy contract instance | ||||
|      */ | ||||
|     public async deployProxyAsync(): Promise<ERC1155ProxyContract> { | ||||
|         this._proxyContract = await ERC1155ProxyContract.deployFrom0xArtifactAsync( | ||||
|             artifacts.ERC1155Proxy, | ||||
|             this._provider, | ||||
|             txDefaults, | ||||
|             artifacts, | ||||
|         ); | ||||
|         this._proxyIdIfExists = await this._proxyContract.getProxyId().callAsync(); | ||||
|         return this._proxyContract; | ||||
|     } | ||||
|     /** | ||||
|      * @dev Gets the ERC1155 proxy id | ||||
|      */ | ||||
|     public getProxyId(): string { | ||||
|         this._validateProxyContractExistsOrThrow(); | ||||
|         return this._proxyIdIfExists as string; | ||||
|     } | ||||
|     /** | ||||
|      * @dev generates abi-encoded tx data for transferring erc1155 fungible/non-fungible tokens. | ||||
|      * @param from source address | ||||
|      * @param to destination address | ||||
|      * @param contractAddress address of erc155 contract | ||||
|      * @param tokensToTransfer array of erc1155 tokens to transfer | ||||
|      * @param valuesToTransfer array of corresponding values for each erc1155 token to transfer | ||||
|      * @param valueMultiplier each value in `valuesToTransfer` is multiplied by this | ||||
|      * @param receiverCallbackData callback data if `to` is a contract | ||||
|      * @param authorizedSender sender of `transferFrom` transaction | ||||
|      * @param extraData extra data to append to `transferFrom` transaction. Optional. | ||||
|      * @return abi encoded tx data. | ||||
|      */ | ||||
|     public async getTransferFromAbiEncodedTxDataAsync( | ||||
|         from: string, | ||||
|         to: string, | ||||
|         contractAddress: string, | ||||
|         tokensToTransfer: BigNumber[], | ||||
|         valuesToTransfer: BigNumber[], | ||||
|         valueMultiplier: BigNumber, | ||||
|         receiverCallbackData: string, | ||||
|         authorizedSender: string, | ||||
|         assetData_?: string, | ||||
|     ): Promise<string> { | ||||
|         this._validateProxyContractExistsOrThrow(); | ||||
|         const assetData = | ||||
|             assetData_ === undefined | ||||
|                 ? this._assetDataInterface | ||||
|                       .ERC1155Assets(contractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData) | ||||
|                       .getABIEncodedTransactionData() | ||||
|                 : assetData_; | ||||
|         const data = this._assetProxyInterface | ||||
|             .transferFrom(assetData, from, to, valueMultiplier) | ||||
|             .getABIEncodedTransactionData(); | ||||
|         return data; | ||||
|     } | ||||
|     /** | ||||
|      * @dev transfers erc1155 fungible/non-fungible tokens. | ||||
|      * @param txData: abi-encoded tx data | ||||
|      * @param authorizedSender sender of `transferFrom` transaction | ||||
|      */ | ||||
|     public async transferFromRawAsync( | ||||
|         txData: string, | ||||
|         authorizedSender: string, | ||||
|     ): Promise<TransactionReceiptWithDecodedLogs> { | ||||
|         const txHash = await this._web3Wrapper.sendTransactionAsync({ | ||||
|             to: (this._proxyContract as ERC1155ProxyContract).address, | ||||
|             data: txData, | ||||
|             from: authorizedSender, | ||||
|             gas: 300000, | ||||
|         }); | ||||
|         const txReceipt = await this._logDecoder.getTxWithDecodedLogsAsync(txHash); | ||||
|         return txReceipt; | ||||
|     } | ||||
|     /** | ||||
|      * @dev transfers erc1155 fungible/non-fungible tokens. | ||||
|      * @param from source address | ||||
|      * @param to destination address | ||||
|      * @param contractAddress address of erc155 contract | ||||
|      * @param tokensToTransfer array of erc1155 tokens to transfer | ||||
|      * @param valuesToTransfer array of corresponding values for each erc1155 token to transfer | ||||
|      * @param valueMultiplier each value in `valuesToTransfer` is multiplied by this | ||||
|      * @param receiverCallbackData callback data if `to` is a contract | ||||
|      * @param authorizedSender sender of `transferFrom` transaction | ||||
|      * @param extraData extra data to append to `transferFrom` transaction. Optional. | ||||
|      * @return tranasction hash. | ||||
|      */ | ||||
|     public async transferFromAsync( | ||||
|         from: string, | ||||
|         to: string, | ||||
|         contractAddress: string, | ||||
|         tokensToTransfer: BigNumber[], | ||||
|         valuesToTransfer: BigNumber[], | ||||
|         valueMultiplier: BigNumber, | ||||
|         receiverCallbackData: string, | ||||
|         authorizedSender: string, | ||||
|         assetData_?: string, | ||||
|     ): Promise<TransactionReceiptWithDecodedLogs> { | ||||
|         this._validateProxyContractExistsOrThrow(); | ||||
|         const assetData = | ||||
|             assetData_ === undefined | ||||
|                 ? this._assetDataInterface | ||||
|                       .ERC1155Assets(contractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData) | ||||
|                       .getABIEncodedTransactionData() | ||||
|                 : assetData_; | ||||
|         const data = this._assetProxyInterface | ||||
|             .transferFrom(assetData, from, to, valueMultiplier) | ||||
|             .getABIEncodedTransactionData(); | ||||
|         const txHash = await this._web3Wrapper.sendTransactionAsync({ | ||||
|             to: (this._proxyContract as ERC1155ProxyContract).address, | ||||
|             data, | ||||
|             from: authorizedSender, | ||||
|             gas: 300000, | ||||
|         }); | ||||
|         const txReceipt = await this._logDecoder.getTxWithDecodedLogsAsync(txHash); | ||||
|         return txReceipt; | ||||
|     } | ||||
|     /** | ||||
|      * @dev For each deployed ERC1155 contract, this function mints a set of fungible/non-fungible | ||||
|      *      tokens for each token owner address (`_tokenOwnerAddresses`). | ||||
|      * @return Balances of each token owner, across all ERC1155 contracts and tokens. | ||||
|      */ | ||||
|     public async setBalancesAndAllowancesAsync(): Promise<ERC1155HoldingsByOwner> { | ||||
|         this._validateDummyTokenContractsExistOrThrow(); | ||||
|         this._validateProxyContractExistsOrThrow(); | ||||
|         this._initialTokenIdsByOwner = { | ||||
|             fungible: {}, | ||||
|             nonFungible: {}, | ||||
|         }; | ||||
|         const fungibleHoldingsByOwner: ERC1155FungibleHoldingsByOwner = {}; | ||||
|         const nonFungibleHoldingsByOwner: ERC1155NonFungibleHoldingsByOwner = {}; | ||||
|         // Set balances accordingly | ||||
|         for (const dummyWrapper of this._dummyTokenWrappers) { | ||||
|             const dummyAddress = dummyWrapper.getContract().address; | ||||
|             // tslint:disable-next-line:no-unused-variable | ||||
|             for (const i of _.times(constants.NUM_ERC1155_FUNGIBLE_TOKENS_MINT)) { | ||||
|                 // Create a fungible token | ||||
|                 const tokenId = await dummyWrapper.mintFungibleTokensAsync( | ||||
|                     this._tokenOwnerAddresses, | ||||
|                     constants.INITIAL_ERC1155_FUNGIBLE_BALANCE, | ||||
|                 ); | ||||
|                 const tokenIdAsString = tokenId.toString(); | ||||
|                 this._fungibleTokenIds.push(tokenIdAsString); | ||||
|                 // Mint tokens for each owner for this token | ||||
|                 for (const tokenOwnerAddress of this._tokenOwnerAddresses) { | ||||
|                     // tslint:disable-next-line:no-unused-variable | ||||
|                     if (fungibleHoldingsByOwner[tokenOwnerAddress] === undefined) { | ||||
|                         fungibleHoldingsByOwner[tokenOwnerAddress] = {}; | ||||
|                     } | ||||
|                     if (fungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress] === undefined) { | ||||
|                         fungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress] = {}; | ||||
|                     } | ||||
|                     fungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress][tokenIdAsString] = | ||||
|                         constants.INITIAL_ERC1155_FUNGIBLE_BALANCE; | ||||
|                     await dummyWrapper.setApprovalForAllAsync( | ||||
|                         tokenOwnerAddress, | ||||
|                         (this._proxyContract as ERC1155ProxyContract).address, | ||||
|                         true, | ||||
|                     ); | ||||
|                 } | ||||
|             } | ||||
|             // Non-fungible tokens | ||||
|             // tslint:disable-next-line:no-unused-variable | ||||
|             for (const j of _.times(constants.NUM_ERC1155_NONFUNGIBLE_TOKENS_MINT)) { | ||||
|                 const [tokenId, nftIds] = await dummyWrapper.mintNonFungibleTokensAsync(this._tokenOwnerAddresses); | ||||
|                 const tokenIdAsString = tokenId.toString(); | ||||
|                 this._nonFungibleTokenIds.push(tokenIdAsString); | ||||
|                 _.each(this._tokenOwnerAddresses, async (tokenOwnerAddress: string, i: number) => { | ||||
|                     if (nonFungibleHoldingsByOwner[tokenOwnerAddress] === undefined) { | ||||
|                         nonFungibleHoldingsByOwner[tokenOwnerAddress] = {}; | ||||
|                     } | ||||
|                     if (nonFungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress] === undefined) { | ||||
|                         nonFungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress] = {}; | ||||
|                     } | ||||
|                     if (nonFungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress][tokenIdAsString] === undefined) { | ||||
|                         nonFungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress][tokenIdAsString] = []; | ||||
|                     } | ||||
|                     this._nfts.push({ id: nftIds[i], tokenId }); | ||||
|                     nonFungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress][tokenIdAsString].push(nftIds[i]); | ||||
|                     await dummyWrapper.setApprovalForAllAsync( | ||||
|                         tokenOwnerAddress, | ||||
|                         (this._proxyContract as ERC1155ProxyContract).address, | ||||
|                         true, | ||||
|                     ); | ||||
|                 }); | ||||
|             } | ||||
|         } | ||||
|         this._initialTokenIdsByOwner = { | ||||
|             fungible: fungibleHoldingsByOwner, | ||||
|             nonFungible: nonFungibleHoldingsByOwner, | ||||
|         }; | ||||
|         return this._initialTokenIdsByOwner; | ||||
|     } | ||||
|     /** | ||||
|      * @dev For each deployed ERC1155 contract, this function quieries the set of fungible/non-fungible | ||||
|      *      tokens for each token owner address (`_tokenOwnerAddresses`). | ||||
|      * @return Balances of each token owner, across all ERC1155 contracts and tokens. | ||||
|      */ | ||||
|     public async getBalancesAsync(): Promise<ERC1155HoldingsByOwner> { | ||||
|         this._validateDummyTokenContractsExistOrThrow(); | ||||
|         this._validateBalancesAndAllowancesSetOrThrow(); | ||||
|         const tokenHoldingsByOwner: ERC1155FungibleHoldingsByOwner = {}; | ||||
|         const nonFungibleHoldingsByOwner: ERC1155NonFungibleHoldingsByOwner = {}; | ||||
|         for (const dummyTokenWrapper of this._dummyTokenWrappers) { | ||||
|             const tokenContract = dummyTokenWrapper.getContract(); | ||||
|             const tokenAddress = tokenContract.address; | ||||
|             // Construct batch balance call | ||||
|             const tokenOwners: string[] = []; | ||||
|             const tokenIds: BigNumber[] = []; | ||||
|             for (const tokenOwnerAddress of this._tokenOwnerAddresses) { | ||||
|                 for (const tokenId of this._fungibleTokenIds) { | ||||
|                     tokenOwners.push(tokenOwnerAddress); | ||||
|                     tokenIds.push(new BigNumber(tokenId)); | ||||
|                 } | ||||
|                 for (const nft of this._nfts) { | ||||
|                     tokenOwners.push(tokenOwnerAddress); | ||||
|                     tokenIds.push(nft.id); | ||||
|                 } | ||||
|             } | ||||
|             const balances = await dummyTokenWrapper.getBalancesAsync(tokenOwners, tokenIds); | ||||
|             // Parse out balances into fungible / non-fungible token holdings | ||||
|             let i = 0; | ||||
|             for (const tokenOwnerAddress of this._tokenOwnerAddresses) { | ||||
|                 // Fungible tokens | ||||
|                 for (const tokenId of this._fungibleTokenIds) { | ||||
|                     if (tokenHoldingsByOwner[tokenOwnerAddress] === undefined) { | ||||
|                         tokenHoldingsByOwner[tokenOwnerAddress] = {}; | ||||
|                     } | ||||
|                     if (tokenHoldingsByOwner[tokenOwnerAddress][tokenAddress] === undefined) { | ||||
|                         tokenHoldingsByOwner[tokenOwnerAddress][tokenAddress] = {}; | ||||
|                     } | ||||
|                     tokenHoldingsByOwner[tokenOwnerAddress][tokenAddress][tokenId] = balances[i++]; | ||||
|                 } | ||||
|                 // Non-fungible tokens | ||||
|                 for (const nft of this._nfts) { | ||||
|                     if (nonFungibleHoldingsByOwner[tokenOwnerAddress] === undefined) { | ||||
|                         nonFungibleHoldingsByOwner[tokenOwnerAddress] = {}; | ||||
|                     } | ||||
|                     if (nonFungibleHoldingsByOwner[tokenOwnerAddress][tokenAddress] === undefined) { | ||||
|                         nonFungibleHoldingsByOwner[tokenOwnerAddress][tokenAddress] = {}; | ||||
|                     } | ||||
|                     if ( | ||||
|                         nonFungibleHoldingsByOwner[tokenOwnerAddress][tokenAddress][nft.tokenId.toString()] === | ||||
|                         undefined | ||||
|                     ) { | ||||
|                         nonFungibleHoldingsByOwner[tokenOwnerAddress][tokenAddress][nft.tokenId.toString()] = []; | ||||
|                     } | ||||
|                     const isOwner = balances[i++]; | ||||
|                     if (isOwner.isEqualTo(1)) { | ||||
|                         nonFungibleHoldingsByOwner[tokenOwnerAddress][tokenAddress][nft.tokenId.toString()].push( | ||||
|                             nft.id, | ||||
|                         ); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         const holdingsByOwner = { | ||||
|             fungible: tokenHoldingsByOwner, | ||||
|             nonFungible: nonFungibleHoldingsByOwner, | ||||
|         }; | ||||
|         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. | ||||
|      * @param contractAddress address of ERC1155 contract. | ||||
|      * @return True iff the proxy is approved for all. False otherwise. | ||||
|      */ | ||||
|     public async isProxyApprovedForAllAsync(userAddress: string, contractAddress: string): Promise<boolean> { | ||||
|         this._validateProxyContractExistsOrThrow(); | ||||
|         const tokenContract = this._getContractFromAddress(contractAddress); | ||||
|         const operator = (this._proxyContract as ERC1155ProxyContract).address; | ||||
|         const didApproveAll = await tokenContract.isApprovedForAll(userAddress, operator).callAsync(); | ||||
|         return didApproveAll; | ||||
|     } | ||||
|     public getFungibleTokenIds(): BigNumber[] { | ||||
|         const fungibleTokenIds = _.map(this._fungibleTokenIds, (tokenIdAsString: string) => { | ||||
|             return new BigNumber(tokenIdAsString); | ||||
|         }); | ||||
|         return fungibleTokenIds; | ||||
|     } | ||||
|     public getNonFungibleTokenIds(): BigNumber[] { | ||||
|         const nonFungibleTokenIds = _.map(this._nonFungibleTokenIds, (tokenIdAsString: string) => { | ||||
|             return new BigNumber(tokenIdAsString); | ||||
|         }); | ||||
|         return nonFungibleTokenIds; | ||||
|     } | ||||
|     public getTokenOwnerAddresses(): string[] { | ||||
|         return this._tokenOwnerAddresses; | ||||
|     } | ||||
|     public getContractWrapper(contractAddress: string): Erc1155Wrapper { | ||||
|         const tokenWrapper = _.find(this._dummyTokenWrappers, (wrapper: Erc1155Wrapper) => { | ||||
|             return wrapper.getContract().address === contractAddress; | ||||
|         }); | ||||
|         if (tokenWrapper === undefined) { | ||||
|             throw new Error(`Contract: ${contractAddress} was not deployed through ERC1155ProxyWrapper`); | ||||
|         } | ||||
|         return tokenWrapper; | ||||
|     } | ||||
|     private _getContractFromAddress(tokenAddress: string): ERC1155MintableContract { | ||||
|         const tokenContractIfExists = _.find(this._dummyTokenWrappers, c => c.getContract().address === tokenAddress); | ||||
|         if (tokenContractIfExists === undefined) { | ||||
|             throw new Error(`Token: ${tokenAddress} was not deployed through ERC1155ProxyWrapper`); | ||||
|         } | ||||
|         return tokenContractIfExists.getContract(); | ||||
|     } | ||||
|     private _validateDummyTokenContractsExistOrThrow(): void { | ||||
|         if (this._dummyTokenWrappers === undefined) { | ||||
|             throw new Error('Dummy ERC1155 tokens not yet deployed, please call "deployDummyTokensAsync"'); | ||||
|         } | ||||
|     } | ||||
|     private _validateProxyContractExistsOrThrow(): void { | ||||
|         if (this._proxyContract === undefined) { | ||||
|             throw new Error('ERC1155 proxy contract not yet deployed, please call "deployProxyAsync"'); | ||||
|         } | ||||
|     } | ||||
|     private _validateBalancesAndAllowancesSetOrThrow(): void { | ||||
|         if ( | ||||
|             _.keys(this._initialTokenIdsByOwner.fungible).length === 0 || | ||||
|             _.keys(this._initialTokenIdsByOwner.nonFungible).length === 0 | ||||
|         ) { | ||||
|             throw new Error( | ||||
|                 'Dummy ERC1155 balances and allowances not yet set, please call "setBalancesAndAllowancesAsync"', | ||||
|             ); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,164 +0,0 @@ | ||||
| import { artifacts as erc20Artifacts, DummyERC20TokenContract } from '@0x/contracts-erc20'; | ||||
| import { constants, ERC20BalancesByOwner, txDefaults } from '@0x/contracts-test-utils'; | ||||
| import { BigNumber } from '@0x/utils'; | ||||
| import { ZeroExProvider } from 'ethereum-types'; | ||||
| import * as _ from 'lodash'; | ||||
|  | ||||
| import { artifacts } from './artifacts'; | ||||
|  | ||||
| import { ERC20ProxyContract, IAssetDataContract } from './wrappers'; | ||||
|  | ||||
| export class ERC20Wrapper { | ||||
|     private readonly _tokenOwnerAddresses: string[]; | ||||
|     private readonly _contractOwnerAddress: string; | ||||
|     private readonly _provider: ZeroExProvider; | ||||
|     private readonly _dummyTokenContracts: DummyERC20TokenContract[]; | ||||
|     private readonly _assetDataInterface: IAssetDataContract; | ||||
|     private _proxyContract?: ERC20ProxyContract; | ||||
|     private _proxyIdIfExists?: string; | ||||
|     /** | ||||
|      * Instanitates an ERC20Wrapper | ||||
|      * @param provider Web3 provider to use for all JSON RPC requests | ||||
|      * @param tokenOwnerAddresses Addresses that we want to endow as owners for dummy ERC20 tokens | ||||
|      * @param contractOwnerAddress Desired owner of the contract | ||||
|      * Instance of ERC20Wrapper | ||||
|      */ | ||||
|     constructor(provider: ZeroExProvider, tokenOwnerAddresses: string[], contractOwnerAddress: string) { | ||||
|         this._dummyTokenContracts = []; | ||||
|         this._provider = provider; | ||||
|         this._tokenOwnerAddresses = tokenOwnerAddresses; | ||||
|         this._contractOwnerAddress = contractOwnerAddress; | ||||
|         this._assetDataInterface = new IAssetDataContract(constants.NULL_ADDRESS, provider); | ||||
|     } | ||||
|     public async deployDummyTokensAsync( | ||||
|         numberToDeploy: number, | ||||
|         decimals: BigNumber, | ||||
|     ): Promise<DummyERC20TokenContract[]> { | ||||
|         for (let i = 0; i < numberToDeploy; i++) { | ||||
|             this._dummyTokenContracts.push( | ||||
|                 await DummyERC20TokenContract.deployFrom0xArtifactAsync( | ||||
|                     erc20Artifacts.DummyERC20Token, | ||||
|                     this._provider, | ||||
|                     txDefaults, | ||||
|                     artifacts, | ||||
|                     constants.DUMMY_TOKEN_NAME, | ||||
|                     constants.DUMMY_TOKEN_SYMBOL, | ||||
|                     decimals, | ||||
|                     constants.DUMMY_TOKEN_TOTAL_SUPPLY, | ||||
|                 ), | ||||
|             ); | ||||
|         } | ||||
|         return this._dummyTokenContracts; | ||||
|     } | ||||
|     public async deployProxyAsync(): Promise<ERC20ProxyContract> { | ||||
|         this._proxyContract = await ERC20ProxyContract.deployFrom0xArtifactAsync( | ||||
|             artifacts.ERC20Proxy, | ||||
|             this._provider, | ||||
|             txDefaults, | ||||
|             artifacts, | ||||
|         ); | ||||
|         this._proxyIdIfExists = await this._proxyContract.getProxyId().callAsync(); | ||||
|         return this._proxyContract; | ||||
|     } | ||||
|     public getProxyId(): string { | ||||
|         this._validateProxyContractExistsOrThrow(); | ||||
|         return this._proxyIdIfExists as string; | ||||
|     } | ||||
|     public async setBalancesAndAllowancesAsync(): Promise<void> { | ||||
|         this._validateDummyTokenContractsExistOrThrow(); | ||||
|         this._validateProxyContractExistsOrThrow(); | ||||
|         for (const dummyTokenContract of this._dummyTokenContracts) { | ||||
|             for (const tokenOwnerAddress of this._tokenOwnerAddresses) { | ||||
|                 await dummyTokenContract | ||||
|                     .setBalance(tokenOwnerAddress, constants.INITIAL_ERC20_BALANCE) | ||||
|                     .awaitTransactionSuccessAsync({ from: this._contractOwnerAddress }); | ||||
|                 await dummyTokenContract | ||||
|                     .approve((this._proxyContract as ERC20ProxyContract).address, constants.INITIAL_ERC20_ALLOWANCE) | ||||
|                     .awaitTransactionSuccessAsync({ from: tokenOwnerAddress }); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     public async getBalanceAsync(userAddress: string, assetData: string): Promise<BigNumber> { | ||||
|         const tokenContract = await this._getTokenContractFromAssetDataAsync(assetData); | ||||
|         const balance = new BigNumber(await tokenContract.balanceOf(userAddress).callAsync()); | ||||
|         return balance; | ||||
|     } | ||||
|     public async setBalanceAsync(userAddress: string, assetData: string, amount: BigNumber): Promise<void> { | ||||
|         const tokenContract = await this._getTokenContractFromAssetDataAsync(assetData); | ||||
|         await tokenContract | ||||
|             .setBalance(userAddress, amount) | ||||
|             .awaitTransactionSuccessAsync( | ||||
|                 { from: this._contractOwnerAddress }, | ||||
|                 { pollingIntervalMs: constants.AWAIT_TRANSACTION_MINED_MS }, | ||||
|             ); | ||||
|     } | ||||
|     public async getProxyAllowanceAsync(userAddress: string, assetData: string): Promise<BigNumber> { | ||||
|         const tokenContract = await this._getTokenContractFromAssetDataAsync(assetData); | ||||
|         const proxyAddress = (this._proxyContract as ERC20ProxyContract).address; | ||||
|         const allowance = new BigNumber(await tokenContract.allowance(userAddress, proxyAddress).callAsync()); | ||||
|         return allowance; | ||||
|     } | ||||
|     public async setAllowanceAsync(userAddress: string, assetData: string, amount: BigNumber): Promise<void> { | ||||
|         const tokenContract = await this._getTokenContractFromAssetDataAsync(assetData); | ||||
|         const proxyAddress = (this._proxyContract as ERC20ProxyContract).address; | ||||
|         await tokenContract.approve(proxyAddress, amount).awaitTransactionSuccessAsync({ from: userAddress }); | ||||
|     } | ||||
|     public async getBalancesAsync(): Promise<ERC20BalancesByOwner> { | ||||
|         this._validateDummyTokenContractsExistOrThrow(); | ||||
|         const balancesByOwner: ERC20BalancesByOwner = {}; | ||||
|         const balances: BigNumber[] = []; | ||||
|         const balanceInfo: Array<{ tokenOwnerAddress: string; tokenAddress: string }> = []; | ||||
|         for (const dummyTokenContract of this._dummyTokenContracts) { | ||||
|             for (const tokenOwnerAddress of this._tokenOwnerAddresses) { | ||||
|                 balances.push(await dummyTokenContract.balanceOf(tokenOwnerAddress).callAsync()); | ||||
|                 balanceInfo.push({ | ||||
|                     tokenOwnerAddress, | ||||
|                     tokenAddress: dummyTokenContract.address, | ||||
|                 }); | ||||
|             } | ||||
|         } | ||||
|         _.forEach(balances, (balance, balanceIndex) => { | ||||
|             const tokenAddress = balanceInfo[balanceIndex].tokenAddress; | ||||
|             const tokenOwnerAddress = balanceInfo[balanceIndex].tokenOwnerAddress; | ||||
|             if (balancesByOwner[tokenOwnerAddress] === undefined) { | ||||
|                 balancesByOwner[tokenOwnerAddress] = {}; | ||||
|             } | ||||
|             const wrappedBalance = new BigNumber(balance); | ||||
|             balancesByOwner[tokenOwnerAddress][tokenAddress] = wrappedBalance; | ||||
|         }); | ||||
|         return balancesByOwner; | ||||
|     } | ||||
|     public addDummyTokenContract(dummy: DummyERC20TokenContract): void { | ||||
|         if (this._dummyTokenContracts !== undefined) { | ||||
|             this._dummyTokenContracts.push(dummy); | ||||
|         } | ||||
|     } | ||||
|     public addTokenOwnerAddress(address: string): void { | ||||
|         this._tokenOwnerAddresses.push(address); | ||||
|     } | ||||
|     public getTokenOwnerAddresses(): string[] { | ||||
|         return this._tokenOwnerAddresses; | ||||
|     } | ||||
|     public getTokenAddresses(): string[] { | ||||
|         const tokenAddresses = _.map(this._dummyTokenContracts, dummyTokenContract => dummyTokenContract.address); | ||||
|         return tokenAddresses; | ||||
|     } | ||||
|     private async _getTokenContractFromAssetDataAsync(assetData: string): Promise<DummyERC20TokenContract> { | ||||
|         const tokenAddress = this._assetDataInterface.getABIDecodedTransactionData<string>('ERC20Token', assetData); // tslint:disable-line:no-unused-variable | ||||
|         const tokenContractIfExists = _.find(this._dummyTokenContracts, c => c.address === tokenAddress); | ||||
|         if (tokenContractIfExists === undefined) { | ||||
|             throw new Error(`Token: ${tokenAddress} was not deployed through ERC20Wrapper`); | ||||
|         } | ||||
|         return tokenContractIfExists; | ||||
|     } | ||||
|     private _validateDummyTokenContractsExistOrThrow(): void { | ||||
|         if (this._dummyTokenContracts === undefined) { | ||||
|             throw new Error('Dummy ERC20 tokens not yet deployed, please call "deployDummyTokensAsync"'); | ||||
|         } | ||||
|     } | ||||
|     private _validateProxyContractExistsOrThrow(): void { | ||||
|         if (this._proxyContract === undefined) { | ||||
|             throw new Error('ERC20 proxy contract not yet deployed, please call "deployProxyAsync"'); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,220 +0,0 @@ | ||||
| import { artifacts as erc721Artifacts, DummyERC721TokenContract } from '@0x/contracts-erc721'; | ||||
| import { constants, ERC721TokenIdsByOwner, txDefaults } from '@0x/contracts-test-utils'; | ||||
| import { generatePseudoRandomSalt } from '@0x/order-utils'; | ||||
| import { BigNumber } from '@0x/utils'; | ||||
| import { ZeroExProvider } from 'ethereum-types'; | ||||
| import * as _ from 'lodash'; | ||||
|  | ||||
| import { artifacts } from './artifacts'; | ||||
|  | ||||
| import { ERC721ProxyContract } from './wrappers'; | ||||
|  | ||||
| export class ERC721Wrapper { | ||||
|     private readonly _tokenOwnerAddresses: string[]; | ||||
|     private readonly _contractOwnerAddress: string; | ||||
|     private readonly _provider: ZeroExProvider; | ||||
|     private readonly _dummyTokenContracts: DummyERC721TokenContract[]; | ||||
|     private _proxyContract?: ERC721ProxyContract; | ||||
|     private _proxyIdIfExists?: string; | ||||
|     private _initialTokenIdsByOwner: ERC721TokenIdsByOwner = {}; | ||||
|     constructor(provider: ZeroExProvider, tokenOwnerAddresses: string[], contractOwnerAddress: string) { | ||||
|         this._provider = provider; | ||||
|         this._dummyTokenContracts = []; | ||||
|         this._tokenOwnerAddresses = tokenOwnerAddresses; | ||||
|         this._contractOwnerAddress = contractOwnerAddress; | ||||
|     } | ||||
|     public async deployDummyTokensAsync(): Promise<DummyERC721TokenContract[]> { | ||||
|         // tslint:disable-next-line:no-unused-variable | ||||
|         for (const i of _.times(constants.NUM_DUMMY_ERC721_TO_DEPLOY)) { | ||||
|             this._dummyTokenContracts.push( | ||||
|                 await DummyERC721TokenContract.deployFrom0xArtifactAsync( | ||||
|                     erc721Artifacts.DummyERC721Token, | ||||
|                     this._provider, | ||||
|                     txDefaults, | ||||
|                     artifacts, | ||||
|                     constants.DUMMY_TOKEN_NAME, | ||||
|                     constants.DUMMY_TOKEN_SYMBOL, | ||||
|                 ), | ||||
|             ); | ||||
|         } | ||||
|         return this._dummyTokenContracts; | ||||
|     } | ||||
|     public async deployProxyAsync(): Promise<ERC721ProxyContract> { | ||||
|         this._proxyContract = await ERC721ProxyContract.deployFrom0xArtifactAsync( | ||||
|             artifacts.ERC721Proxy, | ||||
|             this._provider, | ||||
|             txDefaults, | ||||
|             artifacts, | ||||
|         ); | ||||
|         this._proxyIdIfExists = await this._proxyContract.getProxyId().callAsync(); | ||||
|         return this._proxyContract; | ||||
|     } | ||||
|     public getProxyId(): string { | ||||
|         this._validateProxyContractExistsOrThrow(); | ||||
|         return this._proxyIdIfExists as string; | ||||
|     } | ||||
|     public async setBalancesAndAllowancesAsync(): Promise<void> { | ||||
|         this._validateDummyTokenContractsExistOrThrow(); | ||||
|         this._validateProxyContractExistsOrThrow(); | ||||
|         this._initialTokenIdsByOwner = {}; | ||||
|         for (const dummyTokenContract of this._dummyTokenContracts) { | ||||
|             for (const tokenOwnerAddress of this._tokenOwnerAddresses) { | ||||
|                 // tslint:disable-next-line:no-unused-variable | ||||
|                 for (const i of _.times(constants.NUM_ERC721_TOKENS_TO_MINT)) { | ||||
|                     const tokenId = generatePseudoRandomSalt(); | ||||
|                     await this.mintAsync(dummyTokenContract.address, tokenId, tokenOwnerAddress); | ||||
|                     if (this._initialTokenIdsByOwner[tokenOwnerAddress] === undefined) { | ||||
|                         this._initialTokenIdsByOwner[tokenOwnerAddress] = { | ||||
|                             [dummyTokenContract.address]: [], | ||||
|                         }; | ||||
|                     } | ||||
|                     if (this._initialTokenIdsByOwner[tokenOwnerAddress][dummyTokenContract.address] === undefined) { | ||||
|                         this._initialTokenIdsByOwner[tokenOwnerAddress][dummyTokenContract.address] = []; | ||||
|                     } | ||||
|                     this._initialTokenIdsByOwner[tokenOwnerAddress][dummyTokenContract.address].push(tokenId); | ||||
|  | ||||
|                     await this.approveProxyForAllAsync(dummyTokenContract.address, tokenOwnerAddress, true); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     public async doesTokenExistAsync(tokenAddress: string, tokenId: BigNumber): Promise<boolean> { | ||||
|         const tokenContract = this._getTokenContractFromAssetData(tokenAddress); | ||||
|         const owner = await tokenContract.ownerOf(tokenId).callAsync(); | ||||
|         const doesExist = owner !== constants.NULL_ADDRESS; | ||||
|         return doesExist; | ||||
|     } | ||||
|     public async approveProxyAsync(tokenAddress: string, tokenId: BigNumber): Promise<void> { | ||||
|         const proxyAddress = (this._proxyContract as ERC721ProxyContract).address; | ||||
|         await this.approveAsync(proxyAddress, tokenAddress, tokenId); | ||||
|     } | ||||
|     public async approveProxyForAllAsync( | ||||
|         tokenAddress: string, | ||||
|         ownerAddress: string, | ||||
|         isApproved: boolean, | ||||
|     ): Promise<void> { | ||||
|         const tokenContract = this._getTokenContractFromAssetData(tokenAddress); | ||||
|         const proxyAddress = (this._proxyContract as ERC721ProxyContract).address; | ||||
|         await tokenContract.setApprovalForAll(proxyAddress, isApproved).awaitTransactionSuccessAsync({ | ||||
|             from: ownerAddress, | ||||
|         }); | ||||
|     } | ||||
|     public async approveAsync(to: string, tokenAddress: string, tokenId: BigNumber): Promise<void> { | ||||
|         const tokenContract = this._getTokenContractFromAssetData(tokenAddress); | ||||
|         const tokenOwner = await this.ownerOfAsync(tokenAddress, tokenId); | ||||
|         await tokenContract.approve(to, tokenId).awaitTransactionSuccessAsync({ from: tokenOwner }); | ||||
|     } | ||||
|     public async transferFromAsync( | ||||
|         tokenAddress: string, | ||||
|         tokenId: BigNumber, | ||||
|         currentOwner: string, | ||||
|         userAddress: string, | ||||
|     ): Promise<void> { | ||||
|         const tokenContract = this._getTokenContractFromAssetData(tokenAddress); | ||||
|         await tokenContract.transferFrom(currentOwner, userAddress, tokenId).awaitTransactionSuccessAsync({ | ||||
|             from: currentOwner, | ||||
|         }); | ||||
|     } | ||||
|     public async mintAsync(tokenAddress: string, tokenId: BigNumber, userAddress: string): Promise<void> { | ||||
|         const tokenContract = this._getTokenContractFromAssetData(tokenAddress); | ||||
|         await tokenContract.mint(userAddress, tokenId).awaitTransactionSuccessAsync({ | ||||
|             from: this._contractOwnerAddress, | ||||
|         }); | ||||
|     } | ||||
|     public async burnAsync(tokenAddress: string, tokenId: BigNumber, owner: string): Promise<void> { | ||||
|         const tokenContract = this._getTokenContractFromAssetData(tokenAddress); | ||||
|         await tokenContract.burn(owner, tokenId).awaitTransactionSuccessAsync({ from: this._contractOwnerAddress }); | ||||
|     } | ||||
|     public async ownerOfAsync(tokenAddress: string, tokenId: BigNumber): Promise<string> { | ||||
|         const tokenContract = this._getTokenContractFromAssetData(tokenAddress); | ||||
|         const owner = await tokenContract.ownerOf(tokenId).callAsync(); | ||||
|         return owner; | ||||
|     } | ||||
|     public async isOwnerAsync(userAddress: string, tokenAddress: string, tokenId: BigNumber): Promise<boolean> { | ||||
|         const tokenContract = this._getTokenContractFromAssetData(tokenAddress); | ||||
|         const tokenOwner = await tokenContract.ownerOf(tokenId).callAsync(); | ||||
|         const isOwner = tokenOwner === userAddress; | ||||
|         return isOwner; | ||||
|     } | ||||
|     public async isProxyApprovedForAllAsync(userAddress: string, tokenAddress: string): Promise<boolean> { | ||||
|         this._validateProxyContractExistsOrThrow(); | ||||
|         const tokenContract = this._getTokenContractFromAssetData(tokenAddress); | ||||
|         const operator = (this._proxyContract as ERC721ProxyContract).address; | ||||
|         const didApproveAll = await tokenContract.isApprovedForAll(userAddress, operator).callAsync(); | ||||
|         return didApproveAll; | ||||
|     } | ||||
|     public async isProxyApprovedAsync(tokenAddress: string, tokenId: BigNumber): Promise<boolean> { | ||||
|         this._validateProxyContractExistsOrThrow(); | ||||
|         const tokenContract = this._getTokenContractFromAssetData(tokenAddress); | ||||
|         const approvedAddress = await tokenContract.getApproved(tokenId).callAsync(); | ||||
|         const proxyAddress = (this._proxyContract as ERC721ProxyContract).address; | ||||
|         const isProxyAnApprovedOperator = approvedAddress === proxyAddress; | ||||
|         return isProxyAnApprovedOperator; | ||||
|     } | ||||
|     public async getBalancesAsync(): Promise<ERC721TokenIdsByOwner> { | ||||
|         this._validateDummyTokenContractsExistOrThrow(); | ||||
|         this._validateBalancesAndAllowancesSetOrThrow(); | ||||
|         const tokenIdsByOwner: ERC721TokenIdsByOwner = {}; | ||||
|         const tokenOwnerAddresses: string[] = []; | ||||
|         const tokenInfo: Array<{ tokenId: BigNumber; tokenAddress: string }> = []; | ||||
|         for (const dummyTokenContract of this._dummyTokenContracts) { | ||||
|             for (const tokenOwnerAddress of this._tokenOwnerAddresses) { | ||||
|                 const initialTokenOwnerIds = this._initialTokenIdsByOwner[tokenOwnerAddress][ | ||||
|                     dummyTokenContract.address | ||||
|                 ]; | ||||
|                 for (const tokenId of initialTokenOwnerIds) { | ||||
|                     tokenOwnerAddresses.push(await dummyTokenContract.ownerOf(tokenId).callAsync()); | ||||
|                     tokenInfo.push({ | ||||
|                         tokenId, | ||||
|                         tokenAddress: dummyTokenContract.address, | ||||
|                     }); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         _.forEach(tokenOwnerAddresses, (tokenOwnerAddress, ownerIndex) => { | ||||
|             const tokenAddress = tokenInfo[ownerIndex].tokenAddress; | ||||
|             const tokenId = tokenInfo[ownerIndex].tokenId; | ||||
|             if (tokenIdsByOwner[tokenOwnerAddress] === undefined) { | ||||
|                 tokenIdsByOwner[tokenOwnerAddress] = { | ||||
|                     [tokenAddress]: [], | ||||
|                 }; | ||||
|             } | ||||
|             if (tokenIdsByOwner[tokenOwnerAddress][tokenAddress] === undefined) { | ||||
|                 tokenIdsByOwner[tokenOwnerAddress][tokenAddress] = []; | ||||
|             } | ||||
|             tokenIdsByOwner[tokenOwnerAddress][tokenAddress].push(tokenId); | ||||
|         }); | ||||
|         return tokenIdsByOwner; | ||||
|     } | ||||
|     public getTokenOwnerAddresses(): string[] { | ||||
|         return this._tokenOwnerAddresses; | ||||
|     } | ||||
|     public getTokenAddresses(): string[] { | ||||
|         const tokenAddresses = _.map(this._dummyTokenContracts, dummyTokenContract => dummyTokenContract.address); | ||||
|         return tokenAddresses; | ||||
|     } | ||||
|     private _getTokenContractFromAssetData(tokenAddress: string): DummyERC721TokenContract { | ||||
|         const tokenContractIfExists = _.find(this._dummyTokenContracts, c => c.address === tokenAddress); | ||||
|         if (tokenContractIfExists === undefined) { | ||||
|             throw new Error(`Token: ${tokenAddress} was not deployed through ERC20Wrapper`); | ||||
|         } | ||||
|         return tokenContractIfExists; | ||||
|     } | ||||
|     private _validateDummyTokenContractsExistOrThrow(): void { | ||||
|         if (this._dummyTokenContracts === undefined) { | ||||
|             throw new Error('Dummy ERC721 tokens not yet deployed, please call "deployDummyTokensAsync"'); | ||||
|         } | ||||
|     } | ||||
|     private _validateProxyContractExistsOrThrow(): void { | ||||
|         if (this._proxyContract === undefined) { | ||||
|             throw new Error('ERC721 proxy contract not yet deployed, please call "deployProxyAsync"'); | ||||
|         } | ||||
|     } | ||||
|     private _validateBalancesAndAllowancesSetOrThrow(): void { | ||||
|         if (_.keys(this._initialTokenIdsByOwner).length === 0) { | ||||
|             throw new Error( | ||||
|                 'Dummy ERC721 balances and allowances not yet set, please call "setBalancesAndAllowancesAsync"', | ||||
|             ); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,90 +0,0 @@ | ||||
| export { artifacts } from './artifacts'; | ||||
| export { | ||||
|     ChaiBridgeContract, | ||||
|     ERC1155ProxyContract, | ||||
|     ERC20BridgeProxyContract, | ||||
|     ERC20ProxyContract, | ||||
|     ERC721ProxyContract, | ||||
|     Eth2DaiBridgeContract, | ||||
|     DydxBridgeContract, | ||||
|     IAssetDataContract, | ||||
|     IAssetProxyContract, | ||||
|     IChaiContract, | ||||
|     IDydxContract, | ||||
|     KyberBridgeContract, | ||||
|     MultiAssetProxyContract, | ||||
|     StaticCallProxyContract, | ||||
|     TestDydxBridgeContract, | ||||
|     TestStaticCallTargetContract, | ||||
|     UniswapBridgeContract, | ||||
| } from './wrappers'; | ||||
|  | ||||
| export { ERC20Wrapper } from './erc20_wrapper'; | ||||
| export { ERC721Wrapper } from './erc721_wrapper'; | ||||
| export { ERC1155ProxyWrapper } from './erc1155_proxy_wrapper'; | ||||
| export { ERC1155MintableContract, Erc1155Wrapper } from '@0x/contracts-erc1155'; | ||||
| export { DummyERC20TokenContract } from '@0x/contracts-erc20'; | ||||
| export { DummyERC721TokenContract } from '@0x/contracts-erc721'; | ||||
| export { AssetProxyId } from '@0x/types'; | ||||
| export { | ||||
|     ERC1155HoldingsByOwner, | ||||
|     ERC20BalancesByOwner, | ||||
|     ERC721TokenIdsByOwner, | ||||
|     ERC1155FungibleHoldingsByOwner, | ||||
|     ERC1155NonFungibleHoldingsByOwner, | ||||
| } from '@0x/contracts-test-utils'; | ||||
| export { | ||||
|     TransactionReceiptWithDecodedLogs, | ||||
|     Provider, | ||||
|     ZeroExProvider, | ||||
|     JSONRPCRequestPayload, | ||||
|     JSONRPCErrorCallback, | ||||
|     TransactionReceiptStatus, | ||||
|     JSONRPCResponsePayload, | ||||
|     JSONRPCResponseError, | ||||
|     ContractArtifact, | ||||
|     ContractChains, | ||||
|     CompilerOpts, | ||||
|     StandardContractOutput, | ||||
|     CompilerSettings, | ||||
|     ContractChainData, | ||||
|     ContractAbi, | ||||
|     DevdocOutput, | ||||
|     EvmOutput, | ||||
|     CompilerSettingsMetadata, | ||||
|     OptimizerSettings, | ||||
|     OutputField, | ||||
|     ParamDescription, | ||||
|     EvmBytecodeOutput, | ||||
|     EvmBytecodeOutputLinkReferences, | ||||
|     AbiDefinition, | ||||
|     FunctionAbi, | ||||
|     EventAbi, | ||||
|     RevertErrorAbi, | ||||
|     EventParameter, | ||||
|     DataItem, | ||||
|     MethodAbi, | ||||
|     ConstructorAbi, | ||||
|     FallbackAbi, | ||||
|     ConstructorStateMutability, | ||||
|     TupleDataItem, | ||||
|     StateMutability, | ||||
| } from 'ethereum-types'; | ||||
|  | ||||
| export { | ||||
|     decodeERC1155AssetData, | ||||
|     decodeERC20AssetData, | ||||
|     decodeERC20BridgeAssetData, | ||||
|     decodeERC721AssetData, | ||||
|     decodeMultiAssetData, | ||||
|     decodeStaticCallAssetData, | ||||
|     encodeERC1155AssetData, | ||||
|     encodeERC20AssetData, | ||||
|     encodeERC20BridgeAssetData, | ||||
|     encodeERC721AssetData, | ||||
|     encodeMultiAssetData, | ||||
|     encodeStaticCallAssetData, | ||||
|     getAssetDataProxyId, | ||||
| } from './asset_data'; | ||||
|  | ||||
| export * from './dydx_bridge_encoder'; | ||||
| @@ -1,40 +0,0 @@ | ||||
| /* | ||||
|  * ----------------------------------------------------------------------------- | ||||
|  * Warning: This file is auto-generated by contracts-gen. Don't edit manually. | ||||
|  * ----------------------------------------------------------------------------- | ||||
|  */ | ||||
| export * from '../generated-wrappers/chai_bridge'; | ||||
| export * from '../generated-wrappers/curve_bridge'; | ||||
| export * from '../generated-wrappers/dydx_bridge'; | ||||
| export * from '../generated-wrappers/erc1155_proxy'; | ||||
| export * from '../generated-wrappers/erc20_bridge_proxy'; | ||||
| 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_chai'; | ||||
| export * from '../generated-wrappers/i_curve'; | ||||
| export * from '../generated-wrappers/i_dydx'; | ||||
| export * from '../generated-wrappers/i_dydx_bridge'; | ||||
| export * from '../generated-wrappers/i_erc20_bridge'; | ||||
| export * from '../generated-wrappers/i_eth2_dai'; | ||||
| export * from '../generated-wrappers/i_kyber_network_proxy'; | ||||
| export * from '../generated-wrappers/i_uniswap_exchange'; | ||||
| export * from '../generated-wrappers/i_uniswap_exchange_factory'; | ||||
| export * from '../generated-wrappers/kyber_bridge'; | ||||
| 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_chai_bridge'; | ||||
| export * from '../generated-wrappers/test_dydx_bridge'; | ||||
| export * from '../generated-wrappers/test_erc20_bridge'; | ||||
| export * from '../generated-wrappers/test_eth2_dai_bridge'; | ||||
| export * from '../generated-wrappers/test_kyber_bridge'; | ||||
| export * from '../generated-wrappers/test_static_call_target'; | ||||
| export * from '../generated-wrappers/test_uniswap_bridge'; | ||||
| export * from '../generated-wrappers/uniswap_bridge'; | ||||
| @@ -1,79 +0,0 @@ | ||||
| /* | ||||
|  * ----------------------------------------------------------------------------- | ||||
|  * Warning: This file is auto-generated by contracts-gen. Don't edit manually. | ||||
|  * ----------------------------------------------------------------------------- | ||||
|  */ | ||||
| import { ContractArtifact } from 'ethereum-types'; | ||||
|  | ||||
| import * as ChaiBridge from '../test/generated-artifacts/ChaiBridge.json'; | ||||
| import * as CurveBridge from '../test/generated-artifacts/CurveBridge.json'; | ||||
| import * as DydxBridge from '../test/generated-artifacts/DydxBridge.json'; | ||||
| import * as ERC1155Proxy from '../test/generated-artifacts/ERC1155Proxy.json'; | ||||
| import * as ERC20BridgeProxy from '../test/generated-artifacts/ERC20BridgeProxy.json'; | ||||
| import * as ERC20Proxy from '../test/generated-artifacts/ERC20Proxy.json'; | ||||
| import * as ERC721Proxy from '../test/generated-artifacts/ERC721Proxy.json'; | ||||
| import * as Eth2DaiBridge from '../test/generated-artifacts/Eth2DaiBridge.json'; | ||||
| import * as IAssetData from '../test/generated-artifacts/IAssetData.json'; | ||||
| import * as IAssetProxy from '../test/generated-artifacts/IAssetProxy.json'; | ||||
| import * as IAssetProxyDispatcher from '../test/generated-artifacts/IAssetProxyDispatcher.json'; | ||||
| import * as IAuthorizable from '../test/generated-artifacts/IAuthorizable.json'; | ||||
| import * as IChai from '../test/generated-artifacts/IChai.json'; | ||||
| import * as ICurve from '../test/generated-artifacts/ICurve.json'; | ||||
| import * as IDydx from '../test/generated-artifacts/IDydx.json'; | ||||
| import * as IDydxBridge from '../test/generated-artifacts/IDydxBridge.json'; | ||||
| import * as IERC20Bridge from '../test/generated-artifacts/IERC20Bridge.json'; | ||||
| import * as IEth2Dai from '../test/generated-artifacts/IEth2Dai.json'; | ||||
| import * as IKyberNetworkProxy from '../test/generated-artifacts/IKyberNetworkProxy.json'; | ||||
| import * as IUniswapExchange from '../test/generated-artifacts/IUniswapExchange.json'; | ||||
| import * as IUniswapExchangeFactory from '../test/generated-artifacts/IUniswapExchangeFactory.json'; | ||||
| import * as KyberBridge from '../test/generated-artifacts/KyberBridge.json'; | ||||
| import * as MixinAssetProxyDispatcher from '../test/generated-artifacts/MixinAssetProxyDispatcher.json'; | ||||
| import * as MixinAuthorizable from '../test/generated-artifacts/MixinAuthorizable.json'; | ||||
| import * as MultiAssetProxy from '../test/generated-artifacts/MultiAssetProxy.json'; | ||||
| import * as Ownable from '../test/generated-artifacts/Ownable.json'; | ||||
| import * as StaticCallProxy from '../test/generated-artifacts/StaticCallProxy.json'; | ||||
| import * as TestChaiBridge from '../test/generated-artifacts/TestChaiBridge.json'; | ||||
| import * as TestDydxBridge from '../test/generated-artifacts/TestDydxBridge.json'; | ||||
| import * as TestERC20Bridge from '../test/generated-artifacts/TestERC20Bridge.json'; | ||||
| import * as TestEth2DaiBridge from '../test/generated-artifacts/TestEth2DaiBridge.json'; | ||||
| import * as TestKyberBridge from '../test/generated-artifacts/TestKyberBridge.json'; | ||||
| import * as TestStaticCallTarget from '../test/generated-artifacts/TestStaticCallTarget.json'; | ||||
| import * as TestUniswapBridge from '../test/generated-artifacts/TestUniswapBridge.json'; | ||||
| import * as UniswapBridge from '../test/generated-artifacts/UniswapBridge.json'; | ||||
| export const artifacts = { | ||||
|     MixinAssetProxyDispatcher: MixinAssetProxyDispatcher as ContractArtifact, | ||||
|     MixinAuthorizable: MixinAuthorizable as ContractArtifact, | ||||
|     Ownable: Ownable as ContractArtifact, | ||||
|     ERC1155Proxy: ERC1155Proxy as ContractArtifact, | ||||
|     ERC20BridgeProxy: ERC20BridgeProxy as ContractArtifact, | ||||
|     ERC20Proxy: ERC20Proxy as ContractArtifact, | ||||
|     ERC721Proxy: ERC721Proxy as ContractArtifact, | ||||
|     MultiAssetProxy: MultiAssetProxy as ContractArtifact, | ||||
|     StaticCallProxy: StaticCallProxy as ContractArtifact, | ||||
|     ChaiBridge: ChaiBridge as ContractArtifact, | ||||
|     CurveBridge: CurveBridge as ContractArtifact, | ||||
|     DydxBridge: DydxBridge as ContractArtifact, | ||||
|     Eth2DaiBridge: Eth2DaiBridge as ContractArtifact, | ||||
|     KyberBridge: KyberBridge as ContractArtifact, | ||||
|     UniswapBridge: UniswapBridge as ContractArtifact, | ||||
|     IAssetData: IAssetData as ContractArtifact, | ||||
|     IAssetProxy: IAssetProxy as ContractArtifact, | ||||
|     IAssetProxyDispatcher: IAssetProxyDispatcher as ContractArtifact, | ||||
|     IAuthorizable: IAuthorizable as ContractArtifact, | ||||
|     IChai: IChai as ContractArtifact, | ||||
|     ICurve: ICurve as ContractArtifact, | ||||
|     IDydx: IDydx as ContractArtifact, | ||||
|     IDydxBridge: IDydxBridge as ContractArtifact, | ||||
|     IERC20Bridge: IERC20Bridge as ContractArtifact, | ||||
|     IEth2Dai: IEth2Dai as ContractArtifact, | ||||
|     IKyberNetworkProxy: IKyberNetworkProxy as ContractArtifact, | ||||
|     IUniswapExchange: IUniswapExchange as ContractArtifact, | ||||
|     IUniswapExchangeFactory: IUniswapExchangeFactory as ContractArtifact, | ||||
|     TestChaiBridge: TestChaiBridge as ContractArtifact, | ||||
|     TestDydxBridge: TestDydxBridge as ContractArtifact, | ||||
|     TestERC20Bridge: TestERC20Bridge as ContractArtifact, | ||||
|     TestEth2DaiBridge: TestEth2DaiBridge as ContractArtifact, | ||||
|     TestKyberBridge: TestKyberBridge as ContractArtifact, | ||||
|     TestStaticCallTarget: TestStaticCallTarget as ContractArtifact, | ||||
|     TestUniswapBridge: TestUniswapBridge as ContractArtifact, | ||||
| }; | ||||
| @@ -1,128 +0,0 @@ | ||||
| import { blockchainTests, expect, provider, txDefaults, web3Wrapper } from '@0x/contracts-test-utils'; | ||||
| import { RevertReason } from '@0x/types'; | ||||
| import { BigNumber } from '@0x/utils'; | ||||
|  | ||||
| import { artifacts } from './artifacts'; | ||||
|  | ||||
| import { MixinAuthorizableContract } from './wrappers'; | ||||
|  | ||||
| blockchainTests.resets('Authorizable', () => { | ||||
|     let owner: string; | ||||
|     let notOwner: string; | ||||
|     let address: string; | ||||
|     let authorizable: MixinAuthorizableContract; | ||||
|  | ||||
|     before(async () => { | ||||
|         const accounts = await web3Wrapper.getAvailableAddressesAsync(); | ||||
|         [owner, address, notOwner] = accounts.slice(0, 3); | ||||
|         authorizable = await MixinAuthorizableContract.deployFrom0xArtifactAsync( | ||||
|             artifacts.MixinAuthorizable, | ||||
|             provider, | ||||
|             txDefaults, | ||||
|             artifacts, | ||||
|         ); | ||||
|     }); | ||||
|  | ||||
|     describe('addAuthorizedAddress', () => { | ||||
|         it('should revert if not called by owner', async () => { | ||||
|             const tx = authorizable.addAuthorizedAddress(notOwner).sendTransactionAsync({ from: notOwner }); | ||||
|             return expect(tx).to.revertWith(RevertReason.OnlyContractOwner); | ||||
|         }); | ||||
|  | ||||
|         it('should allow owner to add an authorized address', async () => { | ||||
|             await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner }); | ||||
|             const isAuthorized = await authorizable.authorized(address).callAsync(); | ||||
|             expect(isAuthorized).to.be.true(); | ||||
|         }); | ||||
|  | ||||
|         it('should revert if owner attempts to authorize a duplicate address', async () => { | ||||
|             await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner }); | ||||
|             const tx = authorizable.addAuthorizedAddress(address).sendTransactionAsync({ from: owner }); | ||||
|             return expect(tx).to.revertWith(RevertReason.TargetAlreadyAuthorized); | ||||
|         }); | ||||
|     }); | ||||
|  | ||||
|     describe('removeAuthorizedAddress', () => { | ||||
|         it('should revert if not called by owner', async () => { | ||||
|             await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner }); | ||||
|             const tx = authorizable.removeAuthorizedAddress(address).sendTransactionAsync({ from: notOwner }); | ||||
|             return expect(tx).to.revertWith(RevertReason.OnlyContractOwner); | ||||
|         }); | ||||
|  | ||||
|         it('should allow owner to remove an authorized address', async () => { | ||||
|             await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner }); | ||||
|             await authorizable.removeAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner }); | ||||
|             const isAuthorized = await authorizable.authorized(address).callAsync(); | ||||
|             expect(isAuthorized).to.be.false(); | ||||
|         }); | ||||
|  | ||||
|         it('should revert if owner attempts to remove an address that is not authorized', async () => { | ||||
|             const tx = authorizable.removeAuthorizedAddress(address).sendTransactionAsync({ from: owner }); | ||||
|             return expect(tx).to.revertWith(RevertReason.TargetNotAuthorized); | ||||
|         }); | ||||
|     }); | ||||
|  | ||||
|     describe('removeAuthorizedAddressAtIndex', () => { | ||||
|         it('should revert if not called by owner', async () => { | ||||
|             await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner }); | ||||
|             const index = new BigNumber(0); | ||||
|             const tx = authorizable | ||||
|                 .removeAuthorizedAddressAtIndex(address, index) | ||||
|                 .sendTransactionAsync({ from: notOwner }); | ||||
|             return expect(tx).to.revertWith(RevertReason.OnlyContractOwner); | ||||
|         }); | ||||
|  | ||||
|         it('should revert if index is >= authorities.length', async () => { | ||||
|             await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner }); | ||||
|             const index = new BigNumber(1); | ||||
|             const tx = authorizable | ||||
|                 .removeAuthorizedAddressAtIndex(address, index) | ||||
|                 .sendTransactionAsync({ from: owner }); | ||||
|             return expect(tx).to.revertWith(RevertReason.IndexOutOfBounds); | ||||
|         }); | ||||
|  | ||||
|         it('should revert if owner attempts to remove an address that is not authorized', async () => { | ||||
|             const index = new BigNumber(0); | ||||
|             const tx = authorizable | ||||
|                 .removeAuthorizedAddressAtIndex(address, index) | ||||
|                 .sendTransactionAsync({ from: owner }); | ||||
|             return expect(tx).to.revertWith(RevertReason.TargetNotAuthorized); | ||||
|         }); | ||||
|  | ||||
|         it('should revert if address at index does not match target', async () => { | ||||
|             const address1 = address; | ||||
|             const address2 = notOwner; | ||||
|             await authorizable.addAuthorizedAddress(address1).awaitTransactionSuccessAsync({ from: owner }); | ||||
|             await authorizable.addAuthorizedAddress(address2).awaitTransactionSuccessAsync({ from: owner }); | ||||
|             const address1Index = new BigNumber(0); | ||||
|             const tx = authorizable | ||||
|                 .removeAuthorizedAddressAtIndex(address2, address1Index) | ||||
|                 .sendTransactionAsync({ from: owner }); | ||||
|             return expect(tx).to.revertWith(RevertReason.AuthorizedAddressMismatch); | ||||
|         }); | ||||
|  | ||||
|         it('should allow owner to remove an authorized address', async () => { | ||||
|             await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner }); | ||||
|             const index = new BigNumber(0); | ||||
|             await authorizable.removeAuthorizedAddressAtIndex(address, index).awaitTransactionSuccessAsync({ | ||||
|                 from: owner, | ||||
|             }); | ||||
|             const isAuthorized = await authorizable.authorized(address).callAsync(); | ||||
|             expect(isAuthorized).to.be.false(); | ||||
|         }); | ||||
|     }); | ||||
|  | ||||
|     describe('getAuthorizedAddresses', () => { | ||||
|         it('should return all authorized addresses', async () => { | ||||
|             const initial = await authorizable.getAuthorizedAddresses().callAsync(); | ||||
|             expect(initial).to.have.length(0); | ||||
|             await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner }); | ||||
|             const afterAdd = await authorizable.getAuthorizedAddresses().callAsync(); | ||||
|             expect(afterAdd).to.have.length(1); | ||||
|             expect(afterAdd).to.include(address); | ||||
|             await authorizable.removeAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner }); | ||||
|             const afterRemove = await authorizable.getAuthorizedAddresses().callAsync(); | ||||
|             expect(afterRemove).to.have.length(0); | ||||
|         }); | ||||
|     }); | ||||
| }); | ||||
| @@ -1,60 +0,0 @@ | ||||
| import { ERC20TokenContract } from '@0x/contracts-erc20'; | ||||
| import { blockchainTests, constants, expect, randomAddress } from '@0x/contracts-test-utils'; | ||||
| import { AssetProxyId, RevertReason } from '@0x/types'; | ||||
| import { BigNumber } from '@0x/utils'; | ||||
|  | ||||
| import { artifacts } from './artifacts'; | ||||
| import { TestChaiBridgeContract } from './wrappers'; | ||||
|  | ||||
| blockchainTests.resets('ChaiBridge unit tests', env => { | ||||
|     let chaiBridgeContract: TestChaiBridgeContract; | ||||
|     let testDaiContract: ERC20TokenContract; | ||||
|     let fromAddress: string; | ||||
|     let toAddress: string; | ||||
|  | ||||
|     const alwaysRevertAddress = '0x0000000000000000000000000000000000000001'; | ||||
|     const amount = new BigNumber(1); | ||||
|  | ||||
|     before(async () => { | ||||
|         [fromAddress, toAddress] = await env.getAccountAddressesAsync(); | ||||
|         chaiBridgeContract = await TestChaiBridgeContract.deployFrom0xArtifactAsync( | ||||
|             artifacts.TestChaiBridge, | ||||
|             env.provider, | ||||
|             env.txDefaults, | ||||
|             artifacts, | ||||
|         ); | ||||
|         const testChaiDaiAddress = await chaiBridgeContract.testChaiDai().callAsync(); | ||||
|         testDaiContract = new ERC20TokenContract(testChaiDaiAddress, env.provider, env.txDefaults); | ||||
|     }); | ||||
|  | ||||
|     describe('bridgeTransferFrom()', () => { | ||||
|         it('fails if not called by ERC20BridgeProxy', async () => { | ||||
|             return expect( | ||||
|                 chaiBridgeContract | ||||
|                     .bridgeTransferFrom(randomAddress(), fromAddress, toAddress, amount, constants.NULL_BYTES) | ||||
|                     .awaitTransactionSuccessAsync({ from: alwaysRevertAddress }), | ||||
|             ).to.revertWith(RevertReason.ChaiBridgeOnlyCallableByErc20BridgeProxy); | ||||
|         }); | ||||
|         it('returns magic bytes upon success', async () => { | ||||
|             const magicBytes = await chaiBridgeContract | ||||
|                 .bridgeTransferFrom(randomAddress(), fromAddress, toAddress, amount, constants.NULL_BYTES) | ||||
|                 .callAsync(); | ||||
|             expect(magicBytes).to.eq(AssetProxyId.ERC20Bridge); | ||||
|         }); | ||||
|         it('should increase the Dai balance of `toAddress` by `amount` if successful', async () => { | ||||
|             const initialBalance = await testDaiContract.balanceOf(toAddress).callAsync(); | ||||
|             await chaiBridgeContract | ||||
|                 .bridgeTransferFrom(randomAddress(), fromAddress, toAddress, amount, constants.NULL_BYTES) | ||||
|                 .awaitTransactionSuccessAsync(); | ||||
|             const endBalance = await testDaiContract.balanceOf(toAddress).callAsync(); | ||||
|             expect(endBalance).to.bignumber.eq(initialBalance.plus(amount)); | ||||
|         }); | ||||
|         it('fails if the `chai.draw` call fails', async () => { | ||||
|             return expect( | ||||
|                 chaiBridgeContract | ||||
|                     .bridgeTransferFrom(randomAddress(), alwaysRevertAddress, toAddress, amount, constants.NULL_BYTES) | ||||
|                     .awaitTransactionSuccessAsync(), | ||||
|             ).to.revertWith(RevertReason.ChaiBridgeDrawDaiFailed); | ||||
|         }); | ||||
|     }); | ||||
| }); | ||||
| @@ -1,399 +0,0 @@ | ||||
| import { LibMathRevertErrors } from '@0x/contracts-exchange-libs'; | ||||
| import { blockchainTests, constants, expect, verifyEventsFromLogs } from '@0x/contracts-test-utils'; | ||||
| import { AssetProxyId, RevertReason } from '@0x/types'; | ||||
| import { BigNumber } from '@0x/utils'; | ||||
| import * as _ from 'lodash'; | ||||
|  | ||||
| import { DydxBridgeActionType, DydxBridgeData, dydxBridgeDataEncoder } from '../src/dydx_bridge_encoder'; | ||||
| import { ERC20BridgeProxyContract, IAssetDataContract } from '../src/wrappers'; | ||||
|  | ||||
| import { artifacts } from './artifacts'; | ||||
| import { TestDydxBridgeContract, TestDydxBridgeEvents } from './wrappers'; | ||||
|  | ||||
| blockchainTests.resets('DydxBridge unit tests', env => { | ||||
|     const defaultAccountNumber = new BigNumber(1); | ||||
|     const marketId = new BigNumber(2); | ||||
|     const defaultAmount = new BigNumber(4); | ||||
|     const notAuthorized = '0x0000000000000000000000000000000000000001'; | ||||
|     const defaultDepositAction = { | ||||
|         actionType: DydxBridgeActionType.Deposit, | ||||
|         accountIdx: constants.ZERO_AMOUNT, | ||||
|         marketId, | ||||
|         conversionRateNumerator: constants.ZERO_AMOUNT, | ||||
|         conversionRateDenominator: constants.ZERO_AMOUNT, | ||||
|     }; | ||||
|     const defaultWithdrawAction = { | ||||
|         actionType: DydxBridgeActionType.Withdraw, | ||||
|         accountIdx: constants.ZERO_AMOUNT, | ||||
|         marketId, | ||||
|         conversionRateNumerator: constants.ZERO_AMOUNT, | ||||
|         conversionRateDenominator: constants.ZERO_AMOUNT, | ||||
|     }; | ||||
|     let testContract: TestDydxBridgeContract; | ||||
|     let testProxyContract: ERC20BridgeProxyContract; | ||||
|     let assetDataEncoder: IAssetDataContract; | ||||
|     let owner: string; | ||||
|     let authorized: string; | ||||
|     let accountOwner: string; | ||||
|     let receiver: string; | ||||
|  | ||||
|     before(async () => { | ||||
|         // Get accounts | ||||
|         const accounts = await env.web3Wrapper.getAvailableAddressesAsync(); | ||||
|         [owner, authorized, accountOwner, receiver] = accounts; | ||||
|  | ||||
|         // Deploy dydx bridge | ||||
|         testContract = await TestDydxBridgeContract.deployFrom0xArtifactAsync( | ||||
|             artifacts.TestDydxBridge, | ||||
|             env.provider, | ||||
|             env.txDefaults, | ||||
|             artifacts, | ||||
|             [accountOwner, receiver], | ||||
|         ); | ||||
|  | ||||
|         // Deploy test erc20 bridge proxy | ||||
|         testProxyContract = await ERC20BridgeProxyContract.deployFrom0xArtifactAsync( | ||||
|             artifacts.ERC20BridgeProxy, | ||||
|             env.provider, | ||||
|             env.txDefaults, | ||||
|             artifacts, | ||||
|         ); | ||||
|         await testProxyContract.addAuthorizedAddress(authorized).awaitTransactionSuccessAsync({ from: owner }); | ||||
|  | ||||
|         // Setup asset data encoder | ||||
|         assetDataEncoder = new IAssetDataContract(constants.NULL_ADDRESS, env.provider); | ||||
|     }); | ||||
|  | ||||
|     describe('bridgeTransferFrom()', () => { | ||||
|         const callBridgeTransferFrom = async ( | ||||
|             from: string, | ||||
|             to: string, | ||||
|             amount: BigNumber, | ||||
|             bridgeData: DydxBridgeData, | ||||
|             sender: string, | ||||
|         ): Promise<string> => { | ||||
|             const returnValue = await testContract | ||||
|                 .bridgeTransferFrom( | ||||
|                     constants.NULL_ADDRESS, | ||||
|                     from, | ||||
|                     to, | ||||
|                     amount, | ||||
|                     dydxBridgeDataEncoder.encode({ bridgeData }), | ||||
|                 ) | ||||
|                 .callAsync({ from: sender }); | ||||
|             return returnValue; | ||||
|         }; | ||||
|         const executeBridgeTransferFromAndVerifyEvents = async ( | ||||
|             from: string, | ||||
|             to: string, | ||||
|             amount: BigNumber, | ||||
|             bridgeData: DydxBridgeData, | ||||
|             sender: string, | ||||
|         ): Promise<void> => { | ||||
|             // Execute transaction. | ||||
|             const txReceipt = await testContract | ||||
|                 .bridgeTransferFrom( | ||||
|                     constants.NULL_ADDRESS, | ||||
|                     from, | ||||
|                     to, | ||||
|                     amount, | ||||
|                     dydxBridgeDataEncoder.encode({ bridgeData }), | ||||
|                 ) | ||||
|                 .awaitTransactionSuccessAsync({ from: sender }); | ||||
|  | ||||
|             // Verify `OperateAccount` event. | ||||
|             const expectedOperateAccountEvents = []; | ||||
|             for (const accountNumber of bridgeData.accountNumbers) { | ||||
|                 expectedOperateAccountEvents.push({ | ||||
|                     owner: accountOwner, | ||||
|                     number: accountNumber, | ||||
|                 }); | ||||
|             } | ||||
|             verifyEventsFromLogs(txReceipt.logs, expectedOperateAccountEvents, TestDydxBridgeEvents.OperateAccount); | ||||
|  | ||||
|             // Verify `OperateAction` event. | ||||
|             const weiDenomination = 0; | ||||
|             const deltaAmountRef = 0; | ||||
|             const expectedOperateActionEvents = []; | ||||
|             for (const action of bridgeData.actions) { | ||||
|                 expectedOperateActionEvents.push({ | ||||
|                     actionType: action.actionType as number, | ||||
|                     accountIdx: action.accountIdx, | ||||
|                     amountSign: action.actionType === DydxBridgeActionType.Deposit ? true : false, | ||||
|                     amountDenomination: weiDenomination, | ||||
|                     amountRef: deltaAmountRef, | ||||
|                     amountValue: action.conversionRateDenominator.gt(0) | ||||
|                         ? amount | ||||
|                               .times(action.conversionRateNumerator) | ||||
|                               .dividedToIntegerBy(action.conversionRateDenominator) | ||||
|                         : amount, | ||||
|                     primaryMarketId: marketId, | ||||
|                     secondaryMarketId: constants.ZERO_AMOUNT, | ||||
|                     otherAddress: action.actionType === DydxBridgeActionType.Deposit ? from : to, | ||||
|                     otherAccountId: constants.ZERO_AMOUNT, | ||||
|                     data: '0x', | ||||
|                 }); | ||||
|             } | ||||
|             verifyEventsFromLogs(txReceipt.logs, expectedOperateActionEvents, TestDydxBridgeEvents.OperateAction); | ||||
|         }; | ||||
|         it('succeeds when calling with zero amount', async () => { | ||||
|             const bridgeData = { | ||||
|                 accountNumbers: [defaultAccountNumber], | ||||
|                 actions: [defaultDepositAction], | ||||
|             }; | ||||
|             await executeBridgeTransferFromAndVerifyEvents( | ||||
|                 accountOwner, | ||||
|                 receiver, | ||||
|                 constants.ZERO_AMOUNT, | ||||
|                 bridgeData, | ||||
|                 authorized, | ||||
|             ); | ||||
|         }); | ||||
|         it('succeeds when calling with no accounts', async () => { | ||||
|             const bridgeData = { | ||||
|                 accountNumbers: [], | ||||
|                 actions: [defaultDepositAction], | ||||
|             }; | ||||
|             await executeBridgeTransferFromAndVerifyEvents( | ||||
|                 accountOwner, | ||||
|                 receiver, | ||||
|                 defaultAmount, | ||||
|                 bridgeData, | ||||
|                 authorized, | ||||
|             ); | ||||
|         }); | ||||
|         it('succeeds when calling with no actions', async () => { | ||||
|             const bridgeData = { | ||||
|                 accountNumbers: [defaultAccountNumber], | ||||
|                 actions: [], | ||||
|             }; | ||||
|             await executeBridgeTransferFromAndVerifyEvents( | ||||
|                 accountOwner, | ||||
|                 receiver, | ||||
|                 defaultAmount, | ||||
|                 bridgeData, | ||||
|                 authorized, | ||||
|             ); | ||||
|         }); | ||||
|         it('succeeds when calling `operate` with the `deposit` action and a single account', async () => { | ||||
|             const bridgeData = { | ||||
|                 accountNumbers: [defaultAccountNumber], | ||||
|                 actions: [defaultDepositAction], | ||||
|             }; | ||||
|             await executeBridgeTransferFromAndVerifyEvents( | ||||
|                 accountOwner, | ||||
|                 receiver, | ||||
|                 defaultAmount, | ||||
|                 bridgeData, | ||||
|                 authorized, | ||||
|             ); | ||||
|         }); | ||||
|         it('succeeds when calling `operate` with the `deposit` action and multiple accounts', async () => { | ||||
|             const bridgeData = { | ||||
|                 accountNumbers: [defaultAccountNumber, defaultAccountNumber.plus(1)], | ||||
|                 actions: [defaultDepositAction], | ||||
|             }; | ||||
|             await executeBridgeTransferFromAndVerifyEvents( | ||||
|                 accountOwner, | ||||
|                 receiver, | ||||
|                 defaultAmount, | ||||
|                 bridgeData, | ||||
|                 authorized, | ||||
|             ); | ||||
|         }); | ||||
|         it('succeeds when calling `operate` with the `withdraw` action and a single account', async () => { | ||||
|             const bridgeData = { | ||||
|                 accountNumbers: [defaultAccountNumber], | ||||
|                 actions: [defaultWithdrawAction], | ||||
|             }; | ||||
|             await executeBridgeTransferFromAndVerifyEvents( | ||||
|                 accountOwner, | ||||
|                 receiver, | ||||
|                 defaultAmount, | ||||
|                 bridgeData, | ||||
|                 authorized, | ||||
|             ); | ||||
|         }); | ||||
|         it('succeeds when calling `operate` with the `withdraw` action and multiple accounts', async () => { | ||||
|             const bridgeData = { | ||||
|                 accountNumbers: [defaultAccountNumber, defaultAccountNumber.plus(1)], | ||||
|                 actions: [defaultWithdrawAction], | ||||
|             }; | ||||
|             await executeBridgeTransferFromAndVerifyEvents( | ||||
|                 accountOwner, | ||||
|                 receiver, | ||||
|                 defaultAmount, | ||||
|                 bridgeData, | ||||
|                 authorized, | ||||
|             ); | ||||
|         }); | ||||
|         it('succeeds when calling `operate` with the `deposit` action and multiple accounts', async () => { | ||||
|             const bridgeData = { | ||||
|                 accountNumbers: [defaultAccountNumber, defaultAccountNumber.plus(1)], | ||||
|                 actions: [defaultWithdrawAction, defaultDepositAction], | ||||
|             }; | ||||
|             await executeBridgeTransferFromAndVerifyEvents( | ||||
|                 accountOwner, | ||||
|                 receiver, | ||||
|                 defaultAmount, | ||||
|                 bridgeData, | ||||
|                 authorized, | ||||
|             ); | ||||
|         }); | ||||
|         it('succeeds when calling `operate` with multiple actions under a single account', async () => { | ||||
|             const bridgeData = { | ||||
|                 accountNumbers: [defaultAccountNumber], | ||||
|                 actions: [defaultWithdrawAction, defaultDepositAction], | ||||
|             }; | ||||
|             await executeBridgeTransferFromAndVerifyEvents( | ||||
|                 accountOwner, | ||||
|                 receiver, | ||||
|                 defaultAmount, | ||||
|                 bridgeData, | ||||
|                 authorized, | ||||
|             ); | ||||
|         }); | ||||
|         it('succeeds when scaling the `amount` to deposit', async () => { | ||||
|             const conversionRateNumerator = new BigNumber(1); | ||||
|             const conversionRateDenominator = new BigNumber(2); | ||||
|             const bridgeData = { | ||||
|                 accountNumbers: [defaultAccountNumber], | ||||
|                 actions: [ | ||||
|                     defaultWithdrawAction, | ||||
|                     { | ||||
|                         ...defaultDepositAction, | ||||
|                         conversionRateNumerator, | ||||
|                         conversionRateDenominator, | ||||
|                     }, | ||||
|                 ], | ||||
|             }; | ||||
|             await executeBridgeTransferFromAndVerifyEvents( | ||||
|                 accountOwner, | ||||
|                 receiver, | ||||
|                 defaultAmount, | ||||
|                 bridgeData, | ||||
|                 authorized, | ||||
|             ); | ||||
|         }); | ||||
|         it('succeeds when scaling the `amount` to withdraw', async () => { | ||||
|             const conversionRateNumerator = new BigNumber(1); | ||||
|             const conversionRateDenominator = new BigNumber(2); | ||||
|             const bridgeData = { | ||||
|                 accountNumbers: [defaultAccountNumber], | ||||
|                 actions: [ | ||||
|                     defaultDepositAction, | ||||
|                     { | ||||
|                         ...defaultWithdrawAction, | ||||
|                         conversionRateNumerator, | ||||
|                         conversionRateDenominator, | ||||
|                     }, | ||||
|                 ], | ||||
|             }; | ||||
|             await executeBridgeTransferFromAndVerifyEvents( | ||||
|                 accountOwner, | ||||
|                 receiver, | ||||
|                 defaultAmount, | ||||
|                 bridgeData, | ||||
|                 authorized, | ||||
|             ); | ||||
|         }); | ||||
|         it('reverts if not called by the ERC20 Bridge Proxy', async () => { | ||||
|             const bridgeData = { | ||||
|                 accountNumbers: [defaultAccountNumber], | ||||
|                 actions: [defaultDepositAction], | ||||
|             }; | ||||
|             const callBridgeTransferFromPromise = callBridgeTransferFrom( | ||||
|                 accountOwner, | ||||
|                 receiver, | ||||
|                 defaultAmount, | ||||
|                 bridgeData, | ||||
|                 notAuthorized, | ||||
|             ); | ||||
|             const expectedError = RevertReason.DydxBridgeOnlyCallableByErc20BridgeProxy; | ||||
|             return expect(callBridgeTransferFromPromise).to.revertWith(expectedError); | ||||
|         }); | ||||
|         it('should return magic bytes if call succeeds', async () => { | ||||
|             const bridgeData = { | ||||
|                 accountNumbers: [defaultAccountNumber], | ||||
|                 actions: [defaultDepositAction], | ||||
|             }; | ||||
|             const returnValue = await callBridgeTransferFrom( | ||||
|                 accountOwner, | ||||
|                 receiver, | ||||
|                 defaultAmount, | ||||
|                 bridgeData, | ||||
|                 authorized, | ||||
|             ); | ||||
|             expect(returnValue).to.equal(AssetProxyId.ERC20Bridge); | ||||
|         }); | ||||
|         it('should revert when `Operate` reverts', async () => { | ||||
|             // Set revert flag. | ||||
|             await testContract.setRevertOnOperate(true).awaitTransactionSuccessAsync(); | ||||
|  | ||||
|             // Execute transfer. | ||||
|             const bridgeData = { | ||||
|                 accountNumbers: [defaultAccountNumber], | ||||
|                 actions: [defaultDepositAction], | ||||
|             }; | ||||
|             const tx = callBridgeTransferFrom(accountOwner, receiver, defaultAmount, bridgeData, authorized); | ||||
|             const expectedError = 'TestDydxBridge/SHOULD_REVERT_ON_OPERATE'; | ||||
|             return expect(tx).to.revertWith(expectedError); | ||||
|         }); | ||||
|         it('should revert when there is a rounding error', async () => { | ||||
|             // Setup a rounding error | ||||
|             const conversionRateNumerator = new BigNumber(5318); | ||||
|             const conversionRateDenominator = new BigNumber(47958); | ||||
|             const amount = new BigNumber(9000); | ||||
|             const bridgeData = { | ||||
|                 accountNumbers: [defaultAccountNumber], | ||||
|                 actions: [ | ||||
|                     defaultDepositAction, | ||||
|                     { | ||||
|                         ...defaultWithdrawAction, | ||||
|                         conversionRateNumerator, | ||||
|                         conversionRateDenominator, | ||||
|                     }, | ||||
|                 ], | ||||
|             }; | ||||
|  | ||||
|             // Execute transfer and assert error. | ||||
|             const tx = callBridgeTransferFrom(accountOwner, receiver, amount, bridgeData, authorized); | ||||
|             const expectedError = new LibMathRevertErrors.RoundingError( | ||||
|                 conversionRateNumerator, | ||||
|                 conversionRateDenominator, | ||||
|                 amount, | ||||
|             ); | ||||
|             return expect(tx).to.revertWith(expectedError); | ||||
|         }); | ||||
|     }); | ||||
|  | ||||
|     describe('ERC20BridgeProxy.transferFrom()', () => { | ||||
|         const bridgeData = { | ||||
|             accountNumbers: [defaultAccountNumber], | ||||
|             actions: [defaultWithdrawAction], | ||||
|         }; | ||||
|         let assetData: string; | ||||
|  | ||||
|         before(async () => { | ||||
|             const testTokenAddress = await testContract.getTestToken().callAsync(); | ||||
|             assetData = assetDataEncoder | ||||
|                 .ERC20Bridge(testTokenAddress, testContract.address, dydxBridgeDataEncoder.encode({ bridgeData })) | ||||
|                 .getABIEncodedTransactionData(); | ||||
|         }); | ||||
|  | ||||
|         it('should succeed if `bridgeTransferFrom` succeeds', async () => { | ||||
|             await testProxyContract | ||||
|                 .transferFrom(assetData, accountOwner, receiver, defaultAmount) | ||||
|                 .awaitTransactionSuccessAsync({ from: authorized }); | ||||
|         }); | ||||
|         it('should revert if `bridgeTransferFrom` reverts', async () => { | ||||
|             // Set revert flag. | ||||
|             await testContract.setRevertOnOperate(true).awaitTransactionSuccessAsync(); | ||||
|             const tx = testProxyContract | ||||
|                 .transferFrom(assetData, accountOwner, receiver, defaultAmount) | ||||
|                 .awaitTransactionSuccessAsync({ from: authorized }); | ||||
|             const expectedError = 'TestDydxBridge/SHOULD_REVERT_ON_OPERATE'; | ||||
|             return expect(tx).to.revertWith(expectedError); | ||||
|         }); | ||||
|     }); | ||||
| }); | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,287 +0,0 @@ | ||||
| import { | ||||
|     blockchainTests, | ||||
|     constants, | ||||
|     expect, | ||||
|     getRandomInteger, | ||||
|     Numberish, | ||||
|     randomAddress, | ||||
| } from '@0x/contracts-test-utils'; | ||||
| import { AuthorizableRevertErrors } from '@0x/contracts-utils'; | ||||
| import { AssetProxyId } from '@0x/types'; | ||||
| import { AbiEncoder, BigNumber, hexUtils, StringRevertError } from '@0x/utils'; | ||||
| import { DecodedLogs } from 'ethereum-types'; | ||||
| import * as _ from 'lodash'; | ||||
|  | ||||
| import { artifacts } from './artifacts'; | ||||
|  | ||||
| import { ERC20BridgeProxyContract, TestERC20BridgeContract } from './wrappers'; | ||||
|  | ||||
| blockchainTests.resets('ERC20BridgeProxy unit tests', env => { | ||||
|     const PROXY_ID = AssetProxyId.ERC20Bridge; | ||||
|     const BRIDGE_SUCCESS_RETURN_DATA = hexUtils.rightPad(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(owner).awaitTransactionSuccessAsync(); | ||||
|     }); | ||||
|  | ||||
|     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(_owner, new BigNumber(balance)).awaitTransactionSuccessAsync(); | ||||
|     } | ||||
|  | ||||
|     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(encodeAssetData(_opts.assetData), _opts.from, _opts.to, new BigNumber(_opts.amount)) | ||||
|                 .awaitTransactionSuccessAsync({ 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; | ||||
|             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 = hexUtils.slice(encodeAssetData(opts.assetData), 0, -1); | ||||
|             const tx = assetProxy | ||||
|                 .transferFrom(truncatedAssetData, opts.from, opts.to, new BigNumber(opts.amount)) | ||||
|                 .awaitTransactionSuccessAsync(); | ||||
|             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: hexUtils.leftPad('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: hexUtils.rightPad('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(_owner, balance).awaitTransactionSuccessAsync(); | ||||
|             const assetData = createAssetData({ | ||||
|                 tokenAddress: testTokenAddress, | ||||
|             }); | ||||
|             const actualBalance = await assetProxy.balanceOf(encodeAssetData(assetData), _owner).callAsync(); | ||||
|             expect(actualBalance).to.bignumber.eq(balance); | ||||
|         }); | ||||
|     }); | ||||
|  | ||||
|     describe('getProxyId()', () => { | ||||
|         it('returns the correct proxy ID', async () => { | ||||
|             const proxyId = await assetProxy.getProxyId().callAsync(); | ||||
|             expect(proxyId).to.eq(PROXY_ID); | ||||
|         }); | ||||
|     }); | ||||
| }); | ||||
| @@ -1,191 +0,0 @@ | ||||
| import { | ||||
|     blockchainTests, | ||||
|     constants, | ||||
|     expect, | ||||
|     filterLogsToArguments, | ||||
|     getRandomInteger, | ||||
|     Numberish, | ||||
|     randomAddress, | ||||
| } from '@0x/contracts-test-utils'; | ||||
| import { AssetProxyId } from '@0x/types'; | ||||
| import { BigNumber, hexUtils, RawRevertError } from '@0x/utils'; | ||||
| import { DecodedLogs } from 'ethereum-types'; | ||||
| import * as _ from 'lodash'; | ||||
|  | ||||
| import { artifacts } from './artifacts'; | ||||
|  | ||||
| import { | ||||
|     TestEth2DaiBridgeContract, | ||||
|     TestEth2DaiBridgeEvents, | ||||
|     TestEth2DaiBridgeSellAllAmountEventArgs, | ||||
|     TestEth2DaiBridgeTokenApproveEventArgs, | ||||
|     TestEth2DaiBridgeTokenTransferEventArgs, | ||||
| } from './wrappers'; | ||||
|  | ||||
| blockchainTests.resets('Eth2DaiBridge unit tests', env => { | ||||
|     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(hexUtils.random(), hexUtils.random(_.random(0, 32))) | ||||
|                 .callAsync(); | ||||
|             expect(result).to.eq(LEGACY_WALLET_MAGIC_VALUE); | ||||
|         }); | ||||
|     }); | ||||
|  | ||||
|     describe('bridgeTransferFrom()', () => { | ||||
|         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: hexUtils.leftPad(1), | ||||
|                 ...opts, | ||||
|             }; | ||||
|         } | ||||
|  | ||||
|         async function withdrawToAsync(opts?: Partial<WithdrawToOpts>): Promise<WithdrawToResult> { | ||||
|             const _opts = createWithdrawToOpts(opts); | ||||
|             // Set the fill behavior. | ||||
|             await testContract | ||||
|                 .setFillBehavior(_opts.revertReason, new BigNumber(_opts.fillAmount)) | ||||
|                 .awaitTransactionSuccessAsync(); | ||||
|             // Create tokens and balances. | ||||
|             if (_opts.fromTokenAddress === undefined) { | ||||
|                 const createTokenFn = testContract.createToken(new BigNumber(_opts.fromTokenBalance)); | ||||
|                 _opts.fromTokenAddress = await createTokenFn.callAsync(); | ||||
|                 await createTokenFn.awaitTransactionSuccessAsync(); | ||||
|             } | ||||
|             if (_opts.toTokenAddress === undefined) { | ||||
|                 const createTokenFn = testContract.createToken(constants.ZERO_AMOUNT); | ||||
|                 _opts.toTokenAddress = await createTokenFn.callAsync(); | ||||
|                 await createTokenFn.awaitTransactionSuccessAsync(); | ||||
|             } | ||||
|             // Set the transfer behavior of `toTokenAddress`. | ||||
|             await testContract | ||||
|                 .setTransferBehavior( | ||||
|                     _opts.toTokenAddress, | ||||
|                     _opts.toTokentransferRevertReason, | ||||
|                     _opts.toTokenTransferReturnData, | ||||
|                 ) | ||||
|                 .awaitTransactionSuccessAsync(); | ||||
|             // Call bridgeTransferFrom(). | ||||
|             const bridgeTransferFromFn = testContract.bridgeTransferFrom( | ||||
|                 // "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. | ||||
|                 hexUtils.leftPad(_opts.fromTokenAddress as string), | ||||
|             ); | ||||
|             const result = await bridgeTransferFromFn.callAsync(); | ||||
|             const { logs } = await bridgeTransferFromFn.awaitTransactionSuccessAsync(); | ||||
|             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 false', async () => { | ||||
|             const opts = createWithdrawToOpts({ toTokenTransferReturnData: hexUtils.leftPad(0) }); | ||||
|             const tx = withdrawToAsync(opts); | ||||
|             return expect(tx).to.revertWith(new RawRevertError(hexUtils.leftPad(0))); | ||||
|         }); | ||||
|  | ||||
|         it('succeeds if `toTokenAddress.transfer()` returns true', async () => { | ||||
|             await withdrawToAsync({ toTokenTransferReturnData: hexUtils.leftPad(1) }); | ||||
|         }); | ||||
|     }); | ||||
| }); | ||||
| @@ -1,19 +0,0 @@ | ||||
| import { env, EnvVars } from '@0x/dev-utils'; | ||||
|  | ||||
| import { coverage, profiler, provider } from '@0x/contracts-test-utils'; | ||||
| import { providerUtils } from '@0x/utils'; | ||||
|  | ||||
| before('start web3 provider', () => { | ||||
|     providerUtils.startProviderEngine(provider); | ||||
| }); | ||||
| after('generate coverage report', async () => { | ||||
|     if (env.parseBoolean(EnvVars.SolidityCoverage)) { | ||||
|         const coverageSubprovider = coverage.getCoverageSubproviderSingleton(); | ||||
|         await coverageSubprovider.writeCoverageAsync(); | ||||
|     } | ||||
|     if (env.parseBoolean(EnvVars.SolidityProfiler)) { | ||||
|         const profilerSubprovider = profiler.getProfilerSubproviderSingleton(); | ||||
|         await profilerSubprovider.writeProfilerOutputAsync(); | ||||
|     } | ||||
|     provider.stop(); | ||||
| }); | ||||
| @@ -1,283 +0,0 @@ | ||||
| import { | ||||
|     blockchainTests, | ||||
|     constants, | ||||
|     expect, | ||||
|     getRandomInteger, | ||||
|     getRandomPortion, | ||||
|     randomAddress, | ||||
|     verifyEventsFromLogs, | ||||
| } from '@0x/contracts-test-utils'; | ||||
| import { AssetProxyId } from '@0x/types'; | ||||
| import { BigNumber, hexUtils } from '@0x/utils'; | ||||
| import { DecodedLogs } from 'ethereum-types'; | ||||
| import * as _ from 'lodash'; | ||||
|  | ||||
| import { artifacts } from './artifacts'; | ||||
|  | ||||
| import { TestKyberBridgeContract, TestKyberBridgeEvents } from './wrappers'; | ||||
|  | ||||
| blockchainTests.resets('KyberBridge unit tests', env => { | ||||
|     const KYBER_ETH_ADDRESS = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee'; | ||||
|     const FROM_TOKEN_DECIMALS = 6; | ||||
|     const TO_TOKEN_DECIMALS = 18; | ||||
|     const FROM_TOKEN_BASE = new BigNumber(10).pow(FROM_TOKEN_DECIMALS); | ||||
|     const TO_TOKEN_BASE = new BigNumber(10).pow(TO_TOKEN_DECIMALS); | ||||
|     const WETH_BASE = new BigNumber(10).pow(18); | ||||
|     const KYBER_RATE_BASE = WETH_BASE; | ||||
|     let testContract: TestKyberBridgeContract; | ||||
|  | ||||
|     before(async () => { | ||||
|         testContract = await TestKyberBridgeContract.deployFrom0xArtifactAsync( | ||||
|             artifacts.TestKyberBridge, | ||||
|             env.provider, | ||||
|             env.txDefaults, | ||||
|             artifacts, | ||||
|         ); | ||||
|     }); | ||||
|  | ||||
|     describe('isValidSignature()', () => { | ||||
|         it('returns success bytes', async () => { | ||||
|             const LEGACY_WALLET_MAGIC_VALUE = '0xb0671381'; | ||||
|             const result = await testContract | ||||
|                 .isValidSignature(hexUtils.random(), hexUtils.random(_.random(0, 32))) | ||||
|                 .callAsync(); | ||||
|             expect(result).to.eq(LEGACY_WALLET_MAGIC_VALUE); | ||||
|         }); | ||||
|     }); | ||||
|  | ||||
|     describe('bridgeTransferFrom()', () => { | ||||
|         let fromTokenAddress: string; | ||||
|         let toTokenAddress: string; | ||||
|         let wethAddress: string; | ||||
|  | ||||
|         before(async () => { | ||||
|             wethAddress = await testContract.weth().callAsync(); | ||||
|             fromTokenAddress = await testContract.createToken(FROM_TOKEN_DECIMALS).callAsync(); | ||||
|             await testContract.createToken(FROM_TOKEN_DECIMALS).awaitTransactionSuccessAsync(); | ||||
|             toTokenAddress = await testContract.createToken(TO_TOKEN_DECIMALS).callAsync(); | ||||
|             await testContract.createToken(TO_TOKEN_DECIMALS).awaitTransactionSuccessAsync(); | ||||
|         }); | ||||
|  | ||||
|         const STATIC_KYBER_TRADE_ARGS = { | ||||
|             maxBuyTokenAmount: constants.MAX_UINT256, | ||||
|             walletId: constants.NULL_ADDRESS, | ||||
|         }; | ||||
|  | ||||
|         interface TransferFromOpts { | ||||
|             toTokenAddress: string; | ||||
|             fromTokenAddress: string; | ||||
|             toAddress: string; | ||||
|             // Amount to pass into `bridgeTransferFrom()` | ||||
|             amount: BigNumber; | ||||
|             // Amount to convert in `trade()`. | ||||
|             fillAmount: BigNumber; | ||||
|             // Token balance of the bridge. | ||||
|             fromTokenBalance: BigNumber; | ||||
|         } | ||||
|  | ||||
|         interface TransferFromResult { | ||||
|             opts: TransferFromOpts; | ||||
|             result: string; | ||||
|             logs: DecodedLogs; | ||||
|         } | ||||
|  | ||||
|         function createTransferFromOpts(opts?: Partial<TransferFromOpts>): TransferFromOpts { | ||||
|             const amount = getRandomInteger(1, TO_TOKEN_BASE.times(100)); | ||||
|             return { | ||||
|                 fromTokenAddress, | ||||
|                 toTokenAddress, | ||||
|                 amount, | ||||
|                 toAddress: randomAddress(), | ||||
|                 fillAmount: getRandomPortion(amount), | ||||
|                 fromTokenBalance: getRandomInteger(1, FROM_TOKEN_BASE.times(100)), | ||||
|                 ...opts, | ||||
|             }; | ||||
|         } | ||||
|  | ||||
|         async function withdrawToAsync(opts?: Partial<TransferFromOpts>): Promise<TransferFromResult> { | ||||
|             const _opts = createTransferFromOpts(opts); | ||||
|             // Fund the contract with input tokens. | ||||
|             await testContract | ||||
|                 .grantTokensTo(_opts.fromTokenAddress, testContract.address, _opts.fromTokenBalance) | ||||
|                 .awaitTransactionSuccessAsync({ value: _opts.fromTokenBalance }); | ||||
|             // Fund the contract with output tokens. | ||||
|             await testContract.setNextFillAmount(_opts.fillAmount).awaitTransactionSuccessAsync({ | ||||
|                 value: _opts.toTokenAddress === wethAddress ? _opts.fillAmount : constants.ZERO_AMOUNT, | ||||
|             }); | ||||
|             // Call bridgeTransferFrom(). | ||||
|             const bridgeTransferFromFn = testContract.bridgeTransferFrom( | ||||
|                 // Output token | ||||
|                 _opts.toTokenAddress, | ||||
|                 // Random maker address. | ||||
|                 randomAddress(), | ||||
|                 // Recipient address. | ||||
|                 _opts.toAddress, | ||||
|                 // Transfer amount. | ||||
|                 _opts.amount, | ||||
|                 // ABI-encode the input token address as the bridge data. | ||||
|                 hexUtils.leftPad(_opts.fromTokenAddress), | ||||
|             ); | ||||
|             const result = await bridgeTransferFromFn.callAsync(); | ||||
|             const { logs } = await bridgeTransferFromFn.awaitTransactionSuccessAsync(); | ||||
|             return { | ||||
|                 opts: _opts, | ||||
|                 result, | ||||
|                 logs: (logs as any) as DecodedLogs, | ||||
|             }; | ||||
|         } | ||||
|  | ||||
|         function getMinimumConversionRate(opts: TransferFromOpts): BigNumber { | ||||
|             const fromBase = opts.fromTokenAddress === wethAddress ? WETH_BASE : FROM_TOKEN_BASE; | ||||
|             const toBase = opts.toTokenAddress === wethAddress ? WETH_BASE : TO_TOKEN_BASE; | ||||
|             return opts.amount | ||||
|                 .div(toBase) | ||||
|                 .div(opts.fromTokenBalance.div(fromBase)) | ||||
|                 .times(KYBER_RATE_BASE) | ||||
|                 .integerValue(BigNumber.ROUND_DOWN); | ||||
|         } | ||||
|  | ||||
|         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('can trade token -> token', async () => { | ||||
|             const { opts, logs } = await withdrawToAsync(); | ||||
|             verifyEventsFromLogs( | ||||
|                 logs, | ||||
|                 [ | ||||
|                     { | ||||
|                         sellTokenAddress: opts.fromTokenAddress, | ||||
|                         buyTokenAddress: opts.toTokenAddress, | ||||
|                         sellAmount: opts.fromTokenBalance, | ||||
|                         recipientAddress: opts.toAddress, | ||||
|                         minConversionRate: getMinimumConversionRate(opts), | ||||
|                         msgValue: constants.ZERO_AMOUNT, | ||||
|                         ...STATIC_KYBER_TRADE_ARGS, | ||||
|                     }, | ||||
|                 ], | ||||
|                 TestKyberBridgeEvents.KyberBridgeTrade, | ||||
|             ); | ||||
|         }); | ||||
|  | ||||
|         it('can trade token -> ETH', async () => { | ||||
|             const { opts, logs } = await withdrawToAsync({ | ||||
|                 toTokenAddress: wethAddress, | ||||
|             }); | ||||
|             verifyEventsFromLogs( | ||||
|                 logs, | ||||
|                 [ | ||||
|                     { | ||||
|                         sellTokenAddress: opts.fromTokenAddress, | ||||
|                         buyTokenAddress: KYBER_ETH_ADDRESS, | ||||
|                         sellAmount: opts.fromTokenBalance, | ||||
|                         recipientAddress: testContract.address, | ||||
|                         minConversionRate: getMinimumConversionRate(opts), | ||||
|                         msgValue: constants.ZERO_AMOUNT, | ||||
|                         ...STATIC_KYBER_TRADE_ARGS, | ||||
|                     }, | ||||
|                 ], | ||||
|                 TestKyberBridgeEvents.KyberBridgeTrade, | ||||
|             ); | ||||
|         }); | ||||
|  | ||||
|         it('can trade ETH -> token', async () => { | ||||
|             const { opts, logs } = await withdrawToAsync({ | ||||
|                 fromTokenAddress: wethAddress, | ||||
|             }); | ||||
|             verifyEventsFromLogs( | ||||
|                 logs, | ||||
|                 [ | ||||
|                     { | ||||
|                         sellTokenAddress: KYBER_ETH_ADDRESS, | ||||
|                         buyTokenAddress: opts.toTokenAddress, | ||||
|                         sellAmount: opts.fromTokenBalance, | ||||
|                         recipientAddress: opts.toAddress, | ||||
|                         minConversionRate: getMinimumConversionRate(opts), | ||||
|                         msgValue: opts.fromTokenBalance, | ||||
|                         ...STATIC_KYBER_TRADE_ARGS, | ||||
|                     }, | ||||
|                 ], | ||||
|                 TestKyberBridgeEvents.KyberBridgeTrade, | ||||
|             ); | ||||
|         }); | ||||
|  | ||||
|         it('does nothing if bridge has no token balance', async () => { | ||||
|             const { logs } = await withdrawToAsync({ | ||||
|                 fromTokenBalance: constants.ZERO_AMOUNT, | ||||
|             }); | ||||
|             expect(logs).to.be.length(0); | ||||
|         }); | ||||
|  | ||||
|         it('only transfers the token if trading the same token', async () => { | ||||
|             const { opts, logs } = await withdrawToAsync({ | ||||
|                 toTokenAddress: fromTokenAddress, | ||||
|             }); | ||||
|             verifyEventsFromLogs( | ||||
|                 logs, | ||||
|                 [ | ||||
|                     { | ||||
|                         tokenAddress: fromTokenAddress, | ||||
|                         ownerAddress: testContract.address, | ||||
|                         recipientAddress: opts.toAddress, | ||||
|                         amount: opts.fromTokenBalance, | ||||
|                     }, | ||||
|                 ], | ||||
|                 TestKyberBridgeEvents.KyberBridgeTokenTransfer, | ||||
|             ); | ||||
|         }); | ||||
|  | ||||
|         it('grants Kyber an allowance when selling non-WETH', async () => { | ||||
|             const { opts, logs } = await withdrawToAsync(); | ||||
|             verifyEventsFromLogs( | ||||
|                 logs, | ||||
|                 [ | ||||
|                     { | ||||
|                         tokenAddress: opts.fromTokenAddress, | ||||
|                         ownerAddress: testContract.address, | ||||
|                         spenderAddress: testContract.address, | ||||
|                         allowance: constants.MAX_UINT256, | ||||
|                     }, | ||||
|                 ], | ||||
|                 TestKyberBridgeEvents.KyberBridgeTokenApprove, | ||||
|             ); | ||||
|         }); | ||||
|  | ||||
|         it('does not grant Kyber an allowance when selling WETH', async () => { | ||||
|             const { logs } = await withdrawToAsync({ | ||||
|                 fromTokenAddress: wethAddress, | ||||
|             }); | ||||
|             verifyEventsFromLogs(logs, [], TestKyberBridgeEvents.KyberBridgeTokenApprove); | ||||
|         }); | ||||
|  | ||||
|         it('withdraws WETH and passes it to Kyber when selling WETH', async () => { | ||||
|             const { opts, logs } = await withdrawToAsync({ | ||||
|                 fromTokenAddress: wethAddress, | ||||
|             }); | ||||
|             expect(logs[0].event).to.eq(TestKyberBridgeEvents.KyberBridgeWethWithdraw); | ||||
|             expect(logs[0].args).to.deep.eq({ | ||||
|                 ownerAddress: testContract.address, | ||||
|                 amount: opts.fromTokenBalance, | ||||
|             }); | ||||
|             expect(logs[1].event).to.eq(TestKyberBridgeEvents.KyberBridgeTrade); | ||||
|             expect(logs[1].args.msgValue).to.bignumber.eq(opts.fromTokenBalance); | ||||
|         }); | ||||
|  | ||||
|         it('wraps WETH and transfers it to the recipient when buyng WETH', async () => { | ||||
|             const { opts, logs } = await withdrawToAsync({ | ||||
|                 toTokenAddress: wethAddress, | ||||
|             }); | ||||
|             expect(logs[0].event).to.eq(TestKyberBridgeEvents.KyberBridgeTokenApprove); | ||||
|             expect(logs[0].args.tokenAddress).to.eq(opts.fromTokenAddress); | ||||
|             expect(logs[1].event).to.eq(TestKyberBridgeEvents.KyberBridgeTrade); | ||||
|             expect(logs[1].args.recipientAddress).to.eq(testContract.address); | ||||
|             expect(logs[2].event).to.eq(TestKyberBridgeEvents.KyberBridgeWethDeposit); | ||||
|             expect(logs[2].args).to.deep.eq({ | ||||
|                 msgValue: opts.fillAmount, | ||||
|                 ownerAddress: testContract.address, | ||||
|                 amount: opts.fillAmount, | ||||
|             }); | ||||
|         }); | ||||
|     }); | ||||
| }); | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,245 +0,0 @@ | ||||
| import { | ||||
|     chaiSetup, | ||||
|     constants, | ||||
|     expectTransactionFailedWithoutReasonAsync, | ||||
|     provider, | ||||
|     txDefaults, | ||||
|     web3Wrapper, | ||||
| } from '@0x/contracts-test-utils'; | ||||
| import { BlockchainLifecycle } from '@0x/dev-utils'; | ||||
| import { AssetProxyId, RevertReason } from '@0x/types'; | ||||
| import { AbiEncoder, BigNumber } from '@0x/utils'; | ||||
| import * as chai from 'chai'; | ||||
| import * as ethUtil from 'ethereumjs-util'; | ||||
|  | ||||
| import { artifacts } from './artifacts'; | ||||
|  | ||||
| import { | ||||
|     IAssetDataContract, | ||||
|     IAssetProxyContract, | ||||
|     StaticCallProxyContract, | ||||
|     TestStaticCallTargetContract, | ||||
| } from './wrappers'; | ||||
|  | ||||
| chaiSetup.configure(); | ||||
| const expect = chai.expect; | ||||
| const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); | ||||
|  | ||||
| describe('StaticCallProxy', () => { | ||||
|     const amount = constants.ZERO_AMOUNT; | ||||
|     let fromAddress: string; | ||||
|     let toAddress: string; | ||||
|  | ||||
|     let assetDataInterface: IAssetDataContract; | ||||
|     let staticCallProxy: IAssetProxyContract; | ||||
|     let staticCallTarget: TestStaticCallTargetContract; | ||||
|  | ||||
|     before(async () => { | ||||
|         await blockchainLifecycle.startAsync(); | ||||
|     }); | ||||
|     after(async () => { | ||||
|         await blockchainLifecycle.revertAsync(); | ||||
|     }); | ||||
|     before(async () => { | ||||
|         const accounts = await web3Wrapper.getAvailableAddressesAsync(); | ||||
|         [fromAddress, toAddress] = accounts.slice(0, 2); | ||||
|         const staticCallProxyWithoutTransferFrom = await StaticCallProxyContract.deployFrom0xArtifactAsync( | ||||
|             artifacts.StaticCallProxy, | ||||
|             provider, | ||||
|             txDefaults, | ||||
|             artifacts, | ||||
|         ); | ||||
|         assetDataInterface = new IAssetDataContract(constants.NULL_ADDRESS, provider); | ||||
|         staticCallProxy = new IAssetProxyContract( | ||||
|             staticCallProxyWithoutTransferFrom.address, | ||||
|             provider, | ||||
|             txDefaults, | ||||
|             {}, | ||||
|             StaticCallProxyContract.deployedBytecode, | ||||
|         ); | ||||
|         staticCallTarget = await TestStaticCallTargetContract.deployFrom0xArtifactAsync( | ||||
|             artifacts.TestStaticCallTarget, | ||||
|             provider, | ||||
|             txDefaults, | ||||
|             artifacts, | ||||
|         ); | ||||
|     }); | ||||
|     beforeEach(async () => { | ||||
|         await blockchainLifecycle.startAsync(); | ||||
|     }); | ||||
|     afterEach(async () => { | ||||
|         await blockchainLifecycle.revertAsync(); | ||||
|     }); | ||||
|  | ||||
|     describe('general', () => { | ||||
|         it('should revert if undefined function is called', async () => { | ||||
|             const undefinedSelector = '0x01020304'; | ||||
|             await expectTransactionFailedWithoutReasonAsync( | ||||
|                 web3Wrapper.sendTransactionAsync({ | ||||
|                     from: fromAddress, | ||||
|                     to: staticCallProxy.address, | ||||
|                     value: constants.ZERO_AMOUNT, | ||||
|                     data: undefinedSelector, | ||||
|                 }), | ||||
|             ); | ||||
|         }); | ||||
|         it('should have an id of 0xc339d10a', async () => { | ||||
|             const proxyId = await staticCallProxy.getProxyId().callAsync(); | ||||
|             const expectedProxyId = AssetProxyId.StaticCall; | ||||
|             expect(proxyId).to.equal(expectedProxyId); | ||||
|         }); | ||||
|     }); | ||||
|     describe('transferFrom', () => { | ||||
|         it('should revert if assetData lies outside the bounds of calldata', async () => { | ||||
|             const staticCallData = staticCallTarget.noInputFunction().getABIEncodedTransactionData(); | ||||
|             const expectedResultHash = constants.KECCAK256_NULL; | ||||
|             const assetData = assetDataInterface | ||||
|                 .StaticCall(staticCallTarget.address, staticCallData, expectedResultHash) | ||||
|                 .getABIEncodedTransactionData(); | ||||
|             const txData = staticCallProxy | ||||
|                 .transferFrom(assetData, fromAddress, toAddress, amount) | ||||
|                 .getABIEncodedTransactionData(); | ||||
|             const offsetToAssetData = '0000000000000000000000000000000000000000000000000000000000000080'; | ||||
|             const txDataEndBuffer = ethUtil.toBuffer((txData.length - 2) / 2 - 4); | ||||
|             const paddedTxDataEndBuffer = ethUtil.setLengthLeft(txDataEndBuffer, 32); | ||||
|             const invalidOffsetToAssetData = ethUtil.bufferToHex(paddedTxDataEndBuffer).slice(2); | ||||
|             const newAssetData = '0000000000000000000000000000000000000000000000000000000000000304'; | ||||
|             const badTxData = `${txData.replace(offsetToAssetData, invalidOffsetToAssetData)}${newAssetData}`; | ||||
|             await expectTransactionFailedWithoutReasonAsync( | ||||
|                 web3Wrapper.sendTransactionAsync({ | ||||
|                     to: staticCallProxy.address, | ||||
|                     from: fromAddress, | ||||
|                     data: badTxData, | ||||
|                 }), | ||||
|             ); | ||||
|         }); | ||||
|         it('should revert if the length of assetData is less than 100 bytes', async () => { | ||||
|             const staticCallData = constants.NULL_BYTES; | ||||
|             const expectedResultHash = constants.KECCAK256_NULL; | ||||
|             const assetData = assetDataInterface | ||||
|                 .StaticCall(staticCallTarget.address, staticCallData, expectedResultHash) | ||||
|                 .getABIEncodedTransactionData() | ||||
|                 .slice(0, -128); | ||||
|             const assetDataByteLen = (assetData.length - 2) / 2; | ||||
|             expect((assetDataByteLen - 4) % 32).to.equal(0); | ||||
|             await expectTransactionFailedWithoutReasonAsync( | ||||
|                 staticCallProxy.transferFrom(assetData, fromAddress, toAddress, amount).sendTransactionAsync(), | ||||
|             ); | ||||
|         }); | ||||
|         it('should revert if the offset to `staticCallData` points to outside of assetData', async () => { | ||||
|             const staticCallData = staticCallTarget.noInputFunction().getABIEncodedTransactionData(); | ||||
|             const expectedResultHash = constants.KECCAK256_NULL; | ||||
|             const assetData = assetDataInterface | ||||
|                 .StaticCall(staticCallTarget.address, staticCallData, expectedResultHash) | ||||
|                 .getABIEncodedTransactionData(); | ||||
|             const offsetToStaticCallData = '0000000000000000000000000000000000000000000000000000000000000060'; | ||||
|             const assetDataEndBuffer = ethUtil.toBuffer((assetData.length - 2) / 2 - 4); | ||||
|             const paddedAssetDataEndBuffer = ethUtil.setLengthLeft(assetDataEndBuffer, 32); | ||||
|             const invalidOffsetToStaticCallData = ethUtil.bufferToHex(paddedAssetDataEndBuffer).slice(2); | ||||
|             const newStaticCallData = '0000000000000000000000000000000000000000000000000000000000000304'; | ||||
|             const badAssetData = `${assetData.replace( | ||||
|                 offsetToStaticCallData, | ||||
|                 invalidOffsetToStaticCallData, | ||||
|             )}${newStaticCallData}`; | ||||
|             await expectTransactionFailedWithoutReasonAsync( | ||||
|                 staticCallProxy.transferFrom(badAssetData, fromAddress, toAddress, amount).sendTransactionAsync(), | ||||
|             ); | ||||
|         }); | ||||
|         it('should revert if the callTarget attempts to write to state', async () => { | ||||
|             const staticCallData = staticCallTarget.updateState().getABIEncodedTransactionData(); | ||||
|             const expectedResultHash = constants.KECCAK256_NULL; | ||||
|             const assetData = assetDataInterface | ||||
|                 .StaticCall(staticCallTarget.address, staticCallData, expectedResultHash) | ||||
|                 .getABIEncodedTransactionData(); | ||||
|             await expectTransactionFailedWithoutReasonAsync( | ||||
|                 staticCallProxy.transferFrom(assetData, fromAddress, toAddress, amount).sendTransactionAsync(), | ||||
|             ); | ||||
|         }); | ||||
|         it('should revert with data provided by the callTarget if the staticcall reverts', async () => { | ||||
|             const staticCallData = staticCallTarget.assertEvenNumber(new BigNumber(1)).getABIEncodedTransactionData(); | ||||
|             const expectedResultHash = constants.KECCAK256_NULL; | ||||
|             const assetData = assetDataInterface | ||||
|                 .StaticCall(staticCallTarget.address, staticCallData, expectedResultHash) | ||||
|                 .getABIEncodedTransactionData(); | ||||
|             return expect( | ||||
|                 staticCallProxy.transferFrom(assetData, fromAddress, toAddress, amount).awaitTransactionSuccessAsync(), | ||||
|             ).to.revertWith(RevertReason.TargetNotEven); | ||||
|         }); | ||||
|         it('should revert if the hash of the output is different than expected expected', async () => { | ||||
|             const staticCallData = staticCallTarget.isOddNumber(new BigNumber(0)).getABIEncodedTransactionData(); | ||||
|             const trueAsBuffer = ethUtil.toBuffer('0x0000000000000000000000000000000000000000000000000000000000000001'); | ||||
|             const expectedResultHash = ethUtil.bufferToHex(ethUtil.sha3(trueAsBuffer)); | ||||
|             const assetData = assetDataInterface | ||||
|                 .StaticCall(staticCallTarget.address, staticCallData, expectedResultHash) | ||||
|                 .getABIEncodedTransactionData(); | ||||
|             return expect( | ||||
|                 staticCallProxy.transferFrom(assetData, fromAddress, toAddress, amount).awaitTransactionSuccessAsync(), | ||||
|             ).to.revertWith(RevertReason.UnexpectedStaticCallResult); | ||||
|         }); | ||||
|         it('should be successful if a function call with no inputs and no outputs is successful', async () => { | ||||
|             const staticCallData = staticCallTarget.noInputFunction().getABIEncodedTransactionData(); | ||||
|             const expectedResultHash = constants.KECCAK256_NULL; | ||||
|             const assetData = assetDataInterface | ||||
|                 .StaticCall(staticCallTarget.address, staticCallData, expectedResultHash) | ||||
|                 .getABIEncodedTransactionData(); | ||||
|             await staticCallProxy | ||||
|                 .transferFrom(assetData, fromAddress, toAddress, amount) | ||||
|                 .awaitTransactionSuccessAsync(); | ||||
|         }); | ||||
|         it('should be successful if the staticCallTarget is not a contract and no return value is expected', async () => { | ||||
|             const staticCallData = '0x0102030405060708'; | ||||
|             const expectedResultHash = constants.KECCAK256_NULL; | ||||
|             const assetData = assetDataInterface | ||||
|                 .StaticCall(toAddress, staticCallData, expectedResultHash) | ||||
|                 .getABIEncodedTransactionData(); | ||||
|             await staticCallProxy | ||||
|                 .transferFrom(assetData, fromAddress, toAddress, amount) | ||||
|                 .awaitTransactionSuccessAsync(); | ||||
|         }); | ||||
|         it('should be successful if a function call with one static input returns the correct value', async () => { | ||||
|             const staticCallData = staticCallTarget.isOddNumber(new BigNumber(1)).getABIEncodedTransactionData(); | ||||
|             const trueAsBuffer = ethUtil.toBuffer('0x0000000000000000000000000000000000000000000000000000000000000001'); | ||||
|             const expectedResultHash = ethUtil.bufferToHex(ethUtil.sha3(trueAsBuffer)); | ||||
|             const assetData = assetDataInterface | ||||
|                 .StaticCall(staticCallTarget.address, staticCallData, expectedResultHash) | ||||
|                 .getABIEncodedTransactionData(); | ||||
|             await staticCallProxy | ||||
|                 .transferFrom(assetData, fromAddress, toAddress, amount) | ||||
|                 .awaitTransactionSuccessAsync(); | ||||
|         }); | ||||
|         it('should be successful if a function with one dynamic input is successful', async () => { | ||||
|             const dynamicInput = '0x0102030405060708'; | ||||
|             const staticCallData = staticCallTarget.dynamicInputFunction(dynamicInput).getABIEncodedTransactionData(); | ||||
|             const expectedResultHash = constants.KECCAK256_NULL; | ||||
|             const assetData = assetDataInterface | ||||
|                 .StaticCall(staticCallTarget.address, staticCallData, expectedResultHash) | ||||
|                 .getABIEncodedTransactionData(); | ||||
|             await staticCallProxy | ||||
|                 .transferFrom(assetData, fromAddress, toAddress, amount) | ||||
|                 .awaitTransactionSuccessAsync(); | ||||
|         }); | ||||
|         it('should be successful if a function call returns a complex type', async () => { | ||||
|             const a = new BigNumber(1); | ||||
|             const b = new BigNumber(2); | ||||
|             const staticCallData = staticCallTarget.returnComplexType(a, b).getABIEncodedTransactionData(); | ||||
|             const abiEncoder = new AbiEncoder.DynamicBytes({ | ||||
|                 name: '', | ||||
|                 type: 'bytes', | ||||
|             }); | ||||
|             const aHex = '0000000000000000000000000000000000000000000000000000000000000001'; | ||||
|             const bHex = '0000000000000000000000000000000000000000000000000000000000000002'; | ||||
|             const expectedResults = `${staticCallTarget.address}${aHex}${bHex}`; | ||||
|             const offset = '0000000000000000000000000000000000000000000000000000000000000020'; | ||||
|             const encodedExpectedResultWithOffset = `0x${offset}${abiEncoder.encode(expectedResults).slice(2)}`; | ||||
|             const expectedResultHash = ethUtil.bufferToHex( | ||||
|                 ethUtil.sha3(ethUtil.toBuffer(encodedExpectedResultWithOffset)), | ||||
|             ); | ||||
|             const assetData = assetDataInterface | ||||
|                 .StaticCall(staticCallTarget.address, staticCallData, expectedResultHash) | ||||
|                 .getABIEncodedTransactionData(); | ||||
|             await staticCallProxy | ||||
|                 .transferFrom(assetData, fromAddress, toAddress, amount) | ||||
|                 .awaitTransactionSuccessAsync(); | ||||
|         }); | ||||
|     }); | ||||
| }); | ||||
| @@ -1,370 +0,0 @@ | ||||
| import { | ||||
|     blockchainTests, | ||||
|     constants, | ||||
|     expect, | ||||
|     filterLogs, | ||||
|     filterLogsToArguments, | ||||
|     getRandomInteger, | ||||
|     Numberish, | ||||
|     randomAddress, | ||||
| } from '@0x/contracts-test-utils'; | ||||
| import { AssetProxyId } from '@0x/types'; | ||||
| import { BigNumber, hexUtils } from '@0x/utils'; | ||||
| import { DecodedLogs } from 'ethereum-types'; | ||||
| import * as _ from 'lodash'; | ||||
|  | ||||
| import { artifacts } from './artifacts'; | ||||
|  | ||||
| import { | ||||
|     TestUniswapBridgeContract, | ||||
|     TestUniswapBridgeEthToTokenTransferInputEventArgs as EthToTokenTransferInputArgs, | ||||
|     TestUniswapBridgeEvents as ContractEvents, | ||||
|     TestUniswapBridgeTokenApproveEventArgs as TokenApproveArgs, | ||||
|     TestUniswapBridgeTokenToEthSwapInputEventArgs as TokenToEthSwapInputArgs, | ||||
|     TestUniswapBridgeTokenToTokenTransferInputEventArgs as TokenToTokenTransferInputArgs, | ||||
|     TestUniswapBridgeTokenTransferEventArgs as TokenTransferArgs, | ||||
|     TestUniswapBridgeWethDepositEventArgs as WethDepositArgs, | ||||
|     TestUniswapBridgeWethWithdrawEventArgs as WethWithdrawArgs, | ||||
| } from './wrappers'; | ||||
|  | ||||
| blockchainTests.resets('UniswapBridge unit tests', env => { | ||||
|     let testContract: TestUniswapBridgeContract; | ||||
|     let wethTokenAddress: string; | ||||
|  | ||||
|     before(async () => { | ||||
|         testContract = await TestUniswapBridgeContract.deployFrom0xArtifactAsync( | ||||
|             artifacts.TestUniswapBridge, | ||||
|             env.provider, | ||||
|             env.txDefaults, | ||||
|             artifacts, | ||||
|         ); | ||||
|         wethTokenAddress = await testContract.wethToken().callAsync(); | ||||
|     }); | ||||
|  | ||||
|     describe('isValidSignature()', () => { | ||||
|         it('returns success bytes', async () => { | ||||
|             const LEGACY_WALLET_MAGIC_VALUE = '0xb0671381'; | ||||
|             const result = await testContract | ||||
|                 .isValidSignature(hexUtils.random(), hexUtils.random(_.random(0, 32))) | ||||
|                 .callAsync(); | ||||
|             expect(result).to.eq(LEGACY_WALLET_MAGIC_VALUE); | ||||
|         }); | ||||
|     }); | ||||
|  | ||||
|     describe('bridgeTransferFrom()', () => { | ||||
|         interface WithdrawToOpts { | ||||
|             fromTokenAddress: string; | ||||
|             toTokenAddress: string; | ||||
|             fromTokenBalance: Numberish; | ||||
|             toAddress: string; | ||||
|             amount: Numberish; | ||||
|             exchangeRevertReason: string; | ||||
|             exchangeFillAmount: Numberish; | ||||
|             toTokenRevertReason: string; | ||||
|             fromTokenRevertReason: string; | ||||
|         } | ||||
|  | ||||
|         function createWithdrawToOpts(opts?: Partial<WithdrawToOpts>): WithdrawToOpts { | ||||
|             return { | ||||
|                 fromTokenAddress: constants.NULL_ADDRESS, | ||||
|                 toTokenAddress: constants.NULL_ADDRESS, | ||||
|                 fromTokenBalance: getRandomInteger(1, 1e18), | ||||
|                 toAddress: randomAddress(), | ||||
|                 amount: getRandomInteger(1, 1e18), | ||||
|                 exchangeRevertReason: '', | ||||
|                 exchangeFillAmount: getRandomInteger(1, 1e18), | ||||
|                 toTokenRevertReason: '', | ||||
|                 fromTokenRevertReason: '', | ||||
|                 ...opts, | ||||
|             }; | ||||
|         } | ||||
|  | ||||
|         interface WithdrawToResult { | ||||
|             opts: WithdrawToOpts; | ||||
|             result: string; | ||||
|             logs: DecodedLogs; | ||||
|             blockTime: number; | ||||
|         } | ||||
|  | ||||
|         async function withdrawToAsync(opts?: Partial<WithdrawToOpts>): Promise<WithdrawToResult> { | ||||
|             const _opts = createWithdrawToOpts(opts); | ||||
|             const callData = { value: new BigNumber(_opts.exchangeFillAmount) }; | ||||
|             // Create the "from" token and exchange. | ||||
|             const createFromTokenFn = testContract.createTokenAndExchange( | ||||
|                 _opts.fromTokenAddress, | ||||
|                 _opts.exchangeRevertReason, | ||||
|             ); | ||||
|             [_opts.fromTokenAddress] = await createFromTokenFn.callAsync(callData); | ||||
|             await createFromTokenFn.awaitTransactionSuccessAsync(callData); | ||||
|  | ||||
|             // Create the "to" token and exchange. | ||||
|             const createToTokenFn = testContract.createTokenAndExchange( | ||||
|                 _opts.toTokenAddress, | ||||
|                 _opts.exchangeRevertReason, | ||||
|             ); | ||||
|             [_opts.toTokenAddress] = await createToTokenFn.callAsync(callData); | ||||
|             await createToTokenFn.awaitTransactionSuccessAsync(callData); | ||||
|  | ||||
|             await testContract | ||||
|                 .setTokenRevertReason(_opts.toTokenAddress, _opts.toTokenRevertReason) | ||||
|                 .awaitTransactionSuccessAsync(); | ||||
|             await testContract | ||||
|                 .setTokenRevertReason(_opts.fromTokenAddress, _opts.fromTokenRevertReason) | ||||
|                 .awaitTransactionSuccessAsync(); | ||||
|             // Set the token balance for the token we're converting from. | ||||
|             await testContract.setTokenBalance(_opts.fromTokenAddress).awaitTransactionSuccessAsync({ | ||||
|                 value: new BigNumber(_opts.fromTokenBalance), | ||||
|             }); | ||||
|             // Call bridgeTransferFrom(). | ||||
|             const bridgeTransferFromFn = testContract.bridgeTransferFrom( | ||||
|                 // The "to" token address. | ||||
|                 _opts.toTokenAddress, | ||||
|                 // The "from" address. | ||||
|                 randomAddress(), | ||||
|                 // The "to" address. | ||||
|                 _opts.toAddress, | ||||
|                 // The amount to transfer to "to" | ||||
|                 new BigNumber(_opts.amount), | ||||
|                 // ABI-encoded "from" token address. | ||||
|                 hexUtils.leftPad(_opts.fromTokenAddress), | ||||
|             ); | ||||
|             const result = await bridgeTransferFromFn.callAsync(); | ||||
|             const receipt = await bridgeTransferFromFn.awaitTransactionSuccessAsync(); | ||||
|             return { | ||||
|                 opts: _opts, | ||||
|                 result, | ||||
|                 logs: (receipt.logs as any) as DecodedLogs, | ||||
|                 blockTime: await env.web3Wrapper.getBlockTimestampAsync(receipt.blockNumber), | ||||
|             }; | ||||
|         } | ||||
|  | ||||
|         async function getExchangeForTokenAsync(tokenAddress: string): Promise<string> { | ||||
|             return testContract.getExchange(tokenAddress).callAsync(); | ||||
|         } | ||||
|  | ||||
|         it('returns magic bytes on success', async () => { | ||||
|             const { result } = await withdrawToAsync(); | ||||
|             expect(result).to.eq(AssetProxyId.ERC20Bridge); | ||||
|         }); | ||||
|  | ||||
|         it('just transfers tokens to `to` if the same tokens are in play', async () => { | ||||
|             const createTokenFn = await testContract.createTokenAndExchange(constants.NULL_ADDRESS, ''); | ||||
|             const [tokenAddress] = await createTokenFn.callAsync(); | ||||
|             await createTokenFn.awaitTransactionSuccessAsync(); | ||||
|             const { opts, result, logs } = await withdrawToAsync({ | ||||
|                 fromTokenAddress: tokenAddress, | ||||
|                 toTokenAddress: tokenAddress, | ||||
|             }); | ||||
|             expect(result).to.eq(AssetProxyId.ERC20Bridge); | ||||
|             const transfers = filterLogsToArguments<TokenTransferArgs>(logs, ContractEvents.TokenTransfer); | ||||
|             expect(transfers.length).to.eq(1); | ||||
|             expect(transfers[0].token).to.eq(tokenAddress); | ||||
|             expect(transfers[0].from).to.eq(testContract.address); | ||||
|             expect(transfers[0].to).to.eq(opts.toAddress); | ||||
|             expect(transfers[0].amount).to.bignumber.eq(opts.amount); | ||||
|         }); | ||||
|  | ||||
|         describe('token -> token', () => { | ||||
|             it('calls `IUniswapExchange.tokenToTokenTransferInput()', async () => { | ||||
|                 const { opts, logs, blockTime } = await withdrawToAsync(); | ||||
|                 const exchangeAddress = await getExchangeForTokenAsync(opts.fromTokenAddress); | ||||
|                 const calls = filterLogsToArguments<TokenToTokenTransferInputArgs>( | ||||
|                     logs, | ||||
|                     ContractEvents.TokenToTokenTransferInput, | ||||
|                 ); | ||||
|                 expect(calls.length).to.eq(1); | ||||
|                 expect(calls[0].exchange).to.eq(exchangeAddress); | ||||
|                 expect(calls[0].tokensSold).to.bignumber.eq(opts.fromTokenBalance); | ||||
|                 expect(calls[0].minTokensBought).to.bignumber.eq(opts.amount); | ||||
|                 expect(calls[0].minEthBought).to.bignumber.eq(1); | ||||
|                 expect(calls[0].deadline).to.bignumber.eq(blockTime); | ||||
|                 expect(calls[0].recipient).to.eq(opts.toAddress); | ||||
|                 expect(calls[0].toTokenAddress).to.eq(opts.toTokenAddress); | ||||
|             }); | ||||
|  | ||||
|             it('sets allowance for "from" token', async () => { | ||||
|                 const { opts, logs } = await withdrawToAsync(); | ||||
|                 const approvals = filterLogsToArguments<TokenApproveArgs>(logs, ContractEvents.TokenApprove); | ||||
|                 const exchangeAddress = await getExchangeForTokenAsync(opts.fromTokenAddress); | ||||
|                 expect(approvals.length).to.eq(1); | ||||
|                 expect(approvals[0].spender).to.eq(exchangeAddress); | ||||
|                 expect(approvals[0].allowance).to.bignumber.eq(constants.MAX_UINT256); | ||||
|             }); | ||||
|  | ||||
|             it('sets allowance for "from" token on subsequent calls', async () => { | ||||
|                 const { opts } = await withdrawToAsync(); | ||||
|                 const { logs } = await withdrawToAsync(opts); | ||||
|                 const approvals = filterLogsToArguments<TokenApproveArgs>(logs, ContractEvents.TokenApprove); | ||||
|                 const exchangeAddress = await getExchangeForTokenAsync(opts.fromTokenAddress); | ||||
|                 expect(approvals.length).to.eq(1); | ||||
|                 expect(approvals[0].spender).to.eq(exchangeAddress); | ||||
|                 expect(approvals[0].allowance).to.bignumber.eq(constants.MAX_UINT256); | ||||
|             }); | ||||
|  | ||||
|             it('fails if "from" token does not exist', async () => { | ||||
|                 const tx = testContract | ||||
|                     .bridgeTransferFrom( | ||||
|                         randomAddress(), | ||||
|                         randomAddress(), | ||||
|                         randomAddress(), | ||||
|                         getRandomInteger(1, 1e18), | ||||
|                         hexUtils.leftPad(randomAddress()), | ||||
|                     ) | ||||
|                     .awaitTransactionSuccessAsync(); | ||||
|                 return expect(tx).to.eventually.be.rejectedWith('NO_UNISWAP_EXCHANGE_FOR_TOKEN'); | ||||
|             }); | ||||
|  | ||||
|             it('fails if the exchange fails', async () => { | ||||
|                 const revertReason = 'FOOBAR'; | ||||
|                 const tx = withdrawToAsync({ | ||||
|                     exchangeRevertReason: revertReason, | ||||
|                 }); | ||||
|                 return expect(tx).to.eventually.be.rejectedWith(revertReason); | ||||
|             }); | ||||
|         }); | ||||
|  | ||||
|         describe('token -> ETH', () => { | ||||
|             it('calls `IUniswapExchange.tokenToEthSwapInput()`, `WETH.deposit()`, then `transfer()`', async () => { | ||||
|                 const { opts, logs, blockTime } = await withdrawToAsync({ | ||||
|                     toTokenAddress: wethTokenAddress, | ||||
|                 }); | ||||
|                 const exchangeAddress = await getExchangeForTokenAsync(opts.fromTokenAddress); | ||||
|                 let calls: any = filterLogs<TokenToEthSwapInputArgs>(logs, ContractEvents.TokenToEthSwapInput); | ||||
|                 expect(calls.length).to.eq(1); | ||||
|                 expect(calls[0].args.exchange).to.eq(exchangeAddress); | ||||
|                 expect(calls[0].args.tokensSold).to.bignumber.eq(opts.fromTokenBalance); | ||||
|                 expect(calls[0].args.minEthBought).to.bignumber.eq(opts.amount); | ||||
|                 expect(calls[0].args.deadline).to.bignumber.eq(blockTime); | ||||
|                 calls = filterLogs<WethDepositArgs>( | ||||
|                     logs.slice(calls[0].logIndex as number), | ||||
|                     ContractEvents.WethDeposit, | ||||
|                 ); | ||||
|                 expect(calls.length).to.eq(1); | ||||
|                 expect(calls[0].args.amount).to.bignumber.eq(opts.exchangeFillAmount); | ||||
|                 calls = filterLogs<TokenTransferArgs>( | ||||
|                     logs.slice(calls[0].logIndex as number), | ||||
|                     ContractEvents.TokenTransfer, | ||||
|                 ); | ||||
|                 expect(calls.length).to.eq(1); | ||||
|                 expect(calls[0].args.token).to.eq(opts.toTokenAddress); | ||||
|                 expect(calls[0].args.from).to.eq(testContract.address); | ||||
|                 expect(calls[0].args.to).to.eq(opts.toAddress); | ||||
|                 expect(calls[0].args.amount).to.bignumber.eq(opts.exchangeFillAmount); | ||||
|             }); | ||||
|  | ||||
|             it('sets allowance for "from" token', async () => { | ||||
|                 const { opts, logs } = await withdrawToAsync({ | ||||
|                     toTokenAddress: wethTokenAddress, | ||||
|                 }); | ||||
|                 const transfers = filterLogsToArguments<TokenApproveArgs>(logs, ContractEvents.TokenApprove); | ||||
|                 const exchangeAddress = await getExchangeForTokenAsync(opts.fromTokenAddress); | ||||
|                 expect(transfers.length).to.eq(1); | ||||
|                 expect(transfers[0].spender).to.eq(exchangeAddress); | ||||
|                 expect(transfers[0].allowance).to.bignumber.eq(constants.MAX_UINT256); | ||||
|             }); | ||||
|  | ||||
|             it('sets allowance for "from" token on subsequent calls', async () => { | ||||
|                 const { opts } = await withdrawToAsync({ | ||||
|                     toTokenAddress: wethTokenAddress, | ||||
|                 }); | ||||
|                 const { logs } = await withdrawToAsync(opts); | ||||
|                 const approvals = filterLogsToArguments<TokenApproveArgs>(logs, ContractEvents.TokenApprove); | ||||
|                 const exchangeAddress = await getExchangeForTokenAsync(opts.fromTokenAddress); | ||||
|                 expect(approvals.length).to.eq(1); | ||||
|                 expect(approvals[0].spender).to.eq(exchangeAddress); | ||||
|                 expect(approvals[0].allowance).to.bignumber.eq(constants.MAX_UINT256); | ||||
|             }); | ||||
|  | ||||
|             it('fails if "from" token does not exist', async () => { | ||||
|                 const tx = testContract | ||||
|                     .bridgeTransferFrom( | ||||
|                         randomAddress(), | ||||
|                         randomAddress(), | ||||
|                         randomAddress(), | ||||
|                         getRandomInteger(1, 1e18), | ||||
|                         hexUtils.leftPad(wethTokenAddress), | ||||
|                     ) | ||||
|                     .awaitTransactionSuccessAsync(); | ||||
|                 return expect(tx).to.eventually.be.rejectedWith('NO_UNISWAP_EXCHANGE_FOR_TOKEN'); | ||||
|             }); | ||||
|  | ||||
|             it('fails if `WETH.deposit()` fails', async () => { | ||||
|                 const revertReason = 'FOOBAR'; | ||||
|                 const tx = withdrawToAsync({ | ||||
|                     toTokenAddress: wethTokenAddress, | ||||
|                     toTokenRevertReason: revertReason, | ||||
|                 }); | ||||
|                 return expect(tx).to.eventually.be.rejectedWith(revertReason); | ||||
|             }); | ||||
|  | ||||
|             it('fails if the exchange fails', async () => { | ||||
|                 const revertReason = 'FOOBAR'; | ||||
|                 const tx = withdrawToAsync({ | ||||
|                     toTokenAddress: wethTokenAddress, | ||||
|                     exchangeRevertReason: revertReason, | ||||
|                 }); | ||||
|                 return expect(tx).to.eventually.be.rejectedWith(revertReason); | ||||
|             }); | ||||
|         }); | ||||
|  | ||||
|         describe('ETH -> token', () => { | ||||
|             it('calls  `WETH.withdraw()`, then `IUniswapExchange.ethToTokenTransferInput()`', async () => { | ||||
|                 const { opts, logs, blockTime } = await withdrawToAsync({ | ||||
|                     fromTokenAddress: wethTokenAddress, | ||||
|                 }); | ||||
|                 const exchangeAddress = await getExchangeForTokenAsync(opts.toTokenAddress); | ||||
|                 let calls: any = filterLogs<WethWithdrawArgs>(logs, ContractEvents.WethWithdraw); | ||||
|                 expect(calls.length).to.eq(1); | ||||
|                 expect(calls[0].args.amount).to.bignumber.eq(opts.fromTokenBalance); | ||||
|                 calls = filterLogs<EthToTokenTransferInputArgs>( | ||||
|                     logs.slice(calls[0].logIndex as number), | ||||
|                     ContractEvents.EthToTokenTransferInput, | ||||
|                 ); | ||||
|                 expect(calls.length).to.eq(1); | ||||
|                 expect(calls[0].args.exchange).to.eq(exchangeAddress); | ||||
|                 expect(calls[0].args.minTokensBought).to.bignumber.eq(opts.amount); | ||||
|                 expect(calls[0].args.deadline).to.bignumber.eq(blockTime); | ||||
|                 expect(calls[0].args.recipient).to.eq(opts.toAddress); | ||||
|             }); | ||||
|  | ||||
|             it('does not set any allowance', async () => { | ||||
|                 const { logs } = await withdrawToAsync({ | ||||
|                     fromTokenAddress: wethTokenAddress, | ||||
|                 }); | ||||
|                 const approvals = filterLogsToArguments<TokenApproveArgs>(logs, ContractEvents.TokenApprove); | ||||
|                 expect(approvals).to.be.empty(''); | ||||
|             }); | ||||
|  | ||||
|             it('fails if "to" token does not exist', async () => { | ||||
|                 const tx = testContract | ||||
|                     .bridgeTransferFrom( | ||||
|                         wethTokenAddress, | ||||
|                         randomAddress(), | ||||
|                         randomAddress(), | ||||
|                         getRandomInteger(1, 1e18), | ||||
|                         hexUtils.leftPad(randomAddress()), | ||||
|                     ) | ||||
|                     .awaitTransactionSuccessAsync(); | ||||
|                 return expect(tx).to.eventually.be.rejectedWith('NO_UNISWAP_EXCHANGE_FOR_TOKEN'); | ||||
|             }); | ||||
|  | ||||
|             it('fails if the `WETH.withdraw()` fails', async () => { | ||||
|                 const revertReason = 'FOOBAR'; | ||||
|                 const tx = withdrawToAsync({ | ||||
|                     fromTokenAddress: wethTokenAddress, | ||||
|                     fromTokenRevertReason: revertReason, | ||||
|                 }); | ||||
|                 return expect(tx).to.eventually.be.rejectedWith(revertReason); | ||||
|             }); | ||||
|  | ||||
|             it('fails if the exchange fails', async () => { | ||||
|                 const revertReason = 'FOOBAR'; | ||||
|                 const tx = withdrawToAsync({ | ||||
|                     fromTokenAddress: wethTokenAddress, | ||||
|                     exchangeRevertReason: revertReason, | ||||
|                 }); | ||||
|                 return expect(tx).to.eventually.be.rejectedWith(revertReason); | ||||
|             }); | ||||
|         }); | ||||
|     }); | ||||
| }); | ||||
| @@ -1,40 +0,0 @@ | ||||
| /* | ||||
|  * ----------------------------------------------------------------------------- | ||||
|  * Warning: This file is auto-generated by contracts-gen. Don't edit manually. | ||||
|  * ----------------------------------------------------------------------------- | ||||
|  */ | ||||
| export * from '../test/generated-wrappers/chai_bridge'; | ||||
| export * from '../test/generated-wrappers/curve_bridge'; | ||||
| export * from '../test/generated-wrappers/dydx_bridge'; | ||||
| export * from '../test/generated-wrappers/erc1155_proxy'; | ||||
| export * from '../test/generated-wrappers/erc20_bridge_proxy'; | ||||
| export * from '../test/generated-wrappers/erc20_proxy'; | ||||
| export * from '../test/generated-wrappers/erc721_proxy'; | ||||
| export * from '../test/generated-wrappers/eth2_dai_bridge'; | ||||
| export * from '../test/generated-wrappers/i_asset_data'; | ||||
| export * from '../test/generated-wrappers/i_asset_proxy'; | ||||
| export * from '../test/generated-wrappers/i_asset_proxy_dispatcher'; | ||||
| export * from '../test/generated-wrappers/i_authorizable'; | ||||
| export * from '../test/generated-wrappers/i_chai'; | ||||
| export * from '../test/generated-wrappers/i_curve'; | ||||
| export * from '../test/generated-wrappers/i_dydx'; | ||||
| export * from '../test/generated-wrappers/i_dydx_bridge'; | ||||
| export * from '../test/generated-wrappers/i_erc20_bridge'; | ||||
| export * from '../test/generated-wrappers/i_eth2_dai'; | ||||
| export * from '../test/generated-wrappers/i_kyber_network_proxy'; | ||||
| export * from '../test/generated-wrappers/i_uniswap_exchange'; | ||||
| export * from '../test/generated-wrappers/i_uniswap_exchange_factory'; | ||||
| export * from '../test/generated-wrappers/kyber_bridge'; | ||||
| export * from '../test/generated-wrappers/mixin_asset_proxy_dispatcher'; | ||||
| export * from '../test/generated-wrappers/mixin_authorizable'; | ||||
| export * from '../test/generated-wrappers/multi_asset_proxy'; | ||||
| export * from '../test/generated-wrappers/ownable'; | ||||
| export * from '../test/generated-wrappers/static_call_proxy'; | ||||
| export * from '../test/generated-wrappers/test_chai_bridge'; | ||||
| export * from '../test/generated-wrappers/test_dydx_bridge'; | ||||
| export * from '../test/generated-wrappers/test_erc20_bridge'; | ||||
| export * from '../test/generated-wrappers/test_eth2_dai_bridge'; | ||||
| export * from '../test/generated-wrappers/test_kyber_bridge'; | ||||
| export * from '../test/generated-wrappers/test_static_call_target'; | ||||
| export * from '../test/generated-wrappers/test_uniswap_bridge'; | ||||
| export * from '../test/generated-wrappers/uniswap_bridge'; | ||||
| @@ -1,96 +0,0 @@ | ||||
| /** | ||||
|  * Use this file to configure your truffle project. It's seeded with some | ||||
|  * common settings for different networks and features like migrations, | ||||
|  * compilation and testing. Uncomment the ones you need or modify | ||||
|  * them to suit your project as necessary. | ||||
|  * | ||||
|  * More information about configuration can be found at: | ||||
|  * | ||||
|  * truffleframework.com/docs/advanced/configuration | ||||
|  * | ||||
|  * To deploy via Infura you'll need a wallet provider (like truffle-hdwallet-provider) | ||||
|  * to sign your transactions before they're sent to a remote public node. Infura accounts | ||||
|  * are available for free at: infura.io/register. | ||||
|  * | ||||
|  * You'll also need a mnemonic - the twelve word phrase the wallet uses to generate | ||||
|  * public/private key pairs. If you're publishing your code to GitHub make sure you load this | ||||
|  * phrase from a file you've .gitignored so it doesn't accidentally become public. | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| // const HDWalletProvider = require('truffle-hdwallet-provider'); | ||||
| // const infuraKey = "fj4jll3k....."; | ||||
| // | ||||
| // const fs = require('fs'); | ||||
| // const mnemonic = fs.readFileSync(".secret").toString().trim(); | ||||
|  | ||||
| module.exports = { | ||||
|     /** | ||||
|      * Networks define how you connect to your ethereum client and let you set the | ||||
|      * defaults web3 uses to send transactions. If you don't specify one truffle | ||||
|      * will spin up a development blockchain for you on port 9545 when you | ||||
|      * run `develop` or `test`. You can ask a truffle command to use a specific | ||||
|      * network from the command line, e.g | ||||
|      * | ||||
|      * $ truffle test --network <network-name> | ||||
|      */ | ||||
|  | ||||
|     networks: { | ||||
|         // Useful for testing. The `development` name is special - truffle uses it by default | ||||
|         // if it's defined here and no other network is specified at the command line. | ||||
|         // You should run a client (like ganache-cli, geth or parity) in a separate terminal | ||||
|         // tab if you use this network and you must also set the `host`, `port` and `network_id` | ||||
|         // options below to some value. | ||||
|         // | ||||
|         // development: { | ||||
|         //  host: "127.0.0.1",     // Localhost (default: none) | ||||
|         //  port: 8545,            // Standard Ethereum port (default: none) | ||||
|         //  network_id: "*",       // Any network (default: none) | ||||
|         // }, | ||||
|         // Another network with more advanced options... | ||||
|         // advanced: { | ||||
|         // port: 8777,             // Custom port | ||||
|         // network_id: 1342,       // Custom network | ||||
|         // gas: 8500000,           // Gas sent with each transaction (default: ~6700000) | ||||
|         // gasPrice: 20000000000,  // 20 gwei (in wei) (default: 100 gwei) | ||||
|         // from: <address>,        // Account to send txs from (default: accounts[0]) | ||||
|         // websockets: true        // Enable EventEmitter interface for web3 (default: false) | ||||
|         // }, | ||||
|         // Useful for deploying to a public network. | ||||
|         // NB: It's important to wrap the provider as a function. | ||||
|         // ropsten: { | ||||
|         // provider: () => new HDWalletProvider(mnemonic, `https://ropsten.infura.io/v3/YOUR-PROJECT-ID`), | ||||
|         // network_id: 3,       // Ropsten's id | ||||
|         // gas: 5500000,        // Ropsten has a lower block limit than mainnet | ||||
|         // confirmations: 2,    // # of confs to wait between deployments. (default: 0) | ||||
|         // timeoutBlocks: 200,  // # of blocks before a deployment times out  (minimum/default: 50) | ||||
|         // skipDryRun: true     // Skip dry run before migrations? (default: false for public nets ) | ||||
|         // }, | ||||
|         // Useful for private networks | ||||
|         // private: { | ||||
|         // provider: () => new HDWalletProvider(mnemonic, `https://network.io`), | ||||
|         // network_id: 2111,   // This network is yours, in the cloud. | ||||
|         // production: true    // Treats this network as if it was a public net. (default: false) | ||||
|         // } | ||||
|     }, | ||||
|  | ||||
|     // Set default mocha options here, use special reporters etc. | ||||
|     mocha: { | ||||
|         // timeout: 100000 | ||||
|     }, | ||||
|  | ||||
|     // Configure your compilers | ||||
|     compilers: { | ||||
|         solc: { | ||||
|             version: '0.5.9', | ||||
|             settings: { | ||||
|                 evmVersion: 'istanbul', | ||||
|                 optimizer: { | ||||
|                     enabled: true, | ||||
|                     runs: 1000000, | ||||
|                     details: { yul: true, deduplicate: true, cse: true, constantOptimizer: true }, | ||||
|                 }, | ||||
|             }, | ||||
|         }, | ||||
|     }, | ||||
| }; | ||||
| @@ -1,78 +0,0 @@ | ||||
| { | ||||
|     "extends": "../../tsconfig", | ||||
|     "compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true }, | ||||
|     "include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"], | ||||
|     "files": [ | ||||
|         "generated-artifacts/ChaiBridge.json", | ||||
|         "generated-artifacts/CurveBridge.json", | ||||
|         "generated-artifacts/DydxBridge.json", | ||||
|         "generated-artifacts/ERC1155Proxy.json", | ||||
|         "generated-artifacts/ERC20BridgeProxy.json", | ||||
|         "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/IChai.json", | ||||
|         "generated-artifacts/ICurve.json", | ||||
|         "generated-artifacts/IDydx.json", | ||||
|         "generated-artifacts/IDydxBridge.json", | ||||
|         "generated-artifacts/IERC20Bridge.json", | ||||
|         "generated-artifacts/IEth2Dai.json", | ||||
|         "generated-artifacts/IKyberNetworkProxy.json", | ||||
|         "generated-artifacts/IUniswapExchange.json", | ||||
|         "generated-artifacts/IUniswapExchangeFactory.json", | ||||
|         "generated-artifacts/KyberBridge.json", | ||||
|         "generated-artifacts/MixinAssetProxyDispatcher.json", | ||||
|         "generated-artifacts/MixinAuthorizable.json", | ||||
|         "generated-artifacts/MultiAssetProxy.json", | ||||
|         "generated-artifacts/Ownable.json", | ||||
|         "generated-artifacts/StaticCallProxy.json", | ||||
|         "generated-artifacts/TestChaiBridge.json", | ||||
|         "generated-artifacts/TestDydxBridge.json", | ||||
|         "generated-artifacts/TestERC20Bridge.json", | ||||
|         "generated-artifacts/TestEth2DaiBridge.json", | ||||
|         "generated-artifacts/TestKyberBridge.json", | ||||
|         "generated-artifacts/TestStaticCallTarget.json", | ||||
|         "generated-artifacts/TestUniswapBridge.json", | ||||
|         "generated-artifacts/UniswapBridge.json", | ||||
|         "test/generated-artifacts/ChaiBridge.json", | ||||
|         "test/generated-artifacts/CurveBridge.json", | ||||
|         "test/generated-artifacts/DydxBridge.json", | ||||
|         "test/generated-artifacts/ERC1155Proxy.json", | ||||
|         "test/generated-artifacts/ERC20BridgeProxy.json", | ||||
|         "test/generated-artifacts/ERC20Proxy.json", | ||||
|         "test/generated-artifacts/ERC721Proxy.json", | ||||
|         "test/generated-artifacts/Eth2DaiBridge.json", | ||||
|         "test/generated-artifacts/IAssetData.json", | ||||
|         "test/generated-artifacts/IAssetProxy.json", | ||||
|         "test/generated-artifacts/IAssetProxyDispatcher.json", | ||||
|         "test/generated-artifacts/IAuthorizable.json", | ||||
|         "test/generated-artifacts/IChai.json", | ||||
|         "test/generated-artifacts/ICurve.json", | ||||
|         "test/generated-artifacts/IDydx.json", | ||||
|         "test/generated-artifacts/IDydxBridge.json", | ||||
|         "test/generated-artifacts/IERC20Bridge.json", | ||||
|         "test/generated-artifacts/IEth2Dai.json", | ||||
|         "test/generated-artifacts/IKyberNetworkProxy.json", | ||||
|         "test/generated-artifacts/IUniswapExchange.json", | ||||
|         "test/generated-artifacts/IUniswapExchangeFactory.json", | ||||
|         "test/generated-artifacts/KyberBridge.json", | ||||
|         "test/generated-artifacts/MixinAssetProxyDispatcher.json", | ||||
|         "test/generated-artifacts/MixinAuthorizable.json", | ||||
|         "test/generated-artifacts/MultiAssetProxy.json", | ||||
|         "test/generated-artifacts/Ownable.json", | ||||
|         "test/generated-artifacts/StaticCallProxy.json", | ||||
|         "test/generated-artifacts/TestChaiBridge.json", | ||||
|         "test/generated-artifacts/TestDydxBridge.json", | ||||
|         "test/generated-artifacts/TestERC20Bridge.json", | ||||
|         "test/generated-artifacts/TestEth2DaiBridge.json", | ||||
|         "test/generated-artifacts/TestKyberBridge.json", | ||||
|         "test/generated-artifacts/TestStaticCallTarget.json", | ||||
|         "test/generated-artifacts/TestUniswapBridge.json", | ||||
|         "test/generated-artifacts/UniswapBridge.json" | ||||
|     ], | ||||
|     "exclude": ["./deploy/solc/solc_bin"] | ||||
| } | ||||
| @@ -1,6 +0,0 @@ | ||||
| { | ||||
|     "extends": ["@0x/tslint-config"], | ||||
|     "rules": { | ||||
|         "custom-no-magic-numbers": false | ||||
|     } | ||||
| } | ||||
| @@ -1,7 +0,0 @@ | ||||
| { | ||||
|     "extends": "../../typedoc-tsconfig", | ||||
|     "compilerOptions": { | ||||
|         "outDir": "lib" | ||||
|     }, | ||||
|     "include": ["./src/**/*", "./test/**/*"] | ||||
| } | ||||
| @@ -1,10 +0,0 @@ | ||||
| # Blacklist all files | ||||
| .* | ||||
| * | ||||
| # Whitelist lib | ||||
| !lib/**/* | ||||
| # Whitelist Solidity contracts | ||||
| !contracts/src/**/* | ||||
| # Blacklist tests in lib | ||||
| /lib/test/* | ||||
| # Package specific ignore | ||||
| @@ -1,57 +0,0 @@ | ||||
| [ | ||||
|     { | ||||
|         "timestamp": 1582677073, | ||||
|         "version": "1.1.2", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1582623685, | ||||
|         "version": "1.1.1", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "version": "1.1.0", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Added decoders for broker data", | ||||
|                 "pr": 2484 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1581748629 | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1581204851, | ||||
|         "version": "1.0.2", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1580988106, | ||||
|         "version": "1.0.1", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "version": "1.0.0", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Created package", | ||||
|                 "pr": "2455" | ||||
|             } | ||||
|         ] | ||||
|     } | ||||
| ] | ||||
| @@ -1,30 +0,0 @@ | ||||
| <!-- | ||||
| changelogUtils.file is auto-generated using the monorepo-scripts package. Don't edit directly. | ||||
| Edit the package's CHANGELOG.json file only. | ||||
| --> | ||||
|  | ||||
| CHANGELOG | ||||
|  | ||||
| ## v1.1.2 - _February 26, 2020_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v1.1.1 - _February 25, 2020_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v1.1.0 - _February 15, 2020_ | ||||
|  | ||||
|     * Added decoders for broker data (#2484) | ||||
|  | ||||
| ## v1.0.2 - _February 8, 2020_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v1.0.1 - _February 6, 2020_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v1.0.0 - _Invalid date_ | ||||
|  | ||||
|     * Created package (#2455) | ||||
| @@ -1,73 +0,0 @@ | ||||
| ## Broker | ||||
|  | ||||
| This package contains the implementation of the [`Broker` contract](https://github.com/0xProject/ZEIPs/issues/75). This contract serves as an entry-point to the 0x Exchange for the filling of property-based orders. Addresses of the deployed contracts can be found in this 0x [guide](https://0x.org/docs/guides/0x-cheat-sheet) or the [DEPLOYS](./DEPLOYS.json) file within this package. | ||||
|  | ||||
| ## Installation | ||||
|  | ||||
| **Install** | ||||
|  | ||||
| ```bash | ||||
| npm install @0x/contracts-broker --save | ||||
| ``` | ||||
|  | ||||
| ## Bug bounty | ||||
|  | ||||
| A bug bounty for the 3.0 contracts is ongoing! Instructions can be found [here](https://0x.org/docs/guides/bug-bounty-program). | ||||
|  | ||||
| ## Contributing | ||||
|  | ||||
| We strongly recommend that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository. | ||||
|  | ||||
| For proposals regarding the 0x protocol's smart contract architecture, message format, or additional functionality, go to the [0x Improvement Proposals (ZEIPs)](https://github.com/0xProject/ZEIPs) repository and follow the contribution guidelines provided therein. | ||||
|  | ||||
| Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started. | ||||
|  | ||||
| ### Install Dependencies | ||||
|  | ||||
| If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them: | ||||
|  | ||||
| ```bash | ||||
| yarn config set workspaces-experimental true | ||||
| ``` | ||||
|  | ||||
| Then install dependencies | ||||
|  | ||||
| ```bash | ||||
| yarn install | ||||
| ``` | ||||
|  | ||||
| ### Build | ||||
|  | ||||
| To build this package and all other monorepo packages that it depends on, run the following from the monorepo root directory: | ||||
|  | ||||
| ```bash | ||||
| PKG=@0x/contracts-broker yarn build | ||||
| ``` | ||||
|  | ||||
| Or continuously rebuild on change: | ||||
|  | ||||
| ```bash | ||||
| PKG=@0x/contracts-broker yarn watch | ||||
| ``` | ||||
|  | ||||
| ### Clean | ||||
|  | ||||
| ```bash | ||||
| yarn clean | ||||
| ``` | ||||
|  | ||||
| ### Lint | ||||
|  | ||||
| ```bash | ||||
| yarn lint | ||||
| ``` | ||||
|  | ||||
| ### Run Tests | ||||
|  | ||||
| ```bash | ||||
| yarn test | ||||
| ``` | ||||
|  | ||||
| #### Testing options | ||||
|  | ||||
| Contracts testing options like coverage, profiling, revert traces or backing node choosing - are described [here](../TESTING.md). | ||||
| @@ -1,27 +0,0 @@ | ||||
| { | ||||
|     "artifactsDir": "./test/generated-artifacts", | ||||
|     "contractsDir": "./contracts", | ||||
|     "useDockerisedSolc": false, | ||||
|     "isOfflineMode": false, | ||||
|     "shouldSaveStandardInput": true, | ||||
|     "compilerSettings": { | ||||
|         "evmVersion": "istanbul", | ||||
|         "optimizer": { | ||||
|             "enabled": true, | ||||
|             "runs": 1000000, | ||||
|             "details": { "yul": true, "deduplicate": true, "cse": true, "constantOptimizer": true } | ||||
|         }, | ||||
|         "outputSelection": { | ||||
|             "*": { | ||||
|                 "*": [ | ||||
|                     "abi", | ||||
|                     "devdoc", | ||||
|                     "evm.bytecode.object", | ||||
|                     "evm.bytecode.sourceMap", | ||||
|                     "evm.deployedBytecode.object", | ||||
|                     "evm.deployedBytecode.sourceMap" | ||||
|                 ] | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,314 +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.9; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetData.sol"; | ||||
| import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol"; | ||||
| import "@0x/contracts-erc721/contracts/src/interfaces/IERC721Token.sol"; | ||||
| import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol"; | ||||
| import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol"; | ||||
| import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; | ||||
| import "@0x/contracts-extensions/contracts/src/LibAssetDataTransfer.sol"; | ||||
| import "@0x/contracts-extensions/contracts/src/MixinWethUtils.sol"; | ||||
| import "@0x/contracts-utils/contracts/src/LibBytes.sol"; | ||||
| import "@0x/contracts-utils/contracts/src/LibRichErrors.sol"; | ||||
| import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; | ||||
| import "./interfaces/IBroker.sol"; | ||||
| import "./interfaces/IPropertyValidator.sol"; | ||||
| import "./libs/LibBrokerRichErrors.sol"; | ||||
|  | ||||
|  | ||||
| // solhint-disable space-after-comma, var-name-mixedcase | ||||
| contract Broker is | ||||
|     IBroker, | ||||
|     MixinWethUtils | ||||
| { | ||||
|     // Contract addresses | ||||
|  | ||||
|     // Address of the 0x Exchange contract | ||||
|     address internal EXCHANGE; | ||||
|     // Address of the 0x ERC1155 Asset Proxy contract | ||||
|     address internal ERC1155_PROXY; | ||||
|  | ||||
|     // The following storage variables are used to cache data for the duration of the transcation. | ||||
|     // They should always cleared at the end of the transaction. | ||||
|  | ||||
|     // Token IDs specified by the taker to be used to fill property-based orders. | ||||
|     uint256[] internal _cachedTokenIds; | ||||
|     // An index to the above array keeping track of which assets have been transferred. | ||||
|     uint256 internal _cacheIndex; | ||||
|     // The address that called `brokerTrade` or `batchBrokerTrade`. Assets will be transferred to | ||||
|     // and from this address as the effectual taker of the orders. | ||||
|     address internal _sender; | ||||
|  | ||||
|     using LibSafeMath for uint256; | ||||
|     using LibBytes for bytes; | ||||
|     using LibAssetDataTransfer for bytes; | ||||
|  | ||||
|     /// @param exchange Address of the 0x Exchange contract. | ||||
|     /// @param exchange Address of the Wrapped Ether contract. | ||||
|     /// @param exchange Address of the 0x ERC1155 Asset Proxy contract. | ||||
|     constructor ( | ||||
|         address exchange, | ||||
|         address weth | ||||
|     ) | ||||
|         public | ||||
|         MixinWethUtils( | ||||
|             exchange, | ||||
|             weth | ||||
|         ) | ||||
|     { | ||||
|         EXCHANGE = exchange; | ||||
|         ERC1155_PROXY = IExchange(EXCHANGE).getAssetProxy(IAssetData(address(0)).ERC1155Assets.selector); | ||||
|     } | ||||
|  | ||||
|     /// @dev The Broker implements the ERC1155 transfer function to be compatible with the ERC1155 asset proxy | ||||
|     /// @param from Since the Broker serves as the taker of the order, this should equal `address(this)` | ||||
|     /// @param to This should be the maker of the order. | ||||
|     /// @param amounts Should be an array of just one `uint256`, specifying the amount of the brokered assets to transfer. | ||||
|     /// @param data Encodes the validator contract address and any auxiliary data it needs for property validation. | ||||
|     function safeBatchTransferFrom( | ||||
|         address from, | ||||
|         address to, | ||||
|         uint256[] calldata /* ids */, | ||||
|         uint256[] calldata amounts, | ||||
|         bytes calldata data | ||||
|     ) | ||||
|         external | ||||
|     { | ||||
|         // Only the ERC1155 asset proxy contract should be calling this function. | ||||
|         if (msg.sender != ERC1155_PROXY) { | ||||
|             LibRichErrors.rrevert(LibBrokerRichErrors.OnlyERC1155ProxyError( | ||||
|                 msg.sender | ||||
|             )); | ||||
|         } | ||||
|         // Only `takerAssetData` should be using Broker assets | ||||
|         if (from != address(this)) { | ||||
|             LibRichErrors.rrevert( | ||||
|                 LibBrokerRichErrors.InvalidFromAddressError(from) | ||||
|             ); | ||||
|         } | ||||
|         // Only one asset amount should be specified. | ||||
|         if (amounts.length != 1) { | ||||
|             LibRichErrors.rrevert( | ||||
|                 LibBrokerRichErrors.AmountsLengthMustEqualOneError(amounts.length) | ||||
|             ); | ||||
|         } | ||||
|  | ||||
|         uint256 cacheIndex = _cacheIndex; | ||||
|         uint256 remainingAmount = amounts[0]; | ||||
|  | ||||
|         // Verify that there are enough broker assets to transfer | ||||
|         if (_cachedTokenIds.length.safeSub(cacheIndex) < remainingAmount) { | ||||
|             LibRichErrors.rrevert( | ||||
|                 LibBrokerRichErrors.TooFewBrokerAssetsProvidedError(_cachedTokenIds.length) | ||||
|             ); | ||||
|         } | ||||
|  | ||||
|         // Decode validator and params from `data` | ||||
|         (address tokenAddress, address validator, bytes memory propertyData) = abi.decode( | ||||
|             data, | ||||
|             (address, address, bytes) | ||||
|         ); | ||||
|  | ||||
|         while (remainingAmount != 0) { | ||||
|             uint256 tokenId = _cachedTokenIds[cacheIndex]; | ||||
|             cacheIndex++; | ||||
|  | ||||
|             // Validate asset properties | ||||
|             IPropertyValidator(validator).checkBrokerAsset( | ||||
|                 tokenId, | ||||
|                 propertyData | ||||
|             ); | ||||
|  | ||||
|             // Perform the transfer | ||||
|             IERC721Token(tokenAddress).transferFrom( | ||||
|                 _sender, | ||||
|                 to, | ||||
|                 tokenId | ||||
|             ); | ||||
|  | ||||
|             remainingAmount--; | ||||
|         } | ||||
|         // Update cache index in storage | ||||
|         _cacheIndex = cacheIndex; | ||||
|     } | ||||
|  | ||||
|     /// @dev Fills a single property-based order by the given amount using the given assets. | ||||
|     ///      Pays protocol fees using either the ETH supplied by the taker to the transaction or | ||||
|     ///      WETH acquired from the maker during settlement. The final WETH balance is sent to the taker. | ||||
|     /// @param brokeredTokenIds Token IDs specified by the taker to be used to fill the orders. | ||||
|     /// @param order The property-based order to fill. The format of a property-based order is the | ||||
|     ///        same as that of a normal order, except the takerAssetData. Instaed of specifying a | ||||
|     ///        specific ERC721 asset, the takerAssetData should be ERC1155 assetData where the | ||||
|     ///        underlying tokenAddress is this contract's address and the desired properties are | ||||
|     ///        encoded in the extra data field. Also note that takerFees must be denominated in | ||||
|     ///        WETH (or zero). | ||||
|     /// @param takerAssetFillAmount The amount to fill the order by. | ||||
|     /// @param signature The maker's signature of the given order. | ||||
|     /// @param fillFunctionSelector The selector for either `fillOrder` or `fillOrKillOrder`. | ||||
|     /// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients. | ||||
|     /// @param feeRecipients Addresses that will receive ETH when orders are filled. | ||||
|     /// @return fillResults Amounts filled and fees paid by the maker and taker. | ||||
|     function brokerTrade( | ||||
|         uint256[] memory brokeredTokenIds, | ||||
|         LibOrder.Order memory order, | ||||
|         uint256 takerAssetFillAmount, | ||||
|         bytes memory signature, | ||||
|         bytes4 fillFunctionSelector, | ||||
|         uint256[] memory ethFeeAmounts, | ||||
|         address payable[] memory feeRecipients | ||||
|     ) | ||||
|         public | ||||
|         payable | ||||
|         returns (LibFillResults.FillResults memory fillResults) | ||||
|     { | ||||
|         // Cache the taker-supplied asset data | ||||
|         _cachedTokenIds = brokeredTokenIds; | ||||
|         // Cache the sender's address | ||||
|         _sender = msg.sender; | ||||
|  | ||||
|         // Sanity-check the provided function selector | ||||
|         if ( | ||||
|             fillFunctionSelector != IExchange(address(0)).fillOrder.selector && | ||||
|             fillFunctionSelector != IExchange(address(0)).fillOrKillOrder.selector | ||||
|         ) { | ||||
|             LibBrokerRichErrors.InvalidFunctionSelectorError(fillFunctionSelector); | ||||
|         } | ||||
|  | ||||
|         // Pay ETH affiliate fees to all feeRecipient addresses | ||||
|         _transferEthFeesAndWrapRemaining(ethFeeAmounts, feeRecipients); | ||||
|  | ||||
|         // Perform the fill | ||||
|         bytes memory fillCalldata = abi.encodeWithSelector( | ||||
|             fillFunctionSelector, | ||||
|             order, | ||||
|             takerAssetFillAmount, | ||||
|             signature | ||||
|         ); | ||||
|         // solhint-disable-next-line avoid-call-value | ||||
|         (bool didSucceed, bytes memory returnData) = EXCHANGE.call(fillCalldata); | ||||
|         if (didSucceed) { | ||||
|             fillResults = abi.decode(returnData, (LibFillResults.FillResults)); | ||||
|         } else { | ||||
|             // Re-throw error | ||||
|             LibRichErrors.rrevert(returnData); | ||||
|         } | ||||
|  | ||||
|         // Transfer maker asset to taker | ||||
|         if (!order.makerAssetData.equals(WETH_ASSET_DATA)) { | ||||
|             order.makerAssetData.transferOut(fillResults.makerAssetFilledAmount); | ||||
|         } | ||||
|  | ||||
|         // Refund remaining ETH to msg.sender. | ||||
|         _unwrapAndTransferEth(WETH.balanceOf(address(this))); | ||||
|  | ||||
|         _clearStorage(); | ||||
|  | ||||
|         return fillResults; | ||||
|     } | ||||
|  | ||||
|     /// @dev Fills multiple property-based orders by the given amounts using the given assets. | ||||
|     ///      Pays protocol fees using either the ETH supplied by the taker to the transaction or | ||||
|     ///      WETH acquired from the maker during settlement. The final WETH balance is sent to the taker. | ||||
|     /// @param brokeredTokenIds Token IDs specified by the taker to be used to fill the orders. | ||||
|     /// @param orders The property-based orders to fill. The format of a property-based order is the | ||||
|     ///        same as that of a normal order, except the takerAssetData. Instaed of specifying a | ||||
|     ///        specific ERC721 asset, the takerAssetData should be ERC1155 assetData where the | ||||
|     ///        underlying tokenAddress is this contract's address and the desired properties are | ||||
|     ///        encoded in the extra data field. Also note that takerFees must be denominated in | ||||
|     ///        WETH (or zero). | ||||
|     /// @param takerAssetFillAmounts The amounts to fill the orders by. | ||||
|     /// @param signatures The makers' signatures for the given orders. | ||||
|     /// @param batchFillFunctionSelector The selector for either `batchFillOrders`, | ||||
|     ///        `batchFillOrKillOrders`, or `batchFillOrdersNoThrow`. | ||||
|     /// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients. | ||||
|     /// @param feeRecipients Addresses that will receive ETH when orders are filled. | ||||
|     /// @return fillResults Amounts filled and fees paid by the makers and taker. | ||||
|     function batchBrokerTrade( | ||||
|         uint256[] memory brokeredTokenIds, | ||||
|         LibOrder.Order[] memory orders, | ||||
|         uint256[] memory takerAssetFillAmounts, | ||||
|         bytes[] memory signatures, | ||||
|         bytes4 batchFillFunctionSelector, | ||||
|         uint256[] memory ethFeeAmounts, | ||||
|         address payable[] memory feeRecipients | ||||
|     ) | ||||
|         public | ||||
|         payable | ||||
|         returns (LibFillResults.FillResults[] memory fillResults) | ||||
|     { | ||||
|         // Cache the taker-supplied asset data | ||||
|         _cachedTokenIds = brokeredTokenIds; | ||||
|         // Cache the sender's address | ||||
|         _sender = msg.sender; | ||||
|  | ||||
|         // Sanity-check the provided function selector | ||||
|         if ( | ||||
|             batchFillFunctionSelector != IExchange(address(0)).batchFillOrders.selector && | ||||
|             batchFillFunctionSelector != IExchange(address(0)).batchFillOrKillOrders.selector && | ||||
|             batchFillFunctionSelector != IExchange(address(0)).batchFillOrdersNoThrow.selector | ||||
|         ) { | ||||
|             LibBrokerRichErrors.InvalidFunctionSelectorError(batchFillFunctionSelector); | ||||
|         } | ||||
|  | ||||
|         // Pay ETH affiliate fees to all feeRecipient addresses | ||||
|         _transferEthFeesAndWrapRemaining(ethFeeAmounts, feeRecipients); | ||||
|  | ||||
|         // Perform the batch fill | ||||
|         bytes memory batchFillCalldata = abi.encodeWithSelector( | ||||
|             batchFillFunctionSelector, | ||||
|             orders, | ||||
|             takerAssetFillAmounts, | ||||
|             signatures | ||||
|         ); | ||||
|         // solhint-disable-next-line avoid-call-value | ||||
|         (bool didSucceed, bytes memory returnData) = EXCHANGE.call(batchFillCalldata); | ||||
|         if (didSucceed) { | ||||
|             // solhint-disable-next-line indent | ||||
|             fillResults = abi.decode(returnData, (LibFillResults.FillResults[])); | ||||
|         } else { | ||||
|             // Re-throw error | ||||
|             LibRichErrors.rrevert(returnData); | ||||
|         } | ||||
|  | ||||
|         // Transfer maker assets to taker | ||||
|         for (uint256 i = 0; i < orders.length; i++) { | ||||
|             if (!orders[i].makerAssetData.equals(WETH_ASSET_DATA)) { | ||||
|                 orders[i].makerAssetData.transferOut(fillResults[i].makerAssetFilledAmount); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Refund remaining ETH to msg.sender. | ||||
|         _unwrapAndTransferEth(WETH.balanceOf(address(this))); | ||||
|  | ||||
|         _clearStorage(); | ||||
|  | ||||
|         return fillResults; | ||||
|     } | ||||
|  | ||||
|     function _clearStorage() | ||||
|         private | ||||
|     { | ||||
|         delete _cachedTokenIds; | ||||
|         _cacheIndex = 0; | ||||
|         _sender = address(0); | ||||
|     } | ||||
| } | ||||
| @@ -1,101 +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.9; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol"; | ||||
| import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; | ||||
|  | ||||
|  | ||||
| // solhint-disable space-after-comma | ||||
| interface IBroker { | ||||
|  | ||||
|     /// @dev Fills a single property-based order by the given amount using the given assets. | ||||
|     ///      Pays protocol fees using either the ETH supplied by the taker to the transaction or | ||||
|     ///      WETH acquired from the maker during settlement. The final WETH balance is sent to the taker. | ||||
|     /// @param brokeredTokenIds Token IDs specified by the taker to be used to fill the orders. | ||||
|     /// @param order The property-based order to fill. The format of a property-based order is the | ||||
|     ///        same as that of a normal order, except the takerAssetData. Instaed of specifying a | ||||
|     ///        specific ERC721 asset, the takerAssetData should be ERC1155 assetData where the | ||||
|     ///        underlying tokenAddress is this contract's address and the desired properties are | ||||
|     ///        encoded in the extra data field. Also note that takerFees must be denominated in | ||||
|     ///        WETH (or zero). | ||||
|     /// @param takerAssetFillAmount The amount to fill the order by. | ||||
|     /// @param signature The maker's signature of the given order. | ||||
|     /// @param fillFunctionSelector The selector for either `fillOrder` or `fillOrKillOrder`. | ||||
|     /// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients. | ||||
|     /// @param feeRecipients Addresses that will receive ETH when orders are filled. | ||||
|     /// @return fillResults Amounts filled and fees paid by the maker and taker. | ||||
|     function brokerTrade( | ||||
|         uint256[] calldata brokeredTokenIds, | ||||
|         LibOrder.Order calldata order, | ||||
|         uint256 takerAssetFillAmount, | ||||
|         bytes calldata signature, | ||||
|         bytes4 fillFunctionSelector, | ||||
|         uint256[] calldata ethFeeAmounts, | ||||
|         address payable[] calldata feeRecipients | ||||
|     ) | ||||
|         external | ||||
|         payable | ||||
|         returns (LibFillResults.FillResults memory fillResults); | ||||
|  | ||||
|     /// @dev Fills multiple property-based orders by the given amounts using the given assets. | ||||
|     ///      Pays protocol fees using either the ETH supplied by the taker to the transaction or | ||||
|     ///      WETH acquired from the maker during settlement. The final WETH balance is sent to the taker. | ||||
|     /// @param brokeredTokenIds Token IDs specified by the taker to be used to fill the orders. | ||||
|     /// @param orders The property-based orders to fill. The format of a property-based order is the | ||||
|     ///        same as that of a normal order, except the takerAssetData. Instaed of specifying a | ||||
|     ///        specific ERC721 asset, the takerAssetData should be ERC1155 assetData where the | ||||
|     ///        underlying tokenAddress is this contract's address and the desired properties are | ||||
|     ///        encoded in the extra data field. Also note that takerFees must be denominated in | ||||
|     ///        WETH (or zero). | ||||
|     /// @param takerAssetFillAmounts The amounts to fill the orders by. | ||||
|     /// @param signatures The makers' signatures for the given orders. | ||||
|     /// @param batchFillFunctionSelector The selector for either `batchFillOrders`, | ||||
|     ///        `batchFillOrKillOrders`, or `batchFillOrdersNoThrow`. | ||||
|     /// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients. | ||||
|     /// @param feeRecipients Addresses that will receive ETH when orders are filled. | ||||
|     /// @return fillResults Amounts filled and fees paid by the makers and taker. | ||||
|     function batchBrokerTrade( | ||||
|         uint256[] calldata brokeredTokenIds, | ||||
|         LibOrder.Order[] calldata orders, | ||||
|         uint256[] calldata takerAssetFillAmounts, | ||||
|         bytes[] calldata signatures, | ||||
|         bytes4 batchFillFunctionSelector, | ||||
|         uint256[] calldata ethFeeAmounts, | ||||
|         address payable[] calldata feeRecipients | ||||
|     ) | ||||
|         external | ||||
|         payable | ||||
|         returns (LibFillResults.FillResults[] memory fillResults); | ||||
|  | ||||
|     /// @dev The Broker implements the ERC1155 transfer function to be compatible with the ERC1155 asset proxy | ||||
|     /// @param from Since the Broker serves as the taker of the order, this should equal `address(this)` | ||||
|     /// @param to This should be the maker of the order. | ||||
|     /// @param amounts Should be an array of just one `uint256`, specifying the amount of the brokered assets to transfer. | ||||
|     /// @param data Encodes the validator contract address and any auxiliary data it needs for property validation. | ||||
|     function safeBatchTransferFrom( | ||||
|         address from, | ||||
|         address to, | ||||
|         uint256[] calldata /* ids */, | ||||
|         uint256[] calldata amounts, | ||||
|         bytes calldata data | ||||
|     ) | ||||
|         external; | ||||
| } | ||||
| @@ -1,33 +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.9; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
|  | ||||
| interface IGodsUnchained { | ||||
|  | ||||
|     /// @dev Returns the proto and quality for a particular card given its token id | ||||
|     /// @param tokenId The id of the card to query. | ||||
|     /// @return proto The proto of the given card. | ||||
|     /// @return quality The quality of the given card | ||||
|     function getDetails(uint256 tokenId) | ||||
|         external | ||||
|         view | ||||
|         returns (uint16 proto, uint8 quality); | ||||
| } | ||||
| @@ -1,35 +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.9; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
|  | ||||
| interface IPropertyValidator { | ||||
|  | ||||
|     /// @dev Checks that the given asset data satisfies the properties encoded in `propertyData`. | ||||
|     ///      Should revert if the asset does not satisfy the specified properties. | ||||
|     /// @param tokenId The ERC721 tokenId of the asset to check. | ||||
|     /// @param propertyData Encoded properties or auxiliary data needed to perform the check. | ||||
|     function checkBrokerAsset( | ||||
|         uint256 tokenId, | ||||
|         bytes calldata propertyData | ||||
|     ) | ||||
|         external | ||||
|         view; | ||||
| } | ||||
| @@ -1,109 +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.9; | ||||
|  | ||||
|  | ||||
| library LibBrokerRichErrors { | ||||
|  | ||||
|     // bytes4(keccak256("InvalidFromAddressError(address)")) | ||||
|     bytes4 internal constant INVALID_FROM_ADDRESS_ERROR_SELECTOR = | ||||
|         0x906bfb3c; | ||||
|  | ||||
|     // bytes4(keccak256("AmountsLengthMustEqualOneError(uint256)")) | ||||
|     bytes4 internal constant AMOUNTS_LENGTH_MUST_EQUAL_ONE_ERROR_SELECTOR = | ||||
|         0xba9be200; | ||||
|  | ||||
|     // bytes4(keccak256("TooFewBrokerAssetsProvidedError(uint256)")) | ||||
|     bytes4 internal constant TOO_FEW_BROKER_ASSETS_PROVIDED_ERROR_SELECTOR = | ||||
|         0x55272586; | ||||
|  | ||||
|     // bytes4(keccak256("InvalidFunctionSelectorError(bytes4)")) | ||||
|     bytes4 internal constant INVALID_FUNCTION_SELECTOR_ERROR_SELECTOR = | ||||
|         0x540943f1; | ||||
|  | ||||
|     // bytes4(keccak256("OnlyERC1155ProxyError(address)")) | ||||
|     bytes4 internal constant ONLY_ERC_1155_PROXY_ERROR_SELECTOR = | ||||
|         0xccc529af; | ||||
|  | ||||
|     // solhint-disable func-name-mixedcase | ||||
|     function InvalidFromAddressError( | ||||
|         address from | ||||
|     ) | ||||
|         internal | ||||
|         pure | ||||
|         returns (bytes memory) | ||||
|     { | ||||
|         return abi.encodeWithSelector( | ||||
|             INVALID_FROM_ADDRESS_ERROR_SELECTOR, | ||||
|             from | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     function AmountsLengthMustEqualOneError( | ||||
|         uint256 amountsLength | ||||
|     ) | ||||
|         internal | ||||
|         pure | ||||
|         returns (bytes memory) | ||||
|     { | ||||
|         return abi.encodeWithSelector( | ||||
|             AMOUNTS_LENGTH_MUST_EQUAL_ONE_ERROR_SELECTOR, | ||||
|             amountsLength | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     function TooFewBrokerAssetsProvidedError( | ||||
|         uint256 numBrokeredAssets | ||||
|     ) | ||||
|         internal | ||||
|         pure | ||||
|         returns (bytes memory) | ||||
|     { | ||||
|         return abi.encodeWithSelector( | ||||
|             TOO_FEW_BROKER_ASSETS_PROVIDED_ERROR_SELECTOR, | ||||
|             numBrokeredAssets | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     function InvalidFunctionSelectorError( | ||||
|         bytes4 selector | ||||
|     ) | ||||
|         internal | ||||
|         pure | ||||
|         returns (bytes memory) | ||||
|     { | ||||
|         return abi.encodeWithSelector( | ||||
|             INVALID_FUNCTION_SELECTOR_ERROR_SELECTOR, | ||||
|             selector | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     function OnlyERC1155ProxyError( | ||||
|         address sender | ||||
|     ) | ||||
|         internal | ||||
|         pure | ||||
|         returns (bytes memory) | ||||
|     { | ||||
|         return abi.encodeWithSelector( | ||||
|             ONLY_ERC_1155_PROXY_ERROR_SELECTOR, | ||||
|             sender | ||||
|         ); | ||||
|     } | ||||
| } | ||||
| @@ -1,61 +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.9; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "@0x/contracts-utils/contracts/src/LibBytes.sol"; | ||||
| import "../interfaces/IGodsUnchained.sol"; | ||||
| import "../interfaces/IPropertyValidator.sol"; | ||||
|  | ||||
|  | ||||
| contract GodsUnchainedValidator is | ||||
|     IPropertyValidator | ||||
| { | ||||
|     IGodsUnchained internal GODS_UNCHAINED; // solhint-disable-line var-name-mixedcase | ||||
|  | ||||
|     using LibBytes for bytes; | ||||
|  | ||||
|     constructor(address _godsUnchained) | ||||
|         public | ||||
|     { | ||||
|         GODS_UNCHAINED = IGodsUnchained(_godsUnchained); | ||||
|     } | ||||
|  | ||||
|     /// @dev Checks that the given card (encoded as assetData) has the proto and quality encoded in `propertyData`. | ||||
|     ///      Reverts if the card doesn't match the specified proto and quality. | ||||
|     /// @param tokenId The ERC721 tokenId of the card to check. | ||||
|     /// @param propertyData Encoded proto and quality that the card is expected to have. | ||||
|     function checkBrokerAsset( | ||||
|         uint256 tokenId, | ||||
|         bytes calldata propertyData | ||||
|     ) | ||||
|         external | ||||
|         view | ||||
|     { | ||||
|         (uint16 expectedProto, uint8 expectedQuality) = abi.decode( | ||||
|             propertyData, | ||||
|             (uint16, uint8) | ||||
|         ); | ||||
|  | ||||
|         // Validate card properties. | ||||
|         (uint16 proto, uint8 quality) = GODS_UNCHAINED.getDetails(tokenId); | ||||
|         require(proto == expectedProto, "GodsUnchainedValidator/PROTO_MISMATCH"); | ||||
|         require(quality == expectedQuality, "GodsUnchainedValidator/QUALITY_MISMATCH"); | ||||
|     } | ||||
| } | ||||
| @@ -1,55 +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.9; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "@0x/contracts-erc721/contracts/test/DummyERC721Token.sol"; | ||||
| import "../src/interfaces/IGodsUnchained.sol"; | ||||
|  | ||||
|  | ||||
| contract TestGodsUnchained is | ||||
|     IGodsUnchained, | ||||
|     DummyERC721Token | ||||
| { | ||||
|     mapping (uint256 => uint16) internal _protoByTokenId; | ||||
|     mapping (uint256 => uint8) internal _qualityByTokenId; | ||||
|  | ||||
|     constructor ( | ||||
|         string memory _name, | ||||
|         string memory _symbol | ||||
|     ) | ||||
|         public | ||||
|         DummyERC721Token(_name, _symbol) | ||||
|     {} // solhint-disable-line no-empty-blocks | ||||
|  | ||||
|     function setTokenProperties(uint256 tokenId, uint16 proto, uint8 quality) | ||||
|         external | ||||
|     { | ||||
|         _protoByTokenId[tokenId] = proto; | ||||
|         _qualityByTokenId[tokenId] = quality; | ||||
|     } | ||||
|  | ||||
|     function getDetails(uint256 tokenId) | ||||
|         external | ||||
|         view | ||||
|         returns (uint16 proto, uint8 quality) | ||||
|     { | ||||
|         return (_protoByTokenId[tokenId], _qualityByTokenId[tokenId]); | ||||
|     } | ||||
| } | ||||
| @@ -1,96 +0,0 @@ | ||||
| { | ||||
|     "name": "@0x/contracts-broker", | ||||
|     "version": "1.1.2", | ||||
|     "engines": { | ||||
|         "node": ">=6.12" | ||||
|     }, | ||||
|     "description": "Extension of 0x protocol for property-based orders", | ||||
|     "main": "lib/src/index.js", | ||||
|     "directories": { | ||||
|         "test": "test" | ||||
|     }, | ||||
|     "scripts": { | ||||
|         "build": "yarn build:contracts && yarn build:ts", | ||||
|         "build:contracts": "run-s compile contracts:gen generate_contract_wrappers contracts:copy", | ||||
|         "build:ts": "tsc -b", | ||||
|         "build:ci": "yarn build", | ||||
|         "test": "yarn run_mocha", | ||||
|         "rebuild_and_test": "run-s build test", | ||||
|         "test:coverage": "SOLIDITY_COVERAGE=true run-s build run_mocha coverage:report:text coverage:report:lcov", | ||||
|         "test:profiler": "SOLIDITY_PROFILER=true run-s build run_mocha profiler:report:html", | ||||
|         "test:trace": "SOLIDITY_REVERT_TRACE=true run-s build run_mocha", | ||||
|         "run_mocha": "mocha --require source-map-support/register --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit", | ||||
|         "compile": "sol-compiler", | ||||
|         "watch": "sol-compiler -w", | ||||
|         "clean": "shx rm -rf lib test/generated-artifacts test/generated-wrappers generated-artifacts generated-wrappers", | ||||
|         "generate_contract_wrappers": "abi-gen --debug --abis  ${npm_package_config_abis} --output test/generated-wrappers --backend ethers", | ||||
|         "lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./test/generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts", | ||||
|         "coverage:report:text": "istanbul report text", | ||||
|         "coverage:report:html": "istanbul report html && open coverage/index.html", | ||||
|         "profiler:report:html": "istanbul report html && open coverage/index.html", | ||||
|         "coverage:report:lcov": "istanbul report lcov", | ||||
|         "test:circleci": "yarn test", | ||||
|         "contracts:gen": "contracts-gen generate", | ||||
|         "contracts:copy": "contracts-gen copy", | ||||
|         "lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol", | ||||
|         "compile:truffle": "truffle compile", | ||||
|         "docs:md": "ts-doc-gen --sourceDir='$PROJECT_FILES' --output=$MD_FILE_DIR --fileExtension=mdx --tsconfig=./typedoc-tsconfig.json", | ||||
|         "docs:json": "typedoc --excludePrivate --excludeExternals --excludeProtected --ignoreCompilerErrors --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES" | ||||
|     }, | ||||
|     "config": { | ||||
|         "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.", | ||||
|         "abis": "./test/generated-artifacts/@(Broker|GodsUnchainedValidator|IBroker|IGodsUnchained|IPropertyValidator|LibBrokerRichErrors|TestGodsUnchained).json" | ||||
|     }, | ||||
|     "repository": { | ||||
|         "type": "git", | ||||
|         "url": "https://github.com/0xProject/0x-monorepo.git" | ||||
|     }, | ||||
|     "license": "Apache-2.0", | ||||
|     "bugs": { | ||||
|         "url": "https://github.com/0xProject/0x-monorepo/issues" | ||||
|     }, | ||||
|     "homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md", | ||||
|     "devDependencies": { | ||||
|         "@0x/abi-gen": "^5.2.2", | ||||
|         "@0x/contracts-asset-proxy": "^3.2.3", | ||||
|         "@0x/contracts-erc20": "^3.1.3", | ||||
|         "@0x/contracts-erc721": "^3.1.3", | ||||
|         "@0x/contracts-exchange": "^3.2.3", | ||||
|         "@0x/contracts-exchange-libs": "^4.3.3", | ||||
|         "@0x/contracts-gen": "^2.0.8", | ||||
|         "@0x/contracts-test-utils": "^5.3.0", | ||||
|         "@0x/contracts-utils": "^4.4.1", | ||||
|         "@0x/sol-compiler": "^4.0.8", | ||||
|         "@0x/ts-doc-gen": "^0.0.22", | ||||
|         "@0x/tslint-config": "^4.0.0", | ||||
|         "@0x/types": "^3.1.2", | ||||
|         "@0x/web3-wrapper": "^7.0.7", | ||||
|         "@types/lodash": "4.14.104", | ||||
|         "@types/mocha": "^5.2.7", | ||||
|         "@types/node": "*", | ||||
|         "chai": "^4.0.1", | ||||
|         "chai-as-promised": "^7.1.0", | ||||
|         "chai-bignumber": "^3.0.0", | ||||
|         "dirty-chai": "^2.0.1", | ||||
|         "lodash": "^4.17.11", | ||||
|         "make-promises-safe": "^1.1.0", | ||||
|         "mocha": "^6.2.0", | ||||
|         "npm-run-all": "^4.1.2", | ||||
|         "shx": "^0.2.2", | ||||
|         "solhint": "^1.4.1", | ||||
|         "truffle": "^5.0.32", | ||||
|         "tslint": "5.11.0", | ||||
|         "typedoc": "^0.15.0", | ||||
|         "typescript": "3.0.1" | ||||
|     }, | ||||
|     "dependencies": { | ||||
|         "@0x/base-contract": "^6.2.1", | ||||
|         "@0x/order-utils": "^10.2.2", | ||||
|         "@0x/typescript-typings": "^5.0.2", | ||||
|         "@0x/utils": "^5.4.1", | ||||
|         "ethereum-types": "^3.1.0" | ||||
|     }, | ||||
|     "publishConfig": { | ||||
|         "access": "public" | ||||
|     } | ||||
| } | ||||
| @@ -1,23 +0,0 @@ | ||||
| /* | ||||
|  * ----------------------------------------------------------------------------- | ||||
|  * Warning: This file is auto-generated by contracts-gen. Don't edit manually. | ||||
|  * ----------------------------------------------------------------------------- | ||||
|  */ | ||||
| import { ContractArtifact } from 'ethereum-types'; | ||||
|  | ||||
| import * as Broker from '../generated-artifacts/Broker.json'; | ||||
| import * as GodsUnchainedValidator from '../generated-artifacts/GodsUnchainedValidator.json'; | ||||
| import * as IBroker from '../generated-artifacts/IBroker.json'; | ||||
| import * as IGodsUnchained from '../generated-artifacts/IGodsUnchained.json'; | ||||
| import * as IPropertyValidator from '../generated-artifacts/IPropertyValidator.json'; | ||||
| import * as LibBrokerRichErrors from '../generated-artifacts/LibBrokerRichErrors.json'; | ||||
| import * as TestGodsUnchained from '../generated-artifacts/TestGodsUnchained.json'; | ||||
| export const artifacts = { | ||||
|     Broker: Broker as ContractArtifact, | ||||
|     IBroker: IBroker as ContractArtifact, | ||||
|     IGodsUnchained: IGodsUnchained as ContractArtifact, | ||||
|     IPropertyValidator: IPropertyValidator as ContractArtifact, | ||||
|     LibBrokerRichErrors: LibBrokerRichErrors as ContractArtifact, | ||||
|     GodsUnchainedValidator: GodsUnchainedValidator as ContractArtifact, | ||||
|     TestGodsUnchained: TestGodsUnchained as ContractArtifact, | ||||
| }; | ||||
| @@ -1,59 +0,0 @@ | ||||
| import { assetDataUtils } from '@0x/order-utils'; | ||||
| import { ERC1155AssetData } from '@0x/types'; | ||||
| import { AbiEncoder, BigNumber } from '@0x/utils'; | ||||
|  | ||||
| export interface GodsUnchainedProperties { | ||||
|     proto: BigNumber | number; | ||||
|     quality: BigNumber | number; | ||||
| } | ||||
|  | ||||
| const propertyDataEncoder = AbiEncoder.create([{ name: 'proto', type: 'uint16' }, { name: 'quality', type: 'uint8' }]); | ||||
| const brokerDataEncoder = AbiEncoder.create([ | ||||
|     { name: 'godsUnchainedAddress', type: 'address' }, | ||||
|     { name: 'validatorAddress', type: 'address' }, | ||||
|     { name: 'propertyData', type: 'bytes' }, | ||||
| ]); | ||||
|  | ||||
| /** | ||||
|  * Encodes the given proto and quality into the bytes format expected by the GodsUnchainedValidator. | ||||
|  */ | ||||
| export function encodePropertyData(properties: GodsUnchainedProperties): string { | ||||
|     return propertyDataEncoder.encode(properties); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Encodes the given proto and quality into ERC1155 asset data to be used as the takerAssetData | ||||
|  * of a property-based GodsUnchained order. Must also provide the addresses of the Broker, | ||||
|  * GodsUnchained, and GodsUnchainedValidator contracts. The optional bundleSize parameter specifies | ||||
|  * how many cards are expected for each "unit" of the takerAssetAmount. For example, If the | ||||
|  * takerAssetAmount is 3 and the bundleSize is 2, the taker must provide 2, 4, or 6 cards | ||||
|  * with the given proto and quality to fill the order. If an odd number is provided, the fill fails. | ||||
|  */ | ||||
| export function encodeBrokerAssetData( | ||||
|     brokerAddress: string, | ||||
|     godsUnchainedAddress: string, | ||||
|     validatorAddress: string, | ||||
|     properties: GodsUnchainedProperties, | ||||
|     bundleSize: number = 1, | ||||
| ): string { | ||||
|     const propertyData = propertyDataEncoder.encode(properties); | ||||
|     const brokerData = brokerDataEncoder.encode({ godsUnchainedAddress, validatorAddress, propertyData }); | ||||
|     return assetDataUtils.encodeERC1155AssetData(brokerAddress, [], [new BigNumber(bundleSize)], brokerData); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Decodes proto and quality from the bytes format expected by the GodsUnchainedValidator. | ||||
|  */ | ||||
| export function decodePropertyData(propertyData: string): GodsUnchainedProperties { | ||||
|     return propertyDataEncoder.decode(propertyData); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Decodes proto and quality from the ERC1155 takerAssetData of a property-based GodsUnchained order. | ||||
|  */ | ||||
| export function decodeBrokerAssetData(brokerAssetData: string): GodsUnchainedProperties { | ||||
|     // tslint:disable-next-line:no-unnecessary-type-assertion | ||||
|     const { callbackData: brokerData } = assetDataUtils.decodeAssetDataOrThrow(brokerAssetData) as ERC1155AssetData; | ||||
|     const { propertyData } = brokerDataEncoder.decode(brokerData); | ||||
|     return decodePropertyData(propertyData); | ||||
| } | ||||
| @@ -1,32 +0,0 @@ | ||||
| export { artifacts } from './artifacts'; | ||||
| export { BrokerContract, GodsUnchainedValidatorContract, TestGodsUnchainedContract } from './wrappers'; | ||||
| export * from './gods_unchained_utils'; | ||||
| export { BrokerRevertErrors } from '@0x/utils'; | ||||
| export { | ||||
|     ContractArtifact, | ||||
|     ContractChains, | ||||
|     CompilerOpts, | ||||
|     StandardContractOutput, | ||||
|     CompilerSettings, | ||||
|     ContractChainData, | ||||
|     ContractAbi, | ||||
|     DevdocOutput, | ||||
|     EvmOutput, | ||||
|     CompilerSettingsMetadata, | ||||
|     OptimizerSettings, | ||||
|     OutputField, | ||||
|     ParamDescription, | ||||
|     EvmBytecodeOutput, | ||||
|     AbiDefinition, | ||||
|     FunctionAbi, | ||||
|     EventAbi, | ||||
|     RevertErrorAbi, | ||||
|     EventParameter, | ||||
|     DataItem, | ||||
|     MethodAbi, | ||||
|     ConstructorAbi, | ||||
|     FallbackAbi, | ||||
|     ConstructorStateMutability, | ||||
|     TupleDataItem, | ||||
|     StateMutability, | ||||
| } from 'ethereum-types'; | ||||
| @@ -1,12 +0,0 @@ | ||||
| /* | ||||
|  * ----------------------------------------------------------------------------- | ||||
|  * Warning: This file is auto-generated by contracts-gen. Don't edit manually. | ||||
|  * ----------------------------------------------------------------------------- | ||||
|  */ | ||||
| export * from '../generated-wrappers/broker'; | ||||
| export * from '../generated-wrappers/gods_unchained_validator'; | ||||
| export * from '../generated-wrappers/i_broker'; | ||||
| export * from '../generated-wrappers/i_gods_unchained'; | ||||
| export * from '../generated-wrappers/i_property_validator'; | ||||
| export * from '../generated-wrappers/lib_broker_rich_errors'; | ||||
| export * from '../generated-wrappers/test_gods_unchained'; | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user