Compare commits
1428 Commits
@0x/contra
...
@0x/monore
Author | SHA1 | Date | |
---|---|---|---|
|
c60d1e50c5 | ||
|
501f5ad3de | ||
|
9fe6c196ad | ||
|
6d462b0598 | ||
|
3832c66ad0 | ||
|
57028069c0 | ||
|
8d84ac9cf8 | ||
|
17219d22c3 | ||
|
bf4005b0ee | ||
|
d8605ed91d | ||
|
f18e2a09e6 | ||
|
d5c0f5aa47 | ||
|
2825a201cd | ||
|
2d69afec86 | ||
|
851e4bfbea | ||
|
c63745c2ce | ||
|
95f11f2d0e | ||
|
30417fbf24 | ||
|
06f095ca23 | ||
|
30141ca6cf | ||
|
c4b69efdd1 | ||
|
d810aff337 | ||
|
83532fdae7 | ||
|
043534dd56 | ||
|
a90c808fb4 | ||
|
a06c39df9f | ||
|
24c3aefb6f | ||
|
9544d317a0 | ||
|
506d27816e | ||
|
f5a0c87fdc | ||
|
90541f0436 | ||
|
76cac53692 | ||
|
18366bd58d | ||
|
27c039d51c | ||
|
8465be2a03 | ||
|
7d6f49172d | ||
|
d15f4de4ae | ||
|
4098238019 | ||
|
1356237ec9 | ||
|
35daecd5ae | ||
|
bb87c8e7b5 | ||
|
48f7a24505 | ||
|
98c59091ab | ||
|
4ca08adcfa | ||
|
29bcc1b5b7 | ||
|
6e4186adbe | ||
|
38e540ad9f | ||
|
7762b7b665 | ||
|
82ac8e29e3 | ||
|
e074335285 | ||
|
3adbe843da | ||
|
d5c8c076dc | ||
|
1d68c4105a | ||
|
8077123e9f | ||
|
0ff8b12770 | ||
|
39a8c0f4e6 | ||
|
8c5e12d389 | ||
|
71660850af | ||
|
b83043648e | ||
|
b01de802cb | ||
|
e954e9ca20 | ||
|
3f8639bd9c | ||
|
56c956df44 | ||
|
c4b621e44d | ||
|
9a658bf932 | ||
|
d6d506d1c5 | ||
|
2c8f7fac0e | ||
|
072ff65bf9 | ||
|
aa198ad15f | ||
|
745da8e363 | ||
|
be173a9970 | ||
|
8b2b500414 | ||
|
98d1f5405a | ||
|
03595dd1dd | ||
|
6da48be1a4 | ||
|
9b91d574f8 | ||
|
6ca8edbf19 | ||
|
579dba1473 | ||
|
1b5fa15c8c | ||
|
737ad586a5 | ||
|
c051e11a49 | ||
|
a5692690dc | ||
|
98106ca8a2 | ||
|
891d685951 | ||
|
991cbc9f4e | ||
|
8006e4fe3b | ||
|
f17c6b0a83 | ||
|
57ca601be1 | ||
|
b50e26dc2a | ||
|
b728d13d8c | ||
|
1959d149f8 | ||
|
3e2e05caf2 | ||
|
d6a4d67a14 | ||
|
cf8d424b9b | ||
|
a9f1237208 | ||
|
319b4dfd75 | ||
|
d39fcd3475 | ||
|
c7b7f57ab2 | ||
|
a36a5366d3 | ||
|
87615025fe | ||
|
5b0fc813c4 | ||
|
d21f978def | ||
|
a9ecf7f1f3 | ||
|
f5ad65bb8a | ||
|
88dcf6350d | ||
|
6cfc17de35 | ||
|
a2d105593e | ||
|
efd5eff22c | ||
|
9282684d93 | ||
|
c9e03f7d42 | ||
|
690b31c9be | ||
|
cb20f03a92 | ||
|
97eabc6c03 | ||
|
f0e0f08e0c | ||
|
470643ee07 | ||
|
8ba38b9b29 | ||
|
9870f55d24 | ||
|
23b724dde4 | ||
|
3fa922dbab | ||
|
aa7f082d56 | ||
|
b178d025b5 | ||
|
e333ab18c7 | ||
|
b60db6ac72 | ||
|
96c8da9fdd | ||
|
fca883a4aa | ||
|
e60d43110d | ||
|
b9b135cfa2 | ||
|
f925c35344 | ||
|
ca2e9bed27 | ||
|
5b77e2c8ac | ||
|
9e3331d018 | ||
|
4440075425 | ||
|
626948774b | ||
|
25cb1c1138 | ||
|
4a173deb27 | ||
|
245c87f026 | ||
|
22a6de48ae | ||
|
a347c1e848 | ||
|
e4ab832ced | ||
|
d07005dcbe | ||
|
dc06497cae | ||
|
c1871b5bca | ||
|
410b9c50d3 | ||
|
1c42d0ab3c | ||
|
98698f702f | ||
|
4784131dca | ||
|
6eb28b792a | ||
|
57f5b12e24 | ||
|
e5aaf68277 | ||
|
b62486923f | ||
|
322a0a5967 | ||
|
f30c2c4a23 | ||
|
44e5fa5b25 | ||
|
18a86ef234 | ||
|
a6af3744e2 | ||
|
9b40164787 | ||
|
52e8cf1366 | ||
|
1b159f5ccc | ||
|
893ae35296 | ||
|
85e56706bf | ||
|
b8b21cefe3 | ||
|
6d7bf12ade | ||
|
5266816dd6 | ||
|
0c5f0271c7 | ||
|
b65fd06e95 | ||
|
7f51822bfc | ||
|
1acd8d9577 | ||
|
8aa302f6fc | ||
|
f8af5879af | ||
|
a7aa7feff4 | ||
|
b6a96cea23 | ||
|
50b02a4a55 | ||
|
8a2b178e6f | ||
|
7f1afb57b0 | ||
|
0bc4b50818 | ||
|
91de2194eb | ||
|
fef06908ec | ||
|
a012eb0cae | ||
|
08c805a489 | ||
|
5b595dd080 | ||
|
c29a22187c | ||
|
44f6d21e9b | ||
|
ef04248191 | ||
|
1b47c473b4 | ||
|
fe1fea9a2d | ||
|
970f77beb0 | ||
|
2587cd380f | ||
|
04eab19f15 | ||
|
abb2b46ed3 | ||
|
db241e8f90 | ||
|
5bbd57d236 | ||
|
e9f0f4af86 | ||
|
ae75aed55e | ||
|
b359738037 | ||
|
5ce988957f | ||
|
2d77fce99d | ||
|
62663ed6d2 | ||
|
3965d8f8c6 | ||
|
fd35249de8 | ||
|
156560ae22 | ||
|
ee687a7dc4 | ||
|
1710f13242 | ||
|
ef645e601c | ||
|
7de23c6af2 | ||
|
639026ea66 | ||
|
8ddcf88c01 | ||
|
3883297991 | ||
|
196cc4313f | ||
|
9dd8c61a2f | ||
|
6d20f0e987 | ||
|
eac4520406 | ||
|
e4126189df | ||
|
aa4ee2c166 | ||
|
c72a15b488 | ||
|
6a29654d7d | ||
|
3ad7728a0e | ||
|
14c4491b8c | ||
|
2eff213840 | ||
|
2bb9b9a8f7 | ||
|
d064543108 | ||
|
0270777cfc | ||
|
86106713dd | ||
|
d5bbbe802b | ||
|
b43fa88606 | ||
|
54ac1c284b | ||
|
d33080cf08 | ||
|
b4b6d4d969 | ||
|
993f05d5ac | ||
|
ac7f6aef9e | ||
|
7fb5ed0b42 | ||
|
52b0ba5b05 | ||
|
a43b494302 | ||
|
527ec28915 | ||
|
e267a0e855 | ||
|
0196ce18f3 | ||
|
7ef3c12722 | ||
|
38b94ec5f8 | ||
|
fa65452e2b | ||
|
da0f6b5e8f | ||
|
b4929df1e6 | ||
|
03c59fdaf7 | ||
|
f5ab1e6f86 | ||
|
ada1de429c | ||
|
a1aad2e55e | ||
|
d548ddac0d | ||
|
58a5ab4550 | ||
|
6a8242a6ca | ||
|
46b8bfe338 | ||
|
102ca6b854 | ||
|
06b4d241af | ||
|
712b2569e6 | ||
|
294be37afc | ||
|
b57c0a2ebb | ||
|
94909f1a0f | ||
|
9c47d22ff4 | ||
|
e4b9d14f45 | ||
|
73f1aca4a1 | ||
|
bbae6b3de2 | ||
|
e5133a2dd9 | ||
|
ef0096b7d9 | ||
|
29f4d6918a | ||
|
45c7653850 | ||
|
8bdd1d7680 | ||
|
a1ed7183ea | ||
|
7b81af2cb4 | ||
|
a70a3c9600 | ||
|
a14ddbfac2 | ||
|
e1c57cf0af | ||
|
522994262d | ||
|
f681357eeb | ||
|
f9b593da59 | ||
|
a340c817c9 | ||
|
cc67f732e1 | ||
|
e2ee7e6837 | ||
|
49d223f344 | ||
|
314d1b9873 | ||
|
2a391bf947 | ||
|
7a33f68138 | ||
|
48d0b46e43 | ||
|
5fe9edce8c | ||
|
1c038e1f3c | ||
|
a57dd427ca | ||
|
2253f214a6 | ||
|
ad11dc2421 | ||
|
bd3b200b30 | ||
|
0d259d13b9 | ||
|
6fd55b2f49 | ||
|
057aee8ad2 | ||
|
f47feabb4a | ||
|
eb784a4a7c | ||
|
5d30c957cb | ||
|
585adef75d | ||
|
2f07fcc81c | ||
|
1d55d12c8f | ||
|
bca8c5eccc | ||
|
f7462c9f2b | ||
|
549697dc47 | ||
|
2869dd3bac | ||
|
5a225795e1 | ||
|
877abeda63 | ||
|
768387fea9 | ||
|
db97fe8164 | ||
|
be1a70c461 | ||
|
b631fc610b | ||
|
9b2672841d | ||
|
336e8bafb4 | ||
|
2ea354f748 | ||
|
2d125cdc20 | ||
|
0d441a829f | ||
|
ee5cb6909c | ||
|
5258053dc8 | ||
|
bb46f184ed | ||
|
7cc1304eca | ||
|
94738444de | ||
|
4705b15188 | ||
|
de567da846 | ||
|
6641af2a58 | ||
|
de9527ce2f | ||
|
16ebdfad9a | ||
|
b70db37b4f | ||
|
3843c64c40 | ||
|
1d1dd4b6a2 | ||
|
d3a9ace5fd | ||
|
778c57320c | ||
|
f98f3660f9 | ||
|
fd4141e1f3 | ||
|
97c107be3e | ||
|
2eada9db62 | ||
|
e9362439c3 | ||
|
a2419ab31d | ||
|
e589f10e23 | ||
|
5d84d40a2c | ||
|
43d1d0b217 | ||
|
0f802d5a1b | ||
|
56efde6e34 | ||
|
e224e6cde5 | ||
|
e1d51bae73 | ||
|
f9163ccc01 | ||
|
6353bf545d | ||
|
12f0797ace | ||
|
c9de423fb8 | ||
|
2cd0990c65 | ||
|
6fd9308e1b | ||
|
1fc57baac1 | ||
|
2ed63970d4 | ||
|
7ba6c601e5 | ||
|
cc43c5b28c | ||
|
b7f25ee3b6 | ||
|
82afdda256 | ||
|
be83789bee | ||
|
036c8fe920 | ||
|
b7b125f623 | ||
|
060edf33bd | ||
|
656120cd1f | ||
|
34acd71835 | ||
|
7eb4bebac3 | ||
|
f45ee486e9 | ||
|
3b28c9d5a7 | ||
|
2ed39cd18d | ||
|
d8d791e4f0 | ||
|
89bd42de04 | ||
|
51b460d432 | ||
|
6410366f8b | ||
|
1c2f4906e6 | ||
|
bed90fa8ec | ||
|
25787ea806 | ||
|
2a21d87193 | ||
|
7cee17887a | ||
|
0cc94bcf19 | ||
|
a554ae904f | ||
|
9dcda6113d | ||
|
7d50117903 | ||
|
76c5517739 | ||
|
b9d243e70e | ||
|
d37679c129 | ||
|
d01cfee455 | ||
|
182d360302 | ||
|
0d9069ecfe | ||
|
6488f91e6e | ||
|
70db4d8847 | ||
|
faa0d83013 | ||
|
6f1f226ed0 | ||
|
1d6406bbd6 | ||
|
91cee9c648 | ||
|
6d83b2676e | ||
|
c21bce9641 | ||
|
1d5c175316 | ||
|
2fdd4e9760 | ||
|
abd479dc68 | ||
|
67ef17f929 | ||
|
35bf179b70 | ||
|
10c62c10aa | ||
|
8317628c61 | ||
|
30fee43928 | ||
|
494dc475c1 | ||
|
3a503c61b3 | ||
|
86a28f0d19 | ||
|
24af39d4a8 | ||
|
97773e3f64 | ||
|
1dc1218bfc | ||
|
b458026358 | ||
|
b30a33eef5 | ||
|
0e96a1c8ba | ||
|
f477c0fcc2 | ||
|
2ad6dd1ee8 | ||
|
87cfe1a8c6 | ||
|
d0c6d9cf2d | ||
|
fc7f2e7fc6 | ||
|
49baafadc1 | ||
|
24e62feadf | ||
|
67079d96af | ||
|
5ac4c72f1a | ||
|
deceed37f3 | ||
|
4bc84cd526 | ||
|
293c428186 | ||
|
d1b004ffc1 | ||
|
da83f75a13 | ||
|
b5be162fa2 | ||
|
7e5e2241cb | ||
|
c0cb78bb3f | ||
|
eb6ad7d29d | ||
|
88e56356c4 | ||
|
356660ad4f | ||
|
7c3567f5e7 | ||
|
e9eb3badd9 | ||
|
9bbbaadcf8 | ||
|
19f44fac1e | ||
|
0be2c250ef | ||
|
b07fc95c81 | ||
|
20ba23fe5f | ||
|
b78705120e | ||
|
f601329a47 | ||
|
2b3e7e7ab7 | ||
|
8d5e28f099 | ||
|
cb1dc92594 | ||
|
495bf08498 | ||
|
a1a5bdce78 | ||
|
f724212fd7 | ||
|
5ccbe167a1 | ||
|
2e357ffeab | ||
|
af10f52acf | ||
|
ed8a6bb97b | ||
|
c774b98002 | ||
|
9a63bea763 | ||
|
0c6a6743ab | ||
|
1c37334b18 | ||
|
7f40665a0e | ||
|
b10036444d | ||
|
0542c70d22 | ||
|
f71484c9f0 | ||
|
2cf74a7a96 | ||
|
018bcf273f | ||
|
1a3da4b363 | ||
|
0999805b3a | ||
|
7b5e3dab17 | ||
|
a09cd03ce6 | ||
|
c1fc454d19 | ||
|
93c8284a96 | ||
|
e5dcf9063d | ||
|
cf35a8032d | ||
|
88736aa82b | ||
|
90ac5ec577 | ||
|
d1eb414749 | ||
|
f792d403e5 | ||
|
e5706606a0 | ||
|
49725c8c33 | ||
|
dfcc0c6d09 | ||
|
d806701d28 | ||
|
3935e661fe | ||
|
cb8cf1f107 | ||
|
ea8669439f | ||
|
75a8b1c081 | ||
|
73144fa4d5 | ||
|
a6b60f3230 | ||
|
48dfb3317a | ||
|
b3b0496c49 | ||
|
e880447714 | ||
|
fd4d10e7a4 | ||
|
9974e10069 | ||
|
18b65a61ff | ||
|
02a1e17f50 | ||
|
9a3a302754 | ||
|
d131c39e46 | ||
|
8231e7703e | ||
|
406a78a11a | ||
|
fe01a150f0 | ||
|
dd499591e9 | ||
|
c0f1e5f17f | ||
|
b888e48a30 | ||
|
8410ee9d2f | ||
|
b7238c702b | ||
|
a5996b37b2 | ||
|
b20503c5a2 | ||
|
d0869a8840 | ||
|
c156bfc534 | ||
|
5f8e092c96 | ||
|
87c9f9af71 | ||
|
65e5ecf49d | ||
|
63f051a9d2 | ||
|
2c1393fb09 | ||
|
dba0d8469d | ||
|
75e6c45285 | ||
|
e64e0d7421 | ||
|
13d5a5e2ec | ||
|
3432083343 | ||
|
df4282fb34 | ||
|
861aebb2e3 | ||
|
cc7b8359b4 | ||
|
dd0d848530 | ||
|
7f17033ce3 | ||
|
3a4e72bb08 | ||
|
bf3751fd9e | ||
|
05eb646848 | ||
|
5fe231b689 | ||
|
5ee7c2f9dc | ||
|
2c970a0466 | ||
|
c688b11c86 | ||
|
749c0354b3 | ||
|
415af90ae7 | ||
|
365cb161cf | ||
|
a9857fa298 | ||
|
59ae8d4b86 | ||
|
b81f6ba685 | ||
|
16c9d00494 | ||
|
1a833d9dfb | ||
|
bde6278781 | ||
|
e7c4d2171f | ||
|
3a096ff0b4 | ||
|
9feac6708a | ||
|
aabca97b2d | ||
|
9fb933fd06 | ||
|
df039f05c2 | ||
|
d1bed5729d | ||
|
c926a586d2 | ||
|
b7397bbb8f | ||
|
9b957524a5 | ||
|
078b1af04e | ||
|
6827ebfb78 | ||
|
1d807abe8b | ||
|
2c15b3f9bd | ||
|
0d5e037081 | ||
|
dbda3a04b2 | ||
|
98e5b26eb7 | ||
|
cd1fc6a1f0 | ||
|
52ef745f7c | ||
|
961b09977f | ||
|
df8419cd9e | ||
|
71acf2bfa7 | ||
|
1400ceb4e8 | ||
|
793e338dd3 | ||
|
020e7609c3 | ||
|
b1c2f66126 | ||
|
8ef0a59b98 | ||
|
798fb183a5 | ||
|
6bb3992c2f | ||
|
830d6f726e | ||
|
8f8c16bd0e | ||
|
76c0708cf2 | ||
|
5e51233b49 | ||
|
890bfd18fa | ||
|
37cc948741 | ||
|
edb923b8bb | ||
|
44753bb168 | ||
|
7b96fa8d76 | ||
|
ca35eed955 | ||
|
eb6637afd5 | ||
|
a114bbb30e | ||
|
9d38bf731f | ||
|
f32732db1c | ||
|
f41a29ce55 | ||
|
2b1e0be4fc | ||
|
23dd711396 | ||
|
59369cea2a | ||
|
e6b81a824d | ||
|
1dd216b566 | ||
|
27e2a76110 | ||
|
47da97137f | ||
|
2134537bc3 | ||
|
67f91269ee | ||
|
57338059e1 | ||
|
c1ed836fda | ||
|
cd147dbc41 | ||
|
0253bba83b | ||
|
d845b318b9 | ||
|
4b970905cf | ||
|
907771f084 | ||
|
1724ecd4c3 | ||
|
74b9ad5536 | ||
|
4f1525fe27 | ||
|
4dc7956b56 | ||
|
453bf4d195 | ||
|
249948e787 | ||
|
c0acc8dfdf | ||
|
00e87864b1 | ||
|
697e5df52d | ||
|
ba3cd454ba | ||
|
de26925c13 | ||
|
47e00ff1a7 | ||
|
d106051ee3 | ||
|
c939fe2287 | ||
|
41b372ffe6 | ||
|
5826825d11 | ||
|
a765e47dca | ||
|
de8b032df9 | ||
|
f1b1eb3b58 | ||
|
1f334d29ae | ||
|
3279d2a803 | ||
|
cd14d1ef0f | ||
|
9eb676fb46 | ||
|
6c82ebe956 | ||
|
3922d02910 | ||
|
6da70cfa0d | ||
|
15c8e06129 | ||
|
93506a4e27 | ||
|
508e927d63 | ||
|
ee969261b4 | ||
|
2a5742c12d | ||
|
598d70c6dc | ||
|
a49e47f34b | ||
|
ad4d869137 | ||
|
4ef86e6128 | ||
|
470036f6cb | ||
|
835ab6ddd9 | ||
|
b0b387013c | ||
|
3e6cae0ca0 | ||
|
93844343de | ||
|
42430290d5 | ||
|
ce15b4c678 | ||
|
35f4e2fb4f | ||
|
501f6cbab9 | ||
|
a724dd98a9 | ||
|
d5249425af | ||
|
44c44a2b9c | ||
|
eb1c48674a | ||
|
b44ab72557 | ||
|
e6a33dea0e | ||
|
217811d0af | ||
|
ab3246cc71 | ||
|
829533d501 | ||
|
8881118a15 | ||
|
3f2be5b2da | ||
|
9f1904ad3d | ||
|
09843c3cf1 | ||
|
303279a766 | ||
|
f560e7fa96 | ||
|
c97c6d1fc2 | ||
|
b53bf051ac | ||
|
d5189e6143 | ||
|
a934c71ccd | ||
|
5147b6e699 | ||
|
9294bf40a7 | ||
|
a02f96c913 | ||
|
b756e723ea | ||
|
8bc1d5fe3e | ||
|
180417b581 | ||
|
786655843b | ||
|
5e3eeed10f | ||
|
8a2df9cd1f | ||
|
74d9891e06 | ||
|
e0ff859e0d | ||
|
2c7efd0b97 | ||
|
99a0835ecc | ||
|
0bb227a79b | ||
|
84e7357960 | ||
|
9d0b94305a | ||
|
8343105b54 | ||
|
38cad56bf9 | ||
|
8f291c19c3 | ||
|
9566188d6b | ||
|
cae8c2013d | ||
|
9bc5efe958 | ||
|
b36003896f | ||
|
4d2ba9f1e6 | ||
|
56184c6f4f | ||
|
1f64f9eae6 | ||
|
7aeeaae015 | ||
|
03142d82bc | ||
|
78805b1c39 | ||
|
e1a5ba9864 | ||
|
bc0140ef3a | ||
|
36b76550e0 | ||
|
1f2e94b585 | ||
|
e2a2f932f1 | ||
|
6ca2f7e3ac | ||
|
f3309d3651 | ||
|
0b1d955a9f | ||
|
fb75fa4e9a | ||
|
0ba8690120 | ||
|
cafa3c827c | ||
|
bbacce2986 | ||
|
ead2d26025 | ||
|
7d89449f2d | ||
|
b3d1b6c499 | ||
|
7d85e61cc5 | ||
|
362a8c8fc5 | ||
|
6041fb0445 | ||
|
b2a7e0536e | ||
|
2d39454ce1 | ||
|
16de8bf26c | ||
|
bb7cecd7c1 | ||
|
8e41cc7651 | ||
|
55238b9669 | ||
|
316ef69074 | ||
|
8c839b5c22 | ||
|
f98e1d75f4 | ||
|
c57d17dc58 | ||
|
938f4d2d9d | ||
|
307c38bd16 | ||
|
202dcfb4c5 | ||
|
8dd74bcf82 | ||
|
07acdc26ff | ||
|
de307bf25a | ||
|
b6c4f533d2 | ||
|
cbf41e6ade | ||
|
b1d98a4183 | ||
|
30db88d27b | ||
|
fc9d5dee5e | ||
|
bb0ada3f59 | ||
|
804256075e | ||
|
79f28f121b | ||
|
717a19a08e | ||
|
9c8716da09 | ||
|
8293784629 | ||
|
a17f123608 | ||
|
561fe9c3ea | ||
|
e645aa1ee5 | ||
|
7f86d2c5fa | ||
|
fae14a755f | ||
|
1c14948f8a | ||
|
6a902eff56 | ||
|
c6192ea953 | ||
|
36cf4ad304 | ||
|
bcfabf18bc | ||
|
f15693af1d | ||
|
64e42d18e2 | ||
|
e2a76c621b | ||
|
19f6a8dcfe | ||
|
3c4cfe8aee | ||
|
43173c1aac | ||
|
95b284d648 | ||
|
9787cf8296 | ||
|
93b57445b6 | ||
|
c4ca72cf22 | ||
|
13d2cca2bc | ||
|
7fe8eac511 | ||
|
c062458188 | ||
|
3517dd2741 | ||
|
7407890deb | ||
|
e9a4b0758b | ||
|
abf076fc05 | ||
|
c344625d0d | ||
|
14630465dd | ||
|
a497ddfad2 | ||
|
34f6facdee | ||
|
c3bff31cc4 | ||
|
e4475c08e8 | ||
|
75a4d129f7 | ||
|
c659477358 | ||
|
43f38d02ad | ||
|
6b8bc55c74 | ||
|
0c53e2fe46 | ||
|
edef3bc30e | ||
|
0c7f09b832 | ||
|
34d075ce8c | ||
|
8c06d660ea | ||
|
748566b4fb | ||
|
fb38867e78 | ||
|
a2613625c6 | ||
|
89f1d54ebc | ||
|
740913fa20 | ||
|
fd2a240c9f | ||
|
96bef08ac2 | ||
|
1698519a6a | ||
|
d8372f73bc | ||
|
fb6e8a4608 | ||
|
a3f6160898 | ||
|
66f175b659 | ||
|
755ef35955 | ||
|
b5d6156ffa | ||
|
8dd8cf8673 | ||
|
9e46099ced | ||
|
9f4fe259f9 | ||
|
3c169388e2 | ||
|
b9e75769a3 | ||
|
17a9edd8c3 | ||
|
090b83a237 | ||
|
7796c88be3 | ||
|
e5ee794895 | ||
|
2b572cc28f | ||
|
88544ae0ef | ||
|
146d56be84 | ||
|
1934dddcbe | ||
|
f1c51bd0db | ||
|
d91fc59a28 | ||
|
f8025feda2 | ||
|
c9f0c46017 | ||
|
5879aeac52 | ||
|
c73ae579d3 | ||
|
3da55ad836 | ||
|
26bfcccedc | ||
|
af6243afb0 | ||
|
673a341626 | ||
|
a1aee7111a | ||
|
688209e272 | ||
|
116945047b | ||
|
1b8a9e16e2 | ||
|
7ff7e9d2e7 | ||
|
15c0d622c9 | ||
|
25087f3c92 | ||
|
34be9830af | ||
|
0fad6a6ec1 | ||
|
02599c0df8 | ||
|
430d068d78 | ||
|
f09cadb7b3 | ||
|
c366a4bd83 | ||
|
22c8a25a26 | ||
|
4c78b7d4bb | ||
|
8402d211bf | ||
|
cc3be9448a | ||
|
7ac30c5153 | ||
|
64bc99101c | ||
|
09b5018e65 | ||
|
1dae1d244c | ||
|
2da996f493 | ||
|
c5d4559300 | ||
|
434d027133 | ||
|
f66212ce23 | ||
|
6b4e632101 | ||
|
0134b2874b | ||
|
e2308aabed | ||
|
36fac3532c | ||
|
327c6e8ac2 | ||
|
e9d49d96a6 | ||
|
929bb86a54 | ||
|
f58e28d1be | ||
|
cdabe21e7a | ||
|
a7520eeaa8 | ||
|
070147db52 | ||
|
55436510b6 | ||
|
1aec5e455d | ||
|
dc31294440 | ||
|
d3b8070fd6 | ||
|
26e4d66163 | ||
|
7cfceebeb8 | ||
|
0e2616f16b | ||
|
ccce7e001e | ||
|
e91ba07f14 | ||
|
fb7b51d91b | ||
|
88d055c3db | ||
|
3afce213c0 | ||
|
45f229c531 | ||
|
d6772b4a0a | ||
|
5016d50c2b | ||
|
24eaf93db8 | ||
|
2e519b534d | ||
|
31c2b36039 | ||
|
245956c658 | ||
|
0df360c5e8 | ||
|
9b786df828 | ||
|
ae859fa01e | ||
|
7eb64eb3dc | ||
|
f45014f75b | ||
|
74a5c8c23c | ||
|
28e781db15 | ||
|
6ca9d4ee78 | ||
|
52dcd998c4 | ||
|
a8cd168345 | ||
|
b05a2a90d0 | ||
|
242715240b | ||
|
65f17fd76e | ||
|
58ee4447a1 | ||
|
d153ac0951 | ||
|
2e97cfa5e5 | ||
|
7d5276ad11 | ||
|
2251e5e418 | ||
|
e4257fb6c7 | ||
|
f22b03fdb5 | ||
|
dd4541c825 | ||
|
98f77394ed | ||
|
fc18db10be | ||
|
9382e2e8c7 | ||
|
a3b2dbf8e2 | ||
|
6df190edbb | ||
|
5b0b8a9717 | ||
|
a8ddbe4127 | ||
|
6e1fdda182 | ||
|
ca33090793 | ||
|
e34b390c18 | ||
|
370df0d495 | ||
|
d4e300d0a4 | ||
|
c83864af9c | ||
|
14fe3045dc | ||
|
5d54e6c951 | ||
|
921e78c9e2 | ||
|
b1778825cb | ||
|
cc8d5ac93a | ||
|
1d0dce7366 | ||
|
ae454b0892 | ||
|
a2234b745c | ||
|
3dd8dac146 | ||
|
6752fc9fe5 | ||
|
0d05411cd2 | ||
|
7ce65e3cfe | ||
|
ea1501abd1 | ||
|
ca28b8f93e | ||
|
566e74310a | ||
|
c18e8ba242 | ||
|
1f3f0dce11 | ||
|
b73008d83d | ||
|
10a8291391 | ||
|
ab094ab174 | ||
|
29a82f8471 | ||
|
8adfa52ae3 | ||
|
18485dd456 | ||
|
c318b849fe | ||
|
e3aa76cd09 | ||
|
de897d2ebf | ||
|
08118ec36f | ||
|
f757a9de52 | ||
|
6d502b6898 | ||
|
0eff19f0ff | ||
|
b6dfc791d4 | ||
|
7002dc63bd | ||
|
7eedfc201a | ||
|
ac38390241 | ||
|
3156f602dd | ||
|
ad25942731 | ||
|
fddbfc2d32 | ||
|
8c9bdadf66 | ||
|
6345faa4a9 | ||
|
4711ce5532 | ||
|
293510c087 | ||
|
a179a6892c | ||
|
afb310e90a | ||
|
51391b7f0e | ||
|
264b1d69d9 | ||
|
884b1add8e | ||
|
8c05a92a1e | ||
|
f791cd3a37 | ||
|
4600a656d1 | ||
|
d03f13a729 | ||
|
5a088690b2 | ||
|
8d26f58dfa | ||
|
a3cdb63ae1 | ||
|
9d5b23acd3 | ||
|
41e04c0178 | ||
|
abaa0cf3d0 | ||
|
8670fbe2ae | ||
|
898213bb85 | ||
|
c30d59d5d3 | ||
|
c54d69e5ae | ||
|
38a1f08413 | ||
|
e2bd80253b | ||
|
039cc6e28b | ||
|
1030c96eec | ||
|
0851c5ac8e | ||
|
92d112083e | ||
|
1e462f5cc0 | ||
|
d974ee169a | ||
|
7fb87d4039 | ||
|
fc5963fa3d | ||
|
cfa362321d | ||
|
72c7157138 | ||
|
2f91a12f19 | ||
|
abe72b7745 | ||
|
e7df9d1754 | ||
|
d3ab2b077a | ||
|
467a11f4b4 | ||
|
6cb8c1df42 | ||
|
3915c7e8f2 | ||
|
5ba0e0dc54 | ||
|
9a35e2db77 | ||
|
e204a6d1d0 | ||
|
47ab2a1b1d | ||
|
6fc38292f2 | ||
|
89d8df3385 | ||
|
9c7df2b41e | ||
|
46f6816511 | ||
|
858ccfa934 | ||
|
b4a3218b13 | ||
|
92a4556956 | ||
|
bd42c33daa | ||
|
e1796a9f0f | ||
|
8c5c81fe70 | ||
|
bf8fae2025 | ||
|
7f2b715ceb | ||
|
974189045a | ||
|
77feaec444 | ||
|
e5b6921de9 | ||
|
3ca3a2820d | ||
|
9f4933e33d | ||
|
3cf48a831b | ||
|
930b742663 | ||
|
d3870fed1c | ||
|
99e242affd | ||
|
9792246970 | ||
|
020b953166 | ||
|
52aa8e914a | ||
|
e01eadaecd | ||
|
61fc32b7c0 | ||
|
a9c8207bb0 | ||
|
eac4f172fe | ||
|
d6271426fd | ||
|
7e59110049 | ||
|
8cf4fb9adc | ||
|
f044f364cb | ||
|
4d39892a11 | ||
|
bf1ebe8e53 | ||
|
77b4f32274 | ||
|
b2ada13a21 | ||
|
03fced81f5 | ||
|
f9292a8fb8 | ||
|
065f46a020 | ||
|
6efb7027b5 | ||
|
f4f922acb5 | ||
|
4a4d2e7079 | ||
|
1634c90179 | ||
|
9b5ba6806f | ||
|
4afca6ca8d | ||
|
90d1decb87 | ||
|
1d8cb1b107 | ||
|
65e3d9873d | ||
|
50b22c673e | ||
|
4ef8b7f733 | ||
|
e0ec26255b | ||
|
ffa32f7610 | ||
|
1c1d257bd9 | ||
|
5611cb91a0 | ||
|
e0cff4b74e | ||
|
c1985e6986 | ||
|
416b1aee98 | ||
|
7bb9d8b03a | ||
|
0473c82029 | ||
|
63bd1a4a22 | ||
|
5a64759c83 | ||
|
0df68a6e06 | ||
|
29eff3b515 | ||
|
073976de10 | ||
|
1fe159f432 | ||
|
adad7f4e3f | ||
|
378710533e | ||
|
d966848ef8 | ||
|
d6d613ca37 | ||
|
1a385de367 | ||
|
73eb56c072 | ||
|
9651941cce | ||
|
29be79814f | ||
|
1ea220f44f | ||
|
6cf11554de | ||
|
f289b3112b | ||
|
c61df50167 | ||
|
df5ec33330 | ||
|
6384518ee1 | ||
|
87bf940f89 | ||
|
53db047a4e | ||
|
dabef47ce7 | ||
|
4de1d69282 | ||
|
015c35f2b2 | ||
|
5a491b2624 | ||
|
3d95817dbe | ||
|
96ab74dea4 | ||
|
f937a0b038 | ||
|
da38285046 | ||
|
d3db2dcfbb | ||
|
c788db785b | ||
|
6df41d2562 | ||
|
74fb43998e | ||
|
c1f8eabd12 | ||
|
2f5a1eebe0 | ||
|
4791c120fe | ||
|
f6d445b553 | ||
|
db3dd4ae5a | ||
|
d6ba03916a | ||
|
4734acbe61 | ||
|
527256b416 | ||
|
7a0dc7a364 | ||
|
7f88e8ad6e | ||
|
c7324121ed | ||
|
588ca3a315 | ||
|
eb9b2f355e | ||
|
cf6144599d | ||
|
c23bb5e589 | ||
|
0eb5c825a5 | ||
|
5dfb65b084 | ||
|
ddbe2acbf5 | ||
|
2ff3735adc | ||
|
c2752d5931 | ||
|
309dd7f300 | ||
|
33df11b755 | ||
|
bd5babf65d | ||
|
3c07cbde47 | ||
|
dee5ff852d | ||
|
073930004d | ||
|
01574c5a87 | ||
|
3a49369e68 | ||
|
42f7b7cc19 | ||
|
5f8ebc3601 | ||
|
2e5645108b | ||
|
d73f7beb2f | ||
|
4f6f126952 | ||
|
0099cdd6ad | ||
|
2b7114b704 | ||
|
2041d0d000 | ||
|
698f313b73 | ||
|
1940458306 | ||
|
983def2bbd | ||
|
9213bf47ae | ||
|
f01743e27c | ||
|
9be58972a0 | ||
|
a1a6c3e40c | ||
|
a2b19a1b9d | ||
|
4d1a942e79 | ||
|
eb4afa8f2c | ||
|
468bbea44d | ||
|
b75aa02b0d | ||
|
a39f93bcff | ||
|
e229d2d59f | ||
|
3d58dc2a50 | ||
|
0395188aed | ||
|
4e6dd1b213 | ||
|
a46b13967a | ||
|
e916daf5fd | ||
|
fad9dae9bb | ||
|
83bd5f5561 | ||
|
0ddb9f8923 | ||
|
03ea97734c | ||
|
b7adf59ed5 | ||
|
666b992c51 | ||
|
56d5e9c889 | ||
|
aa36ebf4f2 | ||
|
de60123ec7 | ||
|
cf3790c2f8 | ||
|
b7bac3abf6 | ||
|
f4551dd1e5 | ||
|
b3da4bb5b7 | ||
|
6e4b6929d2 | ||
|
a0602c8863 | ||
|
55246c5d87 | ||
|
81ee577407 | ||
|
55e1045000 | ||
|
fc96df63fd | ||
|
9b787a6bc2 | ||
|
201dc7c28d | ||
|
5189fa6483 | ||
|
1992478cee | ||
|
5ad6b48289 | ||
|
bbcf83b99d | ||
|
9ef55023f2 | ||
|
f2f81b0f7b | ||
|
c22ed861d1 | ||
|
39bed4d306 | ||
|
949946589f | ||
|
09d970f056 | ||
|
5813bb9ca8 | ||
|
c48ad5c90f | ||
|
4fdc1b3e19 | ||
|
dc372a43fe | ||
|
589b791cd7 | ||
|
564dbea126 | ||
|
1bc4bc613e | ||
|
11a25cb1ae | ||
|
d6c1bf691c | ||
|
e6443a2612 | ||
|
d79714a3cf | ||
|
4bb1312cf1 | ||
|
4e2abcaefa | ||
|
d463d4c46b | ||
|
435c81da98 | ||
|
4f818d55fa | ||
|
c96a81e319 | ||
|
7cff9ba86a | ||
|
6ddaa6f52a | ||
|
238877b627 | ||
|
95e7999e45 | ||
|
2f464ee8f0 | ||
|
8fe9883b62 | ||
|
de896f9159 | ||
|
a2468e8129 | ||
|
ee89f74afd | ||
|
cd08c3e8fa | ||
|
9cc8933eec | ||
|
91c27ff972 | ||
|
07e3ba014c | ||
|
57ac0ca6e8 | ||
|
816368b1fe | ||
|
85ea291745 | ||
|
741fdfa52e | ||
|
348ec5bc3c | ||
|
df9698ab1f | ||
|
c1aead970a | ||
|
518f351235 | ||
|
d79a07e2c4 | ||
|
b636057251 | ||
|
c692c8f055 | ||
|
930736060c | ||
|
1c8468d248 | ||
|
575842eab4 | ||
|
f7f55cad43 | ||
|
acd857a8c0 | ||
|
53ff248176 | ||
|
3de13967bc | ||
|
aebb923c2d | ||
|
76d577a08d | ||
|
3fb34a2a83 | ||
|
cdb938ea28 | ||
|
882dd4597e | ||
|
409efb8c67 | ||
|
eaa4373a18 | ||
|
d480f8d82a | ||
|
339fc9ff14 | ||
|
14167412e0 | ||
|
7c0f075d1f | ||
|
f4aea76c6e | ||
|
d263382365 | ||
|
2109ed8464 | ||
|
d11444b983 | ||
|
0508a45681 | ||
|
a5c0b95f8b | ||
|
f1af12b3b9 | ||
|
9d257497bd | ||
|
79f40b4ce0 | ||
|
1ab62b7a80 | ||
|
d2f10d5834 | ||
|
c326ec9d1e | ||
|
26317d16ff | ||
|
79b8f85cdf | ||
|
c84a0b8415 | ||
|
be5336d074 | ||
|
aecb2efad9 | ||
|
3654005c3d | ||
|
d8fd61955c | ||
|
3381ab5093 | ||
|
8c2fa64c47 | ||
|
12ae9fced5 | ||
|
e3bca7e7e7 | ||
|
bca199e118 | ||
|
938ae5f27c | ||
|
8aa3b535f0 | ||
|
f4bf4ee0f2 | ||
|
1c1ab3cd87 | ||
|
f5c215fe65 | ||
|
9952de615a | ||
|
e1c547be98 | ||
|
7cb6795d40 | ||
|
a5f4478e20 | ||
|
94d0db2dba | ||
|
64c596c922 | ||
|
e30b8999d4 | ||
|
2f0ee84b71 | ||
|
c570478aaa | ||
|
051997acb0 | ||
|
51ef0e1e6d | ||
|
ed0fcf2829 | ||
|
2ce94b73ad | ||
|
ef96bff6ec | ||
|
afc888f2ef | ||
|
e823c2af9d | ||
|
18979f3f30 | ||
|
8bd29596c4 | ||
|
0cfcb6aa37 | ||
|
6b40812e6d | ||
|
8af253e9ab | ||
|
6763bce627 | ||
|
3217c1e11f | ||
|
6ce3e18831 | ||
|
3e461ac2e5 | ||
|
25e2baaea7 | ||
|
6696a714f0 | ||
|
46af2ffcea | ||
|
e5b3a82112 | ||
|
9af51aaca1 | ||
|
3bacf09710 | ||
|
61bdbd2d74 | ||
|
a1293f160f | ||
|
847503bff1 | ||
|
576242551f | ||
|
fdb6bee65f | ||
|
a2846faa61 | ||
|
a32544b53a | ||
|
9b093dab0a | ||
|
84d433fa06 | ||
|
e24b8947e0 | ||
|
7835c6e20c | ||
|
d942c47f08 | ||
|
fdaee1375c | ||
|
d25a510291 | ||
|
0cb8586f68 | ||
|
e42a0979bc | ||
|
f1a78682aa | ||
|
dc4bfde76d | ||
|
e717625f86 | ||
|
41444e7ede | ||
|
ac9247195b | ||
|
fc2a59ceaa | ||
|
72f4b216c1 | ||
|
d373f5488a | ||
|
24906138c7 | ||
|
f4b3b69b2f | ||
|
e80abad19a | ||
|
c9c228ffdd | ||
|
6fc30d31bf | ||
|
0bcd47b394 | ||
|
c24bb139dd | ||
|
eb00ff05a8 | ||
|
a7fe47f295 | ||
|
2a6f02c764 | ||
|
1b2ff1f9ae | ||
|
7de9a36d01 | ||
|
cfa8796b18 | ||
|
3c88ede02c | ||
|
a0223835b8 | ||
|
ac18359410 | ||
|
8194e3d3c5 | ||
|
440c4fe9b9 | ||
|
e54f5d563f | ||
|
5781ab5436 | ||
|
f8009dbb27 | ||
|
15efe3ae31 | ||
|
991348bbbe | ||
|
233336ea16 | ||
|
20d8c1b51a | ||
|
06499f2155 | ||
|
5b1d9396d7 | ||
|
633c5d5938 | ||
|
2e846159a8 | ||
|
4408604c2d | ||
|
15db5c8059 | ||
|
53121b1dd4 | ||
|
c36dff6354 | ||
|
94a91ed5c8 | ||
|
162a812189 | ||
|
f06f0785f1 | ||
|
1aae68c614 | ||
|
703a0fde3c | ||
|
abb71cd074 | ||
|
79cf9156eb | ||
|
3a6664282c | ||
|
e00ac37cb2 | ||
|
6583ac9ba1 | ||
|
42963ea77d | ||
|
6231724f49 | ||
|
5b25eb4fbd | ||
|
565cc7b3c8 | ||
|
71dc2690aa | ||
|
3accd48ea8 | ||
|
ed78bde359 | ||
|
ff1a3ab307 | ||
|
26643a489b | ||
|
5955a541a3 | ||
|
995669cccd | ||
|
371dc347cc | ||
|
9a162e5d5c | ||
|
9319f362bb | ||
|
8305168bc4 | ||
|
e8ecbe32ca | ||
|
bc5c5050fb | ||
|
8a9b9c55ce | ||
|
d40f343d2a | ||
|
4954d0a018 | ||
|
7232bef07b | ||
|
7277fb3d93 | ||
|
34e0345b29 | ||
|
f094e9118c | ||
|
63e93d9253 | ||
|
2ec0d421f7 | ||
|
8ddc890e10 | ||
|
095c899913 | ||
|
e0d6a3fd1d | ||
|
308ff15adc | ||
|
c195629a77 | ||
|
6af5a67a17 | ||
|
0b38289703 | ||
|
041bf9b54e | ||
|
5a6cf2b690 | ||
|
2e44bb6085 | ||
|
b8f056b82f | ||
|
259b463b73 | ||
|
4aae7348d1 | ||
|
665942a8c9 | ||
|
dc9a26ae8a | ||
|
55f3322576 | ||
|
376f068719 | ||
|
3688956ee5 | ||
|
53b1037a33 | ||
|
2b5cd02bd9 | ||
|
e5fed57b8b | ||
|
a0b1f3efa2 | ||
|
f7fb1225d2 | ||
|
b380952ff9 | ||
|
2524e7eea3 | ||
|
32460f00f8 | ||
|
d58d7f457d | ||
|
232a43f34f | ||
|
94f5a039d2 | ||
|
7a4ae74727 | ||
|
1295de4c78 | ||
|
77ed54f64d | ||
|
e51b425200 | ||
|
e6aff19a0c | ||
|
bd06c7b343 | ||
|
c096eae644 | ||
|
f77823ee24 | ||
|
35f568e346 | ||
|
2d28fde24d | ||
|
92fe720ac3 | ||
|
74a9a13564 | ||
|
7aaef5d807 | ||
|
64b4158bad | ||
|
4bbaa6b41c | ||
|
964d8171dd | ||
|
5b1cbbf157 | ||
|
db4c29a73c | ||
|
4f73008d95 | ||
|
1b73cb28f1 | ||
|
367c981642 | ||
|
3d30eb0748 | ||
|
34ffdad521 | ||
|
4f82c0c289 | ||
|
fd68746dd7 | ||
|
bec7d1265b | ||
|
620eb2a3be | ||
|
e6971c45c8 | ||
|
961cd0825c | ||
|
a1cb702ecb | ||
|
befc14c980 | ||
|
ff0ad53c11 | ||
|
cf0e57d7ce | ||
|
9883e3ed2e |
@@ -23,37 +23,21 @@ jobs:
|
||||
# command: npm set prefix=/home/circleci/npm && echo 'export PATH=$HOME/circleci/npm/bin:$PATH' >> /home/circleci/.bashrc
|
||||
- run:
|
||||
name: install-yarn
|
||||
command: npm install --global yarn@1.9.4
|
||||
command: npm install --global yarn@1.17.0
|
||||
- run:
|
||||
name: yarn
|
||||
command: yarn --frozen-lockfile --ignore-engines install || yarn --frozen-lockfile --ignore-engines install
|
||||
- setup_remote_docker
|
||||
- run: yarn build:ci:no_website
|
||||
- run: yarn build:ci
|
||||
- run: yarn build:ts
|
||||
- save_cache:
|
||||
key: repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- ~/repo
|
||||
- save_cache:
|
||||
key: python-contract-wrappers-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- ~/repo/packages/python-contract-wrappers/generated
|
||||
- store_artifacts:
|
||||
path: ~/repo/packages/python-contract-wrappers/generated
|
||||
- store_artifacts:
|
||||
path: ~/repo/packages/abi-gen/test-cli/output
|
||||
- store_artifacts:
|
||||
path: ~/repo/packages/abi-gen-wrappers/generated_docs
|
||||
build-website:
|
||||
resource_class: medium+
|
||||
docker:
|
||||
- image: nikolaik/python-nodejs:python3.7-nodejs8
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run: cd packages/website && yarn build:prod
|
||||
test-contracts-ganache:
|
||||
resource_class: medium+
|
||||
docker:
|
||||
@@ -63,19 +47,31 @@ jobs:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run: yarn wsrun test:circleci @0x/contracts-multisig @0x/contracts-utils @0x/contracts-exchange-libs @0x/contracts-erc20 @0x/contracts-erc721 @0x/contracts-erc1155 @0x/contracts-extensions @0x/contracts-asset-proxy @0x/contracts-exchange @0x/contracts-exchange-forwarder @0x/contracts-coordinator @0x/contracts-dev-utils
|
||||
test-contracts-geth:
|
||||
- run: yarn wsrun test:circleci @0x/contracts-multisig @0x/contracts-utils @0x/contracts-exchange-libs @0x/contracts-erc20 @0x/contracts-erc721 @0x/contracts-erc1155 @0x/contracts-extensions @0x/contracts-asset-proxy @0x/contracts-exchange @0x/contracts-exchange-forwarder @0x/contracts-coordinator @0x/contracts-dev-utils @0x/contracts-staking
|
||||
test-exchange-ganache-3.0:
|
||||
resource_class: medium+
|
||||
docker:
|
||||
- image: nikolaik/python-nodejs:python3.7-nodejs8
|
||||
- image: 0xorg/devnet
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
# HACK(albrow): we need to sleep 10 seconds to ensure the devnet is
|
||||
# initialized
|
||||
- run: sleep 10 && TEST_PROVIDER=geth yarn wsrun test:circleci @0x/contracts-multisig @0x/contracts-utils @0x/contracts-exchange-libs @0x/contracts-erc20 @0x/contracts-erc721 @0x/contracts-erc1155 @0x/contracts-extensions @0x/contracts-asset-proxy @0x/contracts-exchange @0x/contracts-exchange-forwarder @0x/contracts-coordinator @0x/contracts-dev-utils
|
||||
- run: yarn wsrun test:circleci @0x/contracts-exchange
|
||||
test-contracts-rest-ganache-3.0:
|
||||
resource_class: medium+
|
||||
docker:
|
||||
- image: nikolaik/python-nodejs:python3.7-nodejs8
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run: yarn wsrun test:circleci @0x/contracts-multisig @0x/contracts-utils @0x/contracts-exchange-libs @0x/contracts-erc20 @0x/contracts-erc721 @0x/contracts-erc1155 @0x/contracts-asset-proxy @0x/contracts-exchange-forwarder @0x/contracts-dev-utils @0x/contracts-staking
|
||||
# TODO(dorothy-zbornak): Re-enable after updating this package for 3.0.
|
||||
# - run: yarn wsrun test:circleci @0x/contracts-extensions
|
||||
# TODO(abandeali): Re-enable after this package is complete.
|
||||
# - run: yarn wsrun test:circleci @0x/contracts-coordinator
|
||||
test-publish:
|
||||
resource_class: medium+
|
||||
docker:
|
||||
@@ -86,7 +82,9 @@ jobs:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run: yarn test:publish:circleci
|
||||
- run:
|
||||
command: yarn test:publish:circleci
|
||||
no_output_timeout: 1800
|
||||
test-doc-generation:
|
||||
docker:
|
||||
- image: nikolaik/python-nodejs:python3.7-nodejs8
|
||||
@@ -95,7 +93,9 @@ jobs:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run: yarn test:generate_docs:circleci
|
||||
- run:
|
||||
command: yarn test:generate_docs:circleci
|
||||
no_output_timeout: 1200
|
||||
test-rest:
|
||||
docker:
|
||||
- image: nikolaik/python-nodejs:python3.7-nodejs8
|
||||
@@ -106,11 +106,13 @@ jobs:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run: yarn wsrun test:circleci @0x/contracts-test-utils
|
||||
- run: yarn wsrun test:circleci @0x/abi-gen
|
||||
- run: yarn wsrun test:circleci @0x/asset-buyer
|
||||
# TODO (xianny): Needs to be updated for 3.0
|
||||
# - run: yarn wsrun test:circleci @0x/asset-buyer
|
||||
- run: yarn wsrun test:circleci @0x/contract-artifacts
|
||||
- run: yarn wsrun test:circleci @0x/assert
|
||||
- run: yarn wsrun test:circleci @0x/base-contract
|
||||
- run: yarn wsrun test:circleci @0x/connect
|
||||
# TODO (xianny): Needs to be updated for 3.0
|
||||
# - run: yarn wsrun test:circleci @0x/connect
|
||||
- run: yarn wsrun test:circleci @0x/contract-wrappers
|
||||
- run: yarn wsrun test:circleci @0x/dev-utils
|
||||
- run: yarn wsrun test:circleci @0x/json-schemas
|
||||
@@ -195,7 +197,8 @@ jobs:
|
||||
- restore_cache:
|
||||
key: installed-py-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
key: python-contract-wrappers-{{ .Environment.CIRCLE_SHA1 }}
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run:
|
||||
command: |
|
||||
cd python-packages
|
||||
@@ -237,9 +240,7 @@ jobs:
|
||||
paths:
|
||||
- ~/repo/python-packages/sra_client/.coverage
|
||||
- store_artifacts:
|
||||
path: ~/repo/python-packages/contract_wrappers/src/zero_ex/contract_wrappers/erc20_token/__init__.py
|
||||
- store_artifacts:
|
||||
path: ~/repo/python-packages/contract_wrappers/src/zero_ex/contract_wrappers/exchange/__init__.py
|
||||
path: ~/repo/python-packages/contract_wrappers/src/zero_ex/contract_wrappers/*/__init__.py
|
||||
- store_artifacts:
|
||||
path: ~/repo/python-packages/contract_addresses/build
|
||||
- store_artifacts:
|
||||
@@ -289,7 +290,8 @@ jobs:
|
||||
- restore_cache:
|
||||
key: installed-py-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
key: python-contract-wrappers-{{ .Environment.CIRCLE_SHA1 }}
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run:
|
||||
command: |
|
||||
python -m ensurepip
|
||||
@@ -298,6 +300,7 @@ jobs:
|
||||
./install
|
||||
./lint
|
||||
static-tests:
|
||||
resource_class: large
|
||||
working_directory: ~/repo
|
||||
docker:
|
||||
- image: nikolaik/python-nodejs:python3.7-nodejs8
|
||||
@@ -308,6 +311,7 @@ jobs:
|
||||
- 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
|
||||
submit-coverage:
|
||||
@@ -387,17 +391,12 @@ workflows:
|
||||
main:
|
||||
jobs:
|
||||
- build
|
||||
- build-website:
|
||||
- test-exchange-ganache-3.0:
|
||||
requires:
|
||||
- build
|
||||
- test-contracts-ganache:
|
||||
- test-contracts-rest-ganache-3.0:
|
||||
requires:
|
||||
- build
|
||||
# TODO(albrow): Tests always fail on Geth right now because our fork
|
||||
# is outdated. Uncomment once we have updated our Geth fork.
|
||||
# - test-contracts-geth:
|
||||
# requires:
|
||||
# - build
|
||||
- test-rest:
|
||||
requires:
|
||||
- build
|
||||
@@ -412,13 +411,16 @@ workflows:
|
||||
- build
|
||||
- submit-coverage:
|
||||
requires:
|
||||
- test-contracts-rest-ganache-3.0
|
||||
- test-exchange-ganache-3.0
|
||||
- test-rest
|
||||
- test-python
|
||||
- static-tests-python:
|
||||
requires:
|
||||
- test-python
|
||||
- test-python:
|
||||
requires:
|
||||
- build
|
||||
- static-tests
|
||||
# - test-python:
|
||||
# requires:
|
||||
# - build
|
||||
# - test-rest
|
||||
# - static-tests-python:
|
||||
# requires:
|
||||
# - test-python
|
||||
# skip python tox run for now, as we don't yet have multiple test environments to support.
|
||||
#- test-rest-python
|
||||
# - test-rest-python
|
||||
|
3
.github/autolabeler.yml
vendored
3
.github/autolabeler.yml
vendored
@@ -13,7 +13,6 @@ contracts: ['contracts']
|
||||
@0x/instant: ['packages/instant']
|
||||
@0x/abi-gen-templates: ['packages/abi-gen-templates']
|
||||
@0x/abi-gen: ['packages/abi-gen']
|
||||
@0x/website: ['packages/website']
|
||||
@0x/sol-coverage: ['packages/sol-coverage']
|
||||
@0x/sol-profiler: ['packages/sol-profiler']
|
||||
@0x/sol-trace: ['packages/sol-trace']
|
||||
@@ -33,7 +32,5 @@ contracts: ['contracts']
|
||||
@0x/json-schemas: ['packages/json-schemas']
|
||||
@0x/ethereum-types: ['ethereum-types']
|
||||
@0x/connect: ['packages/connect']
|
||||
@0x/fill-scenarios: ['packages/fill-scenarios']
|
||||
@0x/dev-tools-pages: ['packages/dev-tools-pages']
|
||||
@0x/testnet-faucets: ['packages/testnet-faucets']
|
||||
@0x/monorepo-scripts: ['packages/monorepo-scripts']
|
||||
|
37
.gitignore
vendored
37
.gitignore
vendored
@@ -40,9 +40,12 @@ build/Release
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# Typescript v1 declaration files
|
||||
# TypeScript v1 declaration files
|
||||
typings/
|
||||
|
||||
# NVM config
|
||||
.nvmrc
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
.npmrc
|
||||
@@ -75,13 +78,11 @@ TODO.md
|
||||
# VSCode file
|
||||
.vscode
|
||||
|
||||
packages/website/public/bundle*
|
||||
packages/dev-tools-pages/public/bundle*
|
||||
|
||||
# server cli
|
||||
packages/testnet-faucets/server/
|
||||
|
||||
# generated contract artifacts/
|
||||
contracts/staking/generated-artifacts/
|
||||
contracts/coordinator/generated-artifacts/
|
||||
contracts/exchange/generated-artifacts/
|
||||
contracts/asset-proxy/generated-artifacts/
|
||||
@@ -97,9 +98,24 @@ contracts/dev-utils/generated-artifacts/
|
||||
packages/sol-tracing-utils/test/fixtures/artifacts/
|
||||
python-packages/contract_artifacts/src/zero_ex/contract_artifacts/artifacts/
|
||||
|
||||
# generated truffle contract artifacts/
|
||||
contracts/staking/build/
|
||||
contracts/coordinator/build/
|
||||
contracts/exchange/build/
|
||||
contracts/asset-proxy/build/
|
||||
contracts/multisig/build/
|
||||
contracts/utils/build/
|
||||
contracts/exchange-libs/build/
|
||||
contracts/erc20/build/
|
||||
contracts/erc721/build/
|
||||
contracts/erc1155/build/
|
||||
contracts/extensions/build/
|
||||
contracts/exchange-forwarder/build/
|
||||
contracts/dev-utils/build/
|
||||
|
||||
# generated contract wrappers
|
||||
packages/abi-gen-wrappers/src/generated-wrappers/
|
||||
packages/python-contract-wrappers/generated/
|
||||
contracts/staking/generated-wrappers/
|
||||
contracts/coordinator/generated-wrappers/
|
||||
contracts/exchange/generated-wrappers/
|
||||
contracts/asset-proxy/generated-wrappers/
|
||||
@@ -133,15 +149,9 @@ python-packages/contract_wrappers/src/zero_ex/contract_wrappers/order_validator/
|
||||
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/weth9/__init__.py
|
||||
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/zrx_token/__init__.py
|
||||
|
||||
# cli test output
|
||||
packages/abi-gen/test-cli/output
|
||||
|
||||
# solc-bin in sol-compiler
|
||||
packages/sol-compiler/solc_bin/
|
||||
|
||||
# Monorepo scripts
|
||||
packages/*/scripts/
|
||||
|
||||
# python stuff
|
||||
.eggs
|
||||
.mypy_cache
|
||||
@@ -154,3 +164,8 @@ python-packages/*/.coverage
|
||||
|
||||
# python keeps package-local copies of json schemas
|
||||
python-packages/json_schemas/src/zero_ex/json_schemas/schemas
|
||||
|
||||
# Doc README copy
|
||||
packages/*/docs/README.md
|
||||
|
||||
.DS_Store
|
||||
|
@@ -1,5 +1,7 @@
|
||||
lib
|
||||
.nyc_output
|
||||
/contracts/staking/generated-wrappers
|
||||
/contracts/staking/generated-artifacts
|
||||
/contracts/coordinator/generated-wrappers
|
||||
/contracts/coordinator/generated-artifacts
|
||||
/contracts/exchange/generated-wrappers
|
||||
@@ -24,11 +26,23 @@ lib
|
||||
/contracts/exchange-forwarder/generated-artifacts
|
||||
/contracts/dev-utils/generated-wrappers
|
||||
/contracts/dev-utils/generated-artifacts
|
||||
/contracts/staking/build/
|
||||
/contracts/coordinator/build/
|
||||
/contracts/exchange/build/
|
||||
/contracts/asset-proxy/build/
|
||||
/contracts/multisig/build/
|
||||
/contracts/utils/build/
|
||||
/contracts/exchange-libs/build/
|
||||
/contracts/erc20/build/
|
||||
/contracts/erc721/build/
|
||||
/contracts/erc1155/build/
|
||||
/contracts/extensions/build/
|
||||
/contracts/exchange-forwarder/build/
|
||||
/contracts/dev-utils/build/
|
||||
/packages/abi-gen/test-cli/output
|
||||
/packages/json-schemas/schemas
|
||||
/python-packages/json_schemas/src/zero_ex/json_schemas/schemas
|
||||
/packages/sra-spec/public/
|
||||
/packages/dev-tools-pages/ts/**/data.json
|
||||
package.json
|
||||
scripts/postpublish_utils.js
|
||||
packages/sol-coverage/test/fixtures/artifacts
|
||||
@@ -38,3 +52,4 @@ packages/sol-coverage/test/fixtures/artifacts
|
||||
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
|
||||
|
@@ -7,7 +7,6 @@
|
||||
# Website
|
||||
packages/asset-buyer/ @BMillman19 @fragosti @steveklebanoff
|
||||
packages/instant/ @BMillman19 @fragosti @steveklebanoff
|
||||
packages/website/ @BMillman19 @fragosti @fabioberger @steveklebanoff
|
||||
|
||||
# Dev tools & setup
|
||||
.circleci/ @LogvinovLeon
|
||||
|
@@ -29,9 +29,9 @@ ALL PRs should be opened against `development`.
|
||||
|
||||
Branch names should be prefixed with `fix`, `feature` or `refactor`.
|
||||
|
||||
- e.g `fix/broken-wiki-link`
|
||||
- e.g `fix/missing-import`
|
||||
- If the PR only edits a single package, add it's name too
|
||||
- e.g `fix/website/broken-wiki-link`
|
||||
- e.g `fix/subproviders/missing-import`
|
||||
|
||||
### CHANGELOGs
|
||||
|
||||
@@ -55,7 +55,7 @@ If an entry without a `timestamp` already exists, this means other changes have
|
||||
|
||||
### Development Tooling
|
||||
|
||||
We strongly recommend you use the [VSCode](https://code.visualstudio.com/) text editor since most of our code is written in Typescript and it offers amazing support for the language.
|
||||
We strongly recommend you use the [VSCode](https://code.visualstudio.com/) text editor since most of our code is written in TypeScript and it offers amazing support for the language.
|
||||
|
||||
#### Linter
|
||||
|
||||
@@ -89,7 +89,7 @@ A few of our coding conventions are not yet enforced by the linter/auto-formatte
|
||||
1. Do not import from a project's `index.ts` (e.g import { Token } from '../src';). Always import from the source file itself.
|
||||
1. Generic error variables should be named `err` instead of `e` or `error`.
|
||||
1. If you _must_ cast a variable to any - try to type it back as fast as possible. (e.g., `const cw = ((zeroEx as any)._contractWrappers as ContractWrappers);`). This ensures subsequent code is type-safe.
|
||||
1. Our enum conventions coincide with the recommended Typescript conventions, using capitalized keys, and all-caps snake-case values. Eg `GetStats = 'GET_STATS'`
|
||||
1. Our enum conventions coincide with the recommended TypeScript conventions, using capitalized keys, and all-caps snake-case values. Eg `GetStats = 'GET_STATS'`
|
||||
1. All public, exported methods/functions/classes must have associated Javadoc-style comments.
|
||||
|
||||
### Fix `submit-coverage` CI failure
|
||||
|
22
README.md
22
README.md
@@ -6,21 +6,16 @@
|
||||
|
||||
This repository is a monorepo including the 0x protocol smart contracts and numerous developer tools. Each public sub-package is independently published to NPM.
|
||||
|
||||
If you're developing on 0x now or are interested in using 0x infrastructure in the future, please join our [developer mailing list][dev-mailing-list-url] for updates.
|
||||
|
||||
[website-url]: https://0xproject.com
|
||||
[whitepaper-url]: https://0xproject.com/pdfs/0x_white_paper.pdf
|
||||
[dev-mailing-list-url]: http://eepurl.com/dx4cPf
|
||||
[website-url]: https://0x.org
|
||||
|
||||
[](https://circleci.com/gh/0xProject/0x-monorepo)
|
||||
[](https://coveralls.io/github/0xProject/0x-monorepo?branch=development)
|
||||
[](https://chat.0xproject.com)
|
||||
[](https://gitter.im/0xProject/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
[](https://discordapp.com/invite/d3FTX3M)
|
||||
[](https://opensource.org/licenses/Apache-2.0)
|
||||
|
||||
## Packages
|
||||
|
||||
Visit our [developer portal](https://0xproject.com/docs/order-utils) for a comprehensive list of core & community maintained packages. All packages maintained with this monorepo are listed below.
|
||||
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
|
||||
|
||||
@@ -48,12 +43,13 @@ These packages are all under development. See [/contracts/README.md](/contracts/
|
||||
| [`@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-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) |
|
||||
|
||||
### Typescript/Javascript Packages
|
||||
### TypeScript/Javascript Packages
|
||||
|
||||
#### 0x-specific packages
|
||||
|
||||
@@ -97,7 +93,6 @@ These packages are all under development. See [/contracts/README.md](/contracts/
|
||||
| [`@0x/assert`](/packages/assert) | [](https://www.npmjs.com/package/@0x/assert) | Type and schema assertions used by our packages |
|
||||
| [`@0x/base-contract`](/packages/base-contract) | [](https://www.npmjs.com/package/@0x/base-contract) | BaseContract used by auto-generated `abi-gen` wrapper contracts |
|
||||
| [`@0x/dev-utils`](/packages/dev-utils) | [](https://www.npmjs.com/package/@0x/dev-utils) | Dev utils to be shared across 0x packages |
|
||||
| [`@0x/fill-scenarios`](/packages/fill-scenarios) | [](https://www.npmjs.com/package/@0x/fill-scenarios) | 0x order fill scenario generator |
|
||||
|
||||
#### Private Packages
|
||||
|
||||
@@ -105,11 +100,10 @@ These packages are all under development. See [/contracts/README.md](/contracts/
|
||||
| -------------------------------------------------- | -------------------------------------------------------------------------------- |
|
||||
| [`@0x/instant`](/packages/instant) | A free and flexible way to offer simple crypto purchasing in any app or website. |
|
||||
| [`@0x/testnet-faucets`](/packages/testnet-faucets) | A faucet micro-service that dispenses test ERC20 tokens or Ether |
|
||||
| [`@0x/website`](/packages/website) | 0x website |
|
||||
|
||||
## Usage
|
||||
|
||||
Node version >= 6.12 is required.
|
||||
Node version 6.x or 8.x is required.
|
||||
|
||||
Most of the packages require additional typings for external dependencies.
|
||||
You can include those by prepending the `@0x/typescript-typings` package to your [`typeRoots`](http://www.typescriptlang.org/docs/handbook/tsconfig-json.html) config.
|
||||
@@ -138,6 +132,8 @@ 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:
|
||||
|
2
contracts/asset-proxy/.solhintignore
Normal file
2
contracts/asset-proxy/.solhintignore
Normal file
@@ -0,0 +1,2 @@
|
||||
# solhint can't parse `abi.decode` syntax.
|
||||
contracts/src/ERC1155Proxy.sol
|
@@ -1,4 +1,61 @@
|
||||
[
|
||||
{
|
||||
"version": "2.3.0-beta.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Disallow the zero address from being made an authorized address in MixinAuthorizable, and created an archive directory that includes an old version of Ownable",
|
||||
"pr": 2019
|
||||
},
|
||||
{
|
||||
"note": "Remove `LibAssetProxyIds` contract",
|
||||
"pr": 2055
|
||||
},
|
||||
{
|
||||
"note": "Compile and export all contracts, artifacts, and wrappers by default",
|
||||
"pr": 2055
|
||||
},
|
||||
{
|
||||
"note": "Remove unused dependency on IAuthorizable in IAssetProxy",
|
||||
"pr": 1910
|
||||
},
|
||||
{
|
||||
"note": "Add `ERC20BridgeProxy`",
|
||||
"pr": 2220
|
||||
},
|
||||
{
|
||||
"note": "Add `Eth2DaiBridge`",
|
||||
"pr": 2221
|
||||
}
|
||||
],
|
||||
"timestamp": 1570135330
|
||||
},
|
||||
{
|
||||
"timestamp": 1568744790,
|
||||
"version": "2.2.8",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1567521715,
|
||||
"version": "2.2.7",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1566446343,
|
||||
"version": "2.2.6",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1565296576,
|
||||
"version": "2.2.5",
|
||||
@@ -96,6 +153,18 @@
|
||||
{
|
||||
"note": "Update tests to use contract-built-in `awaitTransactionSuccessAsync`",
|
||||
"pr": 1797
|
||||
},
|
||||
{
|
||||
"note": "Make `ERC721Wrapper.setApprovalForAll()` take an owner address instead of a token ID",
|
||||
"pr": 1819
|
||||
},
|
||||
{
|
||||
"note": "Automatically set unlimited proxy allowances in `ERC721.setBalancesAndAllowancesAsync()`",
|
||||
"pr": 1819
|
||||
},
|
||||
{
|
||||
"note": "Add `setProxyAllowanceForAllAsync()` to `ERC1155ProxyWrapper`.",
|
||||
"pr": 1819
|
||||
}
|
||||
],
|
||||
"timestamp": 1557507213
|
||||
|
@@ -5,6 +5,27 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v2.3.0-beta.0 - _October 3, 2019_
|
||||
|
||||
* Disallow the zero address from being made an authorized address in MixinAuthorizable, and created an archive directory that includes an old version of Ownable (#2019)
|
||||
* Remove `LibAssetProxyIds` contract (#2055)
|
||||
* Compile and export all contracts, artifacts, and wrappers by default (#2055)
|
||||
* Remove unused dependency on IAuthorizable in IAssetProxy (#1910)
|
||||
* Add `ERC20BridgeProxy` (#2220)
|
||||
* Add `Eth2DaiBridge` (#2221)
|
||||
|
||||
## v2.2.8 - _September 17, 2019_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v2.2.7 - _September 3, 2019_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v2.2.6 - _August 22, 2019_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v2.2.5 - _August 8, 2019_
|
||||
|
||||
* Dependencies updated
|
||||
@@ -46,6 +67,9 @@ CHANGELOG
|
||||
## v2.1.2 - _May 10, 2019_
|
||||
|
||||
* Update tests to use contract-built-in `awaitTransactionSuccessAsync` (#1797)
|
||||
* Make `ERC721Wrapper.setApprovalForAll()` take an owner address instead of a token ID (#1819)
|
||||
* Automatically set unlimited proxy allowances in `ERC721.setBalancesAndAllowancesAsync()` (#1819)
|
||||
* Add `setProxyAllowanceForAllAsync()` to `ERC1155ProxyWrapper`. (#1819)
|
||||
|
||||
## v2.1.1 - _April 11, 2019_
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
## 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 the 0x [wiki](https://0xproject.com/wiki#Deployed-Addresses) or the [DEPLOYS](./DEPLOYS.json) file within this package.
|
||||
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
|
||||
|
||||
@@ -12,7 +12,7 @@ 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://0xproject.com/wiki#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
|
||||
|
||||
|
@@ -22,17 +22,5 @@
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"contracts": [
|
||||
"src/ERC1155Proxy.sol",
|
||||
"src/ERC20Proxy.sol",
|
||||
"src/ERC721Proxy.sol",
|
||||
"src/MixinAuthorizable.sol",
|
||||
"src/MultiAssetProxy.sol",
|
||||
"src/StaticCallProxy.sol",
|
||||
"src/interfaces/IAssetData.sol",
|
||||
"src/interfaces/IAssetProxy.sol",
|
||||
"src/interfaces/IAuthorizable.sol",
|
||||
"test/TestStaticCallTarget.sol"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -16,16 +16,16 @@
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.5;
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
import "@0x/contracts-utils/contracts/src/Ownable.sol";
|
||||
import "./mixins/MAssetProxyDispatcher.sol";
|
||||
import "./interfaces/IAssetProxy.sol";
|
||||
import "../archive/Ownable.sol";
|
||||
import "../src/interfaces/IAssetProxy.sol";
|
||||
import "../src/interfaces/IAssetProxyDispatcher.sol";
|
||||
|
||||
|
||||
contract MixinAssetProxyDispatcher is
|
||||
Ownable,
|
||||
MAssetProxyDispatcher
|
||||
IAssetProxyDispatcher
|
||||
{
|
||||
// Mapping from Asset Proxy Id's to their respective Asset Proxy
|
||||
mapping (bytes4 => address) public assetProxies;
|
||||
@@ -69,7 +69,7 @@ contract MixinAssetProxyDispatcher is
|
||||
/// @param from Address to transfer token from.
|
||||
/// @param to Address to transfer token to.
|
||||
/// @param amount Amount of token to transfer.
|
||||
function dispatchTransferFrom(
|
||||
function _dispatchTransferFrom(
|
||||
bytes memory assetData,
|
||||
address from,
|
||||
address to,
|
||||
@@ -84,7 +84,7 @@ contract MixinAssetProxyDispatcher is
|
||||
assetData.length > 3,
|
||||
"LENGTH_GREATER_THAN_3_REQUIRED"
|
||||
);
|
||||
|
||||
|
||||
// Lookup assetProxy. We do not use `LibBytes.readBytes4` for gas efficiency reasons.
|
||||
bytes4 assetProxyId;
|
||||
assembly {
|
||||
@@ -100,10 +100,10 @@ contract MixinAssetProxyDispatcher is
|
||||
assetProxy != address(0),
|
||||
"ASSET_PROXY_DOES_NOT_EXIST"
|
||||
);
|
||||
|
||||
|
||||
// We construct calldata for the `assetProxy.transferFrom` ABI.
|
||||
// The layout of this calldata is in the table below.
|
||||
//
|
||||
//
|
||||
// | Area | Offset | Length | Contents |
|
||||
// | -------- |--------|---------|-------------------------------------------- |
|
||||
// | Header | 0 | 4 | function selector |
|
||||
@@ -127,12 +127,12 @@ contract MixinAssetProxyDispatcher is
|
||||
// `cdEnd` is the end of the calldata for `assetProxy.transferFrom`.
|
||||
let cdEnd := add(cdStart, add(132, dataAreaLength))
|
||||
|
||||
|
||||
|
||||
/////// Setup Header Area ///////
|
||||
// This area holds the 4-byte `transferFromSelector`.
|
||||
// bytes4(keccak256("transferFrom(bytes,address,address,uint256)")) = 0xa85e59e4
|
||||
mstore(cdStart, 0xa85e59e400000000000000000000000000000000000000000000000000000000)
|
||||
|
||||
|
||||
/////// Setup Params Area ///////
|
||||
// Each parameter is padded to 32-bytes. The entire Params Area is 128 bytes.
|
||||
// Notes:
|
||||
@@ -142,7 +142,7 @@ contract MixinAssetProxyDispatcher is
|
||||
mstore(add(cdStart, 36), and(from, 0xffffffffffffffffffffffffffffffffffffffff))
|
||||
mstore(add(cdStart, 68), and(to, 0xffffffffffffffffffffffffffffffffffffffff))
|
||||
mstore(add(cdStart, 100), amount)
|
||||
|
||||
|
||||
/////// Setup Data Area ///////
|
||||
// This area holds `assetData`.
|
||||
let dataArea := add(cdStart, 132)
|
||||
@@ -159,7 +159,7 @@ contract MixinAssetProxyDispatcher is
|
||||
assetProxy, // call address of asset proxy
|
||||
0, // don't send any ETH
|
||||
cdStart, // pointer to start of input
|
||||
sub(cdEnd, cdStart), // length of input
|
||||
sub(cdEnd, cdStart), // length of input
|
||||
cdStart, // write output over input
|
||||
512 // reserve 512 bytes for output
|
||||
)
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -16,15 +16,15 @@
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.5;
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
import "@0x/contracts-utils/contracts/src/Ownable.sol";
|
||||
import "./mixins/MAuthorizable.sol";
|
||||
import "../archive/Ownable.sol";
|
||||
import "../src/interfaces/IAuthorizable.sol";
|
||||
|
||||
|
||||
contract MixinAuthorizable is
|
||||
Ownable,
|
||||
MAuthorizable
|
||||
IAuthorizable
|
||||
{
|
||||
/// @dev Only authorized addresses can invoke functions with this modifier.
|
||||
modifier onlyAuthorized {
|
33
contracts/asset-proxy/contracts/archive/Ownable.sol
Normal file
33
contracts/asset-proxy/contracts/archive/Ownable.sol
Normal file
@@ -0,0 +1,33 @@
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
import "@0x/contracts-utils/contracts/src/interfaces/IOwnable.sol";
|
||||
|
||||
|
||||
contract Ownable is
|
||||
IOwnable
|
||||
{
|
||||
address public owner;
|
||||
|
||||
constructor ()
|
||||
public
|
||||
{
|
||||
owner = msg.sender;
|
||||
}
|
||||
|
||||
modifier onlyOwner() {
|
||||
require(
|
||||
msg.sender == owner,
|
||||
"ONLY_CONTRACT_OWNER"
|
||||
);
|
||||
_;
|
||||
}
|
||||
|
||||
function transferOwnership(address newOwner)
|
||||
public
|
||||
onlyOwner
|
||||
{
|
||||
if (newOwner != address(0)) {
|
||||
owner = newOwner;
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -21,7 +21,7 @@ pragma solidity ^0.5.9;
|
||||
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
|
||||
import "@0x/contracts-utils/contracts/src/SafeMath.sol";
|
||||
import "@0x/contracts-erc1155/contracts/src/interfaces/IERC1155.sol";
|
||||
import "./MixinAuthorizable.sol";
|
||||
import "../archive/MixinAuthorizable.sol";
|
||||
import "./interfaces/IAssetProxy.sol";
|
||||
|
||||
|
||||
@@ -69,9 +69,9 @@ contract ERC1155Proxy is
|
||||
for (uint256 i = 0; i != length; i++) {
|
||||
// We write the scaled values to an unused location in memory in order
|
||||
// to avoid copying over `ids` or `data`. This is possible if they are
|
||||
// identical to `values` and the offsets for each are pointing to the
|
||||
// identical to `values` and the offsets for each are pointing to the
|
||||
// same location in the ABI encoded calldata.
|
||||
scaledValues[i] = safeMul(values[i], amount);
|
||||
scaledValues[i] = _safeMul(values[i], amount);
|
||||
}
|
||||
|
||||
// Execute `safeBatchTransferFrom` call
|
||||
|
126
contracts/asset-proxy/contracts/src/ERC20BridgeProxy.sol
Normal file
126
contracts/asset-proxy/contracts/src/ERC20BridgeProxy.sol
Normal file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
|
||||
import "@0x/contracts-utils/contracts/src/Authorizable.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||
import "./interfaces/IAssetProxy.sol";
|
||||
import "./interfaces/IERC20Bridge.sol";
|
||||
|
||||
|
||||
contract ERC20BridgeProxy is
|
||||
IAssetProxy,
|
||||
Authorizable
|
||||
{
|
||||
using LibBytes for bytes;
|
||||
using LibSafeMath for uint256;
|
||||
|
||||
// @dev Id of this proxy. Also the result of a successful bridge call.
|
||||
// bytes4(keccak256("ERC20Bridge(address,address,bytes)"))
|
||||
bytes4 constant private PROXY_ID = 0xdc1600f3;
|
||||
|
||||
/// @dev Calls a bridge contract to transfer `amount` of ERC20 from `from`
|
||||
/// to `to`. Asserts that the balance of `to` has increased by `amount`.
|
||||
/// @param assetData Abi-encoded data for this asset proxy encoded as:
|
||||
/// abi.encodeWithSelector(
|
||||
/// bytes4 PROXY_ID,
|
||||
/// address tokenAddress,
|
||||
/// address bridgeAddress,
|
||||
/// bytes bridgeData
|
||||
/// )
|
||||
/// @param from Address to transfer asset from.
|
||||
/// @param to Address to transfer asset to.
|
||||
/// @param amount Amount of asset to transfer.
|
||||
function transferFrom(
|
||||
bytes calldata assetData,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
)
|
||||
external
|
||||
onlyAuthorized
|
||||
{
|
||||
// Extract asset data fields.
|
||||
(
|
||||
address tokenAddress,
|
||||
address bridgeAddress,
|
||||
bytes memory bridgeData
|
||||
) = abi.decode(
|
||||
assetData.sliceDestructive(4, assetData.length),
|
||||
(address, address, bytes)
|
||||
);
|
||||
|
||||
// Remember the balance of `to` before calling the bridge.
|
||||
uint256 balanceBefore = balanceOf(tokenAddress, to);
|
||||
// Call the bridge, who should transfer `amount` of `tokenAddress` to
|
||||
// `to`.
|
||||
bytes4 success = IERC20Bridge(bridgeAddress).withdrawTo(
|
||||
tokenAddress,
|
||||
from,
|
||||
to,
|
||||
amount,
|
||||
bridgeData
|
||||
);
|
||||
// Bridge must return the proxy ID to indicate success.
|
||||
require(success == PROXY_ID, "BRIDGE_FAILED");
|
||||
// Ensure that the balance of `to` has increased by at least `amount`.
|
||||
require(
|
||||
balanceBefore.safeAdd(amount) <= balanceOf(tokenAddress, to),
|
||||
"BRIDGE_UNDERPAY"
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Gets the proxy id associated with this asset proxy.
|
||||
/// @return proxyId The proxy id.
|
||||
function getProxyId()
|
||||
external
|
||||
pure
|
||||
returns (bytes4 proxyId)
|
||||
{
|
||||
return PROXY_ID;
|
||||
}
|
||||
|
||||
/// @dev Retrieves the balance of `owner` for this asset.
|
||||
/// @return balance The balance of the ERC20 token being transferred by this
|
||||
/// asset proxy.
|
||||
function balanceOf(bytes calldata assetData, address owner)
|
||||
external
|
||||
view
|
||||
returns (uint256 balance)
|
||||
{
|
||||
(address tokenAddress) = abi.decode(
|
||||
assetData.sliceDestructive(4, assetData.length),
|
||||
(address)
|
||||
);
|
||||
return balanceOf(tokenAddress, owner);
|
||||
}
|
||||
|
||||
/// @dev Retrieves the balance of `owner` given an ERC20 address.
|
||||
/// @return balance The balance of the ERC20 token for `owner`.
|
||||
function balanceOf(address tokenAddress, address owner)
|
||||
private
|
||||
view
|
||||
returns (uint256 balance)
|
||||
{
|
||||
return IERC20Token(tokenAddress).balanceOf(owner);
|
||||
}
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -16,9 +16,9 @@
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.5;
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
import "./MixinAuthorizable.sol";
|
||||
import "../archive/MixinAuthorizable.sol";
|
||||
|
||||
|
||||
contract ERC20Proxy is
|
||||
@@ -26,9 +26,9 @@ contract ERC20Proxy is
|
||||
{
|
||||
// Id of this proxy.
|
||||
bytes4 constant internal PROXY_ID = bytes4(keccak256("ERC20Token(address)"));
|
||||
|
||||
|
||||
// solhint-disable-next-line payable-fallback
|
||||
function ()
|
||||
function ()
|
||||
external
|
||||
{
|
||||
assembly {
|
||||
@@ -117,13 +117,13 @@ contract ERC20Proxy is
|
||||
// * The "token address" is offset 32+4=36 bytes into "assetData" (tables 1 & 2).
|
||||
// [tokenOffset = assetDataOffsetFromHeader + 36 = calldataload(4) + 4 + 36]
|
||||
let token := calldataload(add(calldataload(4), 40))
|
||||
|
||||
|
||||
/////// Setup Header Area ///////
|
||||
// This area holds the 4-byte `transferFrom` selector.
|
||||
// Any trailing data in transferFromSelector will be
|
||||
// overwritten in the next `mstore` call.
|
||||
mstore(0, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
|
||||
|
||||
|
||||
/////// Setup Params Area ///////
|
||||
// We copy the fields `from`, `to` and `amount` in bulk
|
||||
// from our own calldata to the new calldata.
|
||||
@@ -147,7 +147,7 @@ contract ERC20Proxy is
|
||||
// If the token does return data, we require that it is a single
|
||||
// nonzero 32 bytes value.
|
||||
// So the transfer succeeded if the call succeeded and either
|
||||
// returned nothing, or returned a non-zero 32 byte value.
|
||||
// returned nothing, or returned a non-zero 32 byte value.
|
||||
success := and(success, or(
|
||||
iszero(returndatasize),
|
||||
and(
|
||||
@@ -158,7 +158,7 @@ contract ERC20Proxy is
|
||||
if success {
|
||||
return(0, 0)
|
||||
}
|
||||
|
||||
|
||||
// Revert with `Error("TRANSFER_FAILED")`
|
||||
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
|
||||
mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -16,9 +16,9 @@
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.5;
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
import "./MixinAuthorizable.sol";
|
||||
import "../archive/MixinAuthorizable.sol";
|
||||
|
||||
|
||||
contract ERC721Proxy is
|
||||
@@ -28,7 +28,7 @@ contract ERC721Proxy is
|
||||
bytes4 constant internal PROXY_ID = bytes4(keccak256("ERC721Token(address,uint256)"));
|
||||
|
||||
// solhint-disable-next-line payable-fallback
|
||||
function ()
|
||||
function ()
|
||||
external
|
||||
{
|
||||
assembly {
|
||||
@@ -93,10 +93,10 @@ contract ERC721Proxy is
|
||||
// | Params | | 2 * 32 | function parameters: |
|
||||
// | | 4 | 12 + 20 | 1. token address |
|
||||
// | | 36 | | 2. tokenId |
|
||||
|
||||
|
||||
// We construct calldata for the `token.transferFrom` ABI.
|
||||
// The layout of this calldata is in the table below.
|
||||
//
|
||||
//
|
||||
// | Area | Offset | Length | Contents |
|
||||
// |----------|--------|---------|-------------------------------------|
|
||||
// | Header | 0 | 4 | function selector |
|
||||
@@ -121,7 +121,7 @@ contract ERC721Proxy is
|
||||
// Any trailing data in transferFromSelector will be
|
||||
// overwritten in the next `mstore` call.
|
||||
mstore(0, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
|
||||
|
||||
|
||||
/////// Setup Params Area ///////
|
||||
// We copy the fields `from` and `to` in bulk
|
||||
// from our own calldata to the new calldata.
|
||||
@@ -145,7 +145,7 @@ contract ERC721Proxy is
|
||||
if success {
|
||||
return(0, 0)
|
||||
}
|
||||
|
||||
|
||||
// Revert with `Error("TRANSFER_FAILED")`
|
||||
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
|
||||
mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -16,10 +16,10 @@
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.5;
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
import "./MixinAssetProxyDispatcher.sol";
|
||||
import "./MixinAuthorizable.sol";
|
||||
import "../archive/MixinAssetProxyDispatcher.sol";
|
||||
import "../archive/MixinAuthorizable.sol";
|
||||
|
||||
|
||||
contract MultiAssetProxy is
|
||||
@@ -105,7 +105,7 @@ contract MultiAssetProxy is
|
||||
// | | 36 | | 2. offset to nestedAssetData (*) |
|
||||
// | Data | | | amounts: |
|
||||
// | | 68 | 32 | amounts Length |
|
||||
// | | 100 | a | amounts Contents |
|
||||
// | | 100 | a | amounts Contents |
|
||||
// | | | | nestedAssetData: |
|
||||
// | | 100 + a | 32 | nestedAssetData Length |
|
||||
// | | 132 + a | b | nestedAssetData Contents (offsets) |
|
||||
@@ -149,8 +149,8 @@ contract MultiAssetProxy is
|
||||
// + 32 (amounts offset)
|
||||
let nestedAssetDataOffset := calldataload(add(assetDataOffset, 68))
|
||||
|
||||
// In order to find the start of the `amounts` contents, we must add:
|
||||
// assetDataOffset
|
||||
// In order to find the start of the `amounts` contents, we must add:
|
||||
// assetDataOffset
|
||||
// + 32 (assetData len)
|
||||
// + 4 (assetProxyId)
|
||||
// + amountsOffset
|
||||
@@ -160,8 +160,8 @@ contract MultiAssetProxy is
|
||||
// Load number of elements in `amounts`
|
||||
let amountsLen := calldataload(sub(amountsContentsStart, 32))
|
||||
|
||||
// In order to find the start of the `nestedAssetData` contents, we must add:
|
||||
// assetDataOffset
|
||||
// In order to find the start of the `nestedAssetData` contents, we must add:
|
||||
// assetDataOffset
|
||||
// + 32 (assetData len)
|
||||
// + 4 (assetProxyId)
|
||||
// + nestedAssetDataOffset
|
||||
@@ -190,10 +190,10 @@ contract MultiAssetProxy is
|
||||
|
||||
// Overwrite existing offset to `assetData` with our own
|
||||
mstore(4, 128)
|
||||
|
||||
|
||||
// Load `amount`
|
||||
let amount := calldataload(100)
|
||||
|
||||
|
||||
// Calculate number of bytes in `amounts` contents
|
||||
let amountsByteLen := mul(amountsLen, 32)
|
||||
|
||||
@@ -208,7 +208,7 @@ contract MultiAssetProxy is
|
||||
let amountsElement := calldataload(add(amountsContentsStart, i))
|
||||
let totalAmount := mul(amountsElement, amount)
|
||||
|
||||
// Revert if `amount` != 0 and multiplication resulted in an overflow
|
||||
// Revert if `amount` != 0 and multiplication resulted in an overflow
|
||||
if iszero(or(
|
||||
iszero(amount),
|
||||
eq(div(totalAmount, amount), amountsElement)
|
||||
@@ -228,7 +228,7 @@ contract MultiAssetProxy is
|
||||
let nestedAssetDataElementOffset := calldataload(add(nestedAssetDataContentsStart, i))
|
||||
|
||||
// In order to find the start of the `nestedAssetData[i]` contents, we must add:
|
||||
// assetDataOffset
|
||||
// assetDataOffset
|
||||
// + 32 (assetData len)
|
||||
// + 4 (assetProxyId)
|
||||
// + nestedAssetDataOffset
|
||||
@@ -274,7 +274,7 @@ contract MultiAssetProxy is
|
||||
mstore(164, assetProxies_slot)
|
||||
assetProxy := sload(keccak256(132, 64))
|
||||
}
|
||||
|
||||
|
||||
// Revert if AssetProxy with given id does not exist
|
||||
if iszero(assetProxy) {
|
||||
// Revert with `Error("ASSET_PROXY_DOES_NOT_EXIST")`
|
||||
@@ -284,7 +284,7 @@ contract MultiAssetProxy is
|
||||
mstore(96, 0)
|
||||
revert(0, 100)
|
||||
}
|
||||
|
||||
|
||||
// Copy `nestedAssetData[i]` from calldata to memory
|
||||
calldatacopy(
|
||||
132, // memory slot after `amounts[i]`
|
||||
@@ -298,7 +298,7 @@ contract MultiAssetProxy is
|
||||
assetProxy, // call address of asset proxy
|
||||
0, // don't send any ETH
|
||||
0, // pointer to start of input
|
||||
add(164, nestedAssetDataElementLen), // length of input
|
||||
add(164, nestedAssetDataElementLen), // length of input
|
||||
0, // write output over memory that won't be reused
|
||||
0 // don't copy output to memory
|
||||
)
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
142
contracts/asset-proxy/contracts/src/bridges/Eth2DaiBridge.sol
Normal file
142
contracts/asset-proxy/contracts/src/bridges/Eth2DaiBridge.sol
Normal file
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||
import "../interfaces/IERC20Bridge.sol";
|
||||
import "../interfaces/IEth2Dai.sol";
|
||||
import "../interfaces/IWallet.sol";
|
||||
|
||||
|
||||
// solhint-disable space-after-comma
|
||||
contract Eth2DaiBridge is
|
||||
IERC20Bridge,
|
||||
IWallet
|
||||
{
|
||||
/* Mainnet addresses */
|
||||
address constant public ETH2DAI_ADDRESS = 0x39755357759cE0d7f32dC8dC45414CCa409AE24e;
|
||||
|
||||
/// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of
|
||||
/// `toTokenAddress` tokens by selling the entirety of the opposing asset
|
||||
/// (DAI or WETH) to the Eth2Dai contract, then transfers the bought
|
||||
/// tokens to `to`.
|
||||
/// @param toTokenAddress The token to give to `to` (either DAI or WETH).
|
||||
/// @param to The recipient of the bought tokens.
|
||||
/// @param amount Minimum amount of `toTokenAddress` tokens to buy.
|
||||
/// @param bridgeData The abi-encoeded "from" token address.
|
||||
/// @return success The magic bytes if successful.
|
||||
function withdrawTo(
|
||||
address toTokenAddress,
|
||||
address /* from */,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes calldata bridgeData
|
||||
)
|
||||
external
|
||||
returns (bytes4 success)
|
||||
{
|
||||
// Decode the bridge data to get the `fromTokenAddress`.
|
||||
(address fromTokenAddress) = abi.decode(bridgeData, (address));
|
||||
|
||||
IEth2Dai exchange = _getEth2DaiContract();
|
||||
// Grant an allowance to the exchange to spend `fromTokenAddress` token.
|
||||
IERC20Token(fromTokenAddress).approve(address(exchange), uint256(-1));
|
||||
|
||||
// Try to sell all of this contract's `fromTokenAddress` token balance.
|
||||
uint256 boughtAmount = _getEth2DaiContract().sellAllAmount(
|
||||
address(fromTokenAddress),
|
||||
IERC20Token(fromTokenAddress).balanceOf(address(this)),
|
||||
toTokenAddress,
|
||||
amount
|
||||
);
|
||||
// Transfer the converted `toToken`s to `to`.
|
||||
_transferERC20Token(toTokenAddress, to, boughtAmount);
|
||||
return BRIDGE_SUCCESS;
|
||||
}
|
||||
|
||||
/// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
|
||||
/// and sign for itself in orders. Always succeeds.
|
||||
/// @return magicValue Magic success bytes, always.
|
||||
function isValidSignature(
|
||||
bytes32,
|
||||
bytes calldata
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (bytes4 magicValue)
|
||||
{
|
||||
return LEGACY_WALLET_MAGIC_VALUE;
|
||||
}
|
||||
|
||||
/// @dev Overridable way to get the eth2dai contract.
|
||||
/// @return exchange The Eth2Dai exchange contract.
|
||||
function _getEth2DaiContract()
|
||||
internal
|
||||
view
|
||||
returns (IEth2Dai exchange)
|
||||
{
|
||||
return IEth2Dai(ETH2DAI_ADDRESS);
|
||||
}
|
||||
|
||||
/// @dev Permissively transfers an ERC20 token that may not adhere to
|
||||
/// specs.
|
||||
/// @param tokenAddress The token contract address.
|
||||
/// @param to The token recipient.
|
||||
/// @param amount The amount of tokens to transfer.
|
||||
function _transferERC20Token(
|
||||
address tokenAddress,
|
||||
address to,
|
||||
uint256 amount
|
||||
)
|
||||
private
|
||||
{
|
||||
// Transfer tokens.
|
||||
// We do a raw call so we can check the success separate
|
||||
// from the return data.
|
||||
(bool didSucceed, bytes memory returnData) = tokenAddress.call(
|
||||
abi.encodeWithSelector(
|
||||
IERC20Token(0).transfer.selector,
|
||||
to,
|
||||
amount
|
||||
)
|
||||
);
|
||||
if (!didSucceed) {
|
||||
assembly { revert(add(returnData, 0x20), mload(returnData)) }
|
||||
}
|
||||
|
||||
// Check return data.
|
||||
// If there is no return data, we assume the token incorrectly
|
||||
// does not return a bool. In this case we expect it to revert
|
||||
// on failure, which was handled above.
|
||||
// If the token does return data, we require that it is a single
|
||||
// value that evaluates to true.
|
||||
assembly {
|
||||
if returndatasize {
|
||||
didSucceed := 0
|
||||
if eq(returndatasize, 32) {
|
||||
// First 64 bytes of memory are reserved scratch space
|
||||
returndatacopy(0, 0, 32)
|
||||
didSucceed := mload(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
require(didSucceed, "ERC20_TRANSFER_FAILED");
|
||||
}
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -17,7 +17,7 @@
|
||||
*/
|
||||
|
||||
// solhint-disable
|
||||
pragma solidity ^0.5.5;
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
|
||||
@@ -26,33 +26,63 @@ pragma experimental ABIEncoderV2;
|
||||
// This argument is ABI encoded as one of the methods of this interface.
|
||||
interface IAssetData {
|
||||
|
||||
/// @dev Function signature for encoding ERC20 assetData.
|
||||
/// @param tokenAddress Address of ERC20Token contract.
|
||||
function ERC20Token(address tokenAddress)
|
||||
external;
|
||||
|
||||
|
||||
/// @dev Function signature for encoding ERC721 assetData.
|
||||
/// @param tokenAddress Address of ERC721 token contract.
|
||||
/// @param tokenId Id of ERC721 token to be transferred.
|
||||
function ERC721Token(
|
||||
address tokenAddress,
|
||||
uint256 tokenId
|
||||
)
|
||||
external;
|
||||
|
||||
/// @dev Function signature for encoding ERC1155 assetData.
|
||||
/// @param tokenAddress Address of ERC1155 token contract.
|
||||
/// @param tokenIds Array of ids of tokens to be transferred.
|
||||
/// @param values Array of values that correspond to each token id to be transferred.
|
||||
/// Note that each value will be multiplied by the amount being filled in the order before transferring.
|
||||
/// @param callbackData Extra data to be passed to receiver's `onERC1155Received` callback function.
|
||||
function ERC1155Assets(
|
||||
address tokenAddress,
|
||||
uint256[] calldata tokenIds,
|
||||
uint256[] calldata tokenValues,
|
||||
uint256[] calldata values,
|
||||
bytes calldata callbackData
|
||||
)
|
||||
external;
|
||||
|
||||
/// @dev Function signature for encoding MultiAsset assetData.
|
||||
/// @param values Array of amounts that correspond to each asset to be transferred.
|
||||
/// Note that each value will be multiplied by the amount being filled in the order before transferring.
|
||||
/// @param nestedAssetData Array of assetData fields that will be be dispatched to their correspnding AssetProxy contract.
|
||||
function MultiAsset(
|
||||
uint256[] calldata amounts,
|
||||
uint256[] calldata values,
|
||||
bytes[] calldata nestedAssetData
|
||||
)
|
||||
external;
|
||||
|
||||
/// @dev Function signature for encoding StaticCall assetData.
|
||||
/// @param staticCallTargetAddress Address that will execute the staticcall.
|
||||
/// @param staticCallData Data that will be executed via staticcall on the staticCallTargetAddress.
|
||||
/// @param expectedReturnDataHash Keccak-256 hash of the expected staticcall return data.
|
||||
function StaticCall(
|
||||
address callTarget,
|
||||
address staticCallTargetAddress,
|
||||
bytes calldata staticCallData,
|
||||
bytes32 callResultHash
|
||||
bytes32 expectedReturnDataHash
|
||||
)
|
||||
external;
|
||||
|
||||
/// @dev Function signature for encoding ERC20Bridge assetData.
|
||||
/// @param tokenAddress Address of token to transfer.
|
||||
/// @param bridgeAddress Address of the bridge contract.
|
||||
/// @param bridgeData Arbitrary data to be passed to the bridge contract.
|
||||
function ERC20Bridge(
|
||||
address tokenAddress,
|
||||
address bridgeAddress,
|
||||
bytes calldata bridgeData
|
||||
)
|
||||
external;
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -16,9 +16,7 @@
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.5;
|
||||
|
||||
import "./IAuthorizable.sol";
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
|
||||
contract IAssetProxy {
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -16,11 +16,17 @@
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.5;
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
|
||||
contract IAssetProxyDispatcher {
|
||||
|
||||
// Logs registration of new asset proxy
|
||||
event AssetProxyRegistered(
|
||||
bytes4 id, // Id of new registered AssetProxy.
|
||||
address assetProxy // Address of new registered AssetProxy.
|
||||
);
|
||||
|
||||
/// @dev Registers an asset proxy to its asset proxy id.
|
||||
/// Once an asset proxy is registered, it cannot be unregistered.
|
||||
/// @param assetProxy Address of new asset proxy to register.
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.5;
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
import "@0x/contracts-utils/contracts/src/interfaces/IOwnable.sol";
|
||||
|
||||
@@ -24,6 +24,18 @@ import "@0x/contracts-utils/contracts/src/interfaces/IOwnable.sol";
|
||||
contract IAuthorizable is
|
||||
IOwnable
|
||||
{
|
||||
// Event logged when a new address is authorized.
|
||||
event AuthorizedAddressAdded(
|
||||
address indexed target,
|
||||
address indexed caller
|
||||
);
|
||||
|
||||
// Event logged when a currently authorized address is unauthorized.
|
||||
event AuthorizedAddressRemoved(
|
||||
address indexed target,
|
||||
address indexed caller
|
||||
);
|
||||
|
||||
/// @dev Authorizes an address.
|
||||
/// @param target Address to authorize.
|
||||
function addAuthorizedAddress(address target)
|
||||
@@ -42,7 +54,7 @@ contract IAuthorizable is
|
||||
uint256 index
|
||||
)
|
||||
external;
|
||||
|
||||
|
||||
/// @dev Gets all authorized addresses.
|
||||
/// @return Array of authorized addresses.
|
||||
function getAuthorizedAddresses()
|
||||
|
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
|
||||
contract IERC20Bridge {
|
||||
|
||||
// @dev Result of a successful bridge call.
|
||||
bytes4 constant internal BRIDGE_SUCCESS = 0xdc1600f3;
|
||||
|
||||
/// @dev Transfers `amount` of the ERC20 `tokenAddress` from `from` to `to`.
|
||||
/// @param tokenAddress The address of the ERC20 token to transfer.
|
||||
/// @param from Address to transfer asset from.
|
||||
/// @param to Address to transfer asset to.
|
||||
/// @param amount Amount of asset to transfer.
|
||||
/// @param bridgeData Arbitrary asset data needed by the bridge contract.
|
||||
/// @return success The magic bytes `0x37708e9b` if successful.
|
||||
function withdrawTo(
|
||||
address tokenAddress,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes calldata bridgeData
|
||||
)
|
||||
external
|
||||
returns (bytes4 success);
|
||||
}
|
38
contracts/asset-proxy/contracts/src/interfaces/IEth2Dai.sol
Normal file
38
contracts/asset-proxy/contracts/src/interfaces/IEth2Dai.sol
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
|
||||
interface IEth2Dai {
|
||||
|
||||
/// @dev Sell `sellAmount` of `fromToken` token and receive `toToken` token.
|
||||
/// @param fromToken The token being sold.
|
||||
/// @param sellAmount The amount of `fromToken` token being sold.
|
||||
/// @param toToken The token being bought.
|
||||
/// @param minFillAmount Minimum amount of `toToken` token to buy.
|
||||
/// @return fillAmount Amount of `toToken` bought.
|
||||
function sellAllAmount(
|
||||
address fromToken,
|
||||
uint256 sellAmount,
|
||||
address toToken,
|
||||
uint256 minFillAmount
|
||||
)
|
||||
external
|
||||
returns (uint256 fillAmount);
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -16,22 +16,23 @@
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.5;
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
|
||||
contract IValidator {
|
||||
contract IWallet {
|
||||
|
||||
/// @dev Verifies that a signature is valid.
|
||||
bytes4 internal constant LEGACY_WALLET_MAGIC_VALUE = 0xb0671381;
|
||||
|
||||
/// @dev Validates a hash with the `Wallet` signature type.
|
||||
/// @param hash Message hash that is signed.
|
||||
/// @param signerAddress Address that should have signed the given hash.
|
||||
/// @param signature Proof of signing.
|
||||
/// @return Validity of order signature.
|
||||
/// @return magicValue `bytes4(0xb0671381)` if the signature check succeeds.
|
||||
function isValidSignature(
|
||||
bytes32 hash,
|
||||
address signerAddress,
|
||||
bytes calldata signature
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (bool isValid);
|
||||
returns (bytes4 magicValue);
|
||||
}
|
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.5;
|
||||
|
||||
|
||||
contract LibAssetProxyIds {
|
||||
|
||||
// AssetProxy Ids are equiavalent the first 4 bytes of the keccak256 hash of the function signature assigned to each AssetProxy.
|
||||
|
||||
// ERC20Token(address)
|
||||
bytes4 constant public ERC20_PROXY_ID = 0xf47261b0;
|
||||
|
||||
// ERC721Token(address,uint256)
|
||||
bytes4 constant public ERC721_PROXY_ID = 0x02571792;
|
||||
|
||||
// ERC1155Assets(address,uint256[],uint256[],bytes)
|
||||
bytes4 constant public ERC1155_PROXY_ID = 0xa7cb5fb7;
|
||||
|
||||
// MultiAsset(uint256[],bytes[])
|
||||
bytes4 constant public MULTI_ASSET_PROXY_ID = 0x94cfcdd7;
|
||||
|
||||
// StaticCall(address,bytes,bytes32)
|
||||
bytes4 constant public STATIC_CALL_PROXY_ID = 0xc339d10a;
|
||||
}
|
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.5;
|
||||
|
||||
import "../interfaces/IAssetProxyDispatcher.sol";
|
||||
|
||||
|
||||
contract MAssetProxyDispatcher is
|
||||
IAssetProxyDispatcher
|
||||
{
|
||||
// Logs registration of new asset proxy
|
||||
event AssetProxyRegistered(
|
||||
bytes4 id, // Id of new registered AssetProxy.
|
||||
address assetProxy // Address of new registered AssetProxy.
|
||||
);
|
||||
|
||||
/// @dev Forwards arguments to assetProxy and calls `transferFrom`. Either succeeds or throws.
|
||||
/// @param assetData Byte array encoded for the asset.
|
||||
/// @param from Address to transfer token from.
|
||||
/// @param to Address to transfer token to.
|
||||
/// @param amount Amount of token to transfer.
|
||||
function dispatchTransferFrom(
|
||||
bytes memory assetData,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
)
|
||||
internal;
|
||||
}
|
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.5;
|
||||
|
||||
import "../interfaces/IAuthorizable.sol";
|
||||
|
||||
|
||||
contract MAuthorizable is
|
||||
IAuthorizable
|
||||
{
|
||||
// Event logged when a new address is authorized.
|
||||
event AuthorizedAddressAdded(
|
||||
address indexed target,
|
||||
address indexed caller
|
||||
);
|
||||
|
||||
// Event logged when a currently authorized address is unauthorized.
|
||||
event AuthorizedAddressRemoved(
|
||||
address indexed target,
|
||||
address indexed caller
|
||||
);
|
||||
|
||||
/// @dev Only authorized addresses can invoke functions with this modifier.
|
||||
modifier onlyAuthorized { revert(); _; }
|
||||
}
|
108
contracts/asset-proxy/contracts/test/TestERC20Bridge.sol
Normal file
108
contracts/asset-proxy/contracts/test/TestERC20Bridge.sol
Normal file
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "../src/interfaces/IERC20Bridge.sol";
|
||||
|
||||
|
||||
/// @dev Test bridge token
|
||||
contract TestERC20BridgeToken {
|
||||
mapping (address => uint256) private _balances;
|
||||
|
||||
function addBalance(address owner, int256 amount)
|
||||
external
|
||||
{
|
||||
setBalance(owner, uint256(int256(balanceOf(owner)) + amount));
|
||||
}
|
||||
|
||||
function setBalance(address owner, uint256 balance)
|
||||
public
|
||||
{
|
||||
_balances[owner] = balance;
|
||||
}
|
||||
|
||||
function balanceOf(address owner)
|
||||
public
|
||||
view
|
||||
returns (uint256)
|
||||
{
|
||||
return _balances[owner];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// @dev Test bridge contract.
|
||||
contract TestERC20Bridge is
|
||||
IERC20Bridge
|
||||
{
|
||||
TestERC20BridgeToken public testToken;
|
||||
|
||||
event BridgeWithdrawTo(
|
||||
address tokenAddress,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes bridgeData
|
||||
);
|
||||
|
||||
constructor() public {
|
||||
testToken = new TestERC20BridgeToken();
|
||||
}
|
||||
|
||||
function setTestTokenBalance(address owner, uint256 balance)
|
||||
external
|
||||
{
|
||||
testToken.setBalance(owner, balance);
|
||||
}
|
||||
|
||||
function withdrawTo(
|
||||
address tokenAddress,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes calldata bridgeData
|
||||
)
|
||||
external
|
||||
returns (bytes4)
|
||||
{
|
||||
emit BridgeWithdrawTo(
|
||||
tokenAddress,
|
||||
from,
|
||||
to,
|
||||
amount,
|
||||
bridgeData
|
||||
);
|
||||
// Unpack the bridgeData.
|
||||
(
|
||||
int256 transferAmount,
|
||||
bytes memory revertData,
|
||||
bytes memory returnData
|
||||
) = abi.decode(bridgeData, (int256, bytes, bytes));
|
||||
|
||||
// If `revertData` is set, revert.
|
||||
if (revertData.length != 0) {
|
||||
assembly { revert(add(revertData, 0x20), mload(revertData)) }
|
||||
}
|
||||
// Increase `to`'s balance by `transferAmount`.
|
||||
TestERC20BridgeToken(tokenAddress).addBalance(to, transferAmount);
|
||||
// Return `returnData`.
|
||||
assembly { return(add(returnData, 0x20), mload(returnData)) }
|
||||
}
|
||||
}
|
202
contracts/asset-proxy/contracts/test/TestEth2DaiBridge.sol
Normal file
202
contracts/asset-proxy/contracts/test/TestEth2DaiBridge.sol
Normal file
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||
import "../src/bridges/Eth2DaiBridge.sol";
|
||||
import "../src/interfaces/IEth2Dai.sol";
|
||||
|
||||
|
||||
// solhint-disable no-simple-event-func-name
|
||||
contract TestEvents {
|
||||
|
||||
event TokenTransfer(
|
||||
address token,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
);
|
||||
|
||||
event TokenApprove(
|
||||
address token,
|
||||
address spender,
|
||||
uint256 allowance
|
||||
);
|
||||
|
||||
function raiseTokenTransfer(
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
)
|
||||
external
|
||||
{
|
||||
emit TokenTransfer(
|
||||
msg.sender,
|
||||
from,
|
||||
to,
|
||||
amount
|
||||
);
|
||||
}
|
||||
|
||||
function raiseTokenApprove(address spender, uint256 allowance)
|
||||
external
|
||||
{
|
||||
emit TokenApprove(msg.sender, spender, allowance);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// @dev A minimalist ERC20 token.
|
||||
contract TestToken {
|
||||
|
||||
mapping (address => uint256) public balances;
|
||||
string private _nextTransferRevertReason;
|
||||
bytes private _nextTransferReturnData;
|
||||
|
||||
/// @dev Just calls `raiseTokenTransfer()` on the caller.
|
||||
function transfer(address to, uint256 amount)
|
||||
external
|
||||
returns (bool)
|
||||
{
|
||||
TestEvents(msg.sender).raiseTokenTransfer(msg.sender, to, amount);
|
||||
if (bytes(_nextTransferRevertReason).length != 0) {
|
||||
revert(_nextTransferRevertReason);
|
||||
}
|
||||
bytes memory returnData = _nextTransferReturnData;
|
||||
assembly { return(add(returnData, 0x20), mload(returnData)) }
|
||||
}
|
||||
|
||||
/// @dev Set the balance for `owner`.
|
||||
function setBalance(address owner, uint256 balance)
|
||||
external
|
||||
{
|
||||
balances[owner] = balance;
|
||||
}
|
||||
|
||||
/// @dev Set the behavior of the `transfer()` call.
|
||||
function setTransferBehavior(
|
||||
string calldata revertReason,
|
||||
bytes calldata returnData
|
||||
)
|
||||
external
|
||||
{
|
||||
_nextTransferRevertReason = revertReason;
|
||||
_nextTransferReturnData = returnData;
|
||||
}
|
||||
|
||||
/// @dev Just calls `raiseTokenApprove()` on the caller.
|
||||
function approve(address spender, uint256 allowance)
|
||||
external
|
||||
returns (bool)
|
||||
{
|
||||
TestEvents(msg.sender).raiseTokenApprove(spender, allowance);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// @dev Retrieve the balance for `owner`.
|
||||
function balanceOf(address owner)
|
||||
external
|
||||
view
|
||||
returns (uint256)
|
||||
{
|
||||
return balances[owner];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// @dev Eth2DaiBridge overridden to mock tokens and
|
||||
/// implement IEth2Dai.
|
||||
contract TestEth2DaiBridge is
|
||||
TestEvents,
|
||||
IEth2Dai,
|
||||
Eth2DaiBridge
|
||||
{
|
||||
event SellAllAmount(
|
||||
address sellToken,
|
||||
uint256 sellTokenAmount,
|
||||
address buyToken,
|
||||
uint256 minimumFillAmount
|
||||
);
|
||||
|
||||
mapping (address => TestToken) public testTokens;
|
||||
string private _nextRevertReason;
|
||||
uint256 private _nextFillAmount;
|
||||
|
||||
/// @dev Create a token and set this contract's balance.
|
||||
function createToken(uint256 balance)
|
||||
external
|
||||
returns (address tokenAddress)
|
||||
{
|
||||
TestToken token = new TestToken();
|
||||
testTokens[address(token)] = token;
|
||||
token.setBalance(address(this), balance);
|
||||
return address(token);
|
||||
}
|
||||
|
||||
/// @dev Set the behavior for `IEth2Dai.sellAllAmount()`.
|
||||
function setFillBehavior(string calldata revertReason, uint256 fillAmount)
|
||||
external
|
||||
{
|
||||
_nextRevertReason = revertReason;
|
||||
_nextFillAmount = fillAmount;
|
||||
}
|
||||
|
||||
/// @dev Set the behavior of a token's `transfer()`.
|
||||
function setTransferBehavior(
|
||||
address tokenAddress,
|
||||
string calldata revertReason,
|
||||
bytes calldata returnData
|
||||
)
|
||||
external
|
||||
{
|
||||
testTokens[tokenAddress].setTransferBehavior(revertReason, returnData);
|
||||
}
|
||||
|
||||
/// @dev Implementation of `IEth2Dai.sellAllAmount()`
|
||||
function sellAllAmount(
|
||||
address sellTokenAddress,
|
||||
uint256 sellTokenAmount,
|
||||
address buyTokenAddress,
|
||||
uint256 minimumFillAmount
|
||||
)
|
||||
external
|
||||
returns (uint256 fillAmount)
|
||||
{
|
||||
emit SellAllAmount(
|
||||
sellTokenAddress,
|
||||
sellTokenAmount,
|
||||
buyTokenAddress,
|
||||
minimumFillAmount
|
||||
);
|
||||
if (bytes(_nextRevertReason).length != 0) {
|
||||
revert(_nextRevertReason);
|
||||
}
|
||||
return _nextFillAmount;
|
||||
}
|
||||
|
||||
// @dev This contract will double as the Eth2Dai contract.
|
||||
function _getEth2DaiContract()
|
||||
internal
|
||||
view
|
||||
returns (IEth2Dai)
|
||||
{
|
||||
return IEth2Dai(address(this));
|
||||
}
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-asset-proxy",
|
||||
"version": "2.2.5",
|
||||
"version": "2.3.0-beta.0",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -12,7 +12,7 @@
|
||||
"scripts": {
|
||||
"build": "yarn pre_build && tsc -b",
|
||||
"build:ci": "yarn build",
|
||||
"pre_build": "run-s compile generate_contract_wrappers",
|
||||
"pre_build": "run-s compile contracts:gen generate_contract_wrappers",
|
||||
"test": "yarn run_mocha",
|
||||
"rebuild_and_test": "run-s build test",
|
||||
"test:coverage": "SOLIDITY_COVERAGE=true run-s build run_mocha coverage:report:text coverage:report:lcov",
|
||||
@@ -22,7 +22,7 @@
|
||||
"compile": "sol-compiler",
|
||||
"watch": "sol-compiler -w",
|
||||
"clean": "shx rm -rf lib generated-artifacts generated-wrappers",
|
||||
"generate_contract_wrappers": "abi-gen --abis ${npm_package_config_abis} --template ../../node_modules/@0x/abi-gen-templates/contract.handlebars --partials '../../node_modules/@0x/abi-gen-templates/partials/**/*.handlebars' --output generated-wrappers --backend ethers",
|
||||
"generate_contract_wrappers": "abi-gen --abis ${npm_package_config_abis} --output generated-wrappers --backend ethers",
|
||||
"lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
|
||||
"fix": "tslint --fix --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
|
||||
"coverage:report:text": "istanbul report text",
|
||||
@@ -31,10 +31,11 @@
|
||||
"coverage:report:lcov": "istanbul report lcov",
|
||||
"test:circleci": "yarn test",
|
||||
"contracts:gen": "contracts-gen",
|
||||
"lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol"
|
||||
"lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol",
|
||||
"compile:truffle": "truffle compile"
|
||||
},
|
||||
"config": {
|
||||
"abis": "./generated-artifacts/@(ERC1155Proxy|ERC20Proxy|ERC721Proxy|IAssetData|IAssetProxy|IAuthorizable|MixinAuthorizable|MultiAssetProxy|StaticCallProxy|TestStaticCallTarget).json",
|
||||
"abis": "./generated-artifacts/@(ERC1155Proxy|ERC20BridgeProxy|ERC20Proxy|ERC721Proxy|Eth2DaiBridge|IAssetData|IAssetProxy|IAssetProxyDispatcher|IAuthorizable|IERC20Bridge|IEth2Dai|IWallet|MixinAssetProxyDispatcher|MixinAuthorizable|MultiAssetProxy|Ownable|StaticCallProxy|TestERC20Bridge|TestEth2DaiBridge|TestStaticCallTarget).json",
|
||||
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually."
|
||||
},
|
||||
"repository": {
|
||||
@@ -47,11 +48,11 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/protocol/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^4.1.0",
|
||||
"@0x/contracts-gen": "^1.0.13",
|
||||
"@0x/contracts-test-utils": "^3.1.13",
|
||||
"@0x/dev-utils": "^2.3.0",
|
||||
"@0x/sol-compiler": "^3.1.12",
|
||||
"@0x/abi-gen": "^4.3.0-beta.0",
|
||||
"@0x/contracts-gen": "^1.1.0-beta.0",
|
||||
"@0x/contracts-test-utils": "^3.2.0-beta.0",
|
||||
"@0x/dev-utils": "^2.4.0-beta.0",
|
||||
"@0x/sol-compiler": "^3.2.0-beta.0",
|
||||
"@0x/tslint-config": "^3.0.1",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
@@ -65,21 +66,22 @@
|
||||
"npm-run-all": "^4.1.2",
|
||||
"shx": "^0.2.2",
|
||||
"solhint": "^1.4.1",
|
||||
"truffle": "^5.0.32",
|
||||
"tslint": "5.11.0",
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^5.3.1",
|
||||
"@0x/contracts-erc1155": "^1.1.12",
|
||||
"@0x/contracts-erc20": "^2.2.11",
|
||||
"@0x/contracts-erc721": "^2.1.12",
|
||||
"@0x/contracts-utils": "^3.2.1",
|
||||
"@0x/order-utils": "^8.2.5",
|
||||
"@0x/types": "^2.4.1",
|
||||
"@0x/typescript-typings": "^4.2.4",
|
||||
"@0x/utils": "^4.5.0",
|
||||
"@0x/web3-wrapper": "^6.0.10",
|
||||
"ethereum-types": "^2.1.4",
|
||||
"@0x/base-contract": "^5.5.0-beta.0",
|
||||
"@0x/contracts-erc1155": "^1.2.0-beta.0",
|
||||
"@0x/contracts-erc20": "^2.3.0-beta.0",
|
||||
"@0x/contracts-erc721": "^2.2.0-beta.0",
|
||||
"@0x/contracts-utils": "^3.3.0-beta.0",
|
||||
"@0x/order-utils": "^8.5.0-beta.0",
|
||||
"@0x/types": "^2.5.0-beta.0",
|
||||
"@0x/typescript-typings": "^4.4.0-beta.0",
|
||||
"@0x/utils": "^4.6.0-beta.0",
|
||||
"@0x/web3-wrapper": "^6.1.0-beta.0",
|
||||
"ethereum-types": "^2.2.0-beta.0",
|
||||
"ethereumjs-util": "^5.1.1",
|
||||
"lodash": "^4.17.11"
|
||||
},
|
||||
|
@@ -6,24 +6,44 @@
|
||||
import { ContractArtifact } from 'ethereum-types';
|
||||
|
||||
import * as ERC1155Proxy from '../generated-artifacts/ERC1155Proxy.json';
|
||||
import * as ERC20BridgeProxy from '../generated-artifacts/ERC20BridgeProxy.json';
|
||||
import * as ERC20Proxy from '../generated-artifacts/ERC20Proxy.json';
|
||||
import * as ERC721Proxy from '../generated-artifacts/ERC721Proxy.json';
|
||||
import * as Eth2DaiBridge from '../generated-artifacts/Eth2DaiBridge.json';
|
||||
import * as IAssetData from '../generated-artifacts/IAssetData.json';
|
||||
import * as IAssetProxy from '../generated-artifacts/IAssetProxy.json';
|
||||
import * as IAssetProxyDispatcher from '../generated-artifacts/IAssetProxyDispatcher.json';
|
||||
import * as IAuthorizable from '../generated-artifacts/IAuthorizable.json';
|
||||
import * as IERC20Bridge from '../generated-artifacts/IERC20Bridge.json';
|
||||
import * as IEth2Dai from '../generated-artifacts/IEth2Dai.json';
|
||||
import * as IWallet from '../generated-artifacts/IWallet.json';
|
||||
import * as MixinAssetProxyDispatcher from '../generated-artifacts/MixinAssetProxyDispatcher.json';
|
||||
import * as MixinAuthorizable from '../generated-artifacts/MixinAuthorizable.json';
|
||||
import * as MultiAssetProxy from '../generated-artifacts/MultiAssetProxy.json';
|
||||
import * as Ownable from '../generated-artifacts/Ownable.json';
|
||||
import * as StaticCallProxy from '../generated-artifacts/StaticCallProxy.json';
|
||||
import * as TestERC20Bridge from '../generated-artifacts/TestERC20Bridge.json';
|
||||
import * as TestEth2DaiBridge from '../generated-artifacts/TestEth2DaiBridge.json';
|
||||
import * as TestStaticCallTarget from '../generated-artifacts/TestStaticCallTarget.json';
|
||||
export const artifacts = {
|
||||
MixinAssetProxyDispatcher: MixinAssetProxyDispatcher as ContractArtifact,
|
||||
MixinAuthorizable: MixinAuthorizable as ContractArtifact,
|
||||
Ownable: Ownable as ContractArtifact,
|
||||
ERC1155Proxy: ERC1155Proxy as ContractArtifact,
|
||||
ERC20BridgeProxy: ERC20BridgeProxy as ContractArtifact,
|
||||
ERC20Proxy: ERC20Proxy as ContractArtifact,
|
||||
ERC721Proxy: ERC721Proxy as ContractArtifact,
|
||||
MixinAuthorizable: MixinAuthorizable as ContractArtifact,
|
||||
MultiAssetProxy: MultiAssetProxy as ContractArtifact,
|
||||
StaticCallProxy: StaticCallProxy as ContractArtifact,
|
||||
Eth2DaiBridge: Eth2DaiBridge as ContractArtifact,
|
||||
IAssetData: IAssetData as ContractArtifact,
|
||||
IAssetProxy: IAssetProxy as ContractArtifact,
|
||||
IAssetProxyDispatcher: IAssetProxyDispatcher as ContractArtifact,
|
||||
IAuthorizable: IAuthorizable as ContractArtifact,
|
||||
IERC20Bridge: IERC20Bridge as ContractArtifact,
|
||||
IEth2Dai: IEth2Dai as ContractArtifact,
|
||||
IWallet: IWallet as ContractArtifact,
|
||||
TestERC20Bridge: TestERC20Bridge as ContractArtifact,
|
||||
TestEth2DaiBridge: TestEth2DaiBridge as ContractArtifact,
|
||||
TestStaticCallTarget: TestStaticCallTarget as ContractArtifact,
|
||||
};
|
||||
|
@@ -4,12 +4,22 @@
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
export * from '../generated-wrappers/erc1155_proxy';
|
||||
export * from '../generated-wrappers/erc20_bridge_proxy';
|
||||
export * from '../generated-wrappers/erc20_proxy';
|
||||
export * from '../generated-wrappers/erc721_proxy';
|
||||
export * from '../generated-wrappers/eth2_dai_bridge';
|
||||
export * from '../generated-wrappers/i_asset_data';
|
||||
export * from '../generated-wrappers/i_asset_proxy';
|
||||
export * from '../generated-wrappers/i_asset_proxy_dispatcher';
|
||||
export * from '../generated-wrappers/i_authorizable';
|
||||
export * from '../generated-wrappers/i_erc20_bridge';
|
||||
export * from '../generated-wrappers/i_eth2_dai';
|
||||
export * from '../generated-wrappers/i_wallet';
|
||||
export * from '../generated-wrappers/mixin_asset_proxy_dispatcher';
|
||||
export * from '../generated-wrappers/mixin_authorizable';
|
||||
export * from '../generated-wrappers/multi_asset_proxy';
|
||||
export * from '../generated-wrappers/ownable';
|
||||
export * from '../generated-wrappers/static_call_proxy';
|
||||
export * from '../generated-wrappers/test_erc20_bridge';
|
||||
export * from '../generated-wrappers/test_eth2_dai_bridge';
|
||||
export * from '../generated-wrappers/test_static_call_target';
|
||||
|
@@ -27,9 +27,11 @@ describe('Authorizable', () => {
|
||||
before(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await blockchainLifecycle.revertAsync();
|
||||
});
|
||||
|
||||
before(async () => {
|
||||
const accounts = await web3Wrapper.getAvailableAddressesAsync();
|
||||
[owner, address, notOwner] = _.slice(accounts, 0, 3);
|
||||
@@ -40,19 +42,23 @@ describe('Authorizable', () => {
|
||||
artifacts,
|
||||
);
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await blockchainLifecycle.revertAsync();
|
||||
});
|
||||
|
||||
describe('addAuthorizedAddress', () => {
|
||||
it('should throw if not called by owner', async () => {
|
||||
return expectTransactionFailedAsync(
|
||||
it('should revert if not called by owner', async () => {
|
||||
await expectTransactionFailedAsync(
|
||||
authorizable.addAuthorizedAddress.sendTransactionAsync(notOwner, { from: notOwner }),
|
||||
RevertReason.OnlyContractOwner,
|
||||
);
|
||||
});
|
||||
|
||||
it('should allow owner to add an authorized address', async () => {
|
||||
await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(
|
||||
address,
|
||||
@@ -62,7 +68,8 @@ describe('Authorizable', () => {
|
||||
const isAuthorized = await authorizable.authorized.callAsync(address);
|
||||
expect(isAuthorized).to.be.true();
|
||||
});
|
||||
it('should throw if owner attempts to authorize a duplicate address', async () => {
|
||||
|
||||
it('should revert if owner attempts to authorize a duplicate address', async () => {
|
||||
await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(
|
||||
address,
|
||||
{ from: owner },
|
||||
@@ -76,16 +83,14 @@ describe('Authorizable', () => {
|
||||
});
|
||||
|
||||
describe('removeAuthorizedAddress', () => {
|
||||
it('should throw if not called by owner', async () => {
|
||||
it('should revert if not called by owner', async () => {
|
||||
await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(
|
||||
address,
|
||||
{ from: owner },
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
return expectTransactionFailedAsync(
|
||||
authorizable.removeAuthorizedAddress.sendTransactionAsync(address, {
|
||||
from: notOwner,
|
||||
}),
|
||||
await expectTransactionFailedAsync(
|
||||
authorizable.removeAuthorizedAddress.sendTransactionAsync(address, { from: notOwner }),
|
||||
RevertReason.OnlyContractOwner,
|
||||
);
|
||||
});
|
||||
@@ -105,7 +110,7 @@ describe('Authorizable', () => {
|
||||
expect(isAuthorized).to.be.false();
|
||||
});
|
||||
|
||||
it('should throw if owner attempts to remove an address that is not authorized', async () => {
|
||||
it('should revert if owner attempts to remove an address that is not authorized', async () => {
|
||||
return expectTransactionFailedAsync(
|
||||
authorizable.removeAuthorizedAddress.sendTransactionAsync(address, {
|
||||
from: owner,
|
||||
@@ -116,21 +121,22 @@ describe('Authorizable', () => {
|
||||
});
|
||||
|
||||
describe('removeAuthorizedAddressAtIndex', () => {
|
||||
it('should throw if not called by owner', async () => {
|
||||
it('should revert if not called by owner', async () => {
|
||||
await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(
|
||||
address,
|
||||
{ from: owner },
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
const index = new BigNumber(0);
|
||||
return expectTransactionFailedAsync(
|
||||
await expectTransactionFailedAsync(
|
||||
authorizable.removeAuthorizedAddressAtIndex.sendTransactionAsync(address, index, {
|
||||
from: notOwner,
|
||||
}),
|
||||
RevertReason.OnlyContractOwner,
|
||||
);
|
||||
});
|
||||
it('should throw if index is >= authorities.length', async () => {
|
||||
|
||||
it('should revert if index is >= authorities.length', async () => {
|
||||
await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(
|
||||
address,
|
||||
{ from: owner },
|
||||
@@ -144,7 +150,8 @@ describe('Authorizable', () => {
|
||||
RevertReason.IndexOutOfBounds,
|
||||
);
|
||||
});
|
||||
it('should throw if owner attempts to remove an address that is not authorized', async () => {
|
||||
|
||||
it('should revert if owner attempts to remove an address that is not authorized', async () => {
|
||||
const index = new BigNumber(0);
|
||||
return expectTransactionFailedAsync(
|
||||
authorizable.removeAuthorizedAddressAtIndex.sendTransactionAsync(address, index, {
|
||||
@@ -153,7 +160,8 @@ describe('Authorizable', () => {
|
||||
RevertReason.TargetNotAuthorized,
|
||||
);
|
||||
});
|
||||
it('should throw if address at index does not match target', async () => {
|
||||
|
||||
it('should revert if address at index does not match target', async () => {
|
||||
const address1 = address;
|
||||
const address2 = notOwner;
|
||||
await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(
|
||||
@@ -174,6 +182,7 @@ describe('Authorizable', () => {
|
||||
RevertReason.AuthorizedAddressMismatch,
|
||||
);
|
||||
});
|
||||
|
||||
it('should allow owner to remove an authorized address', async () => {
|
||||
await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(
|
||||
address,
|
||||
|
@@ -17,7 +17,7 @@ import {
|
||||
import { BlockchainLifecycle } from '@0x/dev-utils';
|
||||
import { assetDataUtils } from '@0x/order-utils';
|
||||
import { AssetProxyId, RevertReason } from '@0x/types';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import { BigNumber, SafeMathRevertErrors } from '@0x/utils';
|
||||
import * as chai from 'chai';
|
||||
import { LogWithDecodedArgs } from 'ethereum-types';
|
||||
import * as ethUtil from 'ethereumjs-util';
|
||||
@@ -1748,9 +1748,14 @@ describe('ERC1155Proxy', () => {
|
||||
nftNotOwnerBalance,
|
||||
];
|
||||
await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances);
|
||||
const expectedError = new SafeMathRevertErrors.Uint256BinOpError(
|
||||
SafeMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow,
|
||||
maxUintValue,
|
||||
valueMultiplier,
|
||||
);
|
||||
// execute transfer
|
||||
// note - this will overflow because we are trying to transfer `maxUintValue * 2` of the 2nd token
|
||||
await expectTransactionFailedAsync(
|
||||
await expect(
|
||||
erc1155ProxyWrapper.transferFromAsync(
|
||||
spender,
|
||||
receiver,
|
||||
@@ -1761,8 +1766,7 @@ describe('ERC1155Proxy', () => {
|
||||
receiverCallbackData,
|
||||
authorized,
|
||||
),
|
||||
RevertReason.Uint256Overflow,
|
||||
);
|
||||
).to.revertWith(expectedError);
|
||||
});
|
||||
it('should revert if transferring > 1 instances of a non-fungible token (valueMultiplier field >1)', async () => {
|
||||
// setup test parameters
|
||||
@@ -1832,20 +1836,23 @@ describe('ERC1155Proxy', () => {
|
||||
// check balances before transfer
|
||||
const expectedInitialBalances = [spenderInitialFungibleBalance, receiverInitialFungibleBalance];
|
||||
await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances);
|
||||
// execute transfer
|
||||
await expectTransactionFailedAsync(
|
||||
erc1155ProxyWrapper.transferFromAsync(
|
||||
spender,
|
||||
receiver,
|
||||
erc1155Contract.address,
|
||||
tokensToTransfer,
|
||||
valuesToTransfer,
|
||||
valueMultiplier,
|
||||
receiverCallbackData,
|
||||
authorized,
|
||||
),
|
||||
RevertReason.Uint256Underflow,
|
||||
const expectedError = new SafeMathRevertErrors.Uint256BinOpError(
|
||||
SafeMathRevertErrors.BinOpErrorCodes.SubtractionUnderflow,
|
||||
spenderInitialFungibleBalance,
|
||||
valuesToTransfer[0].times(valueMultiplier),
|
||||
);
|
||||
// execute transfer
|
||||
const tx = erc1155ProxyWrapper.transferFromAsync(
|
||||
spender,
|
||||
receiver,
|
||||
erc1155Contract.address,
|
||||
tokensToTransfer,
|
||||
valuesToTransfer,
|
||||
valueMultiplier,
|
||||
receiverCallbackData,
|
||||
authorized,
|
||||
);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
it('should revert if sender allowance is insufficient', async () => {
|
||||
// dremove allowance for ERC1155 proxy
|
||||
|
299
contracts/asset-proxy/test/erc20bridge_proxy.ts
Normal file
299
contracts/asset-proxy/test/erc20bridge_proxy.ts
Normal file
@@ -0,0 +1,299 @@
|
||||
import {
|
||||
blockchainTests,
|
||||
constants,
|
||||
expect,
|
||||
getRandomInteger,
|
||||
hexLeftPad,
|
||||
hexRightPad,
|
||||
hexSlice,
|
||||
Numberish,
|
||||
randomAddress,
|
||||
} from '@0x/contracts-test-utils';
|
||||
import { AssetProxyId } from '@0x/types';
|
||||
import { AbiEncoder, AuthorizableRevertErrors, BigNumber, StringRevertError } from '@0x/utils';
|
||||
import { DecodedLogs } from 'ethereum-types';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import {
|
||||
artifacts,
|
||||
ERC20BridgeProxyContract,
|
||||
TestERC20BridgeBridgeWithdrawToEventArgs,
|
||||
TestERC20BridgeContract,
|
||||
} from '../src';
|
||||
|
||||
blockchainTests.resets('ERC20BridgeProxy unit tests', env => {
|
||||
const PROXY_ID = AssetProxyId.ERC20Bridge;
|
||||
const BRIDGE_SUCCESS_RETURN_DATA = hexRightPad(PROXY_ID);
|
||||
let owner: string;
|
||||
let badCaller: string;
|
||||
let assetProxy: ERC20BridgeProxyContract;
|
||||
let bridgeContract: TestERC20BridgeContract;
|
||||
let testTokenAddress: string;
|
||||
|
||||
before(async () => {
|
||||
[owner, badCaller] = await env.getAccountAddressesAsync();
|
||||
assetProxy = await ERC20BridgeProxyContract.deployFrom0xArtifactAsync(
|
||||
artifacts.ERC20BridgeProxy,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
artifacts,
|
||||
);
|
||||
bridgeContract = await TestERC20BridgeContract.deployFrom0xArtifactAsync(
|
||||
artifacts.TestERC20Bridge,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
artifacts,
|
||||
);
|
||||
testTokenAddress = await bridgeContract.testToken.callAsync();
|
||||
await assetProxy.addAuthorizedAddress.awaitTransactionSuccessAsync(owner);
|
||||
});
|
||||
|
||||
interface AssetDataOpts {
|
||||
tokenAddress: string;
|
||||
bridgeAddress: string;
|
||||
bridgeData: BridgeDataOpts;
|
||||
}
|
||||
|
||||
interface BridgeDataOpts {
|
||||
transferAmount: Numberish;
|
||||
revertError?: string;
|
||||
returnData: string;
|
||||
}
|
||||
|
||||
function createAssetData(opts?: Partial<AssetDataOpts>): AssetDataOpts {
|
||||
return _.merge(
|
||||
{
|
||||
tokenAddress: testTokenAddress,
|
||||
bridgeAddress: bridgeContract.address,
|
||||
bridgeData: createBridgeData(),
|
||||
},
|
||||
opts,
|
||||
);
|
||||
}
|
||||
|
||||
function createBridgeData(opts?: Partial<BridgeDataOpts>): BridgeDataOpts {
|
||||
return _.merge(
|
||||
{
|
||||
transferAmount: constants.ZERO_AMOUNT,
|
||||
returnData: BRIDGE_SUCCESS_RETURN_DATA,
|
||||
},
|
||||
opts,
|
||||
);
|
||||
}
|
||||
|
||||
function encodeAssetData(opts: AssetDataOpts): string {
|
||||
const encoder = AbiEncoder.createMethod('ERC20BridgeProxy', [
|
||||
{ name: 'tokenAddress', type: 'address' },
|
||||
{ name: 'bridgeAddress', type: 'address' },
|
||||
{ name: 'bridgeData', type: 'bytes' },
|
||||
]);
|
||||
return encoder.encode([opts.tokenAddress, opts.bridgeAddress, encodeBridgeData(opts.bridgeData)]);
|
||||
}
|
||||
|
||||
function encodeBridgeData(opts: BridgeDataOpts): string {
|
||||
const encoder = AbiEncoder.create([
|
||||
{ name: 'transferAmount', type: 'int256' },
|
||||
{ name: 'revertData', type: 'bytes' },
|
||||
{ name: 'returnData', type: 'bytes' },
|
||||
]);
|
||||
const revertErrorBytes =
|
||||
opts.revertError !== undefined ? new StringRevertError(opts.revertError).encode() : '0x';
|
||||
return encoder.encode([new BigNumber(opts.transferAmount), revertErrorBytes, opts.returnData]);
|
||||
}
|
||||
|
||||
async function setTestTokenBalanceAsync(_owner: string, balance: Numberish): Promise<void> {
|
||||
await bridgeContract.setTestTokenBalance.awaitTransactionSuccessAsync(_owner, new BigNumber(balance));
|
||||
}
|
||||
|
||||
describe('transferFrom()', () => {
|
||||
interface TransferFromOpts {
|
||||
assetData: AssetDataOpts;
|
||||
from: string;
|
||||
to: string;
|
||||
amount: Numberish;
|
||||
}
|
||||
|
||||
function createTransferFromOpts(opts?: Partial<TransferFromOpts>): TransferFromOpts {
|
||||
const transferAmount = _.get(opts, ['amount'], getRandomInteger(1, 100e18)) as BigNumber;
|
||||
return _.merge(
|
||||
{
|
||||
assetData: createAssetData({
|
||||
bridgeData: createBridgeData({
|
||||
transferAmount,
|
||||
}),
|
||||
}),
|
||||
from: randomAddress(),
|
||||
to: randomAddress(),
|
||||
amount: transferAmount,
|
||||
},
|
||||
opts,
|
||||
);
|
||||
}
|
||||
|
||||
async function transferFromAsync(opts?: Partial<TransferFromOpts>, caller?: string): Promise<DecodedLogs> {
|
||||
const _opts = createTransferFromOpts(opts);
|
||||
const { logs } = await assetProxy.transferFrom.awaitTransactionSuccessAsync(
|
||||
encodeAssetData(_opts.assetData),
|
||||
_opts.from,
|
||||
_opts.to,
|
||||
new BigNumber(_opts.amount),
|
||||
{ from: caller },
|
||||
);
|
||||
return (logs as any) as DecodedLogs;
|
||||
}
|
||||
|
||||
it('succeeds if the bridge succeeds and balance increases by `amount`', async () => {
|
||||
const tx = transferFromAsync();
|
||||
return expect(tx).to.be.fulfilled('');
|
||||
});
|
||||
|
||||
it('succeeds if balance increases more than `amount`', async () => {
|
||||
const amount = getRandomInteger(1, 100e18);
|
||||
const tx = transferFromAsync({
|
||||
amount,
|
||||
assetData: createAssetData({
|
||||
bridgeData: createBridgeData({
|
||||
transferAmount: amount.plus(1),
|
||||
}),
|
||||
}),
|
||||
});
|
||||
return expect(tx).to.be.fulfilled('');
|
||||
});
|
||||
|
||||
it('passes the correct arguments to the bridge contract', async () => {
|
||||
const opts = createTransferFromOpts();
|
||||
const logs = await transferFromAsync(opts);
|
||||
expect(logs.length).to.eq(1);
|
||||
const args = logs[0].args as TestERC20BridgeBridgeWithdrawToEventArgs;
|
||||
expect(args.tokenAddress).to.eq(opts.assetData.tokenAddress);
|
||||
expect(args.from).to.eq(opts.from);
|
||||
expect(args.to).to.eq(opts.to);
|
||||
expect(args.amount).to.bignumber.eq(opts.amount);
|
||||
expect(args.bridgeData).to.eq(encodeBridgeData(opts.assetData.bridgeData));
|
||||
});
|
||||
|
||||
it('fails if not called by an authorized address', async () => {
|
||||
const tx = transferFromAsync({}, badCaller);
|
||||
return expect(tx).to.revertWith(new AuthorizableRevertErrors.SenderNotAuthorizedError(badCaller));
|
||||
});
|
||||
|
||||
it('fails if asset data is truncated', async () => {
|
||||
const opts = createTransferFromOpts();
|
||||
const truncatedAssetData = hexSlice(encodeAssetData(opts.assetData), 0, -1);
|
||||
const tx = assetProxy.transferFrom.awaitTransactionSuccessAsync(
|
||||
truncatedAssetData,
|
||||
opts.from,
|
||||
opts.to,
|
||||
new BigNumber(opts.amount),
|
||||
);
|
||||
return expect(tx).to.be.rejected();
|
||||
});
|
||||
|
||||
it('fails if bridge returns nothing', async () => {
|
||||
const tx = transferFromAsync({
|
||||
assetData: createAssetData({
|
||||
bridgeData: createBridgeData({
|
||||
returnData: '0x',
|
||||
}),
|
||||
}),
|
||||
});
|
||||
// This will actually revert when the AP tries to decode the return
|
||||
// value.
|
||||
return expect(tx).to.be.rejected();
|
||||
});
|
||||
|
||||
it('fails if bridge returns true', async () => {
|
||||
const tx = transferFromAsync({
|
||||
assetData: createAssetData({
|
||||
bridgeData: createBridgeData({
|
||||
returnData: hexLeftPad('0x1'),
|
||||
}),
|
||||
}),
|
||||
});
|
||||
// This will actually revert when the AP tries to decode the return
|
||||
// value.
|
||||
return expect(tx).to.be.rejected();
|
||||
});
|
||||
|
||||
it('fails if bridge returns 0x1', async () => {
|
||||
const tx = transferFromAsync({
|
||||
assetData: createAssetData({
|
||||
bridgeData: createBridgeData({
|
||||
returnData: hexRightPad('0x1'),
|
||||
}),
|
||||
}),
|
||||
});
|
||||
return expect(tx).to.revertWith('BRIDGE_FAILED');
|
||||
});
|
||||
|
||||
it('fails if bridge is an EOA', async () => {
|
||||
const tx = transferFromAsync({
|
||||
assetData: createAssetData({
|
||||
bridgeAddress: randomAddress(),
|
||||
}),
|
||||
});
|
||||
// This will actually revert when the AP tries to decode the return
|
||||
// value.
|
||||
return expect(tx).to.be.rejected();
|
||||
});
|
||||
|
||||
it('fails if bridge reverts', async () => {
|
||||
const revertError = 'FOOBAR';
|
||||
const tx = transferFromAsync({
|
||||
assetData: createAssetData({
|
||||
bridgeData: createBridgeData({
|
||||
revertError,
|
||||
}),
|
||||
}),
|
||||
});
|
||||
return expect(tx).to.revertWith(revertError);
|
||||
});
|
||||
|
||||
it('fails if balance of `to` increases by less than `amount`', async () => {
|
||||
const amount = getRandomInteger(1, 100e18);
|
||||
const tx = transferFromAsync({
|
||||
amount,
|
||||
assetData: createAssetData({
|
||||
bridgeData: createBridgeData({
|
||||
transferAmount: amount.minus(1),
|
||||
}),
|
||||
}),
|
||||
});
|
||||
return expect(tx).to.revertWith('BRIDGE_UNDERPAY');
|
||||
});
|
||||
|
||||
it('fails if balance of `to` decreases', async () => {
|
||||
const toAddress = randomAddress();
|
||||
await setTestTokenBalanceAsync(toAddress, 1e18);
|
||||
const tx = transferFromAsync({
|
||||
to: toAddress,
|
||||
assetData: createAssetData({
|
||||
bridgeData: createBridgeData({
|
||||
transferAmount: -1,
|
||||
}),
|
||||
}),
|
||||
});
|
||||
return expect(tx).to.revertWith('BRIDGE_UNDERPAY');
|
||||
});
|
||||
});
|
||||
|
||||
describe('balanceOf()', () => {
|
||||
it('retrieves the balance of the encoded token', async () => {
|
||||
const _owner = randomAddress();
|
||||
const balance = getRandomInteger(1, 100e18);
|
||||
await bridgeContract.setTestTokenBalance.awaitTransactionSuccessAsync(_owner, balance);
|
||||
const assetData = createAssetData({
|
||||
tokenAddress: testTokenAddress,
|
||||
});
|
||||
const actualBalance = await assetProxy.balanceOf.callAsync(encodeAssetData(assetData), _owner);
|
||||
expect(actualBalance).to.bignumber.eq(balance);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getProxyId()', () => {
|
||||
it('returns the correct proxy ID', async () => {
|
||||
const proxyId = await assetProxy.getProxyId.callAsync();
|
||||
expect(proxyId).to.eq(PROXY_ID);
|
||||
});
|
||||
});
|
||||
});
|
192
contracts/asset-proxy/test/eth2dai_bridge.ts
Normal file
192
contracts/asset-proxy/test/eth2dai_bridge.ts
Normal file
@@ -0,0 +1,192 @@
|
||||
import {
|
||||
blockchainTests,
|
||||
constants,
|
||||
expect,
|
||||
filterLogsToArguments,
|
||||
getRandomInteger,
|
||||
hexLeftPad,
|
||||
hexRandom,
|
||||
Numberish,
|
||||
randomAddress,
|
||||
TransactionHelper,
|
||||
} from '@0x/contracts-test-utils';
|
||||
import { AssetProxyId } from '@0x/types';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import { DecodedLogs } from 'ethereum-types';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import {
|
||||
artifacts,
|
||||
TestEth2DaiBridgeContract,
|
||||
TestEth2DaiBridgeEvents,
|
||||
TestEth2DaiBridgeSellAllAmountEventArgs,
|
||||
TestEth2DaiBridgeTokenApproveEventArgs,
|
||||
TestEth2DaiBridgeTokenTransferEventArgs,
|
||||
} from '../src';
|
||||
|
||||
blockchainTests.resets('Eth2DaiBridge unit tests', env => {
|
||||
const txHelper = new TransactionHelper(env.web3Wrapper, artifacts);
|
||||
let testContract: TestEth2DaiBridgeContract;
|
||||
|
||||
before(async () => {
|
||||
testContract = await TestEth2DaiBridgeContract.deployFrom0xArtifactAsync(
|
||||
artifacts.TestEth2DaiBridge,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
artifacts,
|
||||
);
|
||||
});
|
||||
|
||||
describe('isValidSignature()', () => {
|
||||
it('returns success bytes', async () => {
|
||||
const LEGACY_WALLET_MAGIC_VALUE = '0xb0671381';
|
||||
const result = await testContract.isValidSignature.callAsync(hexRandom(), hexRandom(_.random(0, 32)));
|
||||
expect(result).to.eq(LEGACY_WALLET_MAGIC_VALUE);
|
||||
});
|
||||
});
|
||||
|
||||
describe('withdrawTo()', () => {
|
||||
interface WithdrawToOpts {
|
||||
toTokenAddress?: string;
|
||||
fromTokenAddress?: string;
|
||||
toAddress: string;
|
||||
amount: Numberish;
|
||||
fromTokenBalance: Numberish;
|
||||
revertReason: string;
|
||||
fillAmount: Numberish;
|
||||
toTokentransferRevertReason: string;
|
||||
toTokenTransferReturnData: string;
|
||||
}
|
||||
|
||||
interface WithdrawToResult {
|
||||
opts: WithdrawToOpts;
|
||||
result: string;
|
||||
logs: DecodedLogs;
|
||||
}
|
||||
|
||||
function createWithdrawToOpts(opts?: Partial<WithdrawToOpts>): WithdrawToOpts {
|
||||
return {
|
||||
toAddress: randomAddress(),
|
||||
amount: getRandomInteger(1, 100e18),
|
||||
revertReason: '',
|
||||
fillAmount: getRandomInteger(1, 100e18),
|
||||
fromTokenBalance: getRandomInteger(1, 100e18),
|
||||
toTokentransferRevertReason: '',
|
||||
toTokenTransferReturnData: hexLeftPad(1),
|
||||
...opts,
|
||||
};
|
||||
}
|
||||
|
||||
async function withdrawToAsync(opts?: Partial<WithdrawToOpts>): Promise<WithdrawToResult> {
|
||||
const _opts = createWithdrawToOpts(opts);
|
||||
// Set the fill behavior.
|
||||
await testContract.setFillBehavior.awaitTransactionSuccessAsync(
|
||||
_opts.revertReason,
|
||||
new BigNumber(_opts.fillAmount),
|
||||
);
|
||||
// Create tokens and balances.
|
||||
if (_opts.fromTokenAddress === undefined) {
|
||||
[_opts.fromTokenAddress] = await txHelper.getResultAndReceiptAsync(
|
||||
testContract.createToken,
|
||||
new BigNumber(_opts.fromTokenBalance),
|
||||
);
|
||||
}
|
||||
if (_opts.toTokenAddress === undefined) {
|
||||
[_opts.toTokenAddress] = await txHelper.getResultAndReceiptAsync(
|
||||
testContract.createToken,
|
||||
constants.ZERO_AMOUNT,
|
||||
);
|
||||
}
|
||||
// Set the transfer behavior of `toTokenAddress`.
|
||||
await testContract.setTransferBehavior.awaitTransactionSuccessAsync(
|
||||
_opts.toTokenAddress,
|
||||
_opts.toTokentransferRevertReason,
|
||||
_opts.toTokenTransferReturnData,
|
||||
);
|
||||
// Call withdrawTo().
|
||||
const [result, { logs }] = await txHelper.getResultAndReceiptAsync(
|
||||
testContract.withdrawTo,
|
||||
// "to" token address
|
||||
_opts.toTokenAddress,
|
||||
// Random from address.
|
||||
randomAddress(),
|
||||
// To address.
|
||||
_opts.toAddress,
|
||||
new BigNumber(_opts.amount),
|
||||
// ABI-encode the "from" token address as the bridge data.
|
||||
hexLeftPad(_opts.fromTokenAddress as string),
|
||||
);
|
||||
return {
|
||||
opts: _opts,
|
||||
result,
|
||||
logs: (logs as any) as DecodedLogs,
|
||||
};
|
||||
}
|
||||
|
||||
it('returns magic bytes on success', async () => {
|
||||
const BRIDGE_SUCCESS_RETURN_DATA = AssetProxyId.ERC20Bridge;
|
||||
const { result } = await withdrawToAsync();
|
||||
expect(result).to.eq(BRIDGE_SUCCESS_RETURN_DATA);
|
||||
});
|
||||
|
||||
it('calls `Eth2Dai.sellAllAmount()`', async () => {
|
||||
const { opts, logs } = await withdrawToAsync();
|
||||
const transfers = filterLogsToArguments<TestEth2DaiBridgeSellAllAmountEventArgs>(
|
||||
logs,
|
||||
TestEth2DaiBridgeEvents.SellAllAmount,
|
||||
);
|
||||
expect(transfers.length).to.eq(1);
|
||||
expect(transfers[0].sellToken).to.eq(opts.fromTokenAddress);
|
||||
expect(transfers[0].buyToken).to.eq(opts.toTokenAddress);
|
||||
expect(transfers[0].sellTokenAmount).to.bignumber.eq(opts.fromTokenBalance);
|
||||
expect(transfers[0].minimumFillAmount).to.bignumber.eq(opts.amount);
|
||||
});
|
||||
|
||||
it('sets an unlimited allowance on the `fromTokenAddress` token', async () => {
|
||||
const { opts, logs } = await withdrawToAsync();
|
||||
const approvals = filterLogsToArguments<TestEth2DaiBridgeTokenApproveEventArgs>(
|
||||
logs,
|
||||
TestEth2DaiBridgeEvents.TokenApprove,
|
||||
);
|
||||
expect(approvals.length).to.eq(1);
|
||||
expect(approvals[0].token).to.eq(opts.fromTokenAddress);
|
||||
expect(approvals[0].spender).to.eq(testContract.address);
|
||||
expect(approvals[0].allowance).to.bignumber.eq(constants.MAX_UINT256);
|
||||
});
|
||||
|
||||
it('transfers filled amount to `to`', async () => {
|
||||
const { opts, logs } = await withdrawToAsync();
|
||||
const transfers = filterLogsToArguments<TestEth2DaiBridgeTokenTransferEventArgs>(
|
||||
logs,
|
||||
TestEth2DaiBridgeEvents.TokenTransfer,
|
||||
);
|
||||
expect(transfers.length).to.eq(1);
|
||||
expect(transfers[0].token).to.eq(opts.toTokenAddress);
|
||||
expect(transfers[0].from).to.eq(testContract.address);
|
||||
expect(transfers[0].to).to.eq(opts.toAddress);
|
||||
expect(transfers[0].amount).to.bignumber.eq(opts.fillAmount);
|
||||
});
|
||||
|
||||
it('fails if `Eth2Dai.sellAllAmount()` reverts', async () => {
|
||||
const opts = createWithdrawToOpts({ revertReason: 'FOOBAR' });
|
||||
const tx = withdrawToAsync(opts);
|
||||
return expect(tx).to.revertWith(opts.revertReason);
|
||||
});
|
||||
|
||||
it('fails if `toTokenAddress.transfer()` reverts', async () => {
|
||||
const opts = createWithdrawToOpts({ toTokentransferRevertReason: 'FOOBAR' });
|
||||
const tx = withdrawToAsync(opts);
|
||||
return expect(tx).to.revertWith(opts.toTokentransferRevertReason);
|
||||
});
|
||||
|
||||
it('fails if `toTokenAddress.transfer()` returns falsey', async () => {
|
||||
const opts = createWithdrawToOpts({ toTokenTransferReturnData: hexLeftPad(0) });
|
||||
const tx = withdrawToAsync(opts);
|
||||
return expect(tx).to.revertWith('ERC20_TRANSFER_FAILED');
|
||||
});
|
||||
|
||||
it('succeeds if `toTokenAddress.transfer()` returns truthy', async () => {
|
||||
await withdrawToAsync({ toTokenTransferReturnData: hexLeftPad(100) });
|
||||
});
|
||||
});
|
||||
});
|
@@ -679,7 +679,14 @@ describe('Asset Transfer Proxies', () => {
|
||||
// Verify pre-condition
|
||||
const ownerFromAsset = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId);
|
||||
expect(ownerFromAsset).to.be.equal(fromAddress);
|
||||
// Remove transfer approval for fromAddress.
|
||||
// Remove blanket transfer approval for fromAddress.
|
||||
await erc721TokenA.setApprovalForAll.awaitTransactionSuccessAsync(
|
||||
erc721Proxy.address,
|
||||
false,
|
||||
{ from: fromAddress },
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
// Remove token transfer approval for fromAddress.
|
||||
await erc721TokenA.approve.awaitTransactionSuccessAsync(
|
||||
constants.NULL_ADDRESS,
|
||||
erc721AFromTokenId,
|
||||
|
@@ -43,7 +43,13 @@ describe('StaticCallProxy', () => {
|
||||
txDefaults,
|
||||
artifacts,
|
||||
);
|
||||
staticCallProxy = new IAssetProxyContract(staticCallProxyWithoutTransferFrom.address, provider, txDefaults);
|
||||
staticCallProxy = new IAssetProxyContract(
|
||||
staticCallProxyWithoutTransferFrom.address,
|
||||
provider,
|
||||
txDefaults,
|
||||
{},
|
||||
StaticCallProxyContract.deployedBytecode,
|
||||
);
|
||||
staticCallTarget = await TestStaticCallTargetContract.deployFrom0xArtifactAsync(
|
||||
artifacts.TestStaticCallTarget,
|
||||
provider,
|
||||
|
@@ -336,6 +336,22 @@ export class ERC1155ProxyWrapper {
|
||||
};
|
||||
return holdingsByOwner;
|
||||
}
|
||||
/**
|
||||
* @dev Set the approval for the proxy on behalf of `userAddress` .
|
||||
* @param userAddress owner of ERC1155 tokens.
|
||||
* @param contractAddress address of ERC1155 contract.
|
||||
* @param isApproved Whether to approve the proxy for all or not.
|
||||
*/
|
||||
public async setProxyAllowanceForAllAsync(
|
||||
userAddress: string,
|
||||
contractAddress: string,
|
||||
isApproved: boolean,
|
||||
): Promise<void> {
|
||||
this._validateProxyContractExistsOrThrow();
|
||||
const tokenWrapper = this.getContractWrapper(contractAddress);
|
||||
const operator = (this._proxyContract as ERC1155ProxyContract).address;
|
||||
await tokenWrapper.setApprovalForAllAsync(userAddress, operator, isApproved);
|
||||
}
|
||||
/**
|
||||
* @dev Checks if proxy is approved to transfer tokens on behalf of `userAddress`.
|
||||
* @param userAddress owner of ERC1155 tokens.
|
||||
|
@@ -71,7 +71,7 @@ export class ERC721Wrapper {
|
||||
}
|
||||
this._initialTokenIdsByOwner[tokenOwnerAddress][dummyTokenContract.address].push(tokenId);
|
||||
|
||||
await this.approveProxyAsync(dummyTokenContract.address, tokenId);
|
||||
await this.approveProxyForAllAsync(dummyTokenContract.address, tokenOwnerAddress, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -86,14 +86,17 @@ export class ERC721Wrapper {
|
||||
const proxyAddress = (this._proxyContract as ERC721ProxyContract).address;
|
||||
await this.approveAsync(proxyAddress, tokenAddress, tokenId);
|
||||
}
|
||||
public async approveProxyForAllAsync(tokenAddress: string, tokenId: BigNumber, isApproved: boolean): Promise<void> {
|
||||
public async approveProxyForAllAsync(
|
||||
tokenAddress: string,
|
||||
ownerAddress: string,
|
||||
isApproved: boolean,
|
||||
): Promise<void> {
|
||||
const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
|
||||
const tokenOwner = await this.ownerOfAsync(tokenAddress, tokenId);
|
||||
const proxyAddress = (this._proxyContract as ERC721ProxyContract).address;
|
||||
await tokenContract.setApprovalForAll.awaitTransactionSuccessAsync(
|
||||
proxyAddress,
|
||||
isApproved,
|
||||
{ from: tokenOwner },
|
||||
{ from: ownerAddress },
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
}
|
||||
|
96
contracts/asset-proxy/truffle-config.js
Normal file
96
contracts/asset-proxy/truffle-config.js
Normal file
@@ -0,0 +1,96 @@
|
||||
/**
|
||||
* Use this file to configure your truffle project. It's seeded with some
|
||||
* common settings for different networks and features like migrations,
|
||||
* compilation and testing. Uncomment the ones you need or modify
|
||||
* them to suit your project as necessary.
|
||||
*
|
||||
* More information about configuration can be found at:
|
||||
*
|
||||
* truffleframework.com/docs/advanced/configuration
|
||||
*
|
||||
* To deploy via Infura you'll need a wallet provider (like truffle-hdwallet-provider)
|
||||
* to sign your transactions before they're sent to a remote public node. Infura accounts
|
||||
* are available for free at: infura.io/register.
|
||||
*
|
||||
* You'll also need a mnemonic - the twelve word phrase the wallet uses to generate
|
||||
* public/private key pairs. If you're publishing your code to GitHub make sure you load this
|
||||
* phrase from a file you've .gitignored so it doesn't accidentally become public.
|
||||
*
|
||||
*/
|
||||
|
||||
// const HDWalletProvider = require('truffle-hdwallet-provider');
|
||||
// const infuraKey = "fj4jll3k.....";
|
||||
//
|
||||
// const fs = require('fs');
|
||||
// const mnemonic = fs.readFileSync(".secret").toString().trim();
|
||||
|
||||
module.exports = {
|
||||
/**
|
||||
* Networks define how you connect to your ethereum client and let you set the
|
||||
* defaults web3 uses to send transactions. If you don't specify one truffle
|
||||
* will spin up a development blockchain for you on port 9545 when you
|
||||
* run `develop` or `test`. You can ask a truffle command to use a specific
|
||||
* network from the command line, e.g
|
||||
*
|
||||
* $ truffle test --network <network-name>
|
||||
*/
|
||||
|
||||
networks: {
|
||||
// Useful for testing. The `development` name is special - truffle uses it by default
|
||||
// if it's defined here and no other network is specified at the command line.
|
||||
// You should run a client (like ganache-cli, geth or parity) in a separate terminal
|
||||
// tab if you use this network and you must also set the `host`, `port` and `network_id`
|
||||
// options below to some value.
|
||||
//
|
||||
// development: {
|
||||
// host: "127.0.0.1", // Localhost (default: none)
|
||||
// port: 8545, // Standard Ethereum port (default: none)
|
||||
// network_id: "*", // Any network (default: none)
|
||||
// },
|
||||
// Another network with more advanced options...
|
||||
// advanced: {
|
||||
// port: 8777, // Custom port
|
||||
// network_id: 1342, // Custom network
|
||||
// gas: 8500000, // Gas sent with each transaction (default: ~6700000)
|
||||
// gasPrice: 20000000000, // 20 gwei (in wei) (default: 100 gwei)
|
||||
// from: <address>, // Account to send txs from (default: accounts[0])
|
||||
// websockets: true // Enable EventEmitter interface for web3 (default: false)
|
||||
// },
|
||||
// Useful for deploying to a public network.
|
||||
// NB: It's important to wrap the provider as a function.
|
||||
// ropsten: {
|
||||
// provider: () => new HDWalletProvider(mnemonic, `https://ropsten.infura.io/v3/YOUR-PROJECT-ID`),
|
||||
// network_id: 3, // Ropsten's id
|
||||
// gas: 5500000, // Ropsten has a lower block limit than mainnet
|
||||
// confirmations: 2, // # of confs to wait between deployments. (default: 0)
|
||||
// timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50)
|
||||
// skipDryRun: true // Skip dry run before migrations? (default: false for public nets )
|
||||
// },
|
||||
// Useful for private networks
|
||||
// private: {
|
||||
// provider: () => new HDWalletProvider(mnemonic, `https://network.io`),
|
||||
// network_id: 2111, // This network is yours, in the cloud.
|
||||
// production: true // Treats this network as if it was a public net. (default: false)
|
||||
// }
|
||||
},
|
||||
|
||||
// Set default mocha options here, use special reporters etc.
|
||||
mocha: {
|
||||
// timeout: 100000
|
||||
},
|
||||
|
||||
// Configure your compilers
|
||||
compilers: {
|
||||
solc: {
|
||||
version: '0.5.9',
|
||||
settings: {
|
||||
evmVersion: 'constantinople',
|
||||
optimizer: {
|
||||
enabled: true,
|
||||
runs: 1000000,
|
||||
details: { yul: true, deduplicate: true, cse: true, constantOptimizer: true },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
@@ -4,14 +4,24 @@
|
||||
"include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
|
||||
"files": [
|
||||
"generated-artifacts/ERC1155Proxy.json",
|
||||
"generated-artifacts/ERC20BridgeProxy.json",
|
||||
"generated-artifacts/ERC20Proxy.json",
|
||||
"generated-artifacts/ERC721Proxy.json",
|
||||
"generated-artifacts/Eth2DaiBridge.json",
|
||||
"generated-artifacts/IAssetData.json",
|
||||
"generated-artifacts/IAssetProxy.json",
|
||||
"generated-artifacts/IAssetProxyDispatcher.json",
|
||||
"generated-artifacts/IAuthorizable.json",
|
||||
"generated-artifacts/IERC20Bridge.json",
|
||||
"generated-artifacts/IEth2Dai.json",
|
||||
"generated-artifacts/IWallet.json",
|
||||
"generated-artifacts/MixinAssetProxyDispatcher.json",
|
||||
"generated-artifacts/MixinAuthorizable.json",
|
||||
"generated-artifacts/MultiAssetProxy.json",
|
||||
"generated-artifacts/Ownable.json",
|
||||
"generated-artifacts/StaticCallProxy.json",
|
||||
"generated-artifacts/TestERC20Bridge.json",
|
||||
"generated-artifacts/TestEth2DaiBridge.json",
|
||||
"generated-artifacts/TestStaticCallTarget.json"
|
||||
],
|
||||
"exclude": ["./deploy/solc/solc_bin"]
|
||||
|
2
contracts/coordinator/.solhintignore
Normal file
2
contracts/coordinator/.solhintignore
Normal file
@@ -0,0 +1,2 @@
|
||||
# solhint can't parse `abi.decode` syntax.
|
||||
contracts/src/MixinCoordinatorApprovalVerifier.sol
|
@@ -1,4 +1,77 @@
|
||||
[
|
||||
{
|
||||
"version": "2.1.0-beta.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Add chainId to domain separator",
|
||||
"pr": 1742
|
||||
},
|
||||
{
|
||||
"note": "Inherit Exchange domain constants from `exchange-libs` to reduce code duplication",
|
||||
"pr": 1742
|
||||
},
|
||||
{
|
||||
"note": "Update domain separator",
|
||||
"pr": 1742
|
||||
},
|
||||
{
|
||||
"note": "Refactor contract to use new ITransactions interface",
|
||||
"pr": 1753
|
||||
},
|
||||
{
|
||||
"note": "Add verifyingContractIfExists arg to LibEIP712CoordinatorDomain constructor",
|
||||
"pr": 1753
|
||||
},
|
||||
{
|
||||
"note": "Remove LibZeroExTransaction contract",
|
||||
"pr": 1753
|
||||
},
|
||||
{
|
||||
"note": "Update tests for arbitrary fee tokens (ZEIP-28).",
|
||||
"pr": 1819
|
||||
},
|
||||
{
|
||||
"note": "Update for new `marketXOrders` consolidation.",
|
||||
"pr": 2042
|
||||
},
|
||||
{
|
||||
"note": "Use built in selectors instead of hard coded constants",
|
||||
"pr": 2055
|
||||
},
|
||||
{
|
||||
"note": "Compile and export all contracts, artifacts, and wrappers by default",
|
||||
"pr": 2055
|
||||
}
|
||||
],
|
||||
"timestamp": 1570135330
|
||||
},
|
||||
{
|
||||
"timestamp": 1568744790,
|
||||
"version": "2.0.13",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1567521715,
|
||||
"version": "2.0.12",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1566446343,
|
||||
"version": "2.0.11",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1565296576,
|
||||
"version": "2.0.10",
|
||||
|
@@ -5,6 +5,31 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v2.1.0-beta.0 - _October 3, 2019_
|
||||
|
||||
* Add chainId to domain separator (#1742)
|
||||
* Inherit Exchange domain constants from `exchange-libs` to reduce code duplication (#1742)
|
||||
* Update domain separator (#1742)
|
||||
* Refactor contract to use new ITransactions interface (#1753)
|
||||
* Add verifyingContractIfExists arg to LibEIP712CoordinatorDomain constructor (#1753)
|
||||
* Remove LibZeroExTransaction contract (#1753)
|
||||
* Update tests for arbitrary fee tokens (ZEIP-28). (#1819)
|
||||
* Update for new `marketXOrders` consolidation. (#2042)
|
||||
* Use built in selectors instead of hard coded constants (#2055)
|
||||
* Compile and export all contracts, artifacts, and wrappers by default (#2055)
|
||||
|
||||
## v2.0.13 - _September 17, 2019_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v2.0.12 - _September 3, 2019_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v2.0.11 - _August 22, 2019_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v2.0.10 - _August 8, 2019_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
## Coordinator
|
||||
|
||||
This package contains a contract that allows users to call arbitrary functions on the Exchange contract with permission from one or more Coordinators. Addresses of the deployed contracts can be found in the 0x [wiki](https://0xproject.com/wiki#Deployed-Addresses) or the [DEPLOYS](./DEPLOYS.json) file within this package.
|
||||
This package contains a contract that allows users to call arbitrary functions on the Exchange contract with permission from one or more Coordinators. 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
|
||||
|
||||
@@ -12,7 +12,7 @@ npm install @0x/contracts-coordinator --save
|
||||
|
||||
## Bug bounty
|
||||
|
||||
A bug bounty for the 2.0.0 contracts is ongoing! Instructions can be found [here](https://0xproject.com/wiki#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
|
||||
|
||||
|
@@ -21,6 +21,5 @@
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"contracts": ["src/Coordinator.sol", "src/registry/CoordinatorRegistry.sol"]
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -16,10 +16,12 @@
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.5;
|
||||
pragma experimental "ABIEncoderV2";
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibEIP712ExchangeDomain.sol";
|
||||
import "./libs/LibConstants.sol";
|
||||
import "./libs/LibEIP712CoordinatorDomain.sol";
|
||||
import "./MixinSignatureValidator.sol";
|
||||
import "./MixinCoordinatorApprovalVerifier.sol";
|
||||
import "./MixinCoordinatorCore.sol";
|
||||
@@ -32,8 +34,12 @@ contract Coordinator is
|
||||
MixinCoordinatorApprovalVerifier,
|
||||
MixinCoordinatorCore
|
||||
{
|
||||
constructor (address _exchange)
|
||||
/// @param exchange Address of the 0x Exchange contract.
|
||||
/// @param chainId Chain ID of the network this contract is deployed on.
|
||||
constructor (address exchange, uint256 chainId)
|
||||
public
|
||||
LibConstants(_exchange)
|
||||
LibConstants(exchange)
|
||||
LibEIP712CoordinatorDomain(chainId, address(0))
|
||||
LibEIP712ExchangeDomain(chainId, exchange)
|
||||
{}
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -16,26 +16,25 @@
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.5;
|
||||
pragma experimental "ABIEncoderV2";
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibExchangeSelectors.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibZeroExTransaction.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibAddressArray.sol";
|
||||
import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol";
|
||||
import "./libs/LibCoordinatorApproval.sol";
|
||||
import "./libs/LibZeroExTransaction.sol";
|
||||
import "./mixins/MSignatureValidator.sol";
|
||||
import "./mixins/MCoordinatorApprovalVerifier.sol";
|
||||
import "./interfaces/ICoordinatorSignatureValidator.sol";
|
||||
import "./interfaces/ICoordinatorApprovalVerifier.sol";
|
||||
|
||||
|
||||
// solhint-disable avoid-tx-origin
|
||||
contract MixinCoordinatorApprovalVerifier is
|
||||
LibExchangeSelectors,
|
||||
LibCoordinatorApproval,
|
||||
LibZeroExTransaction,
|
||||
MSignatureValidator,
|
||||
MCoordinatorApprovalVerifier
|
||||
ICoordinatorSignatureValidator,
|
||||
ICoordinatorApprovalVerifier
|
||||
{
|
||||
using LibBytes for bytes;
|
||||
using LibAddressArray for address[];
|
||||
@@ -63,7 +62,7 @@ contract MixinCoordinatorApprovalVerifier is
|
||||
// No approval is required for non-fill methods
|
||||
if (orders.length > 0) {
|
||||
// Revert if approval is invalid for transaction orders
|
||||
assertValidTransactionOrdersApproval(
|
||||
_assertValidTransactionOrdersApproval(
|
||||
transaction,
|
||||
orders,
|
||||
txOrigin,
|
||||
@@ -84,9 +83,9 @@ contract MixinCoordinatorApprovalVerifier is
|
||||
{
|
||||
bytes4 selector = data.readBytes4(0);
|
||||
if (
|
||||
selector == FILL_ORDER_SELECTOR ||
|
||||
selector == FILL_ORDER_NO_THROW_SELECTOR ||
|
||||
selector == FILL_OR_KILL_ORDER_SELECTOR
|
||||
selector == IExchange(address(0)).fillOrder.selector ||
|
||||
selector == IExchange(address(0)).fillOrderNoThrow.selector ||
|
||||
selector == IExchange(address(0)).fillOrKillOrder.selector
|
||||
) {
|
||||
// Decode single order
|
||||
(LibOrder.Order memory order) = abi.decode(
|
||||
@@ -96,13 +95,11 @@ contract MixinCoordinatorApprovalVerifier is
|
||||
orders = new LibOrder.Order[](1);
|
||||
orders[0] = order;
|
||||
} else if (
|
||||
selector == BATCH_FILL_ORDERS_SELECTOR ||
|
||||
selector == BATCH_FILL_ORDERS_NO_THROW_SELECTOR ||
|
||||
selector == BATCH_FILL_OR_KILL_ORDERS_SELECTOR ||
|
||||
selector == MARKET_BUY_ORDERS_SELECTOR ||
|
||||
selector == MARKET_BUY_ORDERS_NO_THROW_SELECTOR ||
|
||||
selector == MARKET_SELL_ORDERS_SELECTOR ||
|
||||
selector == MARKET_SELL_ORDERS_NO_THROW_SELECTOR
|
||||
selector == IExchange(address(0)).batchFillOrders.selector ||
|
||||
selector == IExchange(address(0)).batchFillOrdersNoThrow.selector ||
|
||||
selector == IExchange(address(0)).batchFillOrKillOrders.selector ||
|
||||
selector == IExchange(address(0)).marketBuyOrders.selector ||
|
||||
selector == IExchange(address(0)).marketSellOrders.selector
|
||||
) {
|
||||
// Decode all orders
|
||||
// solhint-disable indent
|
||||
@@ -110,7 +107,7 @@ contract MixinCoordinatorApprovalVerifier is
|
||||
data.slice(4, data.length),
|
||||
(LibOrder.Order[])
|
||||
);
|
||||
} else if (selector == MATCH_ORDERS_SELECTOR) {
|
||||
} else if (selector == IExchange(address(0)).matchOrders.selector) {
|
||||
// Decode left and right orders
|
||||
(LibOrder.Order memory leftOrder, LibOrder.Order memory rightOrder) = abi.decode(
|
||||
data.slice(4, data.length),
|
||||
@@ -132,7 +129,7 @@ contract MixinCoordinatorApprovalVerifier is
|
||||
/// @param transactionSignature Proof that the transaction has been signed by the signer.
|
||||
/// @param approvalExpirationTimeSeconds Array of expiration times in seconds for which each corresponding approval signature expires.
|
||||
/// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each order.
|
||||
function assertValidTransactionOrdersApproval(
|
||||
function _assertValidTransactionOrdersApproval(
|
||||
LibZeroExTransaction.ZeroExTransaction memory transaction,
|
||||
LibOrder.Order[] memory orders,
|
||||
address txOrigin,
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -16,18 +16,18 @@
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.5;
|
||||
pragma experimental "ABIEncoderV2";
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "./libs/LibZeroExTransaction.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibZeroExTransaction.sol";
|
||||
import "./libs/LibConstants.sol";
|
||||
import "./mixins/MCoordinatorApprovalVerifier.sol";
|
||||
import "./interfaces/ICoordinatorCore.sol";
|
||||
import "./interfaces/ICoordinatorApprovalVerifier.sol";
|
||||
|
||||
|
||||
contract MixinCoordinatorCore is
|
||||
LibConstants,
|
||||
MCoordinatorApprovalVerifier,
|
||||
ICoordinatorApprovalVerifier,
|
||||
ICoordinatorCore
|
||||
{
|
||||
/// @dev Executes a 0x transaction that has been signed by the feeRecipients that correspond to each order in the transaction's Exchange calldata.
|
||||
@@ -55,11 +55,6 @@ contract MixinCoordinatorCore is
|
||||
);
|
||||
|
||||
// Execute the transaction
|
||||
EXCHANGE.executeTransaction(
|
||||
transaction.salt,
|
||||
transaction.signerAddress,
|
||||
transaction.data,
|
||||
transactionSignature
|
||||
);
|
||||
EXCHANGE.executeTransaction(transaction, transactionSignature);
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -16,14 +16,14 @@
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.5;
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
|
||||
import "./mixins/MSignatureValidator.sol";
|
||||
import "./interfaces/ICoordinatorSignatureValidator.sol";
|
||||
|
||||
|
||||
contract MixinSignatureValidator is
|
||||
MSignatureValidator
|
||||
ICoordinatorSignatureValidator
|
||||
{
|
||||
using LibBytes for bytes;
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -16,11 +16,11 @@
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.5;
|
||||
pragma experimental "ABIEncoderV2";
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
|
||||
import "../libs/LibZeroExTransaction.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibZeroExTransaction.sol";
|
||||
|
||||
|
||||
contract ICoordinatorApprovalVerifier {
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -16,10 +16,10 @@
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.5;
|
||||
pragma experimental "ABIEncoderV2";
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "../libs/LibZeroExTransaction.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibZeroExTransaction.sol";
|
||||
|
||||
|
||||
contract ICoordinatorCore {
|
||||
|
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
|
||||
contract ICoordinatorSignatureValidator {
|
||||
|
||||
// Allowed signature types.
|
||||
enum SignatureType {
|
||||
Illegal, // 0x00, default value
|
||||
Invalid, // 0x01
|
||||
EIP712, // 0x02
|
||||
EthSign, // 0x03
|
||||
Wallet, // 0x04
|
||||
Validator, // 0x05
|
||||
PreSigned, // 0x06
|
||||
OrderValidator, // 0x07
|
||||
WalletOrderValidator, // 0x08
|
||||
NSignatureTypes // 0x09, number of signature types. Always leave at end.
|
||||
}
|
||||
|
||||
/// @dev Recovers the address of a signer given a hash and signature.
|
||||
/// @param hash Any 32 byte hash.
|
||||
/// @param signature Proof that the hash has been signed by signer.
|
||||
function getSignerAddress(bytes32 hash, bytes memory signature)
|
||||
public
|
||||
pure
|
||||
returns (address signerAddress);
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -16,19 +16,21 @@
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.5;
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
import "../interfaces/ITransactions.sol";
|
||||
import "@0x/contracts-exchange/contracts/src/interfaces/ITransactions.sol";
|
||||
|
||||
|
||||
// solhint-disable var-name-mixedcase
|
||||
contract LibConstants {
|
||||
|
||||
// solhint-disable-next-line var-name-mixedcase
|
||||
// The 0x Exchange contract.
|
||||
ITransactions internal EXCHANGE;
|
||||
|
||||
constructor (address _exchange)
|
||||
/// @param exchange Address of the 0x Exchange contract.
|
||||
constructor (address exchange)
|
||||
public
|
||||
{
|
||||
EXCHANGE = ITransactions(_exchange);
|
||||
EXCHANGE = ITransactions(exchange);
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -16,14 +16,14 @@
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.5;
|
||||
pragma experimental "ABIEncoderV2";
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "./LibEIP712Domain.sol";
|
||||
import "./LibEIP712CoordinatorDomain.sol";
|
||||
|
||||
|
||||
contract LibCoordinatorApproval is
|
||||
LibEIP712Domain
|
||||
LibEIP712CoordinatorDomain
|
||||
{
|
||||
// Hash for the EIP712 Coordinator approval message
|
||||
// keccak256(abi.encodePacked(
|
||||
@@ -34,7 +34,7 @@ contract LibCoordinatorApproval is
|
||||
// "uint256 approvalExpirationTimeSeconds",
|
||||
// ")"
|
||||
// ));
|
||||
bytes32 constant internal EIP712_COORDINATOR_APPROVAL_SCHEMA_HASH = 0x2fbcdbaa76bc7589916958ae919dfbef04d23f6bbf26de6ff317b32c6cc01e05;
|
||||
bytes32 constant public EIP712_COORDINATOR_APPROVAL_SCHEMA_HASH = 0x2fbcdbaa76bc7589916958ae919dfbef04d23f6bbf26de6ff317b32c6cc01e05;
|
||||
|
||||
struct CoordinatorApproval {
|
||||
address txOrigin; // Required signer of Ethereum transaction that is submitting approval.
|
||||
@@ -51,14 +51,14 @@ contract LibCoordinatorApproval is
|
||||
view
|
||||
returns (bytes32 approvalHash)
|
||||
{
|
||||
approvalHash = hashEIP712CoordinatorMessage(hashCoordinatorApproval(approval));
|
||||
approvalHash = _hashEIP712CoordinatorMessage(_hashCoordinatorApproval(approval));
|
||||
return approvalHash;
|
||||
}
|
||||
|
||||
/// @dev Calculated the EIP712 hash of the Coordinator approval mesasage with no domain separator.
|
||||
/// @param approval Coordinator approval message containing the transaction hash, transaction signature, and expiration of the approval.
|
||||
/// @return EIP712 hash of the Coordinator approval message with no domain separator.
|
||||
function hashCoordinatorApproval(CoordinatorApproval memory approval)
|
||||
function _hashCoordinatorApproval(CoordinatorApproval memory approval)
|
||||
internal
|
||||
pure
|
||||
returns (bytes32 result)
|
||||
|
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
import "@0x/contracts-utils/contracts/src/LibEIP712.sol";
|
||||
|
||||
|
||||
contract LibEIP712CoordinatorDomain is
|
||||
LibEIP712
|
||||
{
|
||||
|
||||
// EIP712 Domain Name value for the Coordinator
|
||||
string constant public EIP712_COORDINATOR_DOMAIN_NAME = "0x Protocol Coordinator";
|
||||
|
||||
// EIP712 Domain Version value for the Coordinator
|
||||
string constant public EIP712_COORDINATOR_DOMAIN_VERSION = "2.0.0";
|
||||
|
||||
// Hash of the EIP712 Domain Separator data for the Coordinator
|
||||
// solhint-disable-next-line var-name-mixedcase
|
||||
bytes32 public EIP712_COORDINATOR_DOMAIN_HASH;
|
||||
|
||||
/// @param chainId Chain ID of the network this contract is deployed on.
|
||||
/// @param verifyingContractAddressIfExists Address of the verifying contract (null if the address of this contract)
|
||||
constructor (
|
||||
uint256 chainId,
|
||||
address verifyingContractAddressIfExists
|
||||
)
|
||||
public
|
||||
{
|
||||
address verifyingContractAddress = verifyingContractAddressIfExists == address(0) ? address(this) : verifyingContractAddressIfExists;
|
||||
EIP712_COORDINATOR_DOMAIN_HASH = LibEIP712.hashEIP712Domain(
|
||||
EIP712_COORDINATOR_DOMAIN_NAME,
|
||||
EIP712_COORDINATOR_DOMAIN_VERSION,
|
||||
chainId,
|
||||
verifyingContractAddress
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Calculates EIP712 encoding for a hash struct in the EIP712 domain
|
||||
/// of this contract.
|
||||
/// @param hashStruct The EIP712 hash struct.
|
||||
/// @return EIP712 hash applied to this EIP712 Domain.
|
||||
function _hashEIP712CoordinatorMessage(bytes32 hashStruct)
|
||||
internal
|
||||
view
|
||||
returns (bytes32 result)
|
||||
{
|
||||
return LibEIP712.hashEIP712Message(EIP712_COORDINATOR_DOMAIN_HASH, hashStruct);
|
||||
}
|
||||
}
|
@@ -1,131 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.5;
|
||||
|
||||
import "./LibConstants.sol";
|
||||
|
||||
|
||||
contract LibEIP712Domain is
|
||||
LibConstants
|
||||
{
|
||||
|
||||
// EIP191 header for EIP712 prefix
|
||||
string constant internal EIP191_HEADER = "\x19\x01";
|
||||
|
||||
// EIP712 Domain Name value for the Coordinator
|
||||
string constant internal EIP712_COORDINATOR_DOMAIN_NAME = "0x Protocol Coordinator";
|
||||
|
||||
// EIP712 Domain Version value for the Coordinator
|
||||
string constant internal EIP712_COORDINATOR_DOMAIN_VERSION = "1.0.0";
|
||||
|
||||
// EIP712 Domain Name value for the Exchange
|
||||
string constant internal EIP712_EXCHANGE_DOMAIN_NAME = "0x Protocol";
|
||||
|
||||
// EIP712 Domain Version value for the Exchange
|
||||
string constant internal EIP712_EXCHANGE_DOMAIN_VERSION = "2";
|
||||
|
||||
// Hash of the EIP712 Domain Separator Schema
|
||||
bytes32 constant internal EIP712_DOMAIN_SEPARATOR_SCHEMA_HASH = keccak256(abi.encodePacked(
|
||||
"EIP712Domain(",
|
||||
"string name,",
|
||||
"string version,",
|
||||
"address verifyingContract",
|
||||
")"
|
||||
));
|
||||
|
||||
// Hash of the EIP712 Domain Separator data for the Coordinator
|
||||
// solhint-disable-next-line var-name-mixedcase
|
||||
bytes32 public EIP712_COORDINATOR_DOMAIN_HASH;
|
||||
|
||||
// Hash of the EIP712 Domain Separator data for the Exchange
|
||||
// solhint-disable-next-line var-name-mixedcase
|
||||
bytes32 public EIP712_EXCHANGE_DOMAIN_HASH;
|
||||
|
||||
constructor ()
|
||||
public
|
||||
{
|
||||
EIP712_COORDINATOR_DOMAIN_HASH = keccak256(abi.encodePacked(
|
||||
EIP712_DOMAIN_SEPARATOR_SCHEMA_HASH,
|
||||
keccak256(bytes(EIP712_COORDINATOR_DOMAIN_NAME)),
|
||||
keccak256(bytes(EIP712_COORDINATOR_DOMAIN_VERSION)),
|
||||
uint256(address(this))
|
||||
));
|
||||
|
||||
EIP712_EXCHANGE_DOMAIN_HASH = keccak256(abi.encodePacked(
|
||||
EIP712_DOMAIN_SEPARATOR_SCHEMA_HASH,
|
||||
keccak256(bytes(EIP712_EXCHANGE_DOMAIN_NAME)),
|
||||
keccak256(bytes(EIP712_EXCHANGE_DOMAIN_VERSION)),
|
||||
uint256(address(EXCHANGE))
|
||||
));
|
||||
}
|
||||
|
||||
/// @dev Calculates EIP712 encoding for a hash struct in the EIP712 domain
|
||||
/// of this contract.
|
||||
/// @param hashStruct The EIP712 hash struct.
|
||||
/// @return EIP712 hash applied to this EIP712 Domain.
|
||||
function hashEIP712CoordinatorMessage(bytes32 hashStruct)
|
||||
internal
|
||||
view
|
||||
returns (bytes32 result)
|
||||
{
|
||||
return hashEIP712Message(EIP712_COORDINATOR_DOMAIN_HASH, hashStruct);
|
||||
}
|
||||
|
||||
/// @dev Calculates EIP712 encoding for a hash struct in the EIP712 domain
|
||||
/// of the Exchange contract.
|
||||
/// @param hashStruct The EIP712 hash struct.
|
||||
/// @return EIP712 hash applied to the Exchange EIP712 Domain.
|
||||
function hashEIP712ExchangeMessage(bytes32 hashStruct)
|
||||
internal
|
||||
view
|
||||
returns (bytes32 result)
|
||||
{
|
||||
return hashEIP712Message(EIP712_EXCHANGE_DOMAIN_HASH, hashStruct);
|
||||
}
|
||||
|
||||
/// @dev Calculates EIP712 encoding for a hash struct with a given domain hash.
|
||||
/// @param eip712DomainHash Hash of the domain domain separator data.
|
||||
/// @param hashStruct The EIP712 hash struct.
|
||||
/// @return EIP712 hash applied to the Exchange EIP712 Domain.
|
||||
function hashEIP712Message(bytes32 eip712DomainHash, bytes32 hashStruct)
|
||||
internal
|
||||
pure
|
||||
returns (bytes32 result)
|
||||
{
|
||||
// Assembly for more efficient computing:
|
||||
// keccak256(abi.encodePacked(
|
||||
// EIP191_HEADER,
|
||||
// EIP712_DOMAIN_HASH,
|
||||
// hashStruct
|
||||
// ));
|
||||
|
||||
assembly {
|
||||
// Load free memory pointer
|
||||
let memPtr := mload(64)
|
||||
|
||||
mstore(memPtr, 0x1901000000000000000000000000000000000000000000000000000000000000) // EIP191 header
|
||||
mstore(add(memPtr, 2), eip712DomainHash) // EIP712 domain hash
|
||||
mstore(add(memPtr, 34), hashStruct) // Hash of struct
|
||||
|
||||
// Compute hash
|
||||
result := keccak256(memPtr, 66)
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
@@ -1,95 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.5;
|
||||
pragma experimental "ABIEncoderV2";
|
||||
|
||||
import "./LibEIP712Domain.sol";
|
||||
|
||||
|
||||
contract LibZeroExTransaction is
|
||||
LibEIP712Domain
|
||||
{
|
||||
// Hash for the EIP712 0x transaction schema
|
||||
// keccak256(abi.encodePacked(
|
||||
// "ZeroExTransaction(",
|
||||
// "uint256 salt,",
|
||||
// "address signerAddress,",
|
||||
// "bytes data",
|
||||
// ")"
|
||||
// ));
|
||||
bytes32 constant internal EIP712_ZEROEX_TRANSACTION_SCHEMA_HASH = 0x213c6f636f3ea94e701c0adf9b2624aa45a6c694f9a292c094f9a81c24b5df4c;
|
||||
|
||||
struct ZeroExTransaction {
|
||||
uint256 salt; // Arbitrary number to ensure uniqueness of transaction hash.
|
||||
address signerAddress; // Address of transaction signer.
|
||||
bytes data; // AbiV2 encoded calldata.
|
||||
}
|
||||
|
||||
/// @dev Calculates the EIP712 hash of a 0x transaction using the domain separator of the Exchange contract.
|
||||
/// @param transaction 0x transaction containing salt, signerAddress, and data.
|
||||
/// @return EIP712 hash of the transaction with the domain separator of this contract.
|
||||
function getTransactionHash(ZeroExTransaction memory transaction)
|
||||
public
|
||||
view
|
||||
returns (bytes32 transactionHash)
|
||||
{
|
||||
// Hash the transaction with the domain separator of the Exchange contract.
|
||||
transactionHash = hashEIP712ExchangeMessage(hashZeroExTransaction(transaction));
|
||||
return transactionHash;
|
||||
}
|
||||
|
||||
/// @dev Calculates EIP712 hash of the 0x transaction with no domain separator.
|
||||
/// @param transaction 0x transaction containing salt, signerAddress, and data.
|
||||
/// @return EIP712 hash of the transaction with no domain separator.
|
||||
function hashZeroExTransaction(ZeroExTransaction memory transaction)
|
||||
internal
|
||||
pure
|
||||
returns (bytes32 result)
|
||||
{
|
||||
bytes32 schemaHash = EIP712_ZEROEX_TRANSACTION_SCHEMA_HASH;
|
||||
bytes memory data = transaction.data;
|
||||
uint256 salt = transaction.salt;
|
||||
address signerAddress = transaction.signerAddress;
|
||||
|
||||
// Assembly for more efficiently computing:
|
||||
// keccak256(abi.encodePacked(
|
||||
// EIP712_ZEROEX_TRANSACTION_SCHEMA_HASH,
|
||||
// transaction.salt,
|
||||
// uint256(transaction.signerAddress),
|
||||
// keccak256(transaction.data)
|
||||
// ));
|
||||
|
||||
assembly {
|
||||
// Compute hash of data
|
||||
let dataHash := keccak256(add(data, 32), mload(data))
|
||||
|
||||
// Load free memory pointer
|
||||
let memPtr := mload(64)
|
||||
|
||||
mstore(memPtr, schemaHash) // hash of schema
|
||||
mstore(add(memPtr, 32), salt) // salt
|
||||
mstore(add(memPtr, 64), and(signerAddress, 0xffffffffffffffffffffffffffffffffffffffff)) // signerAddress
|
||||
mstore(add(memPtr, 96), dataHash) // hash of data
|
||||
|
||||
// Compute hash
|
||||
result := keccak256(memPtr, 128)
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.5;
|
||||
pragma experimental "ABIEncoderV2";
|
||||
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
|
||||
import "../interfaces/ICoordinatorApprovalVerifier.sol";
|
||||
|
||||
|
||||
contract MCoordinatorApprovalVerifier is
|
||||
ICoordinatorApprovalVerifier
|
||||
{
|
||||
/// @dev Validates that the feeRecipients of a batch of order have approved a 0x transaction.
|
||||
/// @param transaction 0x transaction containing salt, signerAddress, and data.
|
||||
/// @param orders Array of order structs containing order specifications.
|
||||
/// @param txOrigin Required signer of Ethereum transaction calling this function.
|
||||
/// @param transactionSignature Proof that the transaction has been signed by the signer.
|
||||
/// @param approvalExpirationTimeSeconds Array of expiration times in seconds for which each corresponding approval signature expires.
|
||||
/// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each order.
|
||||
function assertValidTransactionOrdersApproval(
|
||||
LibZeroExTransaction.ZeroExTransaction memory transaction,
|
||||
LibOrder.Order[] memory orders,
|
||||
address txOrigin,
|
||||
bytes memory transactionSignature,
|
||||
uint256[] memory approvalExpirationTimeSeconds,
|
||||
bytes[] memory approvalSignatures
|
||||
)
|
||||
internal
|
||||
view;
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.5;
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
import "./MixinCoordinatorRegistryCore.sol";
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.5;
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
import "./interfaces/ICoordinatorRegistryCore.sol";
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.5;
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
|
||||
// solhint-disable no-empty-blocks
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-coordinator",
|
||||
"version": "2.0.10",
|
||||
"version": "2.1.0-beta.0",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -12,7 +12,7 @@
|
||||
"scripts": {
|
||||
"build": "yarn pre_build && tsc -b",
|
||||
"build:ci": "yarn build",
|
||||
"pre_build": "run-s compile generate_contract_wrappers",
|
||||
"pre_build": "run-s compile contracts:gen generate_contract_wrappers",
|
||||
"test": "yarn run_mocha",
|
||||
"rebuild_and_test": "run-s build test",
|
||||
"test:coverage": "SOLIDITY_COVERAGE=true run-s build run_mocha coverage:report:text coverage:report:lcov",
|
||||
@@ -22,7 +22,7 @@
|
||||
"compile": "sol-compiler",
|
||||
"watch": "sol-compiler -w",
|
||||
"clean": "shx rm -rf lib generated-artifacts generated-wrappers",
|
||||
"generate_contract_wrappers": "abi-gen --abis ${npm_package_config_abis} --template ../../node_modules/@0x/abi-gen-templates/contract.handlebars --partials '../../node_modules/@0x/abi-gen-templates/partials/**/*.handlebars' --output generated-wrappers --backend ethers",
|
||||
"generate_contract_wrappers": "abi-gen --abis ${npm_package_config_abis} --output generated-wrappers --backend ethers",
|
||||
"lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
|
||||
"fix": "tslint --fix --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
|
||||
"coverage:report:text": "istanbul report text",
|
||||
@@ -31,7 +31,8 @@
|
||||
"coverage:report:lcov": "istanbul report lcov",
|
||||
"test:circleci": "yarn test",
|
||||
"contracts:gen": "contracts-gen",
|
||||
"lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol"
|
||||
"lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol",
|
||||
"compile:truffle": "truffle compile"
|
||||
},
|
||||
"config": {
|
||||
"abis": "./generated-artifacts/@(Coordinator|CoordinatorRegistry).json",
|
||||
@@ -47,11 +48,11 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^4.1.0",
|
||||
"@0x/contracts-gen": "^1.0.13",
|
||||
"@0x/contracts-test-utils": "^3.1.13",
|
||||
"@0x/dev-utils": "^2.3.0",
|
||||
"@0x/sol-compiler": "^3.1.12",
|
||||
"@0x/abi-gen": "^4.3.0-beta.0",
|
||||
"@0x/contracts-gen": "^1.1.0-beta.0",
|
||||
"@0x/contracts-test-utils": "^3.2.0-beta.0",
|
||||
"@0x/dev-utils": "^2.4.0-beta.0",
|
||||
"@0x/sol-compiler": "^3.2.0-beta.0",
|
||||
"@0x/tslint-config": "^3.0.1",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
@@ -65,22 +66,23 @@
|
||||
"npm-run-all": "^4.1.2",
|
||||
"shx": "^0.2.2",
|
||||
"solhint": "^1.4.1",
|
||||
"truffle": "^5.0.32",
|
||||
"tslint": "5.11.0",
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^5.3.1",
|
||||
"@0x/contracts-asset-proxy": "^2.2.5",
|
||||
"@0x/contracts-erc20": "^2.2.11",
|
||||
"@0x/contracts-exchange": "^2.1.11",
|
||||
"@0x/contracts-exchange-libs": "^3.0.5",
|
||||
"@0x/contracts-utils": "^3.2.1",
|
||||
"@0x/order-utils": "^8.2.5",
|
||||
"@0x/types": "^2.4.1",
|
||||
"@0x/typescript-typings": "^4.2.4",
|
||||
"@0x/utils": "^4.5.0",
|
||||
"@0x/web3-wrapper": "^6.0.10",
|
||||
"ethereum-types": "^2.1.4",
|
||||
"@0x/base-contract": "^5.5.0-beta.0",
|
||||
"@0x/contracts-asset-proxy": "^2.3.0-beta.0",
|
||||
"@0x/contracts-erc20": "^2.3.0-beta.0",
|
||||
"@0x/contracts-exchange": "^2.2.0-beta.0",
|
||||
"@0x/contracts-exchange-libs": "^3.1.0-beta.0",
|
||||
"@0x/contracts-utils": "^3.3.0-beta.0",
|
||||
"@0x/order-utils": "^8.5.0-beta.0",
|
||||
"@0x/types": "^2.5.0-beta.0",
|
||||
"@0x/typescript-typings": "^4.4.0-beta.0",
|
||||
"@0x/utils": "^4.6.0-beta.0",
|
||||
"@0x/web3-wrapper": "^6.1.0-beta.0",
|
||||
"ethereum-types": "^2.2.0-beta.0",
|
||||
"ethereumjs-util": "^5.1.1",
|
||||
"lodash": "^4.17.11"
|
||||
},
|
||||
|
@@ -2,14 +2,17 @@ import { ERC20ProxyContract, ERC20Wrapper } from '@0x/contracts-asset-proxy';
|
||||
import { DummyERC20TokenContract } from '@0x/contracts-erc20';
|
||||
import {
|
||||
artifacts as exchangeArtifacts,
|
||||
constants as exchangeConstants,
|
||||
ExchangeCancelEventArgs,
|
||||
ExchangeCancelUpToEventArgs,
|
||||
ExchangeContract,
|
||||
exchangeDataEncoder,
|
||||
ExchangeFillEventArgs,
|
||||
ExchangeFunctionName,
|
||||
} from '@0x/contracts-exchange';
|
||||
import {
|
||||
chaiSetup,
|
||||
constants as devConstants,
|
||||
constants,
|
||||
expectTransactionFailedAsync,
|
||||
getLatestBlockTimestampAsync,
|
||||
OrderFactory,
|
||||
@@ -20,12 +23,12 @@ import {
|
||||
} from '@0x/contracts-test-utils';
|
||||
import { BlockchainLifecycle } from '@0x/dev-utils';
|
||||
import { assetDataUtils, orderHashUtils } from '@0x/order-utils';
|
||||
import { RevertReason, SignedOrder } from '@0x/types';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import { RevertReason } from '@0x/types';
|
||||
import { BigNumber, providerUtils } from '@0x/utils';
|
||||
import * as chai from 'chai';
|
||||
import { LogWithDecodedArgs } from 'ethereum-types';
|
||||
|
||||
import { ApprovalFactory, artifacts, constants, CoordinatorContract, exchangeDataEncoder } from '../src';
|
||||
import { ApprovalFactory, artifacts, CoordinatorContract } from '../src';
|
||||
|
||||
chaiSetup.configure();
|
||||
const expect = chai.expect;
|
||||
@@ -33,6 +36,7 @@ const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||
web3Wrapper.abiDecoder.addABI(exchangeArtifacts.Exchange.compilerOutput.abi);
|
||||
// tslint:disable:no-unnecessary-type-assertion
|
||||
describe('Coordinator tests', () => {
|
||||
let chainId: number;
|
||||
let makerAddress: string;
|
||||
let owner: string;
|
||||
let takerAddress: string;
|
||||
@@ -41,7 +45,7 @@ describe('Coordinator tests', () => {
|
||||
let erc20Proxy: ERC20ProxyContract;
|
||||
let erc20TokenA: DummyERC20TokenContract;
|
||||
let erc20TokenB: DummyERC20TokenContract;
|
||||
let zrxToken: DummyERC20TokenContract;
|
||||
let makerFeeToken: DummyERC20TokenContract;
|
||||
let coordinatorContract: CoordinatorContract;
|
||||
let exchange: ExchangeContract;
|
||||
|
||||
@@ -58,15 +62,16 @@ describe('Coordinator tests', () => {
|
||||
await blockchainLifecycle.revertAsync();
|
||||
});
|
||||
before(async () => {
|
||||
chainId = await providerUtils.getChainIdAsync(provider);
|
||||
const accounts = await web3Wrapper.getAvailableAddressesAsync();
|
||||
const usedAddresses = ([owner, makerAddress, takerAddress, feeRecipientAddress] = accounts.slice(0, 4));
|
||||
|
||||
erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner);
|
||||
erc20Proxy = await erc20Wrapper.deployProxyAsync();
|
||||
const numDummyErc20ToDeploy = 3;
|
||||
[erc20TokenA, erc20TokenB, zrxToken] = await erc20Wrapper.deployDummyTokensAsync(
|
||||
[erc20TokenA, erc20TokenB, makerFeeToken] = await erc20Wrapper.deployDummyTokensAsync(
|
||||
numDummyErc20ToDeploy,
|
||||
devConstants.DUMMY_TOKEN_DECIMALS,
|
||||
constants.DUMMY_TOKEN_DECIMALS,
|
||||
);
|
||||
await erc20Wrapper.setBalancesAndAllowancesAsync();
|
||||
|
||||
@@ -74,18 +79,17 @@ describe('Coordinator tests', () => {
|
||||
exchangeArtifacts.Exchange,
|
||||
provider,
|
||||
txDefaults,
|
||||
artifacts,
|
||||
assetDataUtils.encodeERC20AssetData(zrxToken.address),
|
||||
new BigNumber(chainId),
|
||||
);
|
||||
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, { from: owner }),
|
||||
devConstants.AWAIT_TRANSACTION_MINED_MS,
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await exchange.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, { from: owner }),
|
||||
devConstants.AWAIT_TRANSACTION_MINED_MS,
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
|
||||
coordinatorContract = await CoordinatorContract.deployFrom0xArtifactAsync(
|
||||
@@ -94,24 +98,28 @@ describe('Coordinator tests', () => {
|
||||
txDefaults,
|
||||
artifacts,
|
||||
exchange.address,
|
||||
new BigNumber(chainId),
|
||||
);
|
||||
|
||||
// Configure order defaults
|
||||
const defaultOrderParams = {
|
||||
...devConstants.STATIC_ORDER_PARAMS,
|
||||
exchangeAddress: exchange.address,
|
||||
...constants.STATIC_ORDER_PARAMS,
|
||||
senderAddress: coordinatorContract.address,
|
||||
makerAddress,
|
||||
feeRecipientAddress,
|
||||
makerAssetData: assetDataUtils.encodeERC20AssetData(erc20TokenA.address),
|
||||
takerAssetData: assetDataUtils.encodeERC20AssetData(erc20TokenB.address),
|
||||
makerFeeAssetData: assetDataUtils.encodeERC20AssetData(makerFeeToken.address),
|
||||
takerFeeAssetData: assetDataUtils.encodeERC20AssetData(makerFeeToken.address),
|
||||
exchangeAddress: exchange.address,
|
||||
chainId,
|
||||
};
|
||||
const makerPrivateKey = devConstants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)];
|
||||
const takerPrivateKey = devConstants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(takerAddress)];
|
||||
const feeRecipientPrivateKey = devConstants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(feeRecipientAddress)];
|
||||
const makerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)];
|
||||
const takerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(takerAddress)];
|
||||
const feeRecipientPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(feeRecipientAddress)];
|
||||
orderFactory = new OrderFactory(makerPrivateKey, defaultOrderParams);
|
||||
makerTransactionFactory = new TransactionFactory(makerPrivateKey, exchange.address);
|
||||
takerTransactionFactory = new TransactionFactory(takerPrivateKey, exchange.address);
|
||||
makerTransactionFactory = new TransactionFactory(makerPrivateKey, exchange.address, chainId);
|
||||
takerTransactionFactory = new TransactionFactory(takerPrivateKey, exchange.address, chainId);
|
||||
approvalFactory = new ApprovalFactory(feeRecipientPrivateKey, coordinatorContract.address);
|
||||
});
|
||||
beforeEach(async () => {
|
||||
@@ -122,11 +130,11 @@ describe('Coordinator tests', () => {
|
||||
});
|
||||
|
||||
describe('single order fills', () => {
|
||||
for (const fnName of constants.SINGLE_FILL_FN_NAMES) {
|
||||
for (const fnName of exchangeConstants.SINGLE_FILL_FN_NAMES) {
|
||||
it(`${fnName} should fill the order with a signed approval`, async () => {
|
||||
const orders = [await orderFactory.newSignedOrderAsync()];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = takerTransactionFactory.newSignedTransaction(data);
|
||||
const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data });
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
|
||||
const approval = approvalFactory.newSignedApproval(
|
||||
@@ -143,7 +151,7 @@ describe('Coordinator tests', () => {
|
||||
[approval.signature],
|
||||
{ from: takerAddress },
|
||||
),
|
||||
devConstants.AWAIT_TRANSACTION_MINED_MS,
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
const fillLogs = transactionReceipt.logs.filter(
|
||||
log => (log as LogWithDecodedArgs<ExchangeFillEventArgs>).event === 'Fill',
|
||||
@@ -165,7 +173,7 @@ describe('Coordinator tests', () => {
|
||||
it(`${fnName} should fill the order if called by approver`, async () => {
|
||||
const orders = [await orderFactory.newSignedOrderAsync()];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = takerTransactionFactory.newSignedTransaction(data);
|
||||
const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data });
|
||||
const transactionReceipt = await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await coordinatorContract.executeTransaction.sendTransactionAsync(
|
||||
transaction,
|
||||
@@ -175,7 +183,7 @@ describe('Coordinator tests', () => {
|
||||
[],
|
||||
{ from: feeRecipientAddress },
|
||||
),
|
||||
devConstants.AWAIT_TRANSACTION_MINED_MS,
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
const fillLogs = transactionReceipt.logs.filter(
|
||||
log => (log as LogWithDecodedArgs<ExchangeFillEventArgs>).event === 'Fill',
|
||||
@@ -197,7 +205,7 @@ describe('Coordinator tests', () => {
|
||||
it(`${fnName} should revert with no approval signature`, async () => {
|
||||
const orders = [await orderFactory.newSignedOrderAsync()];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = takerTransactionFactory.newSignedTransaction(data);
|
||||
const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data });
|
||||
await expectTransactionFailedAsync(
|
||||
coordinatorContract.executeTransaction.sendTransactionAsync(
|
||||
transaction,
|
||||
@@ -207,7 +215,7 @@ describe('Coordinator tests', () => {
|
||||
[],
|
||||
{
|
||||
from: takerAddress,
|
||||
gas: devConstants.MAX_EXECUTE_TRANSACTION_GAS,
|
||||
gas: constants.MAX_EXECUTE_TRANSACTION_GAS,
|
||||
},
|
||||
),
|
||||
RevertReason.InvalidApprovalSignature,
|
||||
@@ -216,7 +224,7 @@ describe('Coordinator tests', () => {
|
||||
it(`${fnName} should revert with an invalid approval signature`, async () => {
|
||||
const orders = [await orderFactory.newSignedOrderAsync()];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = takerTransactionFactory.newSignedTransaction(data);
|
||||
const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data });
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
|
||||
const approval = approvalFactory.newSignedApproval(
|
||||
@@ -240,7 +248,7 @@ describe('Coordinator tests', () => {
|
||||
it(`${fnName} should revert with an expired approval`, async () => {
|
||||
const orders = [await orderFactory.newSignedOrderAsync()];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = takerTransactionFactory.newSignedTransaction(data);
|
||||
const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data });
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).minus(constants.TIME_BUFFER);
|
||||
const approval = approvalFactory.newSignedApproval(
|
||||
@@ -263,7 +271,7 @@ describe('Coordinator tests', () => {
|
||||
it(`${fnName} should revert if not called by tx signer or approver`, async () => {
|
||||
const orders = [await orderFactory.newSignedOrderAsync()];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = takerTransactionFactory.newSignedTransaction(data);
|
||||
const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data });
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
|
||||
const approval = approvalFactory.newSignedApproval(
|
||||
@@ -286,11 +294,11 @@ describe('Coordinator tests', () => {
|
||||
}
|
||||
});
|
||||
describe('batch order fills', () => {
|
||||
for (const fnName of [...constants.MARKET_FILL_FN_NAMES, ...constants.BATCH_FILL_FN_NAMES]) {
|
||||
for (const fnName of [...exchangeConstants.MARKET_FILL_FN_NAMES, ...exchangeConstants.BATCH_FILL_FN_NAMES]) {
|
||||
it(`${fnName} should fill the orders with a signed approval`, async () => {
|
||||
const orders = [await orderFactory.newSignedOrderAsync(), await orderFactory.newSignedOrderAsync()];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = takerTransactionFactory.newSignedTransaction(data);
|
||||
const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data });
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
|
||||
const approval = approvalFactory.newSignedApproval(
|
||||
@@ -305,9 +313,9 @@ describe('Coordinator tests', () => {
|
||||
transaction.signature,
|
||||
[approvalExpirationTimeSeconds],
|
||||
[approval.signature],
|
||||
{ from: takerAddress, gas: devConstants.MAX_EXECUTE_TRANSACTION_GAS },
|
||||
{ from: takerAddress, gas: constants.MAX_EXECUTE_TRANSACTION_GAS },
|
||||
),
|
||||
devConstants.AWAIT_TRANSACTION_MINED_MS,
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
const fillLogs = transactionReceipt.logs.filter(
|
||||
log => (log as LogWithDecodedArgs<ExchangeFillEventArgs>).event === 'Fill',
|
||||
@@ -331,7 +339,7 @@ describe('Coordinator tests', () => {
|
||||
it(`${fnName} should fill the orders if called by approver`, async () => {
|
||||
const orders = [await orderFactory.newSignedOrderAsync(), await orderFactory.newSignedOrderAsync()];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = takerTransactionFactory.newSignedTransaction(data);
|
||||
const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data });
|
||||
const transactionReceipt = await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await coordinatorContract.executeTransaction.sendTransactionAsync(
|
||||
transaction,
|
||||
@@ -339,9 +347,9 @@ describe('Coordinator tests', () => {
|
||||
transaction.signature,
|
||||
[],
|
||||
[],
|
||||
{ from: feeRecipientAddress, gas: devConstants.MAX_EXECUTE_TRANSACTION_GAS },
|
||||
{ from: feeRecipientAddress, gas: constants.MAX_EXECUTE_TRANSACTION_GAS },
|
||||
),
|
||||
devConstants.AWAIT_TRANSACTION_MINED_MS,
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
const fillLogs = transactionReceipt.logs.filter(
|
||||
log => (log as LogWithDecodedArgs<ExchangeFillEventArgs>).event === 'Fill',
|
||||
@@ -365,7 +373,7 @@ describe('Coordinator tests', () => {
|
||||
it(`${fnName} should revert with an invalid approval signature`, async () => {
|
||||
const orders = [await orderFactory.newSignedOrderAsync(), await orderFactory.newSignedOrderAsync()];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = takerTransactionFactory.newSignedTransaction(data);
|
||||
const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data });
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
|
||||
const approval = approvalFactory.newSignedApproval(
|
||||
@@ -389,7 +397,7 @@ describe('Coordinator tests', () => {
|
||||
it(`${fnName} should revert with an expired approval`, async () => {
|
||||
const orders = [await orderFactory.newSignedOrderAsync(), await orderFactory.newSignedOrderAsync()];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = takerTransactionFactory.newSignedTransaction(data);
|
||||
const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data });
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).minus(constants.TIME_BUFFER);
|
||||
const approval = approvalFactory.newSignedApproval(
|
||||
@@ -412,7 +420,7 @@ describe('Coordinator tests', () => {
|
||||
it(`${fnName} should revert if not called by tx signer or approver`, async () => {
|
||||
const orders = [await orderFactory.newSignedOrderAsync(), await orderFactory.newSignedOrderAsync()];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = takerTransactionFactory.newSignedTransaction(data);
|
||||
const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data });
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
|
||||
const approval = approvalFactory.newSignedApproval(
|
||||
@@ -437,8 +445,8 @@ describe('Coordinator tests', () => {
|
||||
describe('cancels', () => {
|
||||
it('cancelOrder call should be successful without an approval', async () => {
|
||||
const orders = [await orderFactory.newSignedOrderAsync()];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(constants.CANCEL_ORDER, orders);
|
||||
const transaction = makerTransactionFactory.newSignedTransaction(data);
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.CancelOrder, orders);
|
||||
const transaction = await makerTransactionFactory.newSignedTransactionAsync({ data });
|
||||
const transactionReceipt = await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await coordinatorContract.executeTransaction.sendTransactionAsync(
|
||||
transaction,
|
||||
@@ -465,8 +473,8 @@ describe('Coordinator tests', () => {
|
||||
});
|
||||
it('batchCancelOrders call should be successful without an approval', async () => {
|
||||
const orders = [await orderFactory.newSignedOrderAsync(), await orderFactory.newSignedOrderAsync()];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(constants.BATCH_CANCEL_ORDERS, orders);
|
||||
const transaction = makerTransactionFactory.newSignedTransaction(data);
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.BatchCancelOrders, orders);
|
||||
const transaction = await makerTransactionFactory.newSignedTransactionAsync({ data });
|
||||
const transactionReceipt = await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await coordinatorContract.executeTransaction.sendTransactionAsync(
|
||||
transaction,
|
||||
@@ -494,9 +502,9 @@ describe('Coordinator tests', () => {
|
||||
});
|
||||
});
|
||||
it('cancelOrdersUpTo call should be successful without an approval', async () => {
|
||||
const orders: SignedOrder[] = [];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(constants.CANCEL_ORDERS_UP_TO, orders);
|
||||
const transaction = makerTransactionFactory.newSignedTransaction(data);
|
||||
const targetEpoch = constants.ZERO_AMOUNT;
|
||||
const data = exchange.cancelOrdersUpTo.getABIEncodedTransactionData(targetEpoch);
|
||||
const transaction = await makerTransactionFactory.newSignedTransactionAsync({ data });
|
||||
const transactionReceipt = await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await coordinatorContract.executeTransaction.sendTransactionAsync(
|
||||
transaction,
|
||||
@@ -515,8 +523,8 @@ describe('Coordinator tests', () => {
|
||||
expect(cancelLogs.length).to.eq(1);
|
||||
const cancelLogArgs = (cancelLogs[0] as LogWithDecodedArgs<ExchangeCancelUpToEventArgs>).args;
|
||||
expect(cancelLogArgs.makerAddress).to.eq(makerAddress);
|
||||
expect(cancelLogArgs.senderAddress).to.eq(coordinatorContract.address);
|
||||
expect(cancelLogArgs.orderEpoch).to.bignumber.eq(new BigNumber(1));
|
||||
expect(cancelLogArgs.orderSenderAddress).to.eq(coordinatorContract.address);
|
||||
expect(cancelLogArgs.orderEpoch).to.bignumber.eq(targetEpoch.plus(1));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { addressUtils, chaiSetup, constants, provider, txDefaults, web3Wrapper } from '@0x/contracts-test-utils';
|
||||
import { chaiSetup, constants, provider, randomAddress, txDefaults, web3Wrapper } from '@0x/contracts-test-utils';
|
||||
import { BlockchainLifecycle } from '@0x/dev-utils';
|
||||
import { transactionHashUtils } from '@0x/order-utils';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import { BigNumber, providerUtils } from '@0x/utils';
|
||||
import * as chai from 'chai';
|
||||
|
||||
import { artifacts, CoordinatorContract, hashUtils } from '../src';
|
||||
@@ -12,7 +12,8 @@ const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||
|
||||
describe('Libs tests', () => {
|
||||
let coordinatorContract: CoordinatorContract;
|
||||
const exchangeAddress = addressUtils.generatePseudoRandomAddress();
|
||||
let chainId: number;
|
||||
const exchangeAddress = randomAddress();
|
||||
|
||||
before(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
@@ -21,12 +22,14 @@ describe('Libs tests', () => {
|
||||
await blockchainLifecycle.revertAsync();
|
||||
});
|
||||
before(async () => {
|
||||
chainId = await providerUtils.getChainIdAsync(provider);
|
||||
coordinatorContract = await CoordinatorContract.deployFrom0xArtifactAsync(
|
||||
artifacts.Coordinator,
|
||||
provider,
|
||||
txDefaults,
|
||||
artifacts,
|
||||
exchangeAddress,
|
||||
new BigNumber(chainId),
|
||||
);
|
||||
});
|
||||
beforeEach(async () => {
|
||||
@@ -39,10 +42,14 @@ describe('Libs tests', () => {
|
||||
describe('getTransactionHash', () => {
|
||||
it('should return the correct transaction hash', async () => {
|
||||
const tx = {
|
||||
verifyingContractAddress: exchangeAddress,
|
||||
salt: new BigNumber(0),
|
||||
expirationTimeSeconds: new BigNumber(0),
|
||||
signerAddress: constants.NULL_ADDRESS,
|
||||
data: '0x1234',
|
||||
domain: {
|
||||
verifyingContract: exchangeAddress,
|
||||
chainId,
|
||||
},
|
||||
};
|
||||
const expectedTxHash = transactionHashUtils.getTransactionHashHex(tx);
|
||||
const txHash = await coordinatorContract.getTransactionHash.callAsync(tx);
|
||||
@@ -53,11 +60,15 @@ describe('Libs tests', () => {
|
||||
describe('getApprovalHash', () => {
|
||||
it('should return the correct approval hash', async () => {
|
||||
const signedTx = {
|
||||
verifyingContractAddress: exchangeAddress,
|
||||
salt: new BigNumber(0),
|
||||
expirationTimeSeconds: new BigNumber(0),
|
||||
signerAddress: constants.NULL_ADDRESS,
|
||||
data: '0x1234',
|
||||
signature: '0x5678',
|
||||
domain: {
|
||||
verifyingContract: exchangeAddress,
|
||||
chainId,
|
||||
},
|
||||
};
|
||||
const approvalExpirationTimeSeconds = new BigNumber(0);
|
||||
const txOrigin = constants.NULL_ADDRESS;
|
||||
|
@@ -1,10 +1,11 @@
|
||||
import { constants as exchangeConstants, exchangeDataEncoder, ExchangeFunctionName } from '@0x/contracts-exchange';
|
||||
import {
|
||||
addressUtils,
|
||||
chaiSetup,
|
||||
constants as devConstants,
|
||||
constants,
|
||||
expectContractCallFailedAsync,
|
||||
getLatestBlockTimestampAsync,
|
||||
provider,
|
||||
randomAddress,
|
||||
TransactionFactory,
|
||||
txDefaults,
|
||||
web3Wrapper,
|
||||
@@ -12,17 +13,18 @@ import {
|
||||
import { BlockchainLifecycle } from '@0x/dev-utils';
|
||||
import { transactionHashUtils } from '@0x/order-utils';
|
||||
import { RevertReason, SignatureType, SignedOrder } from '@0x/types';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import { BigNumber, LibBytesRevertErrors, providerUtils } from '@0x/utils';
|
||||
import * as chai from 'chai';
|
||||
import * as ethUtil from 'ethereumjs-util';
|
||||
|
||||
import { ApprovalFactory, artifacts, constants, CoordinatorContract, exchangeDataEncoder } from '../src';
|
||||
import { ApprovalFactory, artifacts, CoordinatorContract } from '../src';
|
||||
|
||||
chaiSetup.configure();
|
||||
const expect = chai.expect;
|
||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||
|
||||
describe('Mixins tests', () => {
|
||||
let chainId: number;
|
||||
let transactionSignerAddress: string;
|
||||
let approvalSignerAddress1: string;
|
||||
let approvalSignerAddress2: string;
|
||||
@@ -31,7 +33,7 @@ describe('Mixins tests', () => {
|
||||
let approvalFactory1: ApprovalFactory;
|
||||
let approvalFactory2: ApprovalFactory;
|
||||
let defaultOrder: SignedOrder;
|
||||
const exchangeAddress = addressUtils.generatePseudoRandomAddress();
|
||||
const exchangeAddress = randomAddress();
|
||||
|
||||
before(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
@@ -40,36 +42,40 @@ describe('Mixins tests', () => {
|
||||
await blockchainLifecycle.revertAsync();
|
||||
});
|
||||
before(async () => {
|
||||
chainId = await providerUtils.getChainIdAsync(provider);
|
||||
mixins = await CoordinatorContract.deployFrom0xArtifactAsync(
|
||||
artifacts.Coordinator,
|
||||
provider,
|
||||
txDefaults,
|
||||
artifacts,
|
||||
exchangeAddress,
|
||||
new BigNumber(chainId),
|
||||
);
|
||||
const accounts = await web3Wrapper.getAvailableAddressesAsync();
|
||||
[transactionSignerAddress, approvalSignerAddress1, approvalSignerAddress2] = accounts.slice(0, 3);
|
||||
defaultOrder = {
|
||||
exchangeAddress: devConstants.NULL_ADDRESS,
|
||||
makerAddress: devConstants.NULL_ADDRESS,
|
||||
takerAddress: devConstants.NULL_ADDRESS,
|
||||
makerAddress: constants.NULL_ADDRESS,
|
||||
takerAddress: constants.NULL_ADDRESS,
|
||||
senderAddress: mixins.address,
|
||||
feeRecipientAddress: approvalSignerAddress1,
|
||||
makerAssetData: devConstants.NULL_BYTES,
|
||||
takerAssetData: devConstants.NULL_BYTES,
|
||||
makerAssetAmount: devConstants.ZERO_AMOUNT,
|
||||
takerAssetAmount: devConstants.ZERO_AMOUNT,
|
||||
makerFee: devConstants.ZERO_AMOUNT,
|
||||
takerFee: devConstants.ZERO_AMOUNT,
|
||||
expirationTimeSeconds: devConstants.ZERO_AMOUNT,
|
||||
salt: devConstants.ZERO_AMOUNT,
|
||||
signature: devConstants.NULL_BYTES,
|
||||
makerAssetData: constants.NULL_BYTES,
|
||||
takerAssetData: constants.NULL_BYTES,
|
||||
makerAssetAmount: constants.ZERO_AMOUNT,
|
||||
takerAssetAmount: constants.ZERO_AMOUNT,
|
||||
makerFee: constants.ZERO_AMOUNT,
|
||||
takerFee: constants.ZERO_AMOUNT,
|
||||
makerFeeAssetData: constants.NULL_BYTES,
|
||||
takerFeeAssetData: constants.NULL_BYTES,
|
||||
expirationTimeSeconds: constants.ZERO_AMOUNT,
|
||||
salt: constants.ZERO_AMOUNT,
|
||||
signature: constants.NULL_BYTES,
|
||||
exchangeAddress: constants.NULL_ADDRESS,
|
||||
chainId,
|
||||
};
|
||||
const transactionSignerPrivateKey =
|
||||
devConstants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(transactionSignerAddress)];
|
||||
const approvalSignerPrivateKey1 = devConstants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(approvalSignerAddress1)];
|
||||
const approvalSignerPrivateKey2 = devConstants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(approvalSignerAddress2)];
|
||||
transactionFactory = new TransactionFactory(transactionSignerPrivateKey, exchangeAddress);
|
||||
const transactionSignerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(transactionSignerAddress)];
|
||||
const approvalSignerPrivateKey1 = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(approvalSignerAddress1)];
|
||||
const approvalSignerPrivateKey2 = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(approvalSignerAddress2)];
|
||||
transactionFactory = new TransactionFactory(transactionSignerPrivateKey, exchangeAddress, chainId);
|
||||
approvalFactory1 = new ApprovalFactory(approvalSignerPrivateKey1, mixins.address);
|
||||
approvalFactory2 = new ApprovalFactory(approvalSignerPrivateKey2, mixins.address);
|
||||
});
|
||||
@@ -82,101 +88,105 @@ describe('Mixins tests', () => {
|
||||
|
||||
describe('getSignerAddress', () => {
|
||||
it('should return the correct address using the EthSign signature type', async () => {
|
||||
const data = devConstants.NULL_BYTES;
|
||||
const transaction = transactionFactory.newSignedTransaction(data, SignatureType.EthSign);
|
||||
const data = constants.NULL_BYTES;
|
||||
const transaction = await transactionFactory.newSignedTransactionAsync({ data }, SignatureType.EthSign);
|
||||
const transactionHash = transactionHashUtils.getTransactionHashHex(transaction);
|
||||
const signerAddress = await mixins.getSignerAddress.callAsync(transactionHash, transaction.signature);
|
||||
expect(transaction.signerAddress).to.eq(signerAddress);
|
||||
});
|
||||
it('should return the correct address using the EIP712 signature type', async () => {
|
||||
const data = devConstants.NULL_BYTES;
|
||||
const transaction = transactionFactory.newSignedTransaction(data, SignatureType.EIP712);
|
||||
const data = constants.NULL_BYTES;
|
||||
const transaction = await transactionFactory.newSignedTransactionAsync({ data }, SignatureType.EIP712);
|
||||
const transactionHash = transactionHashUtils.getTransactionHashHex(transaction);
|
||||
const signerAddress = await mixins.getSignerAddress.callAsync(transactionHash, transaction.signature);
|
||||
expect(transaction.signerAddress).to.eq(signerAddress);
|
||||
});
|
||||
it('should revert with with the Illegal signature type', async () => {
|
||||
const data = devConstants.NULL_BYTES;
|
||||
const transaction = transactionFactory.newSignedTransaction(data);
|
||||
const data = constants.NULL_BYTES;
|
||||
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
|
||||
const illegalSignatureByte = ethUtil.toBuffer(SignatureType.Illegal).toString('hex');
|
||||
transaction.signature = `${transaction.signature.slice(
|
||||
0,
|
||||
transaction.signature.length - 2,
|
||||
)}${illegalSignatureByte}`;
|
||||
const transactionHash = transactionHashUtils.getTransactionHashHex(transaction);
|
||||
expectContractCallFailedAsync(
|
||||
mixins.getSignerAddress.callAsync(transactionHash, transaction.signature),
|
||||
expect(mixins.getSignerAddress.callAsync(transactionHash, transaction.signature)).to.be.rejectedWith(
|
||||
RevertReason.SignatureIllegal,
|
||||
);
|
||||
});
|
||||
it('should revert with with the Invalid signature type', async () => {
|
||||
const data = devConstants.NULL_BYTES;
|
||||
const transaction = transactionFactory.newSignedTransaction(data);
|
||||
const data = constants.NULL_BYTES;
|
||||
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
|
||||
const invalidSignatureByte = ethUtil.toBuffer(SignatureType.Invalid).toString('hex');
|
||||
transaction.signature = `0x${invalidSignatureByte}`;
|
||||
const transactionHash = transactionHashUtils.getTransactionHashHex(transaction);
|
||||
expectContractCallFailedAsync(
|
||||
mixins.getSignerAddress.callAsync(transactionHash, transaction.signature),
|
||||
expect(mixins.getSignerAddress.callAsync(transactionHash, transaction.signature)).to.be.rejectedWith(
|
||||
RevertReason.SignatureInvalid,
|
||||
);
|
||||
});
|
||||
it("should revert with with a signature type that doesn't exist", async () => {
|
||||
const data = devConstants.NULL_BYTES;
|
||||
const transaction = transactionFactory.newSignedTransaction(data);
|
||||
const data = constants.NULL_BYTES;
|
||||
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
|
||||
const invalidSignatureByte = '04';
|
||||
transaction.signature = `${transaction.signature.slice(
|
||||
0,
|
||||
transaction.signature.length - 2,
|
||||
)}${invalidSignatureByte}`;
|
||||
const transactionHash = transactionHashUtils.getTransactionHashHex(transaction);
|
||||
expectContractCallFailedAsync(
|
||||
mixins.getSignerAddress.callAsync(transactionHash, transaction.signature),
|
||||
expect(mixins.getSignerAddress.callAsync(transactionHash, transaction.signature)).to.be.rejectedWith(
|
||||
RevertReason.SignatureUnsupported,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('decodeOrdersFromFillData', () => {
|
||||
for (const fnName of constants.SINGLE_FILL_FN_NAMES) {
|
||||
for (const fnName of exchangeConstants.SINGLE_FILL_FN_NAMES) {
|
||||
it(`should correctly decode the orders for ${fnName} data`, async () => {
|
||||
const orders = [defaultOrder];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const decodedOrders = await mixins.decodeOrdersFromFillData.callAsync(data);
|
||||
const decodedSignedOrders = decodedOrders.map(order => ({
|
||||
...order,
|
||||
exchangeAddress: devConstants.NULL_ADDRESS,
|
||||
signature: devConstants.NULL_BYTES,
|
||||
signature: constants.NULL_BYTES,
|
||||
exchangeAddress: constants.NULL_ADDRESS,
|
||||
chainId,
|
||||
}));
|
||||
expect(orders).to.deep.eq(decodedSignedOrders);
|
||||
});
|
||||
}
|
||||
for (const fnName of constants.BATCH_FILL_FN_NAMES) {
|
||||
for (const fnName of exchangeConstants.BATCH_FILL_FN_NAMES) {
|
||||
it(`should correctly decode the orders for ${fnName} data`, async () => {
|
||||
const orders = [defaultOrder, defaultOrder];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const decodedOrders = await mixins.decodeOrdersFromFillData.callAsync(data);
|
||||
const decodedSignedOrders = decodedOrders.map(order => ({
|
||||
...order,
|
||||
exchangeAddress: devConstants.NULL_ADDRESS,
|
||||
signature: devConstants.NULL_BYTES,
|
||||
signature: constants.NULL_BYTES,
|
||||
exchangeAddress: constants.NULL_ADDRESS,
|
||||
chainId,
|
||||
}));
|
||||
expect(orders).to.deep.eq(decodedSignedOrders);
|
||||
});
|
||||
}
|
||||
for (const fnName of constants.MARKET_FILL_FN_NAMES) {
|
||||
for (const fnName of exchangeConstants.MARKET_FILL_FN_NAMES) {
|
||||
it(`should correctly decode the orders for ${fnName} data`, async () => {
|
||||
const orders = [defaultOrder, defaultOrder];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const decodedOrders = await mixins.decodeOrdersFromFillData.callAsync(data);
|
||||
const decodedSignedOrders = decodedOrders.map(order => ({
|
||||
...order,
|
||||
exchangeAddress: devConstants.NULL_ADDRESS,
|
||||
signature: devConstants.NULL_BYTES,
|
||||
signature: constants.NULL_BYTES,
|
||||
exchangeAddress: constants.NULL_ADDRESS,
|
||||
chainId,
|
||||
}));
|
||||
expect(orders).to.deep.eq(decodedSignedOrders);
|
||||
});
|
||||
}
|
||||
for (const fnName of [constants.CANCEL_ORDER, constants.BATCH_CANCEL_ORDERS, constants.CANCEL_ORDERS_UP_TO]) {
|
||||
for (const fnName of [
|
||||
ExchangeFunctionName.CancelOrder,
|
||||
ExchangeFunctionName.BatchCancelOrders,
|
||||
ExchangeFunctionName.CancelOrdersUpTo,
|
||||
]) {
|
||||
it(`should correctly decode the orders for ${fnName} data`, async () => {
|
||||
const orders = [defaultOrder, defaultOrder];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
@@ -193,19 +203,21 @@ describe('Mixins tests', () => {
|
||||
});
|
||||
it('should revert if data is less than 4 bytes long', async () => {
|
||||
const data = '0x010203';
|
||||
await expectContractCallFailedAsync(
|
||||
mixins.decodeOrdersFromFillData.callAsync(data),
|
||||
RevertReason.LibBytesGreaterOrEqualTo4LengthRequired,
|
||||
const expectedError = new LibBytesRevertErrors.InvalidByteOperationError(
|
||||
LibBytesRevertErrors.InvalidByteOperationErrorCodes.LengthGreaterThanOrEqualsFourRequired,
|
||||
new BigNumber(3), // the length of data
|
||||
new BigNumber(4),
|
||||
);
|
||||
return expect(mixins.decodeOrdersFromFillData.callAsync(data)).to.revertWith(expectedError);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Single order approvals', () => {
|
||||
for (const fnName of constants.SINGLE_FILL_FN_NAMES) {
|
||||
for (const fnName of exchangeConstants.SINGLE_FILL_FN_NAMES) {
|
||||
it(`Should be successful: function=${fnName}, caller=tx_signer, senderAddress=[verifier], approval_sig=[approver1], expiration=[valid]`, async () => {
|
||||
const orders = [defaultOrder];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = transactionFactory.newSignedTransaction(data);
|
||||
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
|
||||
const approval = approvalFactory1.newSignedApproval(
|
||||
@@ -225,11 +237,11 @@ describe('Mixins tests', () => {
|
||||
it(`Should be successful: function=${fnName}, caller=tx_signer, senderAddress=[null], approval_sig=[approver1], expiration=[valid]`, async () => {
|
||||
const order = {
|
||||
...defaultOrder,
|
||||
senderAddress: devConstants.NULL_ADDRESS,
|
||||
senderAddress: constants.NULL_ADDRESS,
|
||||
};
|
||||
const orders = [order];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = transactionFactory.newSignedTransaction(data);
|
||||
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
|
||||
const approval = approvalFactory1.newSignedApproval(
|
||||
@@ -249,7 +261,7 @@ describe('Mixins tests', () => {
|
||||
it(`Should be successful: function=${fnName}, caller=approver1, senderAddress=[verifier], approval_sig=[], expiration=[]`, async () => {
|
||||
const orders = [defaultOrder];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = transactionFactory.newSignedTransaction(data);
|
||||
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
|
||||
await mixins.assertValidCoordinatorApprovals.callAsync(
|
||||
transaction,
|
||||
approvalSignerAddress1,
|
||||
@@ -264,7 +276,7 @@ describe('Mixins tests', () => {
|
||||
it(`Should be successful: function=${fnName}, caller=approver1, senderAddress=[verifier], approval_sig=[approver1], expiration=[invalid]`, async () => {
|
||||
const orders = [defaultOrder];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = transactionFactory.newSignedTransaction(data);
|
||||
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
|
||||
const approval = approvalFactory1.newSignedApproval(
|
||||
@@ -284,7 +296,7 @@ describe('Mixins tests', () => {
|
||||
it(`Should be successful: function=${fnName}, caller=approver1, senderAddress=[verifier], approval_sig=[], expiration=[]`, async () => {
|
||||
const orders = [defaultOrder];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = transactionFactory.newSignedTransaction(data);
|
||||
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
|
||||
await mixins.assertValidCoordinatorApprovals.callAsync(
|
||||
transaction,
|
||||
approvalSignerAddress1,
|
||||
@@ -299,7 +311,7 @@ describe('Mixins tests', () => {
|
||||
it(`Should revert: function=${fnName}, caller=tx_signer, senderAddress=[verifier], approval_sig=[invalid], expiration=[valid]`, async () => {
|
||||
const orders = [defaultOrder];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = transactionFactory.newSignedTransaction(data);
|
||||
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
|
||||
const approval = approvalFactory1.newSignedApproval(
|
||||
@@ -323,7 +335,7 @@ describe('Mixins tests', () => {
|
||||
it(`Should revert: function=${fnName}, caller=tx_signer, senderAddress=[verifier], approval_sig=[approver1], expiration=[invalid]`, async () => {
|
||||
const orders = [defaultOrder];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = transactionFactory.newSignedTransaction(data);
|
||||
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).minus(constants.TIME_BUFFER);
|
||||
const approval = approvalFactory1.newSignedApproval(
|
||||
@@ -346,7 +358,7 @@ describe('Mixins tests', () => {
|
||||
it(`Should revert: function=${fnName}, caller=approver2, senderAddress=[verifier], approval_sig=[approver1], expiration=[valid]`, async () => {
|
||||
const orders = [defaultOrder];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = transactionFactory.newSignedTransaction(data);
|
||||
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
|
||||
const approval = approvalFactory1.newSignedApproval(
|
||||
@@ -370,14 +382,14 @@ describe('Mixins tests', () => {
|
||||
});
|
||||
describe('Batch order approvals', () => {
|
||||
for (const fnName of [
|
||||
...constants.BATCH_FILL_FN_NAMES,
|
||||
...constants.MARKET_FILL_FN_NAMES,
|
||||
constants.MATCH_ORDERS,
|
||||
...exchangeConstants.BATCH_FILL_FN_NAMES,
|
||||
...exchangeConstants.MARKET_FILL_FN_NAMES,
|
||||
ExchangeFunctionName.MatchOrders,
|
||||
]) {
|
||||
it(`Should be successful: function=${fnName} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1,approver1], approval_sig=[approver1], expiration=[valid]`, async () => {
|
||||
const orders = [defaultOrder, defaultOrder];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = transactionFactory.newSignedTransaction(data);
|
||||
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
|
||||
const approval = approvalFactory1.newSignedApproval(
|
||||
@@ -397,10 +409,10 @@ describe('Mixins tests', () => {
|
||||
it(`Should be successful: function=${fnName} caller=tx_signer, senderAddress=[null,null], feeRecipient=[approver1,approver1], approval_sig=[approver1], expiration=[valid]`, async () => {
|
||||
const orders = [defaultOrder, defaultOrder].map(order => ({
|
||||
...order,
|
||||
senderAddress: devConstants.NULL_ADDRESS,
|
||||
senderAddress: constants.NULL_ADDRESS,
|
||||
}));
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = transactionFactory.newSignedTransaction(data);
|
||||
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
|
||||
const approval = approvalFactory1.newSignedApproval(
|
||||
@@ -420,10 +432,10 @@ describe('Mixins tests', () => {
|
||||
it(`Should be successful: function=${fnName} caller=tx_signer, senderAddress=[null,null], feeRecipient=[approver1,approver1], approval_sig=[], expiration=[]`, async () => {
|
||||
const orders = [defaultOrder, defaultOrder].map(order => ({
|
||||
...order,
|
||||
senderAddress: devConstants.NULL_ADDRESS,
|
||||
senderAddress: constants.NULL_ADDRESS,
|
||||
}));
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = transactionFactory.newSignedTransaction(data);
|
||||
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
|
||||
await mixins.assertValidCoordinatorApprovals.callAsync(
|
||||
transaction,
|
||||
transactionSignerAddress,
|
||||
@@ -434,9 +446,9 @@ describe('Mixins tests', () => {
|
||||
);
|
||||
});
|
||||
it(`Should be successful: function=${fnName} caller=tx_signer, senderAddress=[verifier,null], feeRecipient=[approver1,approver1], approval_sig=[approver1], expiration=[valid]`, async () => {
|
||||
const orders = [defaultOrder, { ...defaultOrder, senderAddress: devConstants.NULL_ADDRESS }];
|
||||
const orders = [defaultOrder, { ...defaultOrder, senderAddress: constants.NULL_ADDRESS }];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = transactionFactory.newSignedTransaction(data);
|
||||
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
|
||||
const approval = approvalFactory1.newSignedApproval(
|
||||
@@ -456,7 +468,7 @@ describe('Mixins tests', () => {
|
||||
it(`Should be successful: function=${fnName} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1,approver2], approval_sig=[approver1,approver2], expiration=[valid,valid]`, async () => {
|
||||
const orders = [defaultOrder, { ...defaultOrder, feeRecipientAddress: approvalSignerAddress2 }];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = transactionFactory.newSignedTransaction(data);
|
||||
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
|
||||
const approval1 = approvalFactory1.newSignedApproval(
|
||||
@@ -481,7 +493,7 @@ describe('Mixins tests', () => {
|
||||
it(`Should be successful: function=${fnName} caller=approver1, senderAddress=[verifier,verifier], feeRecipient=[approver1,approver1], approval_sig=[], expiration=[]`, async () => {
|
||||
const orders = [defaultOrder, defaultOrder];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = transactionFactory.newSignedTransaction(data);
|
||||
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
|
||||
await mixins.assertValidCoordinatorApprovals.callAsync(
|
||||
transaction,
|
||||
approvalSignerAddress1,
|
||||
@@ -494,7 +506,7 @@ describe('Mixins tests', () => {
|
||||
it(`Should revert: function=${fnName} caller=approver1, senderAddress=[verifier,verifier], feeRecipient=[approver1,approver2], approval_sig=[approver2], expiration=[valid]`, async () => {
|
||||
const orders = [defaultOrder, { ...defaultOrder, feeRecipientAddress: approvalSignerAddress2 }];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = transactionFactory.newSignedTransaction(data);
|
||||
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
|
||||
const approval2 = approvalFactory2.newSignedApproval(
|
||||
@@ -517,7 +529,7 @@ describe('Mixins tests', () => {
|
||||
it(`Should revert: function=${fnName} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver1], approval_sig=[], expiration=[]`, async () => {
|
||||
const orders = [defaultOrder, defaultOrder];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = transactionFactory.newSignedTransaction(data);
|
||||
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
|
||||
expectContractCallFailedAsync(
|
||||
mixins.assertValidCoordinatorApprovals.callAsync(
|
||||
transaction,
|
||||
@@ -533,7 +545,7 @@ describe('Mixins tests', () => {
|
||||
it(`Should revert: function=${fnName} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver1], approval_sig=[invalid], expiration=[valid]`, async () => {
|
||||
const orders = [defaultOrder, defaultOrder];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = transactionFactory.newSignedTransaction(data);
|
||||
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
|
||||
const approval = approvalFactory1.newSignedApproval(
|
||||
@@ -557,7 +569,7 @@ describe('Mixins tests', () => {
|
||||
it(`Should revert: function=${fnName} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver2], approval_sig=[valid,invalid], expiration=[valid,valid]`, async () => {
|
||||
const orders = [defaultOrder, { ...defaultOrder, feeRecipientAddress: approvalSignerAddress2 }];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = transactionFactory.newSignedTransaction(data);
|
||||
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
|
||||
const approval1 = approvalFactory1.newSignedApproval(
|
||||
@@ -586,7 +598,7 @@ describe('Mixins tests', () => {
|
||||
it(`Should revert: function=${fnName} caller=approver1, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver2], approval_sig=[invalid], expiration=[valid]`, async () => {
|
||||
const orders = [defaultOrder, { ...defaultOrder, feeRecipientAddress: approvalSignerAddress2 }];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = transactionFactory.newSignedTransaction(data);
|
||||
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
|
||||
const approval2 = approvalFactory2.newSignedApproval(
|
||||
@@ -610,7 +622,7 @@ describe('Mixins tests', () => {
|
||||
it(`Should revert: function=${fnName} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver2], approval_sig=[valid,valid], expiration=[valid,invalid]`, async () => {
|
||||
const orders = [defaultOrder, { ...defaultOrder, feeRecipientAddress: approvalSignerAddress2 }];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = transactionFactory.newSignedTransaction(data);
|
||||
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const approvalExpirationTimeSeconds1 = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
|
||||
const approvalExpirationTimeSeconds2 = new BigNumber(currentTimestamp).minus(constants.TIME_BUFFER);
|
||||
@@ -639,7 +651,7 @@ describe('Mixins tests', () => {
|
||||
it(`Should revert: function=${fnName} caller=approver1, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver2], approval_sig=[valid], expiration=[invalid]`, async () => {
|
||||
const orders = [defaultOrder, { ...defaultOrder, feeRecipientAddress: approvalSignerAddress2 }];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = transactionFactory.newSignedTransaction(data);
|
||||
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).minus(constants.TIME_BUFFER);
|
||||
const approval2 = approvalFactory2.newSignedApproval(
|
||||
@@ -662,7 +674,7 @@ describe('Mixins tests', () => {
|
||||
it(`Should revert: function=${fnName} caller=approver2, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver1], approval_sig=[valid], expiration=[valid]`, async () => {
|
||||
const orders = [defaultOrder, defaultOrder];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = transactionFactory.newSignedTransaction(data);
|
||||
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
|
||||
const approval1 = approvalFactory1.newSignedApproval(
|
||||
@@ -687,8 +699,8 @@ describe('Mixins tests', () => {
|
||||
describe('cancels', () => {
|
||||
it('should allow the tx signer to call `cancelOrder` without approval', async () => {
|
||||
const orders = [defaultOrder];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(constants.CANCEL_ORDER, orders);
|
||||
const transaction = transactionFactory.newSignedTransaction(data);
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.CancelOrder, orders);
|
||||
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
|
||||
await mixins.assertValidCoordinatorApprovals.callAsync(
|
||||
transaction,
|
||||
transactionSignerAddress,
|
||||
@@ -700,8 +712,8 @@ describe('Mixins tests', () => {
|
||||
});
|
||||
it('should allow the tx signer to call `batchCancelOrders` without approval', async () => {
|
||||
const orders = [defaultOrder, defaultOrder];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(constants.BATCH_CANCEL_ORDERS, orders);
|
||||
const transaction = transactionFactory.newSignedTransaction(data);
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.BatchCancelOrders, orders);
|
||||
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
|
||||
await mixins.assertValidCoordinatorApprovals.callAsync(
|
||||
transaction,
|
||||
transactionSignerAddress,
|
||||
@@ -712,9 +724,8 @@ describe('Mixins tests', () => {
|
||||
);
|
||||
});
|
||||
it('should allow the tx signer to call `cancelOrdersUpTo` without approval', async () => {
|
||||
const orders: SignedOrder[] = [];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(constants.CANCEL_ORDERS_UP_TO, orders);
|
||||
const transaction = transactionFactory.newSignedTransaction(data);
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.CancelOrdersUpTo);
|
||||
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
|
||||
await mixins.assertValidCoordinatorApprovals.callAsync(
|
||||
transaction,
|
||||
transactionSignerAddress,
|
||||
|
@@ -9,9 +9,9 @@ export class ApprovalFactory {
|
||||
private readonly _privateKey: Buffer;
|
||||
private readonly _verifyingContractAddress: string;
|
||||
|
||||
constructor(privateKey: Buffer, verifyingContractAddress: string) {
|
||||
constructor(privateKey: Buffer, verifyingContract: string) {
|
||||
this._privateKey = privateKey;
|
||||
this._verifyingContractAddress = verifyingContractAddress;
|
||||
this._verifyingContractAddress = verifyingContract;
|
||||
}
|
||||
|
||||
public newSignedApproval(
|
||||
|
@@ -1,12 +0,0 @@
|
||||
import { BigNumber } from '@0x/utils';
|
||||
|
||||
export const constants = {
|
||||
SINGLE_FILL_FN_NAMES: ['fillOrder', 'fillOrKillOrder', 'fillOrderNoThrow'],
|
||||
BATCH_FILL_FN_NAMES: ['batchFillOrders', 'batchFillOrKillOrders', 'batchFillOrdersNoThrow'],
|
||||
MARKET_FILL_FN_NAMES: ['marketBuyOrders', 'marketBuyOrdersNoThrow', 'marketSellOrders', 'marketSellOrdersNoThrow'],
|
||||
MATCH_ORDERS: 'matchOrders',
|
||||
CANCEL_ORDER: 'cancelOrder',
|
||||
BATCH_CANCEL_ORDERS: 'batchCancelOrders',
|
||||
CANCEL_ORDERS_UP_TO: 'cancelOrdersUpTo',
|
||||
TIME_BUFFER: new BigNumber(1000),
|
||||
};
|
@@ -1,47 +0,0 @@
|
||||
import { IExchangeContract } from '@0x/contracts-exchange';
|
||||
import { constants as devConstants, provider } from '@0x/contracts-test-utils';
|
||||
import { SignedOrder } from '@0x/types';
|
||||
|
||||
import { constants } from './index';
|
||||
|
||||
export const exchangeDataEncoder = {
|
||||
encodeOrdersToExchangeData(fnName: string, orders: SignedOrder[]): string {
|
||||
const exchangeInstance = new IExchangeContract(devConstants.NULL_ADDRESS, provider);
|
||||
let data;
|
||||
if (constants.SINGLE_FILL_FN_NAMES.indexOf(fnName) !== -1) {
|
||||
data = (exchangeInstance as any)[fnName].getABIEncodedTransactionData(
|
||||
orders[0],
|
||||
orders[0].takerAssetAmount,
|
||||
orders[0].signature,
|
||||
);
|
||||
} else if (constants.BATCH_FILL_FN_NAMES.indexOf(fnName) !== -1) {
|
||||
data = (exchangeInstance as any)[fnName].getABIEncodedTransactionData(
|
||||
orders,
|
||||
orders.map(order => order.takerAssetAmount),
|
||||
orders.map(order => order.signature),
|
||||
);
|
||||
} else if (constants.MARKET_FILL_FN_NAMES.indexOf(fnName) !== -1) {
|
||||
data = (exchangeInstance as any)[fnName].getABIEncodedTransactionData(
|
||||
orders,
|
||||
orders.map(order => order.takerAssetAmount).reduce((prev, curr) => prev.plus(curr)),
|
||||
orders.map(order => order.signature),
|
||||
);
|
||||
} else if (fnName === constants.MATCH_ORDERS) {
|
||||
data = exchangeInstance.matchOrders.getABIEncodedTransactionData(
|
||||
orders[0],
|
||||
orders[1],
|
||||
orders[0].signature,
|
||||
orders[1].signature,
|
||||
);
|
||||
} else if (fnName === constants.CANCEL_ORDER) {
|
||||
data = exchangeInstance.cancelOrder.getABIEncodedTransactionData(orders[0]);
|
||||
} else if (fnName === constants.BATCH_CANCEL_ORDERS) {
|
||||
data = exchangeInstance.batchCancelOrders.getABIEncodedTransactionData(orders);
|
||||
} else if (fnName === constants.CANCEL_ORDERS_UP_TO) {
|
||||
data = exchangeInstance.cancelOrdersUpTo.getABIEncodedTransactionData(devConstants.ZERO_AMOUNT);
|
||||
} else {
|
||||
throw new Error(`Error: ${fnName} not a supported function`);
|
||||
}
|
||||
return data;
|
||||
},
|
||||
};
|
@@ -6,13 +6,13 @@ import * as _ from 'lodash';
|
||||
export const hashUtils = {
|
||||
getApprovalHashBuffer(
|
||||
transaction: SignedZeroExTransaction,
|
||||
verifyingContractAddress: string,
|
||||
verifyingContract: string,
|
||||
txOrigin: string,
|
||||
approvalExpirationTimeSeconds: BigNumber,
|
||||
): Buffer {
|
||||
const typedData = eip712Utils.createCoordinatorApprovalTypedData(
|
||||
transaction,
|
||||
verifyingContractAddress,
|
||||
verifyingContract,
|
||||
txOrigin,
|
||||
approvalExpirationTimeSeconds,
|
||||
);
|
||||
@@ -21,12 +21,12 @@ export const hashUtils = {
|
||||
},
|
||||
getApprovalHashHex(
|
||||
transaction: SignedZeroExTransaction,
|
||||
verifyingContractAddress: string,
|
||||
verifyingContract: string,
|
||||
txOrigin: string,
|
||||
approvalExpirationTimeSeconds: BigNumber,
|
||||
): string {
|
||||
const hashHex = `0x${hashUtils
|
||||
.getApprovalHashBuffer(transaction, verifyingContractAddress, txOrigin, approvalExpirationTimeSeconds)
|
||||
.getApprovalHashBuffer(transaction, verifyingContract, txOrigin, approvalExpirationTimeSeconds)
|
||||
.toString('hex')}`;
|
||||
return hashHex;
|
||||
},
|
||||
|
@@ -1,5 +1,3 @@
|
||||
export { hashUtils } from './hash_utils';
|
||||
export { ApprovalFactory } from './approval_factory';
|
||||
export { constants } from './constants';
|
||||
export { exchangeDataEncoder } from './exchange_data_encoder';
|
||||
export * from './types';
|
||||
|
96
contracts/coordinator/truffle-config.js
Normal file
96
contracts/coordinator/truffle-config.js
Normal file
@@ -0,0 +1,96 @@
|
||||
/**
|
||||
* Use this file to configure your truffle project. It's seeded with some
|
||||
* common settings for different networks and features like migrations,
|
||||
* compilation and testing. Uncomment the ones you need or modify
|
||||
* them to suit your project as necessary.
|
||||
*
|
||||
* More information about configuration can be found at:
|
||||
*
|
||||
* truffleframework.com/docs/advanced/configuration
|
||||
*
|
||||
* To deploy via Infura you'll need a wallet provider (like truffle-hdwallet-provider)
|
||||
* to sign your transactions before they're sent to a remote public node. Infura accounts
|
||||
* are available for free at: infura.io/register.
|
||||
*
|
||||
* You'll also need a mnemonic - the twelve word phrase the wallet uses to generate
|
||||
* public/private key pairs. If you're publishing your code to GitHub make sure you load this
|
||||
* phrase from a file you've .gitignored so it doesn't accidentally become public.
|
||||
*
|
||||
*/
|
||||
|
||||
// const HDWalletProvider = require('truffle-hdwallet-provider');
|
||||
// const infuraKey = "fj4jll3k.....";
|
||||
//
|
||||
// const fs = require('fs');
|
||||
// const mnemonic = fs.readFileSync(".secret").toString().trim();
|
||||
|
||||
module.exports = {
|
||||
/**
|
||||
* Networks define how you connect to your ethereum client and let you set the
|
||||
* defaults web3 uses to send transactions. If you don't specify one truffle
|
||||
* will spin up a development blockchain for you on port 9545 when you
|
||||
* run `develop` or `test`. You can ask a truffle command to use a specific
|
||||
* network from the command line, e.g
|
||||
*
|
||||
* $ truffle test --network <network-name>
|
||||
*/
|
||||
|
||||
networks: {
|
||||
// Useful for testing. The `development` name is special - truffle uses it by default
|
||||
// if it's defined here and no other network is specified at the command line.
|
||||
// You should run a client (like ganache-cli, geth or parity) in a separate terminal
|
||||
// tab if you use this network and you must also set the `host`, `port` and `network_id`
|
||||
// options below to some value.
|
||||
//
|
||||
// development: {
|
||||
// host: "127.0.0.1", // Localhost (default: none)
|
||||
// port: 8545, // Standard Ethereum port (default: none)
|
||||
// network_id: "*", // Any network (default: none)
|
||||
// },
|
||||
// Another network with more advanced options...
|
||||
// advanced: {
|
||||
// port: 8777, // Custom port
|
||||
// network_id: 1342, // Custom network
|
||||
// gas: 8500000, // Gas sent with each transaction (default: ~6700000)
|
||||
// gasPrice: 20000000000, // 20 gwei (in wei) (default: 100 gwei)
|
||||
// from: <address>, // Account to send txs from (default: accounts[0])
|
||||
// websockets: true // Enable EventEmitter interface for web3 (default: false)
|
||||
// },
|
||||
// Useful for deploying to a public network.
|
||||
// NB: It's important to wrap the provider as a function.
|
||||
// ropsten: {
|
||||
// provider: () => new HDWalletProvider(mnemonic, `https://ropsten.infura.io/v3/YOUR-PROJECT-ID`),
|
||||
// network_id: 3, // Ropsten's id
|
||||
// gas: 5500000, // Ropsten has a lower block limit than mainnet
|
||||
// confirmations: 2, // # of confs to wait between deployments. (default: 0)
|
||||
// timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50)
|
||||
// skipDryRun: true // Skip dry run before migrations? (default: false for public nets )
|
||||
// },
|
||||
// Useful for private networks
|
||||
// private: {
|
||||
// provider: () => new HDWalletProvider(mnemonic, `https://network.io`),
|
||||
// network_id: 2111, // This network is yours, in the cloud.
|
||||
// production: true // Treats this network as if it was a public net. (default: false)
|
||||
// }
|
||||
},
|
||||
|
||||
// Set default mocha options here, use special reporters etc.
|
||||
mocha: {
|
||||
// timeout: 100000
|
||||
},
|
||||
|
||||
// Configure your compilers
|
||||
compilers: {
|
||||
solc: {
|
||||
version: '0.5.9',
|
||||
settings: {
|
||||
evmVersion: 'constantinople',
|
||||
optimizer: {
|
||||
enabled: true,
|
||||
runs: 1000000,
|
||||
details: { yul: true, deduplicate: true, cse: true, constantOptimizer: true },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
@@ -1,4 +1,53 @@
|
||||
[
|
||||
{
|
||||
"version": "0.1.0-beta.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Use built in selectors instead of hard coded constants",
|
||||
"pr": 2055
|
||||
},
|
||||
{
|
||||
"note": "Compile and export all contracts, artifacts, and wrappers by default",
|
||||
"pr": 2055
|
||||
},
|
||||
{
|
||||
"note": "Add `marketBuy/SellOrdersNoThrow` and `marketBuy/SellOrdersFillOrKill` to `LibTransactionDecoder`.",
|
||||
"pr": 2075
|
||||
},
|
||||
{
|
||||
"note": "`run_mocha` package script runs with `UNLIMITED_CONTRACT_SIZE=true` environment variable.",
|
||||
"pr": 2075
|
||||
}
|
||||
],
|
||||
"timestamp": 1570135330
|
||||
},
|
||||
{
|
||||
"timestamp": 1568744790,
|
||||
"version": "0.0.10",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1567521715,
|
||||
"version": "0.0.9",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1566446343,
|
||||
"version": "0.0.8",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1565296576,
|
||||
"version": "0.0.7",
|
||||
@@ -89,6 +138,14 @@
|
||||
{
|
||||
"note": "Add support for StaticCallProxy",
|
||||
"pr": 1863
|
||||
},
|
||||
{
|
||||
"note": "Add `OrderTransferSimulationUtils` contract for simulating order transfers on-chain",
|
||||
"pr": 1868
|
||||
},
|
||||
{
|
||||
"note": "Updated to use the new rich error pattern from @0x/contracts-exchange",
|
||||
"pr": 1913
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@@ -5,6 +5,25 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v0.1.0-beta.0 - _October 3, 2019_
|
||||
|
||||
* Use built in selectors instead of hard coded constants (#2055)
|
||||
* Compile and export all contracts, artifacts, and wrappers by default (#2055)
|
||||
* Add `marketBuy/SellOrdersNoThrow` and `marketBuy/SellOrdersFillOrKill` to `LibTransactionDecoder`. (#2075)
|
||||
* `run_mocha` package script runs with `UNLIMITED_CONTRACT_SIZE=true` environment variable. (#2075)
|
||||
|
||||
## v0.0.10 - _September 17, 2019_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v0.0.9 - _September 3, 2019_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v0.0.8 - _August 22, 2019_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v0.0.7 - _August 8, 2019_
|
||||
|
||||
* Dependencies updated
|
||||
@@ -41,3 +60,5 @@ CHANGELOG
|
||||
* Refactor `LibAssetData` balance/allowance checks to never revert (#1848)
|
||||
* Refactor `OrderValidationUtils` to calculate `fillableTakerAssetAmount` (#1848)
|
||||
* Add support for StaticCallProxy (#1863)
|
||||
* Add `OrderTransferSimulationUtils` contract for simulating order transfers on-chain (#1868)
|
||||
* Updated to use the new rich error pattern from @0x/contracts-exchange (#1913)
|
||||
|
@@ -1,6 +1,6 @@
|
||||
## Dev-Utils
|
||||
|
||||
This package implements various utilities for developers. For example, the `DevUtils` contract can query batches of balances or allowances given some `assetData`, can validate batches of orders, and can decode 0x-specific calldata. Addresses of the deployed contracts can be found in the 0x [wiki](https://0xproject.com/wiki#Deployed-Addresses) or the [DEPLOYS](./DEPLOYS.json) file within this package.
|
||||
This package implements various utilities for developers. For example, the `DevUtils` contract can query batches of balances or allowances given some `assetData`, can validate batches of orders, and can decode 0x-specific calldata. 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
|
||||
|
||||
@@ -12,7 +12,7 @@ npm install @0x/contracts-dev-utils --save
|
||||
|
||||
## Bug bounty
|
||||
|
||||
A bug bounty for the 2.0.0 contracts is ongoing! Instructions can be found [here](https://0xproject.com/wiki#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
|
||||
|
||||
|
@@ -7,7 +7,7 @@
|
||||
"evmVersion": "constantinople",
|
||||
"optimizer": {
|
||||
"enabled": true,
|
||||
"runs": 1000000,
|
||||
"runs": 10000,
|
||||
"details": { "yul": true, "deduplicate": true, "cse": true, "constantOptimizer": true }
|
||||
},
|
||||
"outputSelection": {
|
||||
@@ -22,11 +22,5 @@
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"contracts": [
|
||||
"src/DevUtils.sol",
|
||||
"src/LibAssetData.sol",
|
||||
"src/LibTransactionDecoder.sol",
|
||||
"src/EthBalanceChecker.sol"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -20,6 +20,7 @@ pragma solidity ^0.5.5;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "./OrderValidationUtils.sol";
|
||||
import "./OrderTransferSimulationUtils.sol";
|
||||
import "./LibTransactionDecoder.sol";
|
||||
import "./EthBalanceChecker.sol";
|
||||
|
||||
@@ -28,10 +29,12 @@ import "./EthBalanceChecker.sol";
|
||||
contract DevUtils is
|
||||
OrderValidationUtils,
|
||||
LibTransactionDecoder,
|
||||
EthBalanceChecker
|
||||
EthBalanceChecker,
|
||||
OrderTransferSimulationUtils
|
||||
{
|
||||
constructor (address _exchange, bytes memory _zrxAssetData)
|
||||
constructor (address _exchange)
|
||||
public
|
||||
OrderValidationUtils(_exchange, _zrxAssetData)
|
||||
OrderValidationUtils(_exchange)
|
||||
OrderTransferSimulationUtils(_exchange)
|
||||
{}
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
@@ -20,32 +20,19 @@ pragma solidity ^0.5.5;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
|
||||
import "@0x/contracts-asset-proxy/contracts/src/libs/LibAssetProxyIds.sol";
|
||||
import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol";
|
||||
import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetData.sol";
|
||||
import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetProxy.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||
import "@0x/contracts-erc721/contracts/src/interfaces/IERC721Token.sol";
|
||||
import "@0x/contracts-erc1155/contracts/src/interfaces/IERC1155.sol";
|
||||
|
||||
|
||||
contract LibAssetData is
|
||||
LibAssetProxyIds
|
||||
{
|
||||
contract LibAssetData {
|
||||
|
||||
// 2^256 - 1
|
||||
uint256 constant internal _MAX_UINT256 = uint256(-1);
|
||||
|
||||
// ERC20 selectors
|
||||
bytes4 constant internal _ERC20_BALANCE_OF_SELECTOR = 0x70a08231;
|
||||
bytes4 constant internal _ERC20_ALLOWANCE_SELECTOR = 0xdd62ed3e;
|
||||
|
||||
// ERC721 selectors
|
||||
bytes4 constant internal _ERC721_OWNER_OF_SELECTOR = 0x6352211e;
|
||||
bytes4 constant internal _ERC721_IS_APPROVED_FOR_ALL_SELECTOR = 0xe985e9c5;
|
||||
bytes4 constant internal _ERC721_GET_APPROVED_SELECTOR = 0x081812fc;
|
||||
|
||||
// ERC1155 selectors
|
||||
bytes4 constant internal _ERC1155_BALANCE_OF_SELECTOR = 0x00fdd58e;
|
||||
bytes4 constant internal _ERC1155_IS_APPROVED_FOR_ALL_SELECTOR = 0xe985e9c5;
|
||||
|
||||
// `transferFrom` selector for all AssetProxy contracts
|
||||
bytes4 constant internal _ASSET_PROXY_TRANSFER_FROM_SELECTOR = 0xa85e59e4;
|
||||
|
||||
using LibBytes for bytes;
|
||||
|
||||
// solhint-disable var-name-mixedcase
|
||||
@@ -60,10 +47,10 @@ contract LibAssetData is
|
||||
public
|
||||
{
|
||||
_EXCHANGE = IExchange(_exchange);
|
||||
_ERC20_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(ERC20_PROXY_ID);
|
||||
_ERC721_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(ERC721_PROXY_ID);
|
||||
_ERC1155_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(ERC1155_PROXY_ID);
|
||||
_STATIC_CALL_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(STATIC_CALL_PROXY_ID);
|
||||
_ERC20_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(IAssetData(address(0)).ERC20Token.selector);
|
||||
_ERC721_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(IAssetData(address(0)).ERC721Token.selector);
|
||||
_ERC1155_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(IAssetData(address(0)).ERC1155Assets.selector);
|
||||
_STATIC_CALL_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(IAssetData(address(0)).StaticCall.selector);
|
||||
}
|
||||
|
||||
/// @dev Returns the owner's balance of the assets(s) specified in
|
||||
@@ -81,23 +68,33 @@ contract LibAssetData is
|
||||
// Get id of AssetProxy contract
|
||||
bytes4 assetProxyId = assetData.readBytes4(0);
|
||||
|
||||
if (assetProxyId == ERC20_PROXY_ID) {
|
||||
if (assetProxyId == IAssetData(address(0)).ERC20Token.selector) {
|
||||
// Get ERC20 token address
|
||||
address tokenAddress = assetData.readAddress(16);
|
||||
|
||||
// Encode data for `balanceOf(ownerAddress)`
|
||||
bytes memory balanceOfData = abi.encodeWithSelector(_ERC20_BALANCE_OF_SELECTOR, ownerAddress);
|
||||
bytes memory balanceOfData = abi.encodeWithSelector(
|
||||
IERC20Token(address(0)).balanceOf.selector,
|
||||
ownerAddress
|
||||
);
|
||||
|
||||
// Query balance
|
||||
(bool success, bytes memory returnData) = tokenAddress.staticcall(balanceOfData);
|
||||
balance = success && returnData.length == 32 ? returnData.readUint256(0) : 0;
|
||||
} else if (assetProxyId == ERC721_PROXY_ID) {
|
||||
} else if (assetProxyId == IAssetData(address(0)).ERC721Token.selector) {
|
||||
// Get ERC721 token address and id
|
||||
(, address tokenAddress, uint256 tokenId) = decodeERC721AssetData(assetData);
|
||||
|
||||
// Check if id is owned by ownerAddress
|
||||
balance = getERC721TokenOwner(tokenAddress, tokenId) == ownerAddress ? 1 : 0;
|
||||
} else if (assetProxyId == ERC1155_PROXY_ID) {
|
||||
bytes memory ownerOfCalldata = abi.encodeWithSelector(
|
||||
IERC721Token(address(0)).ownerOf.selector,
|
||||
tokenId
|
||||
);
|
||||
|
||||
(bool success, bytes memory returnData) = tokenAddress.staticcall(ownerOfCalldata);
|
||||
address currentOwnerAddress = (success && returnData.length == 32) ? returnData.readAddress(12) : address(0);
|
||||
balance = currentOwnerAddress == ownerAddress ? 1 : 0;
|
||||
} else if (assetProxyId == IAssetData(address(0)).ERC1155Assets.selector) {
|
||||
// Get ERC1155 token address, array of ids, and array of values
|
||||
(, address tokenAddress, uint256[] memory tokenIds, uint256[] memory tokenValues,) = decodeERC1155AssetData(assetData);
|
||||
|
||||
@@ -105,7 +102,7 @@ contract LibAssetData is
|
||||
for (uint256 i = 0; i != length; i++) {
|
||||
// Encode data for `balanceOf(ownerAddress, tokenIds[i])
|
||||
bytes memory balanceOfData = abi.encodeWithSelector(
|
||||
_ERC1155_BALANCE_OF_SELECTOR,
|
||||
IERC1155(address(0)).balanceOf.selector,
|
||||
ownerAddress,
|
||||
tokenIds[i]
|
||||
);
|
||||
@@ -120,10 +117,10 @@ contract LibAssetData is
|
||||
balance = scaledBalance;
|
||||
}
|
||||
}
|
||||
} else if (assetProxyId == STATIC_CALL_PROXY_ID) {
|
||||
} else if (assetProxyId == IAssetData(address(0)).StaticCall.selector) {
|
||||
// Encode data for `staticCallProxy.transferFrom(assetData,...)`
|
||||
bytes memory transferFromData = abi.encodeWithSelector(
|
||||
_ASSET_PROXY_TRANSFER_FROM_SELECTOR,
|
||||
IAssetProxy(address(0)).transferFrom.selector,
|
||||
assetData,
|
||||
address(0), // `from` address is not used
|
||||
address(0), // `to` address is not used
|
||||
@@ -135,7 +132,7 @@ contract LibAssetData is
|
||||
|
||||
// Success means that the staticcall can be made an unlimited amount of times
|
||||
balance = success ? _MAX_UINT256 : 0;
|
||||
} else if (assetProxyId == MULTI_ASSET_PROXY_ID) {
|
||||
} else if (assetProxyId == IAssetData(address(0)).MultiAsset.selector) {
|
||||
// Get array of values and array of assetDatas
|
||||
(, uint256[] memory assetAmounts, bytes[] memory nestedAssetData) = decodeMultiAssetData(assetData);
|
||||
|
||||
@@ -190,7 +187,7 @@ contract LibAssetData is
|
||||
// Get id of AssetProxy contract
|
||||
bytes4 assetProxyId = assetData.readBytes4(0);
|
||||
|
||||
if (assetProxyId == MULTI_ASSET_PROXY_ID) {
|
||||
if (assetProxyId == IAssetData(address(0)).MultiAsset.selector) {
|
||||
// Get array of values and array of assetDatas
|
||||
(, uint256[] memory amounts, bytes[] memory nestedAssetData) = decodeMultiAssetData(assetData);
|
||||
|
||||
@@ -208,13 +205,13 @@ contract LibAssetData is
|
||||
return allowance;
|
||||
}
|
||||
|
||||
if (assetProxyId == ERC20_PROXY_ID) {
|
||||
if (assetProxyId == IAssetData(address(0)).ERC20Token.selector) {
|
||||
// Get ERC20 token address
|
||||
address tokenAddress = assetData.readAddress(16);
|
||||
|
||||
// Encode data for `allowance(ownerAddress, _ERC20_PROXY_ADDRESS)`
|
||||
bytes memory allowanceData = abi.encodeWithSelector(
|
||||
_ERC20_ALLOWANCE_SELECTOR,
|
||||
IERC20Token(address(0)).allowance.selector,
|
||||
ownerAddress,
|
||||
_ERC20_PROXY_ADDRESS
|
||||
);
|
||||
@@ -222,13 +219,13 @@ contract LibAssetData is
|
||||
// Query allowance
|
||||
(bool success, bytes memory returnData) = tokenAddress.staticcall(allowanceData);
|
||||
allowance = success && returnData.length == 32 ? returnData.readUint256(0) : 0;
|
||||
} else if (assetProxyId == ERC721_PROXY_ID) {
|
||||
} else if (assetProxyId == IAssetData(address(0)).ERC721Token.selector) {
|
||||
// Get ERC721 token address and id
|
||||
(, address tokenAddress, uint256 tokenId) = decodeERC721AssetData(assetData);
|
||||
|
||||
// Encode data for `isApprovedForAll(ownerAddress, _ERC721_PROXY_ADDRESS)`
|
||||
bytes memory isApprovedForAllData = abi.encodeWithSelector(
|
||||
_ERC721_IS_APPROVED_FOR_ALL_SELECTOR,
|
||||
IERC721Token(address(0)).isApprovedForAll.selector,
|
||||
ownerAddress,
|
||||
_ERC721_PROXY_ADDRESS
|
||||
);
|
||||
@@ -238,7 +235,7 @@ contract LibAssetData is
|
||||
// If not approved for all, call `getApproved(tokenId)`
|
||||
if (!success || returnData.length != 32 || returnData.readUint256(0) != 1) {
|
||||
// Encode data for `getApproved(tokenId)`
|
||||
bytes memory getApprovedData = abi.encodeWithSelector(_ERC721_GET_APPROVED_SELECTOR, tokenId);
|
||||
bytes memory getApprovedData = abi.encodeWithSelector(IERC721Token(address(0)).getApproved.selector, tokenId);
|
||||
(success, returnData) = tokenAddress.staticcall(getApprovedData);
|
||||
|
||||
// Allowance is 1 if successful and the approved address is the ERC721Proxy
|
||||
@@ -247,13 +244,13 @@ contract LibAssetData is
|
||||
// Allowance is 2^256 - 1 if `isApprovedForAll` returned true
|
||||
allowance = _MAX_UINT256;
|
||||
}
|
||||
} else if (assetProxyId == ERC1155_PROXY_ID) {
|
||||
} else if (assetProxyId == IAssetData(address(0)).ERC1155Assets.selector) {
|
||||
// Get ERC1155 token address
|
||||
(, address tokenAddress, , , ) = decodeERC1155AssetData(assetData);
|
||||
|
||||
// Encode data for `isApprovedForAll(ownerAddress, _ERC1155_PROXY_ADDRESS)`
|
||||
bytes memory isApprovedForAllData = abi.encodeWithSelector(
|
||||
_ERC1155_IS_APPROVED_FOR_ALL_SELECTOR,
|
||||
IERC1155(address(0)).isApprovedForAll.selector,
|
||||
ownerAddress,
|
||||
_ERC1155_PROXY_ADDRESS
|
||||
);
|
||||
@@ -261,7 +258,7 @@ contract LibAssetData is
|
||||
// Query allowance
|
||||
(bool success, bytes memory returnData) = tokenAddress.staticcall(isApprovedForAllData);
|
||||
allowance = success && returnData.length == 32 && returnData.readUint256(0) == 1 ? _MAX_UINT256 : 0;
|
||||
} else if (assetProxyId == STATIC_CALL_PROXY_ID) {
|
||||
} else if (assetProxyId == IAssetData(address(0)).StaticCall.selector) {
|
||||
// The StaticCallProxy does not require any approvals
|
||||
allowance = _MAX_UINT256;
|
||||
}
|
||||
@@ -327,7 +324,7 @@ contract LibAssetData is
|
||||
pure
|
||||
returns (bytes memory assetData)
|
||||
{
|
||||
assetData = abi.encodeWithSelector(ERC20_PROXY_ID, tokenAddress);
|
||||
assetData = abi.encodeWithSelector(IAssetData(address(0)).ERC20Token.selector, tokenAddress);
|
||||
return assetData;
|
||||
}
|
||||
|
||||
@@ -346,7 +343,7 @@ contract LibAssetData is
|
||||
assetProxyId = assetData.readBytes4(0);
|
||||
|
||||
require(
|
||||
assetProxyId == ERC20_PROXY_ID,
|
||||
assetProxyId == IAssetData(address(0)).ERC20Token.selector,
|
||||
"WRONG_PROXY_ID"
|
||||
);
|
||||
|
||||
@@ -364,7 +361,7 @@ contract LibAssetData is
|
||||
returns (bytes memory assetData)
|
||||
{
|
||||
assetData = abi.encodeWithSelector(
|
||||
ERC721_PROXY_ID,
|
||||
IAssetData(address(0)).ERC721Token.selector,
|
||||
tokenAddress,
|
||||
tokenId
|
||||
);
|
||||
@@ -388,7 +385,7 @@ contract LibAssetData is
|
||||
assetProxyId = assetData.readBytes4(0);
|
||||
|
||||
require(
|
||||
assetProxyId == ERC721_PROXY_ID,
|
||||
assetProxyId == IAssetData(address(0)).ERC721Token.selector,
|
||||
"WRONG_PROXY_ID"
|
||||
);
|
||||
|
||||
@@ -414,7 +411,7 @@ contract LibAssetData is
|
||||
returns (bytes memory assetData)
|
||||
{
|
||||
assetData = abi.encodeWithSelector(
|
||||
ERC1155_PROXY_ID,
|
||||
IAssetData(address(0)).ERC1155Assets.selector,
|
||||
tokenAddress,
|
||||
tokenIds,
|
||||
tokenValues,
|
||||
@@ -446,7 +443,7 @@ contract LibAssetData is
|
||||
assetProxyId = assetData.readBytes4(0);
|
||||
|
||||
require(
|
||||
assetProxyId == ERC1155_PROXY_ID,
|
||||
assetProxyId == IAssetData(address(0)).ERC1155Assets.selector,
|
||||
"WRONG_PROXY_ID"
|
||||
);
|
||||
|
||||
@@ -482,7 +479,7 @@ contract LibAssetData is
|
||||
returns (bytes memory assetData)
|
||||
{
|
||||
assetData = abi.encodeWithSelector(
|
||||
MULTI_ASSET_PROXY_ID,
|
||||
IAssetData(address(0)).MultiAsset.selector,
|
||||
amounts,
|
||||
nestedAssetData
|
||||
);
|
||||
@@ -507,7 +504,7 @@ contract LibAssetData is
|
||||
assetProxyId = assetData.readBytes4(0);
|
||||
|
||||
require(
|
||||
assetProxyId == MULTI_ASSET_PROXY_ID,
|
||||
assetProxyId == IAssetData(address(0)).MultiAsset.selector,
|
||||
"WRONG_PROXY_ID"
|
||||
);
|
||||
|
||||
@@ -518,24 +515,4 @@ contract LibAssetData is
|
||||
);
|
||||
// solhint-enable indent
|
||||
}
|
||||
|
||||
/// @dev Calls `asset.ownerOf(tokenId)`, but returns a null owner instead of reverting on an unowned asset.
|
||||
/// @param tokenAddress Address of ERC721 asset.
|
||||
/// @param tokenId The identifier for the specific NFT.
|
||||
/// @return Owner of tokenId or null address if unowned.
|
||||
function getERC721TokenOwner(address tokenAddress, uint256 tokenId)
|
||||
public
|
||||
view
|
||||
returns (address ownerAddress)
|
||||
{
|
||||
bytes memory ownerOfCalldata = abi.encodeWithSelector(
|
||||
_ERC721_OWNER_OF_SELECTOR,
|
||||
tokenId
|
||||
);
|
||||
|
||||
(bool success, bytes memory returnData) = tokenAddress.staticcall(ownerOfCalldata);
|
||||
|
||||
ownerAddress = (success && returnData.length == 32) ? returnData.readAddress(12) : address(0);
|
||||
return ownerAddress;
|
||||
}
|
||||
}
|
||||
|
@@ -19,14 +19,13 @@
|
||||
pragma solidity ^0.5.5;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibExchangeSelectors.sol";
|
||||
import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
|
||||
|
||||
|
||||
contract LibTransactionDecoder is
|
||||
LibExchangeSelectors
|
||||
{
|
||||
contract LibTransactionDecoder {
|
||||
|
||||
using LibBytes for bytes;
|
||||
|
||||
/// @dev Decodes the call data for an Exchange contract method call.
|
||||
@@ -47,72 +46,68 @@ contract LibTransactionDecoder is
|
||||
{
|
||||
bytes4 functionSelector = transactionData.readBytes4(0);
|
||||
|
||||
if (functionSelector == BATCH_CANCEL_ORDERS_SELECTOR) {
|
||||
if (functionSelector == IExchange(address(0)).batchCancelOrders.selector) {
|
||||
functionName = "batchCancelOrders";
|
||||
} else if (functionSelector == BATCH_FILL_ORDERS_SELECTOR) {
|
||||
} else if (functionSelector == IExchange(address(0)).batchFillOrders.selector) {
|
||||
functionName = "batchFillOrders";
|
||||
} else if (functionSelector == BATCH_FILL_ORDERS_NO_THROW_SELECTOR) {
|
||||
} else if (functionSelector == IExchange(address(0)).batchFillOrdersNoThrow.selector) {
|
||||
functionName = "batchFillOrdersNoThrow";
|
||||
} else if (functionSelector == BATCH_FILL_OR_KILL_ORDERS_SELECTOR) {
|
||||
} else if (functionSelector == IExchange(address(0)).batchFillOrKillOrders.selector) {
|
||||
functionName = "batchFillOrKillOrders";
|
||||
} else if (functionSelector == CANCEL_ORDER_SELECTOR) {
|
||||
} else if (functionSelector == IExchange(address(0)).cancelOrder.selector) {
|
||||
functionName = "cancelOrder";
|
||||
} else if (functionSelector == FILL_ORDER_SELECTOR) {
|
||||
} else if (functionSelector == IExchange(address(0)).fillOrder.selector) {
|
||||
functionName = "fillOrder";
|
||||
} else if (functionSelector == FILL_ORDER_NO_THROW_SELECTOR) {
|
||||
functionName = "fillOrderNoThrow";
|
||||
} else if (functionSelector == FILL_OR_KILL_ORDER_SELECTOR) {
|
||||
} else if (functionSelector == IExchange(address(0)).fillOrKillOrder.selector) {
|
||||
functionName = "fillOrKillOrder";
|
||||
} else if (functionSelector == MARKET_BUY_ORDERS_SELECTOR) {
|
||||
functionName = "marketBuyOrders";
|
||||
} else if (functionSelector == MARKET_BUY_ORDERS_NO_THROW_SELECTOR) {
|
||||
} else if (functionSelector == IExchange(address(0)).marketBuyOrdersNoThrow.selector) {
|
||||
functionName = "marketBuyOrdersNoThrow";
|
||||
} else if (functionSelector == MARKET_SELL_ORDERS_SELECTOR) {
|
||||
functionName = "marketSellOrders";
|
||||
} else if (functionSelector == MARKET_SELL_ORDERS_NO_THROW_SELECTOR) {
|
||||
} else if (functionSelector == IExchange(address(0)).marketSellOrdersNoThrow.selector) {
|
||||
functionName = "marketSellOrdersNoThrow";
|
||||
} else if (functionSelector == MATCH_ORDERS_SELECTOR) {
|
||||
} else if (functionSelector == IExchange(address(0)).marketBuyOrdersFillOrKill.selector) {
|
||||
functionName = "marketBuyOrdersFillOrKill";
|
||||
} else if (functionSelector == IExchange(address(0)).marketSellOrdersFillOrKill.selector) {
|
||||
functionName = "marketSellOrdersFillOrKill";
|
||||
} else if (functionSelector == IExchange(address(0)).matchOrders.selector) {
|
||||
functionName = "matchOrders";
|
||||
} else if (
|
||||
functionSelector == CANCEL_ORDERS_UP_TO_SELECTOR ||
|
||||
functionSelector == EXECUTE_TRANSACTION_SELECTOR
|
||||
// TODO: add new noThrow cancel functions when https://github.com/0xProject/ZEIPs/issues/35 is merged.
|
||||
functionSelector == IExchange(address(0)).cancelOrdersUpTo.selector ||
|
||||
functionSelector == IExchange(address(0)).executeTransaction.selector
|
||||
) {
|
||||
revert("UNIMPLEMENTED");
|
||||
} else {
|
||||
revert("UNKNOWN_FUNCTION_SELECTOR");
|
||||
}
|
||||
|
||||
if (functionSelector == BATCH_CANCEL_ORDERS_SELECTOR) {
|
||||
if (functionSelector == IExchange(address(0)).batchCancelOrders.selector) {
|
||||
// solhint-disable-next-line indent
|
||||
orders = abi.decode(transactionData.slice(4, transactionData.length), (LibOrder.Order[]));
|
||||
takerAssetFillAmounts = new uint256[](0);
|
||||
signatures = new bytes[](0);
|
||||
} else if (
|
||||
functionSelector == BATCH_FILL_OR_KILL_ORDERS_SELECTOR ||
|
||||
functionSelector == BATCH_FILL_ORDERS_NO_THROW_SELECTOR ||
|
||||
functionSelector == BATCH_FILL_ORDERS_SELECTOR
|
||||
functionSelector == IExchange(address(0)).batchFillOrKillOrders.selector ||
|
||||
functionSelector == IExchange(address(0)).batchFillOrders.selector ||
|
||||
functionSelector == IExchange(address(0)).batchFillOrdersNoThrow.selector
|
||||
) {
|
||||
(orders, takerAssetFillAmounts, signatures) = _makeReturnValuesForBatchFill(transactionData);
|
||||
} else if (functionSelector == CANCEL_ORDER_SELECTOR) {
|
||||
} else if (functionSelector == IExchange(address(0)).cancelOrder.selector) {
|
||||
orders = new LibOrder.Order[](1);
|
||||
orders[0] = abi.decode(transactionData.slice(4, transactionData.length), (LibOrder.Order));
|
||||
takerAssetFillAmounts = new uint256[](0);
|
||||
signatures = new bytes[](0);
|
||||
} else if (
|
||||
functionSelector == FILL_OR_KILL_ORDER_SELECTOR ||
|
||||
functionSelector == FILL_ORDER_SELECTOR ||
|
||||
functionSelector == FILL_ORDER_NO_THROW_SELECTOR
|
||||
functionSelector == IExchange(address(0)).fillOrKillOrder.selector ||
|
||||
functionSelector == IExchange(address(0)).fillOrder.selector
|
||||
) {
|
||||
(orders, takerAssetFillAmounts, signatures) = _makeReturnValuesForSingleOrderFill(transactionData);
|
||||
} else if (
|
||||
functionSelector == MARKET_BUY_ORDERS_SELECTOR ||
|
||||
functionSelector == MARKET_BUY_ORDERS_NO_THROW_SELECTOR ||
|
||||
functionSelector == MARKET_SELL_ORDERS_SELECTOR ||
|
||||
functionSelector == MARKET_SELL_ORDERS_NO_THROW_SELECTOR
|
||||
functionSelector == IExchange(address(0)).marketBuyOrdersNoThrow.selector ||
|
||||
functionSelector == IExchange(address(0)).marketSellOrdersNoThrow.selector ||
|
||||
functionSelector == IExchange(address(0)).marketBuyOrdersFillOrKill.selector ||
|
||||
functionSelector == IExchange(address(0)).marketSellOrdersFillOrKill.selector
|
||||
) {
|
||||
(orders, takerAssetFillAmounts, signatures) = _makeReturnValuesForMarketFill(transactionData);
|
||||
} else if (functionSelector == MATCH_ORDERS_SELECTOR) {
|
||||
} else if (functionSelector == IExchange(address(0)).matchOrders.selector) {
|
||||
(
|
||||
LibOrder.Order memory leftOrder,
|
||||
LibOrder.Order memory rightOrder,
|
||||
|
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.5;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
|
||||
import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol";
|
||||
import "@0x/contracts-exchange/contracts/src/libs/LibExchangeRichErrorDecoder.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibExchangeRichErrors.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
|
||||
|
||||
|
||||
contract OrderTransferSimulationUtils is
|
||||
LibExchangeRichErrorDecoder
|
||||
{
|
||||
using LibBytes for bytes;
|
||||
|
||||
enum OrderTransferResults {
|
||||
TakerAssetDataFailed, // Transfer of takerAsset failed
|
||||
MakerAssetDataFailed, // Transfer of makerAsset failed
|
||||
TakerFeeAssetDataFailed, // Transfer of takerFeeAsset failed
|
||||
MakerFeeAssetDataFailed, // Transfer of makerFeeAsset failed
|
||||
TransfersSuccessful // All transfers in the order were successful
|
||||
}
|
||||
|
||||
// keccak256(abi.encodeWithSignature("Error(string)", "TRANSFERS_SUCCESSFUL"));
|
||||
bytes32 constant internal _TRANSFERS_SUCCESSFUL_RESULT_HASH = 0xf43f26ea5a94b478394a975e856464913dc1a8a1ca70939d974aa7c238aa0ce0;
|
||||
|
||||
// solhint-disable var-name-mixedcase
|
||||
IExchange internal _EXCHANGE;
|
||||
// solhint-enable var-name-mixedcase
|
||||
|
||||
constructor (address _exchange)
|
||||
public
|
||||
{
|
||||
_EXCHANGE = IExchange(_exchange);
|
||||
}
|
||||
|
||||
/// @dev Simulates all of the transfers within an order and returns the index of the first failed transfer.
|
||||
/// @param order The order to simulate transfers for.
|
||||
/// @param takerAddress The address of the taker that will fill the order.
|
||||
/// @param takerAssetFillAmount The amount of takerAsset that the taker wished to fill.
|
||||
/// @return The index of the first failed transfer (or 4 if all transfers are successful).
|
||||
function getSimulatedOrderTransferResults(
|
||||
LibOrder.Order memory order,
|
||||
address takerAddress,
|
||||
uint256 takerAssetFillAmount
|
||||
)
|
||||
public
|
||||
returns (OrderTransferResults orderTransferResults)
|
||||
{
|
||||
LibFillResults.FillResults memory fillResults = LibFillResults.calculateFillResults(
|
||||
order,
|
||||
takerAssetFillAmount,
|
||||
_EXCHANGE.protocolFeeMultiplier(),
|
||||
tx.gasprice
|
||||
);
|
||||
|
||||
// Create input arrays
|
||||
bytes[] memory assetData = new bytes[](4);
|
||||
address[] memory fromAddresses = new address[](4);
|
||||
address[] memory toAddresses = new address[](4);
|
||||
uint256[] memory amounts = new uint256[](4);
|
||||
|
||||
// Transfer `takerAsset` from taker to maker
|
||||
assetData[0] = order.takerAssetData;
|
||||
fromAddresses[0] = takerAddress;
|
||||
toAddresses[0] = order.makerAddress;
|
||||
amounts[0] = takerAssetFillAmount;
|
||||
|
||||
// Transfer `makerAsset` from maker to taker
|
||||
assetData[1] = order.makerAssetData;
|
||||
fromAddresses[1] = order.makerAddress;
|
||||
toAddresses[1] = takerAddress;
|
||||
amounts[1] = fillResults.makerAssetFilledAmount;
|
||||
|
||||
// Transfer `takerFeeAsset` from taker to feeRecipient
|
||||
assetData[2] = order.takerFeeAssetData;
|
||||
fromAddresses[2] = takerAddress;
|
||||
toAddresses[2] = order.feeRecipientAddress;
|
||||
amounts[2] = fillResults.takerFeePaid;
|
||||
|
||||
// Transfer `makerFeeAsset` from maker to feeRecipient
|
||||
assetData[3] = order.makerFeeAssetData;
|
||||
fromAddresses[3] = order.makerAddress;
|
||||
toAddresses[3] = order.feeRecipientAddress;
|
||||
amounts[3] = fillResults.makerFeePaid;
|
||||
|
||||
// Encode data for `simulateDispatchTransferFromCalls(assetData, fromAddresses, toAddresses, amounts)`
|
||||
bytes memory simulateDispatchTransferFromCallsData = abi.encodeWithSelector(
|
||||
IExchange(address(0)).simulateDispatchTransferFromCalls.selector,
|
||||
assetData,
|
||||
fromAddresses,
|
||||
toAddresses,
|
||||
amounts
|
||||
);
|
||||
|
||||
// Perform call and catch revert
|
||||
(, bytes memory returnData) = address(_EXCHANGE).call(simulateDispatchTransferFromCallsData);
|
||||
|
||||
bytes4 selector = returnData.readBytes4(0);
|
||||
if (selector == LibExchangeRichErrors.AssetProxyDispatchErrorSelector()) {
|
||||
// Decode AssetProxyDispatchError and return index of failed transfer
|
||||
(, bytes32 failedTransferIndex,) = decodeAssetProxyDispatchError(returnData);
|
||||
return OrderTransferResults(uint8(uint256(failedTransferIndex)));
|
||||
} else if (selector == LibExchangeRichErrors.AssetProxyTransferErrorSelector()) {
|
||||
// Decode AssetProxyTransferError and return index of failed transfer
|
||||
(bytes32 failedTransferIndex, ,) = decodeAssetProxyTransferError(returnData);
|
||||
return OrderTransferResults(uint8(uint256(failedTransferIndex)));
|
||||
} else if (keccak256(returnData) == _TRANSFERS_SUCCESSFUL_RESULT_HASH) {
|
||||
// All transfers were successful
|
||||
return OrderTransferResults.TransfersSuccessful;
|
||||
} else {
|
||||
revert("UNKNOWN_RETURN_DATA");
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Simulates all of the transfers for each given order and returns the indices of each first failed transfer.
|
||||
/// @param orders Array of orders to individually simulate transfers for.
|
||||
/// @param takerAddresses Array of addresses of takers that will fill each order.
|
||||
/// @param takerAssetFillAmounts Array of amounts of takerAsset that will be filled for each order.
|
||||
/// @return The indices of the first failed transfer (or 4 if all transfers are successful) for each order.
|
||||
function getSimulatedOrdersTransferResults(
|
||||
LibOrder.Order[] memory orders,
|
||||
address[] memory takerAddresses,
|
||||
uint256[] memory takerAssetFillAmounts
|
||||
)
|
||||
public
|
||||
returns (OrderTransferResults[] memory orderTransferResults)
|
||||
{
|
||||
uint256 length = orders.length;
|
||||
orderTransferResults = new OrderTransferResults[](length);
|
||||
for (uint256 i = 0; i != length; i++) {
|
||||
orderTransferResults[i] = getSimulatedOrderTransferResults(
|
||||
orders[i],
|
||||
takerAddresses[i],
|
||||
takerAssetFillAmounts[i]
|
||||
);
|
||||
}
|
||||
return orderTransferResults;
|
||||
}
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -23,25 +23,20 @@ import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
|
||||
import "./LibAssetData.sol";
|
||||
|
||||
|
||||
contract OrderValidationUtils is
|
||||
LibAssetData,
|
||||
LibMath
|
||||
LibAssetData
|
||||
{
|
||||
using LibBytes for bytes;
|
||||
using LibSafeMath for uint256;
|
||||
|
||||
// solhint-disable var-name-mixedcase
|
||||
bytes internal _ZRX_ASSET_DATA;
|
||||
// solhint-enable var-name-mixedcase
|
||||
|
||||
constructor (address _exchange, bytes memory _zrxAssetData)
|
||||
constructor (address _exchange)
|
||||
public
|
||||
LibAssetData(_exchange)
|
||||
{
|
||||
_ZRX_ASSET_DATA = _zrxAssetData;
|
||||
}
|
||||
{}
|
||||
|
||||
/// @dev Fetches all order-relevant information needed to validate if the supplied order is fillable.
|
||||
/// @param order The order structure.
|
||||
@@ -67,9 +62,8 @@ contract OrderValidationUtils is
|
||||
|
||||
// Validate the maker's signature
|
||||
address makerAddress = order.makerAddress;
|
||||
isValidSignature = _EXCHANGE.isValidSignature(
|
||||
orderInfo.orderHash,
|
||||
makerAddress,
|
||||
isValidSignature = _EXCHANGE.isValidOrderSignature(
|
||||
order,
|
||||
signature
|
||||
);
|
||||
|
||||
@@ -79,26 +73,22 @@ contract OrderValidationUtils is
|
||||
// Assign to stack variables to reduce redundant mloads/sloads
|
||||
uint256 takerAssetAmount = order.takerAssetAmount;
|
||||
uint256 makerFee = order.makerFee;
|
||||
bytes memory zrxAssetData = _ZRX_ASSET_DATA;
|
||||
|
||||
|
||||
// Get the amount of `takerAsset` that is transferable to maker given the transferability of `makerAsset`, `makerFeeAsset`,
|
||||
// and the total amounts specified in the order
|
||||
uint256 transferableTakerAssetAmount;
|
||||
if (order.makerAssetData.equals(zrxAssetData)) {
|
||||
if (order.makerAssetData.equals(order.makerFeeAssetData)) {
|
||||
// If `makerAsset` equals `makerFeeAsset`, the % that can be filled is
|
||||
// transferableMakerAssetAmount / (makerAssetAmount + makerFee)
|
||||
transferableTakerAssetAmount = getPartialAmountFloor(
|
||||
transferableTakerAssetAmount = LibMath.getPartialAmountFloor(
|
||||
transferableMakerAssetAmount,
|
||||
safeAdd(order.makerAssetAmount, makerFee),
|
||||
order.makerAssetAmount.safeAdd(makerFee),
|
||||
takerAssetAmount
|
||||
);
|
||||
} else {
|
||||
// Get the transferable amount of the `makerFeeAsset`
|
||||
uint256 transferableMakerFeeAssetAmount = getTransferableAssetAmount(makerAddress, zrxAssetData);
|
||||
|
||||
// If `makerFee` is 0, the % that can be filled is (transferableMakerAssetAmount / makerAssetAmount)
|
||||
if (makerFee == 0) {
|
||||
transferableTakerAssetAmount = getPartialAmountFloor(
|
||||
transferableTakerAssetAmount = LibMath.getPartialAmountFloor(
|
||||
transferableMakerAssetAmount,
|
||||
order.makerAssetAmount,
|
||||
takerAssetAmount
|
||||
@@ -107,23 +97,26 @@ contract OrderValidationUtils is
|
||||
// If `makerAsset` does not equal `makerFeeAsset`, the % that can be filled is the lower of
|
||||
// (transferableMakerAssetAmount / makerAssetAmount) and (transferableMakerAssetFeeAmount / makerFee)
|
||||
} else {
|
||||
uint256 transferableMakerToTakerAmount = getPartialAmountFloor(
|
||||
// Get the transferable amount of the `makerFeeAsset`
|
||||
uint256 transferableMakerFeeAssetAmount = getTransferableAssetAmount(makerAddress, order.makerFeeAssetData);
|
||||
|
||||
uint256 transferableMakerToTakerAmount = LibMath.getPartialAmountFloor(
|
||||
transferableMakerAssetAmount,
|
||||
order.makerAssetAmount,
|
||||
takerAssetAmount
|
||||
);
|
||||
uint256 transferableMakerFeeToTakerAmount = getPartialAmountFloor(
|
||||
uint256 transferableMakerFeeToTakerAmount = LibMath.getPartialAmountFloor(
|
||||
transferableMakerFeeAssetAmount,
|
||||
makerFee,
|
||||
takerAssetAmount
|
||||
);
|
||||
transferableTakerAssetAmount = min256(transferableMakerToTakerAmount, transferableMakerFeeToTakerAmount);
|
||||
transferableTakerAssetAmount = LibSafeMath.min256(transferableMakerToTakerAmount, transferableMakerFeeToTakerAmount);
|
||||
}
|
||||
}
|
||||
|
||||
// `fillableTakerAssetAmount` is the lower of the order's remaining `takerAssetAmount` and the `transferableTakerAssetAmount`
|
||||
fillableTakerAssetAmount = min256(
|
||||
safeSub(takerAssetAmount, orderInfo.orderTakerAssetFilledAmount),
|
||||
fillableTakerAssetAmount = LibSafeMath.min256(
|
||||
takerAssetAmount.safeSub(orderInfo.orderTakerAssetFilledAmount),
|
||||
transferableTakerAssetAmount
|
||||
);
|
||||
|
||||
@@ -170,7 +163,7 @@ contract OrderValidationUtils is
|
||||
/// @return The amount of the asset tranferable by the owner.
|
||||
/// NOTE: If the `assetData` encodes data for multiple assets, the `transferableAssetAmount`
|
||||
/// will represent the amount of times the entire `assetData` can be transferred. To calculate
|
||||
/// the total individual transferable amounts, this scaled `transferableAmount` must be multiplied by
|
||||
/// the total individual transferable amounts, this scaled `transferableAmount` must be multiplied by
|
||||
/// the individual asset amounts located within the `assetData`.
|
||||
function getTransferableAssetAmount(address ownerAddress, bytes memory assetData)
|
||||
public
|
||||
@@ -178,7 +171,7 @@ contract OrderValidationUtils is
|
||||
returns (uint256 transferableAssetAmount)
|
||||
{
|
||||
(uint256 balance, uint256 allowance) = getBalanceAndAssetProxyAllowance(ownerAddress, assetData);
|
||||
transferableAssetAmount = min256(balance, allowance);
|
||||
transferableAssetAmount = LibSafeMath.min256(balance, allowance);
|
||||
return transferableAssetAmount;
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-dev-utils",
|
||||
"version": "0.0.7",
|
||||
"version": "0.1.0-beta.0",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -12,17 +12,17 @@
|
||||
"scripts": {
|
||||
"build": "yarn pre_build && tsc -b",
|
||||
"build:ci": "yarn build",
|
||||
"pre_build": "run-s compile generate_contract_wrappers",
|
||||
"pre_build": "run-s compile quantify_bytecode contracts:gen generate_contract_wrappers",
|
||||
"test": "yarn run_mocha",
|
||||
"rebuild_and_test": "run-s build test",
|
||||
"test:coverage": "SOLIDITY_COVERAGE=true run-s build run_mocha coverage:report:text coverage:report:lcov",
|
||||
"test:profiler": "SOLIDITY_PROFILER=true run-s build run_mocha profiler:report:html",
|
||||
"test:trace": "SOLIDITY_REVERT_TRACE=true run-s build run_mocha",
|
||||
"run_mocha": "mocha --require source-map-support/register --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit",
|
||||
"run_mocha": "UNLIMITED_CONTRACT_SIZE=true mocha --require source-map-support/register --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit",
|
||||
"compile": "sol-compiler",
|
||||
"watch": "sol-compiler -w",
|
||||
"clean": "shx rm -rf lib generated-artifacts generated-wrappers",
|
||||
"generate_contract_wrappers": "abi-gen --abis ${npm_package_config_abis} --template ../../node_modules/@0x/abi-gen-templates/contract.handlebars --partials '../../node_modules/@0x/abi-gen-templates/partials/**/*.handlebars' --output generated-wrappers --backend ethers",
|
||||
"generate_contract_wrappers": "abi-gen --abis ${npm_package_config_abis} --output generated-wrappers --backend ethers",
|
||||
"lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
|
||||
"fix": "tslint --fix --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
|
||||
"coverage:report:text": "istanbul report text",
|
||||
@@ -31,10 +31,12 @@
|
||||
"coverage:report:lcov": "istanbul report lcov",
|
||||
"test:circleci": "yarn test",
|
||||
"contracts:gen": "contracts-gen",
|
||||
"lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol"
|
||||
"lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol",
|
||||
"quantify_bytecode": "echo EVM bytecode object lengths:;for i in ./generated-artifacts/*.json; do node -e \"console.log('$i\t' + (require('$i').compilerOutput.evm.bytecode.object.length - 2) / 2)\"; done",
|
||||
"compile:truffle": "truffle compile"
|
||||
},
|
||||
"config": {
|
||||
"abis": "./generated-artifacts/@(DevUtils|LibAssetData|LibTransactionDecoder|EthBalanceChecker).json",
|
||||
"abis": "./generated-artifacts/@(DevUtils|EthBalanceChecker|LibAssetData|LibTransactionDecoder|OrderTransferSimulationUtils|OrderValidationUtils).json",
|
||||
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually."
|
||||
},
|
||||
"repository": {
|
||||
@@ -47,11 +49,11 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/dev-utils/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^4.1.0",
|
||||
"@0x/contracts-gen": "^1.0.13",
|
||||
"@0x/contracts-test-utils": "^3.1.13",
|
||||
"@0x/dev-utils": "^2.3.0",
|
||||
"@0x/sol-compiler": "^3.1.12",
|
||||
"@0x/abi-gen": "^4.3.0-beta.0",
|
||||
"@0x/contracts-gen": "^1.1.0-beta.0",
|
||||
"@0x/contracts-test-utils": "^3.2.0-beta.0",
|
||||
"@0x/dev-utils": "^2.4.0-beta.0",
|
||||
"@0x/sol-compiler": "^3.2.0-beta.0",
|
||||
"@0x/tslint-config": "^3.0.1",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
@@ -65,24 +67,25 @@
|
||||
"npm-run-all": "^4.1.2",
|
||||
"shx": "^0.2.2",
|
||||
"solhint": "^1.4.1",
|
||||
"truffle": "^5.0.32",
|
||||
"tslint": "5.11.0",
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^5.3.1",
|
||||
"@0x/contracts-asset-proxy": "^2.2.5",
|
||||
"@0x/contracts-erc1155": "^1.1.12",
|
||||
"@0x/contracts-erc20": "^2.2.11",
|
||||
"@0x/contracts-erc721": "^2.1.12",
|
||||
"@0x/contracts-exchange": "^2.1.11",
|
||||
"@0x/contracts-exchange-libs": "^3.0.5",
|
||||
"@0x/contracts-utils": "^3.2.1",
|
||||
"@0x/order-utils": "^8.2.5",
|
||||
"@0x/types": "^2.4.1",
|
||||
"@0x/typescript-typings": "^4.2.4",
|
||||
"@0x/utils": "^4.5.0",
|
||||
"@0x/web3-wrapper": "^6.0.10",
|
||||
"ethereum-types": "^2.1.4",
|
||||
"@0x/base-contract": "^5.5.0-beta.0",
|
||||
"@0x/contracts-asset-proxy": "^2.3.0-beta.0",
|
||||
"@0x/contracts-erc1155": "^1.2.0-beta.0",
|
||||
"@0x/contracts-erc20": "^2.3.0-beta.0",
|
||||
"@0x/contracts-erc721": "^2.2.0-beta.0",
|
||||
"@0x/contracts-exchange": "^2.2.0-beta.0",
|
||||
"@0x/contracts-exchange-libs": "^3.1.0-beta.0",
|
||||
"@0x/contracts-utils": "^3.3.0-beta.0",
|
||||
"@0x/order-utils": "^8.5.0-beta.0",
|
||||
"@0x/types": "^2.5.0-beta.0",
|
||||
"@0x/typescript-typings": "^4.4.0-beta.0",
|
||||
"@0x/utils": "^4.6.0-beta.0",
|
||||
"@0x/web3-wrapper": "^6.1.0-beta.0",
|
||||
"ethereum-types": "^2.2.0-beta.0",
|
||||
"ethereumjs-util": "^5.1.1"
|
||||
},
|
||||
"publishConfig": {
|
||||
|
@@ -6,10 +6,16 @@
|
||||
import { ContractArtifact } from 'ethereum-types';
|
||||
|
||||
import * as DevUtils from '../generated-artifacts/DevUtils.json';
|
||||
import * as EthBalanceChecker from '../generated-artifacts/EthBalanceChecker.json';
|
||||
import * as LibAssetData from '../generated-artifacts/LibAssetData.json';
|
||||
import * as LibTransactionDecoder from '../generated-artifacts/LibTransactionDecoder.json';
|
||||
import * as OrderTransferSimulationUtils from '../generated-artifacts/OrderTransferSimulationUtils.json';
|
||||
import * as OrderValidationUtils from '../generated-artifacts/OrderValidationUtils.json';
|
||||
export const artifacts = {
|
||||
DevUtils: DevUtils as ContractArtifact,
|
||||
LibTransactionDecoder: LibTransactionDecoder as ContractArtifact,
|
||||
EthBalanceChecker: EthBalanceChecker as ContractArtifact,
|
||||
LibAssetData: LibAssetData as ContractArtifact,
|
||||
LibTransactionDecoder: LibTransactionDecoder as ContractArtifact,
|
||||
OrderTransferSimulationUtils: OrderTransferSimulationUtils as ContractArtifact,
|
||||
OrderValidationUtils: OrderValidationUtils as ContractArtifact,
|
||||
};
|
||||
|
@@ -4,5 +4,8 @@
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
export * from '../generated-wrappers/dev_utils';
|
||||
export * from '../generated-wrappers/eth_balance_checker';
|
||||
export * from '../generated-wrappers/lib_asset_data';
|
||||
export * from '../generated-wrappers/lib_transaction_decoder';
|
||||
export * from '../generated-wrappers/order_transfer_simulation_utils';
|
||||
export * from '../generated-wrappers/order_validation_utils';
|
||||
|
@@ -22,7 +22,7 @@ import { chaiSetup, constants, LogDecoder, provider, txDefaults, web3Wrapper } f
|
||||
import { BlockchainLifecycle } from '@0x/dev-utils';
|
||||
import { assetDataUtils } from '@0x/order-utils';
|
||||
import { AssetProxyId } from '@0x/types';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import { BigNumber, providerUtils } from '@0x/utils';
|
||||
import * as ethUtil from 'ethereumjs-util';
|
||||
|
||||
import { artifacts, LibAssetDataContract } from '../src';
|
||||
@@ -87,13 +87,13 @@ describe('LibAssetData', () => {
|
||||
|
||||
before(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
|
||||
const chainId = await providerUtils.getChainIdAsync(provider);
|
||||
exchange = await ExchangeContract.deployFrom0xArtifactAsync(
|
||||
exchangeArtifacts.Exchange,
|
||||
provider,
|
||||
txDefaults,
|
||||
artifacts,
|
||||
constants.NULL_BYTES,
|
||||
{},
|
||||
new BigNumber(chainId),
|
||||
);
|
||||
|
||||
erc20Proxy = await ERC20ProxyContract.deployFrom0xArtifactAsync(
|
||||
@@ -476,20 +476,6 @@ describe('LibAssetData', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('getERC721TokenOwner', async () => {
|
||||
it('should return the null address when tokenId is not owned', async () => {
|
||||
const nonexistentTokenId = new BigNumber(1234567890);
|
||||
expect(
|
||||
await libAssetData.getERC721TokenOwner.callAsync(erc721Token.address, nonexistentTokenId),
|
||||
).to.be.equal(constants.NULL_ADDRESS);
|
||||
});
|
||||
it('should return the owner address when tokenId is owned', async () => {
|
||||
expect(
|
||||
await libAssetData.getERC721TokenOwner.callAsync(erc721Token.address, firstERC721TokenId),
|
||||
).to.be.equal(tokenOwnerAddress);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getBalanceAndAllowance', () => {
|
||||
it('should query balance and allowance together, from asset data', async () => {
|
||||
const allowance = new BigNumber(1);
|
||||
|
@@ -23,6 +23,8 @@ const order = {
|
||||
salt: new BigNumber('66097384406870180066678463045003379626790660770396923976862707230261946348951'),
|
||||
makerAssetData: '0xf47261b000000000000000000000000034d402f14d58e001d8efbe6585051bf9706aa064',
|
||||
takerAssetData: '0xf47261b000000000000000000000000025b8fe1de9daf8ba351890744ff28cf7dfa8f5e3',
|
||||
makerFeeAssetData: '0xf47261b000000000000000000000000034d402f14d58e001d8efbe6585051bf9706aa064',
|
||||
takerFeeAssetData: '0xf47261b000000000000000000000000025b8fe1de9daf8ba351890744ff28cf7dfa8f5e3',
|
||||
};
|
||||
const takerAssetFillAmount = new BigNumber('100000000000000000000');
|
||||
const signature =
|
||||
@@ -80,7 +82,7 @@ describe('LibTransactionDecoder', () => {
|
||||
]);
|
||||
});
|
||||
|
||||
for (const func of ['fillOrder', 'fillOrderNoThrow', 'fillOrKillOrder']) {
|
||||
for (const func of ['fillOrder', 'fillOrKillOrder']) {
|
||||
const input = (exchangeInterface as any)[func].getABIEncodedTransactionData(
|
||||
order,
|
||||
takerAssetFillAmount,
|
||||
@@ -96,7 +98,12 @@ describe('LibTransactionDecoder', () => {
|
||||
});
|
||||
}
|
||||
|
||||
for (const func of ['marketBuyOrders', 'marketBuyOrdersNoThrow', 'marketSellOrders', 'marketSellOrdersNoThrow']) {
|
||||
for (const func of [
|
||||
'marketBuyOrdersNoThrow',
|
||||
'marketSellOrdersNoThrow',
|
||||
'marketBuyOrdersFillOrKill',
|
||||
'marketSellOrdersFillOrKill',
|
||||
]) {
|
||||
const input = (exchangeInterface as any)[func].getABIEncodedTransactionData(
|
||||
[order, order],
|
||||
takerAssetFillAmount,
|
||||
@@ -123,6 +130,8 @@ describe('LibTransactionDecoder', () => {
|
||||
takerAssetAmount: order.makerAssetAmount,
|
||||
makerFee: order.takerFee,
|
||||
takerFee: order.makerFee,
|
||||
makerFeeAssetData: order.takerFeeAssetData,
|
||||
takerFeeAssetData: order.makerFeeAssetData,
|
||||
};
|
||||
const input = exchangeInterface.matchOrders.getABIEncodedTransactionData(
|
||||
order,
|
||||
|
@@ -20,8 +20,8 @@ import {
|
||||
} from '@0x/contracts-test-utils';
|
||||
import { BlockchainLifecycle } from '@0x/dev-utils';
|
||||
import { assetDataUtils, orderHashUtils } from '@0x/order-utils';
|
||||
import { SignedOrder } from '@0x/types';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import { OrderTransferResults, SignedOrder } from '@0x/types';
|
||||
import { BigNumber, providerUtils } from '@0x/utils';
|
||||
import * as chai from 'chai';
|
||||
|
||||
import { artifacts, DevUtilsContract } from '../src';
|
||||
@@ -30,18 +30,18 @@ chaiSetup.configure();
|
||||
const expect = chai.expect;
|
||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||
|
||||
describe('OrderValidationUtils', () => {
|
||||
describe('OrderValidationUtils/OrderTransferSimulatorUtils', () => {
|
||||
let makerAddress: string;
|
||||
let takerAddress: string;
|
||||
let owner: string;
|
||||
let erc20AssetData: string;
|
||||
let erc20AssetData2: string;
|
||||
let erc721AssetData: string;
|
||||
let zrxAssetData: string;
|
||||
let feeAssetData: string;
|
||||
|
||||
let erc20Token: DummyERC20TokenContract;
|
||||
let erc20Token2: DummyERC20TokenContract;
|
||||
let zrxToken: DummyERC20TokenContract;
|
||||
let feeErc20Token: DummyERC20TokenContract;
|
||||
let erc721Token: DummyERC721TokenContract;
|
||||
let exchange: ExchangeContract;
|
||||
let devUtils: DevUtilsContract;
|
||||
@@ -64,12 +64,13 @@ describe('OrderValidationUtils', () => {
|
||||
before(async () => {
|
||||
const accounts = await web3Wrapper.getAvailableAddressesAsync();
|
||||
const usedAddresses = ([owner, makerAddress, takerAddress] = accounts.slice(0, 3));
|
||||
const chainId = await providerUtils.getChainIdAsync(provider);
|
||||
|
||||
const erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner);
|
||||
const erc721Wrapper = new ERC721Wrapper(provider, usedAddresses, owner);
|
||||
|
||||
const numDummyErc20ToDeploy = 3;
|
||||
[erc20Token, zrxToken, erc20Token2] = await erc20Wrapper.deployDummyTokensAsync(
|
||||
[erc20Token, erc20Token2, feeErc20Token] = await erc20Wrapper.deployDummyTokensAsync(
|
||||
numDummyErc20ToDeploy,
|
||||
constants.DUMMY_TOKEN_DECIMALS,
|
||||
);
|
||||
@@ -78,13 +79,13 @@ describe('OrderValidationUtils', () => {
|
||||
[erc721Token] = await erc721Wrapper.deployDummyTokensAsync();
|
||||
erc721Proxy = await erc721Wrapper.deployProxyAsync();
|
||||
|
||||
zrxAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
|
||||
feeAssetData = assetDataUtils.encodeERC20AssetData(feeErc20Token.address);
|
||||
exchange = await ExchangeContract.deployFrom0xArtifactAsync(
|
||||
exchangeArtifacts.Exchange,
|
||||
provider,
|
||||
txDefaults,
|
||||
artifacts,
|
||||
zrxAssetData,
|
||||
{},
|
||||
new BigNumber(chainId),
|
||||
);
|
||||
|
||||
multiAssetProxy = await MultiAssetProxyContract.deployFrom0xArtifactAsync(
|
||||
@@ -93,7 +94,7 @@ describe('OrderValidationUtils', () => {
|
||||
txDefaults,
|
||||
artifacts,
|
||||
);
|
||||
const exchangeWrapper = new ExchangeWrapper(exchange, provider);
|
||||
const exchangeWrapper = new ExchangeWrapper(exchange);
|
||||
await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner);
|
||||
await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.address, owner);
|
||||
await exchangeWrapper.registerAssetProxyAsync(multiAssetProxy.address, owner);
|
||||
@@ -106,7 +107,6 @@ describe('OrderValidationUtils', () => {
|
||||
txDefaults,
|
||||
artifacts,
|
||||
exchange.address,
|
||||
zrxAssetData,
|
||||
);
|
||||
|
||||
erc20AssetData = assetDataUtils.encodeERC20AssetData(erc20Token.address);
|
||||
@@ -114,11 +114,14 @@ describe('OrderValidationUtils', () => {
|
||||
erc721AssetData = assetDataUtils.encodeERC721AssetData(erc721Token.address, tokenId);
|
||||
const defaultOrderParams = {
|
||||
...constants.STATIC_ORDER_PARAMS,
|
||||
exchangeAddress: exchange.address,
|
||||
makerAddress,
|
||||
feeRecipientAddress: constants.NULL_ADDRESS,
|
||||
makerAssetData: erc20AssetData,
|
||||
takerAssetData: erc20AssetData2,
|
||||
makerFeeAssetData: feeAssetData,
|
||||
takerFeeAssetData: feeAssetData,
|
||||
exchangeAddress: exchange.address,
|
||||
chainId,
|
||||
};
|
||||
const privateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)];
|
||||
orderFactory = new OrderFactory(privateKey, defaultOrderParams);
|
||||
@@ -245,11 +248,11 @@ describe('OrderValidationUtils', () => {
|
||||
from: makerAddress,
|
||||
});
|
||||
const divisor = 4;
|
||||
await zrxToken.setBalance.awaitTransactionSuccessAsync(
|
||||
await feeErc20Token.setBalance.awaitTransactionSuccessAsync(
|
||||
makerAddress,
|
||||
signedOrder.makerFee.dividedToIntegerBy(divisor),
|
||||
);
|
||||
await zrxToken.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerFee, {
|
||||
await feeErc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerFee, {
|
||||
from: makerAddress,
|
||||
});
|
||||
const [, fillableTakerAssetAmount] = await devUtils.getOrderRelevantState.callAsync(
|
||||
@@ -269,8 +272,8 @@ describe('OrderValidationUtils', () => {
|
||||
await erc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerAssetAmount, {
|
||||
from: makerAddress,
|
||||
});
|
||||
await zrxToken.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerFee);
|
||||
await zrxToken.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerFee, {
|
||||
await feeErc20Token.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerFee);
|
||||
await feeErc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerFee, {
|
||||
from: makerAddress,
|
||||
});
|
||||
const [, fillableTakerAssetAmount] = await devUtils.getOrderRelevantState.callAsync(
|
||||
@@ -291,8 +294,8 @@ describe('OrderValidationUtils', () => {
|
||||
await erc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerAssetAmount, {
|
||||
from: makerAddress,
|
||||
});
|
||||
await zrxToken.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerFee);
|
||||
await zrxToken.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerFee, {
|
||||
await feeErc20Token.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerFee);
|
||||
await feeErc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerFee, {
|
||||
from: makerAddress,
|
||||
});
|
||||
const divisor = 4;
|
||||
@@ -316,8 +319,8 @@ describe('OrderValidationUtils', () => {
|
||||
);
|
||||
});
|
||||
it('should return a fillableTakerAssetAmount of 0 when non-fee balances/allowances are insufficient', async () => {
|
||||
await zrxToken.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerFee);
|
||||
await zrxToken.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerFee, {
|
||||
await feeErc20Token.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerFee);
|
||||
await feeErc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerFee, {
|
||||
from: makerAddress,
|
||||
});
|
||||
const [, fillableTakerAssetAmount] = await devUtils.getOrderRelevantState.callAsync(
|
||||
@@ -331,8 +334,8 @@ describe('OrderValidationUtils', () => {
|
||||
await erc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerAssetAmount, {
|
||||
from: makerAddress,
|
||||
});
|
||||
await zrxToken.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerFee);
|
||||
await zrxToken.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerFee, {
|
||||
await feeErc20Token.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerFee);
|
||||
await feeErc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerFee, {
|
||||
from: makerAddress,
|
||||
});
|
||||
const [, fillableTakerAssetAmount] = await devUtils.getOrderRelevantState.callAsync(
|
||||
@@ -343,14 +346,14 @@ describe('OrderValidationUtils', () => {
|
||||
});
|
||||
it('should return the correct fillableTakerAssetAmount when balances/allowances are partially sufficient and makerAsset=makerFeeAsset', async () => {
|
||||
signedOrder = await orderFactory.newSignedOrderAsync({
|
||||
makerAssetData: zrxAssetData,
|
||||
makerAssetData: feeAssetData,
|
||||
makerAssetAmount: new BigNumber(10),
|
||||
takerAssetAmount: new BigNumber(20),
|
||||
makerFee: new BigNumber(40),
|
||||
});
|
||||
const transferableMakerAssetAmount = new BigNumber(10);
|
||||
await zrxToken.setBalance.awaitTransactionSuccessAsync(makerAddress, transferableMakerAssetAmount);
|
||||
await zrxToken.approve.awaitTransactionSuccessAsync(erc20Proxy.address, transferableMakerAssetAmount, {
|
||||
await feeErc20Token.setBalance.awaitTransactionSuccessAsync(makerAddress, transferableMakerAssetAmount);
|
||||
await feeErc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, transferableMakerAssetAmount, {
|
||||
from: makerAddress,
|
||||
});
|
||||
const expectedFillableTakerAssetAmount = transferableMakerAssetAmount
|
||||
@@ -379,17 +382,17 @@ describe('OrderValidationUtils', () => {
|
||||
await erc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerAssetAmount, {
|
||||
from: makerAddress,
|
||||
});
|
||||
await zrxToken.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerFee);
|
||||
await zrxToken.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerFee, {
|
||||
await feeErc20Token.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerFee);
|
||||
await feeErc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerFee, {
|
||||
from: makerAddress,
|
||||
});
|
||||
await erc20Token2.setBalance.awaitTransactionSuccessAsync(takerAddress, signedOrder.takerAssetAmount);
|
||||
await erc20Token2.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.takerAssetAmount, {
|
||||
from: takerAddress,
|
||||
});
|
||||
await zrxToken.setBalance.awaitTransactionSuccessAsync(takerAddress, signedOrder.takerFee);
|
||||
await feeErc20Token.setBalance.awaitTransactionSuccessAsync(takerAddress, signedOrder.takerFee);
|
||||
|
||||
await zrxToken.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.takerFee, {
|
||||
await feeErc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.takerFee, {
|
||||
from: takerAddress,
|
||||
});
|
||||
const takerAssetFillAmount = signedOrder.takerAssetAmount.dividedToIntegerBy(4);
|
||||
@@ -407,15 +410,38 @@ describe('OrderValidationUtils', () => {
|
||||
signedOrder.takerAssetAmount.minus(takerAssetFillAmount),
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('getOrderRelevantStates', async () => {
|
||||
it('should return the correct information for multiple orders', async () => {
|
||||
it('should return correct info even when there are no fees specified', async () => {
|
||||
signedOrder = await orderFactory.newSignedOrderAsync({
|
||||
makerFee: new BigNumber(0),
|
||||
takerFee: new BigNumber(0),
|
||||
makerFeeAssetData: '0x',
|
||||
takerFeeAssetData: '0x',
|
||||
});
|
||||
await erc20Token.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerAssetAmount);
|
||||
await erc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerAssetAmount, {
|
||||
from: makerAddress,
|
||||
});
|
||||
await zrxToken.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerFee);
|
||||
await zrxToken.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerFee, {
|
||||
const [
|
||||
orderInfo,
|
||||
fillableTakerAssetAmount,
|
||||
isValidSignature,
|
||||
] = await devUtils.getOrderRelevantState.callAsync(signedOrder, signedOrder.signature);
|
||||
expect(orderInfo.orderHash).to.equal(orderHashUtils.getOrderHashHex(signedOrder));
|
||||
expect(orderInfo.orderStatus).to.equal(OrderStatus.Fillable);
|
||||
expect(orderInfo.orderTakerAssetFilledAmount).to.bignumber.equal(constants.ZERO_AMOUNT);
|
||||
expect(fillableTakerAssetAmount).to.bignumber.equal(signedOrder.takerAssetAmount);
|
||||
expect(isValidSignature).to.equal(true);
|
||||
});
|
||||
});
|
||||
describe('getOrderRelevantStates', async () => {
|
||||
it('should return the correct information for multiple orders', async () => {
|
||||
signedOrder = await orderFactory.newSignedOrderAsync();
|
||||
await erc20Token.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerAssetAmount);
|
||||
await erc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerAssetAmount, {
|
||||
from: makerAddress,
|
||||
});
|
||||
await feeErc20Token.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerFee);
|
||||
await feeErc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerFee, {
|
||||
from: makerAddress,
|
||||
});
|
||||
const signedOrder2 = await orderFactory.newSignedOrderAsync({ makerAssetData: erc721AssetData });
|
||||
@@ -441,5 +467,185 @@ describe('OrderValidationUtils', () => {
|
||||
expect(isValidSignature[1]).to.equal(false);
|
||||
});
|
||||
});
|
||||
describe('getSimulatedOrderTransferResults', () => {
|
||||
beforeEach(async () => {
|
||||
signedOrder = await orderFactory.newSignedOrderAsync();
|
||||
});
|
||||
it('should return TakerAssetDataFailed if the takerAsset transfer fails', async () => {
|
||||
const orderTransferResults = await devUtils.getSimulatedOrderTransferResults.callAsync(
|
||||
signedOrder,
|
||||
takerAddress,
|
||||
signedOrder.takerAssetAmount,
|
||||
);
|
||||
expect(orderTransferResults).to.equal(OrderTransferResults.TakerAssetDataFailed);
|
||||
});
|
||||
it('should return MakerAssetDataFailed if the makerAsset transfer fails', async () => {
|
||||
await erc20Token2.setBalance.awaitTransactionSuccessAsync(takerAddress, signedOrder.takerAssetAmount, {
|
||||
from: owner,
|
||||
});
|
||||
await erc20Token2.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.takerAssetAmount, {
|
||||
from: takerAddress,
|
||||
});
|
||||
const orderTransferResults = await devUtils.getSimulatedOrderTransferResults.callAsync(
|
||||
signedOrder,
|
||||
takerAddress,
|
||||
signedOrder.takerAssetAmount,
|
||||
);
|
||||
expect(orderTransferResults).to.equal(OrderTransferResults.MakerAssetDataFailed);
|
||||
});
|
||||
it('should return TakerFeeAssetDataFailed if the takerFeeAsset transfer fails', async () => {
|
||||
await erc20Token2.setBalance.awaitTransactionSuccessAsync(takerAddress, signedOrder.takerAssetAmount, {
|
||||
from: owner,
|
||||
});
|
||||
await erc20Token2.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.takerAssetAmount, {
|
||||
from: takerAddress,
|
||||
});
|
||||
await erc20Token.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerAssetAmount, {
|
||||
from: owner,
|
||||
});
|
||||
await erc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerAssetAmount, {
|
||||
from: makerAddress,
|
||||
});
|
||||
const orderTransferResults = await devUtils.getSimulatedOrderTransferResults.callAsync(
|
||||
signedOrder,
|
||||
takerAddress,
|
||||
signedOrder.takerAssetAmount,
|
||||
);
|
||||
expect(orderTransferResults).to.equal(OrderTransferResults.TakerFeeAssetDataFailed);
|
||||
});
|
||||
it('should return MakerFeeAssetDataFailed if the makerFeeAsset transfer fails', async () => {
|
||||
await erc20Token2.setBalance.awaitTransactionSuccessAsync(takerAddress, signedOrder.takerAssetAmount, {
|
||||
from: owner,
|
||||
});
|
||||
await erc20Token2.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.takerAssetAmount, {
|
||||
from: takerAddress,
|
||||
});
|
||||
await erc20Token.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerAssetAmount, {
|
||||
from: owner,
|
||||
});
|
||||
await erc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerAssetAmount, {
|
||||
from: makerAddress,
|
||||
});
|
||||
await feeErc20Token.setBalance.awaitTransactionSuccessAsync(takerAddress, signedOrder.takerFee, {
|
||||
from: owner,
|
||||
});
|
||||
await feeErc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.takerFee, {
|
||||
from: takerAddress,
|
||||
});
|
||||
const orderTransferResults = await devUtils.getSimulatedOrderTransferResults.callAsync(
|
||||
signedOrder,
|
||||
takerAddress,
|
||||
signedOrder.takerAssetAmount,
|
||||
);
|
||||
expect(orderTransferResults).to.equal(OrderTransferResults.MakerFeeAssetDataFailed);
|
||||
});
|
||||
it('should return TransfersSuccessful if all transfers succeed', async () => {
|
||||
await erc20Token2.setBalance.awaitTransactionSuccessAsync(takerAddress, signedOrder.takerAssetAmount, {
|
||||
from: owner,
|
||||
});
|
||||
await erc20Token2.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.takerAssetAmount, {
|
||||
from: takerAddress,
|
||||
});
|
||||
await erc20Token.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerAssetAmount, {
|
||||
from: owner,
|
||||
});
|
||||
await erc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerAssetAmount, {
|
||||
from: makerAddress,
|
||||
});
|
||||
await feeErc20Token.setBalance.awaitTransactionSuccessAsync(takerAddress, signedOrder.takerFee, {
|
||||
from: owner,
|
||||
});
|
||||
await feeErc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.takerFee, {
|
||||
from: takerAddress,
|
||||
});
|
||||
await feeErc20Token.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerFee, {
|
||||
from: owner,
|
||||
});
|
||||
await feeErc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerFee, {
|
||||
from: makerAddress,
|
||||
});
|
||||
const orderTransferResults = await devUtils.getSimulatedOrderTransferResults.callAsync(
|
||||
signedOrder,
|
||||
takerAddress,
|
||||
signedOrder.takerAssetAmount,
|
||||
);
|
||||
expect(orderTransferResults).to.equal(OrderTransferResults.TransfersSuccessful);
|
||||
});
|
||||
it('should return TransfersSuccessful for a partial fill when taker has ample assets for the fill but not for the whole order', async () => {
|
||||
await erc20Token2.setBalance.awaitTransactionSuccessAsync(
|
||||
takerAddress,
|
||||
signedOrder.takerAssetAmount.dividedBy(2),
|
||||
{
|
||||
from: owner,
|
||||
},
|
||||
);
|
||||
await erc20Token2.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.takerAssetAmount, {
|
||||
from: takerAddress,
|
||||
});
|
||||
await erc20Token.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerAssetAmount, {
|
||||
from: owner,
|
||||
});
|
||||
await erc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerAssetAmount, {
|
||||
from: makerAddress,
|
||||
});
|
||||
await feeErc20Token.setBalance.awaitTransactionSuccessAsync(takerAddress, signedOrder.takerFee, {
|
||||
from: owner,
|
||||
});
|
||||
await feeErc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.takerFee, {
|
||||
from: takerAddress,
|
||||
});
|
||||
await feeErc20Token.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerFee, {
|
||||
from: owner,
|
||||
});
|
||||
await feeErc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerFee, {
|
||||
from: makerAddress,
|
||||
});
|
||||
const orderTransferResults = await devUtils.getSimulatedOrderTransferResults.callAsync(
|
||||
signedOrder,
|
||||
takerAddress,
|
||||
signedOrder.takerAssetAmount.dividedBy(2),
|
||||
);
|
||||
expect(orderTransferResults).to.equal(OrderTransferResults.TransfersSuccessful);
|
||||
});
|
||||
});
|
||||
describe('getSimulatedOrdersTransferResults', async () => {
|
||||
it('should simulate the transfers of each order independently from one another', async () => {
|
||||
// Set balances and allowances to exactly enough to fill a single order
|
||||
await erc20Token2.setBalance.awaitTransactionSuccessAsync(takerAddress, signedOrder.takerAssetAmount, {
|
||||
from: owner,
|
||||
});
|
||||
await erc20Token2.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.takerAssetAmount, {
|
||||
from: takerAddress,
|
||||
});
|
||||
await erc20Token.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerAssetAmount, {
|
||||
from: owner,
|
||||
});
|
||||
await erc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerAssetAmount, {
|
||||
from: makerAddress,
|
||||
});
|
||||
await feeErc20Token.setBalance.awaitTransactionSuccessAsync(takerAddress, signedOrder.takerFee, {
|
||||
from: owner,
|
||||
});
|
||||
await feeErc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.takerFee, {
|
||||
from: takerAddress,
|
||||
});
|
||||
await feeErc20Token.setBalance.awaitTransactionSuccessAsync(makerAddress, signedOrder.makerFee, {
|
||||
from: owner,
|
||||
});
|
||||
await feeErc20Token.approve.awaitTransactionSuccessAsync(erc20Proxy.address, signedOrder.makerFee, {
|
||||
from: makerAddress,
|
||||
});
|
||||
const [
|
||||
orderTransferResults1,
|
||||
orderTransferResults2,
|
||||
] = await devUtils.getSimulatedOrdersTransferResults.callAsync(
|
||||
[signedOrder, signedOrder],
|
||||
[takerAddress, takerAddress],
|
||||
[signedOrder.takerAssetAmount, signedOrder.takerAssetAmount],
|
||||
);
|
||||
expect(orderTransferResults1).to.equal(OrderTransferResults.TransfersSuccessful);
|
||||
expect(orderTransferResults2).to.equal(OrderTransferResults.TransfersSuccessful);
|
||||
});
|
||||
});
|
||||
});
|
||||
// tslint:disable:max-file-line-count
|
||||
|
96
contracts/dev-utils/truffle-config.js
Normal file
96
contracts/dev-utils/truffle-config.js
Normal file
@@ -0,0 +1,96 @@
|
||||
/**
|
||||
* Use this file to configure your truffle project. It's seeded with some
|
||||
* common settings for different networks and features like migrations,
|
||||
* compilation and testing. Uncomment the ones you need or modify
|
||||
* them to suit your project as necessary.
|
||||
*
|
||||
* More information about configuration can be found at:
|
||||
*
|
||||
* truffleframework.com/docs/advanced/configuration
|
||||
*
|
||||
* To deploy via Infura you'll need a wallet provider (like truffle-hdwallet-provider)
|
||||
* to sign your transactions before they're sent to a remote public node. Infura accounts
|
||||
* are available for free at: infura.io/register.
|
||||
*
|
||||
* You'll also need a mnemonic - the twelve word phrase the wallet uses to generate
|
||||
* public/private key pairs. If you're publishing your code to GitHub make sure you load this
|
||||
* phrase from a file you've .gitignored so it doesn't accidentally become public.
|
||||
*
|
||||
*/
|
||||
|
||||
// const HDWalletProvider = require('truffle-hdwallet-provider');
|
||||
// const infuraKey = "fj4jll3k.....";
|
||||
//
|
||||
// const fs = require('fs');
|
||||
// const mnemonic = fs.readFileSync(".secret").toString().trim();
|
||||
|
||||
module.exports = {
|
||||
/**
|
||||
* Networks define how you connect to your ethereum client and let you set the
|
||||
* defaults web3 uses to send transactions. If you don't specify one truffle
|
||||
* will spin up a development blockchain for you on port 9545 when you
|
||||
* run `develop` or `test`. You can ask a truffle command to use a specific
|
||||
* network from the command line, e.g
|
||||
*
|
||||
* $ truffle test --network <network-name>
|
||||
*/
|
||||
|
||||
networks: {
|
||||
// Useful for testing. The `development` name is special - truffle uses it by default
|
||||
// if it's defined here and no other network is specified at the command line.
|
||||
// You should run a client (like ganache-cli, geth or parity) in a separate terminal
|
||||
// tab if you use this network and you must also set the `host`, `port` and `network_id`
|
||||
// options below to some value.
|
||||
//
|
||||
// development: {
|
||||
// host: "127.0.0.1", // Localhost (default: none)
|
||||
// port: 8545, // Standard Ethereum port (default: none)
|
||||
// network_id: "*", // Any network (default: none)
|
||||
// },
|
||||
// Another network with more advanced options...
|
||||
// advanced: {
|
||||
// port: 8777, // Custom port
|
||||
// network_id: 1342, // Custom network
|
||||
// gas: 8500000, // Gas sent with each transaction (default: ~6700000)
|
||||
// gasPrice: 20000000000, // 20 gwei (in wei) (default: 100 gwei)
|
||||
// from: <address>, // Account to send txs from (default: accounts[0])
|
||||
// websockets: true // Enable EventEmitter interface for web3 (default: false)
|
||||
// },
|
||||
// Useful for deploying to a public network.
|
||||
// NB: It's important to wrap the provider as a function.
|
||||
// ropsten: {
|
||||
// provider: () => new HDWalletProvider(mnemonic, `https://ropsten.infura.io/v3/YOUR-PROJECT-ID`),
|
||||
// network_id: 3, // Ropsten's id
|
||||
// gas: 5500000, // Ropsten has a lower block limit than mainnet
|
||||
// confirmations: 2, // # of confs to wait between deployments. (default: 0)
|
||||
// timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50)
|
||||
// skipDryRun: true // Skip dry run before migrations? (default: false for public nets )
|
||||
// },
|
||||
// Useful for private networks
|
||||
// private: {
|
||||
// provider: () => new HDWalletProvider(mnemonic, `https://network.io`),
|
||||
// network_id: 2111, // This network is yours, in the cloud.
|
||||
// production: true // Treats this network as if it was a public net. (default: false)
|
||||
// }
|
||||
},
|
||||
|
||||
// Set default mocha options here, use special reporters etc.
|
||||
mocha: {
|
||||
// timeout: 100000
|
||||
},
|
||||
|
||||
// Configure your compilers
|
||||
compilers: {
|
||||
solc: {
|
||||
version: '0.5.9',
|
||||
settings: {
|
||||
evmVersion: 'constantinople',
|
||||
optimizer: {
|
||||
enabled: true,
|
||||
runs: 1000000,
|
||||
details: { yul: true, deduplicate: true, cse: true, constantOptimizer: true },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
@@ -4,9 +4,11 @@
|
||||
"include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
|
||||
"files": [
|
||||
"generated-artifacts/DevUtils.json",
|
||||
"generated-artifacts/EthBalanceChecker.json",
|
||||
"generated-artifacts/LibAssetData.json",
|
||||
"generated-artifacts/LibTransactionDecoder.json",
|
||||
"generated-artifacts/EthBalanceChecker.json"
|
||||
"generated-artifacts/OrderTransferSimulationUtils.json",
|
||||
"generated-artifacts/OrderValidationUtils.json"
|
||||
],
|
||||
"exclude": ["./deploy/solc/solc_bin"]
|
||||
}
|
||||
|
@@ -1,4 +1,41 @@
|
||||
[
|
||||
{
|
||||
"version": "1.2.0-beta.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Add `mintKnownFungibleTokensAsync()`, `isNonFungibleItemAsync()`, `isFungibleItemAsync()`, `getOwnerOfAsync()`, `getBalanceAsync()` to `Erc1155Wrapper`.",
|
||||
"pr": 1819
|
||||
}
|
||||
],
|
||||
"timestamp": 1570135330
|
||||
},
|
||||
{
|
||||
"timestamp": 1568744790,
|
||||
"version": "1.1.15",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1567521715,
|
||||
"version": "1.1.14",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1566446343,
|
||||
"version": "1.1.13",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1565296576,
|
||||
"version": "1.1.12",
|
||||
|
@@ -5,6 +5,22 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v1.2.0-beta.0 - _October 3, 2019_
|
||||
|
||||
* Add `mintKnownFungibleTokensAsync()`, `isNonFungibleItemAsync()`, `isFungibleItemAsync()`, `getOwnerOfAsync()`, `getBalanceAsync()` to `Erc1155Wrapper`. (#1819)
|
||||
|
||||
## v1.1.15 - _September 17, 2019_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.1.14 - _September 3, 2019_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.1.13 - _August 22, 2019_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.1.12 - _August 8, 2019_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
## ERC1155 Tokens
|
||||
|
||||
This package contains implementations of various [ERC1155](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1155.md) tokens. Addresses of the deployed contracts can be found in the 0x [wiki](https://0xproject.com/wiki#Deployed-Addresses) or the [DEPLOYS](./DEPLOYS.json) file within this package.
|
||||
This package contains implementations of various [ERC1155](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1155.md) tokens. 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
|
||||
|
||||
@@ -12,7 +12,7 @@ npm install @0x/contracts-erc1155 --save
|
||||
|
||||
## Bug bounty
|
||||
|
||||
A bug bounty for the 2.0.0 contracts is ongoing! Instructions can be found [here](https://0xproject.com/wiki#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
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user