Compare commits
946 Commits
@0xproject
...
@0xproject
Author | SHA1 | Date | |
---|---|---|---|
|
0bfcf79e79 | ||
|
49f5495c45 | ||
|
9e431df848 | ||
|
12476c52a4 | ||
|
8fd9aebcb9 | ||
|
8c83f4ba3b | ||
|
25b6d1a232 | ||
|
880cbd88c2 | ||
|
dcd53c3c5b | ||
|
3e64b3da39 | ||
|
9a748c8bf1 | ||
|
53eae14763 | ||
|
074c42e8b6 | ||
|
8633fa7024 | ||
|
19668b9b48 | ||
|
3f02631b98 | ||
|
da46eefe2e | ||
|
a3ca3ed33f | ||
|
efaa33c4d5 | ||
|
0cdfe7f458 | ||
|
2ad411ea29 | ||
|
55cbcd728d | ||
|
8880860105 | ||
|
0c238448fd | ||
|
8a76fdc126 | ||
|
433f830cf3 | ||
|
8893bc102c | ||
|
0cf9927132 | ||
|
5993125cc7 | ||
|
0c34309133 | ||
|
3d6ce0fb76 | ||
|
54f79c2798 | ||
|
d0a3779091 | ||
|
ff0960b174 | ||
|
7032825e35 | ||
|
d118533d87 | ||
|
35f4f75733 | ||
|
ef61c3543f | ||
|
897560745a | ||
|
5a8539a122 | ||
|
d9292a70bf | ||
|
a9c23b7c28 | ||
|
263bfb1bda | ||
|
e7eb220c50 | ||
|
7d67005820 | ||
|
fadd91b6a2 | ||
|
5fa6a2848f | ||
|
7ab921669b | ||
|
4811dfa663 | ||
|
2c7d6a7711 | ||
|
0e354e5ea1 | ||
|
d172a97247 | ||
|
8a3df7e434 | ||
|
eafcbabaa2 | ||
|
14071ea119 | ||
|
421e568232 | ||
|
4efd28c092 | ||
|
d0bbee7e8c | ||
|
7640563991 | ||
|
90cf85c3f0 | ||
|
f1a98693d0 | ||
|
2794d64d3e | ||
|
82743cca92 | ||
|
d0c348e595 | ||
|
f50d3088dc | ||
|
0917fa0d75 | ||
|
cfb73dd534 | ||
|
ef497b7989 | ||
|
9d9341901f | ||
|
155e3d225d | ||
|
ca41f100ab | ||
|
084285a760 | ||
|
982391cd7c | ||
|
d206d0a3ae | ||
|
627ea6c860 | ||
|
bcc76b3764 | ||
|
39692a8b3f | ||
|
eba8b4bf00 | ||
|
f149665660 | ||
|
e3bb64cf35 | ||
|
33f0669100 | ||
|
3a5f3e8b55 | ||
|
a0a90afbc0 | ||
|
2f96cb257c | ||
|
5910bec52e | ||
|
764b1c35cb | ||
|
ee8c9b764d | ||
|
7080f0c35a | ||
|
679d60cd5a | ||
|
bc36c0faed | ||
|
3c073bc360 | ||
|
c52d5e1084 | ||
|
b7bb27fa21 | ||
|
087aaa2f94 | ||
|
474b93a22f | ||
|
0c2f002a7d | ||
|
3d76d83a39 | ||
|
787015f537 | ||
|
fb624fddc4 | ||
|
605ddacb71 | ||
|
71934f05a8 | ||
|
534a0d6836 | ||
|
746b1d0c4d | ||
|
387c80e00a | ||
|
05c914691f | ||
|
94398d70f4 | ||
|
915ddb2b2b | ||
|
b916e7f7ef | ||
|
3cc30f91a9 | ||
|
f4a61b4c70 | ||
|
6eebd693ce | ||
|
bc0ae6be31 | ||
|
c03119d10a | ||
|
e1879ef4d9 | ||
|
b6df727efb | ||
|
fe58b44916 | ||
|
0a2694811d | ||
|
31fe232bac | ||
|
682f6d273c | ||
|
83ddaccf4a | ||
|
e0c0584c59 | ||
|
60f5a52964 | ||
|
7e5866ce3f | ||
|
89b7b56a2c | ||
|
ae54b13d4b | ||
|
927ccc489c | ||
|
21f7722f10 | ||
|
e4afe603f9 | ||
|
30d15a1438 | ||
|
c84586dd66 | ||
|
e9f87c2026 | ||
|
afa27a3c2a | ||
|
ce6078ed94 | ||
|
6d5949ba9c | ||
|
cdb165af7f | ||
|
88a3f8e4aa | ||
|
1c3dc757c3 | ||
|
25866095db | ||
|
b6c8d8e971 | ||
|
ab94b0b231 | ||
|
760bab8f86 | ||
|
817c332d11 | ||
|
05fbc8e6b0 | ||
|
c39301b6da | ||
|
add9a9db9b | ||
|
05123ea6f4 | ||
|
d62ff34a5a | ||
|
a8b8d53d9d | ||
|
0d4ff5a916 | ||
|
8ace41d144 | ||
|
5bb7219f4b | ||
|
f0200ab697 | ||
|
f457a56d4a | ||
|
db086de84a | ||
|
37684c6af0 | ||
|
3c75d4f1dd | ||
|
b19276bb0f | ||
|
774d831fae | ||
|
a1b49d8389 | ||
|
12e2bfc794 | ||
|
6e5abade3c | ||
|
e4e3676095 | ||
|
3ed13150e1 | ||
|
f03e5c6bd1 | ||
|
8496c1cdd3 | ||
|
3c3851c221 | ||
|
05f1e9e3b8 | ||
|
249a1e6d8d | ||
|
e042e0ad32 | ||
|
5db15ca54c | ||
|
069b89b208 | ||
|
63014aeb6b | ||
|
31e21db5b5 | ||
|
7f21872510 | ||
|
27351c9a90 | ||
|
76b918d40e | ||
|
f5bc0b205c | ||
|
b3c253ea2a | ||
|
d17e031259 | ||
|
842363200b | ||
|
d9f9895b2b | ||
|
bc0edd4042 | ||
|
9b82e2df58 | ||
|
3d65341080 | ||
|
80215ea181 | ||
|
78d8526e41 | ||
|
0ddaabe377 | ||
|
9bc6ebde4e | ||
|
011f14d115 | ||
|
62a5cbb5ce | ||
|
5aaf87d612 | ||
|
96b31f3974 | ||
|
09e387bf09 | ||
|
05fe8792ea | ||
|
18ed45597a | ||
|
a200eaacaa | ||
|
f5ad553be3 | ||
|
4f4acc04fe | ||
|
dee0fec9e9 | ||
|
73cc2a140c | ||
|
6058a74da5 | ||
|
bd3b652cfc | ||
|
73429fc720 | ||
|
10478a6b2f | ||
|
e0bc01eea1 | ||
|
2af6d3f6bc | ||
|
cbe5438a31 | ||
|
67c4ad128c | ||
|
870eca0d9f | ||
|
d299458084 | ||
|
e0cf68f1d5 | ||
|
64906a1ba5 | ||
|
e75721016e | ||
|
e0d5b9daf8 | ||
|
5989844f1c | ||
|
14e3f413a2 | ||
|
a97d77064a | ||
|
3342dd4001 | ||
|
785b9811f3 | ||
|
643c77ded0 | ||
|
76f01511a3 | ||
|
dd8727d3ae | ||
|
b933946f33 | ||
|
5d2f9d7a33 | ||
|
3baf14b793 | ||
|
c57e4ba508 | ||
|
98656289ea | ||
|
167a38e27d | ||
|
ba6806df5d | ||
|
fe12101278 | ||
|
d6d7f4e875 | ||
|
63caddea62 | ||
|
36b01fbdcf | ||
|
45a3d8b75a | ||
|
bca62c813d | ||
|
ae1cf74dcd | ||
|
577a8dd005 | ||
|
5900899c01 | ||
|
2dfc468094 | ||
|
98ffe9931d | ||
|
2004c0d739 | ||
|
cd7cb025ad | ||
|
96da267778 | ||
|
5816e410e9 | ||
|
31c98fc0db | ||
|
00bf957b53 | ||
|
5b999c2f7d | ||
|
1cc9d9c071 | ||
|
72fb8460e9 | ||
|
577156fe5f | ||
|
612cc96e41 | ||
|
da3f783a9f | ||
|
b1e8545981 | ||
|
6a2da6dc06 | ||
|
58603e2a5a | ||
|
d97184880c | ||
|
625f40cfa6 | ||
|
49049b8c12 | ||
|
037912ccab | ||
|
8b05b864fb | ||
|
319135c8fe | ||
|
61d9e418e8 | ||
|
475bb2845d | ||
|
42f39de0f9 | ||
|
3898b8e8ab | ||
|
b1fd005c95 | ||
|
cf8fdd3a70 | ||
|
cb754ee125 | ||
|
cea81df969 | ||
|
af1d5fce6e | ||
|
54b86b6131 | ||
|
ec2b83515b | ||
|
2f2724dff5 | ||
|
271fa26890 | ||
|
fe437da751 | ||
|
129876d1be | ||
|
f2ced67a8d | ||
|
787eec8be4 | ||
|
cc39eea999 | ||
|
cbfed99bc6 | ||
|
2b4cd8b2ec | ||
|
b5dc72b126 | ||
|
ab4d2faea3 | ||
|
1677817d9f | ||
|
03854baf53 | ||
|
61dc253de1 | ||
|
a0e8f410d1 | ||
|
2865f63c5d | ||
|
3f19ab1a87 | ||
|
d75fec0cee | ||
|
39570a9663 | ||
|
479c18e21f | ||
|
fd4453d85e | ||
|
7ee7f99780 | ||
|
4c0b8e3113 | ||
|
e0af60d8a7 | ||
|
afcb7f00da | ||
|
e1b06bfce2 | ||
|
8de3f03b49 | ||
|
db8f018b42 | ||
|
59cb2132f2 | ||
|
25f62daf14 | ||
|
05b9dfbe30 | ||
|
3db4e2ee2f | ||
|
86a6a5b826 | ||
|
cc6338d048 | ||
|
57b65726d6 | ||
|
44a736c53b | ||
|
38cbd42d81 | ||
|
28d019f824 | ||
|
54b8e1be89 | ||
|
9778695b4a | ||
|
44b6285268 | ||
|
6c6fb2e287 | ||
|
ecdfde8c38 | ||
|
ea2d5b9d4a | ||
|
1e0522fe8f | ||
|
70858603ed | ||
|
3c508c1d27 | ||
|
5c44db341f | ||
|
cf73363016 | ||
|
351173e554 | ||
|
342432dc76 | ||
|
c4538cada7 | ||
|
de532bb2fc | ||
|
f525afa5de | ||
|
9fba470364 | ||
|
6cd5bf31c9 | ||
|
321c0a8537 | ||
|
b9bc58ef10 | ||
|
7bcf05fd19 | ||
|
f816bdf541 | ||
|
79472552aa | ||
|
c5e5c8288e | ||
|
fd1c7f7169 | ||
|
9212d67e2f | ||
|
f5c74d123a | ||
|
c8421efcd3 | ||
|
f382609d01 | ||
|
f9615c18a1 | ||
|
a74597c7cd | ||
|
d50fbac5f9 | ||
|
95086a75e6 | ||
|
073a96cf63 | ||
|
d3c64bd5b4 | ||
|
7024a7468a | ||
|
62e60e2ba6 | ||
|
fb3860757c | ||
|
e4a8b17522 | ||
|
448df1bb9c | ||
|
bf6900fb2a | ||
|
50552546f3 | ||
|
324fab8186 | ||
|
7ab80f01b5 | ||
|
9ce4a5c7b1 | ||
|
c9a0525a10 | ||
|
83465bb7f5 | ||
|
e8771fb36a | ||
|
d4d03f3d7f | ||
|
d567d667e8 | ||
|
3d55bbbc29 | ||
|
2f8e52f905 | ||
|
a5896ac6b6 | ||
|
94b9d5644c | ||
|
06e5fc233c | ||
|
aefb922a05 | ||
|
a22434fd73 | ||
|
c41846805d | ||
|
b7b45b69a6 | ||
|
ed5528664c | ||
|
fe88d3c225 | ||
|
aed4ee8694 | ||
|
817d9b0d3e | ||
|
df9cfe7840 | ||
|
8cd4578d83 | ||
|
9ca41b9536 | ||
|
559743c911 | ||
|
3a7f26f620 | ||
|
04a0eae241 | ||
|
0500d2fb6e | ||
|
31f1a9e5aa | ||
|
6387aae471 | ||
|
152082e182 | ||
|
08eb2b3df7 | ||
|
846ec87249 | ||
|
62690b5159 | ||
|
719c432ca8 | ||
|
e654616b6d | ||
|
f0473b0320 | ||
|
fcc627e6e1 | ||
|
fe17802cd2 | ||
|
384c05ccc7 | ||
|
193e4f3275 | ||
|
6fd87568e7 | ||
|
484fd68495 | ||
|
792be54443 | ||
|
00df102c29 | ||
|
90e68ddd73 | ||
|
df27f4f118 | ||
|
bee26daf0c | ||
|
b76c738785 | ||
|
8ca9fb0251 | ||
|
3b26a656f7 | ||
|
2f5ac5d993 | ||
|
a2fc9a964b | ||
|
b8a267370d | ||
|
fa3d011f68 | ||
|
a7fc9caacb | ||
|
c284f6dcd4 | ||
|
368d59c3ca | ||
|
94ee82e076 | ||
|
bfefb6e696 | ||
|
95b7601e2b | ||
|
f9c8bd868c | ||
|
a773973b1b | ||
|
a60006366b | ||
|
a66bb7889a | ||
|
adfba06e85 | ||
|
6ee4e954f6 | ||
|
a11d139ff6 | ||
|
85a3e66314 | ||
|
1a3958ed60 | ||
|
743c957918 | ||
|
224a6c192b | ||
|
ae47da3801 | ||
|
a6d669453f | ||
|
0beab9eec4 | ||
|
aa997f1be5 | ||
|
4eb58a70bb | ||
|
5b31d0aa36 | ||
|
79e7c44884 | ||
|
1382c1243a | ||
|
8f2fd9b603 | ||
|
d625b65a09 | ||
|
101e9be7b9 | ||
|
9f93d8f533 | ||
|
6050a59e4a | ||
|
e5b7e29113 | ||
|
ecdd0ce9f2 | ||
|
fc5c598f8f | ||
|
18ebed3c5d | ||
|
822e319efe | ||
|
6d462fc961 | ||
|
4b71c65aea | ||
|
34ab53173d | ||
|
d6be6f79ce | ||
|
87d36f06fd | ||
|
3eb05b4505 | ||
|
0789c6a3d8 | ||
|
b587f076fe | ||
|
a5a7217c8f | ||
|
c0cf55b40b | ||
|
9200ed2216 | ||
|
e1f7dd1372 | ||
|
32833b7301 | ||
|
3302c89284 | ||
|
e18d61b31a | ||
|
61cd1ae525 | ||
|
064608a8ef | ||
|
5a840c88b5 | ||
|
b14c3fe48d | ||
|
4874d55d03 | ||
|
b20e40dd6f | ||
|
bc28a08dd0 | ||
|
0d3010f6fc | ||
|
399a651fa3 | ||
|
30ac5fcb5e | ||
|
92cb5e10be | ||
|
10faa47495 | ||
|
f0bbf2cab0 | ||
|
338e8be327 | ||
|
a4726a0e0d | ||
|
d4a366aeb1 | ||
|
98652997f9 | ||
|
f5a39c2f7b | ||
|
9854db0a63 | ||
|
cc7b0f4623 | ||
|
549e6d57c4 | ||
|
dea322e2c5 | ||
|
ed5b9c2b56 | ||
|
c31ca4af90 | ||
|
2c9ec4bee8 | ||
|
6dcfc36a4a | ||
|
76579a3004 | ||
|
1d68692bb6 | ||
|
790af0fd72 | ||
|
39008372e5 | ||
|
1026952f26 | ||
|
9631927a8c | ||
|
b0e6ce581a | ||
|
e575323c60 | ||
|
809ac3340c | ||
|
f0af638874 | ||
|
b49148ec54 | ||
|
c7f5e77b3f | ||
|
817248369a | ||
|
654698b208 | ||
|
4e5bfae332 | ||
|
895a9093aa | ||
|
35121f0b78 | ||
|
c4a7574f7b | ||
|
4ee636ecca | ||
|
662dc12877 | ||
|
3cc8af819c | ||
|
fcf4a958c3 | ||
|
65676c22f9 | ||
|
3e907d7f4f | ||
|
9fa567aa78 | ||
|
237ebb0716 | ||
|
fdea260e41 | ||
|
9af77dc835 | ||
|
d4aacd218a | ||
|
326a566db2 | ||
|
84257dac2b | ||
|
22ad9e1e1a | ||
|
cc44f5f75d | ||
|
23df5cc201 | ||
|
dab2d5db44 | ||
|
1717c5c00d | ||
|
ea3f82ccc2 | ||
|
fd6ce470e7 | ||
|
6d3fbbe256 | ||
|
45c4de16d2 | ||
|
92b0efff5a | ||
|
bc550c3265 | ||
|
b39aa5d359 | ||
|
f8f8bd95ca | ||
|
d057b77dc5 | ||
|
27d637195d | ||
|
46919ce797 | ||
|
b4e1ce59f9 | ||
|
7af77d3eb0 | ||
|
de1ff52de3 | ||
|
69c1df68c8 | ||
|
62431fee8e | ||
|
357201869a | ||
|
a88e8ffe79 | ||
|
5c88f43e15 | ||
|
2f7ab3e32d | ||
|
3ec05bb5d8 | ||
|
59890f2c83 | ||
|
2c70162bee | ||
|
2f1a4042bf | ||
|
4af7740907 | ||
|
f64ea361d4 | ||
|
9c850d152c | ||
|
71266c0220 | ||
|
0801457ff0 | ||
|
ba7c9ceccc | ||
|
f6f2818a02 | ||
|
b05a3b7aed | ||
|
3fe94891d3 | ||
|
9d11028fce | ||
|
f6b81f588d | ||
|
513007a82c | ||
|
bf18a90da7 | ||
|
2ddd53b355 | ||
|
c9aef16649 | ||
|
6a77e0fe56 | ||
|
0a725415a4 | ||
|
af0d9439d4 | ||
|
65f09d0528 | ||
|
48e6695447 | ||
|
e3604c1662 | ||
|
5913d654bd | ||
|
f3fe9661f6 | ||
|
17cfd7b001 | ||
|
e941bdd945 | ||
|
e7e8773cd4 | ||
|
ebc750d5bf | ||
|
3507fe6d5b | ||
|
f9ef6491e6 | ||
|
61e487224f | ||
|
85eb82acb2 | ||
|
4d364ea261 | ||
|
577528bb9c | ||
|
d49f2c40ae | ||
|
706bfafe74 | ||
|
1b8204dabe | ||
|
05cabded02 | ||
|
1578402cbe | ||
|
49ee56b22c | ||
|
8c7f0902c0 | ||
|
056ef9ccd1 | ||
|
dfc635b451 | ||
|
68321362c5 | ||
|
f7560036b8 | ||
|
fc87caa348 | ||
|
6e0aef5f2b | ||
|
127b3e7d60 | ||
|
9740199870 | ||
|
06be580d2c | ||
|
6540343f45 | ||
|
447b305e3c | ||
|
0c53d276f8 | ||
|
83c37c6a7a | ||
|
ac52ad88a1 | ||
|
84a1b5612d | ||
|
fa4e694859 | ||
|
f8c628b0c7 | ||
|
2f35e4789c | ||
|
253bada643 | ||
|
e4fe497504 | ||
|
5c9bde203e | ||
|
d9907f227e | ||
|
08b08ef1d0 | ||
|
334ef5c3eb | ||
|
ac925aa226 | ||
|
86f17fb466 | ||
|
6aafda4517 | ||
|
8267950dbc | ||
|
56d1b0103f | ||
|
1ff34bd0f4 | ||
|
b86248f13f | ||
|
427a29145d | ||
|
974575b695 | ||
|
60b1fdd367 | ||
|
842f2ea5cc | ||
|
ae220c37df | ||
|
6f57f52ac2 | ||
|
4897513d7d | ||
|
c8dad01137 | ||
|
5a09063adb | ||
|
9de9bf651b | ||
|
09d80b1e50 | ||
|
2b793f372a | ||
|
4cfeb6b8ac | ||
|
9373451ca8 | ||
|
15c199d5a2 | ||
|
cde85243d6 | ||
|
c579db1a7b | ||
|
61fa34e2ce | ||
|
96febf6639 | ||
|
09e59cf677 | ||
|
9119ee14b6 | ||
|
2ac2ae3eee | ||
|
a682b5d90e | ||
|
e26c0c58ae | ||
|
187fa71526 | ||
|
4a0c8d72b0 | ||
|
5456187dd0 | ||
|
73c95c328d | ||
|
4a971be168 | ||
|
f657a3d811 | ||
|
b39f75a2e3 | ||
|
1dad14f8ea | ||
|
5cc2e8de7b | ||
|
d0abc60176 | ||
|
130e83d9b2 | ||
|
ed8acdb11c | ||
|
26370da13d | ||
|
a5d315ee2a | ||
|
4fa57f55e6 | ||
|
2c496a92ad | ||
|
4ca8903a21 | ||
|
d460c0e8b9 | ||
|
11b6d290da | ||
|
d83902834f | ||
|
0fdf32cf6f | ||
|
f4ebbfabf4 | ||
|
b5bcfc8fe7 | ||
|
d13c08cc0d | ||
|
89abd76570 | ||
|
8c1ae35088 | ||
|
bb74789b42 | ||
|
dbbd32d2ce | ||
|
80285a300d | ||
|
2eb5819851 | ||
|
e748e1891b | ||
|
28bb11217c | ||
|
636dae6a79 | ||
|
c8f65a1bf9 | ||
|
ce177ae6f6 | ||
|
c79f3501cd | ||
|
80114edc71 | ||
|
71483e2865 | ||
|
93087324d9 | ||
|
061facdcce | ||
|
3e6e7fb272 | ||
|
12d8c2398f | ||
|
bb73963421 | ||
|
1dd7688bdd | ||
|
5735095521 | ||
|
fa7570352c | ||
|
f378406d15 | ||
|
68fa7ae2a3 | ||
|
9b1015bbce | ||
|
a4c821eb60 | ||
|
c70540e7f4 | ||
|
e291146443 | ||
|
faa2b6237f | ||
|
26661f3091 | ||
|
e6e8d49d72 | ||
|
b9ca055586 | ||
|
9ce7be050a | ||
|
1d2617c826 | ||
|
7c8e9ddc42 | ||
|
157764c0d9 | ||
|
317ff81744 | ||
|
bd7fc780cb | ||
|
4b343d9dcf | ||
|
7a6a5d7595 | ||
|
85020c74cf | ||
|
0137c0da8c | ||
|
407731ab16 | ||
|
72503c0689 | ||
|
e9e570db4f | ||
|
5bc83fceaa | ||
|
e7fd501200 | ||
|
ea0067d999 | ||
|
ec49ca6480 | ||
|
c9d3041460 | ||
|
943b7d39c6 | ||
|
6b1a911604 | ||
|
3d4e03f2cd | ||
|
48b0b54819 | ||
|
00515eb6f9 | ||
|
63e7391981 | ||
|
b6776f53ab | ||
|
6a0cda7396 | ||
|
09692dc70e | ||
|
e0482f5400 | ||
|
c787dc7356 | ||
|
ea948ac2c8 | ||
|
d6e321e97f | ||
|
807250510a | ||
|
ef1e974346 | ||
|
55d1228abb | ||
|
9e76d2ca63 | ||
|
d53915e7e3 | ||
|
e2cbe42ed0 | ||
|
78623ae3bd | ||
|
136c6d01b3 | ||
|
9e0471bfbb | ||
|
f9d2689a12 | ||
|
9744b1906a | ||
|
5198c56db9 | ||
|
7e7364fc83 | ||
|
395d060427 | ||
|
bbf088d903 | ||
|
c84be8ddb3 | ||
|
853b5e1b72 | ||
|
3355a39fe0 | ||
|
0cb357a0e9 | ||
|
668dcb7cf0 | ||
|
b5c4b81aac | ||
|
c849c8ef08 | ||
|
bbb3d5bb67 | ||
|
63ad2ebf0b | ||
|
e4f8ea2f7c | ||
|
599d34f1c0 | ||
|
31411dd11b | ||
|
b7781108ae | ||
|
35ca7d1826 | ||
|
9ddec32260 | ||
|
185e7d43fb | ||
|
0e0a46f373 | ||
|
732202fe8e | ||
|
e1cab78c09 | ||
|
9dc4ec6fb5 | ||
|
0baaf1767b | ||
|
eab76c5819 | ||
|
ebd6f7ace0 | ||
|
a6d5cd4b39 | ||
|
4c5a632095 | ||
|
870693b968 | ||
|
b24b98a365 | ||
|
fd041e2997 | ||
|
27a44f0e77 | ||
|
432b064601 | ||
|
a8a0a5cbfb | ||
|
32e77753b5 | ||
|
f427a736a3 | ||
|
afb02b8bd1 | ||
|
48b44342ab | ||
|
1f968fa4fd | ||
|
ebf5077e1a | ||
|
7d26b96d42 | ||
|
08208acf53 | ||
|
46653a0268 | ||
|
fcef1819b1 | ||
|
3335fc7baf | ||
|
63abf34664 | ||
|
120ca5b1ec | ||
|
1c94ab7cc3 | ||
|
aa3be51980 | ||
|
fe6c77cafb | ||
|
67117913dd | ||
|
e532f2c165 | ||
|
a0c7da95c2 | ||
|
95dbc0f5bc | ||
|
ab13ce96cc | ||
|
ac0c35424b | ||
|
41242a6660 | ||
|
e80f203efc | ||
|
dbd65cdb04 | ||
|
e4dd33a675 | ||
|
0e3544e1f9 | ||
|
f4589b5bd4 | ||
|
3b7068e8d0 | ||
|
2a8fc705c7 | ||
|
c19fb1dffc | ||
|
436a6605fb | ||
|
84eddc3d94 | ||
|
dfe6b2844b | ||
|
6be5fe928e | ||
|
167654c9a0 | ||
|
6d6179fb2c | ||
|
80d06d358a | ||
|
1cace49b74 | ||
|
7ab5442163 | ||
|
4d42f64fa3 | ||
|
8d83243378 | ||
|
e1a74b6bdd | ||
|
44919c353e | ||
|
cf8523da5f | ||
|
10707ebc3a | ||
|
8374a51e6a | ||
|
4e48de1116 | ||
|
b3b29f527e | ||
|
37cfeed0f5 | ||
|
cb27fe17cd | ||
|
682ab76ba1 | ||
|
c811b710eb | ||
|
d0930b9048 | ||
|
591645758a | ||
|
4e093369f6 | ||
|
be8e8791b7 | ||
|
b13a2e71ad | ||
|
28678214d2 | ||
|
f75d03c9ae | ||
|
51508a732d | ||
|
326d8d3976 | ||
|
f559a5510b | ||
|
bf8b123dfc | ||
|
32a7442845 | ||
|
a0dfdefd16 | ||
|
e7b0c24d9d | ||
|
1707f1940d | ||
|
5dd708aae8 | ||
|
2477ea2fcf | ||
|
9b624a884b | ||
|
bc7672652e | ||
|
cc77f8489e | ||
|
564ddff4c7 | ||
|
023ea94f07 | ||
|
adad76eca6 | ||
|
772bb65237 | ||
|
d72a731865 | ||
|
f35fe56d9b | ||
|
1ab70f130d | ||
|
86f79949ea | ||
|
219d6c294d | ||
|
78d81f193f | ||
|
b9e0cd4512 | ||
|
f9d4966000 | ||
|
ad2289935d | ||
|
fd47b3fac5 | ||
|
84d836f22b | ||
|
5d05a2da74 | ||
|
2f639b77bb | ||
|
8b5b371821 | ||
|
0c74a3bc66 | ||
|
75f77f3e86 | ||
|
7a66da5a51 | ||
|
3541f5e1da | ||
|
8f809e3a29 | ||
|
3f76985435 | ||
|
751f9b9240 | ||
|
1efba5979f | ||
|
bf3c4f4743 | ||
|
aeb0742434 | ||
|
e98b4ea26d | ||
|
1729cfaea9 | ||
|
56ade9c44e | ||
|
6db0b2e398 | ||
|
2bd1ddd129 | ||
|
20a37bdd1d | ||
|
234447cb3d | ||
|
97232145a4 | ||
|
056ec6d2b3 | ||
|
2c44c7ea83 | ||
|
9cc1956b4b | ||
|
a35138e2b9 | ||
|
49f6c20b20 | ||
|
6bfc02d79d | ||
|
7b166837d3 | ||
|
3ff8a319c5 | ||
|
cd8f8e1e4a | ||
|
ed43d8d08b | ||
|
ca786cdd11 | ||
|
3e659f0de8 | ||
|
795a357595 | ||
|
5737365b2d | ||
|
8dff54de42 | ||
|
c1b8a7fbb7 | ||
|
6f3c6f7599 | ||
|
246eca91aa | ||
|
5fd378e4ce | ||
|
382f24c556 | ||
|
0773fcf66f | ||
|
650a24ba87 | ||
|
d2be2ee6cd | ||
|
7d63c5d982 | ||
|
a4f294c090 | ||
|
58c5e800d0 | ||
|
6d7097eed5 | ||
|
55da59a537 | ||
|
012ee310a4 | ||
|
1e07fcacac | ||
|
69ab913bc6 | ||
|
83a63f64b1 | ||
|
8f7e67367a | ||
|
0dad3fecb6 | ||
|
09b99bbf8b | ||
|
92e112dc63 | ||
|
6f5a84703e | ||
|
c0de35e71c | ||
|
f7dd6f7a7e | ||
|
655c1eb90f | ||
|
af6885db81 | ||
|
78e216d157 | ||
|
61726d84ac | ||
|
60d3bed393 | ||
|
3133ca0081 | ||
|
0f720223a9 | ||
|
6bb93b8170 | ||
|
d0f32d1865 | ||
|
2fe4e380d1 | ||
|
a7f4701698 | ||
|
f12e4f8889 | ||
|
df99a360fb | ||
|
4c76ad072a | ||
|
edf837ed62 | ||
|
7201a74aea | ||
|
9e2f8bead9 | ||
|
942867179c | ||
|
6b897f6fd2 | ||
|
389f1cde51 | ||
|
1ad31ab007 | ||
|
914db52c4d | ||
|
fe51ec906e | ||
|
85551f4994 | ||
|
fc1cfcceca | ||
|
6b4d4b9246 | ||
|
b06ba55be3 |
@@ -3,7 +3,7 @@ version: 2
|
||||
jobs:
|
||||
build:
|
||||
docker:
|
||||
- image: circleci/node:6.12
|
||||
- image: circleci/node:9
|
||||
environment:
|
||||
CONTRACTS_COMMIT_HASH: '9ed05f5'
|
||||
working_directory: ~/repo
|
||||
@@ -11,95 +11,76 @@ jobs:
|
||||
- checkout
|
||||
- run: echo 'export PATH=$HOME/CIRCLE_PROJECT_REPONAME/node_modules/.bin:$PATH' >> $BASH_ENV
|
||||
- restore_cache:
|
||||
key: dependency-cache-{{ checksum "package.json" }}
|
||||
name: Restore Yarn Package Cache
|
||||
keys:
|
||||
- yarn-packages-{{ .Branch }}-{{ checksum "yarn.lock" }}
|
||||
- yarn-packages-{{ .Branch }}
|
||||
- yarn-packages-master
|
||||
- yarn-packages-
|
||||
- run:
|
||||
name: yarn
|
||||
command: yarn --frozen-lockfile
|
||||
command: yarn --frozen-lockfile install
|
||||
- save_cache:
|
||||
key: dependency-cache-{{ checksum "package.json" }}
|
||||
name: Save Yarn Package Cache
|
||||
key: yarn-packages-{{ .Branch }}-{{ checksum "yarn.lock" }}
|
||||
paths:
|
||||
- ./node_modules
|
||||
- run: wget https://s3.amazonaws.com/testrpc-shapshots/${CONTRACTS_COMMIT_HASH}.zip
|
||||
- run: unzip ${CONTRACTS_COMMIT_HASH}.zip -d testrpc_snapshot
|
||||
- run: node ./node_modules/lerna/bin/lerna.js bootstrap
|
||||
- run: yarn build
|
||||
- node_modules/
|
||||
- run: >
|
||||
if [ -z "$(git diff --name-only v2-prototype packages/website)" ]; then
|
||||
yarn build --exclude website
|
||||
else
|
||||
yarn build
|
||||
fi
|
||||
- save_cache:
|
||||
key: repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- ~/repo
|
||||
test-installation:
|
||||
test-contracts-ganache:
|
||||
docker:
|
||||
- image: circleci/node:6.12
|
||||
- image: circleci/node:9
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run: yarn test:installation
|
||||
test-0xjs:
|
||||
docker:
|
||||
- image: circleci/node:6.12
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run:
|
||||
name: testrpc
|
||||
command: npm run testrpc -- --db testrpc_snapshot
|
||||
background: true
|
||||
- run: yarn wsrun test:circleci 0x.js
|
||||
- save_cache:
|
||||
key: coverage-0xjs-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- ~/repo/packages/0x.js/coverage/lcov.info
|
||||
test-contracts:
|
||||
docker:
|
||||
- image: circleci/node:6.12
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run:
|
||||
name: testrpc
|
||||
command: npm run testrpc -- --db testrpc_snapshot
|
||||
background: true
|
||||
- run: yarn wsrun test:circleci contracts
|
||||
- save_cache:
|
||||
key: coverage-contracts-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- ~/repo/packages/contracts/coverage/lcov.info
|
||||
test-sol-compiler:
|
||||
test-contracts-geth:
|
||||
docker:
|
||||
- image: circleci/node:6.12
|
||||
- image: circleci/node:9
|
||||
- image: albrow/0x-devnet
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run:
|
||||
name: testrpc
|
||||
command: npm run testrpc -- --db testrpc_snapshot
|
||||
background: true
|
||||
# HACK(albrow): we need to sleep 15 seconds to ensure the devnet is
|
||||
# initialized
|
||||
- run: sleep 15 && TEST_PROVIDER=geth yarn wsrun test contracts
|
||||
test-rest:
|
||||
docker:
|
||||
- image: circleci/node:9
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run: yarn wsrun test:circleci @0xproject/contract-wrappers
|
||||
- run: yarn wsrun test:circleci @0xproject/sol-compiler
|
||||
- run: yarn wsrun test:circleci @0xproject/assert
|
||||
- run: yarn wsrun test:circleci @0xproject/connect
|
||||
- run: yarn wsrun test:circleci @0xproject/dev-utils
|
||||
- run: yarn wsrun test:circleci @0xproject/json-schemas
|
||||
- run: yarn wsrun test:circleci @0xproject/subproviders
|
||||
- run: yarn wsrun test:circleci @0xproject/sol-cov
|
||||
- run: yarn wsrun test:circleci @0xproject/metacoin
|
||||
- save_cache:
|
||||
key: coverage-contract-wrappers-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- ~/repo/packages/contract-wrappers/coverage/lcov.info
|
||||
- save_cache:
|
||||
key: coverage-sol-compiler-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- ~/repo/packages/sol-compiler/coverage/lcov.info
|
||||
test-rest:
|
||||
docker:
|
||||
- image: circleci/node:6.12
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run:
|
||||
name: testrpc
|
||||
command: npm run testrpc -- --db testrpc_snapshot
|
||||
background: true
|
||||
- run: yarn wsrun test:circleci --exclude contracts --exclude 0x.js --exclude @0xproject/sol-compiler --stages --exclude-missing
|
||||
- save_cache:
|
||||
key: coverage-assert-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
@@ -128,41 +109,33 @@ jobs:
|
||||
key: coverage-metacoin-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- ~/repo/packages/metacoin/coverage/lcov.info
|
||||
lint:
|
||||
static-tests:
|
||||
working_directory: ~/repo
|
||||
docker:
|
||||
- image: circleci/node:6.12
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run: yarn lerna:run lint
|
||||
prettier:
|
||||
working_directory: ~/repo
|
||||
docker:
|
||||
- image: circleci/node:6.12
|
||||
- image: circleci/node:9
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run: yarn prettier:ci
|
||||
- run: yarn lerna:run lint
|
||||
submit-coverage:
|
||||
docker:
|
||||
- image: circleci/node:6.12
|
||||
- image: circleci/node:9
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- coverage-contracts-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- coverage-assert-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- coverage-connect-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- coverage-contract-wrappers-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- coverage-dev-utils-{{ .Environment.CIRCLE_SHA1 }}
|
||||
@@ -175,6 +148,9 @@ jobs:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- coverage-sol-cov-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- coverage-contracts-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- coverage-sol-compiler-{{ .Environment.CIRCLE_SHA1 }}
|
||||
@@ -190,30 +166,18 @@ workflows:
|
||||
main:
|
||||
jobs:
|
||||
- build
|
||||
- test-installation:
|
||||
- test-contracts-ganache:
|
||||
requires:
|
||||
- build
|
||||
- test-0xjs:
|
||||
requires:
|
||||
- build
|
||||
- test-contracts:
|
||||
requires:
|
||||
- build
|
||||
- test-sol-compiler:
|
||||
- test-contracts-geth:
|
||||
requires:
|
||||
- build
|
||||
- test-rest:
|
||||
requires:
|
||||
- build
|
||||
- prettier:
|
||||
requires:
|
||||
- build
|
||||
- lint:
|
||||
- static-tests:
|
||||
requires:
|
||||
- build
|
||||
- submit-coverage:
|
||||
requires:
|
||||
- test-0xjs
|
||||
- test-sol-compiler
|
||||
- test-rest
|
||||
- test-contracts
|
||||
|
8
.gitignore
vendored
8
.gitignore
vendored
@@ -80,13 +80,15 @@ packages/order-watcher/test/artifacts/
|
||||
packages/contract-wrappers/test/artifacts/
|
||||
|
||||
# generated contract wrappers
|
||||
packages/0x.js/src/contract_wrappers/generated/
|
||||
packages/contracts/src/contract_wrappers/generated/
|
||||
packages/0x.js/src/generated_contract_wrappers/
|
||||
packages/contracts/src/generated_contract_wrappers/
|
||||
packages/contract-wrappers/src/contract_wrappers/generated/
|
||||
packages/metacoin/src/contract_wrappers
|
||||
packages/fill-scenarios/src/generated_contract_wrappers/
|
||||
packages/order-watcher/src/generated_contract_wrappers/
|
||||
packages/migrations/src/contract_wrappers
|
||||
packages/order-utils/src/generated_contract_wrappers/
|
||||
packages/migrations/src/v1/contract_wrappers
|
||||
packages/migrations/src/v2/contract_wrappers
|
||||
|
||||
# solc-bin in sol-compiler
|
||||
packages/sol-compiler/solc_bin/
|
||||
|
@@ -1,10 +1,20 @@
|
||||
lib
|
||||
.nyc_output
|
||||
/packages/contract-wrappers/src/contract_wrappers/generated/
|
||||
/packages/metacoin/src/contract_wrappers
|
||||
/packages/0x.js/src/generated_contract_wrappers/
|
||||
/packages/contracts/src/generated_contract_wrappers/
|
||||
/packages/fill-scenarios/src/generated_contract_wrappers/
|
||||
/packages/order-watcher/src/generated_contract_wrappers/
|
||||
/packages/order-utils/src/generated_contract_wrappers/
|
||||
/packages/migrations/src/v1/contract_wrappers
|
||||
/packages/migrations/src/v2/contract_wrappers
|
||||
/packages/0x.js/test/artifacts
|
||||
/packages/contracts/src/artifacts
|
||||
/packages/metacoin/artifacts
|
||||
/packages/contract-wrappers/test/artifacts
|
||||
/packages/order-watcher/test/artifacts
|
||||
/packages/migrations/artifacts/1.0.0
|
||||
/packages/migrations/artifacts/2.0.0
|
||||
package.json
|
||||
scripts/postpublish_utils.js
|
||||
|
29
package.json
29
package.json
@@ -13,20 +13,24 @@
|
||||
"prettier:ci": "prettier --list-different '**/*.{ts,tsx,json,md}' --config .prettierrc",
|
||||
"report_coverage": "lcov-result-merger 'packages/*/coverage/lcov.info' | coveralls",
|
||||
"test:installation": "node ./packages/monorepo-scripts/lib/test_installation.js",
|
||||
"run:publish": "run-s install:all rebuild script:publish",
|
||||
"run:publish:dry": "run-s install:all rebuild script:publish:dry",
|
||||
"run:publish": "run-s install:all build:monorepo_scripts script:prepublish_checks rebuild script:publish",
|
||||
"run:publish:dry": "run-s install:all build:monorepo_scripts script:prepublish_checks rebuild script:publish:dry",
|
||||
"script:prepublish_checks": "node ./packages/monorepo-scripts/lib/prepublish_checks.js",
|
||||
"script:publish": "node ./packages/monorepo-scripts/lib/publish.js",
|
||||
"script:publish:dry": "IS_DRY_RUN=true yarn script:publish",
|
||||
"install:all": "yarn install",
|
||||
"wsrun": "wsrun",
|
||||
"lerna:run": "lerna run",
|
||||
"watch": "wsrun watch $PKG -r --stages --done-criteria='complete|successfully'",
|
||||
"build": "wsrun build $PKG -r --stages",
|
||||
"clean": "wsrun clean $PKG -r --parallel",
|
||||
"watch": "wsrun watch_without_deps $PKG --fast-exit -r --stages --done-criteria='complete|successfully'",
|
||||
"build": "wsrun build $PKG --fast-exit -r --stages",
|
||||
"build:monorepo_scripts": "PKG=@0xproject/monorepo-scripts yarn build",
|
||||
"clean": "wsrun clean $PKG --fast-exit -r --parallel",
|
||||
"rebuild": "run-s clean build",
|
||||
"test": "wsrun test $PKG --serial --exclude-missing",
|
||||
"stage_docs": "wsrun docs:stage $PKG --parallel --exclude-missing",
|
||||
"lint": "wsrun lint $PKG --parallel --exclude-missing"
|
||||
"test": "wsrun test $PKG --fast-exit --serial --exclude-missing",
|
||||
"stage_docs": "wsrun docs:stage $PKG --fast-exit --parallel --exclude-missing",
|
||||
"lint": "wsrun lint $PKG --fast-exit --parallel --exclude-missing",
|
||||
"comment:postinstall": "HACK: For some reason `yarn` is not setting up symlinks properly for order-utils. We temporarily set them manually. Remove this after V2 refactor is complete.",
|
||||
"postinstall": "rm -rf `pwd`/packages/order-utils/node_modules/@0xproject; mkdir `pwd`/packages/order-utils/node_modules/@0xproject; ln -s `pwd`/packages/json-schemas `pwd`/packages/order-utils/node_modules/@0xproject/json-schemas; ln -s `pwd`/packages/types `pwd`/packages/order-utils/node_modules/@0xproject/types; rm -f `pwd`/packages/contracts/node_modules/@0xproject/types; ln -s `pwd`/packages/types `pwd`/packages/contracts/node_modules/@0xproject/types; mkdir -p `pwd`/packages/fill-scenarios/node_modules/@0xproject; ln -s `pwd`/packages/types `pwd`/packages/fill-scenarios/node_modules/@0xproject/types; ln -s `pwd`/packages/order-utils `pwd`/packages/fill-scenarios/node_modules/@0xproject/order-utils"
|
||||
},
|
||||
"config": {
|
||||
"mnemonic": "concert load couple harbor equip island argue ramp clarify fence smart topic"
|
||||
@@ -35,10 +39,15 @@
|
||||
"async-child-process": "^1.1.1",
|
||||
"coveralls": "^3.0.0",
|
||||
"ganache-cli": "^6.1.0",
|
||||
"lcov-result-merger": "^2.0.0",
|
||||
"lcov-result-merger": "^3.0.0",
|
||||
"lerna": "^2.5.1",
|
||||
"npm-run-all": "^4.1.2",
|
||||
"prettier": "^1.11.1",
|
||||
"wsrun": "^2.2.0"
|
||||
"wsrun": "^2.2.0",
|
||||
"source-map-support": "^0.5.6"
|
||||
},
|
||||
"resolutions": {
|
||||
"ethereumjs-tx": "0xProject/ethereumjs-tx#fake-tx-include-signature-by-default",
|
||||
"ethers": "0xproject/ethers.js#eip-838-reasons"
|
||||
}
|
||||
}
|
||||
|
@@ -15,20 +15,22 @@
|
||||
"main": "lib/src/index.js",
|
||||
"types": "lib/src/index.d.ts",
|
||||
"scripts": {
|
||||
"watch": "tsc -w",
|
||||
"prebuild": "run-s clean generate_contract_wrappers",
|
||||
"build": "run-p build:umd:prod build:commonjs; exit 0;",
|
||||
"generate_contract_wrappers": "abi-gen --abis 'src/compact_artifacts/@(Exchange|Token|TokenTransferProxy|EtherToken|TokenRegistry|DummyToken).json' --template ../contract_templates/contract.handlebars --partials '../contract_templates/partials/**/*.handlebars' --output src/contract_wrappers/generated --backend ethers && prettier --write 'src/contract_wrappers/generated/**.ts'",
|
||||
"lint": "tslint --project .",
|
||||
"watch_without_deps": "yarn pre_build && tsc -w",
|
||||
"build": "yarn pre_build && yarn build:all && copyfiles -u 3 './lib/src/monorepo_scripts/**/*' ./scripts",
|
||||
"build:all": "run-p build:umd:prod build:commonjs; exit 0;",
|
||||
"pre_build": "run-s generate_contract_wrappers copy_artifacts",
|
||||
"copy_artifacts": "copyfiles -u 2 './src/compact_artifacts/**/*.json' ./lib/src/compact_artifacts",
|
||||
"generate_contract_wrappers": "abi-gen --abis 'src/compact_artifacts/@(Exchange|Token|TokenTransferProxy|EtherToken|TokenRegistry|DummyToken).json' --template ../contract_templates/contract.handlebars --partials '../contract_templates/partials/**/*.handlebars' --output src/generated_contract_wrappers --backend ethers",
|
||||
"lint": "tslint --project . --exclude **/src/generated_contract_wrappers/**/*",
|
||||
"test:circleci": "run-s test:coverage",
|
||||
"test": "run-s clean test:commonjs",
|
||||
"test": "yarn run_mocha",
|
||||
"rebuild_and_test": "run-s build test",
|
||||
"test:coverage": "nyc npm run test --all && yarn coverage:report:lcov",
|
||||
"coverage:report:lcov": "nyc report --reporter=text-lcov > coverage/lcov.info",
|
||||
"clean": "shx rm -rf _bundles lib test_temp scripts src/contract_wrappers/generated",
|
||||
"clean": "shx rm -rf _bundles lib test_temp scripts src/generated_contract_wrappers",
|
||||
"build:umd:prod": "NODE_ENV=production webpack",
|
||||
"build:commonjs": "tsc && copyfiles -u 2 './src/compact_artifacts/**/*.json' ./lib/src/compact_artifacts && copyfiles -u 3 './lib/src/monorepo_scripts/**/*' ./scripts",
|
||||
"test:commonjs": "run-s build:commonjs run_mocha",
|
||||
"run_mocha": "mocha lib/test/**/*_test.js lib/test/global_hooks.js --timeout 10000 --bail --exit",
|
||||
"run_mocha": "mocha --require source-map-support/register lib/test/**/*_test.js lib/test/global_hooks.js --timeout 10000 --bail --exit",
|
||||
"manual:postpublish": "yarn build; node ./scripts/postpublish.js",
|
||||
"docs:stage": "node scripts/stage_docs.js",
|
||||
"docs:json": "typedoc --excludePrivate --excludeExternals --target ES5 --json $JSON_FILE_PATH $PROJECT_FILES",
|
||||
@@ -44,6 +46,7 @@
|
||||
"docPublishConfigs": {
|
||||
"extraFileIncludes": [
|
||||
"../types/src/index.ts",
|
||||
"../ethereum-types/src/index.ts",
|
||||
"../contract-wrappers/src/types.ts",
|
||||
"../contract-wrappers/src/contract_wrappers/ether_token_wrapper.ts",
|
||||
"../contract-wrappers/src/contract_wrappers/exchange_wrapper.ts",
|
||||
@@ -51,9 +54,9 @@
|
||||
"../contract-wrappers/src/contract_wrappers/token_transfer_proxy_wrapper.ts",
|
||||
"../contract-wrappers/src/contract_wrappers/token_wrapper.ts",
|
||||
"../order-watcher/src/order_watcher/order_watcher.ts",
|
||||
"./src/contract_wrappers/generated/ether_token.ts",
|
||||
"./src/contract_wrappers/generated/token.ts",
|
||||
"./src/contract_wrappers/generated/exchange.ts"
|
||||
"./src/generated_contract_wrappers/ether_token.ts",
|
||||
"./src/generated_contract_wrappers/token.ts",
|
||||
"./src/generated_contract_wrappers/exchange.ts"
|
||||
],
|
||||
"s3BucketPath": "s3://doc-jsons/0x.js/",
|
||||
"s3StagingBucketPath": "s3://staging-doc-jsons/0x.js/"
|
||||
@@ -88,7 +91,6 @@
|
||||
"npm-run-all": "^4.1.2",
|
||||
"nyc": "^11.0.1",
|
||||
"opn-cli": "^3.1.0",
|
||||
"prettier": "^1.11.1",
|
||||
"shx": "^0.2.2",
|
||||
"sinon": "^4.0.0",
|
||||
"source-map-support": "^0.5.0",
|
||||
@@ -101,13 +103,14 @@
|
||||
"@0xproject/assert": "^0.2.10",
|
||||
"@0xproject/base-contract": "^0.3.2",
|
||||
"@0xproject/contract-wrappers": "^0.0.2",
|
||||
"@0xproject/order-utils": "^0.0.5",
|
||||
"@0xproject/order-utils": "0.0.5",
|
||||
"@0xproject/order-watcher": "^0.0.2",
|
||||
"@0xproject/sol-compiler": "^0.5.0",
|
||||
"@0xproject/types": "^0.7.0",
|
||||
"@0xproject/types": "0.7.0",
|
||||
"@0xproject/typescript-typings": "^0.3.2",
|
||||
"@0xproject/utils": "^0.6.2",
|
||||
"@0xproject/web3-wrapper": "^0.6.4",
|
||||
"ethereum-types": "^0.0.1",
|
||||
"ethers": "^3.0.15",
|
||||
"lodash": "^4.17.4"
|
||||
},
|
||||
|
@@ -19,7 +19,6 @@ import { OrderWatcher, OrderWatcherConfig } from '@0xproject/order-watcher';
|
||||
import { ECSignature, Order, Provider, SignedOrder, TransactionReceiptWithDecodedLogs } from '@0xproject/types';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { constants } from './utils/constants';
|
||||
|
||||
|
@@ -1,16 +1,3 @@
|
||||
import {
|
||||
BlockParam,
|
||||
BlockParamLiteral,
|
||||
ContractAbi,
|
||||
ContractEventArg,
|
||||
ExchangeContractErrs,
|
||||
FilterObject,
|
||||
LogWithDecodedArgs,
|
||||
Order,
|
||||
OrderState,
|
||||
SignedOrder,
|
||||
} from '@0xproject/types';
|
||||
|
||||
export enum InternalZeroExError {
|
||||
NoAbiDecoder = 'NO_ABI_DECODER',
|
||||
ZrxNotInTokenRegistry = 'ZRX_NOT_IN_TOKEN_REGISTRY',
|
||||
|
@@ -1,5 +1,3 @@
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
|
||||
export const constants = {
|
||||
NULL_ADDRESS: '0x0000000000000000000000000000000000000000',
|
||||
TESTRPC_NETWORK_ID: 50,
|
||||
|
@@ -1,14 +1,12 @@
|
||||
import { ContractWrappers } from '@0xproject/contract-wrappers';
|
||||
import { BlockchainLifecycle, devConstants, web3Factory } from '@0xproject/dev-utils';
|
||||
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import * as chai from 'chai';
|
||||
import * as _ from 'lodash';
|
||||
import 'make-promises-safe';
|
||||
import 'mocha';
|
||||
import * as path from 'path';
|
||||
import * as Sinon from 'sinon';
|
||||
|
||||
import { ApprovalContractEventArgs, LogWithDecodedArgs, Order, TokenEvents, ZeroEx } from '../src';
|
||||
import { ApprovalContractEventArgs, LogWithDecodedArgs, TokenEvents, ZeroEx } from '../src';
|
||||
|
||||
import { chaiSetup } from './utils/chai_setup';
|
||||
import { constants } from './utils/constants';
|
||||
@@ -137,6 +135,7 @@ describe('ZeroEx library', () => {
|
||||
const proxyAddress = zeroEx.proxy.getContractAddress();
|
||||
const txHash = await zeroEx.token.setUnlimitedProxyAllowanceAsync(zrxTokenAddress, coinbase);
|
||||
const txReceiptWithDecodedLogs = await zeroEx.awaitTransactionMinedAsync(txHash);
|
||||
// tslint:disable-next-line:no-unnecessary-type-assertion
|
||||
const log = txReceiptWithDecodedLogs.logs[0] as LogWithDecodedArgs<ApprovalContractEventArgs>;
|
||||
expect(log.event).to.be.equal(TokenEvents.Approval);
|
||||
expect(log.args._owner).to.be.equal(coinbase);
|
||||
|
@@ -1,5 +1,4 @@
|
||||
import { web3Factory } from '@0xproject/dev-utils';
|
||||
import * as fs from 'fs';
|
||||
import 'make-promises-safe';
|
||||
|
||||
import { ZeroEx } from '../src';
|
||||
@@ -15,7 +14,7 @@ const TIMEOUT = 10000;
|
||||
describe('Artifacts', () => {
|
||||
describe('contracts are deployed on kovan', () => {
|
||||
const kovanRpcUrl = constants.KOVAN_RPC_URL;
|
||||
const provider = web3Factory.create({ rpcUrl: kovanRpcUrl }).currentProvider;
|
||||
const provider = web3Factory.getRpcProvider({ rpcUrl: kovanRpcUrl });
|
||||
const config = {
|
||||
networkId: constants.KOVAN_NETWORK_ID,
|
||||
};
|
||||
@@ -32,7 +31,7 @@ describe('Artifacts', () => {
|
||||
});
|
||||
describe('contracts are deployed on ropsten', () => {
|
||||
const ropstenRpcUrl = constants.ROPSTEN_RPC_URL;
|
||||
const provider = web3Factory.create({ rpcUrl: ropstenRpcUrl }).currentProvider;
|
||||
const provider = web3Factory.getRpcProvider({ rpcUrl: ropstenRpcUrl });
|
||||
const config = {
|
||||
networkId: constants.ROPSTEN_NETWORK_ID,
|
||||
};
|
||||
|
@@ -1,8 +1,6 @@
|
||||
import { devConstants } from '@0xproject/dev-utils';
|
||||
import { runMigrationsAsync } from '@0xproject/migrations';
|
||||
import * as path from 'path';
|
||||
import { runV1MigrationsAsync } from '@0xproject/migrations';
|
||||
|
||||
import { constants } from './utils/constants';
|
||||
import { provider } from './utils/web3_wrapper';
|
||||
|
||||
before('migrate contracts', async function(): Promise<void> {
|
||||
@@ -11,9 +9,9 @@ before('migrate contracts', async function(): Promise<void> {
|
||||
const mochaTestTimeoutMs = 20000;
|
||||
this.timeout(mochaTestTimeoutMs);
|
||||
const txDefaults = {
|
||||
gas: devConstants.GAS_ESTIMATE,
|
||||
gas: devConstants.GAS_LIMIT,
|
||||
from: devConstants.TESTRPC_FIRST_ADDRESS,
|
||||
};
|
||||
const artifactsDir = `../migrations/artifacts/1.0.0`;
|
||||
await runMigrationsAsync(provider, artifactsDir, txDefaults);
|
||||
await runV1MigrationsAsync(provider, artifactsDir, txDefaults);
|
||||
});
|
||||
|
@@ -1,9 +1,8 @@
|
||||
import { devConstants, web3Factory } from '@0xproject/dev-utils';
|
||||
import { web3Factory } from '@0xproject/dev-utils';
|
||||
import { Provider } from '@0xproject/types';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
|
||||
const web3 = web3Factory.create({ shouldUseInProcessGanache: true });
|
||||
const provider: Provider = web3.currentProvider;
|
||||
const web3Wrapper = new Web3Wrapper(web3.currentProvider);
|
||||
const provider: Provider = web3Factory.getRpcProvider({ shouldUseInProcessGanache: true });
|
||||
const web3Wrapper = new Web3Wrapper(provider);
|
||||
|
||||
export { provider, web3Wrapper };
|
||||
|
@@ -4,8 +4,7 @@ This package allows you to generate TypeScript contract wrappers from ABI files.
|
||||
It's heavily inspired by [Geth abigen](https://github.com/ethereum/go-ethereum/wiki/Native-DApps:-Go-bindings-to-Ethereum-contracts) but takes a different approach.
|
||||
You can write your custom handlebars templates which will allow you to seamlessly integrate the generated code into your existing codebase with existing conventions.
|
||||
|
||||
For an example of the generated [wrapper files](https://github.com/0xProject/0x-monorepo/tree/development/packages/0x.js/src/contract_wrappers/generated) check out 0x.js.
|
||||
[Here](https://github.com/0xProject/0x-monorepo/tree/development/packages/0x.js/contract_templates) are the templates used to generate those files.
|
||||
[Here](https://github.com/0xProject/0x-monorepo/tree/development/packages/0x.js/contract_templates) are the templates used to generate the contract wrappers used by 0x.js.e
|
||||
|
||||
## Installation
|
||||
|
||||
@@ -45,7 +44,7 @@ You need to also specify the location of your main template used for every contr
|
||||
|
||||
## How to write custom templates?
|
||||
|
||||
The best way to get started is to copy [0x.js templates](https://github.com/0xProject/0x-monorepo/tree/development/packages/0x.js/contract_templates) and start adjusting them for your needs.
|
||||
The best way to get started is to copy [0x.js templates](https://github.com/0xProject/0x-monorepo/tree/development/packages/contract_templates) and start adjusting them for your needs.
|
||||
We use [handlebars](http://handlebarsjs.com/) template engine under the hood.
|
||||
You need to have a master template called `contract.mustache`. it will be used to generate each contract wrapper. Although - you don't need and probably shouldn't write all your logic in a single template file. You can write [partial templates](http://handlebarsjs.com/partials.html) and as long as they are within a partials folder - they will be registered and available.
|
||||
|
||||
|
@@ -8,7 +8,7 @@
|
||||
"main": "lib/index.js",
|
||||
"types": "lib/index.d.ts",
|
||||
"scripts": {
|
||||
"watch": "tsc -w",
|
||||
"watch_without_deps": "tsc -w",
|
||||
"lint": "tslint --project .",
|
||||
"clean": "shx rm -rf lib scripts",
|
||||
"build": "tsc && copyfiles -u 2 './lib/monorepo_scripts/**/*' ./scripts",
|
||||
@@ -27,9 +27,9 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/packages/abi-gen/README.md",
|
||||
"dependencies": {
|
||||
"@0xproject/types": "^0.7.0",
|
||||
"@0xproject/typescript-typings": "^0.3.2",
|
||||
"@0xproject/utils": "^0.6.2",
|
||||
"ethereum-types": "^0.0.1",
|
||||
"chalk": "^2.3.0",
|
||||
"glob": "^7.1.2",
|
||||
"handlebars": "^4.0.11",
|
||||
|
@@ -1,8 +1,8 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import { AbiDefinition, ConstructorAbi, EventAbi, MethodAbi } from '@0xproject/types';
|
||||
import { abiUtils, logUtils } from '@0xproject/utils';
|
||||
import chalk from 'chalk';
|
||||
import { AbiDefinition, ConstructorAbi, EventAbi, MethodAbi } from 'ethereum-types';
|
||||
import * as fs from 'fs';
|
||||
import { sync as globSync } from 'glob';
|
||||
import * as Handlebars from 'handlebars';
|
||||
@@ -12,7 +12,7 @@ import * as yargs from 'yargs';
|
||||
|
||||
import toSnakeCase = require('to-snake-case');
|
||||
|
||||
import { ContextData, ContractsBackend, Method, ParamKind } from './types';
|
||||
import { ContextData, ContractsBackend, ParamKind } from './types';
|
||||
import { utils } from './utils';
|
||||
|
||||
const ABI_TYPE_CONSTRUCTOR = 'constructor';
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { EventAbi, MethodAbi } from '@0xproject/types';
|
||||
import { EventAbi, MethodAbi } from 'ethereum-types';
|
||||
|
||||
export enum ParamKind {
|
||||
Input = 'input',
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { AbiType, ConstructorAbi, DataItem } from '@0xproject/types';
|
||||
import { AbiType, ConstructorAbi, DataItem } from 'ethereum-types';
|
||||
import * as fs from 'fs';
|
||||
import * as _ from 'lodash';
|
||||
import * as path from 'path';
|
||||
@@ -56,7 +56,7 @@ export const utils = {
|
||||
const componentType = `${component.name}: ${componentValueType}`;
|
||||
return componentType;
|
||||
});
|
||||
const tsType = `{${componentsType}}`;
|
||||
const tsType = `{${componentsType.join(';')}}`;
|
||||
return tsType;
|
||||
}
|
||||
throw new Error(`Unknown Solidity type found: ${solType}`);
|
||||
|
@@ -8,13 +8,14 @@
|
||||
"main": "lib/src/index.js",
|
||||
"types": "lib/src/index.d.ts",
|
||||
"scripts": {
|
||||
"watch": "tsc -w",
|
||||
"watch_without_deps": "tsc -w",
|
||||
"build": "tsc && copyfiles -u 3 './lib/src/monorepo_scripts/**/*' ./scripts",
|
||||
"clean": "shx rm -rf lib test_temp scripts",
|
||||
"lint": "tslint --project .",
|
||||
"run_mocha": "mocha lib/test/**/*_test.js --exit",
|
||||
"run_mocha": "mocha --require source-map-support/register lib/test/**/*_test.js --exit",
|
||||
"prepublishOnly": "run-p build",
|
||||
"test": "run-s clean build run_mocha",
|
||||
"test": "yarn run_mocha",
|
||||
"rebuild_and_test": "run-s clean build test",
|
||||
"test:coverage": "nyc npm run test --all && yarn coverage:report:lcov",
|
||||
"coverage:report:lcov": "nyc report --reporter=text-lcov > coverage/lcov.info",
|
||||
"test:circleci": "yarn test:coverage",
|
||||
@@ -47,7 +48,7 @@
|
||||
"typescript": "2.7.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0xproject/json-schemas": "^0.7.24",
|
||||
"@0xproject/json-schemas": "0.7.22",
|
||||
"@0xproject/typescript-typings": "^0.3.2",
|
||||
"@0xproject/utils": "^0.6.2",
|
||||
"lodash": "^4.17.4",
|
||||
|
@@ -64,6 +64,9 @@ export const assert = {
|
||||
this.assert(isWeb3Provider, this.typeAssertionMessage(variableName, 'Provider', value));
|
||||
},
|
||||
doesConformToSchema(variableName: string, value: any, schema: Schema, subSchemas?: Schema[]): void {
|
||||
if (_.isUndefined(value)) {
|
||||
throw new Error(`${variableName} can't be undefined`);
|
||||
}
|
||||
const schemaValidator = new SchemaValidator();
|
||||
if (!_.isUndefined(subSchemas)) {
|
||||
_.map(subSchemas, schemaValidator.addSchema.bind(schemaValidator));
|
||||
|
@@ -8,15 +8,16 @@
|
||||
"main": "lib/src/index.js",
|
||||
"types": "lib/src/index.d.ts",
|
||||
"scripts": {
|
||||
"watch": "tsc -w",
|
||||
"watch_without_deps": "tsc -w",
|
||||
"build": "tsc && copyfiles -u 2 './lib/monorepo_scripts/**/*' ./scripts",
|
||||
"clean": "shx rm -rf lib scripts",
|
||||
"test": "run-s clean build run_mocha",
|
||||
"test": "yarn run_mocha",
|
||||
"rebuild_and_test": "run-s clean build test",
|
||||
"test:circleci": "yarn test:coverage",
|
||||
"run_mocha": "mocha lib/test/**/*_test.js --bail --exit",
|
||||
"run_mocha": "mocha --require source-map-support/register lib/test/**/*_test.js --bail --exit",
|
||||
"test:coverage": "nyc npm run test --all && yarn coverage:report:lcov",
|
||||
"coverage:report:lcov": "nyc report --reporter=text-lcov > coverage/lcov.info",
|
||||
"lint": "tslint --project .",
|
||||
"lint": "tslint --project . --exclude **/src/contract_wrappers/**/*",
|
||||
"manual:postpublish": "yarn build; node ./scripts/postpublish.js"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
@@ -42,7 +43,7 @@
|
||||
"typescript": "2.7.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0xproject/types": "^0.7.0",
|
||||
"ethereum-types": "^0.0.1",
|
||||
"@0xproject/typescript-typings": "^0.3.2",
|
||||
"@0xproject/utils": "^0.6.2",
|
||||
"@0xproject/web3-wrapper": "^0.6.4",
|
||||
|
@@ -1,3 +1,5 @@
|
||||
import { abiUtils, BigNumber } from '@0xproject/utils';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
import {
|
||||
AbiDefinition,
|
||||
AbiType,
|
||||
@@ -8,9 +10,7 @@ import {
|
||||
Provider,
|
||||
TxData,
|
||||
TxDataPayable,
|
||||
} from '@0xproject/types';
|
||||
import { abiUtils, BigNumber } from '@0xproject/utils';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
} from 'ethereum-types';
|
||||
import * as ethers from 'ethers';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
@@ -37,13 +37,14 @@ export class BaseContract {
|
||||
protected static _lowercaseAddress(type: string, value: string): string {
|
||||
return type === 'address' ? value.toLowerCase() : value;
|
||||
}
|
||||
protected static _bigNumberToString(type: string, value: any): any {
|
||||
protected static _bigNumberToString(_type: string, value: any): any {
|
||||
return _.isObject(value) && value.isBigNumber ? value.toString() : value;
|
||||
}
|
||||
protected static _lookupConstructorAbi(abi: ContractAbi): ConstructorAbi {
|
||||
const constructorAbiIfExists = _.find(
|
||||
abi,
|
||||
(abiDefinition: AbiDefinition) => abiDefinition.type === AbiType.Constructor,
|
||||
// tslint:disable-next-line:no-unnecessary-type-assertion
|
||||
) as ConstructorAbi | undefined;
|
||||
if (!_.isUndefined(constructorAbiIfExists)) {
|
||||
return constructorAbiIfExists;
|
||||
@@ -59,7 +60,7 @@ export class BaseContract {
|
||||
return defaultConstructorAbi;
|
||||
}
|
||||
}
|
||||
protected static _bnToBigNumber(type: string, value: any): any {
|
||||
protected static _bnToBigNumber(_type: string, value: any): any {
|
||||
return _.isObject(value) && value._bn ? new BigNumber(value.toString()) : value;
|
||||
}
|
||||
protected static async _applyDefaultsToTxDataAsync<T extends Partial<TxData | TxDataPayable>>(
|
||||
@@ -79,8 +80,7 @@ export class BaseContract {
|
||||
// Awaiting https://github.com/Microsoft/TypeScript/pull/13288 to be merged
|
||||
} as any;
|
||||
if (_.isUndefined(txDataWithDefaults.gas) && !_.isUndefined(estimateGasAsync)) {
|
||||
const estimatedGas = await estimateGasAsync(txData);
|
||||
txDataWithDefaults.gas = estimatedGas;
|
||||
txDataWithDefaults.gas = await estimateGasAsync(txData);
|
||||
}
|
||||
return txDataWithDefaults;
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { DataItem } from '@0xproject/types';
|
||||
import { DataItem } from 'ethereum-types';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
// tslint:disable-next-line:completed-docs
|
||||
|
@@ -15,13 +15,14 @@
|
||||
"main": "lib/src/index.js",
|
||||
"types": "lib/src/index.d.ts",
|
||||
"scripts": {
|
||||
"watch": "tsc -w",
|
||||
"watch_without_deps": "tsc -w",
|
||||
"build": "tsc && copyfiles -u 3 './lib/src/monorepo_scripts/**/*' ./scripts",
|
||||
"clean": "shx rm -rf lib test_temp scripts",
|
||||
"copy_test_fixtures": "copyfiles -u 2 './test/fixtures/**/*.json' ./lib/test/fixtures",
|
||||
"lint": "tslint --project .",
|
||||
"run_mocha": "mocha lib/test/**/*_test.js --exit",
|
||||
"test": "run-s clean build copy_test_fixtures run_mocha",
|
||||
"run_mocha": "mocha --require source-map-support/register lib/test/**/*_test.js --exit",
|
||||
"test": "run-s copy_test_fixtures run_mocha",
|
||||
"rebuild_and_test": "run-s clean build test",
|
||||
"test:coverage": "nyc npm run test --all && yarn coverage:report:lcov",
|
||||
"coverage:report:lcov": "nyc report --reporter=text-lcov > coverage/lcov.info",
|
||||
"test:circleci": "yarn test:coverage",
|
||||
@@ -51,7 +52,7 @@
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/packages/connect/README.md",
|
||||
"dependencies": {
|
||||
"@0xproject/assert": "^0.2.10",
|
||||
"@0xproject/json-schemas": "^0.7.24",
|
||||
"@0xproject/json-schemas": "0.7.22",
|
||||
"@0xproject/types": "^0.7.0",
|
||||
"@0xproject/typescript-typings": "^0.3.2",
|
||||
"@0xproject/utils": "^0.6.2",
|
||||
|
@@ -48,7 +48,7 @@ export class HttpClient implements Client {
|
||||
return '';
|
||||
}
|
||||
// format params into a form the api expects
|
||||
const formattedParams = _.mapKeys(params, (value: any, key: string) => {
|
||||
const formattedParams = _.mapKeys(params, (_value: any, key: string) => {
|
||||
return _.get(OPTS_TO_QUERY_FIELD_MAP, key, key);
|
||||
});
|
||||
// stringify the formatted object
|
||||
|
@@ -17,4 +17,4 @@ export {
|
||||
WebSocketOrderbookChannelConfig,
|
||||
} from './types';
|
||||
|
||||
export { ECSignature, Order, SignedOrder } from '@0xproject/types';
|
||||
export { Order, SignedOrder } from '@0xproject/types';
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { ECSignature, Order, SignedOrder } from '@0xproject/types';
|
||||
import { SignedOrder } from '@0xproject/types';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
|
||||
export interface Client {
|
||||
|
@@ -1,7 +1,6 @@
|
||||
import { assert } from '@0xproject/assert';
|
||||
import { schemas } from '@0xproject/json-schemas';
|
||||
import { SignedOrder } from '@0xproject/types';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { FeesResponse, OrderbookResponse, TokenPairsItem } from '../types';
|
||||
|
||||
|
@@ -78,7 +78,7 @@ export class WebSocketOrderbookChannel implements OrderbookChannel {
|
||||
connection.on(WebsocketConnectionEventType.Error, wsError => {
|
||||
handler.onError(this, subscriptionOpts, wsError);
|
||||
});
|
||||
connection.on(WebsocketConnectionEventType.Close, (code: number, desc: string) => {
|
||||
connection.on(WebsocketConnectionEventType.Close, (_code: number, _desc: string) => {
|
||||
handler.onClose(this, subscriptionOpts);
|
||||
});
|
||||
connection.on(WebsocketConnectionEventType.Message, message => {
|
||||
|
@@ -1,4 +1,12 @@
|
||||
[
|
||||
{
|
||||
"version": "0.1.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Expose 'abi' ContractAbi property on all contract wrappers"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "0.0.2",
|
||||
"changes": [
|
||||
|
@@ -11,23 +11,25 @@
|
||||
"main": "lib/src/index.js",
|
||||
"types": "lib/src/index.d.ts",
|
||||
"scripts": {
|
||||
"watch": "tsc -w",
|
||||
"prebuild": "run-s clean generate_contract_wrappers",
|
||||
"watch_without_deps": "yarn pre_build && tsc -w",
|
||||
"build": "yarn pre_build && tsc && copyfiles -u 3 './lib/src/monorepo_scripts/**/*' ./scripts",
|
||||
"pre_build": "run-s generate_contract_wrappers update_test_artifacts update_compact_artifacts",
|
||||
"generate_contract_wrappers": "abi-gen --abis 'src/compact_artifacts/@(Exchange|Token|TokenTransferProxy|EtherToken|TokenRegistry|DummyToken).json' --template ../contract_templates/contract.handlebars --partials '../contract_templates/partials/**/*.handlebars' --output src/contract_wrappers/generated --backend ethers && prettier --write 'src/contract_wrappers/generated/**.ts'",
|
||||
"lint": "tslint --project .",
|
||||
"lint": "tslint --project . --exclude **/src/contract_wrappers/**/* --exclude **/lib/**/*",
|
||||
"test:circleci": "run-s test:coverage",
|
||||
"test": "run-s clean build run_mocha",
|
||||
"test": "yarn run_mocha",
|
||||
"rebuild_and_test": "run-s build test",
|
||||
"test:coverage": "nyc npm run test --all && yarn coverage:report:lcov",
|
||||
"coverage:report:lcov": "nyc report --reporter=text-lcov > coverage/lcov.info",
|
||||
"update_artifacts": "for i in ${npm_package_config_contracts}; do copyfiles -u 4 ../migrations/artifacts/1.0.0/$i.json test/artifacts; done;",
|
||||
"update_compact_artifacts": "copyfiles -u 2 './src/compact_artifacts/**/*.json' ./lib/src/compact_artifacts",
|
||||
"update_test_artifacts": "for i in ${npm_package_config_contracts}; do copyfiles -u 4 ../migrations/artifacts/1.0.0/$i.json test/artifacts; done;",
|
||||
"clean": "shx rm -rf _bundles lib test_temp scripts test/artifacts src/contract_wrappers/generated",
|
||||
"build": "tsc && yarn update_artifacts && copyfiles -u 2 './src/compact_artifacts/**/*.json' ./lib/src/compact_artifacts && copyfiles -u 3 './lib/src/monorepo_scripts/**/*' ./scripts",
|
||||
"run_mocha": "mocha lib/test/**/*_test.js lib/test/global_hooks.js --timeout 10000 --bail --exit",
|
||||
"run_mocha": "mocha --require source-map-support/register lib/test/**/*_test.js lib/test/global_hooks.js --timeout 10000 --bail --exit",
|
||||
"manual:postpublish": "yarn build; node ./scripts/postpublish.js"
|
||||
},
|
||||
"config": {
|
||||
"compact_artifacts": "Exchange DummyToken ZRXToken Token EtherToken TokenTransferProxy TokenRegistry",
|
||||
"contracts": "Exchange DummyToken ZRXToken Token WETH9 TokenTransferProxy MultiSigWallet MultiSigWalletWithTimeLock MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress MaliciousToken TokenRegistry Arbitrage EtherDelta AccountLevels",
|
||||
"contracts": "Exchange DummyToken ZRXToken Token WETH9 TokenTransferProxy_v1 MultiSigWallet MultiSigWalletWithTimeLock MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress MaliciousToken TokenRegistry Arbitrage EtherDelta AccountLevels",
|
||||
"postpublish": {
|
||||
"assets": [
|
||||
"packages/contract-wrappers/_bundles/index.js",
|
||||
@@ -67,7 +69,6 @@
|
||||
"npm-run-all": "^4.1.2",
|
||||
"nyc": "^11.0.1",
|
||||
"opn-cli": "^3.1.0",
|
||||
"prettier": "^1.11.1",
|
||||
"shx": "^0.2.2",
|
||||
"sinon": "^4.0.0",
|
||||
"source-map-support": "^0.5.0",
|
||||
@@ -79,12 +80,13 @@
|
||||
"@0xproject/assert": "^0.2.10",
|
||||
"@0xproject/base-contract": "^0.3.2",
|
||||
"@0xproject/fill-scenarios": "^0.0.2",
|
||||
"@0xproject/json-schemas": "^0.7.24",
|
||||
"@0xproject/order-utils": "^0.0.5",
|
||||
"@0xproject/types": "^0.7.0",
|
||||
"@0xproject/json-schemas": "0.7.22",
|
||||
"@0xproject/order-utils": "0.0.5",
|
||||
"@0xproject/types": "0.7.0",
|
||||
"@0xproject/typescript-typings": "^0.3.2",
|
||||
"@0xproject/utils": "^0.6.2",
|
||||
"@0xproject/web3-wrapper": "^0.6.4",
|
||||
"ethereum-types": "^0.0.1",
|
||||
"ethereumjs-blockstream": "^2.0.6",
|
||||
"ethereumjs-util": "^5.1.1",
|
||||
"ethers": "^3.0.15",
|
||||
|
@@ -0,0 +1,11 @@
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
|
||||
export abstract class AbstractBalanceAndProxyAllowanceLazyStore {
|
||||
public abstract async getBalanceAsync(tokenAddress: string, userAddress: string): Promise<BigNumber>;
|
||||
public abstract async getProxyAllowanceAsync(tokenAddress: string, userAddress: string): Promise<BigNumber>;
|
||||
public abstract setBalance(tokenAddress: string, userAddress: string, balance: BigNumber): void;
|
||||
public abstract deleteBalance(tokenAddress: string, userAddress: string): void;
|
||||
public abstract setProxyAllowance(tokenAddress: string, userAddress: string, proxyAllowance: BigNumber): void;
|
||||
public abstract deleteProxyAllowance(tokenAddress: string, userAddress: string): void;
|
||||
public abstract deleteAll(): void;
|
||||
}
|
@@ -7,7 +7,7 @@ import {
|
||||
LogWithDecodedArgs,
|
||||
RawLog,
|
||||
} from '@0xproject/types';
|
||||
import { AbiDecoder, intervalUtils } from '@0xproject/utils';
|
||||
import { intervalUtils } from '@0xproject/utils';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
import { Block, BlockAndLogStreamer } from 'ethereumjs-blockstream';
|
||||
import * as _ from 'lodash';
|
||||
@@ -35,7 +35,8 @@ const CONTRACT_NAME_TO_NOT_FOUND_ERROR: {
|
||||
Exchange: ContractWrappersError.ExchangeContractDoesNotExist,
|
||||
};
|
||||
|
||||
export class ContractWrapper {
|
||||
export abstract class ContractWrapper {
|
||||
public abstract abi: ContractAbi;
|
||||
protected _web3Wrapper: Web3Wrapper;
|
||||
protected _networkId: number;
|
||||
private _blockAndLogStreamerIfExists?: BlockAndLogStreamer;
|
||||
@@ -185,6 +186,7 @@ export class ContractWrapper {
|
||||
this._unsubscribe(filterToken, err);
|
||||
});
|
||||
}
|
||||
// tslint:disable-next-line:no-unused-variable
|
||||
private _setNetworkId(networkId: number): void {
|
||||
this._networkId = networkId;
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import { schemas } from '@0xproject/json-schemas';
|
||||
import { LogWithDecodedArgs } from '@0xproject/types';
|
||||
import { AbiDecoder, BigNumber } from '@0xproject/utils';
|
||||
import { ContractAbi, LogWithDecodedArgs } from '@0xproject/types';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
@@ -17,6 +17,7 @@ import { TokenWrapper } from './token_wrapper';
|
||||
* The caller can convert ETH into the equivalent number of wrapped ETH ERC20 tokens and back.
|
||||
*/
|
||||
export class EtherTokenWrapper extends ContractWrapper {
|
||||
public abi: ContractAbi = artifacts.EtherToken.abi;
|
||||
private _etherTokenContractsByAddress: {
|
||||
[address: string]: EtherTokenContract;
|
||||
} = {};
|
||||
@@ -181,6 +182,7 @@ export class EtherTokenWrapper extends ContractWrapper {
|
||||
: networkSpecificArtifact.address;
|
||||
return contractAddressIfExists;
|
||||
}
|
||||
// tslint:disable-next-line:no-unused-variable
|
||||
private _invalidateContractInstance(): void {
|
||||
this.unsubscribeAll();
|
||||
this._etherTokenContractsByAddress = {};
|
||||
|
@@ -2,24 +2,24 @@ import { schemas } from '@0xproject/json-schemas';
|
||||
import { formatters, getOrderHashHex, OrderStateUtils } from '@0xproject/order-utils';
|
||||
import {
|
||||
BlockParamLiteral,
|
||||
ContractAbi,
|
||||
DecodedLogArgs,
|
||||
ECSignature,
|
||||
ExchangeContractErrs,
|
||||
LogEntry,
|
||||
LogWithDecodedArgs,
|
||||
Order,
|
||||
OrderAddresses,
|
||||
OrderState,
|
||||
OrderValues,
|
||||
SignedOrder,
|
||||
} from '@0xproject/types';
|
||||
import { AbiDecoder, BigNumber } from '@0xproject/utils';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { artifacts } from '../artifacts';
|
||||
import { SimpleBalanceAndProxyAllowanceFetcher } from '../fetchers/simple_balance_and_proxy_allowance_fetcher';
|
||||
import { SimpleOrderFilledCancelledFetcher } from '../fetchers/simple_order_filled_cancelled_fetcher';
|
||||
import { BalanceAndProxyAllowanceLazyStore } from '../stores/balance_proxy_allowance_lazy_store';
|
||||
import {
|
||||
BlockRange,
|
||||
EventCallback,
|
||||
@@ -35,7 +35,6 @@ import { assert } from '../utils/assert';
|
||||
import { decorators } from '../utils/decorators';
|
||||
import { ExchangeTransferSimulator } from '../utils/exchange_transfer_simulator';
|
||||
import { OrderValidationUtils } from '../utils/order_validation_utils';
|
||||
import { utils } from '../utils/utils';
|
||||
|
||||
import { ContractWrapper } from './contract_wrapper';
|
||||
import {
|
||||
@@ -56,8 +55,9 @@ interface ExchangeContractErrCodesToMsgs {
|
||||
* events of the 0x Exchange smart contract.
|
||||
*/
|
||||
export class ExchangeWrapper extends ContractWrapper {
|
||||
public abi: ContractAbi = artifacts.Exchange.abi;
|
||||
private _exchangeContractIfExists?: ExchangeContract;
|
||||
private _orderValidationUtils: OrderValidationUtils;
|
||||
private _orderValidationUtilsIfExists?: OrderValidationUtils;
|
||||
private _tokenWrapper: TokenWrapper;
|
||||
private _exchangeContractErrCodesToMsg: ExchangeContractErrCodesToMsgs = {
|
||||
[ExchangeContractErrCodes.ERROR_FILL_EXPIRED]: ExchangeContractErrs.OrderFillExpired,
|
||||
@@ -78,7 +78,6 @@ export class ExchangeWrapper extends ContractWrapper {
|
||||
) {
|
||||
super(web3Wrapper, networkId);
|
||||
this._tokenWrapper = tokenWrapper;
|
||||
this._orderValidationUtils = new OrderValidationUtils(this);
|
||||
this._contractAddressIfExists = contractAddressIfExists;
|
||||
this._zrxContractAddressIfExists = zrxContractAddressIfExists;
|
||||
}
|
||||
@@ -180,8 +179,13 @@ export class ExchangeWrapper extends ContractWrapper {
|
||||
: orderTransactionOpts.shouldValidate;
|
||||
if (shouldValidate) {
|
||||
const zrxTokenAddress = this.getZRXTokenAddress();
|
||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
||||
await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
|
||||
const balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore(
|
||||
this._tokenWrapper,
|
||||
BlockParamLiteral.Latest,
|
||||
);
|
||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(balanceAndProxyAllowanceLazyStore);
|
||||
const orderValidationUtils = await this._getOrderValidationUtilsAsync();
|
||||
await orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
|
||||
exchangeTradeEmulator,
|
||||
signedOrder,
|
||||
fillTakerTokenAmount,
|
||||
@@ -255,9 +259,14 @@ export class ExchangeWrapper extends ContractWrapper {
|
||||
if (shouldValidate) {
|
||||
let filledTakerTokenAmount = new BigNumber(0);
|
||||
const zrxTokenAddress = this.getZRXTokenAddress();
|
||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
||||
const balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore(
|
||||
this._tokenWrapper,
|
||||
BlockParamLiteral.Latest,
|
||||
);
|
||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(balanceAndProxyAllowanceLazyStore);
|
||||
const orderValidationUtils = await this._getOrderValidationUtilsAsync();
|
||||
for (const signedOrder of signedOrders) {
|
||||
const singleFilledTakerTokenAmount = await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
|
||||
const singleFilledTakerTokenAmount = await orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
|
||||
exchangeTradeEmulator,
|
||||
signedOrder,
|
||||
fillTakerTokenAmount.minus(filledTakerTokenAmount),
|
||||
@@ -348,9 +357,14 @@ export class ExchangeWrapper extends ContractWrapper {
|
||||
: orderTransactionOpts.shouldValidate;
|
||||
if (shouldValidate) {
|
||||
const zrxTokenAddress = this.getZRXTokenAddress();
|
||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
||||
const balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore(
|
||||
this._tokenWrapper,
|
||||
BlockParamLiteral.Latest,
|
||||
);
|
||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(balanceAndProxyAllowanceLazyStore);
|
||||
const orderValidationUtils = await this._getOrderValidationUtilsAsync();
|
||||
for (const orderFillRequest of orderFillRequests) {
|
||||
await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
|
||||
await orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
|
||||
exchangeTradeEmulator,
|
||||
orderFillRequest.signedOrder,
|
||||
orderFillRequest.takerTokenFillAmount,
|
||||
@@ -424,8 +438,13 @@ export class ExchangeWrapper extends ContractWrapper {
|
||||
: orderTransactionOpts.shouldValidate;
|
||||
if (shouldValidate) {
|
||||
const zrxTokenAddress = this.getZRXTokenAddress();
|
||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
||||
await this._orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync(
|
||||
const balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore(
|
||||
this._tokenWrapper,
|
||||
BlockParamLiteral.Latest,
|
||||
);
|
||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(balanceAndProxyAllowanceLazyStore);
|
||||
const orderValidationUtils = await this._getOrderValidationUtilsAsync();
|
||||
await orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync(
|
||||
exchangeTradeEmulator,
|
||||
signedOrder,
|
||||
fillTakerTokenAmount,
|
||||
@@ -486,9 +505,14 @@ export class ExchangeWrapper extends ContractWrapper {
|
||||
: orderTransactionOpts.shouldValidate;
|
||||
if (shouldValidate) {
|
||||
const zrxTokenAddress = this.getZRXTokenAddress();
|
||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
||||
const balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore(
|
||||
this._tokenWrapper,
|
||||
BlockParamLiteral.Latest,
|
||||
);
|
||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(balanceAndProxyAllowanceLazyStore);
|
||||
const orderValidationUtils = await this._getOrderValidationUtilsAsync();
|
||||
for (const orderFillRequest of orderFillRequests) {
|
||||
await this._orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync(
|
||||
await orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync(
|
||||
exchangeTradeEmulator,
|
||||
orderFillRequest.signedOrder,
|
||||
orderFillRequest.takerTokenFillAmount,
|
||||
@@ -736,8 +760,13 @@ export class ExchangeWrapper extends ContractWrapper {
|
||||
assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
|
||||
const zrxTokenAddress = this.getZRXTokenAddress();
|
||||
const expectedFillTakerTokenAmount = !_.isUndefined(opts) ? opts.expectedFillTakerTokenAmount : undefined;
|
||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
||||
await this._orderValidationUtils.validateOrderFillableOrThrowAsync(
|
||||
const balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore(
|
||||
this._tokenWrapper,
|
||||
BlockParamLiteral.Latest,
|
||||
);
|
||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(balanceAndProxyAllowanceLazyStore);
|
||||
const orderValidationUtils = await this._getOrderValidationUtilsAsync();
|
||||
await orderValidationUtils.validateOrderFillableOrThrowAsync(
|
||||
exchangeTradeEmulator,
|
||||
signedOrder,
|
||||
zrxTokenAddress,
|
||||
@@ -762,8 +791,13 @@ export class ExchangeWrapper extends ContractWrapper {
|
||||
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
|
||||
const normalizedTakerAddress = takerAddress.toLowerCase();
|
||||
const zrxTokenAddress = this.getZRXTokenAddress();
|
||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
||||
await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
|
||||
const balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore(
|
||||
this._tokenWrapper,
|
||||
BlockParamLiteral.Latest,
|
||||
);
|
||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(balanceAndProxyAllowanceLazyStore);
|
||||
const orderValidationUtils = await this._getOrderValidationUtilsAsync();
|
||||
await orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
|
||||
exchangeTradeEmulator,
|
||||
signedOrder,
|
||||
fillTakerTokenAmount,
|
||||
@@ -809,8 +843,13 @@ export class ExchangeWrapper extends ContractWrapper {
|
||||
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
|
||||
const normalizedTakerAddress = takerAddress.toLowerCase();
|
||||
const zrxTokenAddress = this.getZRXTokenAddress();
|
||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
||||
await this._orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync(
|
||||
const balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore(
|
||||
this._tokenWrapper,
|
||||
BlockParamLiteral.Latest,
|
||||
);
|
||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(balanceAndProxyAllowanceLazyStore);
|
||||
const orderValidationUtils = await this._getOrderValidationUtilsAsync();
|
||||
await orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync(
|
||||
exchangeTradeEmulator,
|
||||
signedOrder,
|
||||
fillTakerTokenAmount,
|
||||
@@ -888,6 +927,7 @@ export class ExchangeWrapper extends ContractWrapper {
|
||||
const contractAddress = this._getContractAddress(artifacts.ZRX, this._zrxContractAddressIfExists);
|
||||
return contractAddress;
|
||||
}
|
||||
// tslint:disable:no-unused-variable
|
||||
private _invalidateContractInstances(): void {
|
||||
this.unsubscribeAll();
|
||||
delete this._exchangeContractIfExists;
|
||||
@@ -919,6 +959,15 @@ export class ExchangeWrapper extends ContractWrapper {
|
||||
const orderHashHex = await exchangeInstance.getOrderHash.callAsync(orderAddresses, orderValues);
|
||||
return orderHashHex;
|
||||
}
|
||||
private async _getOrderValidationUtilsAsync(): Promise<OrderValidationUtils> {
|
||||
if (!_.isUndefined(this._orderValidationUtilsIfExists)) {
|
||||
return this._orderValidationUtilsIfExists;
|
||||
}
|
||||
const exchangeContract = await this._getExchangeContractAsync();
|
||||
this._orderValidationUtilsIfExists = new OrderValidationUtils(exchangeContract);
|
||||
return this._orderValidationUtilsIfExists;
|
||||
}
|
||||
// tslint:enable:no-unused-variable
|
||||
private async _getExchangeContractAsync(): Promise<ExchangeContract> {
|
||||
if (!_.isUndefined(this._exchangeContractIfExists)) {
|
||||
return this._exchangeContractIfExists;
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { Token } from '@0xproject/types';
|
||||
import { ContractAbi, Token } from '@0xproject/types';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
@@ -14,6 +14,7 @@ import { TokenRegistryContract } from './generated/token_registry';
|
||||
* This class includes all the functionality related to interacting with the 0x Token Registry smart contract.
|
||||
*/
|
||||
export class TokenRegistryWrapper extends ContractWrapper {
|
||||
public abi: ContractAbi = artifacts.TokenRegistry.abi;
|
||||
private _tokenRegistryContractIfExists?: TokenRegistryContract;
|
||||
private _contractAddressIfExists?: string;
|
||||
private static _createTokenFromMetadata(metadata: TokenMetadata): Token | undefined {
|
||||
@@ -108,6 +109,7 @@ export class TokenRegistryWrapper extends ContractWrapper {
|
||||
const contractAddress = this._getContractAddress(artifacts.TokenRegistry, this._contractAddressIfExists);
|
||||
return contractAddress;
|
||||
}
|
||||
// tslint:disable-next-line:no-unused-variable
|
||||
private _invalidateContractInstance(): void {
|
||||
delete this._tokenRegistryContractIfExists;
|
||||
}
|
||||
|
@@ -1,4 +1,5 @@
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
import { ContractAbi } from '@0xproject/types';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { artifacts } from '../artifacts';
|
||||
@@ -11,6 +12,7 @@ import { TokenTransferProxyContract } from './generated/token_transfer_proxy';
|
||||
* This class includes the functionality related to interacting with the TokenTransferProxy contract.
|
||||
*/
|
||||
export class TokenTransferProxyWrapper extends ContractWrapper {
|
||||
public abi: ContractAbi = artifacts.TokenTransferProxy.abi;
|
||||
private _tokenTransferProxyContractIfExists?: TokenTransferProxyContract;
|
||||
private _contractAddressIfExists?: string;
|
||||
constructor(web3Wrapper: Web3Wrapper, networkId: number, contractAddressIfExists?: string) {
|
||||
@@ -49,6 +51,7 @@ export class TokenTransferProxyWrapper extends ContractWrapper {
|
||||
const contractAddress = this._getContractAddress(artifacts.TokenTransferProxy, this._contractAddressIfExists);
|
||||
return contractAddress;
|
||||
}
|
||||
// tslint:disable-next-line:no-unused-variable
|
||||
private _invalidateContractInstance(): void {
|
||||
delete this._tokenTransferProxyContractIfExists;
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import { schemas } from '@0xproject/json-schemas';
|
||||
import { LogWithDecodedArgs } from '@0xproject/types';
|
||||
import { AbiDecoder, BigNumber } from '@0xproject/utils';
|
||||
import { ContractAbi, LogWithDecodedArgs } from '@0xproject/types';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
@@ -26,6 +26,7 @@ import { TokenTransferProxyWrapper } from './token_transfer_proxy_wrapper';
|
||||
* to the 0x Proxy smart contract.
|
||||
*/
|
||||
export class TokenWrapper extends ContractWrapper {
|
||||
public abi: ContractAbi = artifacts.Token.abi;
|
||||
public UNLIMITED_ALLOWANCE_IN_BASE_UNITS = constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS;
|
||||
private _tokenContractsByAddress: { [address: string]: TokenContract };
|
||||
private _tokenTransferProxyWrapper: TokenTransferProxyWrapper;
|
||||
@@ -414,6 +415,7 @@ export class TokenWrapper extends ContractWrapper {
|
||||
);
|
||||
return logs;
|
||||
}
|
||||
// tslint:disable-next-line:no-unused-variable
|
||||
private _invalidateContractInstances(): void {
|
||||
this.unsubscribeAll();
|
||||
this._tokenContractsByAddress = {};
|
||||
|
@@ -1,14 +1,14 @@
|
||||
import { AbstractBalanceAndProxyAllowanceFetcher } from '@0xproject/order-utils';
|
||||
import { BlockParamLiteral } from '@0xproject/types';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { AbstractBalanceAndProxyAllowanceLazyStore } from '../abstract/abstract_balance_and_proxy_allowance_lazy_store';
|
||||
import { TokenWrapper } from '../contract_wrappers/token_wrapper';
|
||||
|
||||
/**
|
||||
* Copy on read store for balances/proxyAllowances of tokens/accounts
|
||||
*/
|
||||
export class BalanceAndProxyAllowanceLazyStore implements AbstractBalanceAndProxyAllowanceFetcher {
|
||||
export class BalanceAndProxyAllowanceLazyStore implements AbstractBalanceAndProxyAllowanceLazyStore {
|
||||
private _tokenWrapper: TokenWrapper;
|
||||
private _defaultBlock: BlockParamLiteral;
|
||||
private _balance: {
|
||||
|
@@ -2,11 +2,7 @@ import { BigNumber } from '@0xproject/utils';
|
||||
|
||||
import {
|
||||
BlockParam,
|
||||
BlockParamLiteral,
|
||||
ContractAbi,
|
||||
ContractEventArg,
|
||||
ExchangeContractErrs,
|
||||
FilterObject,
|
||||
LogEntryEvent,
|
||||
LogWithDecodedArgs,
|
||||
Order,
|
||||
@@ -158,7 +154,7 @@ export interface MethodOpts {
|
||||
|
||||
/**
|
||||
* gasPrice: Gas price in Wei to use for a transaction
|
||||
* gasLimit: The amount of gas to send with a transaction
|
||||
* gasLimit: The amount of gas to send with a transaction (in Gwei)
|
||||
*/
|
||||
export interface TransactionOpts {
|
||||
gasPrice?: BigNumber;
|
||||
|
@@ -1,12 +1,11 @@
|
||||
import { assert as sharedAssert } from '@0xproject/assert';
|
||||
// We need those two unused imports because they're actually used by sharedAssert which gets injected here
|
||||
// tslint:disable-next-line:no-unused-variable
|
||||
// tslint:disable:no-unused-variable
|
||||
import { Schema } from '@0xproject/json-schemas';
|
||||
// tslint:disable-next-line:no-unused-variable
|
||||
import { ECSignature } from '@0xproject/types';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
import * as _ from 'lodash';
|
||||
// tslint:enable:no-unused-variable
|
||||
|
||||
import { isValidSignature } from '@0xproject/order-utils';
|
||||
|
||||
|
@@ -1,9 +1,8 @@
|
||||
import { BlockParamLiteral, ExchangeContractErrs } from '@0xproject/types';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { AbstractBalanceAndProxyAllowanceLazyStore } from '../abstract/abstract_balance_and_proxy_allowance_lazy_store';
|
||||
import { TokenWrapper } from '../contract_wrappers/token_wrapper';
|
||||
import { BalanceAndProxyAllowanceLazyStore } from '../stores/balance_proxy_allowance_lazy_store';
|
||||
import { TradeSide, TransferType } from '../types';
|
||||
import { constants } from '../utils/constants';
|
||||
|
||||
@@ -36,8 +35,7 @@ const ERR_MSG_MAPPING = {
|
||||
};
|
||||
|
||||
export class ExchangeTransferSimulator {
|
||||
private _store: BalanceAndProxyAllowanceLazyStore;
|
||||
private _UNLIMITED_ALLOWANCE_IN_BASE_UNITS: BigNumber;
|
||||
private _store: AbstractBalanceAndProxyAllowanceLazyStore;
|
||||
private static _throwValidationError(
|
||||
failureReason: FailureReason,
|
||||
tradeSide: TradeSide,
|
||||
@@ -46,9 +44,8 @@ export class ExchangeTransferSimulator {
|
||||
const errMsg = ERR_MSG_MAPPING[failureReason][tradeSide][transferType];
|
||||
throw new Error(errMsg);
|
||||
}
|
||||
constructor(token: TokenWrapper, defaultBlock: BlockParamLiteral) {
|
||||
this._store = new BalanceAndProxyAllowanceLazyStore(token, defaultBlock);
|
||||
this._UNLIMITED_ALLOWANCE_IN_BASE_UNITS = token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS;
|
||||
constructor(store: AbstractBalanceAndProxyAllowanceLazyStore) {
|
||||
this._store = store;
|
||||
}
|
||||
/**
|
||||
* Simulates transferFrom call performed by a proxy
|
||||
@@ -92,7 +89,7 @@ export class ExchangeTransferSimulator {
|
||||
amountInBaseUnits: BigNumber,
|
||||
): Promise<void> {
|
||||
const proxyAllowance = await this._store.getProxyAllowanceAsync(tokenAddress, userAddress);
|
||||
if (!proxyAllowance.eq(this._UNLIMITED_ALLOWANCE_IN_BASE_UNITS)) {
|
||||
if (!proxyAllowance.eq(constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS)) {
|
||||
this._store.setProxyAllowance(tokenAddress, userAddress, proxyAllowance.minus(amountInBaseUnits));
|
||||
}
|
||||
}
|
||||
|
@@ -1,3 +1,4 @@
|
||||
// tslint:disable:no-unused-variable
|
||||
import {
|
||||
ConstructorAbi,
|
||||
ContractAbi,
|
||||
@@ -7,6 +8,7 @@ import {
|
||||
LogEntry,
|
||||
MethodAbi,
|
||||
} from '@0xproject/types';
|
||||
// tslint:enable:no-unused-variable
|
||||
import * as ethUtil from 'ethereumjs-util';
|
||||
import * as jsSHA3 from 'js-sha3';
|
||||
import * as _ from 'lodash';
|
||||
|
@@ -3,15 +3,15 @@ import { ExchangeContractErrs, Order, SignedOrder } from '@0xproject/types';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { ExchangeWrapper } from '../contract_wrappers/exchange_wrapper';
|
||||
import { ContractWrappersError, TradeSide, TransferType } from '../types';
|
||||
import { ExchangeContract } from '../contract_wrappers/generated/exchange';
|
||||
import { TradeSide, TransferType } from '../types';
|
||||
import { constants } from '../utils/constants';
|
||||
import { utils } from '../utils/utils';
|
||||
|
||||
import { ExchangeTransferSimulator } from './exchange_transfer_simulator';
|
||||
|
||||
export class OrderValidationUtils {
|
||||
private _exchangeWrapper: ExchangeWrapper;
|
||||
private _exchangeContract: ExchangeContract;
|
||||
public static validateCancelOrderThrowIfInvalid(
|
||||
order: Order,
|
||||
cancelTakerTokenAmount: BigNumber,
|
||||
@@ -104,8 +104,8 @@ export class OrderValidationUtils {
|
||||
.round(0);
|
||||
return fillMakerTokenAmount;
|
||||
}
|
||||
constructor(exchangeWrapper: ExchangeWrapper) {
|
||||
this._exchangeWrapper = exchangeWrapper;
|
||||
constructor(exchangeContract: ExchangeContract) {
|
||||
this._exchangeContract = exchangeContract;
|
||||
}
|
||||
public async validateOrderFillableOrThrowAsync(
|
||||
exchangeTradeEmulator: ExchangeTransferSimulator,
|
||||
@@ -114,7 +114,9 @@ export class OrderValidationUtils {
|
||||
expectedFillTakerTokenAmount?: BigNumber,
|
||||
): Promise<void> {
|
||||
const orderHash = getOrderHashHex(signedOrder);
|
||||
const unavailableTakerTokenAmount = await this._exchangeWrapper.getUnavailableTakerAmountAsync(orderHash);
|
||||
const unavailableTakerTokenAmount = await this._exchangeContract.getUnavailableTakerTokenAmount.callAsync(
|
||||
orderHash,
|
||||
);
|
||||
OrderValidationUtils._validateRemainingFillAmountNotZeroOrThrow(
|
||||
signedOrder.takerTokenAmount,
|
||||
unavailableTakerTokenAmount,
|
||||
@@ -146,7 +148,9 @@ export class OrderValidationUtils {
|
||||
if (!isValidSignature(orderHash, signedOrder.ecSignature, signedOrder.maker)) {
|
||||
throw new Error(OrderError.InvalidSignature);
|
||||
}
|
||||
const unavailableTakerTokenAmount = await this._exchangeWrapper.getUnavailableTakerAmountAsync(orderHash);
|
||||
const unavailableTakerTokenAmount = await this._exchangeContract.getUnavailableTakerTokenAmount.callAsync(
|
||||
orderHash,
|
||||
);
|
||||
OrderValidationUtils._validateRemainingFillAmountNotZeroOrThrow(
|
||||
signedOrder.takerTokenAmount,
|
||||
unavailableTakerTokenAmount,
|
||||
@@ -167,7 +171,7 @@ export class OrderValidationUtils {
|
||||
zrxTokenAddress,
|
||||
);
|
||||
|
||||
const wouldRoundingErrorOccur = await this._exchangeWrapper.isRoundingErrorAsync(
|
||||
const wouldRoundingErrorOccur = await this._exchangeContract.isRoundingError.callAsync(
|
||||
filledTakerTokenAmount,
|
||||
signedOrder.takerTokenAmount,
|
||||
signedOrder.makerTokenAmount,
|
||||
|
@@ -1,9 +1,6 @@
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
|
||||
export const utils = {
|
||||
spawnSwitchErr(name: string, value: any): Error {
|
||||
return new Error(`Unexpected switch value: ${value} encountered for ${name}`);
|
||||
},
|
||||
getCurrentUnixTimestampSec(): BigNumber {
|
||||
const milisecondsInSecond = 1000;
|
||||
return new BigNumber(Date.now() / milisecondsInSecond).round();
|
||||
|
@@ -1,5 +1,4 @@
|
||||
import { web3Factory } from '@0xproject/dev-utils';
|
||||
import * as fs from 'fs';
|
||||
import 'make-promises-safe';
|
||||
|
||||
import { ContractWrappers } from '../src';
|
||||
@@ -15,7 +14,7 @@ const TIMEOUT = 10000;
|
||||
describe('Artifacts', () => {
|
||||
describe('contracts are deployed on kovan', () => {
|
||||
const kovanRpcUrl = constants.KOVAN_RPC_URL;
|
||||
const provider = web3Factory.create({ rpcUrl: kovanRpcUrl }).currentProvider;
|
||||
const provider = web3Factory.getRpcProvider({ rpcUrl: kovanRpcUrl });
|
||||
const config = {
|
||||
networkId: constants.KOVAN_NETWORK_ID,
|
||||
};
|
||||
@@ -32,7 +31,7 @@ describe('Artifacts', () => {
|
||||
});
|
||||
describe('contracts are deployed on ropsten', () => {
|
||||
const ropstenRpcUrl = constants.ROPSTEN_RPC_URL;
|
||||
const provider = web3Factory.create({ rpcUrl: ropstenRpcUrl }).currentProvider;
|
||||
const provider = web3Factory.getRpcProvider({ rpcUrl: ropstenRpcUrl });
|
||||
const config = {
|
||||
networkId: constants.ROPSTEN_NETWORK_ID,
|
||||
};
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { BlockchainLifecycle, callbackErrorReporter, devConstants, web3Factory } from '@0xproject/dev-utils';
|
||||
import { BlockchainLifecycle, callbackErrorReporter } from '@0xproject/dev-utils';
|
||||
import { DoneCallback } from '@0xproject/types';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
@@ -95,7 +95,7 @@ describe('EtherTokenWrapper', () => {
|
||||
depositWeiAmount,
|
||||
addressWithETH,
|
||||
);
|
||||
await web3Wrapper.awaitTransactionMinedAsync(txHash);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
|
||||
const postETHBalanceInWei = await web3Wrapper.getBalanceInWeiAsync(addressWithETH);
|
||||
const postWETHBalanceInBaseUnits = await contractWrappers.token.getBalanceAsync(
|
||||
@@ -137,7 +137,7 @@ describe('EtherTokenWrapper', () => {
|
||||
depositWeiAmount,
|
||||
addressWithETH,
|
||||
);
|
||||
await web3Wrapper.awaitTransactionMinedAsync(txHash);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
|
||||
const postETHBalance = await web3Wrapper.getBalanceInWeiAsync(addressWithETH);
|
||||
const postWETHBalanceInBaseUnits = await contractWrappers.token.getBalanceAsync(
|
||||
@@ -347,7 +347,7 @@ describe('EtherTokenWrapper', () => {
|
||||
});
|
||||
it('should get logs with decoded args emitted by Approval', async () => {
|
||||
txHash = await contractWrappers.token.setUnlimitedProxyAllowanceAsync(etherTokenAddress, addressWithETH);
|
||||
await web3Wrapper.awaitTransactionMinedAsync(txHash);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
const eventName = EtherTokenEvents.Approval;
|
||||
const indexFilterValues = {};
|
||||
const logs = await contractWrappers.etherToken.getLogsAsync<ApprovalContractEventArgs>(
|
||||
@@ -381,7 +381,7 @@ describe('EtherTokenWrapper', () => {
|
||||
});
|
||||
it('should only get the logs with the correct event name', async () => {
|
||||
txHash = await contractWrappers.token.setUnlimitedProxyAllowanceAsync(etherTokenAddress, addressWithETH);
|
||||
await web3Wrapper.awaitTransactionMinedAsync(txHash);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
const differentEventName = EtherTokenEvents.Transfer;
|
||||
const indexFilterValues = {};
|
||||
const logs = await contractWrappers.etherToken.getLogsAsync(
|
||||
@@ -394,12 +394,12 @@ describe('EtherTokenWrapper', () => {
|
||||
});
|
||||
it('should only get the logs with the correct indexed fields', async () => {
|
||||
txHash = await contractWrappers.token.setUnlimitedProxyAllowanceAsync(etherTokenAddress, addressWithETH);
|
||||
await web3Wrapper.awaitTransactionMinedAsync(txHash);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
txHash = await contractWrappers.token.setUnlimitedProxyAllowanceAsync(
|
||||
etherTokenAddress,
|
||||
addressWithoutFunds,
|
||||
);
|
||||
await web3Wrapper.awaitTransactionMinedAsync(txHash);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
const eventName = EtherTokenEvents.Approval;
|
||||
const indexFilterValues = {
|
||||
_owner: addressWithETH,
|
||||
|
@@ -1,10 +1,11 @@
|
||||
import { BlockchainLifecycle, devConstants } from '@0xproject/dev-utils';
|
||||
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
||||
import { BlockParamLiteral, Token } from '@0xproject/types';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import * as chai from 'chai';
|
||||
import 'make-promises-safe';
|
||||
|
||||
import { ContractWrappers, ExchangeContractErrs } from '../src';
|
||||
import { BalanceAndProxyAllowanceLazyStore } from '../src/stores/balance_proxy_allowance_lazy_store';
|
||||
import { TradeSide, TransferType } from '../src/types';
|
||||
import { ExchangeTransferSimulator } from '../src/utils/exchange_transfer_simulator';
|
||||
|
||||
@@ -44,7 +45,11 @@ describe('ExchangeTransferSimulator', () => {
|
||||
});
|
||||
describe('#transferFromAsync', () => {
|
||||
beforeEach(() => {
|
||||
exchangeTransferSimulator = new ExchangeTransferSimulator(contractWrappers.token, BlockParamLiteral.Latest);
|
||||
const balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore(
|
||||
contractWrappers.token,
|
||||
BlockParamLiteral.Latest,
|
||||
);
|
||||
exchangeTransferSimulator = new ExchangeTransferSimulator(balanceAndProxyAllowanceLazyStore);
|
||||
});
|
||||
it("throws if the user doesn't have enough allowance", async () => {
|
||||
return expect(
|
||||
@@ -60,7 +65,7 @@ describe('ExchangeTransferSimulator', () => {
|
||||
});
|
||||
it("throws if the user doesn't have enough balance", async () => {
|
||||
txHash = await contractWrappers.token.setProxyAllowanceAsync(exampleTokenAddress, sender, transferAmount);
|
||||
await web3Wrapper.awaitTransactionMinedAsync(txHash);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
return expect(
|
||||
exchangeTransferSimulator.transferFromAsync(
|
||||
exampleTokenAddress,
|
||||
@@ -74,9 +79,9 @@ describe('ExchangeTransferSimulator', () => {
|
||||
});
|
||||
it('updates balances and proxyAllowance after transfer', async () => {
|
||||
txHash = await contractWrappers.token.transferAsync(exampleTokenAddress, coinbase, sender, transferAmount);
|
||||
await web3Wrapper.awaitTransactionMinedAsync(txHash);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
txHash = await contractWrappers.token.setProxyAllowanceAsync(exampleTokenAddress, sender, transferAmount);
|
||||
await web3Wrapper.awaitTransactionMinedAsync(txHash);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
await exchangeTransferSimulator.transferFromAsync(
|
||||
exampleTokenAddress,
|
||||
sender,
|
||||
@@ -95,9 +100,9 @@ describe('ExchangeTransferSimulator', () => {
|
||||
});
|
||||
it("doesn't update proxyAllowance after transfer if unlimited", async () => {
|
||||
txHash = await contractWrappers.token.transferAsync(exampleTokenAddress, coinbase, sender, transferAmount);
|
||||
await web3Wrapper.awaitTransactionMinedAsync(txHash);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
txHash = await contractWrappers.token.setUnlimitedProxyAllowanceAsync(exampleTokenAddress, sender);
|
||||
await web3Wrapper.awaitTransactionMinedAsync(txHash);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
await exchangeTransferSimulator.transferFromAsync(
|
||||
exampleTokenAddress,
|
||||
sender,
|
||||
|
@@ -1,11 +1,10 @@
|
||||
import { BlockchainLifecycle, callbackErrorReporter, devConstants, web3Factory } from '@0xproject/dev-utils';
|
||||
import { BlockchainLifecycle, callbackErrorReporter } from '@0xproject/dev-utils';
|
||||
import { FillScenarios } from '@0xproject/fill-scenarios';
|
||||
import { getOrderHashHex } from '@0xproject/order-utils';
|
||||
import { BlockParamLiteral, DoneCallback, OrderState } from '@0xproject/types';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
import * as chai from 'chai';
|
||||
import * as _ from 'lodash';
|
||||
import 'make-promises-safe';
|
||||
import 'mocha';
|
||||
|
||||
@@ -276,7 +275,7 @@ describe('ExchangeWrapper', () => {
|
||||
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
takerAddress,
|
||||
);
|
||||
await web3Wrapper.awaitTransactionMinedAsync(txHash);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
expect(
|
||||
await contractWrappers.token.getBalanceAsync(makerTokenAddress, makerAddress),
|
||||
).to.be.bignumber.equal(fillableAmount.minus(takerTokenFillAmount));
|
||||
@@ -305,7 +304,7 @@ describe('ExchangeWrapper', () => {
|
||||
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
takerAddress,
|
||||
);
|
||||
await web3Wrapper.awaitTransactionMinedAsync(txHash);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
expect(
|
||||
await contractWrappers.token.getBalanceAsync(makerTokenAddress, makerAddress),
|
||||
).to.be.bignumber.equal(fillableAmount.minus(partialFillAmount));
|
||||
@@ -338,7 +337,7 @@ describe('ExchangeWrapper', () => {
|
||||
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
takerAddress,
|
||||
);
|
||||
await web3Wrapper.awaitTransactionMinedAsync(txHash);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
expect(
|
||||
await contractWrappers.token.getBalanceAsync(zrxTokenAddress, feeRecipient),
|
||||
).to.be.bignumber.equal(makerFee.plus(takerFee));
|
||||
@@ -469,7 +468,7 @@ describe('ExchangeWrapper', () => {
|
||||
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
takerAddress,
|
||||
);
|
||||
await web3Wrapper.awaitTransactionMinedAsync(txHash);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
const filledAmount = await contractWrappers.exchange.getFilledTakerAmountAsync(signedOrderHashHex);
|
||||
const anotherFilledAmount = await contractWrappers.exchange.getFilledTakerAmountAsync(
|
||||
anotherOrderHashHex,
|
||||
@@ -595,7 +594,7 @@ describe('ExchangeWrapper', () => {
|
||||
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
takerAddress,
|
||||
);
|
||||
await web3Wrapper.awaitTransactionMinedAsync(txHash);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
const filledAmount = await contractWrappers.exchange.getFilledTakerAmountAsync(signedOrderHashHex);
|
||||
const anotherFilledAmount = await contractWrappers.exchange.getFilledTakerAmountAsync(
|
||||
anotherOrderHashHex,
|
||||
@@ -611,7 +610,7 @@ describe('ExchangeWrapper', () => {
|
||||
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
takerAddress,
|
||||
);
|
||||
await web3Wrapper.awaitTransactionMinedAsync(txHash);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
const filledAmount = await contractWrappers.exchange.getFilledTakerAmountAsync(signedOrderHashHex);
|
||||
const zeroAmount = await contractWrappers.exchange.getFilledTakerAmountAsync(anotherOrderHashHex);
|
||||
expect(filledAmount).to.be.bignumber.equal(fillableAmount);
|
||||
@@ -632,7 +631,7 @@ describe('ExchangeWrapper', () => {
|
||||
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
takerAddress,
|
||||
);
|
||||
await web3Wrapper.awaitTransactionMinedAsync(txHash);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
const filledAmount = await contractWrappers.exchange.getFilledTakerAmountAsync(signedOrderHashHex);
|
||||
const anotherFilledAmount = await contractWrappers.exchange.getFilledTakerAmountAsync(
|
||||
anotherOrderHashHex,
|
||||
@@ -730,7 +729,7 @@ describe('ExchangeWrapper', () => {
|
||||
describe('successful cancels', () => {
|
||||
it('should cancel an order', async () => {
|
||||
const txHash = await contractWrappers.exchange.cancelOrderAsync(signedOrder, cancelAmount);
|
||||
await web3Wrapper.awaitTransactionMinedAsync(txHash);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
const cancelledAmount = await contractWrappers.exchange.getCancelledTakerAmountAsync(orderHashHex);
|
||||
expect(cancelledAmount).to.be.bignumber.equal(cancelAmount);
|
||||
});
|
||||
@@ -1112,7 +1111,7 @@ describe('ExchangeWrapper', () => {
|
||||
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
takerAddress,
|
||||
);
|
||||
await web3Wrapper.awaitTransactionMinedAsync(txHash);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
const eventName = ExchangeEvents.LogFill;
|
||||
const indexFilterValues = {};
|
||||
const logs = await contractWrappers.exchange.getLogsAsync(eventName, blockRange, indexFilterValues);
|
||||
@@ -1133,7 +1132,7 @@ describe('ExchangeWrapper', () => {
|
||||
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
takerAddress,
|
||||
);
|
||||
await web3Wrapper.awaitTransactionMinedAsync(txHash);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
const differentEventName = ExchangeEvents.LogCancel;
|
||||
const indexFilterValues = {};
|
||||
const logs = await contractWrappers.exchange.getLogsAsync(
|
||||
@@ -1157,7 +1156,7 @@ describe('ExchangeWrapper', () => {
|
||||
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
takerAddress,
|
||||
);
|
||||
await web3Wrapper.awaitTransactionMinedAsync(txHash);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
|
||||
const differentMakerAddress = userAddresses[2];
|
||||
const anotherSignedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||
@@ -1173,7 +1172,7 @@ describe('ExchangeWrapper', () => {
|
||||
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
takerAddress,
|
||||
);
|
||||
await web3Wrapper.awaitTransactionMinedAsync(txHash);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
|
||||
const eventName = ExchangeEvents.LogFill;
|
||||
const indexFilterValues = {
|
||||
|
@@ -1,19 +1,17 @@
|
||||
import { devConstants } from '@0xproject/dev-utils';
|
||||
import { runMigrationsAsync } from '@0xproject/migrations';
|
||||
import * as path from 'path';
|
||||
import { runV1MigrationsAsync } from '@0xproject/migrations';
|
||||
|
||||
import { constants } from './utils/constants';
|
||||
import { provider } from './utils/web3_wrapper';
|
||||
|
||||
before('migrate contracts', async function(): Promise<void> {
|
||||
// HACK: Since the migrations take longer then our global mocha timeout limit
|
||||
// we manually increase it for this before hook.
|
||||
const mochaTestTimeoutMs = 20000;
|
||||
const mochaTestTimeoutMs = 50000;
|
||||
this.timeout(mochaTestTimeoutMs);
|
||||
const txDefaults = {
|
||||
gas: devConstants.GAS_ESTIMATE,
|
||||
gas: devConstants.GAS_LIMIT,
|
||||
from: devConstants.TESTRPC_FIRST_ADDRESS,
|
||||
};
|
||||
const artifactsDir = `../migrations/artifacts/1.0.0`;
|
||||
await runMigrationsAsync(provider, artifactsDir, txDefaults);
|
||||
await runV1MigrationsAsync(provider, artifactsDir, txDefaults);
|
||||
});
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { BlockchainLifecycle, devConstants } from '@0xproject/dev-utils';
|
||||
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
||||
import { FillScenarios } from '@0xproject/fill-scenarios';
|
||||
import { OrderError } from '@0xproject/order-utils';
|
||||
import { BlockParamLiteral } from '@0xproject/types';
|
||||
@@ -7,7 +7,8 @@ import * as chai from 'chai';
|
||||
import 'make-promises-safe';
|
||||
import * as Sinon from 'sinon';
|
||||
|
||||
import { ContractWrappers, ContractWrappersError, ExchangeContractErrs, SignedOrder, Token } from '../src';
|
||||
import { ContractWrappers, ExchangeContractErrs, SignedOrder, Token } from '../src';
|
||||
import { BalanceAndProxyAllowanceLazyStore } from '../src/stores/balance_proxy_allowance_lazy_store';
|
||||
import { TradeSide, TransferType } from '../src/types';
|
||||
import { ExchangeTransferSimulator } from '../src/utils/exchange_transfer_simulator';
|
||||
import { OrderValidationUtils } from '../src/utils/order_validation_utils';
|
||||
@@ -332,7 +333,11 @@ describe('OrderValidation', () => {
|
||||
return Sinon.match((value: BigNumber) => value.eq(expected));
|
||||
};
|
||||
beforeEach('create exchangeTransferSimulator', async () => {
|
||||
exchangeTransferSimulator = new ExchangeTransferSimulator(contractWrappers.token, BlockParamLiteral.Latest);
|
||||
const balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore(
|
||||
contractWrappers.token,
|
||||
BlockParamLiteral.Latest,
|
||||
);
|
||||
exchangeTransferSimulator = new ExchangeTransferSimulator(balanceAndProxyAllowanceLazyStore);
|
||||
transferFromAsync = Sinon.spy();
|
||||
exchangeTransferSimulator.transferFromAsync = transferFromAsync as any;
|
||||
});
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { BlockchainLifecycle, callbackErrorReporter, devConstants } from '@0xproject/dev-utils';
|
||||
import { BlockchainLifecycle, callbackErrorReporter } from '@0xproject/dev-utils';
|
||||
import { DoneCallback } from '@0xproject/types';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import * as _ from 'lodash';
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { BlockchainLifecycle, devConstants } from '@0xproject/dev-utils';
|
||||
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
||||
import { schemas, SchemaValidator } from '@0xproject/json-schemas';
|
||||
import * as chai from 'chai';
|
||||
import * as _ from 'lodash';
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { BlockchainLifecycle, callbackErrorReporter, devConstants } from '@0xproject/dev-utils';
|
||||
import { BlockchainLifecycle, callbackErrorReporter } from '@0xproject/dev-utils';
|
||||
import { EmptyWalletSubprovider } from '@0xproject/subproviders';
|
||||
import { DoneCallback, Provider } from '@0xproject/types';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
@@ -218,7 +218,6 @@ describe('TokenWrapper', () => {
|
||||
describe('With provider without accounts', () => {
|
||||
let zeroExContractWithoutAccounts: ContractWrappers;
|
||||
before(async () => {
|
||||
const hasAddresses = false;
|
||||
const emptyWalletProvider = addEmptyWalletSubprovider(provider);
|
||||
zeroExContractWithoutAccounts = new ContractWrappers(emptyWalletProvider, config);
|
||||
});
|
||||
@@ -361,7 +360,6 @@ describe('TokenWrapper', () => {
|
||||
describe('With provider without accounts', () => {
|
||||
let zeroExContractWithoutAccounts: ContractWrappers;
|
||||
before(async () => {
|
||||
const hasAddresses = false;
|
||||
const emptyWalletProvider = addEmptyWalletSubprovider(provider);
|
||||
zeroExContractWithoutAccounts = new ContractWrappers(emptyWalletProvider, config);
|
||||
});
|
||||
@@ -542,7 +540,7 @@ describe('TokenWrapper', () => {
|
||||
});
|
||||
it('should get logs with decoded args emitted by Approval', async () => {
|
||||
txHash = await contractWrappers.token.setUnlimitedProxyAllowanceAsync(tokenAddress, coinbase);
|
||||
await web3Wrapper.awaitTransactionMinedAsync(txHash);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
const eventName = TokenEvents.Approval;
|
||||
const indexFilterValues = {};
|
||||
const logs = await contractWrappers.token.getLogsAsync<ApprovalContractEventArgs>(
|
||||
@@ -560,7 +558,7 @@ describe('TokenWrapper', () => {
|
||||
});
|
||||
it('should only get the logs with the correct event name', async () => {
|
||||
txHash = await contractWrappers.token.setUnlimitedProxyAllowanceAsync(tokenAddress, coinbase);
|
||||
await web3Wrapper.awaitTransactionMinedAsync(txHash);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
const differentEventName = TokenEvents.Transfer;
|
||||
const indexFilterValues = {};
|
||||
const logs = await contractWrappers.token.getLogsAsync(
|
||||
@@ -573,9 +571,9 @@ describe('TokenWrapper', () => {
|
||||
});
|
||||
it('should only get the logs with the correct indexed fields', async () => {
|
||||
txHash = await contractWrappers.token.setUnlimitedProxyAllowanceAsync(tokenAddress, coinbase);
|
||||
await web3Wrapper.awaitTransactionMinedAsync(txHash);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
txHash = await contractWrappers.token.setUnlimitedProxyAllowanceAsync(tokenAddress, addressWithoutFunds);
|
||||
await web3Wrapper.awaitTransactionMinedAsync(txHash);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
const eventName = TokenEvents.Approval;
|
||||
const indexFilterValues = {
|
||||
_owner: coinbase,
|
||||
|
@@ -1,9 +1,8 @@
|
||||
import { devConstants, web3Factory } from '@0xproject/dev-utils';
|
||||
import { web3Factory } from '@0xproject/dev-utils';
|
||||
import { Provider } from '@0xproject/types';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
|
||||
const web3 = web3Factory.create({ shouldUseInProcessGanache: true });
|
||||
const provider: Provider = web3.currentProvider;
|
||||
const web3Wrapper = new Web3Wrapper(web3.currentProvider);
|
||||
const provider: Provider = web3Factory.getRpcProvider({ shouldUseInProcessGanache: true });
|
||||
const web3Wrapper = new Web3Wrapper(provider);
|
||||
|
||||
export { provider, web3Wrapper };
|
||||
|
@@ -2,15 +2,16 @@
|
||||
* This file is auto-generated using abi-gen. Don't edit directly.
|
||||
* Templates can be found at https://github.com/0xProject/0x-monorepo/tree/development/packages/contract_templates.
|
||||
*/
|
||||
// tslint:disable:no-consecutive-blank-lines
|
||||
// tslint:disable-next-line:no-unused-variable
|
||||
// tslint:disable:no-consecutive-blank-lines ordered-imports align trailing-comma whitespace
|
||||
// tslint:disable:no-unused-variable
|
||||
import { BaseContract } from '@0xproject/base-contract';
|
||||
import { ContractArtifact } from '@0xproject/sol-compiler';
|
||||
import { BlockParam, BlockParamLiteral, CallData, ContractAbi, DataItem, MethodAbi, Provider, TxData, TxDataPayable } from '@0xproject/types';
|
||||
import { BlockParam, BlockParamLiteral, CallData, ContractAbi, DataItem, DecodedLogArgs, MethodAbi, Provider, TxData, TxDataPayable } from 'ethereum-types';
|
||||
import { BigNumber, classUtils, logUtils, promisify } from '@0xproject/utils';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
import * as ethers from 'ethers';
|
||||
import * as _ from 'lodash';
|
||||
// tslint:enable:no-unused-variable
|
||||
|
||||
{{#if events}}
|
||||
export type {{contractName}}ContractEventArgs =
|
||||
@@ -31,6 +32,7 @@ export enum {{contractName}}Events {
|
||||
{{/if}}
|
||||
|
||||
// tslint:disable:no-parameter-reassignment
|
||||
// tslint:disable-next-line:class-name
|
||||
export class {{contractName}}Contract extends BaseContract {
|
||||
{{#each methods}}
|
||||
{{#this.constant}}
|
||||
@@ -75,14 +77,14 @@ export class {{contractName}}Contract extends BaseContract {
|
||||
);
|
||||
const txHash = await web3Wrapper.sendTransactionAsync(txDataWithDefaults);
|
||||
logUtils.log(`transactionHash: ${txHash}`);
|
||||
const txReceipt = await web3Wrapper.awaitTransactionMinedAsync(txHash);
|
||||
const txReceipt = await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
logUtils.log(`{{contractName}} successfully deployed at ${txReceipt.contractAddress}`);
|
||||
const contractInstance = new {{contractName}}Contract(abi, txReceipt.contractAddress as string, provider, txDefaults);
|
||||
contractInstance.constructorArgs = [{{> params inputs=ctor.inputs}}];
|
||||
return contractInstance;
|
||||
}
|
||||
constructor(abi: ContractAbi, address: string, provider: Provider, txDefaults?: Partial<TxData>) {
|
||||
super("{{contractName}}", abi, address, provider, txDefaults);
|
||||
super('{{contractName}}', abi, address, provider, txDefaults);
|
||||
classUtils.bindAll(this, ['_ethersInterfacesByFunctionSignature', 'address', 'abi', '_web3Wrapper']);
|
||||
}
|
||||
} // tslint:disable:max-file-line-count
|
||||
|
@@ -18,7 +18,7 @@ async callAsync(
|
||||
data: encodedData,
|
||||
},
|
||||
self._web3Wrapper.getContractDefaults(),
|
||||
)
|
||||
);
|
||||
const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock);
|
||||
let resultArray = ethersFunction.parse(rawCallResult);
|
||||
const outputAbi = (_.find(self.abi, {name: '{{this.name}}'}) as MethodAbi).outputs;
|
||||
|
@@ -1,4 +1,4 @@
|
||||
export interface {{name}}ContractEventArgs {
|
||||
export interface {{name}}ContractEventArgs extends DecodedLogArgs {
|
||||
{{#each inputs}}
|
||||
{{name}}: {{#returnType type components}}{{/returnType}};
|
||||
{{/each}}
|
||||
|
@@ -63,3 +63,12 @@ yarn lint
|
||||
```bash
|
||||
yarn test
|
||||
```
|
||||
|
||||
### Run Tests Against Geth
|
||||
|
||||
Follow the instructions in the README for the devnet package to start the
|
||||
devnet.
|
||||
|
||||
```bash
|
||||
TEST_PROVIDER=geth yarn test
|
||||
```
|
||||
|
@@ -1,7 +1,11 @@
|
||||
{
|
||||
"artifactsDir": "../migrations/artifacts/1.0.0",
|
||||
"artifactsDir": "../migrations/artifacts/2.0.0",
|
||||
"contractsDir": "src/contracts",
|
||||
"compilerSettings": {
|
||||
"optimizer": {
|
||||
"enabled": true,
|
||||
"runs": 200
|
||||
},
|
||||
"outputSelection": {
|
||||
"*": {
|
||||
"*": [
|
||||
@@ -15,19 +19,25 @@
|
||||
}
|
||||
},
|
||||
"contracts": [
|
||||
"AssetProxyOwner",
|
||||
"DummyERC20Token",
|
||||
"DummyERC721Receiver",
|
||||
"DummyERC721Token",
|
||||
"ERC20Proxy",
|
||||
"ERC721Proxy",
|
||||
"Exchange",
|
||||
"DummyToken",
|
||||
"ZRXToken",
|
||||
"Token",
|
||||
"WETH9",
|
||||
"TokenTransferProxy",
|
||||
"MixinAuthorizable",
|
||||
"MultiSigWallet",
|
||||
"MultiSigWalletWithTimeLock",
|
||||
"MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress",
|
||||
"MaliciousToken",
|
||||
"TestAssetDataDecoders",
|
||||
"TestAssetProxyDispatcher",
|
||||
"TestLibBytes",
|
||||
"TestLibMem",
|
||||
"TestLibs",
|
||||
"TestSignatureValidator",
|
||||
"TokenRegistry",
|
||||
"Arbitrage",
|
||||
"EtherDelta",
|
||||
"AccountLevels"
|
||||
"Whitelist",
|
||||
"WETH9",
|
||||
"ZRXToken"
|
||||
]
|
||||
}
|
||||
|
@@ -11,25 +11,29 @@
|
||||
"test": "test"
|
||||
},
|
||||
"scripts": {
|
||||
"watch": "tsc -w",
|
||||
"prebuild": "run-s clean copy_artifacts generate_contract_wrappers",
|
||||
"copy_artifacts": "copyfiles -u 4 '../migrations/artifacts/1.0.0/**/*' ./lib/src/artifacts;",
|
||||
"build": "tsc",
|
||||
"test": "run-s build run_mocha",
|
||||
"watch_without_deps": "yarn pre_build && tsc -w",
|
||||
"build": "yarn pre_build && tsc",
|
||||
"pre_build": "run-s compile copy_artifacts generate_contract_wrappers",
|
||||
"copy_artifacts": "copyfiles -u 4 '../migrations/artifacts/2.0.0/**/*' ./lib/src/artifacts;",
|
||||
"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",
|
||||
"run_mocha": "mocha 'lib/test/**/*.js' --timeout 100000 --bail --exit",
|
||||
"compile:comment": "Yarn workspaces do not link binaries correctly so we need to reference them directly https://github.com/yarnpkg/yarn/issues/3846",
|
||||
"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 'lib/test/**/*.js' --timeout 100000 --bail --exit",
|
||||
"compile": "sol-compiler",
|
||||
"clean": "shx rm -rf lib src/contract_wrappers/generated",
|
||||
"generate_contract_wrappers": "abi-gen --abis ${npm_package_config_abis} --template ../contract_templates/contract.handlebars --partials '../contract_templates/partials/**/*.handlebars' --output src/contract_wrappers/generated --backend ethers && prettier --write 'src/contract_wrappers/generated/**.ts'",
|
||||
"lint": "tslint --project .",
|
||||
"clean": "shx rm -rf lib src/generated_contract_wrappers",
|
||||
"generate_contract_wrappers":
|
||||
"abi-gen --abis ${npm_package_config_abis} --template ../contract_templates/contract.handlebars --partials '../contract_templates/partials/**/*.handlebars' --output src/generated_contract_wrappers --backend ethers",
|
||||
"lint": "tslint --project . --exclude **/src/generated_contract_wrappers/**/* --exclude **/lib/**/*",
|
||||
"coverage:report:text": "istanbul report text",
|
||||
"coverage:report:html": "istanbul report html && open coverage/index.html",
|
||||
"profiler:report:html": "istanbul report html && open coverage/index.html",
|
||||
"coverage:report:lcov": "istanbul report lcov",
|
||||
"test:circleci": "yarn test:coverage"
|
||||
"test:circleci": "yarn test"
|
||||
},
|
||||
"config": {
|
||||
"abis": "../migrations/artifacts/1.0.0/@(DummyToken|TokenTransferProxy|Exchange|TokenRegistry|MultiSigWallet|MultiSigWalletWithTimeLock|MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress|TokenRegistry|ZRXToken|Arbitrage|EtherDelta|AccountLevels|WETH9|MaliciousToken).json"
|
||||
"abis": "../migrations/artifacts/2.0.0/@(AssetProxyOwner|DummyERC20Token|DummyERC721Receiver|DummyERC721Token|ERC20Proxy|ERC721Proxy|Exchange|MixinAuthorizable|MultiSigWallet|MultiSigWalletWithTimeLock|TestAssetDataDecoders|TestAssetProxyDispatcher|TestLibBytes|TestLibMem|TestLibs|TestSignatureValidator|TokenRegistry|Whitelist|WETH9|ZRXToken).json"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -45,8 +49,12 @@
|
||||
"@0xproject/abi-gen": "^0.3.0",
|
||||
"@0xproject/dev-utils": "^0.4.2",
|
||||
"@0xproject/tslint-config": "^0.4.18",
|
||||
"@0xproject/subproviders": "^0.10.1",
|
||||
"@0xproject/sol-cov": "^0.0.11",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/bn.js": "^4.11.0",
|
||||
"@types/node": "^8.0.53",
|
||||
"@types/ethereumjs-abi": "^0.6.0",
|
||||
"@types/yargs": "^10.0.0",
|
||||
"chai": "^4.0.1",
|
||||
"chai-as-promised": "^7.1.0",
|
||||
@@ -56,21 +64,21 @@
|
||||
"make-promises-safe": "^1.1.0",
|
||||
"mocha": "^4.0.1",
|
||||
"npm-run-all": "^4.1.2",
|
||||
"prettier": "^1.11.1",
|
||||
"shx": "^0.2.2",
|
||||
"solc": "^0.4.23",
|
||||
"solc": "^0.4.24",
|
||||
"tslint": "5.8.0",
|
||||
"typescript": "2.7.1",
|
||||
"yargs": "^10.0.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"0x.js": "^0.38.0",
|
||||
"@0xproject/base-contract": "^0.3.2",
|
||||
"@0xproject/order-utils": "^0.0.6",
|
||||
"@0xproject/sol-compiler": "^0.5.0",
|
||||
"@0xproject/types": "^0.7.0",
|
||||
"@0xproject/types": "^1.0.0",
|
||||
"@0xproject/typescript-typings": "^0.3.2",
|
||||
"@0xproject/utils": "^0.6.2",
|
||||
"@0xproject/web3-wrapper": "^0.6.4",
|
||||
"ethereum-types": "^0.0.1",
|
||||
"bn.js": "^4.11.8",
|
||||
"ethereumjs-abi": "^0.6.4",
|
||||
"ethereumjs-util": "^5.1.1",
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright 2017 ZeroEx Intl.
|
||||
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.
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
pragma solidity ^0.4.10;
|
||||
|
||||
import { MultiSigWallet } from "../MultiSigWallet/MultiSigWallet.sol";
|
||||
import "./MultiSigWallet.sol";
|
||||
|
||||
/// @title Multisignature wallet with time lock- Allows multiple parties to execute a transaction after a time lock has passed.
|
||||
/// @author Amir Bandeali - <amir@0xProject.com>
|
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
|
||||
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.4.24;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "../../utils/LibBytes/LibBytes.sol";
|
||||
import "./MixinAssetProxy.sol";
|
||||
import "./MixinAuthorizable.sol";
|
||||
import "../../tokens/ERC20Token/IERC20Token.sol";
|
||||
|
||||
contract ERC20Proxy is
|
||||
LibBytes,
|
||||
MixinAssetProxy,
|
||||
MixinAuthorizable
|
||||
{
|
||||
|
||||
// Id of this proxy.
|
||||
uint8 constant PROXY_ID = 1;
|
||||
|
||||
/// @dev Internal version of `transferFrom`.
|
||||
/// @param assetData Encoded byte array.
|
||||
/// @param from Address to transfer asset from.
|
||||
/// @param to Address to transfer asset to.
|
||||
/// @param amount Amount of asset to transfer.
|
||||
function transferFromInternal(
|
||||
bytes memory assetData,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
)
|
||||
internal
|
||||
{
|
||||
// Decode asset data.
|
||||
address token = readAddress(assetData, 0);
|
||||
|
||||
// Transfer tokens.
|
||||
// We do a raw call so we can check the success separate
|
||||
// from the return data.
|
||||
bool success = token.call(abi.encodeWithSelector(
|
||||
IERC20Token(token).transferFrom.selector,
|
||||
from,
|
||||
to,
|
||||
amount
|
||||
));
|
||||
require(
|
||||
success,
|
||||
TRANSFER_FAILED
|
||||
);
|
||||
|
||||
// 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 {
|
||||
success := 0
|
||||
if eq(returndatasize, 32) {
|
||||
// First 64 bytes of memory are reserved scratch space
|
||||
returndatacopy(0, 0, 32)
|
||||
success := mload(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
require(
|
||||
success,
|
||||
TRANSFER_FAILED
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Gets the proxy id associated with the proxy address.
|
||||
/// @return Proxy id.
|
||||
function getProxyId()
|
||||
external
|
||||
view
|
||||
returns (uint8)
|
||||
{
|
||||
return PROXY_ID;
|
||||
}
|
||||
}
|
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
|
||||
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.4.24;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "../../utils/LibBytes/LibBytes.sol";
|
||||
import "./MixinAssetProxy.sol";
|
||||
import "./MixinAuthorizable.sol";
|
||||
import "../../tokens/ERC721Token/ERC721Token.sol";
|
||||
|
||||
contract ERC721Proxy is
|
||||
LibBytes,
|
||||
MixinAssetProxy,
|
||||
MixinAuthorizable
|
||||
{
|
||||
|
||||
// Id of this proxy.
|
||||
uint8 constant PROXY_ID = 2;
|
||||
|
||||
/// @dev Internal version of `transferFrom`.
|
||||
/// @param assetData Encoded byte array.
|
||||
/// @param from Address to transfer asset from.
|
||||
/// @param to Address to transfer asset to.
|
||||
/// @param amount Amount of asset to transfer.
|
||||
function transferFromInternal(
|
||||
bytes memory assetData,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
)
|
||||
internal
|
||||
{
|
||||
// There exists only 1 of each token.
|
||||
require(
|
||||
amount == 1,
|
||||
INVALID_AMOUNT
|
||||
);
|
||||
|
||||
// Decode asset data.
|
||||
(
|
||||
address token,
|
||||
uint256 tokenId,
|
||||
bytes memory receiverData
|
||||
) = decodeERC721AssetData(assetData);
|
||||
|
||||
// Transfer token. Saves gas by calling safeTransferFrom only
|
||||
// when there is receiverData present. Either succeeds or throws.
|
||||
if (receiverData.length > 0) {
|
||||
ERC721Token(token).safeTransferFrom(from, to, tokenId, receiverData);
|
||||
} else {
|
||||
ERC721Token(token).transferFrom(from, to, tokenId);
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Gets the proxy id associated with the proxy address.
|
||||
/// @return Proxy id.
|
||||
function getProxyId()
|
||||
external
|
||||
view
|
||||
returns (uint8)
|
||||
{
|
||||
return PROXY_ID;
|
||||
}
|
||||
|
||||
/// @dev Decodes ERC721 Asset data.
|
||||
/// @param assetData Encoded byte array.
|
||||
/// @return proxyId Intended ERC721 proxy id.
|
||||
/// @return token ERC721 token address.
|
||||
/// @return tokenId ERC721 token id.
|
||||
/// @return receiverData Additional data with no specific format, which
|
||||
/// is passed to the receiving contract's onERC721Received.
|
||||
function decodeERC721AssetData(bytes memory assetData)
|
||||
internal
|
||||
pure
|
||||
returns (
|
||||
address token,
|
||||
uint256 tokenId,
|
||||
bytes memory receiverData
|
||||
)
|
||||
{
|
||||
// Decode asset data.
|
||||
token = readAddress(assetData, 0);
|
||||
tokenId = readUint256(assetData, 20);
|
||||
if (assetData.length > 52) {
|
||||
receiverData = readBytes(assetData, 52);
|
||||
}
|
||||
|
||||
return (
|
||||
token,
|
||||
tokenId,
|
||||
receiverData
|
||||
);
|
||||
}
|
||||
}
|
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
|
||||
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.4.24;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "./mixins/MAuthorizable.sol";
|
||||
import "./mixins/MAssetProxy.sol";
|
||||
|
||||
contract MixinAssetProxy is
|
||||
MAuthorizable,
|
||||
MAssetProxy
|
||||
{
|
||||
|
||||
/// @dev Transfers assets. Either succeeds or throws.
|
||||
/// @param assetData Encoded byte array.
|
||||
/// @param from Address to transfer asset from.
|
||||
/// @param to Address to transfer asset to.
|
||||
/// @param amount Amount of asset to transfer.
|
||||
function transferFrom(
|
||||
bytes assetData,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
)
|
||||
external
|
||||
onlyAuthorized
|
||||
{
|
||||
transferFromInternal(
|
||||
assetData,
|
||||
from,
|
||||
to,
|
||||
amount
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Makes multiple transfers of assets. Either succeeds or throws.
|
||||
/// @param assetData Array of byte arrays encoded for the respective asset proxy.
|
||||
/// @param from Array of addresses to transfer assets from.
|
||||
/// @param to Array of addresses to transfer assets to.
|
||||
/// @param amounts Array of amounts of assets to transfer.
|
||||
function batchTransferFrom(
|
||||
bytes[] memory assetData,
|
||||
address[] memory from,
|
||||
address[] memory to,
|
||||
uint256[] memory amounts
|
||||
)
|
||||
public
|
||||
onlyAuthorized
|
||||
{
|
||||
for (uint256 i = 0; i < assetData.length; i++) {
|
||||
transferFromInternal(
|
||||
assetData[i],
|
||||
from[i],
|
||||
to[i],
|
||||
amounts[i]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
|
||||
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.4.24;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "./libs/LibAssetProxyErrors.sol";
|
||||
import "../../utils/Ownable/Ownable.sol";
|
||||
import "./mixins/MAuthorizable.sol";
|
||||
|
||||
contract MixinAuthorizable is
|
||||
LibAssetProxyErrors,
|
||||
Ownable,
|
||||
MAuthorizable
|
||||
{
|
||||
|
||||
/// @dev Only authorized addresses can invoke functions with this modifier.
|
||||
modifier onlyAuthorized {
|
||||
require(
|
||||
authorized[msg.sender],
|
||||
SENDER_NOT_AUTHORIZED
|
||||
);
|
||||
_;
|
||||
}
|
||||
|
||||
mapping (address => bool) public authorized;
|
||||
address[] public authorities;
|
||||
|
||||
/// @dev Authorizes an address.
|
||||
/// @param target Address to authorize.
|
||||
function addAuthorizedAddress(address target)
|
||||
external
|
||||
onlyOwner
|
||||
{
|
||||
require(
|
||||
!authorized[target],
|
||||
TARGET_ALREADY_AUTHORIZED
|
||||
);
|
||||
|
||||
authorized[target] = true;
|
||||
authorities.push(target);
|
||||
emit AuthorizedAddressAdded(target, msg.sender);
|
||||
}
|
||||
|
||||
/// @dev Removes authorizion of an address.
|
||||
/// @param target Address to remove authorization from.
|
||||
function removeAuthorizedAddress(address target)
|
||||
external
|
||||
onlyOwner
|
||||
{
|
||||
require(
|
||||
authorized[target],
|
||||
TARGET_NOT_AUTHORIZED
|
||||
);
|
||||
|
||||
delete authorized[target];
|
||||
for (uint i = 0; i < authorities.length; i++) {
|
||||
if (authorities[i] == target) {
|
||||
authorities[i] = authorities[authorities.length - 1];
|
||||
authorities.length -= 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
emit AuthorizedAddressRemoved(target, msg.sender);
|
||||
}
|
||||
|
||||
/// @dev Removes authorizion of an address.
|
||||
/// @param target Address to remove authorization from.
|
||||
/// @param index Index of target in authorities array.
|
||||
function removeAuthorizedAddressAtIndex(
|
||||
address target,
|
||||
uint256 index
|
||||
)
|
||||
external
|
||||
{
|
||||
require(
|
||||
index < authorities.length,
|
||||
INDEX_OUT_OF_BOUNDS
|
||||
);
|
||||
require(
|
||||
authorities[index] == target,
|
||||
AUTHORIZED_ADDRESS_MISMATCH
|
||||
);
|
||||
|
||||
delete authorized[target];
|
||||
authorities[index] = authorities[authorities.length - 1];
|
||||
authorities.length -= 1;
|
||||
emit AuthorizedAddressRemoved(target, msg.sender);
|
||||
}
|
||||
|
||||
/// @dev Gets all authorized addresses.
|
||||
/// @return Array of authorized addresses.
|
||||
function getAuthorizedAddresses()
|
||||
external
|
||||
view
|
||||
returns (address[] memory)
|
||||
{
|
||||
return authorities;
|
||||
}
|
||||
}
|
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
|
||||
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.4.24;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "./IAuthorizable.sol";
|
||||
|
||||
contract IAssetProxy is
|
||||
IAuthorizable
|
||||
{
|
||||
|
||||
/// @dev Transfers assets. Either succeeds or throws.
|
||||
/// @param assetData Byte array encoded for the respective asset proxy.
|
||||
/// @param from Address to transfer asset from.
|
||||
/// @param to Address to transfer asset to.
|
||||
/// @param amount Amount of asset to transfer.
|
||||
function transferFrom(
|
||||
bytes assetData,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
)
|
||||
external;
|
||||
|
||||
/// @dev Makes multiple transfers of assets. Either succeeds or throws.
|
||||
/// @param assetData Array of byte arrays encoded for the respective asset proxy.
|
||||
/// @param from Array of addresses to transfer assets from.
|
||||
/// @param to Array of addresses to transfer assets to.
|
||||
/// @param amounts Array of amounts of assets to transfer.
|
||||
function batchTransferFrom(
|
||||
bytes[] memory assetData,
|
||||
address[] memory from,
|
||||
address[] memory to,
|
||||
uint256[] memory amounts
|
||||
)
|
||||
public;
|
||||
|
||||
/// @dev Gets the proxy id associated with the proxy address.
|
||||
/// @return Proxy id.
|
||||
function getProxyId()
|
||||
external
|
||||
view
|
||||
returns (uint8);
|
||||
}
|
||||
|
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
|
||||
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.4.24;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "../../../utils/Ownable/IOwnable.sol";
|
||||
|
||||
contract IAuthorizable is
|
||||
IOwnable
|
||||
{
|
||||
|
||||
/// @dev Gets all authorized addresses.
|
||||
/// @return Array of authorized addresses.
|
||||
function getAuthorizedAddresses()
|
||||
external
|
||||
view
|
||||
returns (address[]);
|
||||
|
||||
/// @dev Authorizes an address.
|
||||
/// @param target Address to authorize.
|
||||
function addAuthorizedAddress(address target)
|
||||
external;
|
||||
|
||||
/// @dev Removes authorizion of an address.
|
||||
/// @param target Address to remove authorization from.
|
||||
function removeAuthorizedAddress(address target)
|
||||
external;
|
||||
|
||||
/// @dev Removes authorizion of an address.
|
||||
/// @param target Address to remove authorization from.
|
||||
/// @param index Index of target in authorities array.
|
||||
function removeAuthorizedAddressAtIndex(
|
||||
address target,
|
||||
uint256 index
|
||||
)
|
||||
external;
|
||||
}
|
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
|
||||
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.4.24;
|
||||
|
||||
contract LibAssetProxyErrors {
|
||||
/// Authorizable errors ///
|
||||
string constant SENDER_NOT_AUTHORIZED = "SENDER_NOT_AUTHORIZED"; // Sender not authorized to call this method.
|
||||
string constant TARGET_NOT_AUTHORIZED = "TARGET_NOT_AUTHORIZED"; // Target address not authorized to call this method.
|
||||
string constant TARGET_ALREADY_AUTHORIZED = "TARGET_ALREADY_AUTHORIZED"; // Target address must not already be authorized.
|
||||
string constant INDEX_OUT_OF_BOUNDS = "INDEX_OUT_OF_BOUNDS"; // Specified array index is out of bounds.
|
||||
string constant AUTHORIZED_ADDRESS_MISMATCH = "AUTHORIZED_ADDRESS_MISMATCH"; // Address at index does not match given target address.
|
||||
|
||||
/// AssetProxy errors ///
|
||||
string constant INVALID_AMOUNT = "INVALID_AMOUNT"; // Transfer amount must equal 1.
|
||||
string constant TRANSFER_FAILED = "TRANSFER_FAILED"; // Transfer failed.
|
||||
}
|
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
|
||||
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.4.24;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "../interfaces/IAssetProxy.sol";
|
||||
|
||||
contract MAssetProxy is
|
||||
IAssetProxy
|
||||
{
|
||||
|
||||
/// @dev Internal version of `transferFrom`.
|
||||
/// @param assetData Encoded byte array.
|
||||
/// @param from Address to transfer asset from.
|
||||
/// @param to Address to transfer asset to.
|
||||
/// @param amount Amount of asset to transfer.
|
||||
function transferFromInternal(
|
||||
bytes memory assetData,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
)
|
||||
internal;
|
||||
}
|
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
|
||||
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.4.24;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
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(); _; }
|
||||
}
|
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
|
||||
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.4.10;
|
||||
|
||||
import "../../multisig/MultiSigWalletWithTimeLock.sol";
|
||||
import "../../utils/LibBytes/LibBytes.sol";
|
||||
|
||||
contract AssetProxyOwner is
|
||||
LibBytes,
|
||||
MultiSigWalletWithTimeLock
|
||||
{
|
||||
|
||||
event AssetProxyRegistration(address assetProxyContract, bool isRegistered);
|
||||
|
||||
// Mapping of AssetProxy contract address =>
|
||||
// if this contract is allowed to call the AssetProxy's removeAuthorizedAddress method without a time lock.
|
||||
mapping (address => bool) public isAssetProxyRegistered;
|
||||
|
||||
bytes4 constant REMOVE_AUTHORIZED_ADDRESS_SELECTOR = bytes4(keccak256("removeAuthorizedAddress(address)"));
|
||||
|
||||
/// @dev Function will revert if the transaction does not call `removeAuthorizedAddress`
|
||||
/// on an approved AssetProxy contract.
|
||||
modifier validRemoveAuthorizedAddressTx(uint256 transactionId) {
|
||||
Transaction storage tx = transactions[transactionId];
|
||||
require(isAssetProxyRegistered[tx.destination]);
|
||||
require(isFunctionRemoveAuthorizedAddress(tx.data));
|
||||
_;
|
||||
}
|
||||
|
||||
/// @dev Contract constructor sets initial owners, required number of confirmations,
|
||||
/// time lock, and list of AssetProxy addresses.
|
||||
/// @param _owners List of initial owners.
|
||||
/// @param _assetProxyContracts Array of AssetProxy contract addresses.
|
||||
/// @param _required Number of required confirmations.
|
||||
/// @param _secondsTimeLocked Duration needed after a transaction is confirmed and before it becomes executable, in seconds.
|
||||
function AssetProxyOwner(
|
||||
address[] memory _owners,
|
||||
address[] memory _assetProxyContracts,
|
||||
uint256 _required,
|
||||
uint256 _secondsTimeLocked
|
||||
)
|
||||
public
|
||||
MultiSigWalletWithTimeLock(_owners, _required, _secondsTimeLocked)
|
||||
{
|
||||
for (uint256 i = 0; i < _assetProxyContracts.length; i++) {
|
||||
address assetProxy = _assetProxyContracts[i];
|
||||
require(assetProxy != address(0));
|
||||
isAssetProxyRegistered[assetProxy] = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Registers or deregisters an AssetProxy to be able to execute
|
||||
/// removeAuthorizedAddress without a timelock.
|
||||
/// @param assetProxyContract Address of AssetProxy contract.
|
||||
/// @param isRegistered Status of approval for AssetProxy contract.
|
||||
function registerAssetProxy(address assetProxyContract, bool isRegistered)
|
||||
public
|
||||
onlyWallet
|
||||
notNull(assetProxyContract)
|
||||
{
|
||||
isAssetProxyRegistered[assetProxyContract] = isRegistered;
|
||||
AssetProxyRegistration(assetProxyContract, isRegistered);
|
||||
}
|
||||
|
||||
/// @dev Allows execution of removeAuthorizedAddress without time lock.
|
||||
/// @param transactionId Transaction ID.
|
||||
function executeRemoveAuthorizedAddress(uint256 transactionId)
|
||||
public
|
||||
notExecuted(transactionId)
|
||||
fullyConfirmed(transactionId)
|
||||
validRemoveAuthorizedAddressTx(transactionId)
|
||||
{
|
||||
Transaction storage tx = transactions[transactionId];
|
||||
tx.executed = true;
|
||||
if (tx.destination.call.value(tx.value)(tx.data))
|
||||
Execution(transactionId);
|
||||
else {
|
||||
ExecutionFailure(transactionId);
|
||||
tx.executed = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Compares first 4 bytes of byte array to removeAuthorizedAddress function selector.
|
||||
/// @param data Transaction data.
|
||||
/// @return Successful if data is a call to removeAuthorizedAddress.
|
||||
function isFunctionRemoveAuthorizedAddress(bytes memory data)
|
||||
public
|
||||
pure
|
||||
returns (bool)
|
||||
{
|
||||
bytes4 first4Bytes = readFirst4(data);
|
||||
require(REMOVE_AUTHORIZED_ADDRESS_SELECTOR == first4Bytes);
|
||||
return true;
|
||||
}
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright 2017 ZeroEx Intl.
|
||||
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.
|
||||
@@ -16,587 +16,38 @@
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.4.14;
|
||||
pragma solidity ^0.4.24;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import { TokenTransferProxy } from "../TokenTransferProxy/TokenTransferProxy.sol";
|
||||
import { Token_v1 as Token } from "../../../previous/Token/Token_v1.sol";
|
||||
import { SafeMath_v1 as SafeMath } from "../../../previous/SafeMath/SafeMath_v1.sol";
|
||||
import "./MixinExchangeCore.sol";
|
||||
import "./MixinSignatureValidator.sol";
|
||||
import "./MixinSettlement.sol";
|
||||
import "./MixinWrapperFunctions.sol";
|
||||
import "./MixinAssetProxyDispatcher.sol";
|
||||
import "./MixinTransactions.sol";
|
||||
import "./MixinMatchOrders.sol";
|
||||
|
||||
/// @title Exchange - Facilitates exchange of ERC20 tokens.
|
||||
/// @author Amir Bandeali - <amir@0xProject.com>, Will Warren - <will@0xProject.com>
|
||||
contract Exchange is SafeMath {
|
||||
contract Exchange is
|
||||
MixinExchangeCore,
|
||||
MixinMatchOrders,
|
||||
MixinSettlement,
|
||||
MixinSignatureValidator,
|
||||
MixinTransactions,
|
||||
MixinAssetProxyDispatcher,
|
||||
MixinWrapperFunctions
|
||||
{
|
||||
|
||||
// Error Codes
|
||||
enum Errors {
|
||||
ORDER_EXPIRED, // Order has already expired
|
||||
ORDER_FULLY_FILLED_OR_CANCELLED, // Order has already been fully filled or cancelled
|
||||
ROUNDING_ERROR_TOO_LARGE, // Rounding error too large
|
||||
INSUFFICIENT_BALANCE_OR_ALLOWANCE // Insufficient balance or allowance for token transfer
|
||||
}
|
||||
string constant public VERSION = "2.0.1-alpha";
|
||||
|
||||
string constant public VERSION = "1.0.0";
|
||||
uint16 constant public EXTERNAL_QUERY_GAS_LIMIT = 4999; // Changes to state require at least 5000 gas
|
||||
|
||||
address public ZRX_TOKEN_CONTRACT;
|
||||
address public TOKEN_TRANSFER_PROXY_CONTRACT;
|
||||
|
||||
// Mappings of orderHash => amounts of takerTokenAmount filled or cancelled.
|
||||
mapping (bytes32 => uint) public filled;
|
||||
mapping (bytes32 => uint) public cancelled;
|
||||
|
||||
event LogFill(
|
||||
address indexed maker,
|
||||
address taker,
|
||||
address indexed feeRecipient,
|
||||
address makerToken,
|
||||
address takerToken,
|
||||
uint filledMakerTokenAmount,
|
||||
uint filledTakerTokenAmount,
|
||||
uint paidMakerFee,
|
||||
uint paidTakerFee,
|
||||
bytes32 indexed tokens, // keccak256(makerToken, takerToken), allows subscribing to a token pair
|
||||
bytes32 orderHash
|
||||
);
|
||||
|
||||
event LogCancel(
|
||||
address indexed maker,
|
||||
address indexed feeRecipient,
|
||||
address makerToken,
|
||||
address takerToken,
|
||||
uint cancelledMakerTokenAmount,
|
||||
uint cancelledTakerTokenAmount,
|
||||
bytes32 indexed tokens,
|
||||
bytes32 orderHash
|
||||
);
|
||||
|
||||
event LogError(uint8 indexed errorId, bytes32 indexed orderHash);
|
||||
|
||||
struct Order {
|
||||
address maker;
|
||||
address taker;
|
||||
address makerToken;
|
||||
address takerToken;
|
||||
address feeRecipient;
|
||||
uint makerTokenAmount;
|
||||
uint takerTokenAmount;
|
||||
uint makerFee;
|
||||
uint takerFee;
|
||||
uint expirationTimestampInSec;
|
||||
bytes32 orderHash;
|
||||
}
|
||||
|
||||
function Exchange(address _zrxToken, address _tokenTransferProxy) {
|
||||
ZRX_TOKEN_CONTRACT = _zrxToken;
|
||||
TOKEN_TRANSFER_PROXY_CONTRACT = _tokenTransferProxy;
|
||||
}
|
||||
|
||||
/*
|
||||
* Core exchange functions
|
||||
*/
|
||||
|
||||
/// @dev Fills the input order.
|
||||
/// @param orderAddresses Array of order's maker, taker, makerToken, takerToken, and feeRecipient.
|
||||
/// @param orderValues Array of order's makerTokenAmount, takerTokenAmount, makerFee, takerFee, expirationTimestampInSec, and salt.
|
||||
/// @param fillTakerTokenAmount Desired amount of takerToken to fill.
|
||||
/// @param shouldThrowOnInsufficientBalanceOrAllowance Test if transfer will fail before attempting.
|
||||
/// @param v ECDSA signature parameter v.
|
||||
/// @param r ECDSA signature parameters r.
|
||||
/// @param s ECDSA signature parameters s.
|
||||
/// @return Total amount of takerToken filled in trade.
|
||||
function fillOrder(
|
||||
address[5] orderAddresses,
|
||||
uint[6] orderValues,
|
||||
uint fillTakerTokenAmount,
|
||||
bool shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
uint8 v,
|
||||
bytes32 r,
|
||||
bytes32 s)
|
||||
public
|
||||
returns (uint filledTakerTokenAmount)
|
||||
{
|
||||
Order memory order = Order({
|
||||
maker: orderAddresses[0],
|
||||
taker: orderAddresses[1],
|
||||
makerToken: orderAddresses[2],
|
||||
takerToken: orderAddresses[3],
|
||||
feeRecipient: orderAddresses[4],
|
||||
makerTokenAmount: orderValues[0],
|
||||
takerTokenAmount: orderValues[1],
|
||||
makerFee: orderValues[2],
|
||||
takerFee: orderValues[3],
|
||||
expirationTimestampInSec: orderValues[4],
|
||||
orderHash: getOrderHash(orderAddresses, orderValues)
|
||||
});
|
||||
|
||||
require(order.taker == address(0) || order.taker == msg.sender);
|
||||
require(order.makerTokenAmount > 0 && order.takerTokenAmount > 0 && fillTakerTokenAmount > 0);
|
||||
require(isValidSignature(
|
||||
order.maker,
|
||||
order.orderHash,
|
||||
v,
|
||||
r,
|
||||
s
|
||||
));
|
||||
|
||||
if (block.timestamp >= order.expirationTimestampInSec) {
|
||||
LogError(uint8(Errors.ORDER_EXPIRED), order.orderHash);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint remainingTakerTokenAmount = safeSub(order.takerTokenAmount, getUnavailableTakerTokenAmount(order.orderHash));
|
||||
filledTakerTokenAmount = min256(fillTakerTokenAmount, remainingTakerTokenAmount);
|
||||
if (filledTakerTokenAmount == 0) {
|
||||
LogError(uint8(Errors.ORDER_FULLY_FILLED_OR_CANCELLED), order.orderHash);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (isRoundingError(filledTakerTokenAmount, order.takerTokenAmount, order.makerTokenAmount)) {
|
||||
LogError(uint8(Errors.ROUNDING_ERROR_TOO_LARGE), order.orderHash);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!shouldThrowOnInsufficientBalanceOrAllowance && !isTransferable(order, filledTakerTokenAmount)) {
|
||||
LogError(uint8(Errors.INSUFFICIENT_BALANCE_OR_ALLOWANCE), order.orderHash);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint filledMakerTokenAmount = getPartialAmount(filledTakerTokenAmount, order.takerTokenAmount, order.makerTokenAmount);
|
||||
uint paidMakerFee;
|
||||
uint paidTakerFee;
|
||||
filled[order.orderHash] = safeAdd(filled[order.orderHash], filledTakerTokenAmount);
|
||||
require(transferViaTokenTransferProxy(
|
||||
order.makerToken,
|
||||
order.maker,
|
||||
msg.sender,
|
||||
filledMakerTokenAmount
|
||||
));
|
||||
require(transferViaTokenTransferProxy(
|
||||
order.takerToken,
|
||||
msg.sender,
|
||||
order.maker,
|
||||
filledTakerTokenAmount
|
||||
));
|
||||
if (order.feeRecipient != address(0)) {
|
||||
if (order.makerFee > 0) {
|
||||
paidMakerFee = getPartialAmount(filledTakerTokenAmount, order.takerTokenAmount, order.makerFee);
|
||||
require(transferViaTokenTransferProxy(
|
||||
ZRX_TOKEN_CONTRACT,
|
||||
order.maker,
|
||||
order.feeRecipient,
|
||||
paidMakerFee
|
||||
));
|
||||
}
|
||||
if (order.takerFee > 0) {
|
||||
paidTakerFee = getPartialAmount(filledTakerTokenAmount, order.takerTokenAmount, order.takerFee);
|
||||
require(transferViaTokenTransferProxy(
|
||||
ZRX_TOKEN_CONTRACT,
|
||||
msg.sender,
|
||||
order.feeRecipient,
|
||||
paidTakerFee
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
LogFill(
|
||||
order.maker,
|
||||
msg.sender,
|
||||
order.feeRecipient,
|
||||
order.makerToken,
|
||||
order.takerToken,
|
||||
filledMakerTokenAmount,
|
||||
filledTakerTokenAmount,
|
||||
paidMakerFee,
|
||||
paidTakerFee,
|
||||
keccak256(order.makerToken, order.takerToken),
|
||||
order.orderHash
|
||||
);
|
||||
return filledTakerTokenAmount;
|
||||
}
|
||||
|
||||
/// @dev Cancels the input order.
|
||||
/// @param orderAddresses Array of order's maker, taker, makerToken, takerToken, and feeRecipient.
|
||||
/// @param orderValues Array of order's makerTokenAmount, takerTokenAmount, makerFee, takerFee, expirationTimestampInSec, and salt.
|
||||
/// @param cancelTakerTokenAmount Desired amount of takerToken to cancel in order.
|
||||
/// @return Amount of takerToken cancelled.
|
||||
function cancelOrder(
|
||||
address[5] orderAddresses,
|
||||
uint[6] orderValues,
|
||||
uint cancelTakerTokenAmount)
|
||||
// Mixins are instantiated in the order they are inherited
|
||||
constructor (bytes memory _zrxAssetData)
|
||||
public
|
||||
returns (uint)
|
||||
{
|
||||
Order memory order = Order({
|
||||
maker: orderAddresses[0],
|
||||
taker: orderAddresses[1],
|
||||
makerToken: orderAddresses[2],
|
||||
takerToken: orderAddresses[3],
|
||||
feeRecipient: orderAddresses[4],
|
||||
makerTokenAmount: orderValues[0],
|
||||
takerTokenAmount: orderValues[1],
|
||||
makerFee: orderValues[2],
|
||||
takerFee: orderValues[3],
|
||||
expirationTimestampInSec: orderValues[4],
|
||||
orderHash: getOrderHash(orderAddresses, orderValues)
|
||||
});
|
||||
|
||||
require(order.maker == msg.sender);
|
||||
require(order.makerTokenAmount > 0 && order.takerTokenAmount > 0 && cancelTakerTokenAmount > 0);
|
||||
|
||||
if (block.timestamp >= order.expirationTimestampInSec) {
|
||||
LogError(uint8(Errors.ORDER_EXPIRED), order.orderHash);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint remainingTakerTokenAmount = safeSub(order.takerTokenAmount, getUnavailableTakerTokenAmount(order.orderHash));
|
||||
uint cancelledTakerTokenAmount = min256(cancelTakerTokenAmount, remainingTakerTokenAmount);
|
||||
if (cancelledTakerTokenAmount == 0) {
|
||||
LogError(uint8(Errors.ORDER_FULLY_FILLED_OR_CANCELLED), order.orderHash);
|
||||
return 0;
|
||||
}
|
||||
|
||||
cancelled[order.orderHash] = safeAdd(cancelled[order.orderHash], cancelledTakerTokenAmount);
|
||||
|
||||
LogCancel(
|
||||
order.maker,
|
||||
order.feeRecipient,
|
||||
order.makerToken,
|
||||
order.takerToken,
|
||||
getPartialAmount(cancelledTakerTokenAmount, order.takerTokenAmount, order.makerTokenAmount),
|
||||
cancelledTakerTokenAmount,
|
||||
keccak256(order.makerToken, order.takerToken),
|
||||
order.orderHash
|
||||
);
|
||||
return cancelledTakerTokenAmount;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wrapper functions
|
||||
*/
|
||||
|
||||
/// @dev Fills an order with specified parameters and ECDSA signature, throws if specified amount not filled entirely.
|
||||
/// @param orderAddresses Array of order's maker, taker, makerToken, takerToken, and feeRecipient.
|
||||
/// @param orderValues Array of order's makerTokenAmount, takerTokenAmount, makerFee, takerFee, expirationTimestampInSec, and salt.
|
||||
/// @param fillTakerTokenAmount Desired amount of takerToken to fill.
|
||||
/// @param v ECDSA signature parameter v.
|
||||
/// @param r ECDSA signature parameters r.
|
||||
/// @param s ECDSA signature parameters s.
|
||||
function fillOrKillOrder(
|
||||
address[5] orderAddresses,
|
||||
uint[6] orderValues,
|
||||
uint fillTakerTokenAmount,
|
||||
uint8 v,
|
||||
bytes32 r,
|
||||
bytes32 s)
|
||||
public
|
||||
{
|
||||
require(fillOrder(
|
||||
orderAddresses,
|
||||
orderValues,
|
||||
fillTakerTokenAmount,
|
||||
false,
|
||||
v,
|
||||
r,
|
||||
s
|
||||
) == fillTakerTokenAmount);
|
||||
}
|
||||
|
||||
/// @dev Synchronously executes multiple fill orders in a single transaction.
|
||||
/// @param orderAddresses Array of address arrays containing individual order addresses.
|
||||
/// @param orderValues Array of uint arrays containing individual order values.
|
||||
/// @param fillTakerTokenAmounts Array of desired amounts of takerToken to fill in orders.
|
||||
/// @param shouldThrowOnInsufficientBalanceOrAllowance Test if transfers will fail before attempting.
|
||||
/// @param v Array ECDSA signature v parameters.
|
||||
/// @param r Array of ECDSA signature r parameters.
|
||||
/// @param s Array of ECDSA signature s parameters.
|
||||
function batchFillOrders(
|
||||
address[5][] orderAddresses,
|
||||
uint[6][] orderValues,
|
||||
uint[] fillTakerTokenAmounts,
|
||||
bool shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
uint8[] v,
|
||||
bytes32[] r,
|
||||
bytes32[] s)
|
||||
public
|
||||
{
|
||||
for (uint i = 0; i < orderAddresses.length; i++) {
|
||||
fillOrder(
|
||||
orderAddresses[i],
|
||||
orderValues[i],
|
||||
fillTakerTokenAmounts[i],
|
||||
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
v[i],
|
||||
r[i],
|
||||
s[i]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Synchronously executes multiple fillOrKill orders in a single transaction.
|
||||
/// @param orderAddresses Array of address arrays containing individual order addresses.
|
||||
/// @param orderValues Array of uint arrays containing individual order values.
|
||||
/// @param fillTakerTokenAmounts Array of desired amounts of takerToken to fill in orders.
|
||||
/// @param v Array ECDSA signature v parameters.
|
||||
/// @param r Array of ECDSA signature r parameters.
|
||||
/// @param s Array of ECDSA signature s parameters.
|
||||
function batchFillOrKillOrders(
|
||||
address[5][] orderAddresses,
|
||||
uint[6][] orderValues,
|
||||
uint[] fillTakerTokenAmounts,
|
||||
uint8[] v,
|
||||
bytes32[] r,
|
||||
bytes32[] s)
|
||||
public
|
||||
{
|
||||
for (uint i = 0; i < orderAddresses.length; i++) {
|
||||
fillOrKillOrder(
|
||||
orderAddresses[i],
|
||||
orderValues[i],
|
||||
fillTakerTokenAmounts[i],
|
||||
v[i],
|
||||
r[i],
|
||||
s[i]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Synchronously executes multiple fill orders in a single transaction until total fillTakerTokenAmount filled.
|
||||
/// @param orderAddresses Array of address arrays containing individual order addresses.
|
||||
/// @param orderValues Array of uint arrays containing individual order values.
|
||||
/// @param fillTakerTokenAmount Desired total amount of takerToken to fill in orders.
|
||||
/// @param shouldThrowOnInsufficientBalanceOrAllowance Test if transfers will fail before attempting.
|
||||
/// @param v Array ECDSA signature v parameters.
|
||||
/// @param r Array of ECDSA signature r parameters.
|
||||
/// @param s Array of ECDSA signature s parameters.
|
||||
/// @return Total amount of fillTakerTokenAmount filled in orders.
|
||||
function fillOrdersUpTo(
|
||||
address[5][] orderAddresses,
|
||||
uint[6][] orderValues,
|
||||
uint fillTakerTokenAmount,
|
||||
bool shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
uint8[] v,
|
||||
bytes32[] r,
|
||||
bytes32[] s)
|
||||
public
|
||||
returns (uint)
|
||||
{
|
||||
uint filledTakerTokenAmount = 0;
|
||||
for (uint i = 0; i < orderAddresses.length; i++) {
|
||||
require(orderAddresses[i][3] == orderAddresses[0][3]); // takerToken must be the same for each order
|
||||
filledTakerTokenAmount = safeAdd(filledTakerTokenAmount, fillOrder(
|
||||
orderAddresses[i],
|
||||
orderValues[i],
|
||||
safeSub(fillTakerTokenAmount, filledTakerTokenAmount),
|
||||
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
v[i],
|
||||
r[i],
|
||||
s[i]
|
||||
));
|
||||
if (filledTakerTokenAmount == fillTakerTokenAmount) break;
|
||||
}
|
||||
return filledTakerTokenAmount;
|
||||
}
|
||||
|
||||
/// @dev Synchronously cancels multiple orders in a single transaction.
|
||||
/// @param orderAddresses Array of address arrays containing individual order addresses.
|
||||
/// @param orderValues Array of uint arrays containing individual order values.
|
||||
/// @param cancelTakerTokenAmounts Array of desired amounts of takerToken to cancel in orders.
|
||||
function batchCancelOrders(
|
||||
address[5][] orderAddresses,
|
||||
uint[6][] orderValues,
|
||||
uint[] cancelTakerTokenAmounts)
|
||||
public
|
||||
{
|
||||
for (uint i = 0; i < orderAddresses.length; i++) {
|
||||
cancelOrder(
|
||||
orderAddresses[i],
|
||||
orderValues[i],
|
||||
cancelTakerTokenAmounts[i]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Constant public functions
|
||||
*/
|
||||
|
||||
/// @dev Calculates Keccak-256 hash of order with specified parameters.
|
||||
/// @param orderAddresses Array of order's maker, taker, makerToken, takerToken, and feeRecipient.
|
||||
/// @param orderValues Array of order's makerTokenAmount, takerTokenAmount, makerFee, takerFee, expirationTimestampInSec, and salt.
|
||||
/// @return Keccak-256 hash of order.
|
||||
function getOrderHash(address[5] orderAddresses, uint[6] orderValues)
|
||||
public
|
||||
constant
|
||||
returns (bytes32)
|
||||
{
|
||||
return keccak256(
|
||||
address(this),
|
||||
orderAddresses[0], // maker
|
||||
orderAddresses[1], // taker
|
||||
orderAddresses[2], // makerToken
|
||||
orderAddresses[3], // takerToken
|
||||
orderAddresses[4], // feeRecipient
|
||||
orderValues[0], // makerTokenAmount
|
||||
orderValues[1], // takerTokenAmount
|
||||
orderValues[2], // makerFee
|
||||
orderValues[3], // takerFee
|
||||
orderValues[4], // expirationTimestampInSec
|
||||
orderValues[5] // salt
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Verifies that an order signature is valid.
|
||||
/// @param signer address of signer.
|
||||
/// @param hash Signed Keccak-256 hash.
|
||||
/// @param v ECDSA signature parameter v.
|
||||
/// @param r ECDSA signature parameters r.
|
||||
/// @param s ECDSA signature parameters s.
|
||||
/// @return Validity of order signature.
|
||||
function isValidSignature(
|
||||
address signer,
|
||||
bytes32 hash,
|
||||
uint8 v,
|
||||
bytes32 r,
|
||||
bytes32 s)
|
||||
public
|
||||
constant
|
||||
returns (bool)
|
||||
{
|
||||
return signer == ecrecover(
|
||||
keccak256("\x19Ethereum Signed Message:\n32", hash),
|
||||
v,
|
||||
r,
|
||||
s
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Checks if rounding error > 0.1%.
|
||||
/// @param numerator Numerator.
|
||||
/// @param denominator Denominator.
|
||||
/// @param target Value to multiply with numerator/denominator.
|
||||
/// @return Rounding error is present.
|
||||
function isRoundingError(uint numerator, uint denominator, uint target)
|
||||
public
|
||||
constant
|
||||
returns (bool)
|
||||
{
|
||||
uint remainder = mulmod(target, numerator, denominator);
|
||||
if (remainder == 0) return false; // No rounding error.
|
||||
|
||||
uint errPercentageTimes1000000 = safeDiv(
|
||||
safeMul(remainder, 1000000),
|
||||
safeMul(numerator, target)
|
||||
);
|
||||
return errPercentageTimes1000000 > 1000;
|
||||
}
|
||||
|
||||
/// @dev Calculates partial value given a numerator and denominator.
|
||||
/// @param numerator Numerator.
|
||||
/// @param denominator Denominator.
|
||||
/// @param target Value to calculate partial of.
|
||||
/// @return Partial value of target.
|
||||
function getPartialAmount(uint numerator, uint denominator, uint target)
|
||||
public
|
||||
constant
|
||||
returns (uint)
|
||||
{
|
||||
return safeDiv(safeMul(numerator, target), denominator);
|
||||
}
|
||||
|
||||
/// @dev Calculates the sum of values already filled and cancelled for a given order.
|
||||
/// @param orderHash The Keccak-256 hash of the given order.
|
||||
/// @return Sum of values already filled and cancelled.
|
||||
function getUnavailableTakerTokenAmount(bytes32 orderHash)
|
||||
public
|
||||
constant
|
||||
returns (uint)
|
||||
{
|
||||
return safeAdd(filled[orderHash], cancelled[orderHash]);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Internal functions
|
||||
*/
|
||||
|
||||
/// @dev Transfers a token using TokenTransferProxy transferFrom function.
|
||||
/// @param token Address of token to transferFrom.
|
||||
/// @param from Address transfering token.
|
||||
/// @param to Address receiving token.
|
||||
/// @param value Amount of token to transfer.
|
||||
/// @return Success of token transfer.
|
||||
function transferViaTokenTransferProxy(
|
||||
address token,
|
||||
address from,
|
||||
address to,
|
||||
uint value)
|
||||
internal
|
||||
returns (bool)
|
||||
{
|
||||
return TokenTransferProxy(TOKEN_TRANSFER_PROXY_CONTRACT).transferFrom(token, from, to, value);
|
||||
}
|
||||
|
||||
/// @dev Checks if any order transfers will fail.
|
||||
/// @param order Order struct of params that will be checked.
|
||||
/// @param fillTakerTokenAmount Desired amount of takerToken to fill.
|
||||
/// @return Predicted result of transfers.
|
||||
function isTransferable(Order order, uint fillTakerTokenAmount)
|
||||
internal
|
||||
constant // The called token contracts may attempt to change state, but will not be able to due to gas limits on getBalance and getAllowance.
|
||||
returns (bool)
|
||||
{
|
||||
address taker = msg.sender;
|
||||
uint fillMakerTokenAmount = getPartialAmount(fillTakerTokenAmount, order.takerTokenAmount, order.makerTokenAmount);
|
||||
|
||||
if (order.feeRecipient != address(0)) {
|
||||
bool isMakerTokenZRX = order.makerToken == ZRX_TOKEN_CONTRACT;
|
||||
bool isTakerTokenZRX = order.takerToken == ZRX_TOKEN_CONTRACT;
|
||||
uint paidMakerFee = getPartialAmount(fillTakerTokenAmount, order.takerTokenAmount, order.makerFee);
|
||||
uint paidTakerFee = getPartialAmount(fillTakerTokenAmount, order.takerTokenAmount, order.takerFee);
|
||||
uint requiredMakerZRX = isMakerTokenZRX ? safeAdd(fillMakerTokenAmount, paidMakerFee) : paidMakerFee;
|
||||
uint requiredTakerZRX = isTakerTokenZRX ? safeAdd(fillTakerTokenAmount, paidTakerFee) : paidTakerFee;
|
||||
|
||||
if ( getBalance(ZRX_TOKEN_CONTRACT, order.maker) < requiredMakerZRX
|
||||
|| getAllowance(ZRX_TOKEN_CONTRACT, order.maker) < requiredMakerZRX
|
||||
|| getBalance(ZRX_TOKEN_CONTRACT, taker) < requiredTakerZRX
|
||||
|| getAllowance(ZRX_TOKEN_CONTRACT, taker) < requiredTakerZRX
|
||||
) return false;
|
||||
|
||||
if (!isMakerTokenZRX && ( getBalance(order.makerToken, order.maker) < fillMakerTokenAmount // Don't double check makerToken if ZRX
|
||||
|| getAllowance(order.makerToken, order.maker) < fillMakerTokenAmount)
|
||||
) return false;
|
||||
if (!isTakerTokenZRX && ( getBalance(order.takerToken, taker) < fillTakerTokenAmount // Don't double check takerToken if ZRX
|
||||
|| getAllowance(order.takerToken, taker) < fillTakerTokenAmount)
|
||||
) return false;
|
||||
} else if ( getBalance(order.makerToken, order.maker) < fillMakerTokenAmount
|
||||
|| getAllowance(order.makerToken, order.maker) < fillMakerTokenAmount
|
||||
|| getBalance(order.takerToken, taker) < fillTakerTokenAmount
|
||||
|| getAllowance(order.takerToken, taker) < fillTakerTokenAmount
|
||||
) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// @dev Get token balance of an address.
|
||||
/// @param token Address of token.
|
||||
/// @param owner Address of owner.
|
||||
/// @return Token balance of owner.
|
||||
function getBalance(address token, address owner)
|
||||
internal
|
||||
constant // The called token contract may attempt to change state, but will not be able to due to an added gas limit.
|
||||
returns (uint)
|
||||
{
|
||||
return Token(token).balanceOf.gas(EXTERNAL_QUERY_GAS_LIMIT)(owner); // Limit gas to prevent reentrancy
|
||||
}
|
||||
|
||||
/// @dev Get allowance of token given to TokenTransferProxy by an address.
|
||||
/// @param token Address of token.
|
||||
/// @param owner Address of owner.
|
||||
/// @return Allowance of token given to TokenTransferProxy by owner.
|
||||
function getAllowance(address token, address owner)
|
||||
internal
|
||||
constant // The called token contract may attempt to change state, but will not be able to due to an added gas limit.
|
||||
returns (uint)
|
||||
{
|
||||
return Token(token).allowance.gas(EXTERNAL_QUERY_GAS_LIMIT)(owner, TOKEN_TRANSFER_PROXY_CONTRACT); // Limit gas to prevent reentrancy
|
||||
}
|
||||
MixinExchangeCore()
|
||||
MixinMatchOrders()
|
||||
MixinSettlement(_zrxAssetData)
|
||||
MixinSignatureValidator()
|
||||
MixinTransactions()
|
||||
MixinAssetProxyDispatcher()
|
||||
MixinWrapperFunctions()
|
||||
{}
|
||||
}
|
||||
|
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
|
||||
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.4.24;
|
||||
|
||||
import "../../utils/Ownable/Ownable.sol";
|
||||
import "../../utils/LibBytes/LibBytes.sol";
|
||||
import "./libs/LibExchangeErrors.sol";
|
||||
import "./mixins/MAssetProxyDispatcher.sol";
|
||||
import "../AssetProxy/interfaces/IAssetProxy.sol";
|
||||
|
||||
contract MixinAssetProxyDispatcher is
|
||||
Ownable,
|
||||
LibBytes,
|
||||
LibExchangeErrors,
|
||||
MAssetProxyDispatcher
|
||||
{
|
||||
// Mapping from Asset Proxy Id's to their respective Asset Proxy
|
||||
mapping (uint8 => IAssetProxy) public assetProxies;
|
||||
|
||||
/// @dev Registers an asset proxy to an asset proxy id.
|
||||
/// An id can only be assigned to a single proxy at a given time.
|
||||
/// @param assetProxyId Id to register`newAssetProxy` under.
|
||||
/// @param newAssetProxy Address of new asset proxy to register, or 0x0 to unset assetProxyId.
|
||||
/// @param oldAssetProxy Existing asset proxy to overwrite, or 0x0 if assetProxyId is currently unused.
|
||||
function registerAssetProxy(
|
||||
uint8 assetProxyId,
|
||||
address newAssetProxy,
|
||||
address oldAssetProxy
|
||||
)
|
||||
external
|
||||
onlyOwner
|
||||
{
|
||||
// Ensure the existing asset proxy is not unintentionally overwritten
|
||||
address currentAssetProxy = address(assetProxies[assetProxyId]);
|
||||
require(
|
||||
oldAssetProxy == currentAssetProxy,
|
||||
ASSET_PROXY_MISMATCH
|
||||
);
|
||||
|
||||
IAssetProxy assetProxy = IAssetProxy(newAssetProxy);
|
||||
|
||||
// Ensure that the id of newAssetProxy matches the passed in assetProxyId, unless it is being reset to 0.
|
||||
if (newAssetProxy != address(0)) {
|
||||
uint8 newAssetProxyId = assetProxy.getProxyId();
|
||||
require(
|
||||
newAssetProxyId == assetProxyId,
|
||||
ASSET_PROXY_ID_MISMATCH
|
||||
);
|
||||
}
|
||||
|
||||
// Add asset proxy and log registration.
|
||||
assetProxies[assetProxyId] = assetProxy;
|
||||
emit AssetProxySet(assetProxyId, newAssetProxy, oldAssetProxy);
|
||||
}
|
||||
|
||||
/// @dev Gets an asset proxy.
|
||||
/// @param assetProxyId Id of the asset proxy.
|
||||
/// @return The asset proxy registered to assetProxyId. Returns 0x0 if no proxy is registered.
|
||||
function getAssetProxy(uint8 assetProxyId)
|
||||
external
|
||||
view
|
||||
returns (address)
|
||||
{
|
||||
address assetProxy = address(assetProxies[assetProxyId]);
|
||||
return assetProxy;
|
||||
}
|
||||
|
||||
/// @dev Forwards arguments to assetProxy and calls `transferFrom`. Either succeeds or throws.
|
||||
/// @param assetData Byte array encoded for the respective asset proxy.
|
||||
/// @param assetProxyId Id of assetProxy to dispach to.
|
||||
/// @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,
|
||||
uint8 assetProxyId,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
)
|
||||
internal
|
||||
{
|
||||
// Do nothing if no amount should be transferred.
|
||||
if (amount > 0) {
|
||||
// Lookup assetProxy
|
||||
IAssetProxy assetProxy = assetProxies[assetProxyId];
|
||||
// transferFrom will either succeed or throw.
|
||||
assetProxy.transferFrom(assetData, from, to, amount);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,388 @@
|
||||
/*
|
||||
|
||||
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.4.24;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "./libs/LibFillResults.sol";
|
||||
import "./libs/LibOrder.sol";
|
||||
import "./libs/LibMath.sol";
|
||||
import "./libs/LibExchangeErrors.sol";
|
||||
import "./mixins/MExchangeCore.sol";
|
||||
import "./mixins/MSettlement.sol";
|
||||
import "./mixins/MSignatureValidator.sol";
|
||||
import "./mixins/MTransactions.sol";
|
||||
|
||||
contract MixinExchangeCore is
|
||||
LibMath,
|
||||
LibOrder,
|
||||
LibFillResults,
|
||||
LibExchangeErrors,
|
||||
MExchangeCore,
|
||||
MSettlement,
|
||||
MSignatureValidator,
|
||||
MTransactions
|
||||
{
|
||||
// Mapping of orderHash => amount of takerAsset already bought by maker
|
||||
mapping (bytes32 => uint256) public filled;
|
||||
|
||||
// Mapping of orderHash => cancelled
|
||||
mapping (bytes32 => bool) public cancelled;
|
||||
|
||||
// Mapping of makerAddress => lowest salt an order can have in order to be fillable
|
||||
// Orders with a salt less than their maker's epoch are considered cancelled
|
||||
mapping (address => uint256) public makerEpoch;
|
||||
|
||||
////// Core exchange functions //////
|
||||
|
||||
/// @dev Cancels all orders created by sender with a salt less than or equal to the specified salt value.
|
||||
/// @param salt Orders created with a salt less or equal to this value will be cancelled.
|
||||
function cancelOrdersUpTo(uint256 salt)
|
||||
external
|
||||
{
|
||||
address makerAddress = getCurrentContextAddress();
|
||||
|
||||
// makerEpoch is initialized to 0, so to cancelUpTo we need salt + 1
|
||||
uint256 newMakerEpoch = salt + 1;
|
||||
uint256 oldMakerEpoch = makerEpoch[makerAddress];
|
||||
|
||||
// Ensure makerEpoch is monotonically increasing
|
||||
require(
|
||||
newMakerEpoch > oldMakerEpoch,
|
||||
INVALID_NEW_MAKER_EPOCH
|
||||
);
|
||||
|
||||
// Update makerEpoch
|
||||
makerEpoch[makerAddress] = newMakerEpoch;
|
||||
emit CancelUpTo(makerAddress, newMakerEpoch);
|
||||
}
|
||||
|
||||
/// @dev Fills the input order.
|
||||
/// @param order Order struct containing order specifications.
|
||||
/// @param takerAssetFillAmount Desired amount of takerAsset to sell.
|
||||
/// @param signature Proof that order has been created by maker.
|
||||
/// @return Amounts filled and fees paid by maker and taker.
|
||||
function fillOrder(
|
||||
Order memory order,
|
||||
uint256 takerAssetFillAmount,
|
||||
bytes memory signature
|
||||
)
|
||||
public
|
||||
returns (FillResults memory fillResults)
|
||||
{
|
||||
// Fetch order info
|
||||
OrderInfo memory orderInfo = getOrderInfo(order);
|
||||
|
||||
// Fetch taker address
|
||||
address takerAddress = getCurrentContextAddress();
|
||||
|
||||
// Get amount of takerAsset to fill
|
||||
uint256 remainingTakerAssetAmount = safeSub(order.takerAssetAmount, orderInfo.orderTakerAssetFilledAmount);
|
||||
uint256 takerAssetFilledAmount = min256(takerAssetFillAmount, remainingTakerAssetAmount);
|
||||
|
||||
// Validate context
|
||||
assertValidFill(
|
||||
order,
|
||||
orderInfo,
|
||||
takerAddress,
|
||||
takerAssetFillAmount,
|
||||
takerAssetFilledAmount,
|
||||
signature
|
||||
);
|
||||
|
||||
// Compute proportional fill amounts
|
||||
fillResults = calculateFillResults(order, takerAssetFilledAmount);
|
||||
|
||||
// Update exchange internal state
|
||||
updateFilledState(
|
||||
order,
|
||||
takerAddress,
|
||||
orderInfo.orderHash,
|
||||
orderInfo.orderTakerAssetFilledAmount,
|
||||
fillResults
|
||||
);
|
||||
|
||||
// Settle order
|
||||
settleOrder(order, takerAddress, fillResults);
|
||||
|
||||
return fillResults;
|
||||
}
|
||||
|
||||
/// @dev After calling, the order can not be filled anymore.
|
||||
/// Throws if order is invalid or sender does not have permission to cancel.
|
||||
/// @param order Order to cancel. Order must be OrderStatus.FILLABLE.
|
||||
function cancelOrder(Order memory order)
|
||||
public
|
||||
{
|
||||
// Fetch current order status
|
||||
OrderInfo memory orderInfo = getOrderInfo(order);
|
||||
|
||||
// Validate context
|
||||
assertValidCancel(order, orderInfo);
|
||||
|
||||
// Perform cancel
|
||||
updateCancelledState(order, orderInfo.orderHash);
|
||||
}
|
||||
|
||||
/// @dev Gets information about an order: status, hash, and amount filled.
|
||||
/// @param order Order to gather information on.
|
||||
/// @return OrderInfo Information about the order and its state.
|
||||
/// See LibOrder.OrderInfo for a complete description.
|
||||
function getOrderInfo(Order memory order)
|
||||
public
|
||||
view
|
||||
returns (OrderInfo memory orderInfo)
|
||||
{
|
||||
// Compute the order hash
|
||||
orderInfo.orderHash = getOrderHash(order);
|
||||
|
||||
// If order.makerAssetAmount is zero, we also reject the order.
|
||||
// While the Exchange contract handles them correctly, they create
|
||||
// edge cases in the supporting infrastructure because they have
|
||||
// an 'infinite' price when computed by a simple division.
|
||||
if (order.makerAssetAmount == 0) {
|
||||
orderInfo.orderStatus = uint8(OrderStatus.INVALID_MAKER_ASSET_AMOUNT);
|
||||
return orderInfo;
|
||||
}
|
||||
|
||||
// If order.takerAssetAmount is zero, then the order will always
|
||||
// be considered filled because 0 == takerAssetAmount == orderTakerAssetFilledAmount
|
||||
// Instead of distinguishing between unfilled and filled zero taker
|
||||
// amount orders, we choose not to support them.
|
||||
if (order.takerAssetAmount == 0) {
|
||||
orderInfo.orderStatus = uint8(OrderStatus.INVALID_TAKER_ASSET_AMOUNT);
|
||||
return orderInfo;
|
||||
}
|
||||
|
||||
// Validate order expiration
|
||||
if (block.timestamp >= order.expirationTimeSeconds) {
|
||||
orderInfo.orderStatus = uint8(OrderStatus.EXPIRED);
|
||||
return orderInfo;
|
||||
}
|
||||
|
||||
// Check if order has been cancelled
|
||||
if (cancelled[orderInfo.orderHash]) {
|
||||
orderInfo.orderStatus = uint8(OrderStatus.CANCELLED);
|
||||
return orderInfo;
|
||||
}
|
||||
if (makerEpoch[order.makerAddress] > order.salt) {
|
||||
orderInfo.orderStatus = uint8(OrderStatus.CANCELLED);
|
||||
return orderInfo;
|
||||
}
|
||||
|
||||
// Fetch filled amount and validate order availability
|
||||
orderInfo.orderTakerAssetFilledAmount = filled[orderInfo.orderHash];
|
||||
if (orderInfo.orderTakerAssetFilledAmount >= order.takerAssetAmount) {
|
||||
orderInfo.orderStatus = uint8(OrderStatus.FULLY_FILLED);
|
||||
return orderInfo;
|
||||
}
|
||||
|
||||
// All other statuses are ruled out: order is Fillable
|
||||
orderInfo.orderStatus = uint8(OrderStatus.FILLABLE);
|
||||
return orderInfo;
|
||||
}
|
||||
|
||||
/// @dev Updates state with results of a fill order.
|
||||
/// @param order that was filled.
|
||||
/// @param takerAddress Address of taker who filled the order.
|
||||
/// @param orderTakerAssetFilledAmount Amount of order already filled.
|
||||
/// @return fillResults Amounts filled and fees paid by maker and taker.
|
||||
function updateFilledState(
|
||||
Order memory order,
|
||||
address takerAddress,
|
||||
bytes32 orderHash,
|
||||
uint256 orderTakerAssetFilledAmount,
|
||||
FillResults memory fillResults
|
||||
)
|
||||
internal
|
||||
{
|
||||
// Update state
|
||||
filled[orderHash] = safeAdd(orderTakerAssetFilledAmount, fillResults.takerAssetFilledAmount);
|
||||
|
||||
// Log order
|
||||
emit Fill(
|
||||
order.makerAddress,
|
||||
takerAddress,
|
||||
order.feeRecipientAddress,
|
||||
fillResults.makerAssetFilledAmount,
|
||||
fillResults.takerAssetFilledAmount,
|
||||
fillResults.makerFeePaid,
|
||||
fillResults.takerFeePaid,
|
||||
orderHash,
|
||||
order.makerAssetData,
|
||||
order.takerAssetData
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Updates state with results of cancelling an order.
|
||||
/// State is only updated if the order is currently fillable.
|
||||
/// Otherwise, updating state would have no effect.
|
||||
/// @param order that was cancelled.
|
||||
/// @param orderHash Hash of order that was cancelled.
|
||||
function updateCancelledState(
|
||||
Order memory order,
|
||||
bytes32 orderHash
|
||||
)
|
||||
internal
|
||||
{
|
||||
// Perform cancel
|
||||
cancelled[orderHash] = true;
|
||||
|
||||
// Log cancel
|
||||
emit Cancel(
|
||||
order.makerAddress,
|
||||
order.feeRecipientAddress,
|
||||
orderHash,
|
||||
order.makerAssetData,
|
||||
order.takerAssetData
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Validates context for fillOrder. Succeeds or throws.
|
||||
/// @param order to be filled.
|
||||
/// @param orderInfo OrderStatus, orderHash, and amount already filled of order.
|
||||
/// @param takerAddress Address of order taker.
|
||||
/// @param takerAssetFillAmount Desired amount of order to fill by taker.
|
||||
/// @param takerAssetFilledAmount Amount of takerAsset that will be filled.
|
||||
/// @param signature Proof that the orders was created by its maker.
|
||||
function assertValidFill(
|
||||
Order memory order,
|
||||
OrderInfo memory orderInfo,
|
||||
address takerAddress,
|
||||
uint256 takerAssetFillAmount,
|
||||
uint256 takerAssetFilledAmount,
|
||||
bytes memory signature
|
||||
)
|
||||
internal
|
||||
view
|
||||
{
|
||||
// An order can only be filled if its status is FILLABLE.
|
||||
require(
|
||||
orderInfo.orderStatus == uint8(OrderStatus.FILLABLE),
|
||||
ORDER_UNFILLABLE
|
||||
);
|
||||
|
||||
// Revert if fill amount is invalid
|
||||
require(
|
||||
takerAssetFillAmount != 0,
|
||||
INVALID_TAKER_AMOUNT
|
||||
);
|
||||
|
||||
// Validate sender is allowed to fill this order
|
||||
if (order.senderAddress != address(0)) {
|
||||
require(
|
||||
order.senderAddress == msg.sender,
|
||||
INVALID_SENDER
|
||||
);
|
||||
}
|
||||
|
||||
// Validate taker is allowed to fill this order
|
||||
if (order.takerAddress != address(0)) {
|
||||
require(
|
||||
order.takerAddress == takerAddress,
|
||||
INVALID_TAKER
|
||||
);
|
||||
}
|
||||
|
||||
// Validate Maker signature (check only if first time seen)
|
||||
if (orderInfo.orderTakerAssetFilledAmount == 0) {
|
||||
require(
|
||||
isValidSignature(orderInfo.orderHash, order.makerAddress, signature),
|
||||
INVALID_ORDER_SIGNATURE
|
||||
);
|
||||
}
|
||||
|
||||
// Validate fill order rounding
|
||||
require(
|
||||
!isRoundingError(
|
||||
takerAssetFilledAmount,
|
||||
order.takerAssetAmount,
|
||||
order.makerAssetAmount
|
||||
),
|
||||
ROUNDING_ERROR
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Validates context for cancelOrder. Succeeds or throws.
|
||||
/// @param order to be cancelled.
|
||||
/// @param orderInfo OrderStatus, orderHash, and amount already filled of order.
|
||||
function assertValidCancel(
|
||||
Order memory order,
|
||||
OrderInfo memory orderInfo
|
||||
)
|
||||
internal
|
||||
view
|
||||
{
|
||||
// Ensure order is valid
|
||||
// An order can only be cancelled if its status is FILLABLE.
|
||||
require(
|
||||
orderInfo.orderStatus == uint8(OrderStatus.FILLABLE),
|
||||
ORDER_UNFILLABLE
|
||||
);
|
||||
|
||||
// Validate sender is allowed to cancel this order
|
||||
if (order.senderAddress != address(0)) {
|
||||
require(
|
||||
order.senderAddress == msg.sender,
|
||||
INVALID_SENDER
|
||||
);
|
||||
}
|
||||
|
||||
// Validate transaction signed by maker
|
||||
address makerAddress = getCurrentContextAddress();
|
||||
require(
|
||||
order.makerAddress == makerAddress,
|
||||
INVALID_MAKER
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Calculates amounts filled and fees paid by maker and taker.
|
||||
/// @param order to be filled.
|
||||
/// @param takerAssetFilledAmount Amount of takerAsset that will be filled.
|
||||
/// @return fillResults Amounts filled and fees paid by maker and taker.
|
||||
function calculateFillResults(
|
||||
Order memory order,
|
||||
uint256 takerAssetFilledAmount
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (FillResults memory fillResults)
|
||||
{
|
||||
// Compute proportional transfer amounts
|
||||
// TODO: All three are multiplied by the same fraction. This can
|
||||
// potentially be optimized.
|
||||
fillResults.takerAssetFilledAmount = takerAssetFilledAmount;
|
||||
fillResults.makerAssetFilledAmount = getPartialAmount(
|
||||
fillResults.takerAssetFilledAmount,
|
||||
order.takerAssetAmount,
|
||||
order.makerAssetAmount
|
||||
);
|
||||
fillResults.makerFeePaid = getPartialAmount(
|
||||
fillResults.takerAssetFilledAmount,
|
||||
order.takerAssetAmount,
|
||||
order.makerFee
|
||||
);
|
||||
fillResults.takerFeePaid = getPartialAmount(
|
||||
fillResults.takerAssetFilledAmount,
|
||||
order.takerAssetAmount,
|
||||
order.takerFee
|
||||
);
|
||||
|
||||
return fillResults;
|
||||
}
|
||||
}
|
@@ -0,0 +1,227 @@
|
||||
/*
|
||||
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.4.24;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "./libs/LibMath.sol";
|
||||
import "./libs/LibOrder.sol";
|
||||
import "./libs/LibFillResults.sol";
|
||||
import "./libs/LibExchangeErrors.sol";
|
||||
import "./mixins/MExchangeCore.sol";
|
||||
import "./mixins/MMatchOrders.sol";
|
||||
import "./mixins/MSettlement.sol";
|
||||
import "./mixins/MTransactions.sol";
|
||||
|
||||
contract MixinMatchOrders is
|
||||
LibMath,
|
||||
LibExchangeErrors,
|
||||
MExchangeCore,
|
||||
MMatchOrders,
|
||||
MSettlement,
|
||||
MTransactions
|
||||
{
|
||||
|
||||
/// @dev Match two complementary orders that have a profitable spread.
|
||||
/// Each order is filled at their respective price point. However, the calculations are
|
||||
/// carried out as though the orders are both being filled at the right order's price point.
|
||||
/// The profit made by the left order goes to the taker (who matched the two orders).
|
||||
/// @param leftOrder First order to match.
|
||||
/// @param rightOrder Second order to match.
|
||||
/// @param leftSignature Proof that order was created by the left maker.
|
||||
/// @param rightSignature Proof that order was created by the right maker.
|
||||
/// @return matchedFillResults Amounts filled and fees paid by maker and taker of matched orders.
|
||||
/// TODO: Make this function external once supported by Solidity (See Solidity Issues #3199, #1603)
|
||||
function matchOrders(
|
||||
LibOrder.Order memory leftOrder,
|
||||
LibOrder.Order memory rightOrder,
|
||||
bytes memory leftSignature,
|
||||
bytes memory rightSignature
|
||||
)
|
||||
public
|
||||
returns (LibFillResults.MatchedFillResults memory matchedFillResults)
|
||||
{
|
||||
// We assume that rightOrder.takerAssetData == leftOrder.makerAssetData and rightOrder.makerAssetData == leftOrder.takerAssetData.
|
||||
// If this assumption isn't true, the match will fail at signature validation.
|
||||
rightOrder.makerAssetData = leftOrder.takerAssetData;
|
||||
rightOrder.takerAssetData = leftOrder.makerAssetData;
|
||||
|
||||
// Get left & right order info
|
||||
LibOrder.OrderInfo memory leftOrderInfo = getOrderInfo(leftOrder);
|
||||
LibOrder.OrderInfo memory rightOrderInfo = getOrderInfo(rightOrder);
|
||||
|
||||
// Fetch taker address
|
||||
address takerAddress = getCurrentContextAddress();
|
||||
|
||||
// Either our context is valid or we revert
|
||||
assertValidMatch(leftOrder, rightOrder);
|
||||
|
||||
// Compute proportional fill amounts
|
||||
matchedFillResults = calculateMatchedFillResults(
|
||||
leftOrder,
|
||||
rightOrder,
|
||||
leftOrderInfo.orderTakerAssetFilledAmount,
|
||||
rightOrderInfo.orderTakerAssetFilledAmount
|
||||
);
|
||||
|
||||
// Validate fill contexts
|
||||
assertValidFill(
|
||||
leftOrder,
|
||||
leftOrderInfo,
|
||||
takerAddress,
|
||||
matchedFillResults.left.takerAssetFilledAmount,
|
||||
matchedFillResults.left.takerAssetFilledAmount,
|
||||
leftSignature
|
||||
);
|
||||
assertValidFill(
|
||||
rightOrder,
|
||||
rightOrderInfo,
|
||||
takerAddress,
|
||||
matchedFillResults.right.takerAssetFilledAmount,
|
||||
matchedFillResults.right.takerAssetFilledAmount,
|
||||
rightSignature
|
||||
);
|
||||
|
||||
// Update exchange state
|
||||
updateFilledState(
|
||||
leftOrder,
|
||||
takerAddress,
|
||||
leftOrderInfo.orderHash,
|
||||
leftOrderInfo.orderTakerAssetFilledAmount,
|
||||
matchedFillResults.left
|
||||
);
|
||||
updateFilledState(
|
||||
rightOrder,
|
||||
takerAddress,
|
||||
rightOrderInfo.orderHash,
|
||||
rightOrderInfo.orderTakerAssetFilledAmount,
|
||||
matchedFillResults.right
|
||||
);
|
||||
|
||||
// Settle matched orders. Succeeds or throws.
|
||||
settleMatchedOrders(
|
||||
leftOrder,
|
||||
rightOrder,
|
||||
takerAddress,
|
||||
matchedFillResults
|
||||
);
|
||||
|
||||
return matchedFillResults;
|
||||
}
|
||||
|
||||
/// @dev Validates context for matchOrders. Succeeds or throws.
|
||||
/// @param leftOrder First order to match.
|
||||
/// @param rightOrder Second order to match.
|
||||
function assertValidMatch(
|
||||
LibOrder.Order memory leftOrder,
|
||||
LibOrder.Order memory rightOrder
|
||||
)
|
||||
internal
|
||||
pure
|
||||
{
|
||||
// Make sure there is a profitable spread.
|
||||
// There is a profitable spread iff the cost per unit bought (OrderA.MakerAmount/OrderA.TakerAmount) for each order is greater
|
||||
// than the profit per unit sold of the matched order (OrderB.TakerAmount/OrderB.MakerAmount).
|
||||
// This is satisfied by the equations below:
|
||||
// <leftOrder.makerAssetAmount> / <leftOrder.takerAssetAmount> >= <rightOrder.takerAssetAmount> / <rightOrder.makerAssetAmount>
|
||||
// AND
|
||||
// <rightOrder.makerAssetAmount> / <rightOrder.takerAssetAmount> >= <leftOrder.takerAssetAmount> / <leftOrder.makerAssetAmount>
|
||||
// These equations can be combined to get the following:
|
||||
require(
|
||||
safeMul(leftOrder.makerAssetAmount, rightOrder.makerAssetAmount) >=
|
||||
safeMul(leftOrder.takerAssetAmount, rightOrder.takerAssetAmount),
|
||||
NEGATIVE_SPREAD_REQUIRED
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Calculates fill amounts for the matched orders.
|
||||
/// Each order is filled at their respective price point. However, the calculations are
|
||||
/// carried out as though the orders are both being filled at the right order's price point.
|
||||
/// The profit made by the leftOrder order goes to the taker (who matched the two orders).
|
||||
/// @param leftOrder First order to match.
|
||||
/// @param rightOrder Second order to match.
|
||||
/// @param leftOrderTakerAssetFilledAmount Amount of left order already filled.
|
||||
/// @param rightOrderTakerAssetFilledAmount Amount of right order already filled.
|
||||
/// @param matchedFillResults Amounts to fill and fees to pay by maker and taker of matched orders.
|
||||
function calculateMatchedFillResults(
|
||||
LibOrder.Order memory leftOrder,
|
||||
LibOrder.Order memory rightOrder,
|
||||
uint256 leftOrderTakerAssetFilledAmount,
|
||||
uint256 rightOrderTakerAssetFilledAmount
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (LibFillResults.MatchedFillResults memory matchedFillResults)
|
||||
{
|
||||
// We settle orders at the exchange rate of the right order.
|
||||
// The amount saved by the left maker goes to the taker.
|
||||
// Either the left or right order will be fully filled; possibly both.
|
||||
// The left order is fully filled iff the right order can sell more than left can buy.
|
||||
// That is: the amount required to fill the left order is less than or equal to
|
||||
// the amount we can spend from the right order:
|
||||
// <leftTakerAssetAmountRemaining> <= <rightTakerAssetAmountRemaining> * <rightMakerToTakerRatio>
|
||||
// <leftTakerAssetAmountRemaining> <= <rightTakerAssetAmountRemaining> * <rightOrder.makerAssetAmount> / <rightOrder.takerAssetAmount>
|
||||
// <leftTakerAssetAmountRemaining> * <rightOrder.takerAssetAmount> <= <rightTakerAssetAmountRemaining> * <rightOrder.makerAssetAmount>
|
||||
uint256 leftTakerAssetAmountRemaining = safeSub(leftOrder.takerAssetAmount, leftOrderTakerAssetFilledAmount);
|
||||
uint256 rightTakerAssetAmountRemaining = safeSub(rightOrder.takerAssetAmount, rightOrderTakerAssetFilledAmount);
|
||||
uint256 leftTakerAssetFilledAmount;
|
||||
uint256 rightTakerAssetFilledAmount;
|
||||
if (
|
||||
safeMul(leftTakerAssetAmountRemaining, rightOrder.takerAssetAmount) <=
|
||||
safeMul(rightTakerAssetAmountRemaining, rightOrder.makerAssetAmount)
|
||||
) {
|
||||
// Left order will be fully filled: maximally fill left
|
||||
leftTakerAssetFilledAmount = leftTakerAssetAmountRemaining;
|
||||
|
||||
// The right order receives an amount proportional to how much was spent.
|
||||
// TODO: Can we ensure rounding error is in the correct direction?
|
||||
rightTakerAssetFilledAmount = getPartialAmount(
|
||||
rightOrder.takerAssetAmount,
|
||||
rightOrder.makerAssetAmount,
|
||||
leftTakerAssetFilledAmount
|
||||
);
|
||||
} else {
|
||||
// Right order will be fully filled: maximally fill right
|
||||
rightTakerAssetFilledAmount = rightTakerAssetAmountRemaining;
|
||||
|
||||
// The left order receives an amount proportional to how much was spent.
|
||||
// TODO: Can we ensure rounding error is in the correct direction?
|
||||
leftTakerAssetFilledAmount = getPartialAmount(
|
||||
rightOrder.makerAssetAmount,
|
||||
rightOrder.takerAssetAmount,
|
||||
rightTakerAssetFilledAmount
|
||||
);
|
||||
}
|
||||
|
||||
// Calculate fill results for left order
|
||||
matchedFillResults.left = calculateFillResults(
|
||||
leftOrder,
|
||||
leftTakerAssetFilledAmount
|
||||
);
|
||||
|
||||
// Calculate fill results for right order
|
||||
matchedFillResults.right = calculateFillResults(
|
||||
rightOrder,
|
||||
rightTakerAssetFilledAmount
|
||||
);
|
||||
|
||||
// Calculate amount given to taker
|
||||
matchedFillResults.leftMakerAssetSpreadAmount = safeSub(
|
||||
matchedFillResults.left.makerAssetFilledAmount,
|
||||
matchedFillResults.right.takerAssetFilledAmount
|
||||
);
|
||||
|
||||
// Return fill results
|
||||
return matchedFillResults;
|
||||
}
|
||||
}
|
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
|
||||
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.4.24;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "../../utils/LibBytes/LibBytes.sol";
|
||||
import "./libs/LibMath.sol";
|
||||
import "./libs/LibFillResults.sol";
|
||||
import "./libs/LibOrder.sol";
|
||||
import "./libs/LibExchangeErrors.sol";
|
||||
import "./mixins/MMatchOrders.sol";
|
||||
import "./mixins/MSettlement.sol";
|
||||
import "./mixins/MAssetProxyDispatcher.sol";
|
||||
|
||||
contract MixinSettlement is
|
||||
LibBytes,
|
||||
LibMath,
|
||||
LibExchangeErrors,
|
||||
MMatchOrders,
|
||||
MSettlement,
|
||||
MAssetProxyDispatcher
|
||||
{
|
||||
// ZRX address encoded as a byte array.
|
||||
// This will be constant throughout the life of the Exchange contract,
|
||||
// since ZRX will always be transferred via the ERC20 AssetProxy.
|
||||
bytes internal ZRX_ASSET_DATA;
|
||||
uint8 constant ZRX_PROXY_ID = 1;
|
||||
|
||||
/// TODO: _zrxAssetData should be a constant in production.
|
||||
/// @dev Constructor sets the metadata that will be used for paying ZRX fees.
|
||||
/// @param _zrxAssetData Byte array containing ERC20 proxy id concatenated with address of ZRX.
|
||||
constructor (bytes memory _zrxAssetData)
|
||||
public
|
||||
{
|
||||
ZRX_ASSET_DATA = _zrxAssetData;
|
||||
}
|
||||
|
||||
/// @dev Settles an order by transferring assets between counterparties.
|
||||
/// @param order Order struct containing order specifications.
|
||||
/// @param takerAddress Address selling takerAsset and buying makerAsset.
|
||||
/// @param fillResults Amounts to be filled and fees paid by maker and taker.
|
||||
function settleOrder(
|
||||
LibOrder.Order memory order,
|
||||
address takerAddress,
|
||||
LibFillResults.FillResults memory fillResults
|
||||
)
|
||||
internal
|
||||
{
|
||||
uint8 makerAssetProxyId = uint8(popLastByte(order.makerAssetData));
|
||||
uint8 takerAssetProxyId = uint8(popLastByte(order.takerAssetData));
|
||||
bytes memory zrxAssetData = ZRX_ASSET_DATA;
|
||||
dispatchTransferFrom(
|
||||
order.makerAssetData,
|
||||
makerAssetProxyId,
|
||||
order.makerAddress,
|
||||
takerAddress,
|
||||
fillResults.makerAssetFilledAmount
|
||||
);
|
||||
dispatchTransferFrom(
|
||||
order.takerAssetData,
|
||||
takerAssetProxyId,
|
||||
takerAddress,
|
||||
order.makerAddress,
|
||||
fillResults.takerAssetFilledAmount
|
||||
);
|
||||
dispatchTransferFrom(
|
||||
zrxAssetData,
|
||||
ZRX_PROXY_ID,
|
||||
order.makerAddress,
|
||||
order.feeRecipientAddress,
|
||||
fillResults.makerFeePaid
|
||||
);
|
||||
dispatchTransferFrom(
|
||||
zrxAssetData,
|
||||
ZRX_PROXY_ID,
|
||||
takerAddress,
|
||||
order.feeRecipientAddress,
|
||||
fillResults.takerFeePaid
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Settles matched order by transferring appropriate funds between order makers, taker, and fee recipient.
|
||||
/// @param leftOrder First matched order.
|
||||
/// @param rightOrder Second matched order.
|
||||
/// @param takerAddress Address that matched the orders. The taker receives the spread between orders as profit.
|
||||
/// @param matchedFillResults Struct holding amounts to transfer between makers, taker, and fee recipients.
|
||||
function settleMatchedOrders(
|
||||
LibOrder.Order memory leftOrder,
|
||||
LibOrder.Order memory rightOrder,
|
||||
address takerAddress,
|
||||
LibFillResults.MatchedFillResults memory matchedFillResults
|
||||
)
|
||||
internal
|
||||
{
|
||||
uint8 leftMakerAssetProxyId = uint8(popLastByte(leftOrder.makerAssetData));
|
||||
uint8 rightMakerAssetProxyId = uint8(popLastByte(rightOrder.makerAssetData));
|
||||
bytes memory zrxAssetData = ZRX_ASSET_DATA;
|
||||
// Order makers and taker
|
||||
dispatchTransferFrom(
|
||||
leftOrder.makerAssetData,
|
||||
leftMakerAssetProxyId,
|
||||
leftOrder.makerAddress,
|
||||
rightOrder.makerAddress,
|
||||
matchedFillResults.right.takerAssetFilledAmount
|
||||
);
|
||||
dispatchTransferFrom(
|
||||
rightOrder.makerAssetData,
|
||||
rightMakerAssetProxyId,
|
||||
rightOrder.makerAddress,
|
||||
leftOrder.makerAddress,
|
||||
matchedFillResults.left.takerAssetFilledAmount
|
||||
);
|
||||
dispatchTransferFrom(
|
||||
leftOrder.makerAssetData,
|
||||
leftMakerAssetProxyId,
|
||||
leftOrder.makerAddress,
|
||||
takerAddress,
|
||||
matchedFillResults.leftMakerAssetSpreadAmount
|
||||
);
|
||||
|
||||
// Maker fees
|
||||
dispatchTransferFrom(
|
||||
zrxAssetData,
|
||||
ZRX_PROXY_ID,
|
||||
leftOrder.makerAddress,
|
||||
leftOrder.feeRecipientAddress,
|
||||
matchedFillResults.left.makerFeePaid
|
||||
);
|
||||
dispatchTransferFrom(
|
||||
zrxAssetData,
|
||||
ZRX_PROXY_ID,
|
||||
rightOrder.makerAddress,
|
||||
rightOrder.feeRecipientAddress,
|
||||
matchedFillResults.right.makerFeePaid
|
||||
);
|
||||
|
||||
// Taker fees
|
||||
if (leftOrder.feeRecipientAddress == rightOrder.feeRecipientAddress) {
|
||||
dispatchTransferFrom(
|
||||
zrxAssetData,
|
||||
ZRX_PROXY_ID,
|
||||
takerAddress,
|
||||
leftOrder.feeRecipientAddress,
|
||||
safeAdd(
|
||||
matchedFillResults.left.takerFeePaid,
|
||||
matchedFillResults.right.takerFeePaid
|
||||
)
|
||||
);
|
||||
} else {
|
||||
dispatchTransferFrom(
|
||||
zrxAssetData,
|
||||
ZRX_PROXY_ID,
|
||||
takerAddress,
|
||||
leftOrder.feeRecipientAddress,
|
||||
matchedFillResults.left.takerFeePaid
|
||||
);
|
||||
dispatchTransferFrom(
|
||||
zrxAssetData,
|
||||
ZRX_PROXY_ID,
|
||||
takerAddress,
|
||||
rightOrder.feeRecipientAddress,
|
||||
matchedFillResults.right.takerFeePaid
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,241 @@
|
||||
/*
|
||||
|
||||
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.4.24;
|
||||
|
||||
import "../../utils/LibBytes/LibBytes.sol";
|
||||
import "./libs/LibExchangeErrors.sol";
|
||||
import "./mixins/MSignatureValidator.sol";
|
||||
import "./mixins/MTransactions.sol";
|
||||
import "./interfaces/IWallet.sol";
|
||||
import "./interfaces/IValidator.sol";
|
||||
|
||||
contract MixinSignatureValidator is
|
||||
LibBytes,
|
||||
LibExchangeErrors,
|
||||
MSignatureValidator,
|
||||
MTransactions
|
||||
{
|
||||
// Personal message headers
|
||||
string constant ETH_PERSONAL_MESSAGE = "\x19Ethereum Signed Message:\n32";
|
||||
string constant TREZOR_PERSONAL_MESSAGE = "\x19Ethereum Signed Message:\n\x41";
|
||||
|
||||
// Mapping of hash => signer => signed
|
||||
mapping (bytes32 => mapping (address => bool)) public preSigned;
|
||||
|
||||
// Mapping of signer => validator => approved
|
||||
mapping (address => mapping (address => bool)) public allowedValidators;
|
||||
|
||||
/// @dev Approves a hash on-chain using any valid signature type.
|
||||
/// After presigning a hash, the preSign signature type will become valid for that hash and signer.
|
||||
/// @param signer Address that should have signed the given hash.
|
||||
/// @param signature Proof that the hash has been signed by signer.
|
||||
function preSign(
|
||||
bytes32 hash,
|
||||
address signer,
|
||||
bytes signature
|
||||
)
|
||||
external
|
||||
{
|
||||
require(
|
||||
isValidSignature(hash, signer, signature),
|
||||
INVALID_SIGNATURE
|
||||
);
|
||||
preSigned[hash][signer] = true;
|
||||
}
|
||||
|
||||
/// @dev Approves/unnapproves a Validator contract to verify signatures on signer's behalf.
|
||||
/// @param validator Address of Validator contract.
|
||||
/// @param approval Approval or disapproval of Validator contract.
|
||||
function setSignatureValidatorApproval(
|
||||
address validator,
|
||||
bool approval
|
||||
)
|
||||
external
|
||||
{
|
||||
address signer = getCurrentContextAddress();
|
||||
allowedValidators[signer][validator] = approval;
|
||||
}
|
||||
|
||||
/// @dev Verifies that a hash has been signed by the given signer.
|
||||
/// @param hash Any 32 byte hash.
|
||||
/// @param signer Address that should have signed the given hash.
|
||||
/// @param signature Proof that the hash has been signed by signer.
|
||||
/// @return True if the address recovered from the provided signature matches the input signer address.
|
||||
function isValidSignature(
|
||||
bytes32 hash,
|
||||
address signer,
|
||||
bytes memory signature
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (bool isValid)
|
||||
{
|
||||
// TODO: Domain separation: make hash depend on role. (Taker sig should not be valid as maker sig, etc.)
|
||||
require(
|
||||
signature.length > 0,
|
||||
LENGTH_GREATER_THAN_0_REQUIRED
|
||||
);
|
||||
|
||||
// Pop last byte off of signature byte array.
|
||||
SignatureType signatureType = SignatureType(uint8(popLastByte(signature)));
|
||||
|
||||
// Variables are not scoped in Solidity.
|
||||
uint8 v;
|
||||
bytes32 r;
|
||||
bytes32 s;
|
||||
address recovered;
|
||||
|
||||
// Always illegal signature.
|
||||
// This is always an implicit option since a signer can create a
|
||||
// signature array with invalid type or length. We may as well make
|
||||
// it an explicit option. This aids testing and analysis. It is
|
||||
// also the initialization value for the enum type.
|
||||
if (signatureType == SignatureType.Illegal) {
|
||||
revert(SIGNATURE_ILLEGAL);
|
||||
|
||||
// Always invalid signature.
|
||||
// Like Illegal, this is always implicitly available and therefore
|
||||
// offered explicitly. It can be implicitly created by providing
|
||||
// a correctly formatted but incorrect signature.
|
||||
} else if (signatureType == SignatureType.Invalid) {
|
||||
require(
|
||||
signature.length == 0,
|
||||
LENGTH_0_REQUIRED
|
||||
);
|
||||
isValid = false;
|
||||
return isValid;
|
||||
|
||||
// Signature using EIP712
|
||||
} else if (signatureType == SignatureType.EIP712) {
|
||||
require(
|
||||
signature.length == 65,
|
||||
LENGTH_65_REQUIRED
|
||||
);
|
||||
v = uint8(signature[0]);
|
||||
r = readBytes32(signature, 1);
|
||||
s = readBytes32(signature, 33);
|
||||
recovered = ecrecover(hash, v, r, s);
|
||||
isValid = signer == recovered;
|
||||
return isValid;
|
||||
|
||||
// Signed using web3.eth_sign
|
||||
} else if (signatureType == SignatureType.EthSign) {
|
||||
require(
|
||||
signature.length == 65,
|
||||
LENGTH_65_REQUIRED
|
||||
);
|
||||
v = uint8(signature[0]);
|
||||
r = readBytes32(signature, 1);
|
||||
s = readBytes32(signature, 33);
|
||||
recovered = ecrecover(
|
||||
keccak256(abi.encodePacked(ETH_PERSONAL_MESSAGE, hash)),
|
||||
v,
|
||||
r,
|
||||
s
|
||||
);
|
||||
isValid = signer == recovered;
|
||||
return isValid;
|
||||
|
||||
// Implicitly signed by caller.
|
||||
// The signer has initiated the call. In the case of non-contract
|
||||
// accounts it means the transaction itself was signed.
|
||||
// Example: let's say for a particular operation three signatures
|
||||
// A, B and C are required. To submit the transaction, A and B can
|
||||
// give a signature to C, who can then submit the transaction using
|
||||
// `Caller` for his own signature. Or A and C can sign and B can
|
||||
// submit using `Caller`. Having `Caller` allows this flexibility.
|
||||
} else if (signatureType == SignatureType.Caller) {
|
||||
require(
|
||||
signature.length == 0,
|
||||
LENGTH_0_REQUIRED
|
||||
);
|
||||
isValid = signer == msg.sender;
|
||||
return isValid;
|
||||
|
||||
// Signature verified by wallet contract.
|
||||
// If used with an order, the maker of the order is the wallet contract.
|
||||
} else if (signatureType == SignatureType.Wallet) {
|
||||
isValid = IWallet(signer).isValidSignature(hash, signature);
|
||||
return isValid;
|
||||
|
||||
// Signature verified by validator contract.
|
||||
// If used with an order, the maker of the order can still be an EOA.
|
||||
// A signature using this type should be encoded as:
|
||||
// | Offset | Length | Contents |
|
||||
// | 0x00 | x | Signature to validate |
|
||||
// | 0x00 + x | 20 | Address of validator contract |
|
||||
// | 0x14 + x | 1 | Signature type is always "\x06" |
|
||||
} else if (signatureType == SignatureType.Validator) {
|
||||
// Pop last 20 bytes off of signature byte array.
|
||||
address validator = popLast20Bytes(signature);
|
||||
// Ensure signer has approved validator.
|
||||
if (!allowedValidators[signer][validator]) {
|
||||
return false;
|
||||
}
|
||||
isValid = IValidator(validator).isValidSignature(
|
||||
hash,
|
||||
signer,
|
||||
signature
|
||||
);
|
||||
return isValid;
|
||||
|
||||
// Signer signed hash previously using the preSign function.
|
||||
} else if (signatureType == SignatureType.PreSigned) {
|
||||
isValid = preSigned[hash][signer];
|
||||
return isValid;
|
||||
|
||||
// Signature from Trezor hardware wallet.
|
||||
// It differs from web3.eth_sign in the encoding of message length
|
||||
// (Bitcoin varint encoding vs ascii-decimal, the latter is not
|
||||
// self-terminating which leads to ambiguities).
|
||||
// See also:
|
||||
// https://en.bitcoin.it/wiki/Protocol_documentation#Variable_length_integer
|
||||
// https://github.com/trezor/trezor-mcu/blob/master/firmware/ethereum.c#L602
|
||||
// https://github.com/trezor/trezor-mcu/blob/master/firmware/crypto.c#L36
|
||||
} else if (signatureType == SignatureType.Trezor) {
|
||||
require(
|
||||
signature.length == 65,
|
||||
LENGTH_65_REQUIRED
|
||||
);
|
||||
v = uint8(signature[0]);
|
||||
r = readBytes32(signature, 1);
|
||||
s = readBytes32(signature, 33);
|
||||
recovered = ecrecover(
|
||||
keccak256(abi.encodePacked(TREZOR_PERSONAL_MESSAGE, hash)),
|
||||
v,
|
||||
r,
|
||||
s
|
||||
);
|
||||
isValid = signer == recovered;
|
||||
return isValid;
|
||||
|
||||
// Signer signed hash previously using the preSign function
|
||||
} else if (signatureType == SignatureType.PreSigned) {
|
||||
isValid = preSigned[hash][signer];
|
||||
return isValid;
|
||||
}
|
||||
|
||||
// Anything else is illegal (We do not return false because
|
||||
// the signature may actually be valid, just not in a format
|
||||
// that we currently support. In this case returning false
|
||||
// may lead the caller to incorrectly believe that the
|
||||
// signature was invalid.)
|
||||
revert(SIGNATURE_UNSUPPORTED);
|
||||
}
|
||||
}
|
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
|
||||
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.4.24;
|
||||
|
||||
import "./libs/LibExchangeErrors.sol";
|
||||
import "./mixins/MSignatureValidator.sol";
|
||||
import "./mixins/MTransactions.sol";
|
||||
|
||||
contract MixinTransactions is
|
||||
LibExchangeErrors,
|
||||
MSignatureValidator,
|
||||
MTransactions
|
||||
{
|
||||
|
||||
// Mapping of transaction hash => executed
|
||||
// This prevents transactions from being executed more than once.
|
||||
mapping (bytes32 => bool) public transactions;
|
||||
|
||||
// Address of current transaction signer
|
||||
address public currentContextAddress;
|
||||
|
||||
/// @dev Executes an exchange method call in the context of signer.
|
||||
/// @param salt Arbitrary number to ensure uniqueness of transaction hash.
|
||||
/// @param signer Address of transaction signer.
|
||||
/// @param data AbiV2 encoded calldata.
|
||||
/// @param signature Proof of signer transaction by signer.
|
||||
function executeTransaction(
|
||||
uint256 salt,
|
||||
address signer,
|
||||
bytes data,
|
||||
bytes signature
|
||||
)
|
||||
external
|
||||
{
|
||||
// Prevent reentrancy
|
||||
require(
|
||||
currentContextAddress == address(0),
|
||||
REENTRANCY_ILLEGAL
|
||||
);
|
||||
|
||||
// Calculate transaction hash
|
||||
bytes32 transactionHash = keccak256(abi.encodePacked(
|
||||
address(this),
|
||||
signer,
|
||||
salt,
|
||||
data
|
||||
));
|
||||
|
||||
// Validate transaction has not been executed
|
||||
require(
|
||||
!transactions[transactionHash],
|
||||
INVALID_TX_HASH
|
||||
);
|
||||
|
||||
// Transaction always valid if signer is sender of transaction
|
||||
if (signer != msg.sender) {
|
||||
// Validate signature
|
||||
require(
|
||||
isValidSignature(transactionHash, signer, signature),
|
||||
INVALID_TX_SIGNATURE
|
||||
);
|
||||
|
||||
// Set the current transaction signer
|
||||
currentContextAddress = signer;
|
||||
}
|
||||
|
||||
// Execute transaction
|
||||
transactions[transactionHash] = true;
|
||||
require(
|
||||
address(this).delegatecall(data),
|
||||
FAILED_EXECUTION
|
||||
);
|
||||
|
||||
// Reset current transaction signer
|
||||
// TODO: Check if gas is paid when currentContextAddress is already 0.
|
||||
currentContextAddress = address(0);
|
||||
}
|
||||
|
||||
/// @dev The current function will be called in the context of this address (either 0x transaction signer or `msg.sender`).
|
||||
/// If calling a fill function, this address will represent the taker.
|
||||
/// If calling a cancel function, this address will represent the maker.
|
||||
/// @return Signer of 0x transaction if entry point is `executeTransaction`.
|
||||
/// `msg.sender` if entry point is any other function.
|
||||
function getCurrentContextAddress()
|
||||
internal
|
||||
view
|
||||
returns (address)
|
||||
{
|
||||
address contextAddress = currentContextAddress == address(0) ? msg.sender : currentContextAddress;
|
||||
return contextAddress;
|
||||
}
|
||||
}
|
@@ -0,0 +1,549 @@
|
||||
/*
|
||||
|
||||
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.4.24;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "./libs/LibMath.sol";
|
||||
import "./libs/LibOrder.sol";
|
||||
import "./libs/LibFillResults.sol";
|
||||
import "./libs/LibExchangeErrors.sol";
|
||||
import "./mixins/MExchangeCore.sol";
|
||||
|
||||
contract MixinWrapperFunctions is
|
||||
LibMath,
|
||||
LibFillResults,
|
||||
LibExchangeErrors,
|
||||
MExchangeCore
|
||||
{
|
||||
/// @dev Fills the input order. Reverts if exact takerAssetFillAmount not filled.
|
||||
/// @param order Order struct containing order specifications.
|
||||
/// @param takerAssetFillAmount Desired amount of takerAsset to sell.
|
||||
/// @param signature Proof that order has been created by maker.
|
||||
function fillOrKillOrder(
|
||||
LibOrder.Order memory order,
|
||||
uint256 takerAssetFillAmount,
|
||||
bytes memory signature
|
||||
)
|
||||
public
|
||||
returns (FillResults memory fillResults)
|
||||
{
|
||||
fillResults = fillOrder(
|
||||
order,
|
||||
takerAssetFillAmount,
|
||||
signature
|
||||
);
|
||||
require(
|
||||
fillResults.takerAssetFilledAmount == takerAssetFillAmount,
|
||||
COMPLETE_FILL_FAILED
|
||||
);
|
||||
return fillResults;
|
||||
}
|
||||
|
||||
/// @dev Fills an order with specified parameters and ECDSA signature.
|
||||
/// Returns false if the transaction would otherwise revert.
|
||||
/// @param order Order struct containing order specifications.
|
||||
/// @param takerAssetFillAmount Desired amount of takerAsset to sell.
|
||||
/// @param signature Proof that order has been created by maker.
|
||||
/// @return Amounts filled and fees paid by maker and taker.
|
||||
function fillOrderNoThrow(
|
||||
LibOrder.Order memory order,
|
||||
uint256 takerAssetFillAmount,
|
||||
bytes memory signature
|
||||
)
|
||||
public
|
||||
returns (FillResults memory fillResults)
|
||||
{
|
||||
// We need to call MExchangeCore.fillOrder using a delegatecall in
|
||||
// assembly so that we can intercept a call that throws. For this, we
|
||||
// need the input encoded in memory in the Ethereum ABIv2 format [1].
|
||||
|
||||
// | Area | Offset | Length | Contents |
|
||||
// | -------- |--------|---------|-------------------------------------------- |
|
||||
// | Header | 0x00 | 4 | function selector |
|
||||
// | Params | | 3 * 32 | function parameters: |
|
||||
// | | 0x00 | | 1. offset to order (*) |
|
||||
// | | 0x20 | | 2. takerAssetFillAmount |
|
||||
// | | 0x40 | | 3. offset to signature (*) |
|
||||
// | Data | | 12 * 32 | order: |
|
||||
// | | 0x000 | | 1. senderAddress |
|
||||
// | | 0x020 | | 2. makerAddress |
|
||||
// | | 0x040 | | 3. takerAddress |
|
||||
// | | 0x060 | | 4. feeRecipientAddress |
|
||||
// | | 0x080 | | 5. makerAssetAmount |
|
||||
// | | 0x0A0 | | 6. takerAssetAmount |
|
||||
// | | 0x0C0 | | 7. makerFeeAmount |
|
||||
// | | 0x0E0 | | 8. takerFeeAmount |
|
||||
// | | 0x100 | | 9. expirationTimeSeconds |
|
||||
// | | 0x120 | | 10. salt |
|
||||
// | | 0x140 | | 11. Offset to makerAssetData (*) |
|
||||
// | | 0x160 | | 12. Offset to takerAssetData (*) |
|
||||
// | | 0x180 | 32 | makerAssetData Length |
|
||||
// | | 0x1A0 | ** | makerAssetData Contents |
|
||||
// | | 0x1C0 | 32 | takerAssetData Length |
|
||||
// | | 0x1E0 | ** | takerAssetData Contents |
|
||||
// | | 0x200 | 32 | signature Length |
|
||||
// | | 0x220 | ** | signature Contents |
|
||||
|
||||
// * Offsets are calculated from the beginning of the current area: Header, Params, Data:
|
||||
// An offset stored in the Params area is calculated from the beginning of the Params section.
|
||||
// An offset stored in the Data area is calculated from the beginning of the Data section.
|
||||
|
||||
// ** The length of dynamic array contents are stored in the field immediately preceeding the contents.
|
||||
|
||||
// [1]: https://solidity.readthedocs.io/en/develop/abi-spec.html
|
||||
|
||||
bytes4 fillOrderSelector = this.fillOrder.selector;
|
||||
|
||||
assembly {
|
||||
|
||||
// Areas below may use the following variables:
|
||||
// 1. <area>Start -- Start of this area in memory
|
||||
// 2. <area>End -- End of this area in memory. This value may
|
||||
// be precomputed (before writing contents),
|
||||
// or it may be computed as contents are written.
|
||||
// 3. <area>Offset -- Current offset into area. If an area's End
|
||||
// is precomputed, this variable tracks the
|
||||
// offsets of contents as they are written.
|
||||
|
||||
/////// Setup Header Area ///////
|
||||
// Load free memory pointer
|
||||
let headerAreaStart := mload(0x40)
|
||||
mstore(headerAreaStart, fillOrderSelector)
|
||||
let headerAreaEnd := add(headerAreaStart, 0x4)
|
||||
|
||||
/////// Setup Params Area ///////
|
||||
// This area is preallocated and written to later.
|
||||
// This is because we need to fill in offsets that have not yet been calculated.
|
||||
let paramsAreaStart := headerAreaEnd
|
||||
let paramsAreaEnd := add(paramsAreaStart, 0x60)
|
||||
let paramsAreaOffset := paramsAreaStart
|
||||
|
||||
/////// Setup Data Area ///////
|
||||
let dataAreaStart := paramsAreaEnd
|
||||
let dataAreaEnd := dataAreaStart
|
||||
|
||||
// Offset from the source data we're reading from
|
||||
let sourceOffset := order
|
||||
// arrayLenBytes and arrayLenWords track the length of a dynamically-allocated bytes array.
|
||||
let arrayLenBytes := 0
|
||||
let arrayLenWords := 0
|
||||
|
||||
/////// Write order Struct ///////
|
||||
// Write memory location of Order, relative to the start of the
|
||||
// parameter list, then increment the paramsAreaOffset respectively.
|
||||
mstore(paramsAreaOffset, sub(dataAreaEnd, paramsAreaStart))
|
||||
paramsAreaOffset := add(paramsAreaOffset, 0x20)
|
||||
|
||||
// Write values for each field in the order
|
||||
// It would be nice to use a loop, but we save on gas by writing
|
||||
// the stores sequentially.
|
||||
mstore(dataAreaEnd, mload(sourceOffset)) // makerAddress
|
||||
mstore(add(dataAreaEnd, 0x20), mload(add(sourceOffset, 0x20))) // takerAddress
|
||||
mstore(add(dataAreaEnd, 0x40), mload(add(sourceOffset, 0x40))) // feeRecipientAddress
|
||||
mstore(add(dataAreaEnd, 0x60), mload(add(sourceOffset, 0x60))) // senderAddress
|
||||
mstore(add(dataAreaEnd, 0x80), mload(add(sourceOffset, 0x80))) // makerAssetAmount
|
||||
mstore(add(dataAreaEnd, 0xA0), mload(add(sourceOffset, 0xA0))) // takerAssetAmount
|
||||
mstore(add(dataAreaEnd, 0xC0), mload(add(sourceOffset, 0xC0))) // makerFeeAmount
|
||||
mstore(add(dataAreaEnd, 0xE0), mload(add(sourceOffset, 0xE0))) // takerFeeAmount
|
||||
mstore(add(dataAreaEnd, 0x100), mload(add(sourceOffset, 0x100))) // expirationTimeSeconds
|
||||
mstore(add(dataAreaEnd, 0x120), mload(add(sourceOffset, 0x120))) // salt
|
||||
mstore(add(dataAreaEnd, 0x140), mload(add(sourceOffset, 0x140))) // Offset to makerAssetData
|
||||
mstore(add(dataAreaEnd, 0x160), mload(add(sourceOffset, 0x160))) // Offset to takerAssetData
|
||||
dataAreaEnd := add(dataAreaEnd, 0x180)
|
||||
sourceOffset := add(sourceOffset, 0x180)
|
||||
|
||||
// Write offset to <order.makerAssetData>
|
||||
mstore(add(dataAreaStart, mul(10, 0x20)), sub(dataAreaEnd, dataAreaStart))
|
||||
|
||||
// Calculate length of <order.makerAssetData>
|
||||
sourceOffset := mload(add(order, 0x140)) // makerAssetData
|
||||
arrayLenBytes := mload(sourceOffset)
|
||||
sourceOffset := add(sourceOffset, 0x20)
|
||||
arrayLenWords := div(add(arrayLenBytes, 0x1F), 0x20)
|
||||
|
||||
// Write length of <order.makerAssetData>
|
||||
mstore(dataAreaEnd, arrayLenBytes)
|
||||
dataAreaEnd := add(dataAreaEnd, 0x20)
|
||||
|
||||
// Write contents of <order.makerAssetData>
|
||||
for {let i := 0} lt(i, arrayLenWords) {i := add(i, 1)} {
|
||||
mstore(dataAreaEnd, mload(sourceOffset))
|
||||
dataAreaEnd := add(dataAreaEnd, 0x20)
|
||||
sourceOffset := add(sourceOffset, 0x20)
|
||||
}
|
||||
|
||||
// Write offset to <order.takerAssetData>
|
||||
mstore(add(dataAreaStart, mul(11, 0x20)), sub(dataAreaEnd, dataAreaStart))
|
||||
|
||||
// Calculate length of <order.takerAssetData>
|
||||
sourceOffset := mload(add(order, 0x160)) // takerAssetData
|
||||
arrayLenBytes := mload(sourceOffset)
|
||||
sourceOffset := add(sourceOffset, 0x20)
|
||||
arrayLenWords := div(add(arrayLenBytes, 0x1F), 0x20)
|
||||
|
||||
// Write length of <order.takerAssetData>
|
||||
mstore(dataAreaEnd, arrayLenBytes)
|
||||
dataAreaEnd := add(dataAreaEnd, 0x20)
|
||||
|
||||
// Write contents of <order.takerAssetData>
|
||||
for {let i := 0} lt(i, arrayLenWords) {i := add(i, 1)} {
|
||||
mstore(dataAreaEnd, mload(sourceOffset))
|
||||
dataAreaEnd := add(dataAreaEnd, 0x20)
|
||||
sourceOffset := add(sourceOffset, 0x20)
|
||||
}
|
||||
|
||||
/////// Write takerAssetFillAmount ///////
|
||||
mstore(paramsAreaOffset, takerAssetFillAmount)
|
||||
paramsAreaOffset := add(paramsAreaOffset, 0x20)
|
||||
|
||||
/////// Write signature ///////
|
||||
// Write offset to paramsArea
|
||||
mstore(paramsAreaOffset, sub(dataAreaEnd, paramsAreaStart))
|
||||
|
||||
// Calculate length of signature
|
||||
sourceOffset := signature
|
||||
arrayLenBytes := mload(sourceOffset)
|
||||
sourceOffset := add(sourceOffset, 0x20)
|
||||
arrayLenWords := div(add(arrayLenBytes, 0x1F), 0x20)
|
||||
|
||||
// Write length of signature
|
||||
mstore(dataAreaEnd, arrayLenBytes)
|
||||
dataAreaEnd := add(dataAreaEnd, 0x20)
|
||||
|
||||
// Write contents of signature
|
||||
for {let i := 0} lt(i, arrayLenWords) {i := add(i, 1)} {
|
||||
mstore(dataAreaEnd, mload(sourceOffset))
|
||||
dataAreaEnd := add(dataAreaEnd, 0x20)
|
||||
sourceOffset := add(sourceOffset, 0x20)
|
||||
}
|
||||
|
||||
// Execute delegatecall
|
||||
let success := delegatecall(
|
||||
gas, // forward all gas, TODO: look into gas consumption of assert/throw
|
||||
address, // call address of this contract
|
||||
headerAreaStart, // pointer to start of input
|
||||
sub(dataAreaEnd, headerAreaStart), // length of input
|
||||
headerAreaStart, // write output over input
|
||||
128 // output size is 128 bytes
|
||||
)
|
||||
switch success
|
||||
case 0 {
|
||||
mstore(fillResults, 0)
|
||||
mstore(add(fillResults, 32), 0)
|
||||
mstore(add(fillResults, 64), 0)
|
||||
mstore(add(fillResults, 96), 0)
|
||||
}
|
||||
case 1 {
|
||||
mstore(fillResults, mload(headerAreaStart))
|
||||
mstore(add(fillResults, 32), mload(add(headerAreaStart, 32)))
|
||||
mstore(add(fillResults, 64), mload(add(headerAreaStart, 64)))
|
||||
mstore(add(fillResults, 96), mload(add(headerAreaStart, 96)))
|
||||
}
|
||||
}
|
||||
return fillResults;
|
||||
}
|
||||
|
||||
/// @dev Synchronously executes multiple calls of fillOrder.
|
||||
/// @param orders Array of order specifications.
|
||||
/// @param takerAssetFillAmounts Array of desired amounts of takerAsset to sell in orders.
|
||||
/// @param signatures Proofs that orders have been created by makers.
|
||||
/// @return Amounts filled and fees paid by makers and taker.
|
||||
/// NOTE: makerAssetFilledAmount and takerAssetFilledAmount may include amounts filled of different assets.
|
||||
function batchFillOrders(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256[] memory takerAssetFillAmounts,
|
||||
bytes[] memory signatures
|
||||
)
|
||||
public
|
||||
returns (FillResults memory totalFillResults)
|
||||
{
|
||||
for (uint256 i = 0; i < orders.length; i++) {
|
||||
FillResults memory singleFillResults = fillOrder(
|
||||
orders[i],
|
||||
takerAssetFillAmounts[i],
|
||||
signatures[i]
|
||||
);
|
||||
addFillResults(totalFillResults, singleFillResults);
|
||||
}
|
||||
return totalFillResults;
|
||||
}
|
||||
|
||||
/// @dev Synchronously executes multiple calls of fillOrKill.
|
||||
/// @param orders Array of order specifications.
|
||||
/// @param takerAssetFillAmounts Array of desired amounts of takerAsset to sell in orders.
|
||||
/// @param signatures Proofs that orders have been created by makers.
|
||||
/// @return Amounts filled and fees paid by makers and taker.
|
||||
/// NOTE: makerAssetFilledAmount and takerAssetFilledAmount may include amounts filled of different assets.
|
||||
function batchFillOrKillOrders(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256[] memory takerAssetFillAmounts,
|
||||
bytes[] memory signatures
|
||||
)
|
||||
public
|
||||
returns (FillResults memory totalFillResults)
|
||||
{
|
||||
for (uint256 i = 0; i < orders.length; i++) {
|
||||
FillResults memory singleFillResults = fillOrKillOrder(
|
||||
orders[i],
|
||||
takerAssetFillAmounts[i],
|
||||
signatures[i]
|
||||
);
|
||||
addFillResults(totalFillResults, singleFillResults);
|
||||
}
|
||||
return totalFillResults;
|
||||
}
|
||||
|
||||
/// @dev Fills an order with specified parameters and ECDSA signature.
|
||||
/// Returns false if the transaction would otherwise revert.
|
||||
/// @param orders Array of order specifications.
|
||||
/// @param takerAssetFillAmounts Array of desired amounts of takerAsset to sell in orders.
|
||||
/// @param signatures Proofs that orders have been created by makers.
|
||||
/// @return Amounts filled and fees paid by makers and taker.
|
||||
/// NOTE: makerAssetFilledAmount and takerAssetFilledAmount may include amounts filled of different assets.
|
||||
function batchFillOrdersNoThrow(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256[] memory takerAssetFillAmounts,
|
||||
bytes[] memory signatures
|
||||
)
|
||||
public
|
||||
returns (FillResults memory totalFillResults)
|
||||
{
|
||||
for (uint256 i = 0; i < orders.length; i++) {
|
||||
FillResults memory singleFillResults = fillOrderNoThrow(
|
||||
orders[i],
|
||||
takerAssetFillAmounts[i],
|
||||
signatures[i]
|
||||
);
|
||||
addFillResults(totalFillResults, singleFillResults);
|
||||
}
|
||||
return totalFillResults;
|
||||
}
|
||||
|
||||
/// @dev Synchronously executes multiple calls of fillOrder until total amount of takerAsset is sold by taker.
|
||||
/// @param orders Array of order specifications.
|
||||
/// @param takerAssetFillAmount Desired amount of takerAsset to sell.
|
||||
/// @param signatures Proofs that orders have been created by makers.
|
||||
/// @return Amounts filled and fees paid by makers and taker.
|
||||
function marketSellOrders(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256 takerAssetFillAmount,
|
||||
bytes[] memory signatures
|
||||
)
|
||||
public
|
||||
returns (FillResults memory totalFillResults)
|
||||
{
|
||||
bytes memory takerAssetData = orders[0].takerAssetData;
|
||||
|
||||
for (uint256 i = 0; i < orders.length; i++) {
|
||||
|
||||
// We assume that asset being sold by taker is the same for each order.
|
||||
// Rather than passing this in as calldata, we use the takerAssetData from the first order in all later orders.
|
||||
orders[i].takerAssetData = takerAssetData;
|
||||
|
||||
// Calculate the remaining amount of takerAsset to sell
|
||||
uint256 remainingTakerAssetFillAmount = safeSub(takerAssetFillAmount, totalFillResults.takerAssetFilledAmount);
|
||||
|
||||
// Attempt to sell the remaining amount of takerAsset
|
||||
FillResults memory singleFillResults = fillOrder(
|
||||
orders[i],
|
||||
remainingTakerAssetFillAmount,
|
||||
signatures[i]
|
||||
);
|
||||
|
||||
// HACK: the proxyId is "popped" from the byte array before a fill is settled
|
||||
// by subtracting from the length of the array. Since the popped byte is
|
||||
// still in memory, we can "unpop" it by incrementing the length of the byte array.
|
||||
assembly {
|
||||
let len := mload(takerAssetData)
|
||||
mstore(takerAssetData, add(len, 1))
|
||||
}
|
||||
|
||||
// Update amounts filled and fees paid by maker and taker
|
||||
addFillResults(totalFillResults, singleFillResults);
|
||||
|
||||
// Stop execution if the entire amount of takerAsset has been sold
|
||||
if (totalFillResults.takerAssetFilledAmount == takerAssetFillAmount) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return totalFillResults;
|
||||
}
|
||||
|
||||
/// @dev Synchronously executes multiple calls of fillOrder until total amount of takerAsset is sold by taker.
|
||||
/// Returns false if the transaction would otherwise revert.
|
||||
/// @param orders Array of order specifications.
|
||||
/// @param takerAssetFillAmount Desired amount of takerAsset to sell.
|
||||
/// @param signatures Proofs that orders have been signed by makers.
|
||||
/// @return Amounts filled and fees paid by makers and taker.
|
||||
function marketSellOrdersNoThrow(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256 takerAssetFillAmount,
|
||||
bytes[] memory signatures
|
||||
)
|
||||
public
|
||||
returns (FillResults memory totalFillResults)
|
||||
{
|
||||
bytes memory takerAssetData = orders[0].takerAssetData;
|
||||
|
||||
for (uint256 i = 0; i < orders.length; i++) {
|
||||
|
||||
// We assume that asset being sold by taker is the same for each order.
|
||||
// Rather than passing this in as calldata, we use the takerAssetData from the first order in all later orders.
|
||||
orders[i].takerAssetData = takerAssetData;
|
||||
|
||||
// Calculate the remaining amount of takerAsset to sell
|
||||
uint256 remainingTakerAssetFillAmount = safeSub(takerAssetFillAmount, totalFillResults.takerAssetFilledAmount);
|
||||
|
||||
// Attempt to sell the remaining amount of takerAsset
|
||||
FillResults memory singleFillResults = fillOrderNoThrow(
|
||||
orders[i],
|
||||
remainingTakerAssetFillAmount,
|
||||
signatures[i]
|
||||
);
|
||||
|
||||
// Update amounts filled and fees paid by maker and taker
|
||||
addFillResults(totalFillResults, singleFillResults);
|
||||
|
||||
// Stop execution if the entire amount of takerAsset has been sold
|
||||
if (totalFillResults.takerAssetFilledAmount == takerAssetFillAmount) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return totalFillResults;
|
||||
}
|
||||
|
||||
/// @dev Synchronously executes multiple calls of fillOrder until total amount of makerAsset is bought by taker.
|
||||
/// @param orders Array of order specifications.
|
||||
/// @param makerAssetFillAmount Desired amount of makerAsset to buy.
|
||||
/// @param signatures Proofs that orders have been signed by makers.
|
||||
/// @return Amounts filled and fees paid by makers and taker.
|
||||
function marketBuyOrders(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256 makerAssetFillAmount,
|
||||
bytes[] memory signatures
|
||||
)
|
||||
public
|
||||
returns (FillResults memory totalFillResults)
|
||||
{
|
||||
bytes memory makerAssetData = orders[0].makerAssetData;
|
||||
|
||||
for (uint256 i = 0; i < orders.length; i++) {
|
||||
|
||||
// We assume that asset being bought by taker is the same for each order.
|
||||
// Rather than passing this in as calldata, we copy the makerAssetData from the first order onto all later orders.
|
||||
orders[i].makerAssetData = makerAssetData;
|
||||
|
||||
// Calculate the remaining amount of makerAsset to buy
|
||||
uint256 remainingMakerAssetFillAmount = safeSub(makerAssetFillAmount, totalFillResults.makerAssetFilledAmount);
|
||||
|
||||
// Convert the remaining amount of makerAsset to buy into remaining amount
|
||||
// of takerAsset to sell, assuming entire amount can be sold in the current order
|
||||
uint256 remainingTakerAssetFillAmount = getPartialAmount(
|
||||
orders[i].takerAssetAmount,
|
||||
orders[i].makerAssetAmount,
|
||||
remainingMakerAssetFillAmount
|
||||
);
|
||||
|
||||
// Attempt to sell the remaining amount of takerAsset
|
||||
FillResults memory singleFillResults = fillOrder(
|
||||
orders[i],
|
||||
remainingTakerAssetFillAmount,
|
||||
signatures[i]
|
||||
);
|
||||
|
||||
// HACK: the proxyId is "popped" from the byte array before a fill is settled
|
||||
// by subtracting from the length of the array. Since the popped byte is
|
||||
// still in memory, we can "unpop" it by incrementing the length of the byte array.
|
||||
assembly {
|
||||
let len := mload(makerAssetData)
|
||||
mstore(makerAssetData, add(len, 1))
|
||||
}
|
||||
|
||||
// Update amounts filled and fees paid by maker and taker
|
||||
addFillResults(totalFillResults, singleFillResults);
|
||||
|
||||
// Stop execution if the entire amount of makerAsset has been bought
|
||||
if (totalFillResults.makerAssetFilledAmount == makerAssetFillAmount) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return totalFillResults;
|
||||
}
|
||||
|
||||
/// @dev Synchronously executes multiple fill orders in a single transaction until total amount is bought by taker.
|
||||
/// Returns false if the transaction would otherwise revert.
|
||||
/// @param orders Array of order specifications.
|
||||
/// @param makerAssetFillAmount Desired amount of makerAsset to buy.
|
||||
/// @param signatures Proofs that orders have been signed by makers.
|
||||
/// @return Amounts filled and fees paid by makers and taker.
|
||||
function marketBuyOrdersNoThrow(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256 makerAssetFillAmount,
|
||||
bytes[] memory signatures
|
||||
)
|
||||
public
|
||||
returns (FillResults memory totalFillResults)
|
||||
{
|
||||
bytes memory makerAssetData = orders[0].makerAssetData;
|
||||
|
||||
for (uint256 i = 0; i < orders.length; i++) {
|
||||
|
||||
// We assume that asset being bought by taker is the same for each order.
|
||||
// Rather than passing this in as calldata, we copy the makerAssetData from the first order onto all later orders.
|
||||
orders[i].makerAssetData = makerAssetData;
|
||||
|
||||
// Calculate the remaining amount of makerAsset to buy
|
||||
uint256 remainingMakerAssetFillAmount = safeSub(makerAssetFillAmount, totalFillResults.makerAssetFilledAmount);
|
||||
|
||||
// Convert the remaining amount of makerAsset to buy into remaining amount
|
||||
// of takerAsset to sell, assuming entire amount can be sold in the current order
|
||||
uint256 remainingTakerAssetFillAmount = getPartialAmount(
|
||||
orders[i].takerAssetAmount,
|
||||
orders[i].makerAssetAmount,
|
||||
remainingMakerAssetFillAmount
|
||||
);
|
||||
|
||||
// Attempt to sell the remaining amount of takerAsset
|
||||
FillResults memory singleFillResults = fillOrderNoThrow(
|
||||
orders[i],
|
||||
remainingTakerAssetFillAmount,
|
||||
signatures[i]
|
||||
);
|
||||
|
||||
// Update amounts filled and fees paid by maker and taker
|
||||
addFillResults(totalFillResults, singleFillResults);
|
||||
|
||||
// Stop execution if the entire amount of makerAsset has been bought
|
||||
if (totalFillResults.makerAssetFilledAmount == makerAssetFillAmount) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return totalFillResults;
|
||||
}
|
||||
|
||||
/// @dev Synchronously cancels multiple orders in a single transaction.
|
||||
/// @param orders Array of order specifications.
|
||||
function batchCancelOrders(LibOrder.Order[] memory orders)
|
||||
public
|
||||
{
|
||||
for (uint256 i = 0; i < orders.length; i++) {
|
||||
cancelOrder(orders[i]);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
|
||||
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.4.24;
|
||||
|
||||
contract IAssetProxyDispatcher {
|
||||
|
||||
/// @dev Registers an asset proxy to an asset proxy id.
|
||||
/// An id can only be assigned to a single proxy at a given time.
|
||||
/// @param assetProxyId Id to register`newAssetProxy` under.
|
||||
/// @param newAssetProxy Address of new asset proxy to register, or 0x0 to unset assetProxyId.
|
||||
/// @param oldAssetProxy Existing asset proxy to overwrite, or 0x0 if assetProxyId is currently unused.
|
||||
function registerAssetProxy(
|
||||
uint8 assetProxyId,
|
||||
address newAssetProxy,
|
||||
address oldAssetProxy
|
||||
)
|
||||
external;
|
||||
|
||||
/// @dev Gets an asset proxy.
|
||||
/// @param assetProxyId Id of the asset proxy.
|
||||
/// @return The asset proxy registered to assetProxyId. Returns 0x0 if no proxy is registered.
|
||||
function getAssetProxy(uint8 assetProxyId)
|
||||
external
|
||||
view
|
||||
returns (address);
|
||||
}
|
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
|
||||
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.4.24;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "./IExchangeCore.sol";
|
||||
import "./IMatchOrders.sol";
|
||||
import "./ISignatureValidator.sol";
|
||||
import "./ITransactions.sol";
|
||||
import "./IAssetProxyDispatcher.sol";
|
||||
import "./IWrapperFunctions.sol";
|
||||
|
||||
contract IExchange is
|
||||
IExchangeCore,
|
||||
IMatchOrders,
|
||||
ISignatureValidator,
|
||||
ITransactions,
|
||||
IAssetProxyDispatcher,
|
||||
IWrapperFunctions
|
||||
{}
|
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
|
||||
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.4.24;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "../libs/LibOrder.sol";
|
||||
import "../libs/LibFillResults.sol";
|
||||
|
||||
contract IExchangeCore {
|
||||
|
||||
/// @dev Cancels all orders reated by sender with a salt less than or equal to the specified salt value.
|
||||
/// @param salt Orders created with a salt less or equal to this value will be cancelled.
|
||||
function cancelOrdersUpTo(uint256 salt)
|
||||
external;
|
||||
|
||||
/// @dev Fills the input order.
|
||||
/// @param order Order struct containing order specifications.
|
||||
/// @param takerAssetFillAmount Desired amount of takerAsset to sell.
|
||||
/// @param signature Proof that order has been created by maker.
|
||||
/// @return Amounts filled and fees paid by maker and taker.
|
||||
function fillOrder(
|
||||
LibOrder.Order memory order,
|
||||
uint256 takerAssetFillAmount,
|
||||
bytes memory signature
|
||||
)
|
||||
public
|
||||
returns (LibFillResults.FillResults memory fillResults);
|
||||
|
||||
/// @dev After calling, the order can not be filled anymore.
|
||||
/// @param order Order struct containing order specifications.
|
||||
function cancelOrder(LibOrder.Order memory order)
|
||||
public;
|
||||
|
||||
/// @dev Gets information about an order: status, hash, and amount filled.
|
||||
/// @param order Order to gather information on.
|
||||
/// @return OrderInfo Information about the order and its state.
|
||||
/// See LibOrder.OrderInfo for a complete description.
|
||||
function getOrderInfo(LibOrder.Order memory order)
|
||||
public
|
||||
view
|
||||
returns (LibOrder.OrderInfo memory orderInfo);
|
||||
}
|
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
|
||||
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.4.24;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "../libs/LibOrder.sol";
|
||||
import "../libs/LibFillResults.sol";
|
||||
|
||||
contract IMatchOrders {
|
||||
|
||||
/// @dev Match two complementary orders that have a profitable spread.
|
||||
/// Each order is filled at their respective price point. However, the calculations are
|
||||
/// carried out as though the orders are both being filled at the right order's price point.
|
||||
/// The profit made by the left order goes to the taker (who matched the two orders).
|
||||
/// @param leftOrder First order to match.
|
||||
/// @param rightOrder Second order to match.
|
||||
/// @param leftSignature Proof that order was created by the left maker.
|
||||
/// @param rightSignature Proof that order was created by the right maker.
|
||||
/// @return matchedFillResults Amounts filled and fees paid by maker and taker of matched orders.
|
||||
/// TODO: Make this function external once supported by Solidity (See Solidity Issues #3199, #1603)
|
||||
function matchOrders(
|
||||
LibOrder.Order memory leftOrder,
|
||||
LibOrder.Order memory rightOrder,
|
||||
bytes memory leftSignature,
|
||||
bytes memory rightSignature
|
||||
)
|
||||
public
|
||||
returns (LibFillResults.MatchedFillResults memory matchedFillResults);
|
||||
}
|
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
|
||||
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.4.24;
|
||||
|
||||
contract ISignatureValidator {
|
||||
|
||||
/// @dev Approves a hash on-chain using any valid signature type.
|
||||
/// After presigning a hash, the preSign signature type will become valid for that hash and signer.
|
||||
/// @param signer Address that should have signed the given hash.
|
||||
/// @param signature Proof that the hash has been signed by signer.
|
||||
function preSign(
|
||||
bytes32 hash,
|
||||
address signer,
|
||||
bytes signature
|
||||
)
|
||||
external;
|
||||
|
||||
/// @dev Approves/unnapproves a Validator contract to verify signatures on signer's behalf.
|
||||
/// @param validator Address of Validator contract.
|
||||
/// @param approval Approval or disapproval of Validator contract.
|
||||
function setSignatureValidatorApproval(
|
||||
address validator,
|
||||
bool approval
|
||||
)
|
||||
external;
|
||||
|
||||
/// @dev Verifies that a signature is valid.
|
||||
/// @param hash Message hash that is signed.
|
||||
/// @param signer Address of signer.
|
||||
/// @param signature Proof of signing.
|
||||
/// @return Validity of order signature.
|
||||
function isValidSignature(
|
||||
bytes32 hash,
|
||||
address signer,
|
||||
bytes memory signature
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (bool isValid);
|
||||
}
|
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
|
||||
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.4.24;
|
||||
|
||||
contract ITransactions {
|
||||
|
||||
/// @dev Executes an exchange method call in the context of signer.
|
||||
/// @param salt Arbitrary number to ensure uniqueness of transaction hash.
|
||||
/// @param signer Address of transaction signer.
|
||||
/// @param data AbiV2 encoded calldata.
|
||||
/// @param signature Proof of signer transaction by signer.
|
||||
function executeTransaction(
|
||||
uint256 salt,
|
||||
address signer,
|
||||
bytes data,
|
||||
bytes signature
|
||||
)
|
||||
external;
|
||||
}
|
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
|
||||
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.4.23;
|
||||
|
||||
contract IValidator {
|
||||
|
||||
/// @dev Verifies that a signature is valid.
|
||||
/// @param hash Message hash that is signed.
|
||||
/// @param signer Address that should have signed the given hash.
|
||||
/// @param signature Proof of signing.
|
||||
/// @return Validity of order signature.
|
||||
function isValidSignature(
|
||||
bytes32 hash,
|
||||
address signer,
|
||||
bytes signature
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (bool isValid);
|
||||
}
|
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
|
||||
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.4.24;
|
||||
|
||||
contract IWallet {
|
||||
|
||||
/// @dev Verifies that a signature is valid.
|
||||
/// @param hash Message hash that is signed.
|
||||
/// @param signature Proof of signing.
|
||||
/// @return Validity of order signature.
|
||||
function isValidSignature(
|
||||
bytes32 hash,
|
||||
bytes signature
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (bool isValid);
|
||||
}
|
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
|
||||
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.4.24;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "../libs/LibOrder.sol";
|
||||
import "../libs/LibFillResults.sol";
|
||||
|
||||
contract IWrapperFunctions {
|
||||
/// @dev Fills the input order. Reverts if exact takerAssetFillAmount not filled.
|
||||
/// @param order LibOrder.Order struct containing order specifications.
|
||||
/// @param takerAssetFillAmount Desired amount of takerAsset to sell.
|
||||
/// @param signature Proof that order has been created by maker.
|
||||
function fillOrKillOrder(
|
||||
LibOrder.Order memory order,
|
||||
uint256 takerAssetFillAmount,
|
||||
bytes memory signature
|
||||
)
|
||||
public
|
||||
returns (LibFillResults.FillResults memory fillResults);
|
||||
|
||||
/// @dev Fills an order with specified parameters and ECDSA signature.
|
||||
/// Returns false if the transaction would otherwise revert.
|
||||
/// @param order LibOrder.Order struct containing order specifications.
|
||||
/// @param takerAssetFillAmount Desired amount of takerAsset to sell.
|
||||
/// @param signature Proof that order has been created by maker.
|
||||
/// @return Amounts filled and fees paid by maker and taker.
|
||||
function fillOrderNoThrow(
|
||||
LibOrder.Order memory order,
|
||||
uint256 takerAssetFillAmount,
|
||||
bytes memory signature
|
||||
)
|
||||
public
|
||||
returns (LibFillResults.FillResults memory fillResults);
|
||||
|
||||
/// @dev Synchronously executes multiple calls of fillOrder.
|
||||
/// @param orders Array of order specifications.
|
||||
/// @param takerAssetFillAmounts Array of desired amounts of takerAsset to sell in orders.
|
||||
/// @param signatures Proofs that orders have been created by makers.
|
||||
/// @return Amounts filled and fees paid by makers and taker.
|
||||
function batchFillOrders(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256[] memory takerAssetFillAmounts,
|
||||
bytes[] memory signatures
|
||||
)
|
||||
public
|
||||
returns (LibFillResults.FillResults memory totalFillResults);
|
||||
|
||||
/// @dev Synchronously executes multiple calls of fillOrKill.
|
||||
/// @param orders Array of order specifications.
|
||||
/// @param takerAssetFillAmounts Array of desired amounts of takerAsset to sell in orders.
|
||||
/// @param signatures Proofs that orders have been created by makers.
|
||||
/// @return Amounts filled and fees paid by makers and taker.
|
||||
function batchFillOrKillOrders(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256[] memory takerAssetFillAmounts,
|
||||
bytes[] memory signatures
|
||||
)
|
||||
public
|
||||
returns (LibFillResults.FillResults memory totalFillResults);
|
||||
|
||||
/// @dev Fills an order with specified parameters and ECDSA signature.
|
||||
/// Returns false if the transaction would otherwise revert.
|
||||
/// @param orders Array of order specifications.
|
||||
/// @param takerAssetFillAmounts Array of desired amounts of takerAsset to sell in orders.
|
||||
/// @param signatures Proofs that orders have been created by makers.
|
||||
/// @return Amounts filled and fees paid by makers and taker.
|
||||
function batchFillOrdersNoThrow(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256[] memory takerAssetFillAmounts,
|
||||
bytes[] memory signatures
|
||||
)
|
||||
public
|
||||
returns (LibFillResults.FillResults memory totalFillResults);
|
||||
|
||||
/// @dev Synchronously executes multiple calls of fillOrder until total amount of takerAsset is sold by taker.
|
||||
/// @param orders Array of order specifications.
|
||||
/// @param takerAssetFillAmount Desired amount of takerAsset to sell.
|
||||
/// @param signatures Proofs that orders have been created by makers.
|
||||
/// @return Amounts filled and fees paid by makers and taker.
|
||||
function marketSellOrders(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256 takerAssetFillAmount,
|
||||
bytes[] memory signatures
|
||||
)
|
||||
public
|
||||
returns (LibFillResults.FillResults memory totalFillResults);
|
||||
|
||||
/// @dev Synchronously executes multiple calls of fillOrder until total amount of takerAsset is sold by taker.
|
||||
/// Returns false if the transaction would otherwise revert.
|
||||
/// @param orders Array of order specifications.
|
||||
/// @param takerAssetFillAmount Desired amount of takerAsset to sell.
|
||||
/// @param signatures Proofs that orders have been signed by makers.
|
||||
/// @return Amounts filled and fees paid by makers and taker.
|
||||
function marketSellOrdersNoThrow(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256 takerAssetFillAmount,
|
||||
bytes[] memory signatures
|
||||
)
|
||||
public
|
||||
returns (LibFillResults.FillResults memory totalFillResults);
|
||||
|
||||
/// @dev Synchronously executes multiple calls of fillOrder until total amount of makerAsset is bought by taker.
|
||||
/// @param orders Array of order specifications.
|
||||
/// @param makerAssetFillAmount Desired amount of makerAsset to buy.
|
||||
/// @param signatures Proofs that orders have been signed by makers.
|
||||
/// @return Amounts filled and fees paid by makers and taker.
|
||||
function marketBuyOrders(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256 makerAssetFillAmount,
|
||||
bytes[] memory signatures
|
||||
)
|
||||
public
|
||||
returns (LibFillResults.FillResults memory totalFillResults);
|
||||
|
||||
/// @dev Synchronously executes multiple fill orders in a single transaction until total amount is bought by taker.
|
||||
/// Returns false if the transaction would otherwise revert.
|
||||
/// @param orders Array of order specifications.
|
||||
/// @param makerAssetFillAmount Desired amount of makerAsset to buy.
|
||||
/// @param signatures Proofs that orders have been signed by makers.
|
||||
/// @return Amounts filled and fees paid by makers and taker.
|
||||
function marketBuyOrdersNoThrow(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256 makerAssetFillAmount,
|
||||
bytes[] memory signatures
|
||||
)
|
||||
public
|
||||
returns (LibFillResults.FillResults memory totalFillResults);
|
||||
|
||||
/// @dev Synchronously cancels multiple orders in a single transaction.
|
||||
/// @param orders Array of order specifications.
|
||||
function batchCancelOrders(LibOrder.Order[] memory orders)
|
||||
public;
|
||||
}
|
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
|
||||
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.4.24;
|
||||
|
||||
contract LibExchangeErrors {
|
||||
/// Order validation errors ///
|
||||
string constant ORDER_UNFILLABLE = "ORDER_UNFILLABLE"; // Order cannot be filled.
|
||||
string constant INVALID_MAKER = "INVALID_MAKER"; // Invalid makerAddress.
|
||||
string constant INVALID_TAKER = "INVALID_TAKER"; // Invalid takerAddress.
|
||||
string constant INVALID_SENDER = "INVALID_SENDER"; // Invalid `msg.sender`.
|
||||
string constant INVALID_ORDER_SIGNATURE = "INVALID_ORDER_SIGNATURE"; // Signature validation failed.
|
||||
|
||||
/// fillOrder validation errors ///
|
||||
string constant INVALID_TAKER_AMOUNT = "INVALID_TAKER_AMOUNT"; // takerAssetFillAmount cannot equal 0.
|
||||
string constant ROUNDING_ERROR = "ROUNDING_ERROR"; // Rounding error greater than 0.1% of takerAssetFillAmount.
|
||||
|
||||
/// Signature validation errors ///
|
||||
string constant INVALID_SIGNATURE = "INVALID_SIGNATURE"; // Signature validation failed.
|
||||
string constant SIGNATURE_ILLEGAL = "SIGNATURE_ILLEGAL"; // Signature type is illegal.
|
||||
string constant SIGNATURE_UNSUPPORTED = "SIGNATURE_UNSUPPORTED"; // Signature type unsupported.
|
||||
|
||||
/// cancelOrdersUptTo errors ///
|
||||
string constant INVALID_NEW_MAKER_EPOCH = "INVALID_NEW_MAKER_EPOCH"; // Specified salt must be greater than or equal to existing makerEpoch.
|
||||
|
||||
/// fillOrKillOrder errors ///
|
||||
string constant COMPLETE_FILL_FAILED = "COMPLETE_FILL_FAILED"; // Desired takerAssetFillAmount could not be completely filled.
|
||||
|
||||
/// matchOrders errors ///
|
||||
string constant NEGATIVE_SPREAD_REQUIRED = "NEGATIVE_SPREAD_REQUIRED"; // Matched orders must have a negative spread.
|
||||
|
||||
/// Transaction errors ///
|
||||
string constant REENTRANCY_ILLEGAL = "REENTRANCY_ILLEGAL"; // Recursive reentrancy is not allowed.
|
||||
string constant INVALID_TX_HASH = "INVALID_TX_HASH"; // Transaction has already been executed.
|
||||
string constant INVALID_TX_SIGNATURE = "INVALID_TX_SIGNATURE"; // Signature validation failed.
|
||||
string constant FAILED_EXECUTION = "FAILED_EXECUTION"; // Transaction execution failed.
|
||||
|
||||
/// registerAssetProxy errors ///
|
||||
string constant ASSET_PROXY_MISMATCH = "ASSET_PROXY_MISMATCH"; // oldAssetProxy proxy does not match currentAssetProxy.
|
||||
string constant ASSET_PROXY_ID_MISMATCH = "ASSET_PROXY_ID_MISMATCH"; // newAssetProxyId does not match given assetProxyId.
|
||||
|
||||
/// Length validation errors ///
|
||||
string constant LENGTH_GREATER_THAN_0_REQUIRED = "LENGTH_GREATER_THAN_0_REQUIRED"; // Byte array must have a length greater than 0.
|
||||
string constant LENGTH_0_REQUIRED = "LENGTH_1_REQUIRED"; // Byte array must have a length of 1.
|
||||
string constant LENGTH_65_REQUIRED = "LENGTH_66_REQUIRED"; // Byte array must have a length of 66.
|
||||
}
|
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
|
||||
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.4.24;
|
||||
|
||||
import "../../../utils/SafeMath/SafeMath.sol";
|
||||
|
||||
contract LibFillResults is
|
||||
SafeMath
|
||||
{
|
||||
|
||||
struct FillResults {
|
||||
uint256 makerAssetFilledAmount;
|
||||
uint256 takerAssetFilledAmount;
|
||||
uint256 makerFeePaid;
|
||||
uint256 takerFeePaid;
|
||||
}
|
||||
|
||||
struct MatchedFillResults {
|
||||
FillResults left;
|
||||
FillResults right;
|
||||
uint256 leftMakerAssetSpreadAmount;
|
||||
}
|
||||
|
||||
/// @dev Adds properties of both FillResults instances.
|
||||
/// Modifies the first FillResults instance specified.
|
||||
/// @param totalFillResults Fill results instance that will be added onto.
|
||||
/// @param singleFillResults Fill results instance that will be added to totalFillResults.
|
||||
function addFillResults(FillResults memory totalFillResults, FillResults memory singleFillResults)
|
||||
internal
|
||||
pure
|
||||
{
|
||||
totalFillResults.makerAssetFilledAmount = safeAdd(totalFillResults.makerAssetFilledAmount, singleFillResults.makerAssetFilledAmount);
|
||||
totalFillResults.takerAssetFilledAmount = safeAdd(totalFillResults.takerAssetFilledAmount, singleFillResults.takerAssetFilledAmount);
|
||||
totalFillResults.makerFeePaid = safeAdd(totalFillResults.makerFeePaid, singleFillResults.makerFeePaid);
|
||||
totalFillResults.takerFeePaid = safeAdd(totalFillResults.takerFeePaid, singleFillResults.takerFeePaid);
|
||||
}
|
||||
}
|
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
|
||||
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.4.24;
|
||||
|
||||
import "../../../utils/SafeMath/SafeMath.sol";
|
||||
|
||||
contract LibMath is
|
||||
SafeMath
|
||||
{
|
||||
string constant ROUNDING_ERROR_ON_PARTIAL_AMOUNT = "A rounding error occurred when calculating partial transfer amounts.";
|
||||
|
||||
/// @dev Calculates partial value given a numerator and denominator.
|
||||
/// @param numerator Numerator.
|
||||
/// @param denominator Denominator.
|
||||
/// @param target Value to calculate partial of.
|
||||
/// @return Partial value of target.
|
||||
function getPartialAmount(
|
||||
uint256 numerator,
|
||||
uint256 denominator,
|
||||
uint256 target)
|
||||
internal
|
||||
pure
|
||||
returns (uint256 partialAmount)
|
||||
{
|
||||
partialAmount = safeDiv(
|
||||
safeMul(numerator, target),
|
||||
denominator
|
||||
);
|
||||
return partialAmount;
|
||||
}
|
||||
|
||||
/// @dev Checks if rounding error > 0.1%.
|
||||
/// @param numerator Numerator.
|
||||
/// @param denominator Denominator.
|
||||
/// @param target Value to multiply with numerator/denominator.
|
||||
/// @return Rounding error is present.
|
||||
function isRoundingError(
|
||||
uint256 numerator,
|
||||
uint256 denominator,
|
||||
uint256 target)
|
||||
internal
|
||||
pure
|
||||
returns (bool isError)
|
||||
{
|
||||
uint256 remainder = mulmod(target, numerator, denominator);
|
||||
if (remainder == 0) {
|
||||
return false; // No rounding error.
|
||||
}
|
||||
|
||||
uint256 errPercentageTimes1000000 = safeDiv(
|
||||
safeMul(remainder, 1000000),
|
||||
safeMul(numerator, target)
|
||||
);
|
||||
isError = errPercentageTimes1000000 > 1000;
|
||||
return isError;
|
||||
}
|
||||
}
|
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
|
||||
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.4.24;
|
||||
|
||||
contract LibOrder {
|
||||
|
||||
bytes32 constant DOMAIN_SEPARATOR_SCHEMA_HASH = keccak256(abi.encodePacked(
|
||||
"DomainSeparator(address contract)"
|
||||
));
|
||||
|
||||
bytes32 constant ORDER_SCHEMA_HASH = keccak256(abi.encodePacked(
|
||||
"Order(",
|
||||
"address makerAddress,",
|
||||
"address takerAddress,",
|
||||
"address feeRecipientAddress,",
|
||||
"address senderAddress,",
|
||||
"uint256 makerAssetAmount,",
|
||||
"uint256 takerAssetAmount,",
|
||||
"uint256 makerFee,",
|
||||
"uint256 takerFee,",
|
||||
"uint256 expirationTimeSeconds,",
|
||||
"uint256 salt,",
|
||||
"bytes makerAssetData,",
|
||||
"bytes takerAssetData,",
|
||||
")"
|
||||
));
|
||||
|
||||
// A valid order remains fillable until it is expired, fully filled, or cancelled.
|
||||
// An order's state is unaffected by external factors, like account balances.
|
||||
enum OrderStatus {
|
||||
INVALID, // Default value
|
||||
INVALID_MAKER_ASSET_AMOUNT, // Order does not have a valid maker asset amount
|
||||
INVALID_TAKER_ASSET_AMOUNT, // Order does not have a valid taker asset amount
|
||||
FILLABLE, // Order is fillable
|
||||
EXPIRED, // Order has already expired
|
||||
FULLY_FILLED, // Order is fully filled
|
||||
CANCELLED // Order has been cancelled
|
||||
}
|
||||
|
||||
struct Order {
|
||||
address makerAddress;
|
||||
address takerAddress;
|
||||
address feeRecipientAddress;
|
||||
address senderAddress;
|
||||
uint256 makerAssetAmount;
|
||||
uint256 takerAssetAmount;
|
||||
uint256 makerFee;
|
||||
uint256 takerFee;
|
||||
uint256 expirationTimeSeconds;
|
||||
uint256 salt;
|
||||
bytes makerAssetData;
|
||||
bytes takerAssetData;
|
||||
}
|
||||
|
||||
struct OrderInfo {
|
||||
// See LibStatus for a complete description of order statuses
|
||||
uint8 orderStatus;
|
||||
// Keccak-256 EIP712 hash of the order
|
||||
bytes32 orderHash;
|
||||
// Amount of order that has been filled
|
||||
uint256 orderTakerAssetFilledAmount;
|
||||
}
|
||||
|
||||
/// @dev Calculates Keccak-256 hash of the order.
|
||||
/// @param order The order structure.
|
||||
/// @return Keccak-256 EIP712 hash of the order.
|
||||
function getOrderHash(Order memory order)
|
||||
internal
|
||||
view
|
||||
returns (bytes32 orderHash)
|
||||
{
|
||||
// TODO: EIP712 is not finalized yet
|
||||
// Source: https://github.com/ethereum/EIPs/pull/712
|
||||
orderHash = keccak256(abi.encodePacked(
|
||||
DOMAIN_SEPARATOR_SCHEMA_HASH,
|
||||
keccak256(abi.encodePacked(address(this))),
|
||||
ORDER_SCHEMA_HASH,
|
||||
keccak256(abi.encodePacked(
|
||||
order.makerAddress,
|
||||
order.takerAddress,
|
||||
order.feeRecipientAddress,
|
||||
order.senderAddress,
|
||||
order.makerAssetAmount,
|
||||
order.takerAssetAmount,
|
||||
order.makerFee,
|
||||
order.takerFee,
|
||||
order.expirationTimeSeconds,
|
||||
order.salt,
|
||||
keccak256(abi.encodePacked(order.makerAssetData)),
|
||||
keccak256(abi.encodePacked(order.takerAssetData))
|
||||
))
|
||||
));
|
||||
return orderHash;
|
||||
}
|
||||
}
|
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
|
||||
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.4.24;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "../interfaces/IAssetProxyDispatcher.sol";
|
||||
|
||||
contract MAssetProxyDispatcher is
|
||||
IAssetProxyDispatcher
|
||||
{
|
||||
|
||||
// Logs registration of new asset proxy
|
||||
event AssetProxySet(
|
||||
uint8 id,
|
||||
address newAssetProxy,
|
||||
address oldAssetProxy
|
||||
);
|
||||
|
||||
/// @dev Forwards arguments to assetProxy and calls `transferFrom`. Either succeeds or throws.
|
||||
/// @param assetData Byte array encoded for the respective asset proxy.
|
||||
/// @param assetProxyId Id of assetProxy to dispach to.
|
||||
/// @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,
|
||||
uint8 assetProxyId,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
)
|
||||
internal;
|
||||
}
|
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
|
||||
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.4.24;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "../libs/LibOrder.sol";
|
||||
import "../libs/LibFillResults.sol";
|
||||
import "../interfaces/IExchangeCore.sol";
|
||||
|
||||
contract MExchangeCore is
|
||||
IExchangeCore
|
||||
{
|
||||
// Fill event is emitted whenever an order is filled.
|
||||
event Fill(
|
||||
address indexed makerAddress,
|
||||
address takerAddress,
|
||||
address indexed feeRecipientAddress,
|
||||
uint256 makerAssetFilledAmount,
|
||||
uint256 takerAssetFilledAmount,
|
||||
uint256 makerFeePaid,
|
||||
uint256 takerFeePaid,
|
||||
bytes32 indexed orderHash,
|
||||
bytes makerAssetData,
|
||||
bytes takerAssetData
|
||||
);
|
||||
|
||||
// Cancel event is emitted whenever an individual order is cancelled.
|
||||
event Cancel(
|
||||
address indexed makerAddress,
|
||||
address indexed feeRecipientAddress,
|
||||
bytes32 indexed orderHash,
|
||||
bytes makerAssetData,
|
||||
bytes takerAssetData
|
||||
);
|
||||
|
||||
// CancelUpTo event is emitted whenever `cancelOrdersUpTo` is executed succesfully.
|
||||
event CancelUpTo(
|
||||
address indexed makerAddress,
|
||||
uint256 makerEpoch
|
||||
);
|
||||
|
||||
/// @dev Updates state with results of a fill order.
|
||||
/// @param order that was filled.
|
||||
/// @param takerAddress Address of taker who filled the order.
|
||||
/// @param orderTakerAssetFilledAmount Amount of order already filled.
|
||||
/// @return fillResults Amounts filled and fees paid by maker and taker.
|
||||
function updateFilledState(
|
||||
LibOrder.Order memory order,
|
||||
address takerAddress,
|
||||
bytes32 orderHash,
|
||||
uint256 orderTakerAssetFilledAmount,
|
||||
LibFillResults.FillResults memory fillResults
|
||||
)
|
||||
internal;
|
||||
|
||||
/// @dev Updates state with results of cancelling an order.
|
||||
/// State is only updated if the order is currently fillable.
|
||||
/// Otherwise, updating state would have no effect.
|
||||
/// @param order that was cancelled.
|
||||
/// @param orderHash Hash of order that was cancelled.
|
||||
function updateCancelledState(
|
||||
LibOrder.Order memory order,
|
||||
bytes32 orderHash
|
||||
)
|
||||
internal;
|
||||
|
||||
/// @dev Validates context for fillOrder. Succeeds or throws.
|
||||
/// @param order to be filled.
|
||||
/// @param orderInfo Status, orderHash, and amount already filled of order.
|
||||
/// @param takerAddress Address of order taker.
|
||||
/// @param takerAssetFillAmount Desired amount of order to fill by taker.
|
||||
/// @param takerAssetFilledAmount Amount of takerAsset that will be filled.
|
||||
/// @param signature Proof that the orders was created by its maker.
|
||||
function assertValidFill(
|
||||
LibOrder.Order memory order,
|
||||
LibOrder.OrderInfo memory orderInfo,
|
||||
address takerAddress,
|
||||
uint256 takerAssetFillAmount,
|
||||
uint256 takerAssetFilledAmount,
|
||||
bytes memory signature
|
||||
)
|
||||
internal
|
||||
view;
|
||||
|
||||
|
||||
/// @dev Validates context for cancelOrder. Succeeds or throws.
|
||||
/// @param order to be cancelled.
|
||||
/// @param orderInfo OrderStatus, orderHash, and amount already filled of order.
|
||||
function assertValidCancel(
|
||||
LibOrder.Order memory order,
|
||||
LibOrder.OrderInfo memory orderInfo
|
||||
)
|
||||
internal
|
||||
view;
|
||||
|
||||
/// @dev Calculates amounts filled and fees paid by maker and taker.
|
||||
/// @param order to be filled.
|
||||
/// @param takerAssetFilledAmount Amount of takerAsset that will be filled.
|
||||
/// @return fillResults Amounts filled and fees paid by maker and taker.
|
||||
function calculateFillResults(
|
||||
LibOrder.Order memory order,
|
||||
uint256 takerAssetFilledAmount
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (LibFillResults.FillResults memory fillResults);
|
||||
}
|
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
|
||||
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.4.24;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "../libs/LibOrder.sol";
|
||||
import "../libs/LibFillResults.sol";
|
||||
import "../interfaces/IMatchOrders.sol";
|
||||
|
||||
contract MMatchOrders is
|
||||
IMatchOrders
|
||||
{
|
||||
|
||||
/// @dev Validates context for matchOrders. Succeeds or throws.
|
||||
/// @param leftOrder First order to match.
|
||||
/// @param rightOrder Second order to match.
|
||||
function assertValidMatch(
|
||||
LibOrder.Order memory leftOrder,
|
||||
LibOrder.Order memory rightOrder
|
||||
)
|
||||
internal
|
||||
pure;
|
||||
|
||||
/// @dev Calculates fill amounts for the matched orders.
|
||||
/// Each order is filled at their respective price point. However, the calculations are
|
||||
/// carried out as though the orders are both being filled at the right order's price point.
|
||||
/// The profit made by the leftOrder order goes to the taker (who matched the two orders).
|
||||
/// @param leftOrder First order to match.
|
||||
/// @param rightOrder Second order to match.
|
||||
/// @param leftOrderTakerAssetFilledAmount Amount of left order already filled.
|
||||
/// @param rightOrderTakerAssetFilledAmount Amount of right order already filled.
|
||||
/// @param matchedFillResults Amounts to fill and fees to pay by maker and taker of matched orders.
|
||||
function calculateMatchedFillResults(
|
||||
LibOrder.Order memory leftOrder,
|
||||
LibOrder.Order memory rightOrder,
|
||||
uint256 leftOrderTakerAssetFilledAmount,
|
||||
uint256 rightOrderTakerAssetFilledAmount
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (LibFillResults.MatchedFillResults memory matchedFillResults);
|
||||
}
|
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
|
||||
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.4.24;
|
||||
|
||||
import "../libs/LibOrder.sol";
|
||||
import "../libs/LibFillResults.sol";
|
||||
|
||||
contract MSettlement {
|
||||
|
||||
/// @dev Settles an order by transferring assets between counterparties.
|
||||
/// @param order Order struct containing order specifications.
|
||||
/// @param takerAddress Address selling takerAsset and buying makerAsset.
|
||||
/// @param fillResults Amounts to be filled and fees paid by maker and taker.
|
||||
function settleOrder(
|
||||
LibOrder.Order memory order,
|
||||
address takerAddress,
|
||||
LibFillResults.FillResults memory fillResults
|
||||
)
|
||||
internal;
|
||||
|
||||
/// @dev Settles matched order by transferring appropriate funds between order makers, taker, and fee recipient.
|
||||
/// @param leftOrder First matched order.
|
||||
/// @param rightOrder Second matched order.
|
||||
/// @param takerAddress Address that matched the orders. The taker receives the spread between orders as profit.
|
||||
/// @param matchedFillResults Struct holding amounts to transfer between makers, taker, and fee recipients.
|
||||
function settleMatchedOrders(
|
||||
LibOrder.Order memory leftOrder,
|
||||
LibOrder.Order memory rightOrder,
|
||||
address takerAddress,
|
||||
LibFillResults.MatchedFillResults memory matchedFillResults
|
||||
)
|
||||
internal;
|
||||
}
|
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
|
||||
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.4.24;
|
||||
|
||||
import "../interfaces/ISignatureValidator.sol";
|
||||
|
||||
contract MSignatureValidator is
|
||||
ISignatureValidator
|
||||
{
|
||||
// Allowed signature types.
|
||||
enum SignatureType {
|
||||
Illegal, // 0x00, default value
|
||||
Invalid, // 0x01
|
||||
EIP712, // 0x02
|
||||
EthSign, // 0x03
|
||||
Caller, // 0x04
|
||||
Wallet, // 0x05
|
||||
Validator, // 0x06
|
||||
PreSigned, // 0x07
|
||||
Trezor // 0x08
|
||||
}
|
||||
}
|
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
|
||||
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.4.24;
|
||||
|
||||
import "../interfaces/ITransactions.sol";
|
||||
|
||||
contract MTransactions is
|
||||
ITransactions
|
||||
{
|
||||
|
||||
/// @dev The current function will be called in the context of this address (either 0x transaction signer or `msg.sender`).
|
||||
/// If calling a fill function, this address will represent the taker.
|
||||
/// If calling a cancel function, this address will represent the maker.
|
||||
/// @return Signer of 0x transaction if entry point is `executeTransaction`.
|
||||
/// `msg.sender` if entry point is any other function.
|
||||
function getCurrentContextAddress()
|
||||
internal
|
||||
view
|
||||
returns (address);
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user