Compare commits
955 Commits
@0xproject
...
@0xproject
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8e5a876b37 | ||
|
|
c71b710d7e | ||
|
|
7440b87596 | ||
|
|
583a17d627 | ||
|
|
caf1a22084 | ||
|
|
29abc5e921 | ||
|
|
098dae9a7e | ||
|
|
aaa7affa46 | ||
|
|
40ca846cdc | ||
|
|
2a24f6e2ea | ||
|
|
98e8105ec5 | ||
|
|
4a94a2b4e8 | ||
|
|
2011349eb1 | ||
|
|
8057f4a678 | ||
|
|
f9ec8a0828 | ||
|
|
a0030c7bdb | ||
|
|
0e4448fd3f | ||
|
|
21d2d59b50 | ||
|
|
295f177271 | ||
|
|
f3154313a8 | ||
|
|
e37f3b4fa3 | ||
|
|
7e5c35d06e | ||
|
|
60756aa02b | ||
|
|
3779ab90de | ||
|
|
5b5037a844 | ||
|
|
03902b0b26 | ||
|
|
883feabb8b | ||
|
|
5fb79e3253 | ||
|
|
c44811fbc2 | ||
|
|
c3eaa694dd | ||
|
|
bd8b8abfea | ||
|
|
1a6c2e2bac | ||
|
|
e2e6ae937d | ||
|
|
5b9c5d2790 | ||
|
|
896a57d4ed | ||
|
|
c3de8d3a67 | ||
|
|
d1a92a0a2e | ||
|
|
5f626495fd | ||
|
|
238f3c89a7 | ||
|
|
6e724eb8a5 | ||
|
|
9aec1feae3 | ||
|
|
8517de128b | ||
|
|
a3e15c910c | ||
|
|
a6303de4d1 | ||
|
|
5356b0e118 | ||
|
|
e31309f213 | ||
|
|
6f8a70834b | ||
|
|
327cc307b3 | ||
|
|
f191ba6e69 | ||
|
|
a2b89411b0 | ||
|
|
f66efed777 | ||
|
|
f61b59fa89 | ||
|
|
6288a72036 | ||
|
|
a941f0ffb6 | ||
|
|
d7373a5c04 | ||
|
|
2ff485d2e0 | ||
|
|
5a67068348 | ||
|
|
d39af6c9eb | ||
|
|
1789025da9 | ||
|
|
696f49497b | ||
|
|
e88eba1877 | ||
|
|
f8b8a10b8f | ||
|
|
01e505a5f4 | ||
|
|
5b2d9a4668 | ||
|
|
71008dc819 | ||
|
|
9301173f7d | ||
|
|
60d95475eb | ||
|
|
c8ace2edc0 | ||
|
|
0b1ba9f997 | ||
|
|
f3026e33fd | ||
|
|
f014a97e9a | ||
|
|
ddad09a936 | ||
|
|
5dd0654105 | ||
|
|
b4b664e97a | ||
|
|
551771235b | ||
|
|
eb201c4084 | ||
|
|
7bfc499ec8 | ||
|
|
71e7e9c9c3 | ||
|
|
8521775389 | ||
|
|
61ad8d4c10 | ||
|
|
38a4ccd9f2 | ||
|
|
cf342dd00e | ||
|
|
08ab81c54c | ||
|
|
d355382f70 | ||
|
|
d171ce4fba | ||
|
|
5a90fece80 | ||
|
|
994935b5da | ||
|
|
874e667849 | ||
|
|
1817f6eaf6 | ||
|
|
2e19930178 | ||
|
|
2b01461748 | ||
|
|
24b9df475c | ||
|
|
011bab3c80 | ||
|
|
699c0c3e05 | ||
|
|
5f4b28960e | ||
|
|
3837913855 | ||
|
|
65eb3997d9 | ||
|
|
47411b406d | ||
|
|
f710026a8f | ||
|
|
925e133f50 | ||
|
|
2bdd60ed72 | ||
|
|
9ac1cce26f | ||
|
|
0a597c94d6 | ||
|
|
02f82be094 | ||
|
|
86e26240a1 | ||
|
|
82c5be2564 | ||
|
|
42f4f07268 | ||
|
|
df4db8fa4c | ||
|
|
bd85fe0af3 | ||
|
|
aee15e5dff | ||
|
|
d7a803d9fd | ||
|
|
839e5895e4 | ||
|
|
49a4f0c74c | ||
|
|
5bea8e63de | ||
|
|
e64be284dd | ||
|
|
e11e26a352 | ||
|
|
bee90abbc4 | ||
|
|
8782559c33 | ||
|
|
223ddc0f68 | ||
|
|
4445d1d5a0 | ||
|
|
b7d001da88 | ||
|
|
3592ebef08 | ||
|
|
a783d21409 | ||
|
|
a716e3de74 | ||
|
|
c797c720be | ||
|
|
1b5742fbf0 | ||
|
|
5794349d97 | ||
|
|
456f094913 | ||
|
|
abb9eb0df4 | ||
|
|
9e7b45ea4c | ||
|
|
6c6bd60a48 | ||
|
|
cef82e72dc | ||
|
|
45b9647ba0 | ||
|
|
160f74d53e | ||
|
|
3ab6139522 | ||
|
|
9aa54257e7 | ||
|
|
8eafa62bbe | ||
|
|
968c24f0bc | ||
|
|
e5c755b1fc | ||
|
|
6d56f01c40 | ||
|
|
eefce48e68 | ||
|
|
c7d97c733a | ||
|
|
3db42deb42 | ||
|
|
02603e8926 | ||
|
|
c5003554f4 | ||
|
|
eb223805ca | ||
|
|
244c148a80 | ||
|
|
4dbb2ed167 | ||
|
|
212d680a47 | ||
|
|
a853e35dec | ||
|
|
fdaf9f0bfc | ||
|
|
0afe45b3a8 | ||
|
|
f9a37168b0 | ||
|
|
52232e98c7 | ||
|
|
0fbb443e4b | ||
|
|
8021694b81 | ||
|
|
a2b262c9df | ||
|
|
5906f4c995 | ||
|
|
da8edd2226 | ||
|
|
406aedfdc2 | ||
|
|
67c834841e | ||
|
|
edaa0b0e34 | ||
|
|
31f03fcf3a | ||
|
|
4a57f2a762 | ||
|
|
92b9dbd706 | ||
|
|
6edd7682a9 | ||
|
|
447891b396 | ||
|
|
89bfcafb80 | ||
|
|
a74a04c5d5 | ||
|
|
0c16f0ea22 | ||
|
|
003d43b03a | ||
|
|
6323496945 | ||
|
|
fd5e231a93 | ||
|
|
ae209677de | ||
|
|
d5ca00de95 | ||
|
|
7be84c6ad3 | ||
|
|
425039e4d3 | ||
|
|
6c5333180d | ||
|
|
cb47a51b70 | ||
|
|
e36fb654b0 | ||
|
|
6325fac020 | ||
|
|
c6358d5f22 | ||
|
|
413e8b6062 | ||
|
|
e113a8e7af | ||
|
|
e42891ae5b | ||
|
|
c90770472e | ||
|
|
45df9de5b5 | ||
|
|
2d0940589e | ||
|
|
5908f189a7 | ||
|
|
17328bce53 | ||
|
|
451a0dacbe | ||
|
|
a46199e37d | ||
|
|
e25cc301fd | ||
|
|
5bbb0d1f60 | ||
|
|
a5b8875356 | ||
|
|
3e86df311d | ||
|
|
002f9ebde7 | ||
|
|
72e6e1ce8b | ||
|
|
a3c7af95e1 | ||
|
|
0987c9a7cf | ||
|
|
bbd87daf6d | ||
|
|
30e4613d0a | ||
|
|
79593f52b0 | ||
|
|
bab8c1eeff | ||
|
|
8b6cc95c1b | ||
|
|
90236b87de | ||
|
|
b6a133cc64 | ||
|
|
7aa070f9ea | ||
|
|
c2ec2291e8 | ||
|
|
97fcfb7f6c | ||
|
|
ce677fd55a | ||
|
|
e48a3edacb | ||
|
|
ce0b92d681 | ||
|
|
29c5ba5639 | ||
|
|
cdea618457 | ||
|
|
425a519f97 | ||
|
|
c07d64c6ff | ||
|
|
c07e3a76bb | ||
|
|
8fe844bcc9 | ||
|
|
a0390956a9 | ||
|
|
4f1e6296ca | ||
|
|
0ef372e531 | ||
|
|
06e2894750 | ||
|
|
10e2d4b99c | ||
|
|
ef40cb9687 | ||
|
|
758604fc1a | ||
|
|
34c1134b55 | ||
|
|
a5ef1db0c5 | ||
|
|
748ed40321 | ||
|
|
42063f785e | ||
|
|
1657451f37 | ||
|
|
0bb0bff0b3 | ||
|
|
747732118c | ||
|
|
2aec1501d0 | ||
|
|
39c6bc1106 | ||
|
|
4e451479f8 | ||
|
|
93b2736d65 | ||
|
|
34274a1042 | ||
|
|
fa822caa62 | ||
|
|
ddc30cc2c0 | ||
|
|
9d9cab1711 | ||
|
|
fe8f2d8d89 | ||
|
|
2d561bc8a0 | ||
|
|
f5275d3ad7 | ||
|
|
5fbdf9cfb9 | ||
|
|
0409c9c1e5 | ||
|
|
42a5da1df4 | ||
|
|
0b326a8bbe | ||
|
|
9c8501a84e | ||
|
|
2da7f82171 | ||
|
|
593474031d | ||
|
|
fce10548d2 | ||
|
|
addca63938 | ||
|
|
6961169f89 | ||
|
|
3d66feb89f | ||
|
|
bb157eefc6 | ||
|
|
7f8f4df0a0 | ||
|
|
4b325676f7 | ||
|
|
ecba95250d | ||
|
|
dd116b3cd6 | ||
|
|
eabe96fd19 | ||
|
|
7dd9ce2e32 | ||
|
|
fffaafe4c9 | ||
|
|
0b9646136a | ||
|
|
55f38b9c35 | ||
|
|
709fa9e02e | ||
|
|
f42bdb8bab | ||
|
|
10aed46062 | ||
|
|
6e43e89b2d | ||
|
|
10c0c0b6d2 | ||
|
|
e13924cd2d | ||
|
|
7afe00f06a | ||
|
|
87b9caa7dc | ||
|
|
f689d335c0 | ||
|
|
31f9a848f9 | ||
|
|
3d2c5d67af | ||
|
|
63f8f469b0 | ||
|
|
9929f1acf0 | ||
|
|
42ecc087cb | ||
|
|
93adee36b0 | ||
|
|
0e95fd0b9b | ||
|
|
611ddfeeb8 | ||
|
|
dfe2579eeb | ||
|
|
66b36f6d8f | ||
|
|
1b3a9102f1 | ||
|
|
9993a50903 | ||
|
|
c226509be0 | ||
|
|
ef6f52e722 | ||
|
|
7d8cad8e3a | ||
|
|
15507d3827 | ||
|
|
e2d17d122e | ||
|
|
0d7bf50581 | ||
|
|
a50618fcb0 | ||
|
|
fc2a9a756a | ||
|
|
07721eb99f | ||
|
|
13fed15e0c | ||
|
|
38a308ce5b | ||
|
|
be19316dfb | ||
|
|
c4f65681a1 | ||
|
|
f600226aa9 | ||
|
|
67f2864501 | ||
|
|
c1bbcaba73 | ||
|
|
6685cb3fba | ||
|
|
d770e46208 | ||
|
|
665636e642 | ||
|
|
0028e71ab2 | ||
|
|
7fb66bf71a | ||
|
|
3120d854f8 | ||
|
|
c85c14210f | ||
|
|
0fb81a11a8 | ||
|
|
7b67afae06 | ||
|
|
fe9e319a61 | ||
|
|
097fc477a2 | ||
|
|
f60b00d116 | ||
|
|
3a36e0621f | ||
|
|
b482473e23 | ||
|
|
9a5fd3f784 | ||
|
|
b703ccde9b | ||
|
|
80eca30725 | ||
|
|
7dbc14dc43 | ||
|
|
b3f9010eb5 | ||
|
|
f62d72e548 | ||
|
|
d12352972e | ||
|
|
03d3d84db3 | ||
|
|
6d818c25c7 | ||
|
|
6a8f624e75 | ||
|
|
0801b1ddf9 | ||
|
|
4fd64ca492 | ||
|
|
c4bcf24640 | ||
|
|
0114fc9608 | ||
|
|
8db098eaec | ||
|
|
05c3a66543 | ||
|
|
9349752baa | ||
|
|
974fab7284 | ||
|
|
8a52ffe7b7 | ||
|
|
c6ecdbd86e | ||
|
|
03797545f9 | ||
|
|
2778f96483 | ||
|
|
6cd4e7a17e | ||
|
|
5c91b4bfc6 | ||
|
|
e2b51c5dc4 | ||
|
|
b610b7c192 | ||
|
|
b75fdd6b66 | ||
|
|
060b02eaed | ||
|
|
003e5da00d | ||
|
|
02951d4813 | ||
|
|
db52ed9941 | ||
|
|
af333b1838 | ||
|
|
f62762bd0e | ||
|
|
4b67352278 | ||
|
|
76afb6b116 | ||
|
|
db52e87740 | ||
|
|
e22788abe8 | ||
|
|
bbfbfcda85 | ||
|
|
0dfb36e675 | ||
|
|
95a9d77301 | ||
|
|
ab1f070901 | ||
|
|
8201d5d1f8 | ||
|
|
8704c34a0f | ||
|
|
599adaf1bf | ||
|
|
778e399438 | ||
|
|
485ae4d997 | ||
|
|
8cd2ba3ad6 | ||
|
|
dbad7d1869 | ||
|
|
4d482438f5 | ||
|
|
b53a1b51d6 | ||
|
|
49375c73d4 | ||
|
|
98b78c56c5 | ||
|
|
f3e6ef0fa9 | ||
|
|
18e1c2dea5 | ||
|
|
91ae01e484 | ||
|
|
2897b72967 | ||
|
|
3510985cf4 | ||
|
|
5927e65045 | ||
|
|
13e2041d50 | ||
|
|
4bf530ed9e | ||
|
|
4c797405ad | ||
|
|
713c922e35 | ||
|
|
7f1e789264 | ||
|
|
07d00cc515 | ||
|
|
cd55e346af | ||
|
|
6746428fb1 | ||
|
|
634032d5be | ||
|
|
602abc53dd | ||
|
|
fdbaa9768a | ||
|
|
293d7261e0 | ||
|
|
efb6eb28ce | ||
|
|
ac5531ce85 | ||
|
|
bc2415c70e | ||
|
|
0fd411f83f | ||
|
|
b74ad0ad12 | ||
|
|
4c58836735 | ||
|
|
3206b80dbd | ||
|
|
4910f7a61e | ||
|
|
6e9109eaec | ||
|
|
a04ec14cf0 | ||
|
|
7d3df3c117 | ||
|
|
b3a03f8e3e | ||
|
|
e5668c1e5c | ||
|
|
92e74bc4fa | ||
|
|
7e12269baf | ||
|
|
f3f264f5fd | ||
|
|
2e3c9b87df | ||
|
|
0a113e1cf7 | ||
|
|
fd772c48cf | ||
|
|
1c7dce6054 | ||
|
|
0a2947b860 | ||
|
|
c80877af43 | ||
|
|
e68b9c7e81 | ||
|
|
19198737a5 | ||
|
|
fea4b6aecd | ||
|
|
20e2673b82 | ||
|
|
ef1375b9dd | ||
|
|
58f1939ec1 | ||
|
|
ba57c34adb | ||
|
|
936f6ac10f | ||
|
|
7e04c4f24b | ||
|
|
9495c8f46c | ||
|
|
b3f91600d3 | ||
|
|
ddf4437fb6 | ||
|
|
4153d57849 | ||
|
|
0652790703 | ||
|
|
9c934d903d | ||
|
|
d7a7e28925 | ||
|
|
6dec29e214 | ||
|
|
43cf8d30bd | ||
|
|
254d3f53e2 | ||
|
|
ec198343b5 | ||
|
|
876517d458 | ||
|
|
1233c33116 | ||
|
|
eebf205817 | ||
|
|
e666bb44c6 | ||
|
|
39cb0b5122 | ||
|
|
58003a2811 | ||
|
|
7f2a7cfa77 | ||
|
|
8fba0477a6 | ||
|
|
7ca1ba7e1e | ||
|
|
e6f2c7a382 | ||
|
|
69f5f5e946 | ||
|
|
68a8acbe7b | ||
|
|
852811b314 | ||
|
|
2404ff0304 | ||
|
|
9ff4cacf0f | ||
|
|
e443cb2a3b | ||
|
|
f3c6cce455 | ||
|
|
ae14b0a71d | ||
|
|
3c7ebe2697 | ||
|
|
10fb6061cc | ||
|
|
223df8006a | ||
|
|
1c9428cbba | ||
|
|
18dc5d17b5 | ||
|
|
4d50933189 | ||
|
|
9b3680780f | ||
|
|
a26e77074f | ||
|
|
568e4d33f2 | ||
|
|
fd004032cb | ||
|
|
4b6324050d | ||
|
|
12d62e1157 | ||
|
|
063c6b66b6 | ||
|
|
d9b1d31e73 | ||
|
|
0bad911a16 | ||
|
|
518efa8ad2 | ||
|
|
6e87c9e713 | ||
|
|
b61852b1f5 | ||
|
|
fcbe24a126 | ||
|
|
55312d00ef | ||
|
|
a96e3f3222 | ||
|
|
e35519b50f | ||
|
|
ae775f9664 | ||
|
|
071b1c47d1 | ||
|
|
4cc5bbaf19 | ||
|
|
a264c36a48 | ||
|
|
0c2ab22656 | ||
|
|
47adad5122 | ||
|
|
745f209f7e | ||
|
|
2287597712 | ||
|
|
eea8b15180 | ||
|
|
600a2b40af | ||
|
|
a7c51593e4 | ||
|
|
218876ac19 | ||
|
|
6cda67df10 | ||
|
|
897515c002 | ||
|
|
9deaf612f1 | ||
|
|
b7676d8c46 | ||
|
|
05aa2fa421 | ||
|
|
03f5c9b950 | ||
|
|
4c9c4c487a | ||
|
|
c172b9e080 | ||
|
|
5533a84dcd | ||
|
|
562bcb8571 | ||
|
|
00c07b38a4 | ||
|
|
f44bfa9682 | ||
|
|
7357a0a324 | ||
|
|
36a49966eb | ||
|
|
f818d06b43 | ||
|
|
548246c05f | ||
|
|
2bf1aa975a | ||
|
|
4be8eca3fe | ||
|
|
e17ace397c | ||
|
|
6bdabe72b9 | ||
|
|
00bfc7f889 | ||
|
|
5fcb77e591 | ||
|
|
df8de7ff51 | ||
|
|
67d7540907 | ||
|
|
83d0bad3a1 | ||
|
|
9d80a62bb1 | ||
|
|
629653425d | ||
|
|
03ce1d8641 | ||
|
|
225baeb5cb | ||
|
|
cf171d28c7 | ||
|
|
61434a9121 | ||
|
|
20590b7d35 | ||
|
|
fce7081215 | ||
|
|
83c7c8110d | ||
|
|
c4680a97a8 | ||
|
|
91a5bcf380 | ||
|
|
7e9ae458e2 | ||
|
|
4e284f5e6c | ||
|
|
75ded89790 | ||
|
|
598ce0d401 | ||
|
|
fc3058c1e2 | ||
|
|
d14ae70776 | ||
|
|
882816d609 | ||
|
|
2205e2b9a0 | ||
|
|
855fdd7921 | ||
|
|
99b1f81e89 | ||
|
|
46ad7b1b38 | ||
|
|
7e5b7a7f2a | ||
|
|
156e85a6b3 | ||
|
|
6fce02d25e | ||
|
|
4ddb86df53 | ||
|
|
3565e96f42 | ||
|
|
2c7db23022 | ||
|
|
fe51c9a9a2 | ||
|
|
5324dfa5a7 | ||
|
|
881d32e733 | ||
|
|
1f4cbb7479 | ||
|
|
b17bbdaa7d | ||
|
|
5458a1c1b7 | ||
|
|
fa98450754 | ||
|
|
7b4f2b47de | ||
|
|
400a97e7a8 | ||
|
|
a816fb5958 | ||
|
|
c7ad6ebad6 | ||
|
|
85b4a82a4b | ||
|
|
f18fa8e947 | ||
|
|
44cd185c66 | ||
|
|
890f414b5a | ||
|
|
03b1b12ef1 | ||
|
|
dae6f28f8a | ||
|
|
5aca3a2d7d | ||
|
|
7f257e258f | ||
|
|
6a9d3de0f9 | ||
|
|
05aae36813 | ||
|
|
d5d6079b67 | ||
|
|
bb4c8bf8eb | ||
|
|
3eb40db498 | ||
|
|
576f63d5e4 | ||
|
|
cda1dc82e9 | ||
|
|
2721252d6a | ||
|
|
45ac960308 | ||
|
|
47d74aa24a | ||
|
|
48aa1ad57d | ||
|
|
2eccb28dee | ||
|
|
9c3bfd920f | ||
|
|
76eb1e9e7f | ||
|
|
b7af597668 | ||
|
|
d635559a30 | ||
|
|
58dd90b7b7 | ||
|
|
ead990a734 | ||
|
|
27400fcd5b | ||
|
|
d4631e14b2 | ||
|
|
8df2cc103e | ||
|
|
8e0e9c7d3a | ||
|
|
913930b561 | ||
|
|
994c8db1f3 | ||
|
|
0c6cbb66b1 | ||
|
|
f09393d4f4 | ||
|
|
f6d963d45a | ||
|
|
39e3733be4 | ||
|
|
09659cc304 | ||
|
|
6811bdec40 | ||
|
|
6577d60733 | ||
|
|
c7db837214 | ||
|
|
03cb7233dc | ||
|
|
6682abf89d | ||
|
|
78fbf0f7ba | ||
|
|
89547332ee | ||
|
|
75539bf675 | ||
|
|
eaeb715e56 | ||
|
|
ca55cc99ed | ||
|
|
7cc4a8f5ce | ||
|
|
fa35768fc9 | ||
|
|
4d0ff0dce4 | ||
|
|
8aac6e46d4 | ||
|
|
1feac1a308 | ||
|
|
d3e42e4b3e | ||
|
|
3a1ca32ff1 | ||
|
|
ecf86d1d13 | ||
|
|
adc6170f02 | ||
|
|
02600f40d2 | ||
|
|
16ea0348a9 | ||
|
|
44162811bd | ||
|
|
57acb8db5c | ||
|
|
2bcb7d5639 | ||
|
|
a99e54330a | ||
|
|
e219772b2a | ||
|
|
144a507a2e | ||
|
|
5019c51940 | ||
|
|
da1071526f | ||
|
|
7ad314472d | ||
|
|
4f6168a982 | ||
|
|
218a872968 | ||
|
|
0043c5e1ac | ||
|
|
d0e7046a89 | ||
|
|
52ad16b920 | ||
|
|
5a4c0bff6a | ||
|
|
6205209fbb | ||
|
|
6ebf8a57d1 | ||
|
|
c02dfc4fb1 | ||
|
|
9d62e5fb6f | ||
|
|
6f13d107c4 | ||
|
|
e56b2ceebb | ||
|
|
7de244ed62 | ||
|
|
1e9147b8bb | ||
|
|
2f65fadeaa | ||
|
|
a17091b394 | ||
|
|
ed77c6cb54 | ||
|
|
bc37cc8a91 | ||
|
|
387363283c | ||
|
|
709026bf1a | ||
|
|
f2b2b86786 | ||
|
|
d0fbea76d8 | ||
|
|
8269610a5c | ||
|
|
20c88a46d9 | ||
|
|
661029f7cc | ||
|
|
850d32d60c | ||
|
|
eb881b9729 | ||
|
|
091ba473ff | ||
|
|
fca051c565 | ||
|
|
6463cda204 | ||
|
|
d004df56e3 | ||
|
|
359dd482c4 | ||
|
|
89e98240b4 | ||
|
|
1c1f2ef1ff | ||
|
|
4fa774f866 | ||
|
|
4671999ea0 | ||
|
|
0a73bbe279 | ||
|
|
8d30058a6d | ||
|
|
69151c06e4 | ||
|
|
2e3c02887e | ||
|
|
7603cef308 | ||
|
|
be370c4e19 | ||
|
|
c6dece6bd1 | ||
|
|
93a5b3f457 | ||
|
|
4242176d29 | ||
|
|
1cadbeed88 | ||
|
|
86cc011212 | ||
|
|
c0facfc28f | ||
|
|
ad52a82190 | ||
|
|
60b6ed514f | ||
|
|
ef32822b31 | ||
|
|
bb0cedd2de | ||
|
|
8175c7c085 | ||
|
|
5c2d725721 | ||
|
|
72571628da | ||
|
|
fa6130c907 | ||
|
|
8ccdd54974 | ||
|
|
6c1409b00d | ||
|
|
542a1a11b9 | ||
|
|
63ffa80c5c | ||
|
|
609342be7a | ||
|
|
52394884da | ||
|
|
af08177f79 | ||
|
|
45fdfc2d3d | ||
|
|
d18554e0e8 | ||
|
|
3c3f9ca85b | ||
|
|
005a02efeb | ||
|
|
6206ebc994 | ||
|
|
dd9f5adc2e | ||
|
|
748d805a32 | ||
|
|
4b59bf01b3 | ||
|
|
b4faa4851a | ||
|
|
f37fcc147c | ||
|
|
dc5694e544 | ||
|
|
e588f6f8c3 | ||
|
|
d227f2ad7c | ||
|
|
97c228031a | ||
|
|
ad85011d62 | ||
|
|
a70379625d | ||
|
|
7350333129 | ||
|
|
216420fdc5 | ||
|
|
c559fbbe8c | ||
|
|
71d68f975c | ||
|
|
390534497e | ||
|
|
3f0ec89f11 | ||
|
|
d3aa4f2bc7 | ||
|
|
f58f0ddb67 | ||
|
|
633e3129d4 | ||
|
|
877bdce4c8 | ||
|
|
6e1fbd2d97 | ||
|
|
36bfe62a8f | ||
|
|
b08bd0f9ab | ||
|
|
3998b47d84 | ||
|
|
d965fdb11d | ||
|
|
ddb64b3ec1 | ||
|
|
5055ec8617 | ||
|
|
8a858501f2 | ||
|
|
e1af25c8a6 | ||
|
|
6091f818da | ||
|
|
a45f9b4802 | ||
|
|
9ccf63b44a | ||
|
|
d34135ae43 | ||
|
|
a81f6f9ad1 | ||
|
|
8a80b10cc2 | ||
|
|
22b1ee132a | ||
|
|
ab7f681f15 | ||
|
|
2ac806ef08 | ||
|
|
13ec8ed03c | ||
|
|
fb77817c2d | ||
|
|
ceb8a492b1 | ||
|
|
cfc868bf4d | ||
|
|
7b4e2257d8 | ||
|
|
4ac6e5477d | ||
|
|
614ea14a7f | ||
|
|
ce45f99006 | ||
|
|
9203813a61 | ||
|
|
ba987b0574 | ||
|
|
b20f34adb7 | ||
|
|
63d0d810b1 | ||
|
|
5491400684 | ||
|
|
6a5165e9b3 | ||
|
|
9a7c4442d2 | ||
|
|
0e5363b5c3 | ||
|
|
d41bce36be | ||
|
|
1380cd811e | ||
|
|
d99bb3a87c | ||
|
|
4b9501318d | ||
|
|
e5eec04f92 | ||
|
|
f9c21efc30 | ||
|
|
ae72b71895 | ||
|
|
87e3fe725d | ||
|
|
807d9e3eef | ||
|
|
9e569b3791 | ||
|
|
024f093585 | ||
|
|
996e9e9102 | ||
|
|
d58bfb46cf | ||
|
|
eb0d7df50b | ||
|
|
547bee38c0 | ||
|
|
60614ba250 | ||
|
|
278f68ae77 | ||
|
|
b4375d6f64 | ||
|
|
9f47c72d31 | ||
|
|
de3bf03f42 | ||
|
|
59a39ac57d | ||
|
|
df9c2b193e | ||
|
|
3894311d68 | ||
|
|
35501dd4fc | ||
|
|
e2ca713658 | ||
|
|
a45de6d427 | ||
|
|
a350638526 | ||
|
|
59f9605ed9 | ||
|
|
9521bf8d4f | ||
|
|
7c1c94d39b | ||
|
|
8a74963815 | ||
|
|
3ebd8b7f45 | ||
|
|
ae8cb2e6a8 | ||
|
|
1ccb978612 | ||
|
|
7040a01cf2 | ||
|
|
6bc0e815e9 | ||
|
|
593f7e826c | ||
|
|
835fa0af13 | ||
|
|
0e3bd0c6c1 | ||
|
|
86668eb7b9 | ||
|
|
771f65c858 | ||
|
|
89d6326a83 | ||
|
|
8b81ea162f | ||
|
|
a53e6db537 | ||
|
|
62e3feeb94 | ||
|
|
a950494503 | ||
|
|
3cb310122e | ||
|
|
feace988b4 | ||
|
|
6a56f20928 | ||
|
|
80a46d14be | ||
|
|
fbcbf066cd | ||
|
|
4d30e1115f | ||
|
|
897cfb491c | ||
|
|
c2c7512431 | ||
|
|
568cf4d182 | ||
|
|
f54330f1c5 | ||
|
|
97e01d7a42 | ||
|
|
4be3e000e1 | ||
|
|
b47baa9ee1 | ||
|
|
f6c98112df | ||
|
|
94d29ab22e | ||
|
|
b0b179550a | ||
|
|
41c7ab4f9c | ||
|
|
432c7c63fe | ||
|
|
2bba1ae292 | ||
|
|
7830d518e0 | ||
|
|
571b3c4da8 | ||
|
|
5b6f8d4c3f | ||
|
|
ae57b21b98 | ||
|
|
292c3bbff8 | ||
|
|
065570ebf5 | ||
|
|
1f5dfd71d5 | ||
|
|
31b3ac4b98 | ||
|
|
7f4a383d75 | ||
|
|
de943c5f30 | ||
|
|
e34b0af251 | ||
|
|
fa7237fde7 | ||
|
|
ed530cef72 | ||
|
|
0f8b2703d1 | ||
|
|
a2176f566b | ||
|
|
bef056b084 | ||
|
|
c8c86c44f8 | ||
|
|
f917a4a34a | ||
|
|
78fd942faa | ||
|
|
a3274ac9b1 | ||
|
|
2e67d69434 | ||
|
|
c2d6e78b2a | ||
|
|
7233a11ba0 | ||
|
|
3a1360ce11 | ||
|
|
ba761044a6 | ||
|
|
d8636a2c5d | ||
|
|
9889c8f9e0 | ||
|
|
7e2e392ecc | ||
|
|
6912a67eba | ||
|
|
6abc83de83 | ||
|
|
0ca66a1469 | ||
|
|
a88be1af44 | ||
|
|
ae47fda257 | ||
|
|
6eb5411029 | ||
|
|
73d13d61a7 | ||
|
|
fdf213ef72 | ||
|
|
22fe605b1e | ||
|
|
bcc902a889 | ||
|
|
24ff2ec30c | ||
|
|
4e0c67e2a1 | ||
|
|
0cc21db654 | ||
|
|
dd5d1c00e5 | ||
|
|
cad2555c03 | ||
|
|
005d8184aa | ||
|
|
c228eddc57 | ||
|
|
ae37f8d9b6 | ||
|
|
6a8113af1d | ||
|
|
0c8cf12650 | ||
|
|
2e29a51ccf | ||
|
|
162f1d94dc | ||
|
|
a76bce1f32 | ||
|
|
be20e04c7b | ||
|
|
d9df82f31d | ||
|
|
6210333628 | ||
|
|
a552a790d3 | ||
|
|
9acb745956 | ||
|
|
875edaf96f | ||
|
|
a9afc0f3f0 | ||
|
|
3bbeaabe26 | ||
|
|
c04cbb480a | ||
|
|
2c241c294e | ||
|
|
ce851f3c28 | ||
|
|
817a6d1828 | ||
|
|
4d0735e7f6 | ||
|
|
80291930f0 | ||
|
|
cf8678b979 | ||
|
|
67722c0fb8 | ||
|
|
0b6e246c04 | ||
|
|
3992295678 | ||
|
|
da404b9acc | ||
|
|
da8db153be | ||
|
|
2c90f7324b | ||
|
|
2cdb0de1c3 | ||
|
|
66bd798e80 | ||
|
|
cf37dfb257 | ||
|
|
217f84204e | ||
|
|
fbbe0ec3db | ||
|
|
1ec34767f9 | ||
|
|
14e94a5376 | ||
|
|
08508afdb2 | ||
|
|
4220f25e01 | ||
|
|
4ff5afecc8 | ||
|
|
2eabb439d9 | ||
|
|
2bc9d5d490 | ||
|
|
9e1c142f02 | ||
|
|
1a38893b52 | ||
|
|
f28d75cf7c | ||
|
|
a3c9d0ace5 | ||
|
|
aea1799a64 | ||
|
|
ef76c4c62b | ||
|
|
210e7c5579 | ||
|
|
3fa0046542 | ||
|
|
d6754685cc | ||
|
|
bb5721700b | ||
|
|
5c4a1dcbd5 | ||
|
|
4f488dee61 | ||
|
|
0d33758104 | ||
|
|
15b5fcbaf9 | ||
|
|
0718b0d5b0 | ||
|
|
0af2ba1b7d | ||
|
|
ea2fdecb83 | ||
|
|
07eb250083 | ||
|
|
ee04717e1b | ||
|
|
d7d22c36ed | ||
|
|
36bf91f920 | ||
|
|
98e9c3b800 | ||
|
|
a7f1137db8 | ||
|
|
f86159e717 | ||
|
|
6e93223ea3 | ||
|
|
a6d677043f | ||
|
|
eb1bf198ac | ||
|
|
0a2f82a19d | ||
|
|
27d9fba785 | ||
|
|
e6a783aff8 | ||
|
|
a767c353d2 | ||
|
|
a39d3d7233 | ||
|
|
40c7ee6355 | ||
|
|
eb760aa33f | ||
|
|
262c34abac | ||
|
|
8019b1b823 | ||
|
|
7a56e83fa3 | ||
|
|
a1c38d9cb2 | ||
|
|
734cf5819a | ||
|
|
35e0b6143a | ||
|
|
e019ae4aed | ||
|
|
c700046b76 | ||
|
|
326a6b729f | ||
|
|
e2ef0c5b94 | ||
|
|
c49f68ef3e | ||
|
|
d0f66f8624 | ||
|
|
4dfa720f2d | ||
|
|
f3b8bac477 | ||
|
|
ce6abad97f | ||
|
|
807e908f78 | ||
|
|
94c75b5262 | ||
|
|
eb0dd6b6e9 | ||
|
|
1c542c3e0d | ||
|
|
d46fcb33c5 | ||
|
|
d5e0da0eb6 | ||
|
|
e744e4cd98 | ||
|
|
9a96e8c704 | ||
|
|
31a94f468e | ||
|
|
7422b9b53b | ||
|
|
161a9d6ad2 | ||
|
|
8fe81c9d09 | ||
|
|
9f3acf8e28 | ||
|
|
31c9c82f6c | ||
|
|
ec3d8a034f | ||
|
|
c452294bcc | ||
|
|
d5757499bc | ||
|
|
139c8c2e78 | ||
|
|
215e33fa6c | ||
|
|
3d12b84f1d | ||
|
|
d8adc88c52 | ||
|
|
5119e49e47 | ||
|
|
cfb9f87418 |
@@ -6,23 +6,117 @@ jobs:
|
|||||||
- image: circleci/node:6.12
|
- image: circleci/node:6.12
|
||||||
environment:
|
environment:
|
||||||
CONTRACTS_COMMIT_HASH: '9ed05f5'
|
CONTRACTS_COMMIT_HASH: '9ed05f5'
|
||||||
|
working_directory: ~/repo
|
||||||
steps:
|
steps:
|
||||||
- checkout
|
- checkout
|
||||||
- run: echo 'export PATH=$HOME/CIRCLE_PROJECT_REPONAME/node_modules/.bin:$PATH' >> $BASH_ENV
|
- run: echo 'export PATH=$HOME/CIRCLE_PROJECT_REPONAME/node_modules/.bin:$PATH' >> $BASH_ENV
|
||||||
|
- restore_cache:
|
||||||
|
key: dependency-cache-{{ checksum "package.json" }}
|
||||||
- run:
|
- run:
|
||||||
name: yarn
|
name: yarn
|
||||||
command: yarn
|
command: yarn --frozen-lockfile
|
||||||
- save_cache:
|
- save_cache:
|
||||||
key: dependency-cache-{{ checksum "package.json" }}
|
key: dependency-cache-{{ checksum "package.json" }}
|
||||||
paths:
|
paths:
|
||||||
- ~/.cache/yarn
|
- ./node_modules
|
||||||
- run: wget https://s3.amazonaws.com/testrpc-shapshots/${CONTRACTS_COMMIT_HASH}.zip
|
- run: wget https://s3.amazonaws.com/testrpc-shapshots/${CONTRACTS_COMMIT_HASH}.zip
|
||||||
- run: unzip ${CONTRACTS_COMMIT_HASH}.zip -d testrpc_snapshot
|
- run: unzip ${CONTRACTS_COMMIT_HASH}.zip -d testrpc_snapshot
|
||||||
- run: node ./node_modules/lerna/bin/lerna.js bootstrap
|
- run: node ./node_modules/lerna/bin/lerna.js bootstrap
|
||||||
- run: yarn lerna:run build
|
- run: yarn lerna:run build
|
||||||
|
- save_cache:
|
||||||
|
key: repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||||
|
paths:
|
||||||
|
- ~/repo
|
||||||
|
test-0xjs:
|
||||||
|
docker:
|
||||||
|
- image: circleci/node:6.12
|
||||||
|
working_directory: ~/repo
|
||||||
|
steps:
|
||||||
|
- restore_cache:
|
||||||
|
keys:
|
||||||
|
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||||
- run:
|
- run:
|
||||||
name: testrpc
|
name: testrpc
|
||||||
command: npm run testrpc -- --db testrpc_snapshot
|
command: npm run testrpc -- --db testrpc_snapshot
|
||||||
background: true
|
background: true
|
||||||
- run: yarn lerna:run test:circleci
|
- run: yarn lerna:run --scope 0x.js test:circleci
|
||||||
|
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 lerna:run --scope contracts test:circleci
|
||||||
|
test-deployer:
|
||||||
|
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 lerna:run --scope @0xproject/deployer test:circleci
|
||||||
|
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 lerna:run --ignore contracts --ignore 0x.js --ignore @0xproject/deployer test:circleci
|
||||||
|
lint:
|
||||||
|
working_directory: ~/repo
|
||||||
|
docker:
|
||||||
|
- image: circleci/node:6.12
|
||||||
|
steps:
|
||||||
|
- restore_cache:
|
||||||
|
keys:
|
||||||
|
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||||
- run: yarn lerna:run lint
|
- run: yarn lerna:run lint
|
||||||
|
prettier:
|
||||||
|
working_directory: ~/repo
|
||||||
|
docker:
|
||||||
|
- image: circleci/node:6.12
|
||||||
|
steps:
|
||||||
|
- restore_cache:
|
||||||
|
keys:
|
||||||
|
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||||
|
- run: yarn prettier:ci
|
||||||
|
workflows:
|
||||||
|
version: 2
|
||||||
|
main:
|
||||||
|
jobs:
|
||||||
|
- build
|
||||||
|
- test-0xjs:
|
||||||
|
requires:
|
||||||
|
- build
|
||||||
|
- test-contracts:
|
||||||
|
requires:
|
||||||
|
- build
|
||||||
|
- test-deployer:
|
||||||
|
requires:
|
||||||
|
- build
|
||||||
|
- test-rest:
|
||||||
|
requires:
|
||||||
|
- build
|
||||||
|
- prettier:
|
||||||
|
requires:
|
||||||
|
- build
|
||||||
|
- lint:
|
||||||
|
requires:
|
||||||
|
- build
|
||||||
|
|||||||
12
.editorconfig
Normal file
12
.editorconfig
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# EditorConfig http://EditorConfig.org
|
||||||
|
|
||||||
|
# top-most EditorConfig file
|
||||||
|
root = true
|
||||||
|
|
||||||
|
# All files
|
||||||
|
[*]
|
||||||
|
end_of_line = lf
|
||||||
|
insert_final_newline = true
|
||||||
|
charset = utf-8
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
*.sol linguist-language=Solidity
|
||||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -68,6 +68,10 @@ generated_docs/
|
|||||||
TODO.md
|
TODO.md
|
||||||
|
|
||||||
packages/website/public/bundle*
|
packages/website/public/bundle*
|
||||||
|
packages/react-docs/example/public/bundle*
|
||||||
|
|
||||||
# generated binaries
|
# generated binaries
|
||||||
bin/
|
bin/
|
||||||
|
|
||||||
|
# generated contract artifacts
|
||||||
|
packages/contracts/src/artifacts
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
.*
|
|
||||||
tsconfig.json
|
|
||||||
tslint.json
|
|
||||||
webpack.config.js
|
|
||||||
yarn.lock
|
|
||||||
docs
|
|
||||||
5
.prettierignore
Normal file
5
.prettierignore
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
lib
|
||||||
|
.nyc_output
|
||||||
|
/packages/contracts/src/artifacts
|
||||||
|
package.json
|
||||||
|
scripts/postpublish_utils.js
|
||||||
6
.prettierrc
Normal file
6
.prettierrc
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"tabWidth": 4,
|
||||||
|
"printWidth": 120,
|
||||||
|
"trailingComma": all,
|
||||||
|
"singleQuote": true
|
||||||
|
}
|
||||||
1
CODEOWNERS
Normal file
1
CODEOWNERS
Normal file
@@ -0,0 +1 @@
|
|||||||
|
* @abandeali1 @BMillman19 @dekz @fabioberger @LogvinovLeon @Recmo
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
0x Contribution Guide
|
## 0x Contribution Guide
|
||||||
---------------------
|
|
||||||
|
|
||||||
Thank you for your interest in contributing to 0x protocol! We welcome contributions from anyone on the internet, and are grateful for even the smallest of fixes!
|
Thank you for your interest in contributing to 0x protocol! We welcome contributions from anyone on the internet, and are grateful for even the smallest of fixes!
|
||||||
|
|
||||||
@@ -9,9 +8,9 @@ If you'd like to contribute to 0x protocol, please fork the repo, fix, commit an
|
|||||||
|
|
||||||
We encourage a “PR early” approach so create the PR as early as possible even without the fix/feature ready, so that devs and other contributors know you have picked up the issue. These early PRs should indicate an 'in progress' status by adding the '[WIP]' prefix to the PR title. Please make sure your contributions adhere to our coding guidelines:
|
We encourage a “PR early” approach so create the PR as early as possible even without the fix/feature ready, so that devs and other contributors know you have picked up the issue. These early PRs should indicate an 'in progress' status by adding the '[WIP]' prefix to the PR title. Please make sure your contributions adhere to our coding guidelines:
|
||||||
|
|
||||||
* Pull requests adding features or refactoring should be opened against the `development` branch
|
* Pull requests adding features or refactoring should be opened against the `development` branch
|
||||||
* Pull requests fixing bugs in the latest release version should be opened again the `master` branch
|
* Pull requests fixing bugs in the latest release version should be opened again the `master` branch
|
||||||
* Write [good commit messages](https://chris.beams.io/posts/git-commit/)
|
* Write [good commit messages](https://chris.beams.io/posts/git-commit/)
|
||||||
|
|
||||||
### Code quality
|
### Code quality
|
||||||
|
|
||||||
@@ -24,7 +23,7 @@ If the sub-package you are modifying has a `CHANGELOG.md` file, make sure to add
|
|||||||
|
|
||||||
### Styleguide
|
### Styleguide
|
||||||
|
|
||||||
We use [TSLint](https://palantir.github.io/tslint/) with [custom configs](https://github.com/0xProject/0x.js/tree/development/packages/tslint-config) to keep our code style consistent.
|
We use [TSLint](https://palantir.github.io/tslint/) with [custom configs](https://github.com/0xProject/0x-monorepo/tree/development/packages/tslint-config) to keep our code style consistent.
|
||||||
|
|
||||||
To lint your code just run: `yarn lint`
|
To lint your code just run: `yarn lint`
|
||||||
|
|
||||||
@@ -32,10 +31,10 @@ We also use [Prettier](https://prettier.io/) to auto-format our code. Be sure to
|
|||||||
|
|
||||||
If using the Atom text editor, we recommend you install the following packages:
|
If using the Atom text editor, we recommend you install the following packages:
|
||||||
|
|
||||||
* [atom-typescript](https://atom.io/packages/atom-typescript)
|
* [atom-typescript](https://atom.io/packages/atom-typescript)
|
||||||
* [linter-tslint](https://atom.io/packages/linter-tslint)
|
* [linter-tslint](https://atom.io/packages/linter-tslint)
|
||||||
* [prettier-atom](https://atom.io/packages/prettier-atom)
|
* [prettier-atom](https://atom.io/packages/prettier-atom)
|
||||||
* [language-ethereum](https://atom.io/packages/language-ethereum)
|
* [language-ethereum](https://atom.io/packages/language-ethereum)
|
||||||
|
|
||||||
Our CI will also run TSLint and Prettier as a part of the test run when you submit your PR. Make sure that the CI tests pass for your contribution.
|
Our CI will also run TSLint and Prettier as a part of the test run when you submit your PR. Make sure that the CI tests pass for your contribution.
|
||||||
|
|
||||||
|
|||||||
62
ISSUE_TEMPLATE.md
Normal file
62
ISSUE_TEMPLATE.md
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
<!--- Thank you for taking the time to file an Issue -->
|
||||||
|
|
||||||
|
<!--- Before submitting please check to see if this issue was already reported -->
|
||||||
|
|
||||||
|
<!--- Provide a general summary of the issue in the Title above -->
|
||||||
|
|
||||||
|
## Expected Behavior
|
||||||
|
|
||||||
|
<!--- If you're describing a bug, tell us what should happen -->
|
||||||
|
|
||||||
|
<!--- If you're suggesting a package change/improvement, tell us how it should work -->
|
||||||
|
|
||||||
|
<!--- If you're suggesting a contract or protocol change/improvement, visit our ZEIPs repo -->
|
||||||
|
|
||||||
|
## Current Behavior
|
||||||
|
|
||||||
|
<!--- If describing a bug, tell us what happens instead of the expected behavior -->
|
||||||
|
|
||||||
|
<!--- If suggesting a change/improvement, explain the difference from current behavior -->
|
||||||
|
|
||||||
|
## Possible Solution
|
||||||
|
|
||||||
|
<!--- Not obligatory, but suggest a fix/reason for the bug, -->
|
||||||
|
|
||||||
|
<!--- or ideas how to implement the addition or change -->
|
||||||
|
|
||||||
|
## Steps to Reproduce (for bugs)
|
||||||
|
|
||||||
|
<!--- Provide a link to a live example, or an unambiguous set of steps to -->
|
||||||
|
|
||||||
|
<!--- reproduce this bug. Include code to reproduce, if relevant -->
|
||||||
|
|
||||||
|
```
|
||||||
|
1.
|
||||||
|
2.
|
||||||
|
3.
|
||||||
|
```
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
<!--- How has this issue affected you? What are you trying to accomplish? -->
|
||||||
|
|
||||||
|
<!--- Providing context helps us come up with a solution that is most useful in the real world -->
|
||||||
|
|
||||||
|
## Your Environment
|
||||||
|
|
||||||
|
<!--- Include as many relevant details about the environment you experienced the bug in -->
|
||||||
|
|
||||||
|
| Package | Version |
|
||||||
|
| ------------------: | :------ |
|
||||||
|
| `0x.js` | 0.25.0 |
|
||||||
|
| `Exchange Contract` | v1 |
|
||||||
|
|
||||||
|
| Network |
|
||||||
|
| ------- |
|
||||||
|
| NAME |
|
||||||
|
|
||||||
|
<!-- For example:
|
||||||
|
| mainnet |
|
||||||
|
| kovan |
|
||||||
|
| testrpc |
|
||||||
|
-->
|
||||||
@@ -1,2 +1,42 @@
|
|||||||
This PR:
|
<!--- Thank you for taking the time to submit a Pull Request -->
|
||||||
*
|
|
||||||
|
<!--- Provide a general summary of the issue in the Title above -->
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!--- Describe your changes in detail -->
|
||||||
|
|
||||||
|
## Motivation and Context
|
||||||
|
|
||||||
|
<!--- Why is this change required? What problem does it solve? -->
|
||||||
|
|
||||||
|
<!--- If it fixes an open issue, please link to the issue here. -->
|
||||||
|
|
||||||
|
## How Has This Been Tested?
|
||||||
|
|
||||||
|
<!--- Please describe in detail how you tested your changes. -->
|
||||||
|
|
||||||
|
<!--- Include details of your testing environment, and the tests you ran to -->
|
||||||
|
|
||||||
|
<!--- see how your change affects other areas of the code, etc. -->
|
||||||
|
|
||||||
|
## Types of changes
|
||||||
|
|
||||||
|
<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->
|
||||||
|
|
||||||
|
* [ ] Bug fix (non-breaking change which fixes an issue)
|
||||||
|
* [ ] New feature (non-breaking change which adds functionality)
|
||||||
|
* [ ] Breaking change (fix or feature that would cause existing functionality to change)
|
||||||
|
|
||||||
|
## Checklist:
|
||||||
|
|
||||||
|
<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
|
||||||
|
|
||||||
|
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->
|
||||||
|
|
||||||
|
* [ ] Change requires a change to the documentation.
|
||||||
|
* [ ] Added tests to cover my changes.
|
||||||
|
* [ ] Added new entries to the relevant CHANGELOGs.
|
||||||
|
* [ ] Updated the new versions of the changed packages in the relevant CHANGELOGs.
|
||||||
|
* [ ] Labeled this PR with the 'WIP' label if it is a work in progress.
|
||||||
|
* [ ] Labeled this PR with the labels corresponding to the changed package.
|
||||||
|
|||||||
75
README.md
75
README.md
@@ -4,50 +4,57 @@
|
|||||||
|
|
||||||
[0x][website-url] is an open protocol that facilitates trustless, low friction exchange of Ethereum-based assets. A full description of the protocol may be found in our [whitepaper][whitepaper-url].
|
[0x][website-url] is an open protocol that facilitates trustless, low friction exchange of Ethereum-based assets. A full description of the protocol may be found in our [whitepaper][whitepaper-url].
|
||||||
|
|
||||||
This repository contains all the 0x developer tools written in TypeScript. Our hope is that these tools make it easy to build Relayers and other DApps that use the 0x protocol.
|
This repository is a monorepo including the 0x protocol smart contracts and numerous developer tools. Each public sub-package is independently published to NPM.
|
||||||
|
|
||||||
[website-url]: https://0xproject.com/
|
[website-url]: https://0xproject.com/
|
||||||
[whitepaper-url]: https://0xproject.com/pdfs/0x_white_paper.pdf
|
[whitepaper-url]: https://0xproject.com/pdfs/0x_white_paper.pdf
|
||||||
|
|
||||||
[](https://circleci.com/gh/0xProject/0x.js)
|
[](https://circleci.com/gh/0xProject/0x-monorepo)
|
||||||
[](https://coveralls.io/github/0xProject/0x.js?branch=master)
|
[](https://coveralls.io/github/0xProject/0x-monorepo?branch=master)
|
||||||
[](https://chat.0xproject.com)
|
||||||
)](https://chat.0xproject.com)
|
|
||||||
[](https://gitter.im/0xProject/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
[](https://gitter.im/0xProject/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||||
[](https://opensource.org/licenses/Apache-2.0)
|
[](https://opensource.org/licenses/Apache-2.0)
|
||||||
[](https://greenkeeper.io/)
|
[](https://greenkeeper.io/)
|
||||||
|
|
||||||
### Published Packages
|
### Published Packages
|
||||||
|
|
||||||
| Package | Version | Description |
|
| Package | Version | Description |
|
||||||
|---------|---------|-------------|
|
| -------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------- |
|
||||||
| [`0x.js`](/packages/0x.js) | [](https://www.npmjs.com/package/0x.js) | A Javascript library for interacting with the 0x protocol |
|
| [`0x.js`](/packages/0x.js) | [](https://www.npmjs.com/package/0x.js) | A Javascript library for interacting with the 0x protocol |
|
||||||
| [`@0xproject/abi-gen`](/packages/abi-gen) | [](https://www.npmjs.com/package/@0xproject/abi-gen) | Tool to generate TS wrappers from smart contract ABIs |
|
| [`@0xproject/abi-gen`](/packages/abi-gen) | [](https://www.npmjs.com/package/@0xproject/abi-gen) | Tool to generate TS wrappers from smart contract ABIs |
|
||||||
| [`@0xproject/assert`](/packages/assert) | [](https://www.npmjs.com/package/@0xproject/assert) | Type and schema assertions used by our packages |
|
| [`@0xproject/assert`](/packages/assert) | [](https://www.npmjs.com/package/@0xproject/assert) | Type and schema assertions used by our packages |
|
||||||
| [`@0xproject/connect`](/packages/connect) | [](https://www.npmjs.com/package/@0xproject/connect) | A Javascript library for interacting with the standard relayer api |
|
| [`@0xproject/base-contract`](/packages/base-contract) | [](https://www.npmjs.com/package/@0xproject/base-contract) | BaseContract to derive all auto-generated wrappers from |
|
||||||
| [`@0xproject/json-schemas`](/packages/json-schemas) | [](https://www.npmjs.com/package/@0xproject/json-schemas) | 0x-related json schemas |
|
| [`chai-as-promised-typescript-typings`](/packages/chai-as-promised-typescript-typings) | [](https://www.npmjs.com/package/chai-as-promised-typescript-typings) | Chai as promised typescript typings |
|
||||||
| [`@0xproject/subproviders`](/packages/subproviders) | [](https://www.npmjs.com/package/@0xproject/subproviders) | Useful web3 subproviders (e.g LedgerSubprovider) |
|
| [`chai-typescript-typings`](/packages/chai-typescript-typings) | [](https://www.npmjs.com/package/chai-typescript-typings) | Chai typescript typings |
|
||||||
| [`@0xproject/tslint-config`](/packages/tslint-config) | [](https://www.npmjs.com/package/@0xproject/tslint-config) | Custom 0x development TSLint rules |
|
| [`@0xproject/connect`](/packages/connect) | [](https://www.npmjs.com/package/@0xproject/connect) | A Javascript library for interacting with the standard relayer api |
|
||||||
| [`@0xproject/types`](/packages/types) | [](https://www.npmjs.com/package/@0xproject/types) | Shared type declarations |
|
| [`@0xproject/deployer`](/packages/deployer) | [](https://www.npmjs.com/package/@0xproject/deployer) | Smart contract deployer |
|
||||||
| [`@0xproject/utils`](/packages/utils) | [](https://www.npmjs.com/package/@0xproject/utils) | Shared utilities |
|
| [`@0xproject/dev-utils`](/packages/dev-utils) | [](https://www.npmjs.com/package/@0xproject/dev-utils) | Dev utils to be shared across 0x projects and packages |
|
||||||
| [`@0xproject/web3-wrapper`](/packages/web3-wrapper) | [](https://www.npmjs.com/package/@0xproject/web3-wrapper) | Web3 wrapper |
|
| [`ethers-typescript-typings`](/packages/ethers-typescript-typings) | [](https://www.npmjs.com/package/ethers-typescript-typings) | [Ethers.js](https://github.com/ethers-io/ethers.js/) typescript typings |
|
||||||
|
| [`@0xproject/json-schemas`](/packages/json-schemas) | [](https://www.npmjs.com/package/@0xproject/json-schemas) | 0x-related json schemas |
|
||||||
|
| [`@0xproject/subproviders`](/packages/subproviders) | [](https://www.npmjs.com/package/@0xproject/subproviders) | Useful web3 subproviders (e.g LedgerSubprovider) |
|
||||||
|
| [`@0xproject/tslint-config`](/packages/tslint-config) | [](https://www.npmjs.com/package/@0xproject/tslint-config) | Custom 0x development TSLint rules |
|
||||||
|
| [`@0xproject/types`](/packages/types) | [](https://www.npmjs.com/package/@0xproject/types) | Shared type declarations |
|
||||||
|
| [`@0xproject/utils`](/packages/utils) | [](https://www.npmjs.com/package/@0xproject/utils) | Shared utilities |
|
||||||
|
| [`web3-typescript-typings`](/packages/web3-typescript-typings) | [](https://www.npmjs.com/package/web3-typescript-typings) | Web3 typescript typings |
|
||||||
|
| [`@0xproject/web3-wrapper`](/packages/web3-wrapper) | [](https://www.npmjs.com/package/@0xproject/web3-wrapper) | Web3 wrapper |
|
||||||
|
|
||||||
### Private Packages
|
### Private Packages
|
||||||
|
|
||||||
| Package | Description |
|
| Package | Description |
|
||||||
|---------|-------------|
|
| ----------------------------------------------------------- | ---------------------------------------------------------------- |
|
||||||
| [`@0xproject/contracts`](/packages/contracts) | 0x solidity smart contracts & tests |
|
| [`@0xproject/contracts`](/packages/contracts) | 0x solidity smart contracts & tests |
|
||||||
| [`@0xproject/kovan_faucets`](/packages/kovan-faucets) | A faucet micro-service that dispenses test ERC20 tokens or Ether |
|
| [`@0xproject/monorepo-scripts`](/packages/monorepo-scripts) | Shared monorepo scripts |
|
||||||
| [`@0xproject/monorepo-scripts`](/packages/monorepo-scripts) | Shared monorepo scripts |
|
| [`@0xproject/testnet-faucets`](/packages/testnet-faucets) | A faucet micro-service that dispenses test ERC20 tokens or Ether |
|
||||||
| [`@0xproject/website`](/packages/website) | 0x website & Portal DApp |
|
| [`@0xproject/website`](/packages/website) | 0x website & Portal DApp |
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
Dedicated documentation pages:
|
Dedicated documentation pages:
|
||||||
- [0x.js Library](https://0xproject.com/docs/0xjs)
|
|
||||||
- [0x Connect](https://0xproject.com/docs/connect)
|
* [0x.js Library](https://0xproject.com/docs/0xjs)
|
||||||
- [Smart contracts](https://0xproject.com/docs/contracts)
|
* [0x Connect](https://0xproject.com/docs/connect)
|
||||||
- [Standard Relayer API](https://github.com/0xProject/standard-relayer-api/blob/master/README.md)
|
* [Smart contracts](https://0xproject.com/docs/contracts)
|
||||||
|
* [Standard Relayer API](https://github.com/0xProject/standard-relayer-api/blob/master/README.md)
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
@@ -58,11 +65,13 @@ Please read our [contribution guidelines](./CONTRIBUTING.md) before getting star
|
|||||||
### Install dependencies
|
### Install dependencies
|
||||||
|
|
||||||
If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them:
|
If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
yarn config set workspaces-experimental true
|
yarn config set workspaces-experimental true
|
||||||
```
|
```
|
||||||
|
|
||||||
Then install dependencies
|
Then install dependencies
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
yarn install
|
yarn install
|
||||||
```
|
```
|
||||||
@@ -75,9 +84,16 @@ Build all packages
|
|||||||
yarn lerna:run build
|
yarn lerna:run build
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Continuously rebuild on exchange
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yarn dev
|
||||||
|
```
|
||||||
|
|
||||||
### Lint
|
### Lint
|
||||||
|
|
||||||
Lint all packages
|
Lint all packages
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
yarn lerna:run lint
|
yarn lerna:run lint
|
||||||
```
|
```
|
||||||
@@ -87,11 +103,13 @@ yarn lerna:run lint
|
|||||||
Before running the tests, you will need to spin up a [TestRPC](https://www.npmjs.com/package/ethereumjs-testrpc) instance and deploy all the 0x smart contracts.
|
Before running the tests, you will need to spin up a [TestRPC](https://www.npmjs.com/package/ethereumjs-testrpc) instance and deploy all the 0x smart contracts.
|
||||||
|
|
||||||
In a separate terminal, start TestRPC (a convenience command is provided as part of this repo)
|
In a separate terminal, start TestRPC (a convenience command is provided as part of this repo)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
yarn testrpc
|
yarn testrpc
|
||||||
```
|
```
|
||||||
|
|
||||||
Then in your main terminal run
|
Then in your main terminal run
|
||||||
|
|
||||||
```
|
```
|
||||||
cd packages/contracts
|
cd packages/contracts
|
||||||
yarn migrate
|
yarn migrate
|
||||||
@@ -99,6 +117,7 @@ cd ..
|
|||||||
```
|
```
|
||||||
|
|
||||||
And finally from the root project directory run
|
And finally from the root project directory run
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
yarn lerna:run test
|
yarn lerna:run test
|
||||||
```
|
```
|
||||||
|
|||||||
22
lerna.json
22
lerna.json
@@ -1,9 +1,17 @@
|
|||||||
{
|
{
|
||||||
"lerna": "2.5.1",
|
"lerna": "2.5.1",
|
||||||
"packages": [
|
"packages": ["packages/*"],
|
||||||
"packages/*"
|
"commands": {
|
||||||
],
|
"publish": {
|
||||||
"version": "independent",
|
"allowBranch": "development"
|
||||||
"npmClient": "yarn",
|
}
|
||||||
"useWorkspaces": true
|
},
|
||||||
|
"version": "independent",
|
||||||
|
"commands": {
|
||||||
|
"publish": {
|
||||||
|
"ignore": ["test/**/*", "*.md", "scripts", "lib", "tslint.json", "tsconfig.json"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"npmClient": "yarn",
|
||||||
|
"useWorkspaces": true
|
||||||
}
|
}
|
||||||
|
|||||||
17
package.json
17
package.json
@@ -1,23 +1,26 @@
|
|||||||
{
|
{
|
||||||
"private": true,
|
"private": true,
|
||||||
"name": "0x.js",
|
"name": "0x-monorepo",
|
||||||
"workspaces": [
|
"workspaces": ["packages/*"],
|
||||||
"packages/*"
|
|
||||||
],
|
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"dev": "lerna run --parallel build:watch",
|
||||||
"testrpc": "testrpc -p 8545 --networkId 50 -m \"${npm_package_config_mnemonic}\"",
|
"testrpc": "testrpc -p 8545 --networkId 50 -m \"${npm_package_config_mnemonic}\"",
|
||||||
|
"prettier": "prettier --write '**/*.{ts,tsx,json,md}' --config .prettierrc",
|
||||||
|
"prettier:ci": "prettier --list-different '**/*.{ts,tsx,json,md}' --config .prettierrc",
|
||||||
"lerna:run": "lerna run",
|
"lerna:run": "lerna run",
|
||||||
"lerna:rebuild": "lerna run clean; lerna run build;",
|
"lerna:rebuild": "lerna run clean; lerna run build;",
|
||||||
"lerna:publish": "yarn install; lerna run clean; lerna run build; lerna publish --registry=https://registry.npmjs.org/"
|
"lerna:publish":
|
||||||
|
"yarn install; lerna run clean; lerna run build; lerna publish --registry=https://registry.npmjs.org/"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"mnemonic": "concert load couple harbor equip island argue ramp clarify fence smart topic"
|
"mnemonic": "concert load couple harbor equip island argue ramp clarify fence smart topic"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@0xproject/utils": "^0.1.0",
|
"@0xproject/utils": "^0.4.0",
|
||||||
"async-child-process": "^1.1.1",
|
"async-child-process": "^1.1.1",
|
||||||
"ethereumjs-testrpc": "6.0.3",
|
"ethereumjs-testrpc": "^6.0.3",
|
||||||
"lerna": "^2.5.1",
|
"lerna": "^2.5.1",
|
||||||
|
"prettier": "^1.11.1",
|
||||||
"publish-release": "0xproject/publish-release",
|
"publish-release": "0xproject/publish-release",
|
||||||
"semver-sort": "^0.0.4"
|
"semver-sort": "^0.0.4"
|
||||||
}
|
}
|
||||||
|
|||||||
10
packages/0x.js/.npmignore
Normal file
10
packages/0x.js/.npmignore
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
.*
|
||||||
|
tsconfig.json
|
||||||
|
webpack.config.js
|
||||||
|
yarn-error.log
|
||||||
|
test/
|
||||||
|
/src/
|
||||||
|
/_bundles/
|
||||||
|
/contract_templates/
|
||||||
|
/generated_docs/
|
||||||
|
/scripts/
|
||||||
@@ -1,12 +1,69 @@
|
|||||||
# CHANGELOG
|
# CHANGELOG
|
||||||
|
|
||||||
v0.29.0 - _December 28, 2017_
|
## v0.33.1 - _March 8, 2018_
|
||||||
------------------------
|
|
||||||
|
* Add missing EthersJs typescript typings as dependency
|
||||||
|
|
||||||
|
## v0.33.0 - _March 4, 2018_
|
||||||
|
|
||||||
|
* Validate and lowercase all addresses in public methods (#373)
|
||||||
|
* Improve validation to force passing contract addresses on private networks (#385)
|
||||||
|
* Change `LogErrorContractEventArgs.errorId` type from `BigNumber` to `number` (#413)
|
||||||
|
* Rename all public `_unsubscribeAll` methods to `unsubscribeAll` (#415)
|
||||||
|
* Move web3 typings from devDep to dep since cannot use this package without it (#429)
|
||||||
|
|
||||||
|
## v0.32.2 - _February 9, 2018_
|
||||||
|
|
||||||
|
* Fix publishing issue where .npmignore was not properly excluding undesired content (#389)
|
||||||
|
|
||||||
|
## v0.32.1 - _February 7, 2018_
|
||||||
|
|
||||||
|
* Reorganized `BlockParamLiteral` export into `@0xproject/types` package (#355)
|
||||||
|
* Now using `abi-gen` package to generate ContractEventArgs types (#371)
|
||||||
|
|
||||||
|
## v0.32.0 - _February 5, 2018_
|
||||||
|
|
||||||
|
* Add `zeroEx.etherToken.getContractAddressIfExists` (#350)
|
||||||
|
* Fixed the bug causing order watcher to throw if there is an event with the same signature but different indexed fields (#366)
|
||||||
|
|
||||||
|
## v0.31.1 - _February 1, 2018_
|
||||||
|
|
||||||
|
* Fix the bug causing order watcher to throw if makerToken === zrx (#357)
|
||||||
|
|
||||||
|
## v0.31.0 - _January 30, 2018_
|
||||||
|
|
||||||
|
* Add the `shouldAddPersonalMessagePrefix` parameter to `signOrderHashAsync` so that the
|
||||||
|
caller can decide on whether to add the personalMessage prefix before relaying the request
|
||||||
|
to the signer. Parity Signer, Ledger and TestRPC add the prefix themselves, Metamask expects
|
||||||
|
it to have already been added. (#349)
|
||||||
|
|
||||||
|
## v0.30.2 - _January 29, 2018_
|
||||||
|
|
||||||
|
* Add Rinkeby testnet addresses to artifacts (#337)
|
||||||
|
* Move @0xproject/types to dependencies from devDependencies fixing missing type errors
|
||||||
|
|
||||||
|
## v0.30.1 - _January 24, 2018_
|
||||||
|
|
||||||
|
* Fix a bug allowing negative fill values (#212)
|
||||||
|
* Fix a bug that made it impossible to pass a custom ZRX address (#341)
|
||||||
|
|
||||||
|
## v0.30.0 - _January 17, 2018_
|
||||||
|
|
||||||
|
* Add an error parameter to the order watcher callback (#312)
|
||||||
|
* Fix a bug making it impossible to catch some errors from awaitTransactionMinedAsync (#312)
|
||||||
|
* Fix a bug in fillOrdersUpTo validation making it impossible to fill up to if user doesn't have enough balance to fully fill all the orders (#321)
|
||||||
|
|
||||||
|
## v0.29.1 - _January 11, 2018_
|
||||||
|
|
||||||
|
* Fixed bignumber config issue #301 (#305)
|
||||||
|
|
||||||
|
## v0.29.0 - _December 28, 2017_
|
||||||
|
|
||||||
* Assert baseUnit amount supplied to `toUnitAmount` is integer amount. (#287)
|
* Assert baseUnit amount supplied to `toUnitAmount` is integer amount. (#287)
|
||||||
* `toBaseUnitAmount` throws if amount supplied has too many decimals (#287)
|
* `toBaseUnitAmount` throws if amount supplied has too many decimals (#287)
|
||||||
|
|
||||||
v0.28.0 - _December 20, 2017_
|
## v0.28.0 - _December 20, 2017_
|
||||||
------------------------
|
|
||||||
* Add `etherTokenAddress` arg to `depositAsync` and `withdrawAsync` methods on `zeroEx.etherToken` (#267)
|
* Add `etherTokenAddress` arg to `depositAsync` and `withdrawAsync` methods on `zeroEx.etherToken` (#267)
|
||||||
* Removed accidentally included `unsubscribeAll` method from `zeroEx.proxy`, `zeroEx.etherToken` and `zeroEx.tokenRegistry` (#267)
|
* Removed accidentally included `unsubscribeAll` method from `zeroEx.proxy`, `zeroEx.etherToken` and `zeroEx.tokenRegistry` (#267)
|
||||||
* Removed `etherTokenContractAddress` from `ZeroEx` constructor arg `ZeroExConfig` (#267)
|
* Removed `etherTokenContractAddress` from `ZeroEx` constructor arg `ZeroExConfig` (#267)
|
||||||
@@ -17,12 +74,12 @@ v0.28.0 - _December 20, 2017_
|
|||||||
* Support `Deposit` and `Withdraw` events on etherToken (#277)
|
* Support `Deposit` and `Withdraw` events on etherToken (#277)
|
||||||
* Improve the error message when taker is not a string (#278)
|
* Improve the error message when taker is not a string (#278)
|
||||||
|
|
||||||
v0.27.1 - _November 28, 2017_
|
## v0.27.1 - _November 28, 2017_
|
||||||
------------------------
|
|
||||||
* Export `TransactionOpts` type
|
* Export `TransactionOpts` type
|
||||||
|
|
||||||
v0.27.0 - _November 28, 2017_
|
## v0.27.0 - _November 28, 2017_
|
||||||
------------------------
|
|
||||||
* Make `ZeroExConfig` required parameter of `ZeroEx` constructor (#233)
|
* Make `ZeroExConfig` required parameter of `ZeroEx` constructor (#233)
|
||||||
* Add a required property `networkId` to `ZeroExConfig` (#233)
|
* Add a required property `networkId` to `ZeroExConfig` (#233)
|
||||||
* Make all `getContractAddress` functions, `zeroEx.exchange.subscribe`, `zeroEx.exchange.getZRXTokenAddress` sync (#233)
|
* Make all `getContractAddress` functions, `zeroEx.exchange.subscribe`, `zeroEx.exchange.getZRXTokenAddress` sync (#233)
|
||||||
@@ -33,66 +90,66 @@ v0.27.0 - _November 28, 2017_
|
|||||||
* All transaction sending methods now call `estimateGas` if no gas amount was supplied (#235)
|
* All transaction sending methods now call `estimateGas` if no gas amount was supplied (#235)
|
||||||
* Modify order validation methods to validate against the `latest` block, not against the `pending` block (#236)
|
* Modify order validation methods to validate against the `latest` block, not against the `pending` block (#236)
|
||||||
|
|
||||||
v0.26.0 - _November 21, 2017_
|
## v0.26.0 - _November 21, 2017_
|
||||||
------------------------
|
|
||||||
* Add post-formatter for logs converting `blockNumber`, `logIndex`, `transactionIndex` from hexes to numbers (#231)
|
* Add post-formatter for logs converting `blockNumber`, `logIndex`, `transactionIndex` from hexes to numbers (#231)
|
||||||
* Remove support for Async callback types when used in Subscribe functions (#222)
|
* Remove support for Async callback types when used in Subscribe functions (#222)
|
||||||
* In OrderWatcher subscribe to ZRX Token Transfer and Approval events when maker token is different (#225)
|
* In OrderWatcher subscribe to ZRX Token Transfer and Approval events when maker token is different (#225)
|
||||||
|
|
||||||
v0.25.1 - _November 13, 2017_
|
## v0.25.1 - _November 13, 2017_
|
||||||
------------------------
|
|
||||||
* Standardise on Cancelled over Canceled (#217)
|
* Standardise on Cancelled over Canceled (#217)
|
||||||
* Add missing `DecodedLogEvent` type to exported types (#205)
|
* Add missing `DecodedLogEvent` type to exported types (#205)
|
||||||
* Normalized the transactionReceipt status to be `null|0|1`, 1 meaning transaction execution successful, 0 unsuccessful and `null` if it is a pre-byzantinium transaction. (#200)
|
* Normalized the transactionReceipt status to be `null|0|1`, 1 meaning transaction execution successful, 0 unsuccessful and `null` if it is a pre-byzantinium transaction. (#200)
|
||||||
|
|
||||||
v0.23.0 - _November 12, 2017_
|
## v0.23.0 - _November 12, 2017_
|
||||||
------------------------
|
|
||||||
* Fixed unhandled promise rejection error in subscribe methods (#209)
|
* Fixed unhandled promise rejection error in subscribe methods (#209)
|
||||||
* Subscribe callbacks now receive an error object as their first argument
|
* Subscribe callbacks now receive an error object as their first argument
|
||||||
|
|
||||||
v0.22.6 - _November 10, 2017_
|
## v0.22.6 - _November 10, 2017_
|
||||||
------------------------
|
|
||||||
* Add a timeout parameter to transaction awaiting (#206)
|
* Add a timeout parameter to transaction awaiting (#206)
|
||||||
|
|
||||||
v0.22.5 - _November 7, 2017_
|
## v0.22.5 - _November 7, 2017_
|
||||||
------------------------
|
|
||||||
* Re-publish v0.22.4 to fix publishing issue
|
* Re-publish v0.22.4 to fix publishing issue
|
||||||
|
|
||||||
v0.22.4 - _October 25, 2017_
|
## v0.22.4 - _October 25, 2017_
|
||||||
------------------------
|
|
||||||
* Upgraded bignumber.js to a new version that ships with native typings
|
* Upgraded bignumber.js to a new version that ships with native typings
|
||||||
|
|
||||||
v0.22.3 - _October 25, 2017_
|
## v0.22.3 - _October 25, 2017_
|
||||||
------------------------
|
|
||||||
* Fixed an issue with new version of testrpc and unlimited proxy allowance (#199)
|
* Fixed an issue with new version of testrpc and unlimited proxy allowance (#199)
|
||||||
|
|
||||||
v0.22.2 - _October 24, 2017_
|
## v0.22.2 - _October 24, 2017_
|
||||||
------------------------
|
|
||||||
* Fixed rounding of maker fill amount and incorrect validation of partial fees (#197)
|
* Fixed rounding of maker fill amount and incorrect validation of partial fees (#197)
|
||||||
|
|
||||||
v0.22.0 - _October 16, 2017_
|
## v0.22.0 - _October 16, 2017_
|
||||||
------------------------
|
|
||||||
* Started using `OrderFillRequest` interface instead of `OrderFillOrKillRequest` interface for `zeroEx.exchange.batchFillOrKill` (#187)
|
* Started using `OrderFillRequest` interface instead of `OrderFillOrKillRequest` interface for `zeroEx.exchange.batchFillOrKill` (#187)
|
||||||
* Removed `OrderFillOrKillRequest` (#187)
|
* Removed `OrderFillOrKillRequest` (#187)
|
||||||
|
|
||||||
v0.21.4 - _October 13, 2017_
|
## v0.21.4 - _October 13, 2017_
|
||||||
------------------------
|
|
||||||
* Made 0x.js more type-safe by making `getLogsAsync` and `subscribe/subscribeAsync` generics parametrized with arg type (#194)
|
* Made 0x.js more type-safe by making `getLogsAsync` and `subscribe/subscribeAsync` generics parametrized with arg type (#194)
|
||||||
|
|
||||||
v0.21.3 - _October 12, 2017_
|
## v0.21.3 - _October 12, 2017_
|
||||||
------------------------
|
|
||||||
* Fixed a bug causing order fills to throw `INSUFFICIENT_TAKER_ALLOWANCE` (#193)
|
* Fixed a bug causing order fills to throw `INSUFFICIENT_TAKER_ALLOWANCE` (#193)
|
||||||
|
|
||||||
v0.21.2 - _October 11, 2017_
|
## v0.21.2 - _October 11, 2017_
|
||||||
------------------------
|
|
||||||
* Exported `ContractEventArg` as a public type (#190)
|
* Exported `ContractEventArg` as a public type (#190)
|
||||||
|
|
||||||
v0.21.1 - _October 11, 2017_
|
## v0.21.1 - _October 11, 2017_
|
||||||
------------------------
|
|
||||||
* Fixed a bug in subscriptions (#189)
|
* Fixed a bug in subscriptions (#189)
|
||||||
|
|
||||||
v0.21.0 - _October 10, 2017_
|
## v0.21.0 - _October 10, 2017_
|
||||||
------------------------
|
|
||||||
* Complete rewrite of subscription logic (#182)
|
* Complete rewrite of subscription logic (#182)
|
||||||
* Subscriptions no longer return historical logs. If you want them - use `getLogsAsync`
|
* Subscriptions no longer return historical logs. If you want them - use `getLogsAsync`
|
||||||
* Subscriptions now use [ethereumjs-blockstream](https://github.com/ethereumjs/ethereumjs-blockstream) under the hood
|
* Subscriptions now use [ethereumjs-blockstream](https://github.com/ethereumjs/ethereumjs-blockstream) under the hood
|
||||||
@@ -106,77 +163,77 @@ v0.21.0 - _October 10, 2017_
|
|||||||
* Renamed `zeroEx.token.stopWatchingAllEventsAsync` to `zeroEx.token.unsubscribeAll`
|
* Renamed `zeroEx.token.stopWatchingAllEventsAsync` to `zeroEx.token.unsubscribeAll`
|
||||||
* Fixed the batch fills validation by emulating all balance & proxy allowance changes (#185)
|
* Fixed the batch fills validation by emulating all balance & proxy allowance changes (#185)
|
||||||
|
|
||||||
v0.20.0 - _October 5, 2017_
|
## v0.20.0 - _October 5, 2017_
|
||||||
------------------------
|
|
||||||
* Add `zeroEx.token.getLogsAsync` (#178)
|
* Add `zeroEx.token.getLogsAsync` (#178)
|
||||||
* Add `zeroEx.exchange.getLogsAsync` (#178)
|
* Add `zeroEx.exchange.getLogsAsync` (#178)
|
||||||
* Fixed fees validation when one of the tokens transferred is ZRX (#181)
|
* Fixed fees validation when one of the tokens transferred is ZRX (#181)
|
||||||
|
|
||||||
v0.19.0 - _September 29, 2017_
|
## v0.19.0 - _September 29, 2017_
|
||||||
------------------------
|
|
||||||
* Made order validation optional (#172)
|
* Made order validation optional (#172)
|
||||||
* Added Ropsten testnet support (#173)
|
* Added Ropsten testnet support (#173)
|
||||||
* Fixed a bug causing awaitTransactionMinedAsync to DDos backend nodes (#175)
|
* Fixed a bug causing awaitTransactionMinedAsync to DDos backend nodes (#175)
|
||||||
|
|
||||||
v0.18.0 - _September 26, 2017_
|
## v0.18.0 - _September 26, 2017_
|
||||||
------------------------
|
|
||||||
* Added `zeroEx.exchange.validateOrderFillableOrThrowAsync` to simplify orderbook pruning (#170)
|
* Added `zeroEx.exchange.validateOrderFillableOrThrowAsync` to simplify orderbook pruning (#170)
|
||||||
|
|
||||||
v0.17.0 - _September 26, 2017_
|
## v0.17.0 - _September 26, 2017_
|
||||||
------------------------
|
|
||||||
* Made `zeroEx.exchange.getZRXTokenAddressAsync` public (#171)
|
* Made `zeroEx.exchange.getZRXTokenAddressAsync` public (#171)
|
||||||
|
|
||||||
v0.16.0 - _September 20, 2017_
|
## v0.16.0 - _September 20, 2017_
|
||||||
------------------------
|
|
||||||
* Added the ability to specify custom contract addresses to be used with 0x.js (#165)
|
* Added the ability to specify custom contract addresses to be used with 0x.js (#165)
|
||||||
* ZeroExConfig.exchangeContractAddress
|
* ZeroExConfig.exchangeContractAddress
|
||||||
* ZeroExConfig.tokenRegistryContractAddress
|
* ZeroExConfig.tokenRegistryContractAddress
|
||||||
* ZeroExConfig.etherTokenContractAddress
|
* ZeroExConfig.etherTokenContractAddress
|
||||||
* Added `zeroEx.tokenRegistry.getContractAddressAsync` (#165)
|
* Added `zeroEx.tokenRegistry.getContractAddressAsync` (#165)
|
||||||
|
|
||||||
v0.15.0 - _September 8, 2017_
|
## v0.15.0 - _September 8, 2017_
|
||||||
------------------------
|
|
||||||
* Added the ability to specify a historical `blockNumber` at which to query the blockchain's state when calling a token or exchange method (#161)
|
* Added the ability to specify a historical `blockNumber` at which to query the blockchain's state when calling a token or exchange method (#161)
|
||||||
|
|
||||||
v0.14.2 - _September 7, 2017_
|
## v0.14.2 - _September 7, 2017_
|
||||||
------------------------
|
|
||||||
* Fixed an issue with bignumber.js types not found (#160)
|
* Fixed an issue with bignumber.js types not found (#160)
|
||||||
|
|
||||||
v0.14.1 - _September 7, 2017_
|
## v0.14.1 - _September 7, 2017_
|
||||||
------------------------
|
|
||||||
* Fixed an issue with Artifact type not found (#159)
|
* Fixed an issue with Artifact type not found (#159)
|
||||||
|
|
||||||
v0.14.0 - _September 6, 2017_
|
## v0.14.0 - _September 6, 2017_
|
||||||
------------------------
|
|
||||||
* Added `zeroEx.exchange.throwLogErrorsAsErrors` method to public interface (#157)
|
* Added `zeroEx.exchange.throwLogErrorsAsErrors` method to public interface (#157)
|
||||||
* Fixed an issue with overlapping async intervals in `zeroEx.awaitTransactionMinedAsync` (#157)
|
* Fixed an issue with overlapping async intervals in `zeroEx.awaitTransactionMinedAsync` (#157)
|
||||||
* Fixed an issue with log decoder returning `BigNumber`s as `strings` (#157)
|
* Fixed an issue with log decoder returning `BigNumber`s as `strings` (#157)
|
||||||
|
|
||||||
v0.13.0 - _September 6, 2017_
|
## v0.13.0 - _September 6, 2017_
|
||||||
------------------------
|
|
||||||
* Made all the functions submitting transactions to the network to immediately return transaction hash (#151)
|
* Made all the functions submitting transactions to the network to immediately return transaction hash (#151)
|
||||||
* Added `zeroEx.awaitTransactionMinedAsync` (#151)
|
* Added `zeroEx.awaitTransactionMinedAsync` (#151)
|
||||||
* Added `TransactionReceiptWithDecodedLogs`, `LogWithDecodedArgs`, `DecodedLogArgs` to public types (#151)
|
* Added `TransactionReceiptWithDecodedLogs`, `LogWithDecodedArgs`, `DecodedLogArgs` to public types (#151)
|
||||||
* Added signature validation to `validateFillOrderThrowIfInvalidAsync` (#152)
|
* Added signature validation to `validateFillOrderThrowIfInvalidAsync` (#152)
|
||||||
|
|
||||||
v0.12.1 - _September 2, 2017_
|
## v0.12.1 - _September 2, 2017_
|
||||||
------------------------
|
|
||||||
* Added the support for web3@1.x.x provider (#142)
|
* Added the support for web3@1.x.x provider (#142)
|
||||||
* Added the optional `zeroExConfig` parameter to the constructor of `ZeroEx` (#139)
|
* Added the optional `zeroExConfig` parameter to the constructor of `ZeroEx` (#139)
|
||||||
* Added the ability to specify `gasPrice` when instantiating `ZeroEx` (#139)
|
* Added the ability to specify `gasPrice` when instantiating `ZeroEx` (#139)
|
||||||
|
|
||||||
v0.11.0 - _August 24, 2017_
|
## v0.11.0 - _August 24, 2017_
|
||||||
------------------------
|
|
||||||
* Added `zeroEx.token.setUnlimitedProxyAllowanceAsync` (#137)
|
* Added `zeroEx.token.setUnlimitedProxyAllowanceAsync` (#137)
|
||||||
* Added `zeroEx.token.setUnlimitedAllowanceAsync` (#137)
|
* Added `zeroEx.token.setUnlimitedAllowanceAsync` (#137)
|
||||||
* Added `zeroEx.token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS` (#137)
|
* Added `zeroEx.token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS` (#137)
|
||||||
|
|
||||||
v0.10.4 - _Aug 24, 2017_
|
## v0.10.4 - _Aug 24, 2017_
|
||||||
------------------------
|
|
||||||
* Fixed a bug where checksummed addresses were being pulled from artifacts and not lower-cased. (#135)
|
* Fixed a bug where checksummed addresses were being pulled from artifacts and not lower-cased. (#135)
|
||||||
|
|
||||||
v0.10.1 - _Aug 24, 2017_
|
## v0.10.1 - _Aug 24, 2017_
|
||||||
------------------------
|
|
||||||
* Added `zeroEx.exchange.validateFillOrderThrowIfInvalidAsync` (#128)
|
* Added `zeroEx.exchange.validateFillOrderThrowIfInvalidAsync` (#128)
|
||||||
* Added `zeroEx.exchange.validateFillOrKillOrderThrowIfInvalidAsync` (#128)
|
* Added `zeroEx.exchange.validateFillOrKillOrderThrowIfInvalidAsync` (#128)
|
||||||
* Added `zeroEx.exchange.validateCancelOrderThrowIfInvalidAsync` (#128)
|
* Added `zeroEx.exchange.validateCancelOrderThrowIfInvalidAsync` (#128)
|
||||||
@@ -190,21 +247,21 @@ v0.10.1 - _Aug 24, 2017_
|
|||||||
* Added clear error message when checksummed address is passed to a public method (#124)
|
* Added clear error message when checksummed address is passed to a public method (#124)
|
||||||
* Fixes the description of `shouldThrowOnInsufficientBalanceOrAllowance` in docs (#127)
|
* Fixes the description of `shouldThrowOnInsufficientBalanceOrAllowance` in docs (#127)
|
||||||
|
|
||||||
v0.9.3 - _Aug 22, 2017_
|
## v0.9.3 - _Aug 22, 2017_
|
||||||
------------------------
|
|
||||||
* Update contract artifacts to include latest Kovan and Mainnet deploys (#118)
|
* Update contract artifacts to include latest Kovan and Mainnet deploys (#118)
|
||||||
|
|
||||||
v0.9.2 - _Aug 21, 2017_
|
## v0.9.2 - _Aug 21, 2017_
|
||||||
------------------------
|
|
||||||
* *This version was unpublished because of a publishing issue.*
|
* *This version was unpublished because of a publishing issue.*
|
||||||
* Update contract artifacts to include latest Kovan and Mainnet deploys (#118)
|
* Update contract artifacts to include latest Kovan and Mainnet deploys (#118)
|
||||||
|
|
||||||
v0.9.1 - _Aug. 16, 2017_
|
## v0.9.1 - _Aug. 16, 2017_
|
||||||
------------------------
|
|
||||||
* Fixed the bug causing `zeroEx.token.getBalanceAsync()` to fail if no addresses available (#120)
|
* Fixed the bug causing `zeroEx.token.getBalanceAsync()` to fail if no addresses available (#120)
|
||||||
|
|
||||||
v0.9.0 - _Jul. 26, 2017_
|
## v0.9.0 - _Jul. 26, 2017_
|
||||||
------------------------
|
|
||||||
* Migrated to the new version of smart contracts (#101)
|
* Migrated to the new version of smart contracts (#101)
|
||||||
* Removed the ability to call methods on multiple authorized Exchange smart contracts (#106)
|
* Removed the ability to call methods on multiple authorized Exchange smart contracts (#106)
|
||||||
* Made `zeroEx.getOrderHashHex` a static method (#107)
|
* Made `zeroEx.getOrderHashHex` a static method (#107)
|
||||||
@@ -214,8 +271,8 @@ v0.9.0 - _Jul. 26, 2017_
|
|||||||
* Updated to typescript v2.4 (#104)
|
* Updated to typescript v2.4 (#104)
|
||||||
* Fixed an issue with incorrect balance/allowance validation when ZRX is one of the tokens traded (#109)
|
* Fixed an issue with incorrect balance/allowance validation when ZRX is one of the tokens traded (#109)
|
||||||
|
|
||||||
v0.8.0 - _Jul. 4, 2017_
|
## v0.8.0 - _Jul. 4, 2017_
|
||||||
------------------------
|
|
||||||
* Added the ability to call methods on different authorized versions of the Exchange smart contract (#82)
|
* Added the ability to call methods on different authorized versions of the Exchange smart contract (#82)
|
||||||
* Updated contract artifacts to reflect latest changes to the smart contracts (0xproject/contracts#59)
|
* Updated contract artifacts to reflect latest changes to the smart contracts (0xproject/contracts#59)
|
||||||
* Added `zeroEx.proxy.isAuthorizedAsync` and `zeroEx.proxy.getAuthorizedAddressesAsync` (#89)
|
* Added `zeroEx.proxy.isAuthorizedAsync` and `zeroEx.proxy.getAuthorizedAddressesAsync` (#89)
|
||||||
@@ -227,35 +284,35 @@ v0.8.0 - _Jul. 4, 2017_
|
|||||||
* `zeroEx.tokenRegistry.invalidateContractInstance`
|
* `zeroEx.tokenRegistry.invalidateContractInstance`
|
||||||
* Fixed the bug where `zeroEx.setProviderAsync` didn't invalidate etherToken contract's instance
|
* Fixed the bug where `zeroEx.setProviderAsync` didn't invalidate etherToken contract's instance
|
||||||
|
|
||||||
v0.7.1 - _Jun. 26, 2017_
|
## v0.7.1 - _Jun. 26, 2017_
|
||||||
------------------------
|
|
||||||
* Added the ability to convert Ether to wrapped Ether tokens and back via `zeroEx.etherToken.depostAsync` and `zeroEx.etherToken.withdrawAsync` (#81)
|
* Added the ability to convert Ether to wrapped Ether tokens and back via `zeroEx.etherToken.depostAsync` and `zeroEx.etherToken.withdrawAsync` (#81)
|
||||||
|
|
||||||
v0.7.0 - _Jun. 22, 2017_
|
## v0.7.0 - _Jun. 22, 2017_
|
||||||
------------------------
|
|
||||||
* Added Kovan smart contract artifacts (#78)
|
* Added Kovan smart contract artifacts (#78)
|
||||||
* Started returning fillAmount from `fillOrderAsync` and `fillUpToAsync` (#72)
|
* Started returning fillAmount from `fillOrderAsync` and `fillUpToAsync` (#72)
|
||||||
* Started returning cancelledAmount from `cancelOrderAsync` (#72)
|
* Started returning cancelledAmount from `cancelOrderAsync` (#72)
|
||||||
* Renamed type `LogCancelArgs` to `LogCancelContractEventArgs` and `LogFillArgs` to `LogFillContractEventArgs`
|
* Renamed type `LogCancelArgs` to `LogCancelContractEventArgs` and `LogFillArgs` to `LogFillContractEventArgs`
|
||||||
|
|
||||||
v0.6.2 - _Jun. 21, 2017_
|
## v0.6.2 - _Jun. 21, 2017_
|
||||||
------------------------
|
|
||||||
* Reduced bundle size
|
* Reduced bundle size
|
||||||
* Improved documentation
|
* Improved documentation
|
||||||
|
|
||||||
v0.6.1 - _Jun. 19, 2017_
|
## v0.6.1 - _Jun. 19, 2017_
|
||||||
------------------------
|
|
||||||
* Improved documentation
|
* Improved documentation
|
||||||
|
|
||||||
v0.6.0 - _Jun. 19, 2017_
|
## v0.6.0 - _Jun. 19, 2017_
|
||||||
------------------------
|
|
||||||
* Made `ZeroEx` class accept `Web3Provider` instance instead of `Web3` instance
|
* Made `ZeroEx` class accept `Web3Provider` instance instead of `Web3` instance
|
||||||
* Added types for contract event arguments
|
* Added types for contract event arguments
|
||||||
|
|
||||||
v0.5.2 - _Jun. 15, 2017_
|
## v0.5.2 - _Jun. 15, 2017_
|
||||||
------------------------
|
|
||||||
* Fixed the bug in `postpublish` script that caused that only unminified UMD bundle was uploaded to release page
|
* Fixed the bug in `postpublish` script that caused that only unminified UMD bundle was uploaded to release page
|
||||||
|
|
||||||
v0.5.1 - _Jun. 15, 2017_
|
## v0.5.1 - _Jun. 15, 2017_
|
||||||
------------------------
|
|
||||||
* Added `postpublish` script to publish to Github Releases with assets.
|
* Added `postpublish` script to publish to Github Releases with assets.
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
0x.js
|
## 0x.js
|
||||||
-----
|
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
0x.js ships as both a [UMD](https://github.com/umdjs/umd) module and a [CommonJS](https://en.wikipedia.org/wiki/CommonJS) package.
|
0x.js ships as both a [UMD](https://github.com/umdjs/umd) module and a [CommonJS](https://en.wikipedia.org/wiki/CommonJS) package.
|
||||||
|
|
||||||
#### CommonJS *(recommended)*:
|
#### CommonJS _(recommended)_:
|
||||||
|
|
||||||
**Install**
|
**Install**
|
||||||
|
|
||||||
@@ -16,14 +15,23 @@ npm install 0x.js --save
|
|||||||
**Import**
|
**Import**
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
import {ZeroEx} from '0x.js';
|
import { ZeroEx } from '0x.js';
|
||||||
|
```
|
||||||
|
|
||||||
|
If your project is in [TypeScript](https://www.typescriptlang.org/), add the following to your `tsconfig.json`:
|
||||||
|
|
||||||
|
```
|
||||||
|
"include": [
|
||||||
|
"./node_modules/web3-typescript-typings/index.d.ts",
|
||||||
|
"./node_modules/ethers-typescript-typings/index.d.ts"
|
||||||
|
]
|
||||||
```
|
```
|
||||||
|
|
||||||
#### UMD:
|
#### UMD:
|
||||||
|
|
||||||
**Install**
|
**Install**
|
||||||
|
|
||||||
Download the UMD module from our [releases page](https://github.com/0xProject/0x.js/releases) and add it to your project.
|
Download the UMD module from our [releases page](https://github.com/0xProject/0x-monorepo/releases) and add it to your project.
|
||||||
|
|
||||||
**Import**
|
**Import**
|
||||||
|
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
/**
|
|
||||||
* This file is auto-generated using abi-gen. Don't edit directly.
|
|
||||||
* Templates can be found at https://github.com/0xProject/0x.js/tree/development/packages/abi-gen-templates.
|
|
||||||
*/
|
|
||||||
// tslint:disable-next-line:no-unused-variable
|
|
||||||
import {TxData, TxDataPayable} from '@0xproject/types';
|
|
||||||
import {classUtils, promisify} from '@0xproject/utils';
|
|
||||||
import {BigNumber} from 'bignumber.js';
|
|
||||||
import * as Web3 from 'web3';
|
|
||||||
|
|
||||||
import {BaseContract} from './base_contract';
|
|
||||||
|
|
||||||
export class {{contractName}}Contract extends BaseContract {
|
|
||||||
{{#each methods}}
|
|
||||||
{{#this.constant}}
|
|
||||||
{{> call contractName=../contractName}}
|
|
||||||
{{/this.constant}}
|
|
||||||
{{^this.constant}}
|
|
||||||
{{> tx contractName=../contractName}}
|
|
||||||
{{/this.constant}}
|
|
||||||
{{/each}}
|
|
||||||
constructor(web3ContractInstance: Web3.ContractInstance, defaults: Partial<TxData>) {
|
|
||||||
super(web3ContractInstance, defaults);
|
|
||||||
classUtils.bindAll(this, ['web3ContractInstance', 'defaults']);
|
|
||||||
}
|
|
||||||
} // tslint:disable:max-file-line-count
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
public {{this.name}} = {
|
|
||||||
async callAsync(
|
|
||||||
{{> typed_params inputs=inputs}}
|
|
||||||
defaultBlock?: Web3.BlockParam,
|
|
||||||
): Promise<{{> return_type outputs=outputs}}> {
|
|
||||||
const self = this as {{contractName}}Contract;
|
|
||||||
const result = await promisify<{{> return_type outputs=outputs}}>(
|
|
||||||
self.web3ContractInstance.{{this.name}}.call,
|
|
||||||
self.web3ContractInstance,
|
|
||||||
)(
|
|
||||||
{{> params inputs=inputs}}
|
|
||||||
);
|
|
||||||
return result;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
{{#singleReturnValue}}
|
|
||||||
{{#returnType outputs.0.type}}{{/returnType}}
|
|
||||||
{{/singleReturnValue}}
|
|
||||||
{{^singleReturnValue}}
|
|
||||||
[{{#each outputs}}{{#returnType type}}{{/returnType}}{{#unless @last}}, {{/unless}}{{/each}}]
|
|
||||||
{{/singleReturnValue}}
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
public {{this.name}} = {
|
|
||||||
async sendTransactionAsync(
|
|
||||||
{{> typed_params inputs=inputs}}
|
|
||||||
{{#this.payable}}
|
|
||||||
txData: TxDataPayable = {},
|
|
||||||
{{/this.payable}}
|
|
||||||
{{^this.payable}}
|
|
||||||
txData: TxData = {},
|
|
||||||
{{/this.payable}}
|
|
||||||
): Promise<string> {
|
|
||||||
const self = this as {{contractName}}Contract;
|
|
||||||
const txDataWithDefaults = await self.applyDefaultsToTxDataAsync(
|
|
||||||
txData,
|
|
||||||
self.{{this.name}}.estimateGasAsync.bind(
|
|
||||||
self,
|
|
||||||
{{> params inputs=inputs}}
|
|
||||||
),
|
|
||||||
);
|
|
||||||
const txHash = await promisify<string>(
|
|
||||||
self.web3ContractInstance.{{this.name}}, self.web3ContractInstance,
|
|
||||||
)(
|
|
||||||
{{> params inputs=inputs}}
|
|
||||||
txDataWithDefaults,
|
|
||||||
);
|
|
||||||
return txHash;
|
|
||||||
},
|
|
||||||
async estimateGasAsync(
|
|
||||||
{{> typed_params inputs=inputs}}
|
|
||||||
txData: TxData = {},
|
|
||||||
): Promise<number> {
|
|
||||||
const self = this as {{contractName}}Contract;
|
|
||||||
const txDataWithDefaults = await self.applyDefaultsToTxDataAsync(
|
|
||||||
txData,
|
|
||||||
);
|
|
||||||
const gas = await promisify<number>(
|
|
||||||
self.web3ContractInstance.{{this.name}}.estimateGas, self.web3ContractInstance,
|
|
||||||
)(
|
|
||||||
{{> params inputs=inputs}}
|
|
||||||
txDataWithDefaults,
|
|
||||||
);
|
|
||||||
return gas;
|
|
||||||
},
|
|
||||||
getABIEncodedTransactionData(
|
|
||||||
{{> typed_params inputs=inputs}}
|
|
||||||
txData: TxData = {},
|
|
||||||
): string {
|
|
||||||
const self = this as {{contractName}}Contract;
|
|
||||||
const abiEncodedTransactionData = self.web3ContractInstance.{{this.name}}.getData();
|
|
||||||
return abiEncodedTransactionData;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
{{#each inputs}}
|
|
||||||
{{name}}: {{#parameterType type}}{{/parameterType}},
|
|
||||||
{{/each}}
|
|
||||||
@@ -1,104 +1,102 @@
|
|||||||
{
|
{
|
||||||
"name": "0x.js",
|
"name": "0x.js",
|
||||||
"version": "0.29.0",
|
"version": "0.33.1",
|
||||||
"description": "A javascript library for interacting with the 0x protocol",
|
"description": "A javascript library for interacting with the 0x protocol",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"0x.js",
|
"0x.js",
|
||||||
"0xproject",
|
"0xproject",
|
||||||
"ethereum",
|
"ethereum",
|
||||||
"tokens",
|
"tokens",
|
||||||
"exchange"
|
"exchange"
|
||||||
],
|
],
|
||||||
"main": "lib/src/index.js",
|
"main": "lib/src/index.js",
|
||||||
"types": "lib/src/index.d.ts",
|
"types": "lib/src/index.d.ts",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"prebuild": "run-s clean generate_contract_wrappers",
|
"build:watch": "tsc -w",
|
||||||
"build": "run-p build:umd:prod build:commonjs; exit 0;",
|
"prebuild": "run-s clean generate_contract_wrappers",
|
||||||
"docs:json": "typedoc --excludePrivate --excludeExternals --target ES5 --json $JSON_FILE_PATH $PROJECT_DIR",
|
"build": "run-p build:umd:prod build:commonjs; exit 0;",
|
||||||
"upload_docs_json": "aws s3 cp generated_docs/index.json $S3_URL --profile 0xproject --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers --content-type application/json",
|
"docs:json": "typedoc --excludePrivate --excludeExternals --target ES5 --json $JSON_FILE_PATH $PROJECT_FILES",
|
||||||
"generate_contract_wrappers": "node ../abi-gen/lib/index.js --abiGlob 'src/artifacts/@(Exchange|Token|TokenTransferProxy|EtherToken|TokenRegistry|DummyToken).json' --templates contract_templates --output src/contract_wrappers/generated",
|
"upload_docs_json": "aws s3 cp generated_docs/index.json $S3_URL --profile 0xproject --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers --content-type application/json",
|
||||||
"lint": "tslint --project . 'src/**/*.ts' 'test/**/*.ts'",
|
"generate_contract_wrappers": "node ../abi-gen/lib/index.js --abis 'src/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'",
|
||||||
"test:circleci": "run-s test:coverage report_test_coverage && if [ $CIRCLE_BRANCH = \"development\" ]; then yarn test:umd; fi",
|
"lint": "tslint --project . 'src/**/*.ts' 'test/**/*.ts'",
|
||||||
"test": "run-s clean test:commonjs",
|
"test:circleci": "run-s test:coverage report_test_coverage",
|
||||||
"test:umd": "./scripts/test_umd.sh",
|
"test": "run-s clean test:commonjs",
|
||||||
"test:coverage": "nyc npm run test --all",
|
"test:coverage": "nyc npm run test --all",
|
||||||
"report_test_coverage": "nyc report --reporter=text-lcov | coveralls",
|
"report_test_coverage": "nyc report --reporter=text-lcov | coveralls",
|
||||||
"update_contracts": "for i in ${npm_package_config_artifacts}; do copyfiles -u 4 ../contracts/build/contracts/$i.json ../0x.js/src/artifacts; done;",
|
"update_contracts": "for i in ${npm_package_config_artifacts}; do copyfiles -u 4 ../contracts/build/contracts/$i.json ../0x.js/src/artifacts; done;",
|
||||||
"clean": "shx rm -rf _bundles lib test_temp",
|
"clean": "shx rm -rf _bundles lib test_temp",
|
||||||
"build:umd:dev": "webpack",
|
"build:umd:prod": "NODE_ENV=production webpack",
|
||||||
"build:umd:prod": "NODE_ENV=production webpack",
|
"build:commonjs": "tsc && copyfiles -u 2 './src/artifacts/**/*.json' ./lib/src/artifacts;",
|
||||||
"build:commonjs": "tsc && copyfiles -u 2 './src/artifacts/**/*.json' ./lib/src/artifacts;",
|
"test:commonjs": "run-s build:commonjs run_mocha",
|
||||||
"test:commonjs": "run-s build:commonjs run_mocha",
|
"run_mocha": "mocha lib/test/**/*_test.js --timeout 10000 --bail --exit"
|
||||||
"pretest:umd": "run-s clean build:umd:dev build:commonjs",
|
},
|
||||||
"substitute_umd_bundle": "shx mv _bundles/* lib/src",
|
"config": {
|
||||||
"run_mocha": "mocha lib/test/**/*_test.js --timeout 10000 --bail --exit"
|
"artifacts": "TokenTransferProxy Exchange TokenRegistry Token EtherToken"
|
||||||
},
|
},
|
||||||
"config": {
|
"repository": {
|
||||||
"artifacts": "TokenTransferProxy Exchange TokenRegistry Token EtherToken"
|
"type": "git",
|
||||||
},
|
"url": "https://github.com/0xProject/0x-monorepo"
|
||||||
"repository": {
|
},
|
||||||
"type": "git",
|
"license": "Apache-2.0",
|
||||||
"url": "https://github.com/0xProject/0x.js"
|
"engines": {
|
||||||
},
|
"node": ">=6.0.0"
|
||||||
"license": "Apache-2.0",
|
},
|
||||||
"engines": {
|
"devDependencies": {
|
||||||
"node": ">=6.0.0"
|
"@0xproject/abi-gen": "^0.2.5",
|
||||||
},
|
"@0xproject/dev-utils": "^0.2.1",
|
||||||
"devDependencies": {
|
"@0xproject/tslint-config": "^0.4.10",
|
||||||
"@0xproject/abi-gen": "^0.0.4",
|
"@types/bintrees": "^1.0.2",
|
||||||
"@0xproject/dev-utils": "^0.0.3",
|
"@types/jsonschema": "^1.1.1",
|
||||||
"@0xproject/tslint-config": "^0.4.0",
|
"@types/lodash": "^4.14.86",
|
||||||
"@0xproject/types": "^0.1.2",
|
"@types/mocha": "^2.2.42",
|
||||||
"@types/bintrees": "^1.0.2",
|
"@types/node": "^8.0.53",
|
||||||
"@types/jsonschema": "^1.1.1",
|
"@types/sinon": "^2.2.2",
|
||||||
"@types/lodash": "^4.14.86",
|
"@types/uuid": "^3.4.2",
|
||||||
"@types/mocha": "^2.2.42",
|
"awesome-typescript-loader": "^3.1.3",
|
||||||
"@types/node": "^8.0.53",
|
"chai": "^4.0.1",
|
||||||
"@types/sinon": "^2.2.2",
|
"chai-as-promised": "^7.1.0",
|
||||||
"@types/uuid": "^3.4.2",
|
"chai-as-promised-typescript-typings": "^0.0.10",
|
||||||
"awesome-typescript-loader": "^3.1.3",
|
"chai-bignumber": "^2.0.1",
|
||||||
"chai": "^4.0.1",
|
"chai-typescript-typings": "^0.0.4",
|
||||||
"chai-as-promised": "^7.1.0",
|
"copyfiles": "^1.2.0",
|
||||||
"chai-as-promised-typescript-typings": "^0.0.3",
|
"coveralls": "^3.0.0",
|
||||||
"chai-bignumber": "^2.0.1",
|
"dirty-chai": "^2.0.1",
|
||||||
"chai-typescript-typings": "^0.0.1",
|
"json-loader": "^0.5.4",
|
||||||
"copyfiles": "^1.2.0",
|
"mocha": "^4.0.1",
|
||||||
"coveralls": "^3.0.0",
|
"npm-run-all": "^4.1.2",
|
||||||
"dirty-chai": "^2.0.1",
|
"nyc": "^11.0.1",
|
||||||
"json-loader": "^0.5.4",
|
"opn-cli": "^3.1.0",
|
||||||
"mocha": "^4.0.1",
|
"request": "^2.81.0",
|
||||||
"npm-run-all": "^4.1.2",
|
"request-promise-native": "^1.0.5",
|
||||||
"nyc": "^11.0.1",
|
"shx": "^0.2.2",
|
||||||
"opn-cli": "^3.1.0",
|
"sinon": "^4.0.0",
|
||||||
"request": "^2.81.0",
|
"source-map-support": "^0.5.0",
|
||||||
"request-promise-native": "^1.0.4",
|
"truffle-hdwallet-provider": "^0.0.3",
|
||||||
"shx": "^0.2.2",
|
"tslint": "5.8.0",
|
||||||
"sinon": "^4.0.0",
|
"typedoc": "0xProject/typedoc",
|
||||||
"source-map-support": "^0.5.0",
|
"types-bn": "^0.0.1",
|
||||||
"truffle-hdwallet-provider": "^0.0.3",
|
"typescript": "2.7.1",
|
||||||
"tslint": "5.8.0",
|
"web3-provider-engine": "^13.0.1",
|
||||||
"typedoc": "~0.8.0",
|
"webpack": "^3.1.0"
|
||||||
"typescript": "~2.6.1",
|
},
|
||||||
"web3-provider-engine": "^13.0.1",
|
"dependencies": {
|
||||||
"web3-typescript-typings": "^0.7.2",
|
"@0xproject/assert": "^0.2.0",
|
||||||
"webpack": "^3.1.0"
|
"@0xproject/base-contract": "^0.0.3",
|
||||||
},
|
"@0xproject/json-schemas": "^0.7.14",
|
||||||
"dependencies": {
|
"@0xproject/types": "^0.3.1",
|
||||||
"@0xproject/assert": "^0.0.9",
|
"@0xproject/utils": "^0.4.1",
|
||||||
"@0xproject/json-schemas": "^0.7.1",
|
"@0xproject/web3-wrapper": "^0.2.1",
|
||||||
"@0xproject/utils": "^0.1.2",
|
"bintrees": "^1.0.2",
|
||||||
"@0xproject/web3-wrapper": "^0.1.2",
|
"bn.js": "^4.11.8",
|
||||||
"bignumber.js": "~4.1.0",
|
"ethereumjs-abi": "^0.6.4",
|
||||||
"bintrees": "^1.0.2",
|
"ethereumjs-blockstream": "^2.0.6",
|
||||||
"bn.js": "^4.11.8",
|
"ethereumjs-util": "^5.1.1",
|
||||||
"compare-versions": "^3.0.1",
|
"ethers-contracts": "^2.2.1",
|
||||||
"ethereumjs-abi": "^0.6.4",
|
"ethers-typescript-typings": "^0.0.2",
|
||||||
"ethereumjs-blockstream": "^2.0.6",
|
"js-sha3": "^0.7.0",
|
||||||
"ethereumjs-util": "^5.1.1",
|
"lodash": "^4.17.4",
|
||||||
"find-versions": "^2.0.0",
|
"uuid": "^3.1.0",
|
||||||
"js-sha3": "^0.6.1",
|
"web3": "^0.20.0",
|
||||||
"lodash": "^4.17.4",
|
"web3-typescript-typings": "^0.10.0"
|
||||||
"uuid": "^3.1.0",
|
}
|
||||||
"web3": "^0.20.0"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,33 +1,35 @@
|
|||||||
const execAsync = require('async-child-process').execAsync;
|
const execAsync = require('async-child-process').execAsync;
|
||||||
const postpublish_utils = require('../../../scripts/postpublish_utils');
|
const postpublish_utils = require('../../../scripts/postpublish_utils');
|
||||||
const packageJSON = require('../package.json');
|
const packageJSON = require('../package.json');
|
||||||
|
const tsConfig = require('../tsconfig.json');
|
||||||
|
|
||||||
const cwd = __dirname + '/..';
|
const cwd = __dirname + '/..';
|
||||||
const subPackageName = packageJSON.name;
|
const subPackageName = packageJSON.name;
|
||||||
|
// Include any external packages that are part of the 0x.js public interface
|
||||||
|
// to this array so that TypeDoc picks it up and adds it to the Docs JSON
|
||||||
|
// So far, we only have @0xproject/types as part of 0x.js's public interface.
|
||||||
|
const fileIncludes = [...tsConfig.include, '../types/src/index.ts'];
|
||||||
|
const fileIncludesAdjusted = postpublish_utils.adjustFileIncludePaths(fileIncludes, __dirname);
|
||||||
|
const projectFiles = fileIncludesAdjusted.join(' ');
|
||||||
const S3BucketPath = 's3://0xjs-docs-jsons/';
|
const S3BucketPath = 's3://0xjs-docs-jsons/';
|
||||||
|
|
||||||
let tag;
|
let tag;
|
||||||
let version;
|
let version;
|
||||||
postpublish_utils.getLatestTagAndVersionAsync(subPackageName)
|
postpublish_utils
|
||||||
|
.getLatestTagAndVersionAsync(subPackageName)
|
||||||
.then(function(result) {
|
.then(function(result) {
|
||||||
tag = result.tag;
|
tag = result.tag;
|
||||||
version = result.version;
|
version = result.version;
|
||||||
const releaseName = postpublish_utils.getReleaseName(subPackageName, version);
|
const releaseName = postpublish_utils.getReleaseName(subPackageName, version);
|
||||||
const assets = [
|
const assets = [__dirname + '/../_bundles/index.js', __dirname + '/../_bundles/index.min.js'];
|
||||||
__dirname + '/../_bundles/index.js',
|
return postpublish_utils.publishReleaseNotesAsync(tag, releaseName, assets);
|
||||||
__dirname + '/../_bundles/index.min.js',
|
|
||||||
];
|
|
||||||
return postpublish_utils.publishReleaseNotes(tag, releaseName, assets);
|
|
||||||
})
|
})
|
||||||
.then(function(release) {
|
.then(function(release) {
|
||||||
console.log('POSTPUBLISH: Release successful, generating docs...');
|
console.log('POSTPUBLISH: Release successful, generating docs...');
|
||||||
const jsonFilePath = __dirname + '/../' + postpublish_utils.generatedDocsDirectoryName + '/index.json';
|
const jsonFilePath = __dirname + '/../' + postpublish_utils.generatedDocsDirectoryName + '/index.json';
|
||||||
return execAsync(
|
return execAsync('JSON_FILE_PATH=' + jsonFilePath + ' PROJECT_FILES="' + projectFiles + '" yarn docs:json', {
|
||||||
'JSON_FILE_PATH=' + jsonFilePath + ' PROJECT_DIR=' + __dirname + '/.. yarn docs:json',
|
cwd,
|
||||||
{
|
});
|
||||||
cwd,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
})
|
})
|
||||||
.then(function(result) {
|
.then(function(result) {
|
||||||
if (result.stderr !== '') {
|
if (result.stderr !== '') {
|
||||||
@@ -39,6 +41,7 @@ postpublish_utils.getLatestTagAndVersionAsync(subPackageName)
|
|||||||
return execAsync('S3_URL=' + s3Url + ' yarn upload_docs_json', {
|
return execAsync('S3_URL=' + s3Url + ' yarn upload_docs_json', {
|
||||||
cwd,
|
cwd,
|
||||||
});
|
});
|
||||||
}).catch (function(err) {
|
})
|
||||||
|
.catch(function(err) {
|
||||||
throw err;
|
throw err;
|
||||||
});
|
});
|
||||||
|
|||||||
31
packages/0x.js/scripts/stagedocs.js
Normal file
31
packages/0x.js/scripts/stagedocs.js
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
const execAsync = require('async-child-process').execAsync;
|
||||||
|
const postpublish_utils = require('../../../scripts/postpublish_utils');
|
||||||
|
const tsConfig = require('../tsconfig.json');
|
||||||
|
|
||||||
|
const cwd = __dirname + '/..';
|
||||||
|
const S3BucketPath = 's3://staging-0xjs-docs-jsons/';
|
||||||
|
// Include any external packages that are part of the 0x.js public interface
|
||||||
|
// to this array so that TypeDoc picks it up and adds it to the Docs JSON
|
||||||
|
// So far, we only have @0xproject/types as part of 0x.js's public interface.
|
||||||
|
const fileIncludes = [...tsConfig.include, '../types/src/index.ts'];
|
||||||
|
const fileIncludesAdjusted = postpublish_utils.adjustFileIncludePaths(fileIncludes, __dirname);
|
||||||
|
const projectFiles = fileIncludesAdjusted.join(' ');
|
||||||
|
const jsonFilePath = __dirname + '/../' + postpublish_utils.generatedDocsDirectoryName + '/index.json';
|
||||||
|
const version = process.env.DOCS_VERSION;
|
||||||
|
|
||||||
|
execAsync('JSON_FILE_PATH=' + jsonFilePath + ' PROJECT_FILES="' + projectFiles + '" yarn docs:json', {
|
||||||
|
cwd,
|
||||||
|
})
|
||||||
|
.then(function(result) {
|
||||||
|
if (result.stderr !== '') {
|
||||||
|
throw new Error(result.stderr);
|
||||||
|
}
|
||||||
|
const fileName = 'v' + version + '.json';
|
||||||
|
const s3Url = S3BucketPath + fileName;
|
||||||
|
return execAsync('S3_URL=' + s3Url + ' yarn upload_docs_json', {
|
||||||
|
cwd,
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(function(err) {
|
||||||
|
console.log(err);
|
||||||
|
});
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
# This script runs umd tests and cleans up after them while preserving the `return_code` for CI
|
|
||||||
# UMD tests should only be run after building the commonjs because they reuse some of the commonjs build artifacts
|
|
||||||
run-s substitute_umd_bundle run_mocha
|
|
||||||
return_code=$?
|
|
||||||
exit $return_code
|
|
||||||
@@ -1,36 +1,26 @@
|
|||||||
import {schemas, SchemaValidator} from '@0xproject/json-schemas';
|
import { schemas, SchemaValidator } from '@0xproject/json-schemas';
|
||||||
import {bigNumberConfigs, intervalUtils} from '@0xproject/utils';
|
import { TransactionReceiptWithDecodedLogs } from '@0xproject/types';
|
||||||
import {Web3Wrapper} from '@0xproject/web3-wrapper';
|
import { AbiDecoder, BigNumber, intervalUtils } from '@0xproject/utils';
|
||||||
import BigNumber from 'bignumber.js';
|
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||||
import * as ethUtil from 'ethereumjs-util';
|
import * as ethUtil from 'ethereumjs-util';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import {artifacts} from './artifacts';
|
import { artifacts } from './artifacts';
|
||||||
import {EtherTokenWrapper} from './contract_wrappers/ether_token_wrapper';
|
import { EtherTokenWrapper } from './contract_wrappers/ether_token_wrapper';
|
||||||
import {ExchangeWrapper} from './contract_wrappers/exchange_wrapper';
|
import { ExchangeWrapper } from './contract_wrappers/exchange_wrapper';
|
||||||
import {TokenRegistryWrapper} from './contract_wrappers/token_registry_wrapper';
|
import { TokenRegistryWrapper } from './contract_wrappers/token_registry_wrapper';
|
||||||
import {TokenTransferProxyWrapper} from './contract_wrappers/token_transfer_proxy_wrapper';
|
import { TokenTransferProxyWrapper } from './contract_wrappers/token_transfer_proxy_wrapper';
|
||||||
import {TokenWrapper} from './contract_wrappers/token_wrapper';
|
import { TokenWrapper } from './contract_wrappers/token_wrapper';
|
||||||
import {OrderStateWatcher} from './order_watcher/order_state_watcher';
|
import { OrderStateWatcher } from './order_watcher/order_state_watcher';
|
||||||
import {zeroExConfigSchema} from './schemas/zero_ex_config_schema';
|
import { zeroExConfigSchema } from './schemas/zero_ex_config_schema';
|
||||||
import {
|
import { zeroExPrivateNetworkConfigSchema } from './schemas/zero_ex_private_network_config_schema';
|
||||||
ECSignature,
|
import { zeroExPublicNetworkConfigSchema } from './schemas/zero_ex_public_network_config_schema';
|
||||||
Order,
|
import { ECSignature, Order, SignedOrder, Web3Provider, ZeroExConfig, ZeroExError } from './types';
|
||||||
SignedOrder,
|
import { assert } from './utils/assert';
|
||||||
TransactionReceiptWithDecodedLogs,
|
import { constants } from './utils/constants';
|
||||||
Web3Provider,
|
import { decorators } from './utils/decorators';
|
||||||
ZeroExConfig,
|
import { signatureUtils } from './utils/signature_utils';
|
||||||
ZeroExError,
|
import { utils } from './utils/utils';
|
||||||
} from './types';
|
|
||||||
import {AbiDecoder} from './utils/abi_decoder';
|
|
||||||
import {assert} from './utils/assert';
|
|
||||||
import {constants} from './utils/constants';
|
|
||||||
import {decorators} from './utils/decorators';
|
|
||||||
import {signatureUtils} from './utils/signature_utils';
|
|
||||||
import {utils} from './utils/utils';
|
|
||||||
|
|
||||||
// Customize our BigNumber instances
|
|
||||||
bigNumberConfigs.configure();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The ZeroEx class is the single entry-point into the 0x.js library. It contains all of the library's functionality
|
* The ZeroEx class is the single entry-point into the 0x.js library. It contains all of the library's functionality
|
||||||
@@ -86,8 +76,9 @@ export class ZeroEx {
|
|||||||
assert.isHexString('data', data);
|
assert.isHexString('data', data);
|
||||||
assert.doesConformToSchema('signature', signature, schemas.ecSignatureSchema);
|
assert.doesConformToSchema('signature', signature, schemas.ecSignatureSchema);
|
||||||
assert.isETHAddressHex('signerAddress', signerAddress);
|
assert.isETHAddressHex('signerAddress', signerAddress);
|
||||||
|
const normalizedSignerAddress = signerAddress.toLowerCase();
|
||||||
|
|
||||||
const isValidSignature = signatureUtils.isValidSignature(data, signature, signerAddress);
|
const isValidSignature = signatureUtils.isValidSignature(data, signature, normalizedSignerAddress);
|
||||||
return isValidSignature;
|
return isValidSignature;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@@ -161,7 +152,7 @@ export class ZeroEx {
|
|||||||
* @return The resulting orderHash from hashing the supplied order.
|
* @return The resulting orderHash from hashing the supplied order.
|
||||||
*/
|
*/
|
||||||
@decorators.syncZeroExErrorHandler
|
@decorators.syncZeroExErrorHandler
|
||||||
public static getOrderHashHex(order: Order|SignedOrder): string {
|
public static getOrderHashHex(order: Order | SignedOrder): string {
|
||||||
assert.doesConformToSchema('order', order, schemas.orderSchema);
|
assert.doesConformToSchema('order', order, schemas.orderSchema);
|
||||||
const orderHashHex = utils.getOrderHashHex(order);
|
const orderHashHex = utils.getOrderHashHex(order);
|
||||||
return orderHashHex;
|
return orderHashHex;
|
||||||
@@ -175,7 +166,10 @@ export class ZeroEx {
|
|||||||
*/
|
*/
|
||||||
constructor(provider: Web3Provider, config: ZeroExConfig) {
|
constructor(provider: Web3Provider, config: ZeroExConfig) {
|
||||||
assert.isWeb3Provider('provider', provider);
|
assert.isWeb3Provider('provider', provider);
|
||||||
assert.doesConformToSchema('config', config, zeroExConfigSchema);
|
assert.doesConformToSchema('config', config, zeroExConfigSchema, [
|
||||||
|
zeroExPrivateNetworkConfigSchema,
|
||||||
|
zeroExPublicNetworkConfigSchema,
|
||||||
|
]);
|
||||||
const artifactJSONs = _.values(artifacts);
|
const artifactJSONs = _.values(artifacts);
|
||||||
const abiArrays = _.map(artifactJSONs, artifact => artifact.abi);
|
const abiArrays = _.map(artifactJSONs, artifact => artifact.abi);
|
||||||
this._abiDecoder = new AbiDecoder(abiArrays);
|
this._abiDecoder = new AbiDecoder(abiArrays);
|
||||||
@@ -188,27 +182,27 @@ export class ZeroEx {
|
|||||||
config.networkId,
|
config.networkId,
|
||||||
config.tokenTransferProxyContractAddress,
|
config.tokenTransferProxyContractAddress,
|
||||||
);
|
);
|
||||||
this.token = new TokenWrapper(
|
this.token = new TokenWrapper(this._web3Wrapper, config.networkId, this._abiDecoder, this.proxy);
|
||||||
this._web3Wrapper,
|
|
||||||
config.networkId,
|
|
||||||
this._abiDecoder,
|
|
||||||
this.proxy,
|
|
||||||
);
|
|
||||||
this.exchange = new ExchangeWrapper(
|
this.exchange = new ExchangeWrapper(
|
||||||
this._web3Wrapper,
|
this._web3Wrapper,
|
||||||
config.networkId,
|
config.networkId,
|
||||||
this._abiDecoder,
|
this._abiDecoder,
|
||||||
this.token,
|
this.token,
|
||||||
config.exchangeContractAddress,
|
config.exchangeContractAddress,
|
||||||
|
config.zrxContractAddress,
|
||||||
);
|
);
|
||||||
this.tokenRegistry = new TokenRegistryWrapper(
|
this.tokenRegistry = new TokenRegistryWrapper(
|
||||||
this._web3Wrapper, config.networkId, config.tokenRegistryContractAddress,
|
this._web3Wrapper,
|
||||||
);
|
config.networkId,
|
||||||
this.etherToken = new EtherTokenWrapper(
|
config.tokenRegistryContractAddress,
|
||||||
this._web3Wrapper, config.networkId, this._abiDecoder, this.token,
|
|
||||||
);
|
);
|
||||||
|
this.etherToken = new EtherTokenWrapper(this._web3Wrapper, config.networkId, this._abiDecoder, this.token);
|
||||||
this.orderStateWatcher = new OrderStateWatcher(
|
this.orderStateWatcher = new OrderStateWatcher(
|
||||||
this._web3Wrapper, this._abiDecoder, this.token, this.exchange, config.orderWatcherConfig,
|
this._web3Wrapper,
|
||||||
|
this._abiDecoder,
|
||||||
|
this.token,
|
||||||
|
this.exchange,
|
||||||
|
config.orderWatcherConfig,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@@ -218,12 +212,17 @@ export class ZeroEx {
|
|||||||
* @param networkId The id of the network your provider is connected to
|
* @param networkId The id of the network your provider is connected to
|
||||||
*/
|
*/
|
||||||
public setProvider(provider: Web3Provider, networkId: number): void {
|
public setProvider(provider: Web3Provider, networkId: number): void {
|
||||||
this._web3Wrapper.setProvider(provider, networkId);
|
this._web3Wrapper.setProvider(provider);
|
||||||
(this.exchange as any)._invalidateContractInstances();
|
(this.exchange as any)._invalidateContractInstances();
|
||||||
|
(this.exchange as any)._setNetworkId(networkId);
|
||||||
(this.tokenRegistry as any)._invalidateContractInstance();
|
(this.tokenRegistry as any)._invalidateContractInstance();
|
||||||
|
(this.tokenRegistry as any)._setNetworkId(networkId);
|
||||||
(this.token as any)._invalidateContractInstances();
|
(this.token as any)._invalidateContractInstances();
|
||||||
|
(this.token as any)._setNetworkId(networkId);
|
||||||
(this.proxy as any)._invalidateContractInstance();
|
(this.proxy as any)._invalidateContractInstance();
|
||||||
|
(this.proxy as any)._setNetworkId(networkId);
|
||||||
(this.etherToken as any)._invalidateContractInstance();
|
(this.etherToken as any)._invalidateContractInstance();
|
||||||
|
(this.etherToken as any)._setNetworkId(networkId);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Get user Ethereum addresses available through the supplied web3 provider available for sending transactions.
|
* Get user Ethereum addresses available through the supplied web3 provider available for sending transactions.
|
||||||
@@ -239,26 +238,29 @@ export class ZeroEx {
|
|||||||
* @param orderHash Hex encoded orderHash to sign.
|
* @param orderHash Hex encoded orderHash to sign.
|
||||||
* @param signerAddress The hex encoded Ethereum address you wish to sign it with. This address
|
* @param signerAddress The hex encoded Ethereum address you wish to sign it with. This address
|
||||||
* must be available via the Web3.Provider supplied to 0x.js.
|
* must be available via the Web3.Provider supplied to 0x.js.
|
||||||
|
* @param shouldAddPersonalMessagePrefix Some signers add the personal message prefix `\x19Ethereum Signed Message`
|
||||||
|
* themselves (e.g Parity Signer, Ledger, TestRPC) and others expect it to already be done by the client
|
||||||
|
* (e.g Metamask). Depending on which signer this request is going to, decide on whether to add the prefix
|
||||||
|
* before sending the request.
|
||||||
* @return An object containing the Elliptic curve signature parameters generated by signing the orderHash.
|
* @return An object containing the Elliptic curve signature parameters generated by signing the orderHash.
|
||||||
*/
|
*/
|
||||||
public async signOrderHashAsync(orderHash: string, signerAddress: string): Promise<ECSignature> {
|
public async signOrderHashAsync(
|
||||||
|
orderHash: string,
|
||||||
|
signerAddress: string,
|
||||||
|
shouldAddPersonalMessagePrefix: boolean,
|
||||||
|
): Promise<ECSignature> {
|
||||||
assert.isHexString('orderHash', orderHash);
|
assert.isHexString('orderHash', orderHash);
|
||||||
await assert.isSenderAddressAsync('signerAddress', signerAddress, this._web3Wrapper);
|
await assert.isSenderAddressAsync('signerAddress', signerAddress, this._web3Wrapper);
|
||||||
|
const normalizedSignerAddress = signerAddress.toLowerCase();
|
||||||
|
|
||||||
let msgHashHex;
|
let msgHashHex = orderHash;
|
||||||
const nodeVersion = await this._web3Wrapper.getNodeVersionAsync();
|
if (shouldAddPersonalMessagePrefix) {
|
||||||
const isParityNode = utils.isParityNode(nodeVersion);
|
|
||||||
const isTestRpc = utils.isTestRpc(nodeVersion);
|
|
||||||
if (isParityNode || isTestRpc) {
|
|
||||||
// Parity and TestRpc nodes add the personalMessage prefix itself
|
|
||||||
msgHashHex = orderHash;
|
|
||||||
} else {
|
|
||||||
const orderHashBuff = ethUtil.toBuffer(orderHash);
|
const orderHashBuff = ethUtil.toBuffer(orderHash);
|
||||||
const msgHashBuff = ethUtil.hashPersonalMessage(orderHashBuff);
|
const msgHashBuff = ethUtil.hashPersonalMessage(orderHashBuff);
|
||||||
msgHashHex = ethUtil.bufferToHex(msgHashBuff);
|
msgHashHex = ethUtil.bufferToHex(msgHashBuff);
|
||||||
}
|
}
|
||||||
|
|
||||||
const signature = await this._web3Wrapper.signTransactionAsync(signerAddress, msgHashHex);
|
const signature = await this._web3Wrapper.signTransactionAsync(normalizedSignerAddress, msgHashHex);
|
||||||
|
|
||||||
// HACK: There is no consensus on whether the signatureHex string should be formatted as
|
// HACK: There is no consensus on whether the signatureHex string should be formatted as
|
||||||
// v + r + s OR r + s + v, and different clients (even different versions of the same client)
|
// v + r + s OR r + s + v, and different clients (even different versions of the same client)
|
||||||
@@ -267,7 +269,7 @@ export class ZeroEx {
|
|||||||
const validVParamValues = [27, 28];
|
const validVParamValues = [27, 28];
|
||||||
const ecSignatureVRS = signatureUtils.parseSignatureHexAsVRS(signature);
|
const ecSignatureVRS = signatureUtils.parseSignatureHexAsVRS(signature);
|
||||||
if (_.includes(validVParamValues, ecSignatureVRS.v)) {
|
if (_.includes(validVParamValues, ecSignatureVRS.v)) {
|
||||||
const isValidVRSSignature = ZeroEx.isValidSignature(orderHash, ecSignatureVRS, signerAddress);
|
const isValidVRSSignature = ZeroEx.isValidSignature(orderHash, ecSignatureVRS, normalizedSignerAddress);
|
||||||
if (isValidVRSSignature) {
|
if (isValidVRSSignature) {
|
||||||
return ecSignatureVRS;
|
return ecSignatureVRS;
|
||||||
}
|
}
|
||||||
@@ -275,7 +277,7 @@ export class ZeroEx {
|
|||||||
|
|
||||||
const ecSignatureRSV = signatureUtils.parseSignatureHexAsRSV(signature);
|
const ecSignatureRSV = signatureUtils.parseSignatureHexAsRSV(signature);
|
||||||
if (_.includes(validVParamValues, ecSignatureRSV.v)) {
|
if (_.includes(validVParamValues, ecSignatureRSV.v)) {
|
||||||
const isValidRSVSignature = ZeroEx.isValidSignature(orderHash, ecSignatureRSV, signerAddress);
|
const isValidRSVSignature = ZeroEx.isValidSignature(orderHash, ecSignatureRSV, normalizedSignerAddress);
|
||||||
if (isValidRSVSignature) {
|
if (isValidRSVSignature) {
|
||||||
return ecSignatureRSV;
|
return ecSignatureRSV;
|
||||||
}
|
}
|
||||||
@@ -291,37 +293,48 @@ export class ZeroEx {
|
|||||||
* @return Transaction receipt with decoded log args.
|
* @return Transaction receipt with decoded log args.
|
||||||
*/
|
*/
|
||||||
public async awaitTransactionMinedAsync(
|
public async awaitTransactionMinedAsync(
|
||||||
txHash: string, pollingIntervalMs = 1000, timeoutMs?: number): Promise<TransactionReceiptWithDecodedLogs> {
|
txHash: string,
|
||||||
|
pollingIntervalMs = 1000,
|
||||||
|
timeoutMs?: number,
|
||||||
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
let timeoutExceeded = false;
|
let timeoutExceeded = false;
|
||||||
if (timeoutMs) {
|
if (timeoutMs) {
|
||||||
setTimeout(() => timeoutExceeded = true, timeoutMs);
|
setTimeout(() => (timeoutExceeded = true), timeoutMs);
|
||||||
}
|
}
|
||||||
|
|
||||||
const txReceiptPromise = new Promise(
|
const txReceiptPromise = new Promise(
|
||||||
(resolve: (receipt: TransactionReceiptWithDecodedLogs) => void, reject) => {
|
(resolve: (receipt: TransactionReceiptWithDecodedLogs) => void, reject) => {
|
||||||
const intervalId = intervalUtils.setAsyncExcludingInterval(async () => {
|
const intervalId = intervalUtils.setAsyncExcludingInterval(
|
||||||
if (timeoutExceeded) {
|
async () => {
|
||||||
intervalUtils.clearAsyncExcludingInterval(intervalId);
|
if (timeoutExceeded) {
|
||||||
return reject(ZeroExError.TransactionMiningTimeout);
|
intervalUtils.clearAsyncExcludingInterval(intervalId);
|
||||||
}
|
return reject(ZeroExError.TransactionMiningTimeout);
|
||||||
|
}
|
||||||
|
|
||||||
const transactionReceipt = await this._web3Wrapper.getTransactionReceiptAsync(txHash);
|
const transactionReceipt = await this._web3Wrapper.getTransactionReceiptAsync(txHash);
|
||||||
if (!_.isNull(transactionReceipt)) {
|
if (!_.isNull(transactionReceipt)) {
|
||||||
intervalUtils.clearAsyncExcludingInterval(intervalId);
|
intervalUtils.clearAsyncExcludingInterval(intervalId);
|
||||||
const logsWithDecodedArgs = _.map(
|
const logsWithDecodedArgs = _.map(
|
||||||
transactionReceipt.logs,
|
transactionReceipt.logs,
|
||||||
this._abiDecoder.tryToDecodeLogOrNoop.bind(this._abiDecoder),
|
this._abiDecoder.tryToDecodeLogOrNoop.bind(this._abiDecoder),
|
||||||
);
|
);
|
||||||
const transactionReceiptWithDecodedLogArgs: TransactionReceiptWithDecodedLogs = {
|
const transactionReceiptWithDecodedLogArgs: TransactionReceiptWithDecodedLogs = {
|
||||||
...transactionReceipt,
|
...transactionReceipt,
|
||||||
logs: logsWithDecodedArgs,
|
logs: logsWithDecodedArgs,
|
||||||
};
|
};
|
||||||
resolve(transactionReceiptWithDecodedLogArgs);
|
resolve(transactionReceiptWithDecodedLogArgs);
|
||||||
}
|
}
|
||||||
}, pollingIntervalMs);
|
},
|
||||||
});
|
pollingIntervalMs,
|
||||||
|
(err: Error) => {
|
||||||
return txReceiptPromise;
|
intervalUtils.clearAsyncExcludingInterval(intervalId);
|
||||||
|
reject(err);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
const txReceipt = await txReceiptPromise;
|
||||||
|
return txReceipt;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* HACK: `TokenWrapper` needs a token transfer proxy address. `TokenTransferProxy` address is fetched from
|
* HACK: `TokenWrapper` needs a token transfer proxy address. `TokenTransferProxy` address is fetched from
|
||||||
|
|||||||
@@ -5,14 +5,14 @@ import * as TokenArtifact from './artifacts/Token.json';
|
|||||||
import * as TokenRegistryArtifact from './artifacts/TokenRegistry.json';
|
import * as TokenRegistryArtifact from './artifacts/TokenRegistry.json';
|
||||||
import * as TokenTransferProxyArtifact from './artifacts/TokenTransferProxy.json';
|
import * as TokenTransferProxyArtifact from './artifacts/TokenTransferProxy.json';
|
||||||
import * as ZRXArtifact from './artifacts/ZRX.json';
|
import * as ZRXArtifact from './artifacts/ZRX.json';
|
||||||
import {Artifact} from './types';
|
import { Artifact } from './types';
|
||||||
|
|
||||||
export const artifacts = {
|
export const artifacts = {
|
||||||
ZRXArtifact: ZRXArtifact as any as Artifact,
|
ZRXArtifact: (ZRXArtifact as any) as Artifact,
|
||||||
DummyTokenArtifact: DummyTokenArtifact as any as Artifact,
|
DummyTokenArtifact: (DummyTokenArtifact as any) as Artifact,
|
||||||
TokenArtifact: TokenArtifact as any as Artifact,
|
TokenArtifact: (TokenArtifact as any) as Artifact,
|
||||||
ExchangeArtifact: ExchangeArtifact as any as Artifact,
|
ExchangeArtifact: (ExchangeArtifact as any) as Artifact,
|
||||||
EtherTokenArtifact: EtherTokenArtifact as any as Artifact,
|
EtherTokenArtifact: (EtherTokenArtifact as any) as Artifact,
|
||||||
TokenRegistryArtifact: TokenRegistryArtifact as any as Artifact,
|
TokenRegistryArtifact: (TokenRegistryArtifact as any) as Artifact,
|
||||||
TokenTransferProxyArtifact: TokenTransferProxyArtifact as any as Artifact,
|
TokenTransferProxyArtifact: (TokenTransferProxyArtifact as any) as Artifact,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
{
|
{
|
||||||
"contract_name": "DummyToken",
|
"contract_name": "DummyToken",
|
||||||
"abi":
|
"abi": [
|
||||||
[
|
|
||||||
{
|
{
|
||||||
"constant": false,
|
"constant": false,
|
||||||
"inputs": [
|
"inputs": [
|
||||||
|
|||||||
@@ -1,284 +1,287 @@
|
|||||||
{
|
{
|
||||||
"contract_name": "EtherToken",
|
"contract_name": "EtherToken",
|
||||||
"abi": [
|
"abi": [
|
||||||
{
|
|
||||||
"constant": true,
|
|
||||||
"inputs": [],
|
|
||||||
"name": "name",
|
|
||||||
"outputs": [
|
|
||||||
{
|
{
|
||||||
"name": "",
|
"constant": true,
|
||||||
"type": "string"
|
"inputs": [],
|
||||||
}
|
"name": "name",
|
||||||
],
|
"outputs": [
|
||||||
"payable": false,
|
{
|
||||||
"type": "function"
|
"name": "",
|
||||||
},
|
"type": "string"
|
||||||
{
|
}
|
||||||
"constant": false,
|
],
|
||||||
"inputs": [
|
"payable": false,
|
||||||
{
|
"type": "function"
|
||||||
"name": "_spender",
|
|
||||||
"type": "address"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "_value",
|
"constant": false,
|
||||||
"type": "uint256"
|
"inputs": [
|
||||||
}
|
{
|
||||||
],
|
"name": "_spender",
|
||||||
"name": "approve",
|
"type": "address"
|
||||||
"outputs": [
|
},
|
||||||
{
|
{
|
||||||
"name": "",
|
"name": "_value",
|
||||||
"type": "bool"
|
"type": "uint256"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"payable": false,
|
"name": "approve",
|
||||||
"type": "function"
|
"outputs": [
|
||||||
},
|
{
|
||||||
{
|
"name": "",
|
||||||
"constant": true,
|
"type": "bool"
|
||||||
"inputs": [],
|
}
|
||||||
"name": "totalSupply",
|
],
|
||||||
"outputs": [
|
"payable": false,
|
||||||
{
|
"type": "function"
|
||||||
"name": "",
|
|
||||||
"type": "uint256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"payable": false,
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"name": "_from",
|
|
||||||
"type": "address"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "_to",
|
"constant": true,
|
||||||
"type": "address"
|
"inputs": [],
|
||||||
|
"name": "totalSupply",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"payable": false,
|
||||||
|
"type": "function"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "_value",
|
"constant": false,
|
||||||
"type": "uint256"
|
"inputs": [
|
||||||
}
|
{
|
||||||
],
|
"name": "_from",
|
||||||
"name": "transferFrom",
|
"type": "address"
|
||||||
"outputs": [
|
},
|
||||||
{
|
{
|
||||||
"name": "",
|
"name": "_to",
|
||||||
"type": "bool"
|
"type": "address"
|
||||||
}
|
},
|
||||||
],
|
{
|
||||||
"payable": false,
|
"name": "_value",
|
||||||
"type": "function"
|
"type": "uint256"
|
||||||
},
|
}
|
||||||
{
|
],
|
||||||
"constant": false,
|
"name": "transferFrom",
|
||||||
"inputs": [
|
"outputs": [
|
||||||
{
|
{
|
||||||
"name": "amount",
|
"name": "",
|
||||||
"type": "uint256"
|
"type": "bool"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"name": "withdraw",
|
"payable": false,
|
||||||
"outputs": [],
|
"type": "function"
|
||||||
"payable": false,
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": true,
|
|
||||||
"inputs": [],
|
|
||||||
"name": "decimals",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "",
|
|
||||||
"type": "uint8"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"payable": false,
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": true,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"name": "_owner",
|
|
||||||
"type": "address"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "balanceOf",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "",
|
|
||||||
"type": "uint256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"payable": false,
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": true,
|
|
||||||
"inputs": [],
|
|
||||||
"name": "symbol",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "",
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"payable": false,
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"name": "_to",
|
|
||||||
"type": "address"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "_value",
|
"constant": false,
|
||||||
"type": "uint256"
|
"inputs": [
|
||||||
}
|
{
|
||||||
],
|
"name": "amount",
|
||||||
"name": "transfer",
|
"type": "uint256"
|
||||||
"outputs": [
|
}
|
||||||
{
|
],
|
||||||
"name": "",
|
"name": "withdraw",
|
||||||
"type": "bool"
|
"outputs": [],
|
||||||
}
|
"payable": false,
|
||||||
],
|
"type": "function"
|
||||||
"payable": false,
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": false,
|
|
||||||
"inputs": [],
|
|
||||||
"name": "deposit",
|
|
||||||
"outputs": [],
|
|
||||||
"payable": true,
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": true,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"name": "_owner",
|
|
||||||
"type": "address"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "_spender",
|
"constant": true,
|
||||||
"type": "address"
|
"inputs": [],
|
||||||
}
|
"name": "decimals",
|
||||||
],
|
"outputs": [
|
||||||
"name": "allowance",
|
{
|
||||||
"outputs": [
|
"name": "",
|
||||||
{
|
"type": "uint8"
|
||||||
"name": "",
|
}
|
||||||
"type": "uint256"
|
],
|
||||||
}
|
"payable": false,
|
||||||
],
|
"type": "function"
|
||||||
"payable": false,
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"payable": true,
|
|
||||||
"type": "fallback"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"anonymous": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"name": "_from",
|
|
||||||
"type": "address"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"indexed": true,
|
"constant": true,
|
||||||
"name": "_to",
|
"inputs": [
|
||||||
"type": "address"
|
{
|
||||||
|
"name": "_owner",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "balanceOf",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"payable": false,
|
||||||
|
"type": "function"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"indexed": false,
|
"constant": true,
|
||||||
"name": "_value",
|
"inputs": [],
|
||||||
"type": "uint256"
|
"name": "symbol",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"payable": false,
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"constant": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"name": "_to",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "_value",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "transfer",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "",
|
||||||
|
"type": "bool"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"payable": false,
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"constant": false,
|
||||||
|
"inputs": [],
|
||||||
|
"name": "deposit",
|
||||||
|
"outputs": [],
|
||||||
|
"payable": true,
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"constant": true,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"name": "_owner",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "_spender",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "allowance",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"payable": false,
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"payable": true,
|
||||||
|
"type": "fallback"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anonymous": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"indexed": true,
|
||||||
|
"name": "_from",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": true,
|
||||||
|
"name": "_to",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "_value",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "Transfer",
|
||||||
|
"type": "event"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anonymous": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"indexed": true,
|
||||||
|
"name": "_owner",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": true,
|
||||||
|
"name": "_spender",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "_value",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "Approval",
|
||||||
|
"type": "event"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anonymous": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"indexed": true,
|
||||||
|
"name": "_owner",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "_value",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "Deposit",
|
||||||
|
"type": "event"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anonymous": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"indexed": true,
|
||||||
|
"name": "_owner",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "_value",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "Withdrawal",
|
||||||
|
"type": "event"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"name": "Transfer",
|
"networks": {
|
||||||
"type": "event"
|
"1": {
|
||||||
},
|
"address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"
|
||||||
{
|
|
||||||
"anonymous": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"name": "_owner",
|
|
||||||
"type": "address"
|
|
||||||
},
|
},
|
||||||
{
|
"3": {
|
||||||
"indexed": true,
|
"address": "0xc00fd9820cd2898cc4c054b7bf142de637ad129a"
|
||||||
"name": "_spender",
|
|
||||||
"type": "address"
|
|
||||||
},
|
},
|
||||||
{
|
"4": {
|
||||||
"indexed": false,
|
"address": "0xc778417e063141139fce010982780140aa0cd5ab"
|
||||||
"name": "_value",
|
},
|
||||||
"type": "uint256"
|
"42": {
|
||||||
|
"address": "0x653e49e301e508a13237c0ddc98ae7d4cd2667a1"
|
||||||
|
},
|
||||||
|
"50": {
|
||||||
|
"address": "0x871dd7c2b4b25e1aa18728e9d5f2af4c4e431f5c"
|
||||||
}
|
}
|
||||||
],
|
|
||||||
"name": "Approval",
|
|
||||||
"type": "event"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"anonymous": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"name": "_owner",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"name": "_value",
|
|
||||||
"type": "uint256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "Deposit",
|
|
||||||
"type": "event"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"anonymous": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"name": "_owner",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"name": "_value",
|
|
||||||
"type": "uint256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "Withdrawal",
|
|
||||||
"type": "event"
|
|
||||||
}
|
}
|
||||||
],
|
|
||||||
"networks": {
|
|
||||||
"1": {
|
|
||||||
"address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"
|
|
||||||
},
|
|
||||||
"3": {
|
|
||||||
"address": "0xc00fd9820cd2898cc4c054b7bf142de637ad129a"
|
|
||||||
},
|
|
||||||
"42": {
|
|
||||||
"address": "0x653e49e301e508a13237c0ddc98ae7d4cd2667a1"
|
|
||||||
},
|
|
||||||
"50": {
|
|
||||||
"address": "0x871dd7c2b4b25e1aa18728e9d5f2af4c4e431f5c"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,172 +1,172 @@
|
|||||||
{
|
{
|
||||||
"contract_name": "Token",
|
"contract_name": "Token",
|
||||||
"abi": [
|
"abi": [
|
||||||
{
|
|
||||||
"constant": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
{
|
||||||
"name": "_spender",
|
"constant": false,
|
||||||
"type": "address"
|
"inputs": [
|
||||||
|
{
|
||||||
|
"name": "_spender",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "_value",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "approve",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "success",
|
||||||
|
"type": "bool"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"payable": false,
|
||||||
|
"type": "function"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "_value",
|
"constant": true,
|
||||||
"type": "uint256"
|
"inputs": [],
|
||||||
}
|
"name": "totalSupply",
|
||||||
],
|
"outputs": [
|
||||||
"name": "approve",
|
{
|
||||||
"outputs": [
|
"name": "supply",
|
||||||
{
|
"type": "uint256"
|
||||||
"name": "success",
|
}
|
||||||
"type": "bool"
|
],
|
||||||
}
|
"payable": false,
|
||||||
],
|
"type": "function"
|
||||||
"payable": false,
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": true,
|
|
||||||
"inputs": [],
|
|
||||||
"name": "totalSupply",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "supply",
|
|
||||||
"type": "uint256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"payable": false,
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"name": "_from",
|
|
||||||
"type": "address"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "_to",
|
"constant": false,
|
||||||
"type": "address"
|
"inputs": [
|
||||||
|
{
|
||||||
|
"name": "_from",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "_to",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "_value",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "transferFrom",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "success",
|
||||||
|
"type": "bool"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"payable": false,
|
||||||
|
"type": "function"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "_value",
|
"constant": true,
|
||||||
"type": "uint256"
|
"inputs": [
|
||||||
}
|
{
|
||||||
],
|
"name": "_owner",
|
||||||
"name": "transferFrom",
|
"type": "address"
|
||||||
"outputs": [
|
}
|
||||||
{
|
],
|
||||||
"name": "success",
|
"name": "balanceOf",
|
||||||
"type": "bool"
|
"outputs": [
|
||||||
}
|
{
|
||||||
],
|
"name": "balance",
|
||||||
"payable": false,
|
"type": "uint256"
|
||||||
"type": "function"
|
}
|
||||||
},
|
],
|
||||||
{
|
"payable": false,
|
||||||
"constant": true,
|
"type": "function"
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"name": "_owner",
|
|
||||||
"type": "address"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "balanceOf",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "balance",
|
|
||||||
"type": "uint256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"payable": false,
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"name": "_to",
|
|
||||||
"type": "address"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "_value",
|
"constant": false,
|
||||||
"type": "uint256"
|
"inputs": [
|
||||||
}
|
{
|
||||||
],
|
"name": "_to",
|
||||||
"name": "transfer",
|
"type": "address"
|
||||||
"outputs": [
|
},
|
||||||
{
|
{
|
||||||
"name": "success",
|
"name": "_value",
|
||||||
"type": "bool"
|
"type": "uint256"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"payable": false,
|
"name": "transfer",
|
||||||
"type": "function"
|
"outputs": [
|
||||||
},
|
{
|
||||||
{
|
"name": "success",
|
||||||
"constant": true,
|
"type": "bool"
|
||||||
"inputs": [
|
}
|
||||||
{
|
],
|
||||||
"name": "_owner",
|
"payable": false,
|
||||||
"type": "address"
|
"type": "function"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "_spender",
|
"constant": true,
|
||||||
"type": "address"
|
"inputs": [
|
||||||
}
|
{
|
||||||
],
|
"name": "_owner",
|
||||||
"name": "allowance",
|
"type": "address"
|
||||||
"outputs": [
|
},
|
||||||
{
|
{
|
||||||
"name": "remaining",
|
"name": "_spender",
|
||||||
"type": "uint256"
|
"type": "address"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"payable": false,
|
"name": "allowance",
|
||||||
"type": "function"
|
"outputs": [
|
||||||
},
|
{
|
||||||
{
|
"name": "remaining",
|
||||||
"anonymous": false,
|
"type": "uint256"
|
||||||
"inputs": [
|
}
|
||||||
{
|
],
|
||||||
"indexed": true,
|
"payable": false,
|
||||||
"name": "_from",
|
"type": "function"
|
||||||
"type": "address"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"indexed": true,
|
"anonymous": false,
|
||||||
"name": "_to",
|
"inputs": [
|
||||||
"type": "address"
|
{
|
||||||
|
"indexed": true,
|
||||||
|
"name": "_from",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": true,
|
||||||
|
"name": "_to",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "_value",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "Transfer",
|
||||||
|
"type": "event"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"indexed": false,
|
"anonymous": false,
|
||||||
"name": "_value",
|
"inputs": [
|
||||||
"type": "uint256"
|
{
|
||||||
|
"indexed": true,
|
||||||
|
"name": "_owner",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": true,
|
||||||
|
"name": "_spender",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "_value",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "Approval",
|
||||||
|
"type": "event"
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
"name": "Transfer",
|
|
||||||
"type": "event"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"anonymous": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"name": "_owner",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"name": "_spender",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"name": "_value",
|
|
||||||
"type": "uint256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "Approval",
|
|
||||||
"type": "event"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,184 +1,187 @@
|
|||||||
{
|
{
|
||||||
"contract_name": "TokenTransferProxy",
|
"contract_name": "TokenTransferProxy",
|
||||||
"abi": [
|
"abi": [
|
||||||
{
|
|
||||||
"constant": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
{
|
||||||
"name": "token",
|
"constant": false,
|
||||||
"type": "address"
|
"inputs": [
|
||||||
|
{
|
||||||
|
"name": "token",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "from",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "to",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "value",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "transferFrom",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "",
|
||||||
|
"type": "bool"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"payable": false,
|
||||||
|
"type": "function"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "from",
|
"constant": false,
|
||||||
"type": "address"
|
"inputs": [
|
||||||
|
{
|
||||||
|
"name": "target",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "addAuthorizedAddress",
|
||||||
|
"outputs": [],
|
||||||
|
"payable": false,
|
||||||
|
"type": "function"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "to",
|
"constant": true,
|
||||||
"type": "address"
|
"inputs": [
|
||||||
|
{
|
||||||
|
"name": "",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "authorities",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"payable": false,
|
||||||
|
"type": "function"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "value",
|
"constant": false,
|
||||||
"type": "uint256"
|
"inputs": [
|
||||||
}
|
{
|
||||||
],
|
"name": "target",
|
||||||
"name": "transferFrom",
|
"type": "address"
|
||||||
"outputs": [
|
}
|
||||||
{
|
],
|
||||||
"name": "",
|
"name": "removeAuthorizedAddress",
|
||||||
"type": "bool"
|
"outputs": [],
|
||||||
}
|
"payable": false,
|
||||||
],
|
"type": "function"
|
||||||
"payable": false,
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"name": "target",
|
|
||||||
"type": "address"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "addAuthorizedAddress",
|
|
||||||
"outputs": [],
|
|
||||||
"payable": false,
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": true,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"name": "",
|
|
||||||
"type": "uint256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "authorities",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "",
|
|
||||||
"type": "address"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"payable": false,
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"name": "target",
|
|
||||||
"type": "address"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "removeAuthorizedAddress",
|
|
||||||
"outputs": [],
|
|
||||||
"payable": false,
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": true,
|
|
||||||
"inputs": [],
|
|
||||||
"name": "owner",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "",
|
|
||||||
"type": "address"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"payable": false,
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": true,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"name": "",
|
|
||||||
"type": "address"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "authorized",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "",
|
|
||||||
"type": "bool"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"payable": false,
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": true,
|
|
||||||
"inputs": [],
|
|
||||||
"name": "getAuthorizedAddresses",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "",
|
|
||||||
"type": "address[]"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"payable": false,
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"name": "newOwner",
|
|
||||||
"type": "address"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "transferOwnership",
|
|
||||||
"outputs": [],
|
|
||||||
"payable": false,
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"anonymous": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"name": "target",
|
|
||||||
"type": "address"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"indexed": true,
|
"constant": true,
|
||||||
"name": "caller",
|
"inputs": [],
|
||||||
"type": "address"
|
"name": "owner",
|
||||||
}
|
"outputs": [
|
||||||
],
|
{
|
||||||
"name": "LogAuthorizedAddressAdded",
|
"name": "",
|
||||||
"type": "event"
|
"type": "address"
|
||||||
},
|
}
|
||||||
{
|
],
|
||||||
"anonymous": false,
|
"payable": false,
|
||||||
"inputs": [
|
"type": "function"
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"name": "target",
|
|
||||||
"type": "address"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"indexed": true,
|
"constant": true,
|
||||||
"name": "caller",
|
"inputs": [
|
||||||
"type": "address"
|
{
|
||||||
|
"name": "",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "authorized",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "",
|
||||||
|
"type": "bool"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"payable": false,
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"constant": true,
|
||||||
|
"inputs": [],
|
||||||
|
"name": "getAuthorizedAddresses",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "",
|
||||||
|
"type": "address[]"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"payable": false,
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"constant": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"name": "newOwner",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "transferOwnership",
|
||||||
|
"outputs": [],
|
||||||
|
"payable": false,
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anonymous": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"indexed": true,
|
||||||
|
"name": "target",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": true,
|
||||||
|
"name": "caller",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "LogAuthorizedAddressAdded",
|
||||||
|
"type": "event"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anonymous": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"indexed": true,
|
||||||
|
"name": "target",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": true,
|
||||||
|
"name": "caller",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "LogAuthorizedAddressRemoved",
|
||||||
|
"type": "event"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"networks": {
|
||||||
|
"1": {
|
||||||
|
"address": "0x8da0d80f5007ef1e431dd2127178d224e32c2ef4"
|
||||||
|
},
|
||||||
|
"3": {
|
||||||
|
"address": "0x4e9aad8184de8833365fea970cd9149372fdf1e6"
|
||||||
|
},
|
||||||
|
"4": {
|
||||||
|
"address": "0xa8e9fa8f91e5ae138c74648c9c304f1c75003a8d"
|
||||||
|
},
|
||||||
|
"42": {
|
||||||
|
"address": "0x087eed4bc1ee3de49befbd66c662b434b15d49d4"
|
||||||
|
},
|
||||||
|
"50": {
|
||||||
|
"address": "0x1dc4c1cefef38a777b15aa20260a54e584b16c48"
|
||||||
}
|
}
|
||||||
],
|
|
||||||
"name": "LogAuthorizedAddressRemoved",
|
|
||||||
"type": "event"
|
|
||||||
}
|
}
|
||||||
],
|
|
||||||
"networks": {
|
|
||||||
"1": {
|
|
||||||
"address": "0x8da0d80f5007ef1e431dd2127178d224e32c2ef4"
|
|
||||||
},
|
|
||||||
"3": {
|
|
||||||
"address": "0x4e9aad8184de8833365fea970cd9149372fdf1e6"
|
|
||||||
},
|
|
||||||
"42": {
|
|
||||||
"address": "0x087eed4bc1ee3de49befbd66c662b434b15d49d4"
|
|
||||||
},
|
|
||||||
"50": {
|
|
||||||
"address": "0x1dc4c1cefef38a777b15aa20260a54e584b16c48"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,20 @@
|
|||||||
{
|
{
|
||||||
"contract_name": "ZRX",
|
"contract_name": "ZRX",
|
||||||
"networks": {
|
"networks": {
|
||||||
"1": {
|
"1": {
|
||||||
"address": "0xe41d2489571d322189246dafa5ebde1f4699f498"
|
"address": "0xe41d2489571d322189246dafa5ebde1f4699f498"
|
||||||
},
|
},
|
||||||
"3": {
|
"3": {
|
||||||
"address": "0xa8e9fa8f91e5ae138c74648c9c304f1c75003a8d"
|
"address": "0xa8e9fa8f91e5ae138c74648c9c304f1c75003a8d"
|
||||||
},
|
},
|
||||||
"42": {
|
"4": {
|
||||||
"address": "0x6ff6c0ff1d68b964901f986d4c9fa3ac68346570"
|
"address": "0x00f58d6d585f84b2d7267940cede30ce2fe6eae8"
|
||||||
},
|
},
|
||||||
"50": {
|
"42": {
|
||||||
"address": "0x1d7022f5b17d2f8b695918fb48fa1089c9f85401"
|
"address": "0x6ff6c0ff1d68b964901f986d4c9fa3ac68346570"
|
||||||
|
},
|
||||||
|
"50": {
|
||||||
|
"address": "0x1d7022f5b17d2f8b695918fb48fa1089c9f85401"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,27 +1,26 @@
|
|||||||
import {intervalUtils} from '@0xproject/utils';
|
import { BlockParamLiteral, LogWithDecodedArgs, RawLog } from '@0xproject/types';
|
||||||
import {Web3Wrapper} from '@0xproject/web3-wrapper';
|
import { AbiDecoder, intervalUtils } from '@0xproject/utils';
|
||||||
import {Block, BlockAndLogStreamer} from 'ethereumjs-blockstream';
|
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||||
|
import { Block, BlockAndLogStreamer } from 'ethereumjs-blockstream';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import * as Web3 from 'web3';
|
import * as Web3 from 'web3';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Artifact,
|
Artifact,
|
||||||
BlockParamLiteral,
|
|
||||||
BlockRange,
|
BlockRange,
|
||||||
ContractEventArgs,
|
ContractEventArgs,
|
||||||
ContractEvents,
|
ContractEvents,
|
||||||
EventCallback,
|
EventCallback,
|
||||||
IndexedFilterValues,
|
IndexedFilterValues,
|
||||||
InternalZeroExError,
|
InternalZeroExError,
|
||||||
LogWithDecodedArgs,
|
|
||||||
RawLog,
|
|
||||||
ZeroExError,
|
ZeroExError,
|
||||||
} from '../types';
|
} from '../types';
|
||||||
import {AbiDecoder} from '../utils/abi_decoder';
|
import { constants } from '../utils/constants';
|
||||||
import {constants} from '../utils/constants';
|
import { filterUtils } from '../utils/filter_utils';
|
||||||
import {filterUtils} from '../utils/filter_utils';
|
|
||||||
|
|
||||||
const CONTRACT_NAME_TO_NOT_FOUND_ERROR: {[contractName: string]: ZeroExError} = {
|
const CONTRACT_NAME_TO_NOT_FOUND_ERROR: {
|
||||||
|
[contractName: string]: ZeroExError;
|
||||||
|
} = {
|
||||||
ZRX: ZeroExError.ZRXContractDoesNotExist,
|
ZRX: ZeroExError.ZRXContractDoesNotExist,
|
||||||
EtherToken: ZeroExError.EtherTokenContractDoesNotExist,
|
EtherToken: ZeroExError.EtherTokenContractDoesNotExist,
|
||||||
Token: ZeroExError.TokenContractDoesNotExist,
|
Token: ZeroExError.TokenContractDoesNotExist,
|
||||||
@@ -32,14 +31,16 @@ const CONTRACT_NAME_TO_NOT_FOUND_ERROR: {[contractName: string]: ZeroExError} =
|
|||||||
|
|
||||||
export class ContractWrapper {
|
export class ContractWrapper {
|
||||||
protected _web3Wrapper: Web3Wrapper;
|
protected _web3Wrapper: Web3Wrapper;
|
||||||
private _networkId: number;
|
protected _networkId: number;
|
||||||
private _abiDecoder?: AbiDecoder;
|
private _abiDecoder?: AbiDecoder;
|
||||||
private _blockAndLogStreamerIfExists: BlockAndLogStreamer|undefined;
|
private _blockAndLogStreamerIfExists?: BlockAndLogStreamer;
|
||||||
private _blockAndLogStreamInterval: NodeJS.Timer;
|
private _blockAndLogStreamIntervalIfExists?: NodeJS.Timer;
|
||||||
private _filters: {[filterToken: string]: Web3.FilterObject};
|
private _filters: { [filterToken: string]: Web3.FilterObject };
|
||||||
private _filterCallbacks: {[filterToken: string]: EventCallback<ContractEventArgs>};
|
private _filterCallbacks: {
|
||||||
private _onLogAddedSubscriptionToken: string|undefined;
|
[filterToken: string]: EventCallback<ContractEventArgs>;
|
||||||
private _onLogRemovedSubscriptionToken: string|undefined;
|
};
|
||||||
|
private _onLogAddedSubscriptionToken: string | undefined;
|
||||||
|
private _onLogRemovedSubscriptionToken: string | undefined;
|
||||||
constructor(web3Wrapper: Web3Wrapper, networkId: number, abiDecoder?: AbiDecoder) {
|
constructor(web3Wrapper: Web3Wrapper, networkId: number, abiDecoder?: AbiDecoder) {
|
||||||
this._web3Wrapper = web3Wrapper;
|
this._web3Wrapper = web3Wrapper;
|
||||||
this._networkId = networkId;
|
this._networkId = networkId;
|
||||||
@@ -50,7 +51,7 @@ export class ContractWrapper {
|
|||||||
this._onLogAddedSubscriptionToken = undefined;
|
this._onLogAddedSubscriptionToken = undefined;
|
||||||
this._onLogRemovedSubscriptionToken = undefined;
|
this._onLogRemovedSubscriptionToken = undefined;
|
||||||
}
|
}
|
||||||
protected unsubscribeAll(): void {
|
protected _unsubscribeAll(): void {
|
||||||
const filterTokens = _.keys(this._filterCallbacks);
|
const filterTokens = _.keys(this._filterCallbacks);
|
||||||
_.each(filterTokens, filterToken => {
|
_.each(filterTokens, filterToken => {
|
||||||
this._unsubscribe(filterToken);
|
this._unsubscribe(filterToken);
|
||||||
@@ -71,36 +72,46 @@ export class ContractWrapper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
protected _subscribe<ArgsType extends ContractEventArgs>(
|
protected _subscribe<ArgsType extends ContractEventArgs>(
|
||||||
address: string, eventName: ContractEvents, indexFilterValues: IndexedFilterValues, abi: Web3.ContractAbi,
|
address: string,
|
||||||
callback: EventCallback<ArgsType>): string {
|
eventName: ContractEvents,
|
||||||
|
indexFilterValues: IndexedFilterValues,
|
||||||
|
abi: Web3.ContractAbi,
|
||||||
|
callback: EventCallback<ArgsType>,
|
||||||
|
): string {
|
||||||
const filter = filterUtils.getFilter(address, eventName, indexFilterValues, abi);
|
const filter = filterUtils.getFilter(address, eventName, indexFilterValues, abi);
|
||||||
if (_.isUndefined(this._blockAndLogStreamerIfExists)) {
|
if (_.isUndefined(this._blockAndLogStreamerIfExists)) {
|
||||||
this._startBlockAndLogStream();
|
this._startBlockAndLogStream();
|
||||||
}
|
}
|
||||||
const filterToken = filterUtils.generateUUID();
|
const filterToken = filterUtils.generateUUID();
|
||||||
this._filters[filterToken] = filter;
|
this._filters[filterToken] = filter;
|
||||||
this._filterCallbacks[filterToken] = callback;
|
this._filterCallbacks[filterToken] = callback as EventCallback<ContractEventArgs>;
|
||||||
return filterToken;
|
return filterToken;
|
||||||
}
|
}
|
||||||
protected async _getLogsAsync<ArgsType extends ContractEventArgs>(
|
protected async _getLogsAsync<ArgsType extends ContractEventArgs>(
|
||||||
address: string, eventName: ContractEvents, blockRange: BlockRange,
|
address: string,
|
||||||
indexFilterValues: IndexedFilterValues, abi: Web3.ContractAbi): Promise<Array<LogWithDecodedArgs<ArgsType>>> {
|
eventName: ContractEvents,
|
||||||
|
blockRange: BlockRange,
|
||||||
|
indexFilterValues: IndexedFilterValues,
|
||||||
|
abi: Web3.ContractAbi,
|
||||||
|
): Promise<Array<LogWithDecodedArgs<ArgsType>>> {
|
||||||
const filter = filterUtils.getFilter(address, eventName, indexFilterValues, abi, blockRange);
|
const filter = filterUtils.getFilter(address, eventName, indexFilterValues, abi, blockRange);
|
||||||
const logs = await this._web3Wrapper.getLogsAsync(filter);
|
const logs = await this._web3Wrapper.getLogsAsync(filter);
|
||||||
const logsWithDecodedArguments = _.map(logs, this._tryToDecodeLogOrNoop.bind(this));
|
const logsWithDecodedArguments = _.map(logs, this._tryToDecodeLogOrNoop.bind(this));
|
||||||
return logsWithDecodedArguments;
|
return logsWithDecodedArguments;
|
||||||
}
|
}
|
||||||
protected _tryToDecodeLogOrNoop<ArgsType extends ContractEventArgs>(
|
protected _tryToDecodeLogOrNoop<ArgsType extends ContractEventArgs>(
|
||||||
log: Web3.LogEntry): LogWithDecodedArgs<ArgsType>|RawLog {
|
log: Web3.LogEntry,
|
||||||
|
): LogWithDecodedArgs<ArgsType> | RawLog {
|
||||||
if (_.isUndefined(this._abiDecoder)) {
|
if (_.isUndefined(this._abiDecoder)) {
|
||||||
throw new Error(InternalZeroExError.NoAbiDecoder);
|
throw new Error(InternalZeroExError.NoAbiDecoder);
|
||||||
}
|
}
|
||||||
const logWithDecodedArgs = this._abiDecoder.tryToDecodeLogOrNoop(log);
|
const logWithDecodedArgs = this._abiDecoder.tryToDecodeLogOrNoop(log);
|
||||||
return logWithDecodedArgs;
|
return logWithDecodedArgs;
|
||||||
}
|
}
|
||||||
protected async _instantiateContractIfExistsAsync(
|
protected async _getContractAbiAndAddressFromArtifactsAsync(
|
||||||
artifact: Artifact, addressIfExists?: string,
|
artifact: Artifact,
|
||||||
): Promise<Web3.ContractInstance> {
|
addressIfExists?: string,
|
||||||
|
): Promise<[Web3.ContractAbi, string]> {
|
||||||
let contractAddress: string;
|
let contractAddress: string;
|
||||||
if (_.isUndefined(addressIfExists)) {
|
if (_.isUndefined(addressIfExists)) {
|
||||||
if (_.isUndefined(artifact.networks[this._networkId])) {
|
if (_.isUndefined(artifact.networks[this._networkId])) {
|
||||||
@@ -114,10 +125,8 @@ export class ContractWrapper {
|
|||||||
if (!doesContractExist) {
|
if (!doesContractExist) {
|
||||||
throw new Error(CONTRACT_NAME_TO_NOT_FOUND_ERROR[artifact.contract_name]);
|
throw new Error(CONTRACT_NAME_TO_NOT_FOUND_ERROR[artifact.contract_name]);
|
||||||
}
|
}
|
||||||
const contractInstance = this._web3Wrapper.getContractInstance(
|
const abiAndAddress: [Web3.ContractAbi, string] = [artifact.abi, contractAddress];
|
||||||
artifact.abi, contractAddress,
|
return abiAndAddress;
|
||||||
);
|
|
||||||
return contractInstance;
|
|
||||||
}
|
}
|
||||||
protected _getContractAddress(artifact: Artifact, addressIfExists?: string): string {
|
protected _getContractAddress(artifact: Artifact, addressIfExists?: string): string {
|
||||||
if (_.isUndefined(addressIfExists)) {
|
if (_.isUndefined(addressIfExists)) {
|
||||||
@@ -152,8 +161,10 @@ export class ContractWrapper {
|
|||||||
);
|
);
|
||||||
const catchAllLogFilter = {};
|
const catchAllLogFilter = {};
|
||||||
this._blockAndLogStreamerIfExists.addLogFilter(catchAllLogFilter);
|
this._blockAndLogStreamerIfExists.addLogFilter(catchAllLogFilter);
|
||||||
this._blockAndLogStreamInterval = intervalUtils.setAsyncExcludingInterval(
|
this._blockAndLogStreamIntervalIfExists = intervalUtils.setAsyncExcludingInterval(
|
||||||
this._reconcileBlockAsync.bind(this), constants.DEFAULT_BLOCK_POLLING_INTERVAL,
|
this._reconcileBlockAsync.bind(this),
|
||||||
|
constants.DEFAULT_BLOCK_POLLING_INTERVAL,
|
||||||
|
this._onReconcileBlockError.bind(this),
|
||||||
);
|
);
|
||||||
let isRemoved = false;
|
let isRemoved = false;
|
||||||
this._onLogAddedSubscriptionToken = this._blockAndLogStreamerIfExists.subscribeToOnLogAdded(
|
this._onLogAddedSubscriptionToken = this._blockAndLogStreamerIfExists.subscribeToOnLogAdded(
|
||||||
@@ -164,28 +175,30 @@ export class ContractWrapper {
|
|||||||
this._onLogStateChanged.bind(this, isRemoved),
|
this._onLogStateChanged.bind(this, isRemoved),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
private _onReconcileBlockError(err: Error): void {
|
||||||
|
const filterTokens = _.keys(this._filterCallbacks);
|
||||||
|
_.each(filterTokens, filterToken => {
|
||||||
|
this._unsubscribe(filterToken, err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
private _setNetworkId(networkId: number): void {
|
||||||
|
this._networkId = networkId;
|
||||||
|
}
|
||||||
private _stopBlockAndLogStream(): void {
|
private _stopBlockAndLogStream(): void {
|
||||||
if (_.isUndefined(this._blockAndLogStreamerIfExists)) {
|
if (_.isUndefined(this._blockAndLogStreamerIfExists)) {
|
||||||
throw new Error(ZeroExError.SubscriptionNotFound);
|
throw new Error(ZeroExError.SubscriptionNotFound);
|
||||||
}
|
}
|
||||||
this._blockAndLogStreamerIfExists.unsubscribeFromOnLogAdded(this._onLogAddedSubscriptionToken as string);
|
this._blockAndLogStreamerIfExists.unsubscribeFromOnLogAdded(this._onLogAddedSubscriptionToken as string);
|
||||||
this._blockAndLogStreamerIfExists.unsubscribeFromOnLogRemoved(this._onLogRemovedSubscriptionToken as string);
|
this._blockAndLogStreamerIfExists.unsubscribeFromOnLogRemoved(this._onLogRemovedSubscriptionToken as string);
|
||||||
intervalUtils.clearAsyncExcludingInterval(this._blockAndLogStreamInterval);
|
intervalUtils.clearAsyncExcludingInterval(this._blockAndLogStreamIntervalIfExists as NodeJS.Timer);
|
||||||
delete this._blockAndLogStreamerIfExists;
|
delete this._blockAndLogStreamerIfExists;
|
||||||
}
|
}
|
||||||
private async _reconcileBlockAsync(): Promise<void> {
|
private async _reconcileBlockAsync(): Promise<void> {
|
||||||
try {
|
const latestBlock = await this._web3Wrapper.getBlockAsync(BlockParamLiteral.Latest);
|
||||||
const latestBlock = await this._web3Wrapper.getBlockAsync(BlockParamLiteral.Latest);
|
// We need to coerce to Block type cause Web3.Block includes types for mempool blocks
|
||||||
// We need to coerce to Block type cause Web3.Block includes types for mempool blocks
|
if (!_.isUndefined(this._blockAndLogStreamerIfExists)) {
|
||||||
if (!_.isUndefined(this._blockAndLogStreamerIfExists)) {
|
// If we clear the interval while fetching the block - this._blockAndLogStreamer will be undefined
|
||||||
// If we clear the interval while fetching the block - this._blockAndLogStreamer will be undefined
|
await this._blockAndLogStreamerIfExists.reconcileNewBlock((latestBlock as any) as Block);
|
||||||
await this._blockAndLogStreamerIfExists.reconcileNewBlock(latestBlock as any as Block);
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
const filterTokens = _.keys(this._filterCallbacks);
|
|
||||||
_.each(filterTokens, filterToken => {
|
|
||||||
this._unsubscribe(filterToken, err);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,32 +1,25 @@
|
|||||||
import {schemas} from '@0xproject/json-schemas';
|
import { schemas } from '@0xproject/json-schemas';
|
||||||
import {Web3Wrapper} from '@0xproject/web3-wrapper';
|
import { LogWithDecodedArgs } from '@0xproject/types';
|
||||||
import BigNumber from 'bignumber.js';
|
import { AbiDecoder, BigNumber } from '@0xproject/utils';
|
||||||
|
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import {artifacts} from '../artifacts';
|
import { artifacts } from '../artifacts';
|
||||||
import {
|
import { BlockRange, EventCallback, IndexedFilterValues, TransactionOpts, ZeroExError } from '../types';
|
||||||
BlockRange,
|
import { assert } from '../utils/assert';
|
||||||
EtherTokenContractEventArgs,
|
|
||||||
EtherTokenEvents,
|
|
||||||
EventCallback,
|
|
||||||
IndexedFilterValues,
|
|
||||||
LogWithDecodedArgs,
|
|
||||||
TransactionOpts,
|
|
||||||
ZeroExError,
|
|
||||||
} from '../types';
|
|
||||||
import {AbiDecoder} from '../utils/abi_decoder';
|
|
||||||
import {assert} from '../utils/assert';
|
|
||||||
|
|
||||||
import {ContractWrapper} from './contract_wrapper';
|
import { ContractWrapper } from './contract_wrapper';
|
||||||
import {EtherTokenContract} from './generated/ether_token';
|
import { EtherTokenContract, EtherTokenContractEventArgs, EtherTokenEvents } from './generated/ether_token';
|
||||||
import {TokenWrapper} from './token_wrapper';
|
import { TokenWrapper } from './token_wrapper';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class includes all the functionality related to interacting with a wrapped Ether ERC20 token contract.
|
* This class includes all the functionality related to interacting with a wrapped Ether ERC20 token contract.
|
||||||
* The caller can convert ETH into the equivalent number of wrapped ETH ERC20 tokens and back.
|
* The caller can convert ETH into the equivalent number of wrapped ETH ERC20 tokens and back.
|
||||||
*/
|
*/
|
||||||
export class EtherTokenWrapper extends ContractWrapper {
|
export class EtherTokenWrapper extends ContractWrapper {
|
||||||
private _etherTokenContractsByAddress: {[address: string]: EtherTokenContract} = {};
|
private _etherTokenContractsByAddress: {
|
||||||
|
[address: string]: EtherTokenContract;
|
||||||
|
} = {};
|
||||||
private _tokenWrapper: TokenWrapper;
|
private _tokenWrapper: TokenWrapper;
|
||||||
constructor(web3Wrapper: Web3Wrapper, networkId: number, abiDecoder: AbiDecoder, tokenWrapper: TokenWrapper) {
|
constructor(web3Wrapper: Web3Wrapper, networkId: number, abiDecoder: AbiDecoder, tokenWrapper: TokenWrapper) {
|
||||||
super(web3Wrapper, networkId, abiDecoder);
|
super(web3Wrapper, networkId, abiDecoder);
|
||||||
@@ -43,17 +36,23 @@ export class EtherTokenWrapper extends ContractWrapper {
|
|||||||
* @return Transaction hash.
|
* @return Transaction hash.
|
||||||
*/
|
*/
|
||||||
public async depositAsync(
|
public async depositAsync(
|
||||||
etherTokenAddress: string, amountInWei: BigNumber, depositor: string, txOpts: TransactionOpts = {},
|
etherTokenAddress: string,
|
||||||
|
amountInWei: BigNumber,
|
||||||
|
depositor: string,
|
||||||
|
txOpts: TransactionOpts = {},
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
|
assert.isETHAddressHex('etherTokenAddress', etherTokenAddress);
|
||||||
assert.isValidBaseUnitAmount('amountInWei', amountInWei);
|
assert.isValidBaseUnitAmount('amountInWei', amountInWei);
|
||||||
await assert.isSenderAddressAsync('depositor', depositor, this._web3Wrapper);
|
await assert.isSenderAddressAsync('depositor', depositor, this._web3Wrapper);
|
||||||
|
const normalizedEtherTokenAddress = etherTokenAddress.toLowerCase();
|
||||||
|
const normalizedDepositorAddress = depositor.toLowerCase();
|
||||||
|
|
||||||
const ethBalanceInWei = await this._web3Wrapper.getBalanceInWeiAsync(depositor);
|
const ethBalanceInWei = await this._web3Wrapper.getBalanceInWeiAsync(normalizedDepositorAddress);
|
||||||
assert.assert(ethBalanceInWei.gte(amountInWei), ZeroExError.InsufficientEthBalanceForDeposit);
|
assert.assert(ethBalanceInWei.gte(amountInWei), ZeroExError.InsufficientEthBalanceForDeposit);
|
||||||
|
|
||||||
const wethContract = await this._getEtherTokenContractAsync(etherTokenAddress);
|
const wethContract = await this._getEtherTokenContractAsync(normalizedEtherTokenAddress);
|
||||||
const txHash = await wethContract.deposit.sendTransactionAsync({
|
const txHash = await wethContract.deposit.sendTransactionAsync({
|
||||||
from: depositor,
|
from: normalizedDepositorAddress,
|
||||||
value: amountInWei,
|
value: amountInWei,
|
||||||
gas: txOpts.gasLimit,
|
gas: txOpts.gasLimit,
|
||||||
gasPrice: txOpts.gasPrice,
|
gasPrice: txOpts.gasPrice,
|
||||||
@@ -70,17 +69,26 @@ export class EtherTokenWrapper extends ContractWrapper {
|
|||||||
* @return Transaction hash.
|
* @return Transaction hash.
|
||||||
*/
|
*/
|
||||||
public async withdrawAsync(
|
public async withdrawAsync(
|
||||||
etherTokenAddress: string, amountInWei: BigNumber, withdrawer: string, txOpts: TransactionOpts = {},
|
etherTokenAddress: string,
|
||||||
|
amountInWei: BigNumber,
|
||||||
|
withdrawer: string,
|
||||||
|
txOpts: TransactionOpts = {},
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
assert.isValidBaseUnitAmount('amountInWei', amountInWei);
|
assert.isValidBaseUnitAmount('amountInWei', amountInWei);
|
||||||
|
assert.isETHAddressHex('etherTokenAddress', etherTokenAddress);
|
||||||
await assert.isSenderAddressAsync('withdrawer', withdrawer, this._web3Wrapper);
|
await assert.isSenderAddressAsync('withdrawer', withdrawer, this._web3Wrapper);
|
||||||
|
const normalizedEtherTokenAddress = etherTokenAddress.toLowerCase();
|
||||||
|
const normalizedWithdrawerAddress = withdrawer.toLowerCase();
|
||||||
|
|
||||||
const WETHBalanceInBaseUnits = await this._tokenWrapper.getBalanceAsync(etherTokenAddress, withdrawer);
|
const WETHBalanceInBaseUnits = await this._tokenWrapper.getBalanceAsync(
|
||||||
|
normalizedEtherTokenAddress,
|
||||||
|
normalizedWithdrawerAddress,
|
||||||
|
);
|
||||||
assert.assert(WETHBalanceInBaseUnits.gte(amountInWei), ZeroExError.InsufficientWEthBalanceForWithdrawal);
|
assert.assert(WETHBalanceInBaseUnits.gte(amountInWei), ZeroExError.InsufficientWEthBalanceForWithdrawal);
|
||||||
|
|
||||||
const wethContract = await this._getEtherTokenContractAsync(etherTokenAddress);
|
const wethContract = await this._getEtherTokenContractAsync(normalizedEtherTokenAddress);
|
||||||
const txHash = await wethContract.withdraw.sendTransactionAsync(amountInWei, {
|
const txHash = await wethContract.withdraw.sendTransactionAsync(amountInWei, {
|
||||||
from: withdrawer,
|
from: normalizedWithdrawerAddress,
|
||||||
gas: txOpts.gasLimit,
|
gas: txOpts.gasLimit,
|
||||||
gasPrice: txOpts.gasPrice,
|
gasPrice: txOpts.gasPrice,
|
||||||
});
|
});
|
||||||
@@ -96,14 +104,22 @@ export class EtherTokenWrapper extends ContractWrapper {
|
|||||||
* @return Array of logs that match the parameters
|
* @return Array of logs that match the parameters
|
||||||
*/
|
*/
|
||||||
public async getLogsAsync<ArgsType extends EtherTokenContractEventArgs>(
|
public async getLogsAsync<ArgsType extends EtherTokenContractEventArgs>(
|
||||||
etherTokenAddress: string, eventName: EtherTokenEvents, blockRange: BlockRange,
|
etherTokenAddress: string,
|
||||||
indexFilterValues: IndexedFilterValues): Promise<Array<LogWithDecodedArgs<ArgsType>>> {
|
eventName: EtherTokenEvents,
|
||||||
|
blockRange: BlockRange,
|
||||||
|
indexFilterValues: IndexedFilterValues,
|
||||||
|
): Promise<Array<LogWithDecodedArgs<ArgsType>>> {
|
||||||
assert.isETHAddressHex('etherTokenAddress', etherTokenAddress);
|
assert.isETHAddressHex('etherTokenAddress', etherTokenAddress);
|
||||||
|
const normalizedEtherTokenAddress = etherTokenAddress.toLowerCase();
|
||||||
assert.doesBelongToStringEnum('eventName', eventName, EtherTokenEvents);
|
assert.doesBelongToStringEnum('eventName', eventName, EtherTokenEvents);
|
||||||
assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema);
|
assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema);
|
||||||
assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
|
assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
|
||||||
const logs = await this._getLogsAsync<ArgsType>(
|
const logs = await this._getLogsAsync<ArgsType>(
|
||||||
etherTokenAddress, eventName, blockRange, indexFilterValues, artifacts.EtherTokenArtifact.abi,
|
normalizedEtherTokenAddress,
|
||||||
|
eventName,
|
||||||
|
blockRange,
|
||||||
|
indexFilterValues,
|
||||||
|
artifacts.EtherTokenArtifact.abi,
|
||||||
);
|
);
|
||||||
return logs;
|
return logs;
|
||||||
}
|
}
|
||||||
@@ -117,14 +133,22 @@ export class EtherTokenWrapper extends ContractWrapper {
|
|||||||
* @return Subscription token used later to unsubscribe
|
* @return Subscription token used later to unsubscribe
|
||||||
*/
|
*/
|
||||||
public subscribe<ArgsType extends EtherTokenContractEventArgs>(
|
public subscribe<ArgsType extends EtherTokenContractEventArgs>(
|
||||||
etherTokenAddress: string, eventName: EtherTokenEvents, indexFilterValues: IndexedFilterValues,
|
etherTokenAddress: string,
|
||||||
callback: EventCallback<ArgsType>): string {
|
eventName: EtherTokenEvents,
|
||||||
|
indexFilterValues: IndexedFilterValues,
|
||||||
|
callback: EventCallback<ArgsType>,
|
||||||
|
): string {
|
||||||
assert.isETHAddressHex('etherTokenAddress', etherTokenAddress);
|
assert.isETHAddressHex('etherTokenAddress', etherTokenAddress);
|
||||||
|
const normalizedEtherTokenAddress = etherTokenAddress.toLowerCase();
|
||||||
assert.doesBelongToStringEnum('eventName', eventName, EtherTokenEvents);
|
assert.doesBelongToStringEnum('eventName', eventName, EtherTokenEvents);
|
||||||
assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
|
assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
|
||||||
assert.isFunction('callback', callback);
|
assert.isFunction('callback', callback);
|
||||||
const subscriptionToken = this._subscribe<ArgsType>(
|
const subscriptionToken = this._subscribe<ArgsType>(
|
||||||
etherTokenAddress, eventName, indexFilterValues, artifacts.EtherTokenArtifact.abi, callback,
|
normalizedEtherTokenAddress,
|
||||||
|
eventName,
|
||||||
|
indexFilterValues,
|
||||||
|
artifacts.EtherTokenArtifact.abi,
|
||||||
|
callback,
|
||||||
);
|
);
|
||||||
return subscriptionToken;
|
return subscriptionToken;
|
||||||
}
|
}
|
||||||
@@ -139,7 +163,20 @@ export class EtherTokenWrapper extends ContractWrapper {
|
|||||||
* Cancels all existing subscriptions
|
* Cancels all existing subscriptions
|
||||||
*/
|
*/
|
||||||
public unsubscribeAll(): void {
|
public unsubscribeAll(): void {
|
||||||
super.unsubscribeAll();
|
super._unsubscribeAll();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Retrieves the Ethereum address of the EtherToken contract deployed on the network
|
||||||
|
* that the user-passed web3 provider is connected to. If it's not Kovan, Ropsten, Rinkeby, Mainnet or TestRPC
|
||||||
|
* (networkId: 50), it will return undefined (e.g a private network).
|
||||||
|
* @returns The Ethereum address of the EtherToken contract or undefined.
|
||||||
|
*/
|
||||||
|
public getContractAddressIfExists(): string | undefined {
|
||||||
|
const networkSpecificArtifact = artifacts.EtherTokenArtifact.networks[this._networkId];
|
||||||
|
const contractAddressIfExists = _.isUndefined(networkSpecificArtifact)
|
||||||
|
? undefined
|
||||||
|
: networkSpecificArtifact.address;
|
||||||
|
return contractAddressIfExists;
|
||||||
}
|
}
|
||||||
private _invalidateContractInstance(): void {
|
private _invalidateContractInstance(): void {
|
||||||
this.unsubscribeAll();
|
this.unsubscribeAll();
|
||||||
@@ -150,10 +187,11 @@ export class EtherTokenWrapper extends ContractWrapper {
|
|||||||
if (!_.isUndefined(etherTokenContract)) {
|
if (!_.isUndefined(etherTokenContract)) {
|
||||||
return etherTokenContract;
|
return etherTokenContract;
|
||||||
}
|
}
|
||||||
const web3ContractInstance = await this._instantiateContractIfExistsAsync(
|
const [abi, address] = await this._getContractAbiAndAddressFromArtifactsAsync(
|
||||||
artifacts.EtherTokenArtifact, etherTokenAddress,
|
artifacts.EtherTokenArtifact,
|
||||||
|
etherTokenAddress,
|
||||||
);
|
);
|
||||||
const contractInstance = new EtherTokenContract(web3ContractInstance, this._web3Wrapper.getContractDefaults());
|
const contractInstance = new EtherTokenContract(this._web3Wrapper, abi, address);
|
||||||
etherTokenContract = contractInstance;
|
etherTokenContract = contractInstance;
|
||||||
this._etherTokenContractsByAddress[etherTokenAddress] = etherTokenContract;
|
this._etherTokenContractsByAddress[etherTokenAddress] = etherTokenContract;
|
||||||
return etherTokenContract;
|
return etherTokenContract;
|
||||||
|
|||||||
@@ -1,23 +1,18 @@
|
|||||||
import {schemas} from '@0xproject/json-schemas';
|
import { schemas } from '@0xproject/json-schemas';
|
||||||
import {Web3Wrapper} from '@0xproject/web3-wrapper';
|
import { BlockParamLiteral, DecodedLogArgs, LogWithDecodedArgs } from '@0xproject/types';
|
||||||
import BigNumber from 'bignumber.js';
|
import { AbiDecoder, BigNumber } from '@0xproject/utils';
|
||||||
|
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import * as Web3 from 'web3';
|
import * as Web3 from 'web3';
|
||||||
|
|
||||||
import {artifacts} from '../artifacts';
|
import { artifacts } from '../artifacts';
|
||||||
import {
|
import {
|
||||||
BlockParamLiteral,
|
|
||||||
BlockRange,
|
BlockRange,
|
||||||
DecodedLogArgs,
|
|
||||||
ECSignature,
|
ECSignature,
|
||||||
EventCallback,
|
EventCallback,
|
||||||
ExchangeContractErrCodes,
|
ExchangeContractErrCodes,
|
||||||
ExchangeContractErrs,
|
ExchangeContractErrs,
|
||||||
ExchangeContractEventArgs,
|
|
||||||
ExchangeEvents,
|
|
||||||
IndexedFilterValues,
|
IndexedFilterValues,
|
||||||
LogErrorContractEventArgs,
|
|
||||||
LogWithDecodedArgs,
|
|
||||||
MethodOpts,
|
MethodOpts,
|
||||||
Order,
|
Order,
|
||||||
OrderAddresses,
|
OrderAddresses,
|
||||||
@@ -28,16 +23,20 @@ import {
|
|||||||
SignedOrder,
|
SignedOrder,
|
||||||
ValidateOrderFillableOpts,
|
ValidateOrderFillableOpts,
|
||||||
} from '../types';
|
} from '../types';
|
||||||
import {AbiDecoder} from '../utils/abi_decoder';
|
import { assert } from '../utils/assert';
|
||||||
import {assert} from '../utils/assert';
|
import { decorators } from '../utils/decorators';
|
||||||
import {decorators} from '../utils/decorators';
|
import { ExchangeTransferSimulator } from '../utils/exchange_transfer_simulator';
|
||||||
import {ExchangeTransferSimulator} from '../utils/exchange_transfer_simulator';
|
import { OrderValidationUtils } from '../utils/order_validation_utils';
|
||||||
import {OrderValidationUtils} from '../utils/order_validation_utils';
|
import { utils } from '../utils/utils';
|
||||||
import {utils} from '../utils/utils';
|
|
||||||
|
|
||||||
import {ContractWrapper} from './contract_wrapper';
|
import { ContractWrapper } from './contract_wrapper';
|
||||||
import {ExchangeContract} from './generated/exchange';
|
import {
|
||||||
import {TokenWrapper} from './token_wrapper';
|
ExchangeContract,
|
||||||
|
ExchangeContractEventArgs,
|
||||||
|
ExchangeEvents,
|
||||||
|
LogErrorContractEventArgs,
|
||||||
|
} from './generated/exchange';
|
||||||
|
import { TokenWrapper } from './token_wrapper';
|
||||||
|
|
||||||
const SHOULD_VALIDATE_BY_DEFAULT = true;
|
const SHOULD_VALIDATE_BY_DEFAULT = true;
|
||||||
|
|
||||||
@@ -81,12 +80,19 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
];
|
];
|
||||||
return [orderAddresses, orderValues];
|
return [orderAddresses, orderValues];
|
||||||
}
|
}
|
||||||
constructor(web3Wrapper: Web3Wrapper, networkId: number, abiDecoder: AbiDecoder,
|
constructor(
|
||||||
tokenWrapper: TokenWrapper, contractAddressIfExists?: string) {
|
web3Wrapper: Web3Wrapper,
|
||||||
|
networkId: number,
|
||||||
|
abiDecoder: AbiDecoder,
|
||||||
|
tokenWrapper: TokenWrapper,
|
||||||
|
contractAddressIfExists?: string,
|
||||||
|
zrxContractAddressIfExists?: string,
|
||||||
|
) {
|
||||||
super(web3Wrapper, networkId, abiDecoder);
|
super(web3Wrapper, networkId, abiDecoder);
|
||||||
this._tokenWrapper = tokenWrapper;
|
this._tokenWrapper = tokenWrapper;
|
||||||
this._orderValidationUtils = new OrderValidationUtils(this);
|
this._orderValidationUtils = new OrderValidationUtils(this);
|
||||||
this._contractAddressIfExists = contractAddressIfExists;
|
this._contractAddressIfExists = contractAddressIfExists;
|
||||||
|
this._zrxContractAddressIfExists = zrxContractAddressIfExists;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Returns the unavailable takerAmount of an order. Unavailable amount is defined as the total
|
* Returns the unavailable takerAmount of an order. Unavailable amount is defined as the total
|
||||||
@@ -97,14 +103,16 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
* @param methodOpts Optional arguments this method accepts.
|
* @param methodOpts Optional arguments this method accepts.
|
||||||
* @return The amount of the order (in taker tokens) that has either been filled or cancelled.
|
* @return The amount of the order (in taker tokens) that has either been filled or cancelled.
|
||||||
*/
|
*/
|
||||||
public async getUnavailableTakerAmountAsync(orderHash: string,
|
public async getUnavailableTakerAmountAsync(orderHash: string, methodOpts?: MethodOpts): Promise<BigNumber> {
|
||||||
methodOpts?: MethodOpts): Promise<BigNumber> {
|
|
||||||
assert.doesConformToSchema('orderHash', orderHash, schemas.orderHashSchema);
|
assert.doesConformToSchema('orderHash', orderHash, schemas.orderHashSchema);
|
||||||
|
|
||||||
const exchangeContract = await this._getExchangeContractAsync();
|
const exchangeContract = await this._getExchangeContractAsync();
|
||||||
const defaultBlock = _.isUndefined(methodOpts) ? undefined : methodOpts.defaultBlock;
|
const defaultBlock = _.isUndefined(methodOpts) ? undefined : methodOpts.defaultBlock;
|
||||||
|
const txData = {};
|
||||||
let unavailableTakerTokenAmount = await exchangeContract.getUnavailableTakerTokenAmount.callAsync(
|
let unavailableTakerTokenAmount = await exchangeContract.getUnavailableTakerTokenAmount.callAsync(
|
||||||
orderHash, defaultBlock,
|
orderHash,
|
||||||
|
txData,
|
||||||
|
defaultBlock,
|
||||||
);
|
);
|
||||||
// Wrap BigNumbers returned from web3 with our own (later) version of BigNumber
|
// Wrap BigNumbers returned from web3 with our own (later) version of BigNumber
|
||||||
unavailableTakerTokenAmount = new BigNumber(unavailableTakerTokenAmount);
|
unavailableTakerTokenAmount = new BigNumber(unavailableTakerTokenAmount);
|
||||||
@@ -121,7 +129,8 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
|
|
||||||
const exchangeContract = await this._getExchangeContractAsync();
|
const exchangeContract = await this._getExchangeContractAsync();
|
||||||
const defaultBlock = _.isUndefined(methodOpts) ? undefined : methodOpts.defaultBlock;
|
const defaultBlock = _.isUndefined(methodOpts) ? undefined : methodOpts.defaultBlock;
|
||||||
let fillAmountInBaseUnits = await exchangeContract.filled.callAsync(orderHash, defaultBlock);
|
const txData = {};
|
||||||
|
let fillAmountInBaseUnits = await exchangeContract.filled.callAsync(orderHash, txData, defaultBlock);
|
||||||
// Wrap BigNumbers returned from web3 with our own (later) version of BigNumber
|
// Wrap BigNumbers returned from web3 with our own (later) version of BigNumber
|
||||||
fillAmountInBaseUnits = new BigNumber(fillAmountInBaseUnits);
|
fillAmountInBaseUnits = new BigNumber(fillAmountInBaseUnits);
|
||||||
return fillAmountInBaseUnits;
|
return fillAmountInBaseUnits;
|
||||||
@@ -138,7 +147,8 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
|
|
||||||
const exchangeContract = await this._getExchangeContractAsync();
|
const exchangeContract = await this._getExchangeContractAsync();
|
||||||
const defaultBlock = _.isUndefined(methodOpts) ? undefined : methodOpts.defaultBlock;
|
const defaultBlock = _.isUndefined(methodOpts) ? undefined : methodOpts.defaultBlock;
|
||||||
let cancelledAmountInBaseUnits = await exchangeContract.cancelled.callAsync(orderHash, defaultBlock);
|
const txData = {};
|
||||||
|
let cancelledAmountInBaseUnits = await exchangeContract.cancelled.callAsync(orderHash, txData, defaultBlock);
|
||||||
// Wrap BigNumbers returned from web3 with our own (later) version of BigNumber
|
// Wrap BigNumbers returned from web3 with our own (later) version of BigNumber
|
||||||
cancelledAmountInBaseUnits = new BigNumber(cancelledAmountInBaseUnits);
|
cancelledAmountInBaseUnits = new BigNumber(cancelledAmountInBaseUnits);
|
||||||
return cancelledAmountInBaseUnits;
|
return cancelledAmountInBaseUnits;
|
||||||
@@ -163,24 +173,33 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
* @return Transaction hash.
|
* @return Transaction hash.
|
||||||
*/
|
*/
|
||||||
@decorators.asyncZeroExErrorHandler
|
@decorators.asyncZeroExErrorHandler
|
||||||
public async fillOrderAsync(signedOrder: SignedOrder, fillTakerTokenAmount: BigNumber,
|
public async fillOrderAsync(
|
||||||
shouldThrowOnInsufficientBalanceOrAllowance: boolean,
|
signedOrder: SignedOrder,
|
||||||
takerAddress: string,
|
fillTakerTokenAmount: BigNumber,
|
||||||
orderTransactionOpts: OrderTransactionOpts = {}): Promise<string> {
|
shouldThrowOnInsufficientBalanceOrAllowance: boolean,
|
||||||
|
takerAddress: string,
|
||||||
|
orderTransactionOpts: OrderTransactionOpts = {},
|
||||||
|
): Promise<string> {
|
||||||
assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
|
assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
|
||||||
assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
|
assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
|
||||||
assert.isBoolean('shouldThrowOnInsufficientBalanceOrAllowance', shouldThrowOnInsufficientBalanceOrAllowance);
|
assert.isBoolean('shouldThrowOnInsufficientBalanceOrAllowance', shouldThrowOnInsufficientBalanceOrAllowance);
|
||||||
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
|
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
|
||||||
|
const normalizedTakerAddress = takerAddress.toLowerCase();
|
||||||
|
|
||||||
const exchangeInstance = await this._getExchangeContractAsync();
|
const exchangeInstance = await this._getExchangeContractAsync();
|
||||||
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) ?
|
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate)
|
||||||
SHOULD_VALIDATE_BY_DEFAULT :
|
? SHOULD_VALIDATE_BY_DEFAULT
|
||||||
orderTransactionOpts.shouldValidate;
|
: orderTransactionOpts.shouldValidate;
|
||||||
if (shouldValidate) {
|
if (shouldValidate) {
|
||||||
const zrxTokenAddress = this.getZRXTokenAddress();
|
const zrxTokenAddress = this.getZRXTokenAddress();
|
||||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
||||||
await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
|
await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
|
||||||
exchangeTradeEmulator, signedOrder, fillTakerTokenAmount, takerAddress, zrxTokenAddress);
|
exchangeTradeEmulator,
|
||||||
|
signedOrder,
|
||||||
|
fillTakerTokenAmount,
|
||||||
|
normalizedTakerAddress,
|
||||||
|
zrxTokenAddress,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const [orderAddresses, orderValues] = ExchangeWrapper._getOrderAddressesAndValues(signedOrder);
|
const [orderAddresses, orderValues] = ExchangeWrapper._getOrderAddressesAndValues(signedOrder);
|
||||||
@@ -194,7 +213,7 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
signedOrder.ecSignature.r,
|
signedOrder.ecSignature.r,
|
||||||
signedOrder.ecSignature.s,
|
signedOrder.ecSignature.s,
|
||||||
{
|
{
|
||||||
from: takerAddress,
|
from: normalizedTakerAddress,
|
||||||
gas: orderTransactionOpts.gasLimit,
|
gas: orderTransactionOpts.gasLimit,
|
||||||
gasPrice: orderTransactionOpts.gasPrice,
|
gasPrice: orderTransactionOpts.gasPrice,
|
||||||
},
|
},
|
||||||
@@ -219,30 +238,45 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
* @return Transaction hash.
|
* @return Transaction hash.
|
||||||
*/
|
*/
|
||||||
@decorators.asyncZeroExErrorHandler
|
@decorators.asyncZeroExErrorHandler
|
||||||
public async fillOrdersUpToAsync(signedOrders: SignedOrder[], fillTakerTokenAmount: BigNumber,
|
public async fillOrdersUpToAsync(
|
||||||
shouldThrowOnInsufficientBalanceOrAllowance: boolean,
|
signedOrders: SignedOrder[],
|
||||||
takerAddress: string,
|
fillTakerTokenAmount: BigNumber,
|
||||||
orderTransactionOpts: OrderTransactionOpts = {}): Promise<string> {
|
shouldThrowOnInsufficientBalanceOrAllowance: boolean,
|
||||||
|
takerAddress: string,
|
||||||
|
orderTransactionOpts: OrderTransactionOpts = {},
|
||||||
|
): Promise<string> {
|
||||||
assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema);
|
assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema);
|
||||||
const takerTokenAddresses = _.map(signedOrders, signedOrder => signedOrder.takerTokenAddress);
|
const takerTokenAddresses = _.map(signedOrders, signedOrder => signedOrder.takerTokenAddress);
|
||||||
assert.hasAtMostOneUniqueValue(takerTokenAddresses,
|
assert.hasAtMostOneUniqueValue(
|
||||||
ExchangeContractErrs.MultipleTakerTokensInFillUpToDisallowed);
|
takerTokenAddresses,
|
||||||
|
ExchangeContractErrs.MultipleTakerTokensInFillUpToDisallowed,
|
||||||
|
);
|
||||||
const exchangeContractAddresses = _.map(signedOrders, signedOrder => signedOrder.exchangeContractAddress);
|
const exchangeContractAddresses = _.map(signedOrders, signedOrder => signedOrder.exchangeContractAddress);
|
||||||
assert.hasAtMostOneUniqueValue(exchangeContractAddresses,
|
assert.hasAtMostOneUniqueValue(
|
||||||
ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress);
|
exchangeContractAddresses,
|
||||||
|
ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress,
|
||||||
|
);
|
||||||
assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
|
assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
|
||||||
assert.isBoolean('shouldThrowOnInsufficientBalanceOrAllowance', shouldThrowOnInsufficientBalanceOrAllowance);
|
assert.isBoolean('shouldThrowOnInsufficientBalanceOrAllowance', shouldThrowOnInsufficientBalanceOrAllowance);
|
||||||
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
|
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
|
||||||
|
const normalizedTakerAddress = takerAddress.toLowerCase();
|
||||||
|
|
||||||
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) ?
|
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate)
|
||||||
SHOULD_VALIDATE_BY_DEFAULT :
|
? SHOULD_VALIDATE_BY_DEFAULT
|
||||||
orderTransactionOpts.shouldValidate;
|
: orderTransactionOpts.shouldValidate;
|
||||||
if (shouldValidate) {
|
if (shouldValidate) {
|
||||||
|
let filledTakerTokenAmount = new BigNumber(0);
|
||||||
const zrxTokenAddress = this.getZRXTokenAddress();
|
const zrxTokenAddress = this.getZRXTokenAddress();
|
||||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
||||||
for (const signedOrder of signedOrders) {
|
for (const signedOrder of signedOrders) {
|
||||||
await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
|
const singleFilledTakerTokenAmount = await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
|
||||||
exchangeTradeEmulator, signedOrder, fillTakerTokenAmount, takerAddress, zrxTokenAddress);
|
exchangeTradeEmulator,
|
||||||
|
signedOrder,
|
||||||
|
fillTakerTokenAmount.minus(filledTakerTokenAmount),
|
||||||
|
normalizedTakerAddress,
|
||||||
|
zrxTokenAddress,
|
||||||
|
);
|
||||||
|
filledTakerTokenAmount = filledTakerTokenAmount.plus(singleFilledTakerTokenAmount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -273,7 +307,7 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
rArray,
|
rArray,
|
||||||
sArray,
|
sArray,
|
||||||
{
|
{
|
||||||
from: takerAddress,
|
from: normalizedTakerAddress,
|
||||||
gas: orderTransactionOpts.gasLimit,
|
gas: orderTransactionOpts.gasLimit,
|
||||||
gasPrice: orderTransactionOpts.gasPrice,
|
gasPrice: orderTransactionOpts.gasPrice,
|
||||||
},
|
},
|
||||||
@@ -300,29 +334,37 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
* @return Transaction hash.
|
* @return Transaction hash.
|
||||||
*/
|
*/
|
||||||
@decorators.asyncZeroExErrorHandler
|
@decorators.asyncZeroExErrorHandler
|
||||||
public async batchFillOrdersAsync(orderFillRequests: OrderFillRequest[],
|
public async batchFillOrdersAsync(
|
||||||
shouldThrowOnInsufficientBalanceOrAllowance: boolean,
|
orderFillRequests: OrderFillRequest[],
|
||||||
takerAddress: string,
|
shouldThrowOnInsufficientBalanceOrAllowance: boolean,
|
||||||
orderTransactionOpts: OrderTransactionOpts = {}): Promise<string> {
|
takerAddress: string,
|
||||||
|
orderTransactionOpts: OrderTransactionOpts = {},
|
||||||
|
): Promise<string> {
|
||||||
assert.doesConformToSchema('orderFillRequests', orderFillRequests, schemas.orderFillRequestsSchema);
|
assert.doesConformToSchema('orderFillRequests', orderFillRequests, schemas.orderFillRequestsSchema);
|
||||||
const exchangeContractAddresses = _.map(
|
const exchangeContractAddresses = _.map(
|
||||||
orderFillRequests,
|
orderFillRequests,
|
||||||
orderFillRequest => orderFillRequest.signedOrder.exchangeContractAddress,
|
orderFillRequest => orderFillRequest.signedOrder.exchangeContractAddress,
|
||||||
);
|
);
|
||||||
assert.hasAtMostOneUniqueValue(exchangeContractAddresses,
|
assert.hasAtMostOneUniqueValue(
|
||||||
ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress);
|
exchangeContractAddresses,
|
||||||
|
ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress,
|
||||||
|
);
|
||||||
assert.isBoolean('shouldThrowOnInsufficientBalanceOrAllowance', shouldThrowOnInsufficientBalanceOrAllowance);
|
assert.isBoolean('shouldThrowOnInsufficientBalanceOrAllowance', shouldThrowOnInsufficientBalanceOrAllowance);
|
||||||
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
|
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
|
||||||
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) ?
|
const normalizedTakerAddress = takerAddress.toLowerCase();
|
||||||
SHOULD_VALIDATE_BY_DEFAULT :
|
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate)
|
||||||
orderTransactionOpts.shouldValidate;
|
? SHOULD_VALIDATE_BY_DEFAULT
|
||||||
|
: orderTransactionOpts.shouldValidate;
|
||||||
if (shouldValidate) {
|
if (shouldValidate) {
|
||||||
const zrxTokenAddress = this.getZRXTokenAddress();
|
const zrxTokenAddress = this.getZRXTokenAddress();
|
||||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
||||||
for (const orderFillRequest of orderFillRequests) {
|
for (const orderFillRequest of orderFillRequests) {
|
||||||
await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
|
await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
|
||||||
exchangeTradeEmulator, orderFillRequest.signedOrder, orderFillRequest.takerTokenFillAmount,
|
exchangeTradeEmulator,
|
||||||
takerAddress, zrxTokenAddress,
|
orderFillRequest.signedOrder,
|
||||||
|
orderFillRequest.takerTokenFillAmount,
|
||||||
|
normalizedTakerAddress,
|
||||||
|
zrxTokenAddress,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -354,7 +396,7 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
rArray,
|
rArray,
|
||||||
sArray,
|
sArray,
|
||||||
{
|
{
|
||||||
from: takerAddress,
|
from: normalizedTakerAddress,
|
||||||
gas: orderTransactionOpts.gasLimit,
|
gas: orderTransactionOpts.gasLimit,
|
||||||
gasPrice: orderTransactionOpts.gasPrice,
|
gasPrice: orderTransactionOpts.gasPrice,
|
||||||
},
|
},
|
||||||
@@ -373,23 +415,32 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
* @return Transaction hash.
|
* @return Transaction hash.
|
||||||
*/
|
*/
|
||||||
@decorators.asyncZeroExErrorHandler
|
@decorators.asyncZeroExErrorHandler
|
||||||
public async fillOrKillOrderAsync(signedOrder: SignedOrder, fillTakerTokenAmount: BigNumber,
|
public async fillOrKillOrderAsync(
|
||||||
takerAddress: string,
|
signedOrder: SignedOrder,
|
||||||
orderTransactionOpts: OrderTransactionOpts = {}): Promise<string> {
|
fillTakerTokenAmount: BigNumber,
|
||||||
|
takerAddress: string,
|
||||||
|
orderTransactionOpts: OrderTransactionOpts = {},
|
||||||
|
): Promise<string> {
|
||||||
assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
|
assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
|
||||||
assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
|
assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
|
||||||
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
|
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
|
||||||
|
const normalizedTakerAddress = takerAddress.toLowerCase();
|
||||||
|
|
||||||
const exchangeInstance = await this._getExchangeContractAsync();
|
const exchangeInstance = await this._getExchangeContractAsync();
|
||||||
|
|
||||||
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) ?
|
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate)
|
||||||
SHOULD_VALIDATE_BY_DEFAULT :
|
? SHOULD_VALIDATE_BY_DEFAULT
|
||||||
orderTransactionOpts.shouldValidate;
|
: orderTransactionOpts.shouldValidate;
|
||||||
if (shouldValidate) {
|
if (shouldValidate) {
|
||||||
const zrxTokenAddress = this.getZRXTokenAddress();
|
const zrxTokenAddress = this.getZRXTokenAddress();
|
||||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
||||||
await this._orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync(
|
await this._orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync(
|
||||||
exchangeTradeEmulator, signedOrder, fillTakerTokenAmount, takerAddress, zrxTokenAddress);
|
exchangeTradeEmulator,
|
||||||
|
signedOrder,
|
||||||
|
fillTakerTokenAmount,
|
||||||
|
normalizedTakerAddress,
|
||||||
|
zrxTokenAddress,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const [orderAddresses, orderValues] = ExchangeWrapper._getOrderAddressesAndValues(signedOrder);
|
const [orderAddresses, orderValues] = ExchangeWrapper._getOrderAddressesAndValues(signedOrder);
|
||||||
@@ -401,7 +452,7 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
signedOrder.ecSignature.r,
|
signedOrder.ecSignature.r,
|
||||||
signedOrder.ecSignature.s,
|
signedOrder.ecSignature.s,
|
||||||
{
|
{
|
||||||
from: takerAddress,
|
from: normalizedTakerAddress,
|
||||||
gas: orderTransactionOpts.gasLimit,
|
gas: orderTransactionOpts.gasLimit,
|
||||||
gasPrice: orderTransactionOpts.gasPrice,
|
gasPrice: orderTransactionOpts.gasPrice,
|
||||||
},
|
},
|
||||||
@@ -418,33 +469,40 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
* @return Transaction hash.
|
* @return Transaction hash.
|
||||||
*/
|
*/
|
||||||
@decorators.asyncZeroExErrorHandler
|
@decorators.asyncZeroExErrorHandler
|
||||||
public async batchFillOrKillAsync(orderFillRequests: OrderFillRequest[],
|
public async batchFillOrKillAsync(
|
||||||
takerAddress: string,
|
orderFillRequests: OrderFillRequest[],
|
||||||
orderTransactionOpts: OrderTransactionOpts = {}): Promise<string> {
|
takerAddress: string,
|
||||||
assert.doesConformToSchema('orderFillRequests', orderFillRequests,
|
orderTransactionOpts: OrderTransactionOpts = {},
|
||||||
schemas.orderFillRequestsSchema);
|
): Promise<string> {
|
||||||
|
assert.doesConformToSchema('orderFillRequests', orderFillRequests, schemas.orderFillRequestsSchema);
|
||||||
const exchangeContractAddresses = _.map(
|
const exchangeContractAddresses = _.map(
|
||||||
orderFillRequests,
|
orderFillRequests,
|
||||||
orderFillRequest => orderFillRequest.signedOrder.exchangeContractAddress,
|
orderFillRequest => orderFillRequest.signedOrder.exchangeContractAddress,
|
||||||
);
|
);
|
||||||
assert.hasAtMostOneUniqueValue(exchangeContractAddresses,
|
assert.hasAtMostOneUniqueValue(
|
||||||
ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress);
|
exchangeContractAddresses,
|
||||||
|
ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress,
|
||||||
|
);
|
||||||
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
|
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
|
||||||
|
const normalizedTakerAddress = takerAddress.toLowerCase();
|
||||||
if (_.isEmpty(orderFillRequests)) {
|
if (_.isEmpty(orderFillRequests)) {
|
||||||
throw new Error(ExchangeContractErrs.BatchOrdersMustHaveAtLeastOneItem);
|
throw new Error(ExchangeContractErrs.BatchOrdersMustHaveAtLeastOneItem);
|
||||||
}
|
}
|
||||||
const exchangeInstance = await this._getExchangeContractAsync();
|
const exchangeInstance = await this._getExchangeContractAsync();
|
||||||
|
|
||||||
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) ?
|
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate)
|
||||||
SHOULD_VALIDATE_BY_DEFAULT :
|
? SHOULD_VALIDATE_BY_DEFAULT
|
||||||
orderTransactionOpts.shouldValidate;
|
: orderTransactionOpts.shouldValidate;
|
||||||
if (shouldValidate) {
|
if (shouldValidate) {
|
||||||
const zrxTokenAddress = this.getZRXTokenAddress();
|
const zrxTokenAddress = this.getZRXTokenAddress();
|
||||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
||||||
for (const orderFillRequest of orderFillRequests) {
|
for (const orderFillRequest of orderFillRequests) {
|
||||||
await this._orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync(
|
await this._orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync(
|
||||||
exchangeTradeEmulator, orderFillRequest.signedOrder, orderFillRequest.takerTokenFillAmount,
|
exchangeTradeEmulator,
|
||||||
takerAddress, zrxTokenAddress,
|
orderFillRequest.signedOrder,
|
||||||
|
orderFillRequest.takerTokenFillAmount,
|
||||||
|
normalizedTakerAddress,
|
||||||
|
zrxTokenAddress,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -460,8 +518,9 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// We use _.unzip<any> because _.unzip doesn't type check if values have different types :'(
|
// We use _.unzip<any> because _.unzip doesn't type check if values have different types :'(
|
||||||
const [orderAddresses, orderValues, fillTakerTokenAmounts, vParams, rParams, sParams] =
|
const [orderAddresses, orderValues, fillTakerTokenAmounts, vParams, rParams, sParams] = _.unzip<any>(
|
||||||
_.unzip<any>(orderAddressesValuesAndTakerTokenFillAmounts);
|
orderAddressesValuesAndTakerTokenFillAmounts,
|
||||||
|
);
|
||||||
const txHash = await exchangeInstance.batchFillOrKillOrders.sendTransactionAsync(
|
const txHash = await exchangeInstance.batchFillOrKillOrders.sendTransactionAsync(
|
||||||
orderAddresses,
|
orderAddresses,
|
||||||
orderValues,
|
orderValues,
|
||||||
@@ -470,7 +529,7 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
rParams,
|
rParams,
|
||||||
sParams,
|
sParams,
|
||||||
{
|
{
|
||||||
from: takerAddress,
|
from: normalizedTakerAddress,
|
||||||
gas: orderTransactionOpts.gasLimit,
|
gas: orderTransactionOpts.gasLimit,
|
||||||
gasPrice: orderTransactionOpts.gasPrice,
|
gasPrice: orderTransactionOpts.gasPrice,
|
||||||
},
|
},
|
||||||
@@ -486,23 +545,29 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
* @return Transaction hash.
|
* @return Transaction hash.
|
||||||
*/
|
*/
|
||||||
@decorators.asyncZeroExErrorHandler
|
@decorators.asyncZeroExErrorHandler
|
||||||
public async cancelOrderAsync(order: Order|SignedOrder,
|
public async cancelOrderAsync(
|
||||||
cancelTakerTokenAmount: BigNumber,
|
order: Order | SignedOrder,
|
||||||
orderTransactionOpts: OrderTransactionOpts = {}): Promise<string> {
|
cancelTakerTokenAmount: BigNumber,
|
||||||
|
orderTransactionOpts: OrderTransactionOpts = {},
|
||||||
|
): Promise<string> {
|
||||||
assert.doesConformToSchema('order', order, schemas.orderSchema);
|
assert.doesConformToSchema('order', order, schemas.orderSchema);
|
||||||
assert.isValidBaseUnitAmount('takerTokenCancelAmount', cancelTakerTokenAmount);
|
assert.isValidBaseUnitAmount('takerTokenCancelAmount', cancelTakerTokenAmount);
|
||||||
await assert.isSenderAddressAsync('order.maker', order.maker, this._web3Wrapper);
|
await assert.isSenderAddressAsync('order.maker', order.maker, this._web3Wrapper);
|
||||||
|
const normalizedMakerAddress = order.maker.toLowerCase();
|
||||||
|
|
||||||
const exchangeInstance = await this._getExchangeContractAsync();
|
const exchangeInstance = await this._getExchangeContractAsync();
|
||||||
|
|
||||||
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) ?
|
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate)
|
||||||
SHOULD_VALIDATE_BY_DEFAULT :
|
? SHOULD_VALIDATE_BY_DEFAULT
|
||||||
orderTransactionOpts.shouldValidate;
|
: orderTransactionOpts.shouldValidate;
|
||||||
if (shouldValidate) {
|
if (shouldValidate) {
|
||||||
const orderHash = utils.getOrderHashHex(order);
|
const orderHash = utils.getOrderHashHex(order);
|
||||||
const unavailableTakerTokenAmount = await this.getUnavailableTakerAmountAsync(orderHash);
|
const unavailableTakerTokenAmount = await this.getUnavailableTakerAmountAsync(orderHash);
|
||||||
OrderValidationUtils.validateCancelOrderThrowIfInvalid(
|
OrderValidationUtils.validateCancelOrderThrowIfInvalid(
|
||||||
order, cancelTakerTokenAmount, unavailableTakerTokenAmount);
|
order,
|
||||||
|
cancelTakerTokenAmount,
|
||||||
|
unavailableTakerTokenAmount,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const [orderAddresses, orderValues] = ExchangeWrapper._getOrderAddressesAndValues(order);
|
const [orderAddresses, orderValues] = ExchangeWrapper._getOrderAddressesAndValues(order);
|
||||||
@@ -511,7 +576,7 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
orderValues,
|
orderValues,
|
||||||
cancelTakerTokenAmount,
|
cancelTakerTokenAmount,
|
||||||
{
|
{
|
||||||
from: order.maker,
|
from: normalizedMakerAddress,
|
||||||
gas: orderTransactionOpts.gasLimit,
|
gas: orderTransactionOpts.gasLimit,
|
||||||
gasPrice: orderTransactionOpts.gasPrice,
|
gasPrice: orderTransactionOpts.gasPrice,
|
||||||
},
|
},
|
||||||
@@ -527,33 +592,42 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
* @return Transaction hash.
|
* @return Transaction hash.
|
||||||
*/
|
*/
|
||||||
@decorators.asyncZeroExErrorHandler
|
@decorators.asyncZeroExErrorHandler
|
||||||
public async batchCancelOrdersAsync(orderCancellationRequests: OrderCancellationRequest[],
|
public async batchCancelOrdersAsync(
|
||||||
orderTransactionOpts: OrderTransactionOpts = {}): Promise<string> {
|
orderCancellationRequests: OrderCancellationRequest[],
|
||||||
assert.doesConformToSchema('orderCancellationRequests', orderCancellationRequests,
|
orderTransactionOpts: OrderTransactionOpts = {},
|
||||||
schemas.orderCancellationRequestsSchema);
|
): Promise<string> {
|
||||||
|
assert.doesConformToSchema(
|
||||||
|
'orderCancellationRequests',
|
||||||
|
orderCancellationRequests,
|
||||||
|
schemas.orderCancellationRequestsSchema,
|
||||||
|
);
|
||||||
const exchangeContractAddresses = _.map(
|
const exchangeContractAddresses = _.map(
|
||||||
orderCancellationRequests,
|
orderCancellationRequests,
|
||||||
orderCancellationRequest => orderCancellationRequest.order.exchangeContractAddress,
|
orderCancellationRequest => orderCancellationRequest.order.exchangeContractAddress,
|
||||||
);
|
);
|
||||||
assert.hasAtMostOneUniqueValue(exchangeContractAddresses,
|
assert.hasAtMostOneUniqueValue(
|
||||||
ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress);
|
exchangeContractAddresses,
|
||||||
|
ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress,
|
||||||
|
);
|
||||||
const makers = _.map(orderCancellationRequests, cancellationRequest => cancellationRequest.order.maker);
|
const makers = _.map(orderCancellationRequests, cancellationRequest => cancellationRequest.order.maker);
|
||||||
assert.hasAtMostOneUniqueValue(makers, ExchangeContractErrs.MultipleMakersInSingleCancelBatchDisallowed);
|
assert.hasAtMostOneUniqueValue(makers, ExchangeContractErrs.MultipleMakersInSingleCancelBatchDisallowed);
|
||||||
const maker = makers[0];
|
const maker = makers[0];
|
||||||
await assert.isSenderAddressAsync('maker', maker, this._web3Wrapper);
|
await assert.isSenderAddressAsync('maker', maker, this._web3Wrapper);
|
||||||
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) ?
|
const normalizedMakerAddress = maker.toLowerCase();
|
||||||
SHOULD_VALIDATE_BY_DEFAULT :
|
|
||||||
orderTransactionOpts.shouldValidate;
|
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate)
|
||||||
|
? SHOULD_VALIDATE_BY_DEFAULT
|
||||||
|
: orderTransactionOpts.shouldValidate;
|
||||||
if (shouldValidate) {
|
if (shouldValidate) {
|
||||||
for (const orderCancellationRequest of orderCancellationRequests) {
|
for (const orderCancellationRequest of orderCancellationRequests) {
|
||||||
const orderHash = utils.getOrderHashHex(orderCancellationRequest.order);
|
const orderHash = utils.getOrderHashHex(orderCancellationRequest.order);
|
||||||
const unavailableTakerTokenAmount = await this.getUnavailableTakerAmountAsync(orderHash);
|
const unavailableTakerTokenAmount = await this.getUnavailableTakerAmountAsync(orderHash);
|
||||||
OrderValidationUtils.validateCancelOrderThrowIfInvalid(
|
OrderValidationUtils.validateCancelOrderThrowIfInvalid(
|
||||||
orderCancellationRequest.order, orderCancellationRequest.takerTokenCancelAmount,
|
orderCancellationRequest.order,
|
||||||
|
orderCancellationRequest.takerTokenCancelAmount,
|
||||||
unavailableTakerTokenAmount,
|
unavailableTakerTokenAmount,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
if (_.isEmpty(orderCancellationRequests)) {
|
if (_.isEmpty(orderCancellationRequests)) {
|
||||||
throw new Error(ExchangeContractErrs.BatchOrdersMustHaveAtLeastOneItem);
|
throw new Error(ExchangeContractErrs.BatchOrdersMustHaveAtLeastOneItem);
|
||||||
@@ -566,14 +640,15 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
];
|
];
|
||||||
});
|
});
|
||||||
// We use _.unzip<any> because _.unzip doesn't type check if values have different types :'(
|
// We use _.unzip<any> because _.unzip doesn't type check if values have different types :'(
|
||||||
const [orderAddresses, orderValues, cancelTakerTokenAmounts] =
|
const [orderAddresses, orderValues, cancelTakerTokenAmounts] = _.unzip<any>(
|
||||||
_.unzip<any>(orderAddressesValuesAndTakerTokenCancelAmounts);
|
orderAddressesValuesAndTakerTokenCancelAmounts,
|
||||||
|
);
|
||||||
const txHash = await exchangeInstance.batchCancelOrders.sendTransactionAsync(
|
const txHash = await exchangeInstance.batchCancelOrders.sendTransactionAsync(
|
||||||
orderAddresses,
|
orderAddresses,
|
||||||
orderValues,
|
orderValues,
|
||||||
cancelTakerTokenAmounts,
|
cancelTakerTokenAmounts,
|
||||||
{
|
{
|
||||||
from: maker,
|
from: normalizedMakerAddress,
|
||||||
gas: orderTransactionOpts.gasLimit,
|
gas: orderTransactionOpts.gasLimit,
|
||||||
gasPrice: orderTransactionOpts.gasPrice,
|
gasPrice: orderTransactionOpts.gasPrice,
|
||||||
},
|
},
|
||||||
@@ -589,14 +664,20 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
* @return Subscription token used later to unsubscribe
|
* @return Subscription token used later to unsubscribe
|
||||||
*/
|
*/
|
||||||
public subscribe<ArgsType extends ExchangeContractEventArgs>(
|
public subscribe<ArgsType extends ExchangeContractEventArgs>(
|
||||||
eventName: ExchangeEvents, indexFilterValues: IndexedFilterValues,
|
eventName: ExchangeEvents,
|
||||||
callback: EventCallback<ArgsType>): string {
|
indexFilterValues: IndexedFilterValues,
|
||||||
|
callback: EventCallback<ArgsType>,
|
||||||
|
): string {
|
||||||
assert.doesBelongToStringEnum('eventName', eventName, ExchangeEvents);
|
assert.doesBelongToStringEnum('eventName', eventName, ExchangeEvents);
|
||||||
assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
|
assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
|
||||||
assert.isFunction('callback', callback);
|
assert.isFunction('callback', callback);
|
||||||
const exchangeContractAddress = this.getContractAddress();
|
const exchangeContractAddress = this.getContractAddress();
|
||||||
const subscriptionToken = this._subscribe<ArgsType>(
|
const subscriptionToken = this._subscribe<ArgsType>(
|
||||||
exchangeContractAddress, eventName, indexFilterValues, artifacts.ExchangeArtifact.abi, callback,
|
exchangeContractAddress,
|
||||||
|
eventName,
|
||||||
|
indexFilterValues,
|
||||||
|
artifacts.ExchangeArtifact.abi,
|
||||||
|
callback,
|
||||||
);
|
);
|
||||||
return subscriptionToken;
|
return subscriptionToken;
|
||||||
}
|
}
|
||||||
@@ -611,7 +692,7 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
* Cancels all existing subscriptions
|
* Cancels all existing subscriptions
|
||||||
*/
|
*/
|
||||||
public unsubscribeAll(): void {
|
public unsubscribeAll(): void {
|
||||||
super.unsubscribeAll();
|
super._unsubscribeAll();
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Gets historical logs without creating a subscription
|
* Gets historical logs without creating a subscription
|
||||||
@@ -622,14 +703,20 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
* @return Array of logs that match the parameters
|
* @return Array of logs that match the parameters
|
||||||
*/
|
*/
|
||||||
public async getLogsAsync<ArgsType extends ExchangeContractEventArgs>(
|
public async getLogsAsync<ArgsType extends ExchangeContractEventArgs>(
|
||||||
eventName: ExchangeEvents, blockRange: BlockRange, indexFilterValues: IndexedFilterValues,
|
eventName: ExchangeEvents,
|
||||||
|
blockRange: BlockRange,
|
||||||
|
indexFilterValues: IndexedFilterValues,
|
||||||
): Promise<Array<LogWithDecodedArgs<ArgsType>>> {
|
): Promise<Array<LogWithDecodedArgs<ArgsType>>> {
|
||||||
assert.doesBelongToStringEnum('eventName', eventName, ExchangeEvents);
|
assert.doesBelongToStringEnum('eventName', eventName, ExchangeEvents);
|
||||||
assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema);
|
assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema);
|
||||||
assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
|
assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
|
||||||
const exchangeContractAddress = this.getContractAddress();
|
const exchangeContractAddress = this.getContractAddress();
|
||||||
const logs = await this._getLogsAsync<ArgsType>(
|
const logs = await this._getLogsAsync<ArgsType>(
|
||||||
exchangeContractAddress, eventName, blockRange, indexFilterValues, artifacts.ExchangeArtifact.abi,
|
exchangeContractAddress,
|
||||||
|
eventName,
|
||||||
|
blockRange,
|
||||||
|
indexFilterValues,
|
||||||
|
artifacts.ExchangeArtifact.abi,
|
||||||
);
|
);
|
||||||
return logs;
|
return logs;
|
||||||
}
|
}
|
||||||
@@ -652,14 +739,18 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
* to validate for.
|
* to validate for.
|
||||||
*/
|
*/
|
||||||
public async validateOrderFillableOrThrowAsync(
|
public async validateOrderFillableOrThrowAsync(
|
||||||
signedOrder: SignedOrder, opts?: ValidateOrderFillableOpts,
|
signedOrder: SignedOrder,
|
||||||
|
opts?: ValidateOrderFillableOpts,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
|
assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
|
||||||
const zrxTokenAddress = this.getZRXTokenAddress();
|
const zrxTokenAddress = this.getZRXTokenAddress();
|
||||||
const expectedFillTakerTokenAmount = !_.isUndefined(opts) ? opts.expectedFillTakerTokenAmount : undefined;
|
const expectedFillTakerTokenAmount = !_.isUndefined(opts) ? opts.expectedFillTakerTokenAmount : undefined;
|
||||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
||||||
await this._orderValidationUtils.validateOrderFillableOrThrowAsync(
|
await this._orderValidationUtils.validateOrderFillableOrThrowAsync(
|
||||||
exchangeTradeEmulator, signedOrder, zrxTokenAddress, expectedFillTakerTokenAmount,
|
exchangeTradeEmulator,
|
||||||
|
signedOrder,
|
||||||
|
zrxTokenAddress,
|
||||||
|
expectedFillTakerTokenAmount,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@@ -670,16 +761,24 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
* @param takerAddress The user Ethereum address who would like to fill this order.
|
* @param takerAddress The user Ethereum address who would like to fill this order.
|
||||||
* Must be available via the supplied Web3.Provider passed to 0x.js.
|
* Must be available via the supplied Web3.Provider passed to 0x.js.
|
||||||
*/
|
*/
|
||||||
public async validateFillOrderThrowIfInvalidAsync(signedOrder: SignedOrder,
|
public async validateFillOrderThrowIfInvalidAsync(
|
||||||
fillTakerTokenAmount: BigNumber,
|
signedOrder: SignedOrder,
|
||||||
takerAddress: string): Promise<void> {
|
fillTakerTokenAmount: BigNumber,
|
||||||
|
takerAddress: string,
|
||||||
|
): Promise<void> {
|
||||||
assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
|
assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
|
||||||
assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
|
assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
|
||||||
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
|
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
|
||||||
|
const normalizedTakerAddress = takerAddress.toLowerCase();
|
||||||
const zrxTokenAddress = this.getZRXTokenAddress();
|
const zrxTokenAddress = this.getZRXTokenAddress();
|
||||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
||||||
await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
|
await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
|
||||||
exchangeTradeEmulator, signedOrder, fillTakerTokenAmount, takerAddress, zrxTokenAddress);
|
exchangeTradeEmulator,
|
||||||
|
signedOrder,
|
||||||
|
fillTakerTokenAmount,
|
||||||
|
normalizedTakerAddress,
|
||||||
|
zrxTokenAddress,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Checks if cancelling a given order will succeed and throws an informative error if it won't.
|
* Checks if cancelling a given order will succeed and throws an informative error if it won't.
|
||||||
@@ -688,13 +787,18 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
* @param cancelTakerTokenAmount The amount (specified in taker tokens) that you would like to cancel.
|
* @param cancelTakerTokenAmount The amount (specified in taker tokens) that you would like to cancel.
|
||||||
*/
|
*/
|
||||||
public async validateCancelOrderThrowIfInvalidAsync(
|
public async validateCancelOrderThrowIfInvalidAsync(
|
||||||
order: Order, cancelTakerTokenAmount: BigNumber): Promise<void> {
|
order: Order,
|
||||||
|
cancelTakerTokenAmount: BigNumber,
|
||||||
|
): Promise<void> {
|
||||||
assert.doesConformToSchema('order', order, schemas.orderSchema);
|
assert.doesConformToSchema('order', order, schemas.orderSchema);
|
||||||
assert.isValidBaseUnitAmount('cancelTakerTokenAmount', cancelTakerTokenAmount);
|
assert.isValidBaseUnitAmount('cancelTakerTokenAmount', cancelTakerTokenAmount);
|
||||||
const orderHash = utils.getOrderHashHex(order);
|
const orderHash = utils.getOrderHashHex(order);
|
||||||
const unavailableTakerTokenAmount = await this.getUnavailableTakerAmountAsync(orderHash);
|
const unavailableTakerTokenAmount = await this.getUnavailableTakerAmountAsync(orderHash);
|
||||||
OrderValidationUtils.validateCancelOrderThrowIfInvalid(
|
OrderValidationUtils.validateCancelOrderThrowIfInvalid(
|
||||||
order, cancelTakerTokenAmount, unavailableTakerTokenAmount);
|
order,
|
||||||
|
cancelTakerTokenAmount,
|
||||||
|
unavailableTakerTokenAmount,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Checks if calling fillOrKill on a given order will succeed and throws an informative error if it won't.
|
* Checks if calling fillOrKill on a given order will succeed and throws an informative error if it won't.
|
||||||
@@ -704,16 +808,24 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
* @param takerAddress The user Ethereum address who would like to fill this order.
|
* @param takerAddress The user Ethereum address who would like to fill this order.
|
||||||
* Must be available via the supplied Web3.Provider passed to 0x.js.
|
* Must be available via the supplied Web3.Provider passed to 0x.js.
|
||||||
*/
|
*/
|
||||||
public async validateFillOrKillOrderThrowIfInvalidAsync(signedOrder: SignedOrder,
|
public async validateFillOrKillOrderThrowIfInvalidAsync(
|
||||||
fillTakerTokenAmount: BigNumber,
|
signedOrder: SignedOrder,
|
||||||
takerAddress: string): Promise<void> {
|
fillTakerTokenAmount: BigNumber,
|
||||||
|
takerAddress: string,
|
||||||
|
): Promise<void> {
|
||||||
assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
|
assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
|
||||||
assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
|
assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
|
||||||
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
|
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
|
||||||
|
const normalizedTakerAddress = takerAddress.toLowerCase();
|
||||||
const zrxTokenAddress = this.getZRXTokenAddress();
|
const zrxTokenAddress = this.getZRXTokenAddress();
|
||||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
||||||
await this._orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync(
|
await this._orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync(
|
||||||
exchangeTradeEmulator, signedOrder, fillTakerTokenAmount, takerAddress, zrxTokenAddress);
|
exchangeTradeEmulator,
|
||||||
|
signedOrder,
|
||||||
|
fillTakerTokenAmount,
|
||||||
|
normalizedTakerAddress,
|
||||||
|
zrxTokenAddress,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Checks if rounding error will be > 0.1% when computing makerTokenAmount by doing:
|
* Checks if rounding error will be > 0.1% when computing makerTokenAmount by doing:
|
||||||
@@ -724,15 +836,19 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
* @param takerTokenAmount The order size on the taker side
|
* @param takerTokenAmount The order size on the taker side
|
||||||
* @param makerTokenAmount The order size on the maker side
|
* @param makerTokenAmount The order size on the maker side
|
||||||
*/
|
*/
|
||||||
public async isRoundingErrorAsync(fillTakerTokenAmount: BigNumber,
|
public async isRoundingErrorAsync(
|
||||||
takerTokenAmount: BigNumber,
|
fillTakerTokenAmount: BigNumber,
|
||||||
makerTokenAmount: BigNumber): Promise<boolean> {
|
takerTokenAmount: BigNumber,
|
||||||
|
makerTokenAmount: BigNumber,
|
||||||
|
): Promise<boolean> {
|
||||||
assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
|
assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
|
||||||
assert.isValidBaseUnitAmount('takerTokenAmount', takerTokenAmount);
|
assert.isValidBaseUnitAmount('takerTokenAmount', takerTokenAmount);
|
||||||
assert.isValidBaseUnitAmount('makerTokenAmount', makerTokenAmount);
|
assert.isValidBaseUnitAmount('makerTokenAmount', makerTokenAmount);
|
||||||
const exchangeInstance = await this._getExchangeContractAsync();
|
const exchangeInstance = await this._getExchangeContractAsync();
|
||||||
const isRoundingError = await exchangeInstance.isRoundingError.callAsync(
|
const isRoundingError = await exchangeInstance.isRoundingError.callAsync(
|
||||||
fillTakerTokenAmount, takerTokenAmount, makerTokenAmount,
|
fillTakerTokenAmount,
|
||||||
|
takerTokenAmount,
|
||||||
|
makerTokenAmount,
|
||||||
);
|
);
|
||||||
return isRoundingError;
|
return isRoundingError;
|
||||||
}
|
}
|
||||||
@@ -740,13 +856,13 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
* Checks if logs contain LogError, which is emmited by Exchange contract on transaction failure.
|
* Checks if logs contain LogError, which is emmited by Exchange contract on transaction failure.
|
||||||
* @param logs Transaction logs as returned by `zeroEx.awaitTransactionMinedAsync`
|
* @param logs Transaction logs as returned by `zeroEx.awaitTransactionMinedAsync`
|
||||||
*/
|
*/
|
||||||
public throwLogErrorsAsErrors(logs: Array<LogWithDecodedArgs<DecodedLogArgs>|Web3.LogEntry>): void {
|
public throwLogErrorsAsErrors(logs: Array<LogWithDecodedArgs<DecodedLogArgs> | Web3.LogEntry>): void {
|
||||||
const errLog = _.find(logs, {
|
const errLog = _.find(logs, {
|
||||||
event: ExchangeEvents.LogError,
|
event: ExchangeEvents.LogError,
|
||||||
}) as LogWithDecodedArgs<LogErrorContractEventArgs>|undefined;
|
});
|
||||||
if (!_.isUndefined(errLog)) {
|
if (!_.isUndefined(errLog)) {
|
||||||
const logArgs = errLog.args;
|
const logArgs = (errLog as LogWithDecodedArgs<LogErrorContractEventArgs>).args;
|
||||||
const errCode = logArgs.errorId.toNumber();
|
const errCode = logArgs.errorId;
|
||||||
const errMessage = this._exchangeContractErrCodesToMsg[errCode];
|
const errMessage = this._exchangeContractErrCodesToMsg[errCode];
|
||||||
throw new Error(errMessage);
|
throw new Error(errMessage);
|
||||||
}
|
}
|
||||||
@@ -756,25 +872,27 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
* @return Address of ZRX token
|
* @return Address of ZRX token
|
||||||
*/
|
*/
|
||||||
public getZRXTokenAddress(): string {
|
public getZRXTokenAddress(): string {
|
||||||
const contractAddress = this._getContractAddress(
|
const contractAddress = this._getContractAddress(artifacts.ZRXArtifact, this._zrxContractAddressIfExists);
|
||||||
artifacts.ZRXArtifact, this._zrxContractAddressIfExists,
|
|
||||||
);
|
|
||||||
return contractAddress;
|
return contractAddress;
|
||||||
}
|
}
|
||||||
private _invalidateContractInstances(): void {
|
private _invalidateContractInstances(): void {
|
||||||
this.unsubscribeAll();
|
this.unsubscribeAll();
|
||||||
delete this._exchangeContractIfExists;
|
delete this._exchangeContractIfExists;
|
||||||
}
|
}
|
||||||
private async _isValidSignatureUsingContractCallAsync(dataHex: string, ecSignature: ECSignature,
|
private async _isValidSignatureUsingContractCallAsync(
|
||||||
signerAddressHex: string): Promise<boolean> {
|
dataHex: string,
|
||||||
|
ecSignature: ECSignature,
|
||||||
|
signerAddressHex: string,
|
||||||
|
): Promise<boolean> {
|
||||||
assert.isHexString('dataHex', dataHex);
|
assert.isHexString('dataHex', dataHex);
|
||||||
assert.doesConformToSchema('ecSignature', ecSignature, schemas.ecSignatureSchema);
|
assert.doesConformToSchema('ecSignature', ecSignature, schemas.ecSignatureSchema);
|
||||||
assert.isETHAddressHex('signerAddressHex', signerAddressHex);
|
assert.isETHAddressHex('signerAddressHex', signerAddressHex);
|
||||||
|
const normalizedSignerAddress = signerAddressHex.toLowerCase();
|
||||||
|
|
||||||
const exchangeInstance = await this._getExchangeContractAsync();
|
const exchangeInstance = await this._getExchangeContractAsync();
|
||||||
|
|
||||||
const isValidSignature = await exchangeInstance.isValidSignature.callAsync(
|
const isValidSignature = await exchangeInstance.isValidSignature.callAsync(
|
||||||
signerAddressHex,
|
normalizedSignerAddress,
|
||||||
dataHex,
|
dataHex,
|
||||||
ecSignature.v,
|
ecSignature.v,
|
||||||
ecSignature.r,
|
ecSignature.r,
|
||||||
@@ -782,7 +900,7 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
);
|
);
|
||||||
return isValidSignature;
|
return isValidSignature;
|
||||||
}
|
}
|
||||||
private async _getOrderHashHexUsingContractCallAsync(order: Order|SignedOrder): Promise<string> {
|
private async _getOrderHashHexUsingContractCallAsync(order: Order | SignedOrder): Promise<string> {
|
||||||
const exchangeInstance = await this._getExchangeContractAsync();
|
const exchangeInstance = await this._getExchangeContractAsync();
|
||||||
const [orderAddresses, orderValues] = ExchangeWrapper._getOrderAddressesAndValues(order);
|
const [orderAddresses, orderValues] = ExchangeWrapper._getOrderAddressesAndValues(order);
|
||||||
const orderHashHex = await exchangeInstance.getOrderHash.callAsync(orderAddresses, orderValues);
|
const orderHashHex = await exchangeInstance.getOrderHash.callAsync(orderAddresses, orderValues);
|
||||||
@@ -792,10 +910,11 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
if (!_.isUndefined(this._exchangeContractIfExists)) {
|
if (!_.isUndefined(this._exchangeContractIfExists)) {
|
||||||
return this._exchangeContractIfExists;
|
return this._exchangeContractIfExists;
|
||||||
}
|
}
|
||||||
const web3ContractInstance = await this._instantiateContractIfExistsAsync(
|
const [abi, address] = await this._getContractAbiAndAddressFromArtifactsAsync(
|
||||||
artifacts.ExchangeArtifact, this._contractAddressIfExists,
|
artifacts.ExchangeArtifact,
|
||||||
|
this._contractAddressIfExists,
|
||||||
);
|
);
|
||||||
const contractInstance = new ExchangeContract(web3ContractInstance, this._web3Wrapper.getContractDefaults());
|
const contractInstance = new ExchangeContract(this._web3Wrapper, abi, address);
|
||||||
this._exchangeContractIfExists = contractInstance;
|
this._exchangeContractIfExists = contractInstance;
|
||||||
return this._exchangeContractIfExists;
|
return this._exchangeContractIfExists;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1 @@
|
|||||||
dummy_token.ts
|
*
|
||||||
ether_token.ts
|
|
||||||
exchange.ts
|
|
||||||
token_registry.ts
|
|
||||||
token_transfer_proxy.ts
|
|
||||||
token.ts
|
|
||||||
|
|||||||
@@ -1,33 +0,0 @@
|
|||||||
import {TxData, TxDataPayable} from '@0xproject/types';
|
|
||||||
import * as _ from 'lodash';
|
|
||||||
import * as Web3 from 'web3';
|
|
||||||
|
|
||||||
export class BaseContract {
|
|
||||||
protected web3ContractInstance: Web3.ContractInstance;
|
|
||||||
protected defaults: Partial<TxData>;
|
|
||||||
protected async applyDefaultsToTxDataAsync<T extends TxData|TxDataPayable>(
|
|
||||||
txData: T,
|
|
||||||
estimateGasAsync?: (txData: T) => Promise<number>,
|
|
||||||
): Promise<TxData> {
|
|
||||||
// Gas amount sourced with the following priorities:
|
|
||||||
// 1. Optional param passed in to public method call
|
|
||||||
// 2. Global config passed in at library instantiation
|
|
||||||
// 3. Gas estimate calculation + safety margin
|
|
||||||
const removeUndefinedProperties = _.pickBy;
|
|
||||||
const txDataWithDefaults = {
|
|
||||||
...removeUndefinedProperties(this.defaults),
|
|
||||||
...removeUndefinedProperties(txData as any),
|
|
||||||
// HACK: TS can't prove that T is spreadable.
|
|
||||||
// Awaiting https://github.com/Microsoft/TypeScript/pull/13288 to be merged
|
|
||||||
};
|
|
||||||
if (_.isUndefined(txDataWithDefaults.gas) && !_.isUndefined(estimateGasAsync)) {
|
|
||||||
const estimatedGas = await estimateGasAsync(txData);
|
|
||||||
txDataWithDefaults.gas = estimatedGas;
|
|
||||||
}
|
|
||||||
return txDataWithDefaults;
|
|
||||||
}
|
|
||||||
constructor(web3ContractInstance: Web3.ContractInstance, defaults: Partial<TxData>) {
|
|
||||||
this.web3ContractInstance = web3ContractInstance;
|
|
||||||
this.defaults = defaults;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
import {Web3Wrapper} from '@0xproject/web3-wrapper';
|
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import {artifacts} from '../artifacts';
|
import { artifacts } from '../artifacts';
|
||||||
import {Token, TokenMetadata} from '../types';
|
import { Token, TokenMetadata } from '../types';
|
||||||
import {assert} from '../utils/assert';
|
import { assert } from '../utils/assert';
|
||||||
import {constants} from '../utils/constants';
|
import { constants } from '../utils/constants';
|
||||||
|
|
||||||
import {ContractWrapper} from './contract_wrapper';
|
import { ContractWrapper } from './contract_wrapper';
|
||||||
import {TokenRegistryContract} from './generated/token_registry';
|
import { TokenRegistryContract } from './generated/token_registry';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class includes all the functionality related to interacting with the 0x Token Registry smart contract.
|
* This class includes all the functionality related to interacting with the 0x Token Registry smart contract.
|
||||||
@@ -15,7 +15,7 @@ import {TokenRegistryContract} from './generated/token_registry';
|
|||||||
export class TokenRegistryWrapper extends ContractWrapper {
|
export class TokenRegistryWrapper extends ContractWrapper {
|
||||||
private _tokenRegistryContractIfExists?: TokenRegistryContract;
|
private _tokenRegistryContractIfExists?: TokenRegistryContract;
|
||||||
private _contractAddressIfExists?: string;
|
private _contractAddressIfExists?: string;
|
||||||
private static _createTokenFromMetadata(metadata: TokenMetadata): Token|undefined {
|
private static _createTokenFromMetadata(metadata: TokenMetadata): Token | undefined {
|
||||||
if (metadata[0] === constants.NULL_ADDRESS) {
|
if (metadata[0] === constants.NULL_ADDRESS) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
@@ -23,7 +23,7 @@ export class TokenRegistryWrapper extends ContractWrapper {
|
|||||||
address: metadata[0],
|
address: metadata[0],
|
||||||
name: metadata[1],
|
name: metadata[1],
|
||||||
symbol: metadata[2],
|
symbol: metadata[2],
|
||||||
decimals: metadata[3].toNumber(),
|
decimals: metadata[3],
|
||||||
};
|
};
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
@@ -37,9 +37,8 @@ export class TokenRegistryWrapper extends ContractWrapper {
|
|||||||
*/
|
*/
|
||||||
public async getTokensAsync(): Promise<Token[]> {
|
public async getTokensAsync(): Promise<Token[]> {
|
||||||
const addresses = await this.getTokenAddressesAsync();
|
const addresses = await this.getTokenAddressesAsync();
|
||||||
const tokenPromises: Array<Promise<Token|undefined>> = _.map(
|
const tokenPromises: Array<Promise<Token | undefined>> = _.map(addresses, async (address: string) =>
|
||||||
addresses,
|
this.getTokenIfExistsAsync(address),
|
||||||
async (address: string) => this.getTokenIfExistsAsync(address),
|
|
||||||
);
|
);
|
||||||
const tokens = await Promise.all(tokenPromises);
|
const tokens = await Promise.all(tokenPromises);
|
||||||
return tokens as Token[];
|
return tokens as Token[];
|
||||||
@@ -51,21 +50,23 @@ export class TokenRegistryWrapper extends ContractWrapper {
|
|||||||
public async getTokenAddressesAsync(): Promise<string[]> {
|
public async getTokenAddressesAsync(): Promise<string[]> {
|
||||||
const tokenRegistryContract = await this._getTokenRegistryContractAsync();
|
const tokenRegistryContract = await this._getTokenRegistryContractAsync();
|
||||||
const addresses = await tokenRegistryContract.getTokenAddresses.callAsync();
|
const addresses = await tokenRegistryContract.getTokenAddresses.callAsync();
|
||||||
return addresses;
|
const lowerCaseAddresses = _.map(addresses, address => address.toLowerCase());
|
||||||
|
return lowerCaseAddresses;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Retrieves a token by address currently listed in the Token Registry smart contract
|
* Retrieves a token by address currently listed in the Token Registry smart contract
|
||||||
* @return An object that conforms to the Token interface or undefined if token not found.
|
* @return An object that conforms to the Token interface or undefined if token not found.
|
||||||
*/
|
*/
|
||||||
public async getTokenIfExistsAsync(address: string): Promise<Token|undefined> {
|
public async getTokenIfExistsAsync(address: string): Promise<Token | undefined> {
|
||||||
assert.isETHAddressHex('address', address);
|
assert.isETHAddressHex('address', address);
|
||||||
|
const normalizedAddress = address.toLowerCase();
|
||||||
|
|
||||||
const tokenRegistryContract = await this._getTokenRegistryContractAsync();
|
const tokenRegistryContract = await this._getTokenRegistryContractAsync();
|
||||||
const metadata = await tokenRegistryContract.getTokenMetaData.callAsync(address);
|
const metadata = await tokenRegistryContract.getTokenMetaData.callAsync(normalizedAddress);
|
||||||
const token = TokenRegistryWrapper._createTokenFromMetadata(metadata);
|
const token = TokenRegistryWrapper._createTokenFromMetadata(metadata);
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
public async getTokenAddressBySymbolIfExistsAsync(symbol: string): Promise<string|undefined> {
|
public async getTokenAddressBySymbolIfExistsAsync(symbol: string): Promise<string | undefined> {
|
||||||
assert.isString('symbol', symbol);
|
assert.isString('symbol', symbol);
|
||||||
const tokenRegistryContract = await this._getTokenRegistryContractAsync();
|
const tokenRegistryContract = await this._getTokenRegistryContractAsync();
|
||||||
const addressIfExists = await tokenRegistryContract.getTokenAddressBySymbol.callAsync(symbol);
|
const addressIfExists = await tokenRegistryContract.getTokenAddressBySymbol.callAsync(symbol);
|
||||||
@@ -74,7 +75,7 @@ export class TokenRegistryWrapper extends ContractWrapper {
|
|||||||
}
|
}
|
||||||
return addressIfExists;
|
return addressIfExists;
|
||||||
}
|
}
|
||||||
public async getTokenAddressByNameIfExistsAsync(name: string): Promise<string|undefined> {
|
public async getTokenAddressByNameIfExistsAsync(name: string): Promise<string | undefined> {
|
||||||
assert.isString('name', name);
|
assert.isString('name', name);
|
||||||
const tokenRegistryContract = await this._getTokenRegistryContractAsync();
|
const tokenRegistryContract = await this._getTokenRegistryContractAsync();
|
||||||
const addressIfExists = await tokenRegistryContract.getTokenAddressByName.callAsync(name);
|
const addressIfExists = await tokenRegistryContract.getTokenAddressByName.callAsync(name);
|
||||||
@@ -83,14 +84,14 @@ export class TokenRegistryWrapper extends ContractWrapper {
|
|||||||
}
|
}
|
||||||
return addressIfExists;
|
return addressIfExists;
|
||||||
}
|
}
|
||||||
public async getTokenBySymbolIfExistsAsync(symbol: string): Promise<Token|undefined> {
|
public async getTokenBySymbolIfExistsAsync(symbol: string): Promise<Token | undefined> {
|
||||||
assert.isString('symbol', symbol);
|
assert.isString('symbol', symbol);
|
||||||
const tokenRegistryContract = await this._getTokenRegistryContractAsync();
|
const tokenRegistryContract = await this._getTokenRegistryContractAsync();
|
||||||
const metadata = await tokenRegistryContract.getTokenBySymbol.callAsync(symbol);
|
const metadata = await tokenRegistryContract.getTokenBySymbol.callAsync(symbol);
|
||||||
const token = TokenRegistryWrapper._createTokenFromMetadata(metadata);
|
const token = TokenRegistryWrapper._createTokenFromMetadata(metadata);
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
public async getTokenByNameIfExistsAsync(name: string): Promise<Token|undefined> {
|
public async getTokenByNameIfExistsAsync(name: string): Promise<Token | undefined> {
|
||||||
assert.isString('name', name);
|
assert.isString('name', name);
|
||||||
const tokenRegistryContract = await this._getTokenRegistryContractAsync();
|
const tokenRegistryContract = await this._getTokenRegistryContractAsync();
|
||||||
const metadata = await tokenRegistryContract.getTokenByName.callAsync(name);
|
const metadata = await tokenRegistryContract.getTokenByName.callAsync(name);
|
||||||
@@ -104,7 +105,8 @@ export class TokenRegistryWrapper extends ContractWrapper {
|
|||||||
*/
|
*/
|
||||||
public getContractAddress(): string {
|
public getContractAddress(): string {
|
||||||
const contractAddress = this._getContractAddress(
|
const contractAddress = this._getContractAddress(
|
||||||
artifacts.TokenRegistryArtifact, this._contractAddressIfExists,
|
artifacts.TokenRegistryArtifact,
|
||||||
|
this._contractAddressIfExists,
|
||||||
);
|
);
|
||||||
return contractAddress;
|
return contractAddress;
|
||||||
}
|
}
|
||||||
@@ -115,12 +117,11 @@ export class TokenRegistryWrapper extends ContractWrapper {
|
|||||||
if (!_.isUndefined(this._tokenRegistryContractIfExists)) {
|
if (!_.isUndefined(this._tokenRegistryContractIfExists)) {
|
||||||
return this._tokenRegistryContractIfExists;
|
return this._tokenRegistryContractIfExists;
|
||||||
}
|
}
|
||||||
const web3ContractInstance = await this._instantiateContractIfExistsAsync(
|
const [abi, address] = await this._getContractAbiAndAddressFromArtifactsAsync(
|
||||||
artifacts.TokenRegistryArtifact, this._contractAddressIfExists,
|
artifacts.TokenRegistryArtifact,
|
||||||
);
|
this._contractAddressIfExists,
|
||||||
const contractInstance = new TokenRegistryContract(
|
|
||||||
web3ContractInstance, this._web3Wrapper.getContractDefaults(),
|
|
||||||
);
|
);
|
||||||
|
const contractInstance = new TokenRegistryContract(this._web3Wrapper, abi, address);
|
||||||
this._tokenRegistryContractIfExists = contractInstance;
|
this._tokenRegistryContractIfExists = contractInstance;
|
||||||
return this._tokenRegistryContractIfExists;
|
return this._tokenRegistryContractIfExists;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import {Web3Wrapper} from '@0xproject/web3-wrapper';
|
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import {artifacts} from '../artifacts';
|
import { artifacts } from '../artifacts';
|
||||||
|
import { assert } from '../utils/assert';
|
||||||
|
|
||||||
import {ContractWrapper} from './contract_wrapper';
|
import { ContractWrapper } from './contract_wrapper';
|
||||||
import {TokenTransferProxyContract} from './generated/token_transfer_proxy';
|
import { TokenTransferProxyContract } from './generated/token_transfer_proxy';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class includes the functionality related to interacting with the TokenTransferProxy contract.
|
* This class includes the functionality related to interacting with the TokenTransferProxy contract.
|
||||||
@@ -22,8 +23,12 @@ export class TokenTransferProxyWrapper extends ContractWrapper {
|
|||||||
* @return Whether the exchangeContractAddress is authorized.
|
* @return Whether the exchangeContractAddress is authorized.
|
||||||
*/
|
*/
|
||||||
public async isAuthorizedAsync(exchangeContractAddress: string): Promise<boolean> {
|
public async isAuthorizedAsync(exchangeContractAddress: string): Promise<boolean> {
|
||||||
|
assert.isETHAddressHex('exchangeContractAddress', exchangeContractAddress);
|
||||||
|
const normalizedExchangeContractAddress = exchangeContractAddress.toLowerCase();
|
||||||
const tokenTransferProxyContractInstance = await this._getTokenTransferProxyContractAsync();
|
const tokenTransferProxyContractInstance = await this._getTokenTransferProxyContractAsync();
|
||||||
const isAuthorized = await tokenTransferProxyContractInstance.authorized.callAsync(exchangeContractAddress);
|
const isAuthorized = await tokenTransferProxyContractInstance.authorized.callAsync(
|
||||||
|
normalizedExchangeContractAddress,
|
||||||
|
);
|
||||||
return isAuthorized;
|
return isAuthorized;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@@ -42,7 +47,8 @@ export class TokenTransferProxyWrapper extends ContractWrapper {
|
|||||||
*/
|
*/
|
||||||
public getContractAddress(): string {
|
public getContractAddress(): string {
|
||||||
const contractAddress = this._getContractAddress(
|
const contractAddress = this._getContractAddress(
|
||||||
artifacts.TokenTransferProxyArtifact, this._contractAddressIfExists,
|
artifacts.TokenTransferProxyArtifact,
|
||||||
|
this._contractAddressIfExists,
|
||||||
);
|
);
|
||||||
return contractAddress;
|
return contractAddress;
|
||||||
}
|
}
|
||||||
@@ -53,12 +59,11 @@ export class TokenTransferProxyWrapper extends ContractWrapper {
|
|||||||
if (!_.isUndefined(this._tokenTransferProxyContractIfExists)) {
|
if (!_.isUndefined(this._tokenTransferProxyContractIfExists)) {
|
||||||
return this._tokenTransferProxyContractIfExists;
|
return this._tokenTransferProxyContractIfExists;
|
||||||
}
|
}
|
||||||
const web3ContractInstance = await this._instantiateContractIfExistsAsync(
|
const [abi, address] = await this._getContractAbiAndAddressFromArtifactsAsync(
|
||||||
artifacts.TokenTransferProxyArtifact, this._contractAddressIfExists,
|
artifacts.TokenTransferProxyArtifact,
|
||||||
);
|
this._contractAddressIfExists,
|
||||||
const contractInstance = new TokenTransferProxyContract(
|
|
||||||
web3ContractInstance, this._web3Wrapper.getContractDefaults(),
|
|
||||||
);
|
);
|
||||||
|
const contractInstance = new TokenTransferProxyContract(this._web3Wrapper, abi, address);
|
||||||
this._tokenTransferProxyContractIfExists = contractInstance;
|
this._tokenTransferProxyContractIfExists = contractInstance;
|
||||||
return this._tokenTransferProxyContractIfExists;
|
return this._tokenTransferProxyContractIfExists;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,27 +1,17 @@
|
|||||||
import {schemas} from '@0xproject/json-schemas';
|
import { schemas } from '@0xproject/json-schemas';
|
||||||
import {Web3Wrapper} from '@0xproject/web3-wrapper';
|
import { LogWithDecodedArgs } from '@0xproject/types';
|
||||||
import BigNumber from 'bignumber.js';
|
import { AbiDecoder, BigNumber } from '@0xproject/utils';
|
||||||
|
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import {artifacts} from '../artifacts';
|
import { artifacts } from '../artifacts';
|
||||||
import {
|
import { BlockRange, EventCallback, IndexedFilterValues, MethodOpts, TransactionOpts, ZeroExError } from '../types';
|
||||||
BlockRange,
|
import { assert } from '../utils/assert';
|
||||||
EventCallback,
|
import { constants } from '../utils/constants';
|
||||||
IndexedFilterValues,
|
|
||||||
LogWithDecodedArgs,
|
|
||||||
MethodOpts,
|
|
||||||
TokenContractEventArgs,
|
|
||||||
TokenEvents,
|
|
||||||
TransactionOpts,
|
|
||||||
ZeroExError,
|
|
||||||
} from '../types';
|
|
||||||
import {AbiDecoder} from '../utils/abi_decoder';
|
|
||||||
import {assert} from '../utils/assert';
|
|
||||||
import {constants} from '../utils/constants';
|
|
||||||
|
|
||||||
import {ContractWrapper} from './contract_wrapper';
|
import { ContractWrapper } from './contract_wrapper';
|
||||||
import {TokenContract} from './generated/token';
|
import { TokenContract, TokenContractEventArgs, TokenEvents } from './generated/token';
|
||||||
import {TokenTransferProxyWrapper} from './token_transfer_proxy_wrapper';
|
import { TokenTransferProxyWrapper } from './token_transfer_proxy_wrapper';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class includes all the functionality related to interacting with ERC20 token contracts.
|
* This class includes all the functionality related to interacting with ERC20 token contracts.
|
||||||
@@ -30,10 +20,14 @@ import {TokenTransferProxyWrapper} from './token_transfer_proxy_wrapper';
|
|||||||
*/
|
*/
|
||||||
export class TokenWrapper extends ContractWrapper {
|
export class TokenWrapper extends ContractWrapper {
|
||||||
public UNLIMITED_ALLOWANCE_IN_BASE_UNITS = constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS;
|
public UNLIMITED_ALLOWANCE_IN_BASE_UNITS = constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS;
|
||||||
private _tokenContractsByAddress: {[address: string]: TokenContract};
|
private _tokenContractsByAddress: { [address: string]: TokenContract };
|
||||||
private _tokenTransferProxyWrapper: TokenTransferProxyWrapper;
|
private _tokenTransferProxyWrapper: TokenTransferProxyWrapper;
|
||||||
constructor(web3Wrapper: Web3Wrapper, networkId: number, abiDecoder: AbiDecoder,
|
constructor(
|
||||||
tokenTransferProxyWrapper: TokenTransferProxyWrapper) {
|
web3Wrapper: Web3Wrapper,
|
||||||
|
networkId: number,
|
||||||
|
abiDecoder: AbiDecoder,
|
||||||
|
tokenTransferProxyWrapper: TokenTransferProxyWrapper,
|
||||||
|
) {
|
||||||
super(web3Wrapper, networkId, abiDecoder);
|
super(web3Wrapper, networkId, abiDecoder);
|
||||||
this._tokenContractsByAddress = {};
|
this._tokenContractsByAddress = {};
|
||||||
this._tokenTransferProxyWrapper = tokenTransferProxyWrapper;
|
this._tokenTransferProxyWrapper = tokenTransferProxyWrapper;
|
||||||
@@ -45,14 +39,20 @@ export class TokenWrapper extends ContractWrapper {
|
|||||||
* @param methodOpts Optional arguments this method accepts.
|
* @param methodOpts Optional arguments this method accepts.
|
||||||
* @return The owner's ERC20 token balance in base units.
|
* @return The owner's ERC20 token balance in base units.
|
||||||
*/
|
*/
|
||||||
public async getBalanceAsync(tokenAddress: string, ownerAddress: string,
|
public async getBalanceAsync(
|
||||||
methodOpts?: MethodOpts): Promise<BigNumber> {
|
tokenAddress: string,
|
||||||
|
ownerAddress: string,
|
||||||
|
methodOpts?: MethodOpts,
|
||||||
|
): Promise<BigNumber> {
|
||||||
assert.isETHAddressHex('ownerAddress', ownerAddress);
|
assert.isETHAddressHex('ownerAddress', ownerAddress);
|
||||||
assert.isETHAddressHex('tokenAddress', tokenAddress);
|
assert.isETHAddressHex('tokenAddress', tokenAddress);
|
||||||
|
const normalizedTokenAddress = tokenAddress.toLowerCase();
|
||||||
|
const normalizedOwnerAddress = ownerAddress.toLowerCase();
|
||||||
|
|
||||||
const tokenContract = await this._getTokenContractAsync(tokenAddress);
|
const tokenContract = await this._getTokenContractAsync(normalizedTokenAddress);
|
||||||
const defaultBlock = _.isUndefined(methodOpts) ? undefined : methodOpts.defaultBlock;
|
const defaultBlock = _.isUndefined(methodOpts) ? undefined : methodOpts.defaultBlock;
|
||||||
let balance = await tokenContract.balanceOf.callAsync(ownerAddress, defaultBlock);
|
const txData = {};
|
||||||
|
let balance = await tokenContract.balanceOf.callAsync(normalizedOwnerAddress, txData, defaultBlock);
|
||||||
// Wrap BigNumbers returned from web3 with our own (later) version of BigNumber
|
// Wrap BigNumbers returned from web3 with our own (later) version of BigNumber
|
||||||
balance = new BigNumber(balance);
|
balance = new BigNumber(balance);
|
||||||
return balance;
|
return balance;
|
||||||
@@ -68,16 +68,24 @@ export class TokenWrapper extends ContractWrapper {
|
|||||||
* @param txOpts Transaction parameters.
|
* @param txOpts Transaction parameters.
|
||||||
* @return Transaction hash.
|
* @return Transaction hash.
|
||||||
*/
|
*/
|
||||||
public async setAllowanceAsync(tokenAddress: string, ownerAddress: string, spenderAddress: string,
|
public async setAllowanceAsync(
|
||||||
amountInBaseUnits: BigNumber, txOpts: TransactionOpts = {}): Promise<string> {
|
tokenAddress: string,
|
||||||
await assert.isSenderAddressAsync('ownerAddress', ownerAddress, this._web3Wrapper);
|
ownerAddress: string,
|
||||||
|
spenderAddress: string,
|
||||||
|
amountInBaseUnits: BigNumber,
|
||||||
|
txOpts: TransactionOpts = {},
|
||||||
|
): Promise<string> {
|
||||||
assert.isETHAddressHex('spenderAddress', spenderAddress);
|
assert.isETHAddressHex('spenderAddress', spenderAddress);
|
||||||
assert.isETHAddressHex('tokenAddress', tokenAddress);
|
assert.isETHAddressHex('tokenAddress', tokenAddress);
|
||||||
|
await assert.isSenderAddressAsync('ownerAddress', ownerAddress, this._web3Wrapper);
|
||||||
|
const normalizedTokenAddress = tokenAddress.toLowerCase();
|
||||||
|
const normalizedSpenderAddress = spenderAddress.toLowerCase();
|
||||||
|
const normalizedOwnerAddress = ownerAddress.toLowerCase();
|
||||||
assert.isValidBaseUnitAmount('amountInBaseUnits', amountInBaseUnits);
|
assert.isValidBaseUnitAmount('amountInBaseUnits', amountInBaseUnits);
|
||||||
|
|
||||||
const tokenContract = await this._getTokenContractAsync(tokenAddress);
|
const tokenContract = await this._getTokenContractAsync(normalizedTokenAddress);
|
||||||
const txHash = await tokenContract.approve.sendTransactionAsync(spenderAddress, amountInBaseUnits, {
|
const txHash = await tokenContract.approve.sendTransactionAsync(normalizedSpenderAddress, amountInBaseUnits, {
|
||||||
from: ownerAddress,
|
from: normalizedOwnerAddress,
|
||||||
gas: txOpts.gasLimit,
|
gas: txOpts.gasLimit,
|
||||||
gasPrice: txOpts.gasPrice,
|
gasPrice: txOpts.gasPrice,
|
||||||
});
|
});
|
||||||
@@ -95,10 +103,24 @@ export class TokenWrapper extends ContractWrapper {
|
|||||||
* @param txOpts Transaction parameters.
|
* @param txOpts Transaction parameters.
|
||||||
* @return Transaction hash.
|
* @return Transaction hash.
|
||||||
*/
|
*/
|
||||||
public async setUnlimitedAllowanceAsync(tokenAddress: string, ownerAddress: string,
|
public async setUnlimitedAllowanceAsync(
|
||||||
spenderAddress: string, txOpts: TransactionOpts = {}): Promise<string> {
|
tokenAddress: string,
|
||||||
|
ownerAddress: string,
|
||||||
|
spenderAddress: string,
|
||||||
|
txOpts: TransactionOpts = {},
|
||||||
|
): Promise<string> {
|
||||||
|
assert.isETHAddressHex('ownerAddress', ownerAddress);
|
||||||
|
assert.isETHAddressHex('tokenAddress', tokenAddress);
|
||||||
|
assert.isETHAddressHex('spenderAddress', spenderAddress);
|
||||||
|
const normalizedTokenAddress = tokenAddress.toLowerCase();
|
||||||
|
const normalizedOwnerAddress = ownerAddress.toLowerCase();
|
||||||
|
const normalizedSpenderAddress = spenderAddress.toLowerCase();
|
||||||
const txHash = await this.setAllowanceAsync(
|
const txHash = await this.setAllowanceAsync(
|
||||||
tokenAddress, ownerAddress, spenderAddress, this.UNLIMITED_ALLOWANCE_IN_BASE_UNITS, txOpts,
|
normalizedTokenAddress,
|
||||||
|
normalizedOwnerAddress,
|
||||||
|
normalizedSpenderAddress,
|
||||||
|
this.UNLIMITED_ALLOWANCE_IN_BASE_UNITS,
|
||||||
|
txOpts,
|
||||||
);
|
);
|
||||||
return txHash;
|
return txHash;
|
||||||
}
|
}
|
||||||
@@ -110,14 +132,28 @@ export class TokenWrapper extends ContractWrapper {
|
|||||||
* @param spenderAddress The hex encoded user Ethereum address who can spend the allowance you are fetching.
|
* @param spenderAddress The hex encoded user Ethereum address who can spend the allowance you are fetching.
|
||||||
* @param methodOpts Optional arguments this method accepts.
|
* @param methodOpts Optional arguments this method accepts.
|
||||||
*/
|
*/
|
||||||
public async getAllowanceAsync(tokenAddress: string, ownerAddress: string,
|
public async getAllowanceAsync(
|
||||||
spenderAddress: string, methodOpts?: MethodOpts): Promise<BigNumber> {
|
tokenAddress: string,
|
||||||
|
ownerAddress: string,
|
||||||
|
spenderAddress: string,
|
||||||
|
methodOpts?: MethodOpts,
|
||||||
|
): Promise<BigNumber> {
|
||||||
assert.isETHAddressHex('ownerAddress', ownerAddress);
|
assert.isETHAddressHex('ownerAddress', ownerAddress);
|
||||||
assert.isETHAddressHex('tokenAddress', tokenAddress);
|
assert.isETHAddressHex('tokenAddress', tokenAddress);
|
||||||
|
assert.isETHAddressHex('spenderAddress', spenderAddress);
|
||||||
|
const normalizedTokenAddress = tokenAddress.toLowerCase();
|
||||||
|
const normalizedOwnerAddress = ownerAddress.toLowerCase();
|
||||||
|
const normalizedSpenderAddress = spenderAddress.toLowerCase();
|
||||||
|
|
||||||
const tokenContract = await this._getTokenContractAsync(tokenAddress);
|
const tokenContract = await this._getTokenContractAsync(normalizedTokenAddress);
|
||||||
const defaultBlock = _.isUndefined(methodOpts) ? undefined : methodOpts.defaultBlock;
|
const defaultBlock = _.isUndefined(methodOpts) ? undefined : methodOpts.defaultBlock;
|
||||||
let allowanceInBaseUnits = await tokenContract.allowance.callAsync(ownerAddress, spenderAddress, defaultBlock);
|
const txData = {};
|
||||||
|
let allowanceInBaseUnits = await tokenContract.allowance.callAsync(
|
||||||
|
normalizedOwnerAddress,
|
||||||
|
normalizedSpenderAddress,
|
||||||
|
txData,
|
||||||
|
defaultBlock,
|
||||||
|
);
|
||||||
// Wrap BigNumbers returned from web3 with our own (later) version of BigNumber
|
// Wrap BigNumbers returned from web3 with our own (later) version of BigNumber
|
||||||
allowanceInBaseUnits = new BigNumber(allowanceInBaseUnits);
|
allowanceInBaseUnits = new BigNumber(allowanceInBaseUnits);
|
||||||
return allowanceInBaseUnits;
|
return allowanceInBaseUnits;
|
||||||
@@ -128,13 +164,23 @@ export class TokenWrapper extends ContractWrapper {
|
|||||||
* @param ownerAddress The hex encoded user Ethereum address whose proxy contract allowance we are retrieving.
|
* @param ownerAddress The hex encoded user Ethereum address whose proxy contract allowance we are retrieving.
|
||||||
* @param methodOpts Optional arguments this method accepts.
|
* @param methodOpts Optional arguments this method accepts.
|
||||||
*/
|
*/
|
||||||
public async getProxyAllowanceAsync(tokenAddress: string, ownerAddress: string,
|
public async getProxyAllowanceAsync(
|
||||||
methodOpts?: MethodOpts): Promise<BigNumber> {
|
tokenAddress: string,
|
||||||
|
ownerAddress: string,
|
||||||
|
methodOpts?: MethodOpts,
|
||||||
|
): Promise<BigNumber> {
|
||||||
assert.isETHAddressHex('ownerAddress', ownerAddress);
|
assert.isETHAddressHex('ownerAddress', ownerAddress);
|
||||||
assert.isETHAddressHex('tokenAddress', tokenAddress);
|
assert.isETHAddressHex('tokenAddress', tokenAddress);
|
||||||
|
const normalizedTokenAddress = tokenAddress.toLowerCase();
|
||||||
|
const normalizedOwnerAddress = ownerAddress.toLowerCase();
|
||||||
|
|
||||||
const proxyAddress = this._tokenTransferProxyWrapper.getContractAddress();
|
const proxyAddress = this._tokenTransferProxyWrapper.getContractAddress();
|
||||||
const allowanceInBaseUnits = await this.getAllowanceAsync(tokenAddress, ownerAddress, proxyAddress, methodOpts);
|
const allowanceInBaseUnits = await this.getAllowanceAsync(
|
||||||
|
normalizedTokenAddress,
|
||||||
|
normalizedOwnerAddress,
|
||||||
|
proxyAddress,
|
||||||
|
methodOpts,
|
||||||
|
);
|
||||||
return allowanceInBaseUnits;
|
return allowanceInBaseUnits;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@@ -147,15 +193,25 @@ export class TokenWrapper extends ContractWrapper {
|
|||||||
* @param txOpts Transaction parameters.
|
* @param txOpts Transaction parameters.
|
||||||
* @return Transaction hash.
|
* @return Transaction hash.
|
||||||
*/
|
*/
|
||||||
public async setProxyAllowanceAsync(tokenAddress: string, ownerAddress: string,
|
public async setProxyAllowanceAsync(
|
||||||
amountInBaseUnits: BigNumber, txOpts: TransactionOpts = {}): Promise<string> {
|
tokenAddress: string,
|
||||||
|
ownerAddress: string,
|
||||||
|
amountInBaseUnits: BigNumber,
|
||||||
|
txOpts: TransactionOpts = {},
|
||||||
|
): Promise<string> {
|
||||||
assert.isETHAddressHex('ownerAddress', ownerAddress);
|
assert.isETHAddressHex('ownerAddress', ownerAddress);
|
||||||
assert.isETHAddressHex('tokenAddress', tokenAddress);
|
assert.isETHAddressHex('tokenAddress', tokenAddress);
|
||||||
|
const normalizedTokenAddress = tokenAddress.toLowerCase();
|
||||||
|
const normalizedOwnerAddress = ownerAddress.toLowerCase();
|
||||||
assert.isValidBaseUnitAmount('amountInBaseUnits', amountInBaseUnits);
|
assert.isValidBaseUnitAmount('amountInBaseUnits', amountInBaseUnits);
|
||||||
|
|
||||||
const proxyAddress = this._tokenTransferProxyWrapper.getContractAddress();
|
const proxyAddress = this._tokenTransferProxyWrapper.getContractAddress();
|
||||||
const txHash = await this.setAllowanceAsync(
|
const txHash = await this.setAllowanceAsync(
|
||||||
tokenAddress, ownerAddress, proxyAddress, amountInBaseUnits, txOpts,
|
normalizedTokenAddress,
|
||||||
|
normalizedOwnerAddress,
|
||||||
|
proxyAddress,
|
||||||
|
amountInBaseUnits,
|
||||||
|
txOpts,
|
||||||
);
|
);
|
||||||
return txHash;
|
return txHash;
|
||||||
}
|
}
|
||||||
@@ -171,10 +227,19 @@ export class TokenWrapper extends ContractWrapper {
|
|||||||
* @return Transaction hash.
|
* @return Transaction hash.
|
||||||
*/
|
*/
|
||||||
public async setUnlimitedProxyAllowanceAsync(
|
public async setUnlimitedProxyAllowanceAsync(
|
||||||
tokenAddress: string, ownerAddress: string, txOpts: TransactionOpts = {},
|
tokenAddress: string,
|
||||||
|
ownerAddress: string,
|
||||||
|
txOpts: TransactionOpts = {},
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
|
assert.isETHAddressHex('ownerAddress', ownerAddress);
|
||||||
|
assert.isETHAddressHex('tokenAddress', tokenAddress);
|
||||||
|
const normalizedTokenAddress = tokenAddress.toLowerCase();
|
||||||
|
const normalizedOwnerAddress = ownerAddress.toLowerCase();
|
||||||
const txHash = await this.setProxyAllowanceAsync(
|
const txHash = await this.setProxyAllowanceAsync(
|
||||||
tokenAddress, ownerAddress, this.UNLIMITED_ALLOWANCE_IN_BASE_UNITS, txOpts,
|
normalizedTokenAddress,
|
||||||
|
normalizedOwnerAddress,
|
||||||
|
this.UNLIMITED_ALLOWANCE_IN_BASE_UNITS,
|
||||||
|
txOpts,
|
||||||
);
|
);
|
||||||
return txHash;
|
return txHash;
|
||||||
}
|
}
|
||||||
@@ -187,22 +252,30 @@ export class TokenWrapper extends ContractWrapper {
|
|||||||
* @param txOpts Transaction parameters.
|
* @param txOpts Transaction parameters.
|
||||||
* @return Transaction hash.
|
* @return Transaction hash.
|
||||||
*/
|
*/
|
||||||
public async transferAsync(tokenAddress: string, fromAddress: string, toAddress: string,
|
public async transferAsync(
|
||||||
amountInBaseUnits: BigNumber, txOpts: TransactionOpts = {}): Promise<string> {
|
tokenAddress: string,
|
||||||
|
fromAddress: string,
|
||||||
|
toAddress: string,
|
||||||
|
amountInBaseUnits: BigNumber,
|
||||||
|
txOpts: TransactionOpts = {},
|
||||||
|
): Promise<string> {
|
||||||
assert.isETHAddressHex('tokenAddress', tokenAddress);
|
assert.isETHAddressHex('tokenAddress', tokenAddress);
|
||||||
await assert.isSenderAddressAsync('fromAddress', fromAddress, this._web3Wrapper);
|
|
||||||
assert.isETHAddressHex('toAddress', toAddress);
|
assert.isETHAddressHex('toAddress', toAddress);
|
||||||
|
await assert.isSenderAddressAsync('fromAddress', fromAddress, this._web3Wrapper);
|
||||||
|
const normalizedTokenAddress = tokenAddress.toLowerCase();
|
||||||
|
const normalizedFromAddress = fromAddress.toLowerCase();
|
||||||
|
const normalizedToAddress = toAddress.toLowerCase();
|
||||||
assert.isValidBaseUnitAmount('amountInBaseUnits', amountInBaseUnits);
|
assert.isValidBaseUnitAmount('amountInBaseUnits', amountInBaseUnits);
|
||||||
|
|
||||||
const tokenContract = await this._getTokenContractAsync(tokenAddress);
|
const tokenContract = await this._getTokenContractAsync(normalizedTokenAddress);
|
||||||
|
|
||||||
const fromAddressBalance = await this.getBalanceAsync(tokenAddress, fromAddress);
|
const fromAddressBalance = await this.getBalanceAsync(normalizedTokenAddress, normalizedFromAddress);
|
||||||
if (fromAddressBalance.lessThan(amountInBaseUnits)) {
|
if (fromAddressBalance.lessThan(amountInBaseUnits)) {
|
||||||
throw new Error(ZeroExError.InsufficientBalanceForTransfer);
|
throw new Error(ZeroExError.InsufficientBalanceForTransfer);
|
||||||
}
|
}
|
||||||
|
|
||||||
const txHash = await tokenContract.transfer.sendTransactionAsync(toAddress, amountInBaseUnits, {
|
const txHash = await tokenContract.transfer.sendTransactionAsync(normalizedToAddress, amountInBaseUnits, {
|
||||||
from: fromAddress,
|
from: normalizedFromAddress,
|
||||||
gas: txOpts.gasLimit,
|
gas: txOpts.gasLimit,
|
||||||
gasPrice: txOpts.gasPrice,
|
gasPrice: txOpts.gasPrice,
|
||||||
});
|
});
|
||||||
@@ -222,31 +295,46 @@ export class TokenWrapper extends ContractWrapper {
|
|||||||
* @param txOpts Transaction parameters.
|
* @param txOpts Transaction parameters.
|
||||||
* @return Transaction hash.
|
* @return Transaction hash.
|
||||||
*/
|
*/
|
||||||
public async transferFromAsync(tokenAddress: string, fromAddress: string, toAddress: string,
|
public async transferFromAsync(
|
||||||
senderAddress: string, amountInBaseUnits: BigNumber, txOpts: TransactionOpts = {}):
|
tokenAddress: string,
|
||||||
Promise<string> {
|
fromAddress: string,
|
||||||
assert.isETHAddressHex('tokenAddress', tokenAddress);
|
toAddress: string,
|
||||||
assert.isETHAddressHex('fromAddress', fromAddress);
|
senderAddress: string,
|
||||||
|
amountInBaseUnits: BigNumber,
|
||||||
|
txOpts: TransactionOpts = {},
|
||||||
|
): Promise<string> {
|
||||||
assert.isETHAddressHex('toAddress', toAddress);
|
assert.isETHAddressHex('toAddress', toAddress);
|
||||||
|
assert.isETHAddressHex('fromAddress', fromAddress);
|
||||||
|
assert.isETHAddressHex('tokenAddress', tokenAddress);
|
||||||
await assert.isSenderAddressAsync('senderAddress', senderAddress, this._web3Wrapper);
|
await assert.isSenderAddressAsync('senderAddress', senderAddress, this._web3Wrapper);
|
||||||
|
const normalizedToAddress = toAddress.toLowerCase();
|
||||||
|
const normalizedFromAddress = fromAddress.toLowerCase();
|
||||||
|
const normalizedTokenAddress = tokenAddress.toLowerCase();
|
||||||
|
const normalizedSenderAddress = senderAddress.toLowerCase();
|
||||||
assert.isValidBaseUnitAmount('amountInBaseUnits', amountInBaseUnits);
|
assert.isValidBaseUnitAmount('amountInBaseUnits', amountInBaseUnits);
|
||||||
|
|
||||||
const tokenContract = await this._getTokenContractAsync(tokenAddress);
|
const tokenContract = await this._getTokenContractAsync(normalizedTokenAddress);
|
||||||
|
|
||||||
const fromAddressAllowance = await this.getAllowanceAsync(tokenAddress, fromAddress, senderAddress);
|
const fromAddressAllowance = await this.getAllowanceAsync(
|
||||||
|
normalizedTokenAddress,
|
||||||
|
normalizedFromAddress,
|
||||||
|
normalizedSenderAddress,
|
||||||
|
);
|
||||||
if (fromAddressAllowance.lessThan(amountInBaseUnits)) {
|
if (fromAddressAllowance.lessThan(amountInBaseUnits)) {
|
||||||
throw new Error(ZeroExError.InsufficientAllowanceForTransfer);
|
throw new Error(ZeroExError.InsufficientAllowanceForTransfer);
|
||||||
}
|
}
|
||||||
|
|
||||||
const fromAddressBalance = await this.getBalanceAsync(tokenAddress, fromAddress);
|
const fromAddressBalance = await this.getBalanceAsync(normalizedTokenAddress, normalizedFromAddress);
|
||||||
if (fromAddressBalance.lessThan(amountInBaseUnits)) {
|
if (fromAddressBalance.lessThan(amountInBaseUnits)) {
|
||||||
throw new Error(ZeroExError.InsufficientBalanceForTransfer);
|
throw new Error(ZeroExError.InsufficientBalanceForTransfer);
|
||||||
}
|
}
|
||||||
|
|
||||||
const txHash = await tokenContract.transferFrom.sendTransactionAsync(
|
const txHash = await tokenContract.transferFrom.sendTransactionAsync(
|
||||||
fromAddress, toAddress, amountInBaseUnits,
|
normalizedFromAddress,
|
||||||
|
normalizedToAddress,
|
||||||
|
amountInBaseUnits,
|
||||||
{
|
{
|
||||||
from: senderAddress,
|
from: normalizedSenderAddress,
|
||||||
gas: txOpts.gasLimit,
|
gas: txOpts.gasLimit,
|
||||||
gasPrice: txOpts.gasPrice,
|
gasPrice: txOpts.gasPrice,
|
||||||
},
|
},
|
||||||
@@ -263,14 +351,22 @@ export class TokenWrapper extends ContractWrapper {
|
|||||||
* @return Subscription token used later to unsubscribe
|
* @return Subscription token used later to unsubscribe
|
||||||
*/
|
*/
|
||||||
public subscribe<ArgsType extends TokenContractEventArgs>(
|
public subscribe<ArgsType extends TokenContractEventArgs>(
|
||||||
tokenAddress: string, eventName: TokenEvents, indexFilterValues: IndexedFilterValues,
|
tokenAddress: string,
|
||||||
callback: EventCallback<ArgsType>): string {
|
eventName: TokenEvents,
|
||||||
|
indexFilterValues: IndexedFilterValues,
|
||||||
|
callback: EventCallback<ArgsType>,
|
||||||
|
): string {
|
||||||
assert.isETHAddressHex('tokenAddress', tokenAddress);
|
assert.isETHAddressHex('tokenAddress', tokenAddress);
|
||||||
|
const normalizedTokenAddress = tokenAddress.toLowerCase();
|
||||||
assert.doesBelongToStringEnum('eventName', eventName, TokenEvents);
|
assert.doesBelongToStringEnum('eventName', eventName, TokenEvents);
|
||||||
assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
|
assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
|
||||||
assert.isFunction('callback', callback);
|
assert.isFunction('callback', callback);
|
||||||
const subscriptionToken = this._subscribe<ArgsType>(
|
const subscriptionToken = this._subscribe<ArgsType>(
|
||||||
tokenAddress, eventName, indexFilterValues, artifacts.TokenArtifact.abi, callback,
|
normalizedTokenAddress,
|
||||||
|
eventName,
|
||||||
|
indexFilterValues,
|
||||||
|
artifacts.TokenArtifact.abi,
|
||||||
|
callback,
|
||||||
);
|
);
|
||||||
return subscriptionToken;
|
return subscriptionToken;
|
||||||
}
|
}
|
||||||
@@ -285,7 +381,7 @@ export class TokenWrapper extends ContractWrapper {
|
|||||||
* Cancels all existing subscriptions
|
* Cancels all existing subscriptions
|
||||||
*/
|
*/
|
||||||
public unsubscribeAll(): void {
|
public unsubscribeAll(): void {
|
||||||
super.unsubscribeAll();
|
super._unsubscribeAll();
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Gets historical logs without creating a subscription
|
* Gets historical logs without creating a subscription
|
||||||
@@ -297,14 +393,22 @@ export class TokenWrapper extends ContractWrapper {
|
|||||||
* @return Array of logs that match the parameters
|
* @return Array of logs that match the parameters
|
||||||
*/
|
*/
|
||||||
public async getLogsAsync<ArgsType extends TokenContractEventArgs>(
|
public async getLogsAsync<ArgsType extends TokenContractEventArgs>(
|
||||||
tokenAddress: string, eventName: TokenEvents, blockRange: BlockRange,
|
tokenAddress: string,
|
||||||
indexFilterValues: IndexedFilterValues): Promise<Array<LogWithDecodedArgs<ArgsType>>> {
|
eventName: TokenEvents,
|
||||||
|
blockRange: BlockRange,
|
||||||
|
indexFilterValues: IndexedFilterValues,
|
||||||
|
): Promise<Array<LogWithDecodedArgs<ArgsType>>> {
|
||||||
assert.isETHAddressHex('tokenAddress', tokenAddress);
|
assert.isETHAddressHex('tokenAddress', tokenAddress);
|
||||||
|
const normalizedTokenAddress = tokenAddress.toLowerCase();
|
||||||
assert.doesBelongToStringEnum('eventName', eventName, TokenEvents);
|
assert.doesBelongToStringEnum('eventName', eventName, TokenEvents);
|
||||||
assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema);
|
assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema);
|
||||||
assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
|
assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
|
||||||
const logs = await this._getLogsAsync<ArgsType>(
|
const logs = await this._getLogsAsync<ArgsType>(
|
||||||
tokenAddress, eventName, blockRange, indexFilterValues, artifacts.TokenArtifact.abi,
|
normalizedTokenAddress,
|
||||||
|
eventName,
|
||||||
|
blockRange,
|
||||||
|
indexFilterValues,
|
||||||
|
artifacts.TokenArtifact.abi,
|
||||||
);
|
);
|
||||||
return logs;
|
return logs;
|
||||||
}
|
}
|
||||||
@@ -313,18 +417,18 @@ export class TokenWrapper extends ContractWrapper {
|
|||||||
this._tokenContractsByAddress = {};
|
this._tokenContractsByAddress = {};
|
||||||
}
|
}
|
||||||
private async _getTokenContractAsync(tokenAddress: string): Promise<TokenContract> {
|
private async _getTokenContractAsync(tokenAddress: string): Promise<TokenContract> {
|
||||||
let tokenContract = this._tokenContractsByAddress[tokenAddress];
|
const normalizedTokenAddress = tokenAddress.toLowerCase();
|
||||||
|
let tokenContract = this._tokenContractsByAddress[normalizedTokenAddress];
|
||||||
if (!_.isUndefined(tokenContract)) {
|
if (!_.isUndefined(tokenContract)) {
|
||||||
return tokenContract;
|
return tokenContract;
|
||||||
}
|
}
|
||||||
const web3ContractInstance = await this._instantiateContractIfExistsAsync(
|
const [abi, address] = await this._getContractAbiAndAddressFromArtifactsAsync(
|
||||||
artifacts.TokenArtifact, tokenAddress,
|
artifacts.TokenArtifact,
|
||||||
);
|
normalizedTokenAddress,
|
||||||
const contractInstance = new TokenContract(
|
|
||||||
web3ContractInstance, this._web3Wrapper.getContractDefaults(),
|
|
||||||
);
|
);
|
||||||
|
const contractInstance = new TokenContract(this._web3Wrapper, abi, address);
|
||||||
tokenContract = contractInstance;
|
tokenContract = contractInstance;
|
||||||
this._tokenContractsByAddress[tokenAddress] = tokenContract;
|
this._tokenContractsByAddress[normalizedTokenAddress] = tokenContract;
|
||||||
return tokenContract;
|
return tokenContract;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
31
packages/0x.js/src/globals.d.ts
vendored
31
packages/0x.js/src/globals.d.ts
vendored
@@ -1,5 +1,3 @@
|
|||||||
/// <reference types='chai-typescript-typings' />
|
|
||||||
/// <reference types='chai-as-promised-typescript-typings' />
|
|
||||||
declare module 'web3_beta';
|
declare module 'web3_beta';
|
||||||
declare module 'chai-bignumber';
|
declare module 'chai-bignumber';
|
||||||
declare module 'dirty-chai';
|
declare module 'dirty-chai';
|
||||||
@@ -27,18 +25,6 @@ declare module '*.json' {
|
|||||||
/* tslint:enable */
|
/* tslint:enable */
|
||||||
}
|
}
|
||||||
|
|
||||||
// find-version declarations
|
|
||||||
declare function findVersions(version: string): string[];
|
|
||||||
declare module 'find-versions' {
|
|
||||||
export = findVersions;
|
|
||||||
}
|
|
||||||
|
|
||||||
// compare-version declarations
|
|
||||||
declare function compareVersions(firstVersion: string, secondVersion: string): number;
|
|
||||||
declare module 'compare-versions' {
|
|
||||||
export = compareVersions;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module 'ethereumjs-abi' {
|
declare module 'ethereumjs-abi' {
|
||||||
const soliditySHA3: (argTypes: string[], args: any[]) => Buffer;
|
const soliditySHA3: (argTypes: string[], args: any[]) => Buffer;
|
||||||
}
|
}
|
||||||
@@ -55,20 +41,3 @@ declare module 'truffle-hdwallet-provider' {
|
|||||||
}
|
}
|
||||||
export = HDWalletProvider;
|
export = HDWalletProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
// abi-decoder declarations
|
|
||||||
interface DecodedLogArg {
|
|
||||||
}
|
|
||||||
interface DecodedLog {
|
|
||||||
name: string;
|
|
||||||
events: DecodedLogArg[];
|
|
||||||
}
|
|
||||||
declare module 'abi-decoder' {
|
|
||||||
import * as Web3 from 'web3';
|
|
||||||
const addABI: (abi: Web3.AbiDefinition) => void;
|
|
||||||
const decodeLogs: (logs: Web3.LogEntry[]) => DecodedLog[];
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module 'web3/lib/solidity/coder' {
|
|
||||||
const decodeParams: (types: string[], data: string) => any[];
|
|
||||||
}
|
|
||||||
|
|||||||
6
packages/0x.js/src/globalsAugment.d.ts
vendored
6
packages/0x.js/src/globalsAugment.d.ts
vendored
@@ -1,4 +1,4 @@
|
|||||||
import BigNumber from 'bignumber.js';
|
import { BigNumber } from '@0xproject/utils';
|
||||||
|
|
||||||
// HACK: This module overrides the Chai namespace so that we can use BigNumber types inside.
|
// HACK: This module overrides the Chai namespace so that we can use BigNumber types inside.
|
||||||
// Source: https://github.com/Microsoft/TypeScript/issues/7352#issuecomment-191547232
|
// Source: https://github.com/Microsoft/TypeScript/issues/7352#issuecomment-191547232
|
||||||
@@ -9,7 +9,7 @@ declare global {
|
|||||||
/* tslint:disable */
|
/* tslint:disable */
|
||||||
namespace Chai {
|
namespace Chai {
|
||||||
interface NumberComparer {
|
interface NumberComparer {
|
||||||
(value: number|BigNumber, message?: string): Assertion;
|
(value: number | BigNumber, message?: string): Assertion;
|
||||||
}
|
}
|
||||||
interface NumericComparison {
|
interface NumericComparison {
|
||||||
greaterThan: NumberComparer;
|
greaterThan: NumberComparer;
|
||||||
@@ -18,6 +18,6 @@ declare global {
|
|||||||
/* tslint:enable */
|
/* tslint:enable */
|
||||||
interface DecodedLogArg {
|
interface DecodedLogArg {
|
||||||
name: string;
|
name: string;
|
||||||
value: string|BigNumber;
|
value: string | BigNumber;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
export {ZeroEx} from './0x';
|
export { ZeroEx } from './0x';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
Order,
|
Order,
|
||||||
BlockParamLiteral,
|
|
||||||
SignedOrder,
|
SignedOrder,
|
||||||
ECSignature,
|
ECSignature,
|
||||||
ZeroExError,
|
ZeroExError,
|
||||||
@@ -10,30 +9,13 @@ export {
|
|||||||
ExchangeContractErrs,
|
ExchangeContractErrs,
|
||||||
ContractEvent,
|
ContractEvent,
|
||||||
Token,
|
Token,
|
||||||
ExchangeEvents,
|
|
||||||
TokenEvents,
|
|
||||||
IndexedFilterValues,
|
IndexedFilterValues,
|
||||||
BlockRange,
|
BlockRange,
|
||||||
BlockParam,
|
|
||||||
OrderCancellationRequest,
|
OrderCancellationRequest,
|
||||||
OrderFillRequest,
|
OrderFillRequest,
|
||||||
LogErrorContractEventArgs,
|
|
||||||
LogCancelContractEventArgs,
|
|
||||||
LogFillContractEventArgs,
|
|
||||||
ExchangeContractEventArgs,
|
|
||||||
TransferContractEventArgs,
|
|
||||||
ApprovalContractEventArgs,
|
|
||||||
TokenContractEventArgs,
|
|
||||||
EtherTokenContractEventArgs,
|
|
||||||
WithdrawalContractEventArgs,
|
|
||||||
DepositContractEventArgs,
|
|
||||||
ContractEventArgs,
|
ContractEventArgs,
|
||||||
ContractEventArg,
|
|
||||||
Web3Provider,
|
Web3Provider,
|
||||||
ZeroExConfig,
|
ZeroExConfig,
|
||||||
EtherTokenEvents,
|
|
||||||
TransactionReceiptWithDecodedLogs,
|
|
||||||
LogWithDecodedArgs,
|
|
||||||
MethodOpts,
|
MethodOpts,
|
||||||
OrderTransactionOpts,
|
OrderTransactionOpts,
|
||||||
TransactionOpts,
|
TransactionOpts,
|
||||||
@@ -48,5 +30,32 @@ export {
|
|||||||
} from './types';
|
} from './types';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
BlockParamLiteral,
|
||||||
|
BlockParam,
|
||||||
|
ContractEventArg,
|
||||||
|
LogWithDecodedArgs,
|
||||||
TransactionReceipt,
|
TransactionReceipt,
|
||||||
|
TransactionReceiptWithDecodedLogs,
|
||||||
} from '@0xproject/types';
|
} from '@0xproject/types';
|
||||||
|
|
||||||
|
export {
|
||||||
|
EtherTokenContractEventArgs,
|
||||||
|
WithdrawalContractEventArgs,
|
||||||
|
DepositContractEventArgs,
|
||||||
|
EtherTokenEvents,
|
||||||
|
} from './contract_wrappers/generated/ether_token';
|
||||||
|
|
||||||
|
export {
|
||||||
|
TransferContractEventArgs,
|
||||||
|
ApprovalContractEventArgs,
|
||||||
|
TokenContractEventArgs,
|
||||||
|
TokenEvents,
|
||||||
|
} from './contract_wrappers/generated/token';
|
||||||
|
|
||||||
|
export {
|
||||||
|
LogErrorContractEventArgs,
|
||||||
|
LogCancelContractEventArgs,
|
||||||
|
LogFillContractEventArgs,
|
||||||
|
ExchangeContractEventArgs,
|
||||||
|
ExchangeEvents,
|
||||||
|
} from './contract_wrappers/generated/exchange';
|
||||||
|
|||||||
@@ -1,14 +1,12 @@
|
|||||||
import {intervalUtils} from '@0xproject/utils';
|
import { intervalUtils } from '@0xproject/utils';
|
||||||
import {Web3Wrapper} from '@0xproject/web3-wrapper';
|
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import * as Web3 from 'web3';
|
import * as Web3 from 'web3';
|
||||||
|
|
||||||
import {
|
import { BlockParamLiteral } from '@0xproject/types';
|
||||||
BlockParamLiteral,
|
|
||||||
EventWatcherCallback,
|
import { EventWatcherCallback, ZeroExError } from '../types';
|
||||||
ZeroExError,
|
import { assert } from '../utils/assert';
|
||||||
} from '../types';
|
|
||||||
import {assert} from '../utils/assert';
|
|
||||||
|
|
||||||
const DEFAULT_EVENT_POLLING_INTERVAL_MS = 200;
|
const DEFAULT_EVENT_POLLING_INTERVAL_MS = 200;
|
||||||
|
|
||||||
@@ -26,11 +24,11 @@ export class EventWatcher {
|
|||||||
private _pollingIntervalMs: number;
|
private _pollingIntervalMs: number;
|
||||||
private _intervalIdIfExists?: NodeJS.Timer;
|
private _intervalIdIfExists?: NodeJS.Timer;
|
||||||
private _lastEvents: Web3.LogEntry[] = [];
|
private _lastEvents: Web3.LogEntry[] = [];
|
||||||
constructor(web3Wrapper: Web3Wrapper, pollingIntervalIfExistsMs: undefined|number) {
|
constructor(web3Wrapper: Web3Wrapper, pollingIntervalIfExistsMs: undefined | number) {
|
||||||
this._web3Wrapper = web3Wrapper;
|
this._web3Wrapper = web3Wrapper;
|
||||||
this._pollingIntervalMs = _.isUndefined(pollingIntervalIfExistsMs) ?
|
this._pollingIntervalMs = _.isUndefined(pollingIntervalIfExistsMs)
|
||||||
DEFAULT_EVENT_POLLING_INTERVAL_MS :
|
? DEFAULT_EVENT_POLLING_INTERVAL_MS
|
||||||
pollingIntervalIfExistsMs;
|
: pollingIntervalIfExistsMs;
|
||||||
}
|
}
|
||||||
public subscribe(callback: EventWatcherCallback): void {
|
public subscribe(callback: EventWatcherCallback): void {
|
||||||
assert.isFunction('callback', callback);
|
assert.isFunction('callback', callback);
|
||||||
@@ -38,7 +36,12 @@ export class EventWatcher {
|
|||||||
throw new Error(ZeroExError.SubscriptionAlreadyPresent);
|
throw new Error(ZeroExError.SubscriptionAlreadyPresent);
|
||||||
}
|
}
|
||||||
this._intervalIdIfExists = intervalUtils.setAsyncExcludingInterval(
|
this._intervalIdIfExists = intervalUtils.setAsyncExcludingInterval(
|
||||||
this._pollForBlockchainEventsAsync.bind(this, callback), this._pollingIntervalMs,
|
this._pollForBlockchainEventsAsync.bind(this, callback),
|
||||||
|
this._pollingIntervalMs,
|
||||||
|
(err: Error) => {
|
||||||
|
this.unsubscribe();
|
||||||
|
callback(err);
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
public unsubscribe(): void {
|
public unsubscribe(): void {
|
||||||
@@ -50,6 +53,10 @@ export class EventWatcher {
|
|||||||
}
|
}
|
||||||
private async _pollForBlockchainEventsAsync(callback: EventWatcherCallback): Promise<void> {
|
private async _pollForBlockchainEventsAsync(callback: EventWatcherCallback): Promise<void> {
|
||||||
const pendingEvents = await this._getEventsAsync();
|
const pendingEvents = await this._getEventsAsync();
|
||||||
|
if (_.isUndefined(pendingEvents)) {
|
||||||
|
// HACK: This should never happen, but happens frequently on CI due to a ganache bug
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (pendingEvents.length === 0) {
|
if (pendingEvents.length === 0) {
|
||||||
// HACK: Sometimes when node rebuilds the pending block we get back the empty result.
|
// HACK: Sometimes when node rebuilds the pending block we get back the empty result.
|
||||||
// We don't want to emit a lot of removal events and bring them back after a couple of miliseconds,
|
// We don't want to emit a lot of removal events and bring them back after a couple of miliseconds,
|
||||||
@@ -71,7 +78,9 @@ export class EventWatcher {
|
|||||||
return events;
|
return events;
|
||||||
}
|
}
|
||||||
private async _emitDifferencesAsync(
|
private async _emitDifferencesAsync(
|
||||||
logs: Web3.LogEntry[], logEventState: LogEventState, callback: EventWatcherCallback,
|
logs: Web3.LogEntry[],
|
||||||
|
logEventState: LogEventState,
|
||||||
|
callback: EventWatcherCallback,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
for (const log of logs) {
|
for (const log of logs) {
|
||||||
const logEvent = {
|
const logEvent = {
|
||||||
@@ -79,7 +88,7 @@ export class EventWatcher {
|
|||||||
...log,
|
...log,
|
||||||
};
|
};
|
||||||
if (!_.isUndefined(this._intervalIdIfExists)) {
|
if (!_.isUndefined(this._intervalIdIfExists)) {
|
||||||
callback(logEvent);
|
callback(null, logEvent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
import {intervalUtils} from '@0xproject/utils';
|
import { BigNumber, intervalUtils } from '@0xproject/utils';
|
||||||
import {BigNumber} from 'bignumber.js';
|
import { RBTree } from 'bintrees';
|
||||||
import {RBTree} from 'bintrees';
|
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import {ZeroExError} from '../types';
|
import { ZeroExError } from '../types';
|
||||||
import {utils} from '../utils/utils';
|
import { utils } from '../utils/utils';
|
||||||
|
|
||||||
const DEFAULT_EXPIRATION_MARGIN_MS = 0;
|
const DEFAULT_EXPIRATION_MARGIN_MS = 0;
|
||||||
const DEFAULT_ORDER_EXPIRATION_CHECKING_INTERVAL_MS = 50;
|
const DEFAULT_ORDER_EXPIRATION_CHECKING_INTERVAL_MS = 50;
|
||||||
@@ -15,16 +14,14 @@ const DEFAULT_ORDER_EXPIRATION_CHECKING_INTERVAL_MS = 50;
|
|||||||
*/
|
*/
|
||||||
export class ExpirationWatcher {
|
export class ExpirationWatcher {
|
||||||
private _orderHashByExpirationRBTree: RBTree<string>;
|
private _orderHashByExpirationRBTree: RBTree<string>;
|
||||||
private _expiration: {[orderHash: string]: BigNumber} = {};
|
private _expiration: { [orderHash: string]: BigNumber } = {};
|
||||||
private _orderExpirationCheckingIntervalMs: number;
|
private _orderExpirationCheckingIntervalMs: number;
|
||||||
private _expirationMarginMs: number;
|
private _expirationMarginMs: number;
|
||||||
private _orderExpirationCheckingIntervalIdIfExists?: NodeJS.Timer;
|
private _orderExpirationCheckingIntervalIdIfExists?: NodeJS.Timer;
|
||||||
constructor(expirationMarginIfExistsMs?: number,
|
constructor(expirationMarginIfExistsMs?: number, orderExpirationCheckingIntervalIfExistsMs?: number) {
|
||||||
orderExpirationCheckingIntervalIfExistsMs?: number) {
|
this._expirationMarginMs = expirationMarginIfExistsMs || DEFAULT_EXPIRATION_MARGIN_MS;
|
||||||
this._expirationMarginMs = expirationMarginIfExistsMs ||
|
this._orderExpirationCheckingIntervalMs =
|
||||||
DEFAULT_EXPIRATION_MARGIN_MS;
|
expirationMarginIfExistsMs || DEFAULT_ORDER_EXPIRATION_CHECKING_INTERVAL_MS;
|
||||||
this._orderExpirationCheckingIntervalMs = expirationMarginIfExistsMs ||
|
|
||||||
DEFAULT_ORDER_EXPIRATION_CHECKING_INTERVAL_MS;
|
|
||||||
const scoreFunction = (orderHash: string) => this._expiration[orderHash].toNumber();
|
const scoreFunction = (orderHash: string) => this._expiration[orderHash].toNumber();
|
||||||
const comparator = (lhs: string, rhs: string) => scoreFunction(lhs) - scoreFunction(rhs);
|
const comparator = (lhs: string, rhs: string) => scoreFunction(lhs) - scoreFunction(rhs);
|
||||||
this._orderHashByExpirationRBTree = new RBTree(comparator);
|
this._orderHashByExpirationRBTree = new RBTree(comparator);
|
||||||
@@ -33,15 +30,17 @@ export class ExpirationWatcher {
|
|||||||
if (!_.isUndefined(this._orderExpirationCheckingIntervalIdIfExists)) {
|
if (!_.isUndefined(this._orderExpirationCheckingIntervalIdIfExists)) {
|
||||||
throw new Error(ZeroExError.SubscriptionAlreadyPresent);
|
throw new Error(ZeroExError.SubscriptionAlreadyPresent);
|
||||||
}
|
}
|
||||||
this._orderExpirationCheckingIntervalIdIfExists = intervalUtils.setAsyncExcludingInterval(
|
this._orderExpirationCheckingIntervalIdIfExists = intervalUtils.setInterval(
|
||||||
this._pruneExpiredOrders.bind(this, callback), this._orderExpirationCheckingIntervalMs,
|
this._pruneExpiredOrders.bind(this, callback),
|
||||||
|
this._orderExpirationCheckingIntervalMs,
|
||||||
|
_.noop, // _pruneExpiredOrders never throws
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
public unsubscribe(): void {
|
public unsubscribe(): void {
|
||||||
if (_.isUndefined(this._orderExpirationCheckingIntervalIdIfExists)) {
|
if (_.isUndefined(this._orderExpirationCheckingIntervalIdIfExists)) {
|
||||||
throw new Error(ZeroExError.SubscriptionNotFound);
|
throw new Error(ZeroExError.SubscriptionNotFound);
|
||||||
}
|
}
|
||||||
intervalUtils.clearAsyncExcludingInterval(this._orderExpirationCheckingIntervalIdIfExists);
|
intervalUtils.clearInterval(this._orderExpirationCheckingIntervalIdIfExists);
|
||||||
delete this._orderExpirationCheckingIntervalIdIfExists;
|
delete this._orderExpirationCheckingIntervalIdIfExists;
|
||||||
}
|
}
|
||||||
public addOrder(orderHash: string, expirationUnixTimestampMs: BigNumber): void {
|
public addOrder(orderHash: string, expirationUnixTimestampMs: BigNumber): void {
|
||||||
|
|||||||
@@ -1,41 +1,45 @@
|
|||||||
import {schemas} from '@0xproject/json-schemas';
|
import { schemas } from '@0xproject/json-schemas';
|
||||||
import {intervalUtils} from '@0xproject/utils';
|
import { BlockParamLiteral, LogWithDecodedArgs } from '@0xproject/types';
|
||||||
import {Web3Wrapper} from '@0xproject/web3-wrapper';
|
import { AbiDecoder, intervalUtils } from '@0xproject/utils';
|
||||||
|
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import {ZeroEx} from '../0x';
|
import { ZeroEx } from '../0x';
|
||||||
import {ExchangeWrapper} from '../contract_wrappers/exchange_wrapper';
|
import { ExchangeWrapper } from '../contract_wrappers/exchange_wrapper';
|
||||||
import {TokenWrapper} from '../contract_wrappers/token_wrapper';
|
|
||||||
import {BalanceAndProxyAllowanceLazyStore} from '../stores/balance_proxy_allowance_lazy_store';
|
|
||||||
import {OrderFilledCancelledLazyStore} from '../stores/order_filled_cancelled_lazy_store';
|
|
||||||
import {
|
import {
|
||||||
ApprovalContractEventArgs,
|
|
||||||
BlockParamLiteral,
|
|
||||||
ContractEventArgs,
|
|
||||||
DepositContractEventArgs,
|
DepositContractEventArgs,
|
||||||
EtherTokenEvents,
|
EtherTokenEvents,
|
||||||
ExchangeContractErrs,
|
WithdrawalContractEventArgs,
|
||||||
|
} from '../contract_wrappers/generated/ether_token';
|
||||||
|
import {
|
||||||
ExchangeEvents,
|
ExchangeEvents,
|
||||||
LogCancelContractEventArgs,
|
LogCancelContractEventArgs,
|
||||||
LogEvent,
|
|
||||||
LogFillContractEventArgs,
|
LogFillContractEventArgs,
|
||||||
LogWithDecodedArgs,
|
} from '../contract_wrappers/generated/exchange';
|
||||||
|
import {
|
||||||
|
ApprovalContractEventArgs,
|
||||||
|
TokenEvents,
|
||||||
|
TransferContractEventArgs,
|
||||||
|
} from '../contract_wrappers/generated/token';
|
||||||
|
import { TokenWrapper } from '../contract_wrappers/token_wrapper';
|
||||||
|
import { BalanceAndProxyAllowanceLazyStore } from '../stores/balance_proxy_allowance_lazy_store';
|
||||||
|
import { OrderFilledCancelledLazyStore } from '../stores/order_filled_cancelled_lazy_store';
|
||||||
|
import {
|
||||||
|
ContractEventArgs,
|
||||||
|
ExchangeContractErrs,
|
||||||
|
LogEvent,
|
||||||
OnOrderStateChangeCallback,
|
OnOrderStateChangeCallback,
|
||||||
OrderState,
|
OrderState,
|
||||||
OrderStateWatcherConfig,
|
OrderStateWatcherConfig,
|
||||||
SignedOrder,
|
SignedOrder,
|
||||||
TokenEvents,
|
|
||||||
TransferContractEventArgs,
|
|
||||||
WithdrawalContractEventArgs,
|
|
||||||
ZeroExError,
|
ZeroExError,
|
||||||
} from '../types';
|
} from '../types';
|
||||||
import {AbiDecoder} from '../utils/abi_decoder';
|
import { assert } from '../utils/assert';
|
||||||
import {assert} from '../utils/assert';
|
import { OrderStateUtils } from '../utils/order_state_utils';
|
||||||
import {OrderStateUtils} from '../utils/order_state_utils';
|
import { utils } from '../utils/utils';
|
||||||
import {utils} from '../utils/utils';
|
|
||||||
|
|
||||||
import {EventWatcher} from './event_watcher';
|
import { EventWatcher } from './event_watcher';
|
||||||
import {ExpirationWatcher} from './expiration_watcher';
|
import { ExpirationWatcher } from './expiration_watcher';
|
||||||
|
|
||||||
interface DependentOrderHashes {
|
interface DependentOrderHashes {
|
||||||
[makerAddress: string]: {
|
[makerAddress: string]: {
|
||||||
@@ -74,7 +78,10 @@ export class OrderStateWatcher {
|
|||||||
private _cleanupJobInterval: number;
|
private _cleanupJobInterval: number;
|
||||||
private _cleanupJobIntervalIdIfExists?: NodeJS.Timer;
|
private _cleanupJobIntervalIdIfExists?: NodeJS.Timer;
|
||||||
constructor(
|
constructor(
|
||||||
web3Wrapper: Web3Wrapper, abiDecoder: AbiDecoder, token: TokenWrapper, exchange: ExchangeWrapper,
|
web3Wrapper: Web3Wrapper,
|
||||||
|
abiDecoder: AbiDecoder,
|
||||||
|
token: TokenWrapper,
|
||||||
|
exchange: ExchangeWrapper,
|
||||||
config?: OrderStateWatcherConfig,
|
config?: OrderStateWatcherConfig,
|
||||||
) {
|
) {
|
||||||
this._abiDecoder = abiDecoder;
|
this._abiDecoder = abiDecoder;
|
||||||
@@ -82,24 +89,26 @@ export class OrderStateWatcher {
|
|||||||
const pollingIntervalIfExistsMs = _.isUndefined(config) ? undefined : config.eventPollingIntervalMs;
|
const pollingIntervalIfExistsMs = _.isUndefined(config) ? undefined : config.eventPollingIntervalMs;
|
||||||
this._eventWatcher = new EventWatcher(web3Wrapper, pollingIntervalIfExistsMs);
|
this._eventWatcher = new EventWatcher(web3Wrapper, pollingIntervalIfExistsMs);
|
||||||
this._balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore(
|
this._balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore(
|
||||||
token, BlockParamLiteral.Pending,
|
token,
|
||||||
|
BlockParamLiteral.Pending,
|
||||||
);
|
);
|
||||||
this._orderFilledCancelledLazyStore = new OrderFilledCancelledLazyStore(exchange);
|
this._orderFilledCancelledLazyStore = new OrderFilledCancelledLazyStore(exchange);
|
||||||
this._orderStateUtils = new OrderStateUtils(
|
this._orderStateUtils = new OrderStateUtils(
|
||||||
this._balanceAndProxyAllowanceLazyStore, this._orderFilledCancelledLazyStore,
|
this._balanceAndProxyAllowanceLazyStore,
|
||||||
|
this._orderFilledCancelledLazyStore,
|
||||||
);
|
);
|
||||||
const orderExpirationCheckingIntervalMsIfExists = _.isUndefined(config) ?
|
const orderExpirationCheckingIntervalMsIfExists = _.isUndefined(config)
|
||||||
undefined :
|
? undefined
|
||||||
config.orderExpirationCheckingIntervalMs;
|
: config.orderExpirationCheckingIntervalMs;
|
||||||
const expirationMarginIfExistsMs = _.isUndefined(config) ?
|
const expirationMarginIfExistsMs = _.isUndefined(config) ? undefined : config.expirationMarginMs;
|
||||||
undefined :
|
|
||||||
config.expirationMarginMs;
|
|
||||||
this._expirationWatcher = new ExpirationWatcher(
|
this._expirationWatcher = new ExpirationWatcher(
|
||||||
expirationMarginIfExistsMs, orderExpirationCheckingIntervalMsIfExists,
|
expirationMarginIfExistsMs,
|
||||||
|
orderExpirationCheckingIntervalMsIfExists,
|
||||||
);
|
);
|
||||||
this._cleanupJobInterval = _.isUndefined(config) || _.isUndefined(config.cleanupJobIntervalMs) ?
|
this._cleanupJobInterval =
|
||||||
DEFAULT_CLEANUP_JOB_INTERVAL_MS :
|
_.isUndefined(config) || _.isUndefined(config.cleanupJobIntervalMs)
|
||||||
config.cleanupJobIntervalMs;
|
? DEFAULT_CLEANUP_JOB_INTERVAL_MS
|
||||||
|
: config.cleanupJobIntervalMs;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Add an order to the orderStateWatcher. Before the order is added, it's
|
* Add an order to the orderStateWatcher. Before the order is added, it's
|
||||||
@@ -129,8 +138,12 @@ export class OrderStateWatcher {
|
|||||||
delete this._orderStateByOrderHashCache[orderHash];
|
delete this._orderStateByOrderHashCache[orderHash];
|
||||||
const exchange = (this._orderFilledCancelledLazyStore as any)._exchange as ExchangeWrapper;
|
const exchange = (this._orderFilledCancelledLazyStore as any)._exchange as ExchangeWrapper;
|
||||||
const zrxTokenAddress = exchange.getZRXTokenAddress();
|
const zrxTokenAddress = exchange.getZRXTokenAddress();
|
||||||
|
|
||||||
this._removeFromDependentOrderHashes(signedOrder.maker, zrxTokenAddress, orderHash);
|
this._removeFromDependentOrderHashes(signedOrder.maker, zrxTokenAddress, orderHash);
|
||||||
this._removeFromDependentOrderHashes(signedOrder.maker, signedOrder.makerTokenAddress, orderHash);
|
if (zrxTokenAddress !== signedOrder.makerTokenAddress) {
|
||||||
|
this._removeFromDependentOrderHashes(signedOrder.maker, signedOrder.makerTokenAddress, orderHash);
|
||||||
|
}
|
||||||
|
|
||||||
this._expirationWatcher.removeOrder(orderHash);
|
this._expirationWatcher.removeOrder(orderHash);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@@ -148,7 +161,12 @@ export class OrderStateWatcher {
|
|||||||
this._eventWatcher.subscribe(this._onEventWatcherCallbackAsync.bind(this));
|
this._eventWatcher.subscribe(this._onEventWatcherCallbackAsync.bind(this));
|
||||||
this._expirationWatcher.subscribe(this._onOrderExpired.bind(this));
|
this._expirationWatcher.subscribe(this._onOrderExpired.bind(this));
|
||||||
this._cleanupJobIntervalIdIfExists = intervalUtils.setAsyncExcludingInterval(
|
this._cleanupJobIntervalIdIfExists = intervalUtils.setAsyncExcludingInterval(
|
||||||
this._cleanupAsync.bind(this), this._cleanupJobInterval,
|
this._cleanupAsync.bind(this),
|
||||||
|
this._cleanupJobInterval,
|
||||||
|
(err: Error) => {
|
||||||
|
this.unsubscribe();
|
||||||
|
callback(err);
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@@ -201,37 +219,45 @@ export class OrderStateWatcher {
|
|||||||
if (!_.isUndefined(this._orderByOrderHash[orderHash])) {
|
if (!_.isUndefined(this._orderByOrderHash[orderHash])) {
|
||||||
this.removeOrder(orderHash);
|
this.removeOrder(orderHash);
|
||||||
if (!_.isUndefined(this._callbackIfExists)) {
|
if (!_.isUndefined(this._callbackIfExists)) {
|
||||||
this._callbackIfExists(orderState);
|
this._callbackIfExists(null, orderState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private async _onEventWatcherCallbackAsync(log: LogEvent): Promise<void> {
|
private async _onEventWatcherCallbackAsync(err: Error | null, logIfExists?: LogEvent): Promise<void> {
|
||||||
const maybeDecodedLog = this._abiDecoder.tryToDecodeLogOrNoop(log);
|
if (!_.isNull(err)) {
|
||||||
const isLogDecoded = !_.isUndefined((maybeDecodedLog as LogWithDecodedArgs<any>).event);
|
if (!_.isUndefined(this._callbackIfExists)) {
|
||||||
|
this._callbackIfExists(err);
|
||||||
|
this.unsubscribe();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const log = logIfExists as LogEvent; // At this moment we are sure that no error occured and log is defined.
|
||||||
|
const maybeDecodedLog = this._abiDecoder.tryToDecodeLogOrNoop<ContractEventArgs>(log);
|
||||||
|
const isLogDecoded = !_.isUndefined(((maybeDecodedLog as any) as LogWithDecodedArgs<ContractEventArgs>).event);
|
||||||
if (!isLogDecoded) {
|
if (!isLogDecoded) {
|
||||||
return; // noop
|
return; // noop
|
||||||
}
|
}
|
||||||
const decodedLog = maybeDecodedLog as LogWithDecodedArgs<ContractEventArgs>;
|
const decodedLog = (maybeDecodedLog as any) as LogWithDecodedArgs<ContractEventArgs>;
|
||||||
let makerToken: string;
|
let makerToken: string;
|
||||||
let makerAddress: string;
|
let makerAddress: string;
|
||||||
switch (decodedLog.event) {
|
switch (decodedLog.event) {
|
||||||
case TokenEvents.Approval:
|
case TokenEvents.Approval: {
|
||||||
{
|
|
||||||
// Invalidate cache
|
// Invalidate cache
|
||||||
const args = decodedLog.args as ApprovalContractEventArgs;
|
const args = decodedLog.args as ApprovalContractEventArgs;
|
||||||
this._balanceAndProxyAllowanceLazyStore.deleteProxyAllowance(decodedLog.address, args._owner);
|
this._balanceAndProxyAllowanceLazyStore.deleteProxyAllowance(decodedLog.address, args._owner);
|
||||||
// Revalidate orders
|
// Revalidate orders
|
||||||
makerToken = decodedLog.address;
|
makerToken = decodedLog.address;
|
||||||
makerAddress = args._owner;
|
makerAddress = args._owner;
|
||||||
if (!_.isUndefined(this._dependentOrderHashes[makerAddress]) &&
|
if (
|
||||||
!_.isUndefined(this._dependentOrderHashes[makerAddress][makerToken])) {
|
!_.isUndefined(this._dependentOrderHashes[makerAddress]) &&
|
||||||
|
!_.isUndefined(this._dependentOrderHashes[makerAddress][makerToken])
|
||||||
|
) {
|
||||||
const orderHashes = Array.from(this._dependentOrderHashes[makerAddress][makerToken]);
|
const orderHashes = Array.from(this._dependentOrderHashes[makerAddress][makerToken]);
|
||||||
await this._emitRevalidateOrdersAsync(orderHashes);
|
await this._emitRevalidateOrdersAsync(orderHashes);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TokenEvents.Transfer:
|
case TokenEvents.Transfer: {
|
||||||
{
|
|
||||||
// Invalidate cache
|
// Invalidate cache
|
||||||
const args = decodedLog.args as TransferContractEventArgs;
|
const args = decodedLog.args as TransferContractEventArgs;
|
||||||
this._balanceAndProxyAllowanceLazyStore.deleteBalance(decodedLog.address, args._from);
|
this._balanceAndProxyAllowanceLazyStore.deleteBalance(decodedLog.address, args._from);
|
||||||
@@ -239,45 +265,48 @@ export class OrderStateWatcher {
|
|||||||
// Revalidate orders
|
// Revalidate orders
|
||||||
makerToken = decodedLog.address;
|
makerToken = decodedLog.address;
|
||||||
makerAddress = args._from;
|
makerAddress = args._from;
|
||||||
if (!_.isUndefined(this._dependentOrderHashes[makerAddress]) &&
|
if (
|
||||||
!_.isUndefined(this._dependentOrderHashes[makerAddress][makerToken])) {
|
!_.isUndefined(this._dependentOrderHashes[makerAddress]) &&
|
||||||
|
!_.isUndefined(this._dependentOrderHashes[makerAddress][makerToken])
|
||||||
|
) {
|
||||||
const orderHashes = Array.from(this._dependentOrderHashes[makerAddress][makerToken]);
|
const orderHashes = Array.from(this._dependentOrderHashes[makerAddress][makerToken]);
|
||||||
await this._emitRevalidateOrdersAsync(orderHashes);
|
await this._emitRevalidateOrdersAsync(orderHashes);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case EtherTokenEvents.Deposit:
|
case EtherTokenEvents.Deposit: {
|
||||||
{
|
|
||||||
// Invalidate cache
|
// Invalidate cache
|
||||||
const args = decodedLog.args as DepositContractEventArgs;
|
const args = decodedLog.args as DepositContractEventArgs;
|
||||||
this._balanceAndProxyAllowanceLazyStore.deleteBalance(decodedLog.address, args._owner);
|
this._balanceAndProxyAllowanceLazyStore.deleteBalance(decodedLog.address, args._owner);
|
||||||
// Revalidate orders
|
// Revalidate orders
|
||||||
makerToken = decodedLog.address;
|
makerToken = decodedLog.address;
|
||||||
makerAddress = args._owner;
|
makerAddress = args._owner;
|
||||||
if (!_.isUndefined(this._dependentOrderHashes[makerAddress]) &&
|
if (
|
||||||
!_.isUndefined(this._dependentOrderHashes[makerAddress][makerToken])) {
|
!_.isUndefined(this._dependentOrderHashes[makerAddress]) &&
|
||||||
|
!_.isUndefined(this._dependentOrderHashes[makerAddress][makerToken])
|
||||||
|
) {
|
||||||
const orderHashes = Array.from(this._dependentOrderHashes[makerAddress][makerToken]);
|
const orderHashes = Array.from(this._dependentOrderHashes[makerAddress][makerToken]);
|
||||||
await this._emitRevalidateOrdersAsync(orderHashes);
|
await this._emitRevalidateOrdersAsync(orderHashes);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case EtherTokenEvents.Withdrawal:
|
case EtherTokenEvents.Withdrawal: {
|
||||||
{
|
|
||||||
// Invalidate cache
|
// Invalidate cache
|
||||||
const args = decodedLog.args as WithdrawalContractEventArgs;
|
const args = decodedLog.args as WithdrawalContractEventArgs;
|
||||||
this._balanceAndProxyAllowanceLazyStore.deleteBalance(decodedLog.address, args._owner);
|
this._balanceAndProxyAllowanceLazyStore.deleteBalance(decodedLog.address, args._owner);
|
||||||
// Revalidate orders
|
// Revalidate orders
|
||||||
makerToken = decodedLog.address;
|
makerToken = decodedLog.address;
|
||||||
makerAddress = args._owner;
|
makerAddress = args._owner;
|
||||||
if (!_.isUndefined(this._dependentOrderHashes[makerAddress]) &&
|
if (
|
||||||
!_.isUndefined(this._dependentOrderHashes[makerAddress][makerToken])) {
|
!_.isUndefined(this._dependentOrderHashes[makerAddress]) &&
|
||||||
|
!_.isUndefined(this._dependentOrderHashes[makerAddress][makerToken])
|
||||||
|
) {
|
||||||
const orderHashes = Array.from(this._dependentOrderHashes[makerAddress][makerToken]);
|
const orderHashes = Array.from(this._dependentOrderHashes[makerAddress][makerToken]);
|
||||||
await this._emitRevalidateOrdersAsync(orderHashes);
|
await this._emitRevalidateOrdersAsync(orderHashes);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ExchangeEvents.LogFill:
|
case ExchangeEvents.LogFill: {
|
||||||
{
|
|
||||||
// Invalidate cache
|
// Invalidate cache
|
||||||
const args = decodedLog.args as LogFillContractEventArgs;
|
const args = decodedLog.args as LogFillContractEventArgs;
|
||||||
this._orderFilledCancelledLazyStore.deleteFilledTakerAmount(args.orderHash);
|
this._orderFilledCancelledLazyStore.deleteFilledTakerAmount(args.orderHash);
|
||||||
@@ -289,8 +318,7 @@ export class OrderStateWatcher {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ExchangeEvents.LogCancel:
|
case ExchangeEvents.LogCancel: {
|
||||||
{
|
|
||||||
// Invalidate cache
|
// Invalidate cache
|
||||||
const args = decodedLog.args as LogCancelContractEventArgs;
|
const args = decodedLog.args as LogCancelContractEventArgs;
|
||||||
this._orderFilledCancelledLazyStore.deleteCancelledTakerAmount(args.orderHash);
|
this._orderFilledCancelledLazyStore.deleteCancelledTakerAmount(args.orderHash);
|
||||||
@@ -324,7 +352,7 @@ export class OrderStateWatcher {
|
|||||||
} else {
|
} else {
|
||||||
this._orderStateByOrderHashCache[orderHash] = orderState;
|
this._orderStateByOrderHashCache[orderHash] = orderState;
|
||||||
}
|
}
|
||||||
this._callbackIfExists(orderState);
|
this._callbackIfExists(null, orderState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private _addToDependentOrderHashes(signedOrder: SignedOrder, orderHash: string): void {
|
private _addToDependentOrderHashes(signedOrder: SignedOrder, orderHash: string): void {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import {BigNumber} from 'bignumber.js';
|
import { BigNumber } from '@0xproject/utils';
|
||||||
|
|
||||||
import {SignedOrder} from '../types';
|
import { SignedOrder } from '../types';
|
||||||
|
|
||||||
export class RemainingFillableCalculator {
|
export class RemainingFillableCalculator {
|
||||||
private _signedOrder: SignedOrder;
|
private _signedOrder: SignedOrder;
|
||||||
@@ -10,18 +10,21 @@ export class RemainingFillableCalculator {
|
|||||||
private _transferrableMakerFeeTokenAmount: BigNumber;
|
private _transferrableMakerFeeTokenAmount: BigNumber;
|
||||||
private _remainingMakerTokenAmount: BigNumber;
|
private _remainingMakerTokenAmount: BigNumber;
|
||||||
private _remainingMakerFeeAmount: BigNumber;
|
private _remainingMakerFeeAmount: BigNumber;
|
||||||
constructor(signedOrder: SignedOrder,
|
constructor(
|
||||||
isMakerTokenZRX: boolean,
|
signedOrder: SignedOrder,
|
||||||
transferrableMakerTokenAmount: BigNumber,
|
isMakerTokenZRX: boolean,
|
||||||
transferrableMakerFeeTokenAmount: BigNumber,
|
transferrableMakerTokenAmount: BigNumber,
|
||||||
remainingMakerTokenAmount: BigNumber) {
|
transferrableMakerFeeTokenAmount: BigNumber,
|
||||||
|
remainingMakerTokenAmount: BigNumber,
|
||||||
|
) {
|
||||||
this._signedOrder = signedOrder;
|
this._signedOrder = signedOrder;
|
||||||
this._isMakerTokenZRX = isMakerTokenZRX;
|
this._isMakerTokenZRX = isMakerTokenZRX;
|
||||||
this._transferrableMakerTokenAmount = transferrableMakerTokenAmount;
|
this._transferrableMakerTokenAmount = transferrableMakerTokenAmount;
|
||||||
this._transferrableMakerFeeTokenAmount = transferrableMakerFeeTokenAmount;
|
this._transferrableMakerFeeTokenAmount = transferrableMakerFeeTokenAmount;
|
||||||
this._remainingMakerTokenAmount = remainingMakerTokenAmount;
|
this._remainingMakerTokenAmount = remainingMakerTokenAmount;
|
||||||
this._remainingMakerFeeAmount = remainingMakerTokenAmount.times(signedOrder.makerFee)
|
this._remainingMakerFeeAmount = remainingMakerTokenAmount
|
||||||
.dividedToIntegerBy(signedOrder.makerTokenAmount);
|
.times(signedOrder.makerFee)
|
||||||
|
.dividedToIntegerBy(signedOrder.makerTokenAmount);
|
||||||
}
|
}
|
||||||
public computeRemainingMakerFillable(): BigNumber {
|
public computeRemainingMakerFillable(): BigNumber {
|
||||||
if (this._hasSufficientFundsForFeeAndTransferAmount()) {
|
if (this._hasSufficientFundsForFeeAndTransferAmount()) {
|
||||||
@@ -33,20 +36,24 @@ export class RemainingFillableCalculator {
|
|||||||
return this._calculatePartiallyFillableMakerTokenAmount();
|
return this._calculatePartiallyFillableMakerTokenAmount();
|
||||||
}
|
}
|
||||||
public computeRemainingTakerFillable(): BigNumber {
|
public computeRemainingTakerFillable(): BigNumber {
|
||||||
return this.computeRemainingMakerFillable().times(this._signedOrder.takerTokenAmount)
|
return this.computeRemainingMakerFillable()
|
||||||
.dividedToIntegerBy(this._signedOrder.makerTokenAmount);
|
.times(this._signedOrder.takerTokenAmount)
|
||||||
|
.dividedToIntegerBy(this._signedOrder.makerTokenAmount);
|
||||||
}
|
}
|
||||||
private _hasSufficientFundsForFeeAndTransferAmount(): boolean {
|
private _hasSufficientFundsForFeeAndTransferAmount(): boolean {
|
||||||
if (this._isMakerTokenZRX) {
|
if (this._isMakerTokenZRX) {
|
||||||
const totalZRXTransferAmountRequired = this._remainingMakerTokenAmount.plus(this._remainingMakerFeeAmount);
|
const totalZRXTransferAmountRequired = this._remainingMakerTokenAmount.plus(this._remainingMakerFeeAmount);
|
||||||
const hasSufficientFunds = this._transferrableMakerTokenAmount.greaterThanOrEqualTo(
|
const hasSufficientFunds = this._transferrableMakerTokenAmount.greaterThanOrEqualTo(
|
||||||
totalZRXTransferAmountRequired);
|
totalZRXTransferAmountRequired,
|
||||||
|
);
|
||||||
return hasSufficientFunds;
|
return hasSufficientFunds;
|
||||||
} else {
|
} else {
|
||||||
const hasSufficientFundsForTransferAmount = this._transferrableMakerTokenAmount.greaterThanOrEqualTo(
|
const hasSufficientFundsForTransferAmount = this._transferrableMakerTokenAmount.greaterThanOrEqualTo(
|
||||||
this._remainingMakerTokenAmount);
|
this._remainingMakerTokenAmount,
|
||||||
|
);
|
||||||
const hasSufficientFundsForFeeAmount = this._transferrableMakerFeeTokenAmount.greaterThanOrEqualTo(
|
const hasSufficientFundsForFeeAmount = this._transferrableMakerFeeTokenAmount.greaterThanOrEqualTo(
|
||||||
this._remainingMakerFeeAmount);
|
this._remainingMakerFeeAmount,
|
||||||
|
);
|
||||||
const hasSufficientFunds = hasSufficientFundsForTransferAmount && hasSufficientFundsForFeeAmount;
|
const hasSufficientFunds = hasSufficientFundsForTransferAmount && hasSufficientFundsForFeeAmount;
|
||||||
return hasSufficientFunds;
|
return hasSufficientFunds;
|
||||||
}
|
}
|
||||||
@@ -57,8 +64,10 @@ export class RemainingFillableCalculator {
|
|||||||
// The number of times the maker can fill the order, if each fill only required the transfer of a single
|
// The number of times the maker can fill the order, if each fill only required the transfer of a single
|
||||||
// baseUnit of fee tokens.
|
// baseUnit of fee tokens.
|
||||||
// Given 2 ZRXwei, the maximum amount of times Maker can fill this order, in terms of fees, is 2
|
// Given 2 ZRXwei, the maximum amount of times Maker can fill this order, in terms of fees, is 2
|
||||||
const fillableTimesInFeeTokenBaseUnits = BigNumber.min(this._transferrableMakerFeeTokenAmount,
|
const fillableTimesInFeeTokenBaseUnits = BigNumber.min(
|
||||||
this._remainingMakerFeeAmount);
|
this._transferrableMakerFeeTokenAmount,
|
||||||
|
this._remainingMakerFeeAmount,
|
||||||
|
);
|
||||||
// The number of times the Maker can fill the order, given the Maker Token Balance
|
// The number of times the Maker can fill the order, given the Maker Token Balance
|
||||||
// Assuming a balance of 150 wei, and an orderToFeeRatio of 100:1, maker can fill this order 1 time.
|
// Assuming a balance of 150 wei, and an orderToFeeRatio of 100:1, maker can fill this order 1 time.
|
||||||
let fillableTimesInMakerTokenUnits = this._transferrableMakerTokenAmount.dividedBy(orderToFeeRatio);
|
let fillableTimesInMakerTokenUnits = this._transferrableMakerTokenAmount.dividedBy(orderToFeeRatio);
|
||||||
@@ -68,20 +77,20 @@ export class RemainingFillableCalculator {
|
|||||||
const totalZRXTokenPooled = this._transferrableMakerTokenAmount;
|
const totalZRXTokenPooled = this._transferrableMakerTokenAmount;
|
||||||
// The purchasing power here is less as the tokens are taken from the same Pool
|
// The purchasing power here is less as the tokens are taken from the same Pool
|
||||||
// For every one number of fills, we have to take an extra ZRX out of the pool
|
// For every one number of fills, we have to take an extra ZRX out of the pool
|
||||||
fillableTimesInMakerTokenUnits = totalZRXTokenPooled.dividedBy(
|
fillableTimesInMakerTokenUnits = totalZRXTokenPooled.dividedBy(orderToFeeRatio.plus(new BigNumber(1)));
|
||||||
orderToFeeRatio.plus(new BigNumber(1)));
|
|
||||||
|
|
||||||
}
|
}
|
||||||
// When Ratio is not fully divisible there can be remainders which cannot be represented, so they are floored.
|
// When Ratio is not fully divisible there can be remainders which cannot be represented, so they are floored.
|
||||||
// This can result in a RoundingError being thrown by the Exchange Contract.
|
// This can result in a RoundingError being thrown by the Exchange Contract.
|
||||||
const partiallyFillableMakerTokenAmount = fillableTimesInMakerTokenUnits
|
const partiallyFillableMakerTokenAmount = fillableTimesInMakerTokenUnits
|
||||||
.times(this._signedOrder.makerTokenAmount)
|
.times(this._signedOrder.makerTokenAmount)
|
||||||
.dividedToIntegerBy(this._signedOrder.makerFee);
|
.dividedToIntegerBy(this._signedOrder.makerFee);
|
||||||
const partiallyFillableFeeTokenAmount = fillableTimesInFeeTokenBaseUnits
|
const partiallyFillableFeeTokenAmount = fillableTimesInFeeTokenBaseUnits
|
||||||
.times(this._signedOrder.makerTokenAmount)
|
.times(this._signedOrder.makerTokenAmount)
|
||||||
.dividedToIntegerBy(this._signedOrder.makerFee);
|
.dividedToIntegerBy(this._signedOrder.makerFee);
|
||||||
const partiallyFillableAmount = BigNumber.min(partiallyFillableMakerTokenAmount,
|
const partiallyFillableAmount = BigNumber.min(
|
||||||
partiallyFillableFeeTokenAmount);
|
partiallyFillableMakerTokenAmount,
|
||||||
|
partiallyFillableFeeTokenAmount,
|
||||||
|
);
|
||||||
return partiallyFillableAmount;
|
return partiallyFillableAmount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,27 +1,5 @@
|
|||||||
export const zeroExConfigSchema = {
|
export const zeroExConfigSchema = {
|
||||||
id: '/ZeroExConfig',
|
id: '/ZeroExConfig',
|
||||||
properties: {
|
oneOf: [{ $ref: '/ZeroExPrivateNetworkConfig' }, { $ref: '/ZeroExPublicNetworkConfig' }],
|
||||||
networkId: {
|
|
||||||
type: 'number',
|
|
||||||
minimum: 0,
|
|
||||||
},
|
|
||||||
gasPrice: {$ref: '/Number'},
|
|
||||||
exchangeContractAddress: {$ref: '/Address'},
|
|
||||||
tokenRegistryContractAddress: {$ref: '/Address'},
|
|
||||||
orderWatcherConfig: {
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
pollingIntervalMs: {
|
|
||||||
type: 'number',
|
|
||||||
minimum: 0,
|
|
||||||
},
|
|
||||||
numConfirmations: {
|
|
||||||
type: 'number',
|
|
||||||
minimum: 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
type: 'object',
|
type: 'object',
|
||||||
required: ['networkId'],
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
export const zeroExPrivateNetworkConfigSchema = {
|
||||||
|
id: '/ZeroExPrivateNetworkConfig',
|
||||||
|
properties: {
|
||||||
|
networkId: {
|
||||||
|
type: 'number',
|
||||||
|
minimum: 1,
|
||||||
|
},
|
||||||
|
gasPrice: { $ref: '/Number' },
|
||||||
|
zrxContractAddress: { $ref: '/Address' },
|
||||||
|
exchangeContractAddress: { $ref: '/Address' },
|
||||||
|
tokenRegistryContractAddress: { $ref: '/Address' },
|
||||||
|
tokenTransferProxyContractAddress: { $ref: '/Address' },
|
||||||
|
orderWatcherConfig: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
pollingIntervalMs: {
|
||||||
|
type: 'number',
|
||||||
|
minimum: 0,
|
||||||
|
},
|
||||||
|
numConfirmations: {
|
||||||
|
type: 'number',
|
||||||
|
minimum: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
type: 'object',
|
||||||
|
required: [
|
||||||
|
'networkId',
|
||||||
|
'zrxContractAddress',
|
||||||
|
'exchangeContractAddress',
|
||||||
|
'tokenRegistryContractAddress',
|
||||||
|
'tokenTransferProxyContractAddress',
|
||||||
|
],
|
||||||
|
};
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
export const zeroExPublicNetworkConfigSchema = {
|
||||||
|
id: '/ZeroExPublicNetworkConfig',
|
||||||
|
properties: {
|
||||||
|
networkId: {
|
||||||
|
type: 'number',
|
||||||
|
enum: [1, 3, 4, 42, 50],
|
||||||
|
},
|
||||||
|
gasPrice: { $ref: '/Number' },
|
||||||
|
zrxContractAddress: { $ref: '/Address' },
|
||||||
|
exchangeContractAddress: { $ref: '/Address' },
|
||||||
|
tokenRegistryContractAddress: { $ref: '/Address' },
|
||||||
|
tokenTransferProxyContractAddress: { $ref: '/Address' },
|
||||||
|
orderWatcherConfig: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
pollingIntervalMs: {
|
||||||
|
type: 'number',
|
||||||
|
minimum: 0,
|
||||||
|
},
|
||||||
|
numConfirmations: {
|
||||||
|
type: 'number',
|
||||||
|
minimum: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
type: 'object',
|
||||||
|
required: ['networkId'],
|
||||||
|
};
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
import {BigNumber} from 'bignumber.js';
|
import { BlockParamLiteral } from '@0xproject/types';
|
||||||
|
import { BigNumber } from '@0xproject/utils';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import {TokenWrapper} from '../contract_wrappers/token_wrapper';
|
import { TokenWrapper } from '../contract_wrappers/token_wrapper';
|
||||||
import {BlockParamLiteral} from '../types';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copy on read store for balances/proxyAllowances of tokens/accounts
|
* Copy on read store for balances/proxyAllowances of tokens/accounts
|
||||||
@@ -52,8 +52,10 @@ export class BalanceAndProxyAllowanceLazyStore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
public async getProxyAllowanceAsync(tokenAddress: string, userAddress: string): Promise<BigNumber> {
|
public async getProxyAllowanceAsync(tokenAddress: string, userAddress: string): Promise<BigNumber> {
|
||||||
if (_.isUndefined(this._proxyAllowance[tokenAddress]) ||
|
if (
|
||||||
_.isUndefined(this._proxyAllowance[tokenAddress][userAddress])) {
|
_.isUndefined(this._proxyAllowance[tokenAddress]) ||
|
||||||
|
_.isUndefined(this._proxyAllowance[tokenAddress][userAddress])
|
||||||
|
) {
|
||||||
const methodOpts = {
|
const methodOpts = {
|
||||||
defaultBlock: this._defaultBlock,
|
defaultBlock: this._defaultBlock,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import {BigNumber} from 'bignumber.js';
|
import { BlockParamLiteral } from '@0xproject/types';
|
||||||
|
import { BigNumber } from '@0xproject/utils';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import {ExchangeWrapper} from '../contract_wrappers/exchange_wrapper';
|
import { ExchangeWrapper } from '../contract_wrappers/exchange_wrapper';
|
||||||
import {BlockParamLiteral} from '../types';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copy on read store for filled/cancelled taker amounts
|
* Copy on read store for filled/cancelled taker amounts
|
||||||
|
|||||||
@@ -1,7 +1,13 @@
|
|||||||
import {TransactionReceipt} from '@0xproject/types';
|
import { BigNumber } from '@0xproject/utils';
|
||||||
import BigNumber from 'bignumber.js';
|
|
||||||
|
import { BlockParam, BlockParamLiteral, ContractEventArg, LogWithDecodedArgs } from '@0xproject/types';
|
||||||
|
|
||||||
import * as Web3 from 'web3';
|
import * as Web3 from 'web3';
|
||||||
|
|
||||||
|
import { EtherTokenContractEventArgs, EtherTokenEvents } from './contract_wrappers/generated/ether_token';
|
||||||
|
import { ExchangeContractEventArgs, ExchangeEvents } from './contract_wrappers/generated/exchange';
|
||||||
|
import { TokenContractEventArgs, TokenEvents } from './contract_wrappers/generated/token';
|
||||||
|
|
||||||
export enum ZeroExError {
|
export enum ZeroExError {
|
||||||
ExchangeContractDoesNotExist = 'EXCHANGE_CONTRACT_DOES_NOT_EXIST',
|
ExchangeContractDoesNotExist = 'EXCHANGE_CONTRACT_DOES_NOT_EXIST',
|
||||||
ZRXContractDoesNotExist = 'ZRX_CONTRACT_DOES_NOT_EXIST',
|
ZRXContractDoesNotExist = 'ZRX_CONTRACT_DOES_NOT_EXIST',
|
||||||
@@ -42,8 +48,7 @@ export interface ECSignature {
|
|||||||
|
|
||||||
export type OrderAddresses = [string, string, string, string, string];
|
export type OrderAddresses = [string, string, string, string, string];
|
||||||
|
|
||||||
export type OrderValues = [BigNumber, BigNumber, BigNumber,
|
export type OrderValues = [BigNumber, BigNumber, BigNumber, BigNumber, BigNumber, BigNumber];
|
||||||
BigNumber, BigNumber, BigNumber];
|
|
||||||
|
|
||||||
export type LogEvent = Web3.LogEntryEvent;
|
export type LogEvent = Web3.LogEntryEvent;
|
||||||
export interface DecodedLogEvent<ArgsType> {
|
export interface DecodedLogEvent<ArgsType> {
|
||||||
@@ -51,15 +56,8 @@ export interface DecodedLogEvent<ArgsType> {
|
|||||||
log: LogWithDecodedArgs<ArgsType>;
|
log: LogWithDecodedArgs<ArgsType>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type EventCallback<ArgsType> = (err: null|Error, log?: DecodedLogEvent<ArgsType>) => void;
|
export type EventCallback<ArgsType> = (err: null | Error, log?: DecodedLogEvent<ArgsType>) => void;
|
||||||
export type EventWatcherCallback = (log: LogEvent) => void;
|
export type EventWatcherCallback = (err: null | Error, log?: LogEvent) => void;
|
||||||
|
|
||||||
export enum SolidityTypes {
|
|
||||||
Address = 'address',
|
|
||||||
Uint256 = 'uint256',
|
|
||||||
Uint8 = 'uint8',
|
|
||||||
Uint = 'uint',
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum ExchangeContractErrCodes {
|
export enum ExchangeContractErrCodes {
|
||||||
ERROR_FILL_EXPIRED, // Order has already expired
|
ERROR_FILL_EXPIRED, // Order has already expired
|
||||||
@@ -95,8 +93,6 @@ export enum ExchangeContractErrs {
|
|||||||
BatchOrdersMustHaveAtLeastOneItem = 'BATCH_ORDERS_MUST_HAVE_AT_LEAST_ONE_ITEM',
|
BatchOrdersMustHaveAtLeastOneItem = 'BATCH_ORDERS_MUST_HAVE_AT_LEAST_ONE_ITEM',
|
||||||
}
|
}
|
||||||
|
|
||||||
export type RawLog = Web3.LogEntry;
|
|
||||||
|
|
||||||
export interface ContractEvent {
|
export interface ContractEvent {
|
||||||
logIndex: number;
|
logIndex: number;
|
||||||
transactionIndex: number;
|
transactionIndex: number;
|
||||||
@@ -109,56 +105,7 @@ export interface ContractEvent {
|
|||||||
args: ContractEventArgs;
|
args: ContractEventArgs;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LogFillContractEventArgs {
|
export type ContractEventArgs = ExchangeContractEventArgs | TokenContractEventArgs | EtherTokenContractEventArgs;
|
||||||
maker: string;
|
|
||||||
taker: string;
|
|
||||||
feeRecipient: string;
|
|
||||||
makerToken: string;
|
|
||||||
takerToken: string;
|
|
||||||
filledMakerTokenAmount: BigNumber;
|
|
||||||
filledTakerTokenAmount: BigNumber;
|
|
||||||
paidMakerFee: BigNumber;
|
|
||||||
paidTakerFee: BigNumber;
|
|
||||||
tokens: string;
|
|
||||||
orderHash: string;
|
|
||||||
}
|
|
||||||
export interface LogCancelContractEventArgs {
|
|
||||||
maker: string;
|
|
||||||
feeRecipient: string;
|
|
||||||
makerToken: string;
|
|
||||||
takerToken: string;
|
|
||||||
cancelledMakerTokenAmount: BigNumber;
|
|
||||||
cancelledTakerTokenAmount: BigNumber;
|
|
||||||
tokens: string;
|
|
||||||
orderHash: string;
|
|
||||||
}
|
|
||||||
export interface LogErrorContractEventArgs {
|
|
||||||
errorId: BigNumber;
|
|
||||||
orderHash: string;
|
|
||||||
}
|
|
||||||
export type ExchangeContractEventArgs = LogFillContractEventArgs|LogCancelContractEventArgs|LogErrorContractEventArgs;
|
|
||||||
export interface TransferContractEventArgs {
|
|
||||||
_from: string;
|
|
||||||
_to: string;
|
|
||||||
_value: BigNumber;
|
|
||||||
}
|
|
||||||
export interface ApprovalContractEventArgs {
|
|
||||||
_owner: string;
|
|
||||||
_spender: string;
|
|
||||||
_value: BigNumber;
|
|
||||||
}
|
|
||||||
export interface DepositContractEventArgs {
|
|
||||||
_owner: string;
|
|
||||||
_value: BigNumber;
|
|
||||||
}
|
|
||||||
export interface WithdrawalContractEventArgs {
|
|
||||||
_owner: string;
|
|
||||||
_value: BigNumber;
|
|
||||||
}
|
|
||||||
export type TokenContractEventArgs = TransferContractEventArgs|ApprovalContractEventArgs;
|
|
||||||
export type EtherTokenContractEventArgs = TokenContractEventArgs|DepositContractEventArgs|WithdrawalContractEventArgs;
|
|
||||||
export type ContractEventArgs = ExchangeContractEventArgs|TokenContractEventArgs|EtherTokenContractEventArgs;
|
|
||||||
export type ContractEventArg = string|BigNumber;
|
|
||||||
|
|
||||||
export interface Order {
|
export interface Order {
|
||||||
maker: string;
|
maker: string;
|
||||||
@@ -180,7 +127,7 @@ export interface SignedOrder extends Order {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// [address, name, symbol, decimals, ipfsHash, swarmHash]
|
// [address, name, symbol, decimals, ipfsHash, swarmHash]
|
||||||
export type TokenMetadata = [string, string, string, BigNumber, string, string];
|
export type TokenMetadata = [string, string, string, number, string, string];
|
||||||
|
|
||||||
export interface Token {
|
export interface Token {
|
||||||
name: string;
|
name: string;
|
||||||
@@ -200,40 +147,12 @@ export interface TokenAddressBySymbol {
|
|||||||
[symbol: string]: string;
|
[symbol: string]: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum ExchangeEvents {
|
export type ContractEvents = TokenEvents | ExchangeEvents | EtherTokenEvents;
|
||||||
LogFill = 'LogFill',
|
|
||||||
LogCancel = 'LogCancel',
|
|
||||||
LogError = 'LogError',
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum TokenEvents {
|
|
||||||
Transfer = 'Transfer',
|
|
||||||
Approval = 'Approval',
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum EtherTokenEvents {
|
|
||||||
Transfer = 'Transfer',
|
|
||||||
Approval = 'Approval',
|
|
||||||
Deposit = 'Deposit',
|
|
||||||
Withdrawal = 'Withdrawal',
|
|
||||||
}
|
|
||||||
|
|
||||||
export type ContractEvents = TokenEvents|ExchangeEvents|EtherTokenEvents;
|
|
||||||
|
|
||||||
export interface IndexedFilterValues {
|
export interface IndexedFilterValues {
|
||||||
[index: string]: ContractEventArg;
|
[index: string]: ContractEventArg;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Earliest is omitted by design. It is simply an alias for the `0` constant and
|
|
||||||
// is thus not very helpful. Moreover, this type is used in places that only accept
|
|
||||||
// `latest` or `pending`.
|
|
||||||
export enum BlockParamLiteral {
|
|
||||||
Latest = 'latest',
|
|
||||||
Pending = 'pending',
|
|
||||||
}
|
|
||||||
|
|
||||||
export type BlockParam = BlockParamLiteral|number;
|
|
||||||
|
|
||||||
export interface BlockRange {
|
export interface BlockRange {
|
||||||
fromBlock: BlockParam;
|
fromBlock: BlockParam;
|
||||||
toBlock: BlockParam;
|
toBlock: BlockParam;
|
||||||
@@ -242,7 +161,7 @@ export interface BlockRange {
|
|||||||
export type DoneCallback = (err?: Error) => void;
|
export type DoneCallback = (err?: Error) => void;
|
||||||
|
|
||||||
export interface OrderCancellationRequest {
|
export interface OrderCancellationRequest {
|
||||||
order: Order|SignedOrder;
|
order: Order | SignedOrder;
|
||||||
takerTokenCancelAmount: BigNumber;
|
takerTokenCancelAmount: BigNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -262,11 +181,6 @@ export type SyncMethod = (...args: any[]) => any;
|
|||||||
*/
|
*/
|
||||||
export type Web3Provider = Web3.Provider;
|
export type Web3Provider = Web3.Provider;
|
||||||
|
|
||||||
export interface JSONRPCPayload {
|
|
||||||
params: any[];
|
|
||||||
method: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* orderExpirationCheckingIntervalMs: How often to check for expired orders. Default: 50
|
* orderExpirationCheckingIntervalMs: How often to check for expired orders. Default: 50
|
||||||
* eventPollingIntervalMs: How often to poll the Ethereum node for new events. Defaults: 200
|
* eventPollingIntervalMs: How often to poll the Ethereum node for new events. Defaults: 200
|
||||||
@@ -282,9 +196,10 @@ export interface OrderStateWatcherConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* networkId: The id of the underlying ethereum network your provider is connected to. (1-mainnet, 42-kovan, 50-testrpc)
|
* networkId: The id of the underlying ethereum network your provider is connected to. (1-mainnet, 3-ropsten, 4-rinkeby, 42-kovan, 50-testrpc)
|
||||||
* gasPrice: Gas price to use with every transaction
|
* gasPrice: Gas price to use with every transaction
|
||||||
* exchangeContractAddress: The address of an exchange contract to use
|
* exchangeContractAddress: The address of an exchange contract to use
|
||||||
|
* zrxContractAddress: The address of the ZRX contract to use
|
||||||
* tokenRegistryContractAddress: The address of a token registry contract to use
|
* tokenRegistryContractAddress: The address of a token registry contract to use
|
||||||
* tokenTransferProxyContractAddress: The address of the token transfer proxy contract to use
|
* tokenTransferProxyContractAddress: The address of the token transfer proxy contract to use
|
||||||
* orderWatcherConfig: All the configs related to the orderWatcher
|
* orderWatcherConfig: All the configs related to the orderWatcher
|
||||||
@@ -293,29 +208,13 @@ export interface ZeroExConfig {
|
|||||||
networkId: number;
|
networkId: number;
|
||||||
gasPrice?: BigNumber;
|
gasPrice?: BigNumber;
|
||||||
exchangeContractAddress?: string;
|
exchangeContractAddress?: string;
|
||||||
|
zrxContractAddress?: string;
|
||||||
tokenRegistryContractAddress?: string;
|
tokenRegistryContractAddress?: string;
|
||||||
tokenTransferProxyContractAddress?: string;
|
tokenTransferProxyContractAddress?: string;
|
||||||
orderWatcherConfig?: OrderStateWatcherConfig;
|
orderWatcherConfig?: OrderStateWatcherConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum AbiType {
|
export type ArtifactContractName = 'ZRX' | 'TokenTransferProxy' | 'TokenRegistry' | 'Token' | 'Exchange' | 'EtherToken';
|
||||||
Function = 'function',
|
|
||||||
Constructor = 'constructor',
|
|
||||||
Event = 'event',
|
|
||||||
Fallback = 'fallback',
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface DecodedLogArgs {
|
|
||||||
[argName: string]: ContractEventArg;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface LogWithDecodedArgs<ArgsType> extends Web3.DecodedLogEntry<ArgsType> {}
|
|
||||||
|
|
||||||
export interface TransactionReceiptWithDecodedLogs extends TransactionReceipt {
|
|
||||||
logs: Array<LogWithDecodedArgs<DecodedLogArgs>|Web3.LogEntry>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type ArtifactContractName = 'ZRX'|'TokenTransferProxy'|'TokenRegistry'|'Token'|'Exchange'|'EtherToken';
|
|
||||||
|
|
||||||
export interface Artifact {
|
export interface Artifact {
|
||||||
contract_name: ArtifactContractName;
|
contract_name: ArtifactContractName;
|
||||||
@@ -399,7 +298,7 @@ export interface OrderStateInvalid {
|
|||||||
error: ExchangeContractErrs;
|
error: ExchangeContractErrs;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type OrderState = OrderStateValid|OrderStateInvalid;
|
export type OrderState = OrderStateValid | OrderStateInvalid;
|
||||||
|
|
||||||
export type OnOrderStateChangeCallback = (orderState: OrderState) => void;
|
export type OnOrderStateChangeCallback = (err: Error | null, orderState?: OrderState) => void;
|
||||||
// tslint:disable:max-file-line-count
|
// tslint:disable:max-file-line-count
|
||||||
|
|||||||
@@ -1,69 +0,0 @@
|
|||||||
import BigNumber from 'bignumber.js';
|
|
||||||
import * as _ from 'lodash';
|
|
||||||
import * as Web3 from 'web3';
|
|
||||||
import * as SolidityCoder from 'web3/lib/solidity/coder';
|
|
||||||
|
|
||||||
import {AbiType, ContractEventArgs, DecodedLogArgs, LogWithDecodedArgs, RawLog, SolidityTypes} from '../types';
|
|
||||||
|
|
||||||
export class AbiDecoder {
|
|
||||||
private _savedABIs: Web3.AbiDefinition[] = [];
|
|
||||||
private _methodIds: {[signatureHash: string]: Web3.EventAbi} = {};
|
|
||||||
private static _padZeros(address: string) {
|
|
||||||
let formatted = address;
|
|
||||||
if (_.startsWith(formatted, '0x')) {
|
|
||||||
formatted = formatted.slice(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
formatted = _.padStart(formatted, 40, '0');
|
|
||||||
return `0x${formatted}`;
|
|
||||||
}
|
|
||||||
constructor(abiArrays: Web3.AbiDefinition[][]) {
|
|
||||||
_.map(abiArrays, this._addABI.bind(this));
|
|
||||||
}
|
|
||||||
// This method can only decode logs from the 0x & ERC20 smart contracts
|
|
||||||
public tryToDecodeLogOrNoop<ArgsType extends ContractEventArgs>(
|
|
||||||
log: Web3.LogEntry): LogWithDecodedArgs<ArgsType>|RawLog {
|
|
||||||
const methodId = log.topics[0];
|
|
||||||
const event = this._methodIds[methodId];
|
|
||||||
if (_.isUndefined(event)) {
|
|
||||||
return log;
|
|
||||||
}
|
|
||||||
const logData = log.data;
|
|
||||||
const decodedParams: DecodedLogArgs = {};
|
|
||||||
let dataIndex = 0;
|
|
||||||
let topicsIndex = 1;
|
|
||||||
|
|
||||||
const nonIndexedInputs = _.filter(event.inputs, input => !input.indexed);
|
|
||||||
const dataTypes = _.map(nonIndexedInputs, input => input.type);
|
|
||||||
const decodedData = SolidityCoder.decodeParams(dataTypes, logData.slice('0x'.length));
|
|
||||||
|
|
||||||
_.map(event.inputs, (param: Web3.EventParameter) => {
|
|
||||||
// Indexed parameters are stored in topics. Non-indexed ones in decodedData
|
|
||||||
let value = param.indexed ? log.topics[topicsIndex++] : decodedData[dataIndex++];
|
|
||||||
if (param.type === SolidityTypes.Address) {
|
|
||||||
value = AbiDecoder._padZeros(new BigNumber(value).toString(16));
|
|
||||||
} else if (param.type === SolidityTypes.Uint256 ||
|
|
||||||
param.type === SolidityTypes.Uint8 ||
|
|
||||||
param.type === SolidityTypes.Uint) {
|
|
||||||
value = new BigNumber(value);
|
|
||||||
}
|
|
||||||
decodedParams[param.name] = value;
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
...log,
|
|
||||||
event: event.name,
|
|
||||||
args: decodedParams,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
private _addABI(abiArray: Web3.AbiDefinition[]): void {
|
|
||||||
_.map(abiArray, (abi: Web3.AbiDefinition) => {
|
|
||||||
if (abi.type === AbiType.Event) {
|
|
||||||
const signature = `${abi.name}(${_.map(abi.inputs, input => input.type).join(',')})`;
|
|
||||||
const signatureHash = new Web3().sha3(signature);
|
|
||||||
this._methodIds[signatureHash] = abi;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this._savedABIs = this._savedABIs.concat(abiArray);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
import {assert as sharedAssert} from '@0xproject/assert';
|
import { assert as sharedAssert } from '@0xproject/assert';
|
||||||
// We need those two unused imports because they're actually used by sharedAssert which gets injected here
|
// 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-next-line:no-unused-variable
|
||||||
import {Schema} from '@0xproject/json-schemas';
|
import { Schema } from '@0xproject/json-schemas';
|
||||||
import {Web3Wrapper} from '@0xproject/web3-wrapper';
|
|
||||||
// tslint:disable-next-line:no-unused-variable
|
// tslint:disable-next-line:no-unused-variable
|
||||||
import * as BigNumber from 'bignumber.js';
|
import { BigNumber } from '@0xproject/utils';
|
||||||
|
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import {ECSignature} from '../types';
|
import { ECSignature } from '../types';
|
||||||
import {signatureUtils} from '../utils/signature_utils';
|
import { signatureUtils } from '../utils/signature_utils';
|
||||||
|
|
||||||
export const assert = {
|
export const assert = {
|
||||||
...sharedAssert,
|
...sharedAssert,
|
||||||
@@ -16,11 +16,15 @@ export const assert = {
|
|||||||
const isValidSignature = signatureUtils.isValidSignature(orderHash, ecSignature, signerAddress);
|
const isValidSignature = signatureUtils.isValidSignature(orderHash, ecSignature, signerAddress);
|
||||||
this.assert(isValidSignature, `Expected order with hash '${orderHash}' to have a valid signature`);
|
this.assert(isValidSignature, `Expected order with hash '${orderHash}' to have a valid signature`);
|
||||||
},
|
},
|
||||||
async isSenderAddressAsync(variableName: string, senderAddressHex: string,
|
async isSenderAddressAsync(
|
||||||
web3Wrapper: Web3Wrapper): Promise<void> {
|
variableName: string,
|
||||||
|
senderAddressHex: string,
|
||||||
|
web3Wrapper: Web3Wrapper,
|
||||||
|
): Promise<void> {
|
||||||
sharedAssert.isETHAddressHex(variableName, senderAddressHex);
|
sharedAssert.isETHAddressHex(variableName, senderAddressHex);
|
||||||
const isSenderAddressAvailable = await web3Wrapper.isSenderAddressAvailableAsync(senderAddressHex);
|
const isSenderAddressAvailable = await web3Wrapper.isSenderAddressAvailableAsync(senderAddressHex);
|
||||||
sharedAssert.assert(isSenderAddressAvailable,
|
sharedAssert.assert(
|
||||||
|
isSenderAddressAvailable,
|
||||||
`Specified ${variableName} ${senderAddressHex} isn't available through the supplied web3 provider`,
|
`Specified ${variableName} ${senderAddressHex} isn't available through the supplied web3 provider`,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import BigNumber from 'bignumber.js';
|
import { BigNumber } from '@0xproject/utils';
|
||||||
|
|
||||||
export const constants = {
|
export const constants = {
|
||||||
NULL_ADDRESS: '0x0000000000000000000000000000000000000000',
|
NULL_ADDRESS: '0x0000000000000000000000000000000000000000',
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import {AsyncMethod, SyncMethod, ZeroExError} from '../types';
|
import { AsyncMethod, SyncMethod, ZeroExError } from '../types';
|
||||||
|
|
||||||
import {constants} from './constants';
|
import { constants } from './constants';
|
||||||
|
|
||||||
type ErrorTransformer = (err: Error) => Error;
|
type ErrorTransformer = (err: Error) => Error;
|
||||||
|
|
||||||
@@ -18,8 +18,8 @@ const contractCallErrorTransformer = (error: Error) => {
|
|||||||
|
|
||||||
const schemaErrorTransformer = (error: Error) => {
|
const schemaErrorTransformer = (error: Error) => {
|
||||||
if (_.includes(error.message, constants.INVALID_TAKER_FORMAT)) {
|
if (_.includes(error.message, constants.INVALID_TAKER_FORMAT)) {
|
||||||
// tslint:disable-next-line:max-line-length
|
const errMsg =
|
||||||
const errMsg = 'Order taker must be of type string. If you want anyone to be able to fill an order - pass ZeroEx.NULL_ADDRESS';
|
'Order taker must be of type string. If you want anyone to be able to fill an order - pass ZeroEx.NULL_ADDRESS';
|
||||||
return new Error(errMsg);
|
return new Error(errMsg);
|
||||||
}
|
}
|
||||||
return error;
|
return error;
|
||||||
@@ -30,14 +30,16 @@ const schemaErrorTransformer = (error: Error) => {
|
|||||||
*/
|
*/
|
||||||
const asyncErrorHandlerFactory = (errorTransformer: ErrorTransformer) => {
|
const asyncErrorHandlerFactory = (errorTransformer: ErrorTransformer) => {
|
||||||
const asyncErrorHandlingDecorator = (
|
const asyncErrorHandlingDecorator = (
|
||||||
target: object, key: string|symbol, descriptor: TypedPropertyDescriptor<AsyncMethod>,
|
target: object,
|
||||||
|
key: string | symbol,
|
||||||
|
descriptor: TypedPropertyDescriptor<AsyncMethod>,
|
||||||
) => {
|
) => {
|
||||||
const originalMethod = (descriptor.value as AsyncMethod);
|
const originalMethod = descriptor.value as AsyncMethod;
|
||||||
|
|
||||||
// Do not use arrow syntax here. Use a function expression in
|
// Do not use arrow syntax here. Use a function expression in
|
||||||
// order to use the correct value of `this` in this method
|
// order to use the correct value of `this` in this method
|
||||||
// tslint:disable-next-line:only-arrow-functions
|
// tslint:disable-next-line:only-arrow-functions
|
||||||
descriptor.value = async function(...args: any[]) {
|
descriptor.value = async function(...args: any[]) {
|
||||||
try {
|
try {
|
||||||
const result = await originalMethod.apply(this, args);
|
const result = await originalMethod.apply(this, args);
|
||||||
return result;
|
return result;
|
||||||
@@ -55,9 +57,11 @@ const asyncErrorHandlerFactory = (errorTransformer: ErrorTransformer) => {
|
|||||||
|
|
||||||
const syncErrorHandlerFactory = (errorTransformer: ErrorTransformer) => {
|
const syncErrorHandlerFactory = (errorTransformer: ErrorTransformer) => {
|
||||||
const syncErrorHandlingDecorator = (
|
const syncErrorHandlingDecorator = (
|
||||||
target: object, key: string|symbol, descriptor: TypedPropertyDescriptor<SyncMethod>,
|
target: object,
|
||||||
|
key: string | symbol,
|
||||||
|
descriptor: TypedPropertyDescriptor<SyncMethod>,
|
||||||
) => {
|
) => {
|
||||||
const originalMethod = (descriptor.value as SyncMethod);
|
const originalMethod = descriptor.value as SyncMethod;
|
||||||
|
|
||||||
// Do not use arrow syntax here. Use a function expression in
|
// Do not use arrow syntax here. Use a function expression in
|
||||||
// order to use the correct value of `this` in this method
|
// order to use the correct value of `this` in this method
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import BigNumber from 'bignumber.js';
|
import { BlockParamLiteral } from '@0xproject/types';
|
||||||
|
import { BigNumber } from '@0xproject/utils';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import {TokenWrapper} from '../contract_wrappers/token_wrapper';
|
import { TokenWrapper } from '../contract_wrappers/token_wrapper';
|
||||||
import {BalanceAndProxyAllowanceLazyStore} from '../stores/balance_proxy_allowance_lazy_store';
|
import { BalanceAndProxyAllowanceLazyStore } from '../stores/balance_proxy_allowance_lazy_store';
|
||||||
import {BlockParamLiteral, ExchangeContractErrs, TradeSide, TransferType} from '../types';
|
import { ExchangeContractErrs, TradeSide, TransferType } from '../types';
|
||||||
|
|
||||||
enum FailureReason {
|
enum FailureReason {
|
||||||
Balance = 'balance',
|
Balance = 'balance',
|
||||||
@@ -36,8 +37,11 @@ const ERR_MSG_MAPPING = {
|
|||||||
export class ExchangeTransferSimulator {
|
export class ExchangeTransferSimulator {
|
||||||
private _store: BalanceAndProxyAllowanceLazyStore;
|
private _store: BalanceAndProxyAllowanceLazyStore;
|
||||||
private _UNLIMITED_ALLOWANCE_IN_BASE_UNITS: BigNumber;
|
private _UNLIMITED_ALLOWANCE_IN_BASE_UNITS: BigNumber;
|
||||||
private static _throwValidationError(failureReason: FailureReason, tradeSide: TradeSide,
|
private static _throwValidationError(
|
||||||
transferType: TransferType): never {
|
failureReason: FailureReason,
|
||||||
|
tradeSide: TradeSide,
|
||||||
|
transferType: TransferType,
|
||||||
|
): never {
|
||||||
const errMsg = ERR_MSG_MAPPING[failureReason][tradeSide][transferType];
|
const errMsg = ERR_MSG_MAPPING[failureReason][tradeSide][transferType];
|
||||||
throw new Error(errMsg);
|
throw new Error(errMsg);
|
||||||
}
|
}
|
||||||
@@ -54,9 +58,14 @@ export class ExchangeTransferSimulator {
|
|||||||
* @param tradeSide Is Maker/Taker transferring
|
* @param tradeSide Is Maker/Taker transferring
|
||||||
* @param transferType Is it a fee payment or a value transfer
|
* @param transferType Is it a fee payment or a value transfer
|
||||||
*/
|
*/
|
||||||
public async transferFromAsync(tokenAddress: string, from: string, to: string,
|
public async transferFromAsync(
|
||||||
amountInBaseUnits: BigNumber, tradeSide: TradeSide,
|
tokenAddress: string,
|
||||||
transferType: TransferType): Promise<void> {
|
from: string,
|
||||||
|
to: string,
|
||||||
|
amountInBaseUnits: BigNumber,
|
||||||
|
tradeSide: TradeSide,
|
||||||
|
transferType: TransferType,
|
||||||
|
): Promise<void> {
|
||||||
const balance = await this._store.getBalanceAsync(tokenAddress, from);
|
const balance = await this._store.getBalanceAsync(tokenAddress, from);
|
||||||
const proxyAllowance = await this._store.getProxyAllowanceAsync(tokenAddress, from);
|
const proxyAllowance = await this._store.getProxyAllowanceAsync(tokenAddress, from);
|
||||||
if (proxyAllowance.lessThan(amountInBaseUnits)) {
|
if (proxyAllowance.lessThan(amountInBaseUnits)) {
|
||||||
@@ -69,20 +78,29 @@ export class ExchangeTransferSimulator {
|
|||||||
await this._decreaseBalanceAsync(tokenAddress, from, amountInBaseUnits);
|
await this._decreaseBalanceAsync(tokenAddress, from, amountInBaseUnits);
|
||||||
await this._increaseBalanceAsync(tokenAddress, to, amountInBaseUnits);
|
await this._increaseBalanceAsync(tokenAddress, to, amountInBaseUnits);
|
||||||
}
|
}
|
||||||
private async _decreaseProxyAllowanceAsync(tokenAddress: string, userAddress: string,
|
private async _decreaseProxyAllowanceAsync(
|
||||||
amountInBaseUnits: BigNumber): Promise<void> {
|
tokenAddress: string,
|
||||||
|
userAddress: string,
|
||||||
|
amountInBaseUnits: BigNumber,
|
||||||
|
): Promise<void> {
|
||||||
const proxyAllowance = await this._store.getProxyAllowanceAsync(tokenAddress, userAddress);
|
const proxyAllowance = await this._store.getProxyAllowanceAsync(tokenAddress, userAddress);
|
||||||
if (!proxyAllowance.eq(this._UNLIMITED_ALLOWANCE_IN_BASE_UNITS)) {
|
if (!proxyAllowance.eq(this._UNLIMITED_ALLOWANCE_IN_BASE_UNITS)) {
|
||||||
this._store.setProxyAllowance(tokenAddress, userAddress, proxyAllowance.minus(amountInBaseUnits));
|
this._store.setProxyAllowance(tokenAddress, userAddress, proxyAllowance.minus(amountInBaseUnits));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private async _increaseBalanceAsync(tokenAddress: string, userAddress: string,
|
private async _increaseBalanceAsync(
|
||||||
amountInBaseUnits: BigNumber): Promise<void> {
|
tokenAddress: string,
|
||||||
|
userAddress: string,
|
||||||
|
amountInBaseUnits: BigNumber,
|
||||||
|
): Promise<void> {
|
||||||
const balance = await this._store.getBalanceAsync(tokenAddress, userAddress);
|
const balance = await this._store.getBalanceAsync(tokenAddress, userAddress);
|
||||||
this._store.setBalance(tokenAddress, userAddress, balance.plus(amountInBaseUnits));
|
this._store.setBalance(tokenAddress, userAddress, balance.plus(amountInBaseUnits));
|
||||||
}
|
}
|
||||||
private async _decreaseBalanceAsync(tokenAddress: string, userAddress: string,
|
private async _decreaseBalanceAsync(
|
||||||
amountInBaseUnits: BigNumber): Promise<void> {
|
tokenAddress: string,
|
||||||
|
userAddress: string,
|
||||||
|
amountInBaseUnits: BigNumber,
|
||||||
|
): Promise<void> {
|
||||||
const balance = await this._store.getBalanceAsync(tokenAddress, userAddress);
|
const balance = await this._store.getBalanceAsync(tokenAddress, userAddress);
|
||||||
this._store.setBalance(tokenAddress, userAddress, balance.minus(amountInBaseUnits));
|
this._store.setBalance(tokenAddress, userAddress, balance.minus(amountInBaseUnits));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import * as _ from 'lodash';
|
|||||||
import * as uuid from 'uuid/v4';
|
import * as uuid from 'uuid/v4';
|
||||||
import * as Web3 from 'web3';
|
import * as Web3 from 'web3';
|
||||||
|
|
||||||
import {BlockRange, ContractEvents, IndexedFilterValues} from '../types';
|
import { BlockRange, ContractEvents, IndexedFilterValues } from '../types';
|
||||||
|
|
||||||
const TOPIC_LENGTH = 32;
|
const TOPIC_LENGTH = 32;
|
||||||
|
|
||||||
@@ -12,10 +12,14 @@ export const filterUtils = {
|
|||||||
generateUUID(): string {
|
generateUUID(): string {
|
||||||
return uuid();
|
return uuid();
|
||||||
},
|
},
|
||||||
getFilter(address: string, eventName: ContractEvents,
|
getFilter(
|
||||||
indexFilterValues: IndexedFilterValues, abi: Web3.ContractAbi,
|
address: string,
|
||||||
blockRange?: BlockRange): Web3.FilterObject {
|
eventName: ContractEvents,
|
||||||
const eventAbi = _.find(abi, {name: eventName}) as Web3.EventAbi;
|
indexFilterValues: IndexedFilterValues,
|
||||||
|
abi: Web3.ContractAbi,
|
||||||
|
blockRange?: BlockRange,
|
||||||
|
): Web3.FilterObject {
|
||||||
|
const eventAbi = _.find(abi, { name: eventName }) as Web3.EventAbi;
|
||||||
const eventSignature = filterUtils.getEventSignatureFromAbiByName(eventAbi, eventName);
|
const eventSignature = filterUtils.getEventSignatureFromAbiByName(eventAbi, eventName);
|
||||||
const topicForEventSignature = ethUtil.addHexPrefix(jsSHA3.keccak256(eventSignature));
|
const topicForEventSignature = ethUtil.addHexPrefix(jsSHA3.keccak256(eventSignature));
|
||||||
const topicsForIndexedArgs = filterUtils.getTopicsForIndexedArgs(eventAbi, indexFilterValues);
|
const topicsForIndexedArgs = filterUtils.getTopicsForIndexedArgs(eventAbi, indexFilterValues);
|
||||||
@@ -37,8 +41,8 @@ export const filterUtils = {
|
|||||||
const signature = `${eventAbi.name}(${types.join(',')})`;
|
const signature = `${eventAbi.name}(${types.join(',')})`;
|
||||||
return signature;
|
return signature;
|
||||||
},
|
},
|
||||||
getTopicsForIndexedArgs(abi: Web3.EventAbi, indexFilterValues: IndexedFilterValues): Array<string|null> {
|
getTopicsForIndexedArgs(abi: Web3.EventAbi, indexFilterValues: IndexedFilterValues): Array<string | null> {
|
||||||
const topics: Array<string|null> = [];
|
const topics: Array<string | null> = [];
|
||||||
for (const eventInput of abi.inputs) {
|
for (const eventInput of abi.inputs) {
|
||||||
if (!eventInput.indexed) {
|
if (!eventInput.indexed) {
|
||||||
continue;
|
continue;
|
||||||
@@ -65,12 +69,12 @@ export const filterUtils = {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
matchesTopics(logTopics: string[], filterTopics: Array<string[]|string|null>): boolean {
|
matchesTopics(logTopics: string[], filterTopics: Array<string[] | string | null>): boolean {
|
||||||
const matchesTopic = _.zipWith(logTopics, filterTopics, filterUtils.matchesTopic.bind(filterUtils));
|
const matchesTopic = _.zipWith(logTopics, filterTopics, filterUtils.matchesTopic.bind(filterUtils));
|
||||||
const matchesTopics = _.every(matchesTopic);
|
const matchesTopics = _.every(matchesTopic);
|
||||||
return matchesTopics;
|
return matchesTopics;
|
||||||
},
|
},
|
||||||
matchesTopic(logTopic: string, filterTopic: string[]|string|null): boolean {
|
matchesTopic(logTopic: string, filterTopic: string[] | string | null): boolean {
|
||||||
if (_.isArray(filterTopic)) {
|
if (_.isArray(filterTopic)) {
|
||||||
return _.includes(filterTopic, logTopic);
|
return _.includes(filterTopic, logTopic);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import BigNumber from 'bignumber.js';
|
import { BigNumber } from '@0xproject/utils';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import {ZeroEx} from '../0x';
|
import { ZeroEx } from '../0x';
|
||||||
import {ExchangeWrapper} from '../contract_wrappers/exchange_wrapper';
|
import { ExchangeWrapper } from '../contract_wrappers/exchange_wrapper';
|
||||||
import {RemainingFillableCalculator} from '../order_watcher/remaining_fillable_calculator';
|
import { RemainingFillableCalculator } from '../order_watcher/remaining_fillable_calculator';
|
||||||
import {BalanceAndProxyAllowanceLazyStore} from '../stores/balance_proxy_allowance_lazy_store';
|
import { BalanceAndProxyAllowanceLazyStore } from '../stores/balance_proxy_allowance_lazy_store';
|
||||||
import {OrderFilledCancelledLazyStore} from '../stores/order_filled_cancelled_lazy_store';
|
import { OrderFilledCancelledLazyStore } from '../stores/order_filled_cancelled_lazy_store';
|
||||||
import {
|
import {
|
||||||
ExchangeContractErrs,
|
ExchangeContractErrs,
|
||||||
OrderRelevantState,
|
OrderRelevantState,
|
||||||
@@ -44,15 +44,20 @@ export class OrderStateUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
const minFillableTakerTokenAmountWithinNoRoundingErrorRange = signedOrder.takerTokenAmount
|
const minFillableTakerTokenAmountWithinNoRoundingErrorRange = signedOrder.takerTokenAmount
|
||||||
.dividedBy(ACCEPTABLE_RELATIVE_ROUNDING_ERROR)
|
.dividedBy(ACCEPTABLE_RELATIVE_ROUNDING_ERROR)
|
||||||
.dividedBy(signedOrder.makerTokenAmount);
|
.dividedBy(signedOrder.makerTokenAmount);
|
||||||
if (orderRelevantState.remainingFillableTakerTokenAmount
|
if (
|
||||||
.lessThan(minFillableTakerTokenAmountWithinNoRoundingErrorRange)) {
|
orderRelevantState.remainingFillableTakerTokenAmount.lessThan(
|
||||||
|
minFillableTakerTokenAmountWithinNoRoundingErrorRange,
|
||||||
|
)
|
||||||
|
) {
|
||||||
throw new Error(ExchangeContractErrs.OrderFillRoundingError);
|
throw new Error(ExchangeContractErrs.OrderFillRoundingError);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
constructor(balanceAndProxyAllowanceLazyStore: BalanceAndProxyAllowanceLazyStore,
|
constructor(
|
||||||
orderFilledCancelledLazyStore: OrderFilledCancelledLazyStore) {
|
balanceAndProxyAllowanceLazyStore: BalanceAndProxyAllowanceLazyStore,
|
||||||
|
orderFilledCancelledLazyStore: OrderFilledCancelledLazyStore,
|
||||||
|
) {
|
||||||
this._balanceAndProxyAllowanceLazyStore = balanceAndProxyAllowanceLazyStore;
|
this._balanceAndProxyAllowanceLazyStore = balanceAndProxyAllowanceLazyStore;
|
||||||
this._orderFilledCancelledLazyStore = orderFilledCancelledLazyStore;
|
this._orderFilledCancelledLazyStore = orderFilledCancelledLazyStore;
|
||||||
}
|
}
|
||||||
@@ -85,16 +90,20 @@ export class OrderStateUtils {
|
|||||||
const zrxTokenAddress = exchange.getZRXTokenAddress();
|
const zrxTokenAddress = exchange.getZRXTokenAddress();
|
||||||
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
||||||
const makerBalance = await this._balanceAndProxyAllowanceLazyStore.getBalanceAsync(
|
const makerBalance = await this._balanceAndProxyAllowanceLazyStore.getBalanceAsync(
|
||||||
signedOrder.makerTokenAddress, signedOrder.maker,
|
signedOrder.makerTokenAddress,
|
||||||
|
signedOrder.maker,
|
||||||
);
|
);
|
||||||
const makerProxyAllowance = await this._balanceAndProxyAllowanceLazyStore.getProxyAllowanceAsync(
|
const makerProxyAllowance = await this._balanceAndProxyAllowanceLazyStore.getProxyAllowanceAsync(
|
||||||
signedOrder.makerTokenAddress, signedOrder.maker,
|
signedOrder.makerTokenAddress,
|
||||||
|
signedOrder.maker,
|
||||||
);
|
);
|
||||||
const makerFeeBalance = await this._balanceAndProxyAllowanceLazyStore.getBalanceAsync(
|
const makerFeeBalance = await this._balanceAndProxyAllowanceLazyStore.getBalanceAsync(
|
||||||
zrxTokenAddress, signedOrder.maker,
|
zrxTokenAddress,
|
||||||
|
signedOrder.maker,
|
||||||
);
|
);
|
||||||
const makerFeeProxyAllowance = await this._balanceAndProxyAllowanceLazyStore.getProxyAllowanceAsync(
|
const makerFeeProxyAllowance = await this._balanceAndProxyAllowanceLazyStore.getProxyAllowanceAsync(
|
||||||
zrxTokenAddress, signedOrder.maker,
|
zrxTokenAddress,
|
||||||
|
signedOrder.maker,
|
||||||
);
|
);
|
||||||
const filledTakerTokenAmount = await this._orderFilledCancelledLazyStore.getFilledTakerAmountAsync(orderHash);
|
const filledTakerTokenAmount = await this._orderFilledCancelledLazyStore.getFilledTakerAmountAsync(orderHash);
|
||||||
const cancelledTakerTokenAmount = await this._orderFilledCancelledLazyStore.getCancelledTakerAmountAsync(
|
const cancelledTakerTokenAmount = await this._orderFilledCancelledLazyStore.getCancelledTakerAmountAsync(
|
||||||
@@ -104,17 +113,20 @@ export class OrderStateUtils {
|
|||||||
const totalMakerTokenAmount = signedOrder.makerTokenAmount;
|
const totalMakerTokenAmount = signedOrder.makerTokenAmount;
|
||||||
const totalTakerTokenAmount = signedOrder.takerTokenAmount;
|
const totalTakerTokenAmount = signedOrder.takerTokenAmount;
|
||||||
const remainingTakerTokenAmount = totalTakerTokenAmount.minus(unavailableTakerTokenAmount);
|
const remainingTakerTokenAmount = totalTakerTokenAmount.minus(unavailableTakerTokenAmount);
|
||||||
const remainingMakerTokenAmount = remainingTakerTokenAmount.times(totalMakerTokenAmount)
|
const remainingMakerTokenAmount = remainingTakerTokenAmount
|
||||||
.dividedToIntegerBy(totalTakerTokenAmount);
|
.times(totalMakerTokenAmount)
|
||||||
|
.dividedToIntegerBy(totalTakerTokenAmount);
|
||||||
const transferrableMakerTokenAmount = BigNumber.min([makerProxyAllowance, makerBalance]);
|
const transferrableMakerTokenAmount = BigNumber.min([makerProxyAllowance, makerBalance]);
|
||||||
const transferrableFeeTokenAmount = BigNumber.min([makerFeeProxyAllowance, makerFeeBalance]);
|
const transferrableFeeTokenAmount = BigNumber.min([makerFeeProxyAllowance, makerFeeBalance]);
|
||||||
|
|
||||||
const isMakerTokenZRX = signedOrder.makerTokenAddress === zrxTokenAddress;
|
const isMakerTokenZRX = signedOrder.makerTokenAddress === zrxTokenAddress;
|
||||||
const remainingFillableCalculator = new RemainingFillableCalculator(signedOrder,
|
const remainingFillableCalculator = new RemainingFillableCalculator(
|
||||||
isMakerTokenZRX,
|
signedOrder,
|
||||||
transferrableMakerTokenAmount,
|
isMakerTokenZRX,
|
||||||
transferrableFeeTokenAmount,
|
transferrableMakerTokenAmount,
|
||||||
remainingMakerTokenAmount);
|
transferrableFeeTokenAmount,
|
||||||
|
remainingMakerTokenAmount,
|
||||||
|
);
|
||||||
const remainingFillableMakerTokenAmount = remainingFillableCalculator.computeRemainingMakerFillable();
|
const remainingFillableMakerTokenAmount = remainingFillableCalculator.computeRemainingMakerFillable();
|
||||||
const remainingFillableTakerTokenAmount = remainingFillableCalculator.computeRemainingTakerFillable();
|
const remainingFillableTakerTokenAmount = remainingFillableCalculator.computeRemainingTakerFillable();
|
||||||
const orderRelevantState = {
|
const orderRelevantState = {
|
||||||
|
|||||||
@@ -1,18 +1,20 @@
|
|||||||
import BigNumber from 'bignumber.js';
|
import { BigNumber } from '@0xproject/utils';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import {ZeroEx} from '../0x';
|
import { ZeroEx } from '../0x';
|
||||||
import {ExchangeWrapper} from '../contract_wrappers/exchange_wrapper';
|
import { ExchangeWrapper } from '../contract_wrappers/exchange_wrapper';
|
||||||
import {ExchangeContractErrs, Order, SignedOrder, TradeSide, TransferType, ZeroExError} from '../types';
|
import { ExchangeContractErrs, Order, SignedOrder, TradeSide, TransferType, ZeroExError } from '../types';
|
||||||
import {constants} from '../utils/constants';
|
import { constants } from '../utils/constants';
|
||||||
import {utils} from '../utils/utils';
|
import { utils } from '../utils/utils';
|
||||||
|
|
||||||
import {ExchangeTransferSimulator} from './exchange_transfer_simulator';
|
import { ExchangeTransferSimulator } from './exchange_transfer_simulator';
|
||||||
|
|
||||||
export class OrderValidationUtils {
|
export class OrderValidationUtils {
|
||||||
private _exchangeWrapper: ExchangeWrapper;
|
private _exchangeWrapper: ExchangeWrapper;
|
||||||
public static validateCancelOrderThrowIfInvalid(
|
public static validateCancelOrderThrowIfInvalid(
|
||||||
order: Order, cancelTakerTokenAmount: BigNumber, unavailableTakerTokenAmount: BigNumber,
|
order: Order,
|
||||||
|
cancelTakerTokenAmount: BigNumber,
|
||||||
|
unavailableTakerTokenAmount: BigNumber,
|
||||||
): void {
|
): void {
|
||||||
if (cancelTakerTokenAmount.eq(0)) {
|
if (cancelTakerTokenAmount.eq(0)) {
|
||||||
throw new Error(ExchangeContractErrs.OrderCancelAmountZero);
|
throw new Error(ExchangeContractErrs.OrderCancelAmountZero);
|
||||||
@@ -26,8 +28,11 @@ export class OrderValidationUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
public static async validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
|
public static async validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
|
||||||
exchangeTradeEmulator: ExchangeTransferSimulator, signedOrder: SignedOrder,
|
exchangeTradeEmulator: ExchangeTransferSimulator,
|
||||||
fillTakerTokenAmount: BigNumber, senderAddress: string, zrxTokenAddress: string,
|
signedOrder: SignedOrder,
|
||||||
|
fillTakerTokenAmount: BigNumber,
|
||||||
|
senderAddress: string,
|
||||||
|
zrxTokenAddress: string,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const fillMakerTokenAmount = OrderValidationUtils._getPartialAmount(
|
const fillMakerTokenAmount = OrderValidationUtils._getPartialAmount(
|
||||||
fillTakerTokenAmount,
|
fillTakerTokenAmount,
|
||||||
@@ -35,12 +40,20 @@ export class OrderValidationUtils {
|
|||||||
signedOrder.makerTokenAmount,
|
signedOrder.makerTokenAmount,
|
||||||
);
|
);
|
||||||
await exchangeTradeEmulator.transferFromAsync(
|
await exchangeTradeEmulator.transferFromAsync(
|
||||||
signedOrder.makerTokenAddress, signedOrder.maker, senderAddress, fillMakerTokenAmount,
|
signedOrder.makerTokenAddress,
|
||||||
TradeSide.Maker, TransferType.Trade,
|
signedOrder.maker,
|
||||||
|
senderAddress,
|
||||||
|
fillMakerTokenAmount,
|
||||||
|
TradeSide.Maker,
|
||||||
|
TransferType.Trade,
|
||||||
);
|
);
|
||||||
await exchangeTradeEmulator.transferFromAsync(
|
await exchangeTradeEmulator.transferFromAsync(
|
||||||
signedOrder.takerTokenAddress, senderAddress, signedOrder.maker, fillTakerTokenAmount,
|
signedOrder.takerTokenAddress,
|
||||||
TradeSide.Taker, TransferType.Trade,
|
senderAddress,
|
||||||
|
signedOrder.maker,
|
||||||
|
fillTakerTokenAmount,
|
||||||
|
TradeSide.Taker,
|
||||||
|
TransferType.Trade,
|
||||||
);
|
);
|
||||||
const makerFeeAmount = OrderValidationUtils._getPartialAmount(
|
const makerFeeAmount = OrderValidationUtils._getPartialAmount(
|
||||||
fillTakerTokenAmount,
|
fillTakerTokenAmount,
|
||||||
@@ -48,7 +61,11 @@ export class OrderValidationUtils {
|
|||||||
signedOrder.makerFee,
|
signedOrder.makerFee,
|
||||||
);
|
);
|
||||||
await exchangeTradeEmulator.transferFromAsync(
|
await exchangeTradeEmulator.transferFromAsync(
|
||||||
zrxTokenAddress, signedOrder.maker, signedOrder.feeRecipient, makerFeeAmount, TradeSide.Maker,
|
zrxTokenAddress,
|
||||||
|
signedOrder.maker,
|
||||||
|
signedOrder.feeRecipient,
|
||||||
|
makerFeeAmount,
|
||||||
|
TradeSide.Maker,
|
||||||
TransferType.Fee,
|
TransferType.Fee,
|
||||||
);
|
);
|
||||||
const takerFeeAmount = OrderValidationUtils._getPartialAmount(
|
const takerFeeAmount = OrderValidationUtils._getPartialAmount(
|
||||||
@@ -57,12 +74,17 @@ export class OrderValidationUtils {
|
|||||||
signedOrder.takerFee,
|
signedOrder.takerFee,
|
||||||
);
|
);
|
||||||
await exchangeTradeEmulator.transferFromAsync(
|
await exchangeTradeEmulator.transferFromAsync(
|
||||||
zrxTokenAddress, senderAddress, signedOrder.feeRecipient, takerFeeAmount, TradeSide.Taker,
|
zrxTokenAddress,
|
||||||
|
senderAddress,
|
||||||
|
signedOrder.feeRecipient,
|
||||||
|
takerFeeAmount,
|
||||||
|
TradeSide.Taker,
|
||||||
TransferType.Fee,
|
TransferType.Fee,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private static _validateRemainingFillAmountNotZeroOrThrow(
|
private static _validateRemainingFillAmountNotZeroOrThrow(
|
||||||
takerTokenAmount: BigNumber, unavailableTakerTokenAmount: BigNumber,
|
takerTokenAmount: BigNumber,
|
||||||
|
unavailableTakerTokenAmount: BigNumber,
|
||||||
) {
|
) {
|
||||||
if (takerTokenAmount.eq(unavailableTakerTokenAmount)) {
|
if (takerTokenAmount.eq(unavailableTakerTokenAmount)) {
|
||||||
throw new Error(ExchangeContractErrs.OrderRemainingFillAmountZero);
|
throw new Error(ExchangeContractErrs.OrderRemainingFillAmountZero);
|
||||||
@@ -74,24 +96,27 @@ export class OrderValidationUtils {
|
|||||||
throw new Error(ExchangeContractErrs.OrderFillExpired);
|
throw new Error(ExchangeContractErrs.OrderFillExpired);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private static _getPartialAmount(numerator: BigNumber, denominator: BigNumber,
|
private static _getPartialAmount(numerator: BigNumber, denominator: BigNumber, target: BigNumber): BigNumber {
|
||||||
target: BigNumber): BigNumber {
|
|
||||||
const fillMakerTokenAmount = numerator
|
const fillMakerTokenAmount = numerator
|
||||||
.mul(target)
|
.mul(target)
|
||||||
.div(denominator)
|
.div(denominator)
|
||||||
.round(0);
|
.round(0);
|
||||||
return fillMakerTokenAmount;
|
return fillMakerTokenAmount;
|
||||||
}
|
}
|
||||||
constructor(exchangeWrapper: ExchangeWrapper) {
|
constructor(exchangeWrapper: ExchangeWrapper) {
|
||||||
this._exchangeWrapper = exchangeWrapper;
|
this._exchangeWrapper = exchangeWrapper;
|
||||||
}
|
}
|
||||||
public async validateOrderFillableOrThrowAsync(
|
public async validateOrderFillableOrThrowAsync(
|
||||||
exchangeTradeEmulator: ExchangeTransferSimulator, signedOrder: SignedOrder, zrxTokenAddress: string,
|
exchangeTradeEmulator: ExchangeTransferSimulator,
|
||||||
expectedFillTakerTokenAmount?: BigNumber): Promise<void> {
|
signedOrder: SignedOrder,
|
||||||
|
zrxTokenAddress: string,
|
||||||
|
expectedFillTakerTokenAmount?: BigNumber,
|
||||||
|
): Promise<void> {
|
||||||
const orderHash = utils.getOrderHashHex(signedOrder);
|
const orderHash = utils.getOrderHashHex(signedOrder);
|
||||||
const unavailableTakerTokenAmount = await this._exchangeWrapper.getUnavailableTakerAmountAsync(orderHash);
|
const unavailableTakerTokenAmount = await this._exchangeWrapper.getUnavailableTakerAmountAsync(orderHash);
|
||||||
OrderValidationUtils._validateRemainingFillAmountNotZeroOrThrow(
|
OrderValidationUtils._validateRemainingFillAmountNotZeroOrThrow(
|
||||||
signedOrder.takerTokenAmount, unavailableTakerTokenAmount,
|
signedOrder.takerTokenAmount,
|
||||||
|
unavailableTakerTokenAmount,
|
||||||
);
|
);
|
||||||
OrderValidationUtils._validateOrderNotExpiredOrThrow(signedOrder.expirationUnixTimestampSec);
|
OrderValidationUtils._validateOrderNotExpiredOrThrow(signedOrder.expirationUnixTimestampSec);
|
||||||
let fillTakerTokenAmount = signedOrder.takerTokenAmount.minus(unavailableTakerTokenAmount);
|
let fillTakerTokenAmount = signedOrder.takerTokenAmount.minus(unavailableTakerTokenAmount);
|
||||||
@@ -104,8 +129,12 @@ export class OrderValidationUtils {
|
|||||||
signedOrder.makerTokenAmount,
|
signedOrder.makerTokenAmount,
|
||||||
);
|
);
|
||||||
await exchangeTradeEmulator.transferFromAsync(
|
await exchangeTradeEmulator.transferFromAsync(
|
||||||
signedOrder.makerTokenAddress, signedOrder.maker, signedOrder.taker, fillMakerTokenAmount,
|
signedOrder.makerTokenAddress,
|
||||||
TradeSide.Maker, TransferType.Trade,
|
signedOrder.maker,
|
||||||
|
signedOrder.taker,
|
||||||
|
fillMakerTokenAmount,
|
||||||
|
TradeSide.Maker,
|
||||||
|
TransferType.Trade,
|
||||||
);
|
);
|
||||||
const makerFeeAmount = OrderValidationUtils._getPartialAmount(
|
const makerFeeAmount = OrderValidationUtils._getPartialAmount(
|
||||||
fillTakerTokenAmount,
|
fillTakerTokenAmount,
|
||||||
@@ -113,14 +142,21 @@ export class OrderValidationUtils {
|
|||||||
signedOrder.makerFee,
|
signedOrder.makerFee,
|
||||||
);
|
);
|
||||||
await exchangeTradeEmulator.transferFromAsync(
|
await exchangeTradeEmulator.transferFromAsync(
|
||||||
zrxTokenAddress, signedOrder.maker, signedOrder.feeRecipient, makerFeeAmount,
|
zrxTokenAddress,
|
||||||
TradeSide.Maker, TransferType.Fee,
|
signedOrder.maker,
|
||||||
|
signedOrder.feeRecipient,
|
||||||
|
makerFeeAmount,
|
||||||
|
TradeSide.Maker,
|
||||||
|
TransferType.Fee,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
public async validateFillOrderThrowIfInvalidAsync(
|
public async validateFillOrderThrowIfInvalidAsync(
|
||||||
exchangeTradeEmulator: ExchangeTransferSimulator, signedOrder: SignedOrder,
|
exchangeTradeEmulator: ExchangeTransferSimulator,
|
||||||
fillTakerTokenAmount: BigNumber, takerAddress: string,
|
signedOrder: SignedOrder,
|
||||||
zrxTokenAddress: string): Promise<BigNumber> {
|
fillTakerTokenAmount: BigNumber,
|
||||||
|
takerAddress: string,
|
||||||
|
zrxTokenAddress: string,
|
||||||
|
): Promise<BigNumber> {
|
||||||
if (fillTakerTokenAmount.eq(0)) {
|
if (fillTakerTokenAmount.eq(0)) {
|
||||||
throw new Error(ExchangeContractErrs.OrderFillAmountZero);
|
throw new Error(ExchangeContractErrs.OrderFillAmountZero);
|
||||||
}
|
}
|
||||||
@@ -130,22 +166,29 @@ export class OrderValidationUtils {
|
|||||||
}
|
}
|
||||||
const unavailableTakerTokenAmount = await this._exchangeWrapper.getUnavailableTakerAmountAsync(orderHash);
|
const unavailableTakerTokenAmount = await this._exchangeWrapper.getUnavailableTakerAmountAsync(orderHash);
|
||||||
OrderValidationUtils._validateRemainingFillAmountNotZeroOrThrow(
|
OrderValidationUtils._validateRemainingFillAmountNotZeroOrThrow(
|
||||||
signedOrder.takerTokenAmount, unavailableTakerTokenAmount,
|
signedOrder.takerTokenAmount,
|
||||||
|
unavailableTakerTokenAmount,
|
||||||
);
|
);
|
||||||
if (signedOrder.taker !== constants.NULL_ADDRESS && signedOrder.taker !== takerAddress) {
|
if (signedOrder.taker !== constants.NULL_ADDRESS && signedOrder.taker !== takerAddress) {
|
||||||
throw new Error(ExchangeContractErrs.TransactionSenderIsNotFillOrderTaker);
|
throw new Error(ExchangeContractErrs.TransactionSenderIsNotFillOrderTaker);
|
||||||
}
|
}
|
||||||
OrderValidationUtils._validateOrderNotExpiredOrThrow(signedOrder.expirationUnixTimestampSec);
|
OrderValidationUtils._validateOrderNotExpiredOrThrow(signedOrder.expirationUnixTimestampSec);
|
||||||
const remainingTakerTokenAmount = signedOrder.takerTokenAmount.minus(unavailableTakerTokenAmount);
|
const remainingTakerTokenAmount = signedOrder.takerTokenAmount.minus(unavailableTakerTokenAmount);
|
||||||
const filledTakerTokenAmount = remainingTakerTokenAmount.lessThan(fillTakerTokenAmount) ?
|
const filledTakerTokenAmount = remainingTakerTokenAmount.lessThan(fillTakerTokenAmount)
|
||||||
remainingTakerTokenAmount :
|
? remainingTakerTokenAmount
|
||||||
fillTakerTokenAmount;
|
: fillTakerTokenAmount;
|
||||||
await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
|
await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
|
||||||
exchangeTradeEmulator, signedOrder, filledTakerTokenAmount, takerAddress, zrxTokenAddress,
|
exchangeTradeEmulator,
|
||||||
|
signedOrder,
|
||||||
|
filledTakerTokenAmount,
|
||||||
|
takerAddress,
|
||||||
|
zrxTokenAddress,
|
||||||
);
|
);
|
||||||
|
|
||||||
const wouldRoundingErrorOccur = await this._exchangeWrapper.isRoundingErrorAsync(
|
const wouldRoundingErrorOccur = await this._exchangeWrapper.isRoundingErrorAsync(
|
||||||
filledTakerTokenAmount, signedOrder.takerTokenAmount, signedOrder.makerTokenAmount,
|
filledTakerTokenAmount,
|
||||||
|
signedOrder.takerTokenAmount,
|
||||||
|
signedOrder.makerTokenAmount,
|
||||||
);
|
);
|
||||||
if (wouldRoundingErrorOccur) {
|
if (wouldRoundingErrorOccur) {
|
||||||
throw new Error(ExchangeContractErrs.OrderFillRoundingError);
|
throw new Error(ExchangeContractErrs.OrderFillRoundingError);
|
||||||
@@ -153,10 +196,18 @@ export class OrderValidationUtils {
|
|||||||
return filledTakerTokenAmount;
|
return filledTakerTokenAmount;
|
||||||
}
|
}
|
||||||
public async validateFillOrKillOrderThrowIfInvalidAsync(
|
public async validateFillOrKillOrderThrowIfInvalidAsync(
|
||||||
exchangeTradeEmulator: ExchangeTransferSimulator, signedOrder: SignedOrder,
|
exchangeTradeEmulator: ExchangeTransferSimulator,
|
||||||
fillTakerTokenAmount: BigNumber, takerAddress: string, zrxTokenAddress: string): Promise<void> {
|
signedOrder: SignedOrder,
|
||||||
|
fillTakerTokenAmount: BigNumber,
|
||||||
|
takerAddress: string,
|
||||||
|
zrxTokenAddress: string,
|
||||||
|
): Promise<void> {
|
||||||
const filledTakerTokenAmount = await this.validateFillOrderThrowIfInvalidAsync(
|
const filledTakerTokenAmount = await this.validateFillOrderThrowIfInvalidAsync(
|
||||||
exchangeTradeEmulator, signedOrder, fillTakerTokenAmount, takerAddress, zrxTokenAddress,
|
exchangeTradeEmulator,
|
||||||
|
signedOrder,
|
||||||
|
fillTakerTokenAmount,
|
||||||
|
takerAddress,
|
||||||
|
zrxTokenAddress,
|
||||||
);
|
);
|
||||||
if (filledTakerTokenAmount !== fillTakerTokenAmount) {
|
if (filledTakerTokenAmount !== fillTakerTokenAmount) {
|
||||||
throw new Error(ExchangeContractErrs.InsufficientRemainingFillAmount);
|
throw new Error(ExchangeContractErrs.InsufficientRemainingFillAmount);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import * as ethUtil from 'ethereumjs-util';
|
import * as ethUtil from 'ethereumjs-util';
|
||||||
|
|
||||||
import {ECSignature} from '../types';
|
import { ECSignature } from '../types';
|
||||||
|
|
||||||
export const signatureUtils = {
|
export const signatureUtils = {
|
||||||
isValidSignature(data: string, signature: ECSignature, signerAddress: string): boolean {
|
isValidSignature(data: string, signature: ECSignature, signerAddress: string): boolean {
|
||||||
@@ -11,7 +11,8 @@ export const signatureUtils = {
|
|||||||
msgHashBuff,
|
msgHashBuff,
|
||||||
signature.v,
|
signature.v,
|
||||||
ethUtil.toBuffer(signature.r),
|
ethUtil.toBuffer(signature.r),
|
||||||
ethUtil.toBuffer(signature.s));
|
ethUtil.toBuffer(signature.s),
|
||||||
|
);
|
||||||
const retrievedAddress = ethUtil.bufferToHex(ethUtil.pubToAddress(pubKey));
|
const retrievedAddress = ethUtil.bufferToHex(ethUtil.pubToAddress(pubKey));
|
||||||
return retrievedAddress === signerAddress;
|
return retrievedAddress === signerAddress;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -34,7 +35,7 @@ export const signatureUtils = {
|
|||||||
return ecSignature;
|
return ecSignature;
|
||||||
},
|
},
|
||||||
parseSignatureHexAsRSV(signatureHex: string): ECSignature {
|
parseSignatureHexAsRSV(signatureHex: string): ECSignature {
|
||||||
const {v, r, s} = ethUtil.fromRpcSig(signatureHex);
|
const { v, r, s } = ethUtil.fromRpcSig(signatureHex);
|
||||||
const ecSignature: ECSignature = {
|
const ecSignature: ECSignature = {
|
||||||
v,
|
v,
|
||||||
r: ethUtil.bufferToHex(r),
|
r: ethUtil.bufferToHex(r),
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import BigNumber from 'bignumber.js';
|
import { SolidityTypes } from '@0xproject/types';
|
||||||
|
import { BigNumber } from '@0xproject/utils';
|
||||||
import BN = require('bn.js');
|
import BN = require('bn.js');
|
||||||
import * as ethABI from 'ethereumjs-abi';
|
import * as ethABI from 'ethereumjs-abi';
|
||||||
import * as ethUtil from 'ethereumjs-util';
|
import * as ethUtil from 'ethereumjs-util';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import {Order, SignedOrder, SolidityTypes} from '../types';
|
import { Order, SignedOrder } from '../types';
|
||||||
|
|
||||||
export const utils = {
|
export const utils = {
|
||||||
/**
|
/**
|
||||||
@@ -20,29 +21,38 @@ export const utils = {
|
|||||||
// tslint:disable-next-line: no-console
|
// tslint:disable-next-line: no-console
|
||||||
console.log(message);
|
console.log(message);
|
||||||
},
|
},
|
||||||
isParityNode(nodeVersion: string): boolean {
|
|
||||||
return _.includes(nodeVersion, 'Parity');
|
|
||||||
},
|
|
||||||
isTestRpc(nodeVersion: string): boolean {
|
|
||||||
return _.includes(nodeVersion, 'TestRPC');
|
|
||||||
},
|
|
||||||
spawnSwitchErr(name: string, value: any): Error {
|
spawnSwitchErr(name: string, value: any): Error {
|
||||||
return new Error(`Unexpected switch value: ${value} encountered for ${name}`);
|
return new Error(`Unexpected switch value: ${value} encountered for ${name}`);
|
||||||
},
|
},
|
||||||
getOrderHashHex(order: Order|SignedOrder): string {
|
getOrderHashHex(order: Order | SignedOrder): string {
|
||||||
const orderParts = [
|
const orderParts = [
|
||||||
{value: order.exchangeContractAddress, type: SolidityTypes.Address},
|
{ value: order.exchangeContractAddress, type: SolidityTypes.Address },
|
||||||
{value: order.maker, type: SolidityTypes.Address},
|
{ value: order.maker, type: SolidityTypes.Address },
|
||||||
{value: order.taker, type: SolidityTypes.Address},
|
{ value: order.taker, type: SolidityTypes.Address },
|
||||||
{value: order.makerTokenAddress, type: SolidityTypes.Address},
|
{ value: order.makerTokenAddress, type: SolidityTypes.Address },
|
||||||
{value: order.takerTokenAddress, type: SolidityTypes.Address},
|
{ value: order.takerTokenAddress, type: SolidityTypes.Address },
|
||||||
{value: order.feeRecipient, type: SolidityTypes.Address},
|
{ value: order.feeRecipient, type: SolidityTypes.Address },
|
||||||
{value: utils.bigNumberToBN(order.makerTokenAmount), type: SolidityTypes.Uint256},
|
{
|
||||||
{value: utils.bigNumberToBN(order.takerTokenAmount), type: SolidityTypes.Uint256},
|
value: utils.bigNumberToBN(order.makerTokenAmount),
|
||||||
{value: utils.bigNumberToBN(order.makerFee), type: SolidityTypes.Uint256},
|
type: SolidityTypes.Uint256,
|
||||||
{value: utils.bigNumberToBN(order.takerFee), type: SolidityTypes.Uint256},
|
},
|
||||||
{value: utils.bigNumberToBN(order.expirationUnixTimestampSec), type: SolidityTypes.Uint256},
|
{
|
||||||
{value: utils.bigNumberToBN(order.salt), type: SolidityTypes.Uint256},
|
value: utils.bigNumberToBN(order.takerTokenAmount),
|
||||||
|
type: SolidityTypes.Uint256,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: utils.bigNumberToBN(order.makerFee),
|
||||||
|
type: SolidityTypes.Uint256,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: utils.bigNumberToBN(order.takerFee),
|
||||||
|
type: SolidityTypes.Uint256,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: utils.bigNumberToBN(order.expirationUnixTimestampSec),
|
||||||
|
type: SolidityTypes.Uint256,
|
||||||
|
},
|
||||||
|
{ value: utils.bigNumberToBN(order.salt), type: SolidityTypes.Uint256 },
|
||||||
];
|
];
|
||||||
const types = _.map(orderParts, o => o.type);
|
const types = _.map(orderParts, o => o.type);
|
||||||
const values = _.map(orderParts, o => o.value);
|
const values = _.map(orderParts, o => o.value);
|
||||||
|
|||||||
@@ -1,21 +1,22 @@
|
|||||||
import {BlockchainLifecycle} from '@0xproject/dev-utils';
|
import { BlockchainLifecycle, devConstants, web3Factory } from '@0xproject/dev-utils';
|
||||||
import BigNumber from 'bignumber.js';
|
import { BigNumber } from '@0xproject/utils';
|
||||||
import * as chai from 'chai';
|
import * as chai from 'chai';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import 'mocha';
|
import 'mocha';
|
||||||
import * as Sinon from 'sinon';
|
import * as Sinon from 'sinon';
|
||||||
|
|
||||||
import {ApprovalContractEventArgs, LogWithDecodedArgs, Order, TokenEvents, ZeroEx} from '../src';
|
import { ApprovalContractEventArgs, LogWithDecodedArgs, Order, TokenEvents, ZeroEx } from '../src';
|
||||||
|
|
||||||
import {chaiSetup} from './utils/chai_setup';
|
import { chaiSetup } from './utils/chai_setup';
|
||||||
import {constants} from './utils/constants';
|
import { constants } from './utils/constants';
|
||||||
import {TokenUtils} from './utils/token_utils';
|
import { TokenUtils } from './utils/token_utils';
|
||||||
import {web3Factory} from './utils/web3_factory';
|
|
||||||
|
|
||||||
const blockchainLifecycle = new BlockchainLifecycle(constants.RPC_URL);
|
const blockchainLifecycle = new BlockchainLifecycle();
|
||||||
chaiSetup.configure();
|
chaiSetup.configure();
|
||||||
const expect = chai.expect;
|
const expect = chai.expect;
|
||||||
|
|
||||||
|
const SHOULD_ADD_PERSONAL_MESSAGE_PREFIX = false;
|
||||||
|
|
||||||
describe('ZeroEx library', () => {
|
describe('ZeroEx library', () => {
|
||||||
const web3 = web3Factory.create();
|
const web3 = web3Factory.create();
|
||||||
const config = {
|
const config = {
|
||||||
@@ -41,11 +42,11 @@ describe('ZeroEx library', () => {
|
|||||||
|
|
||||||
// Check that all nested web3 wrapper instances return the updated provider
|
// Check that all nested web3 wrapper instances return the updated provider
|
||||||
const nestedWeb3WrapperProvider = (zeroEx as any)._web3Wrapper.getCurrentProvider();
|
const nestedWeb3WrapperProvider = (zeroEx as any)._web3Wrapper.getCurrentProvider();
|
||||||
expect((nestedWeb3WrapperProvider).zeroExTestId).to.be.a('number');
|
expect(nestedWeb3WrapperProvider.zeroExTestId).to.be.a('number');
|
||||||
const exchangeWeb3WrapperProvider = (zeroEx.exchange as any)._web3Wrapper.getCurrentProvider();
|
const exchangeWeb3WrapperProvider = (zeroEx.exchange as any)._web3Wrapper.getCurrentProvider();
|
||||||
expect((exchangeWeb3WrapperProvider).zeroExTestId).to.be.a('number');
|
expect(exchangeWeb3WrapperProvider.zeroExTestId).to.be.a('number');
|
||||||
const tokenRegistryWeb3WrapperProvider = (zeroEx.tokenRegistry as any)._web3Wrapper.getCurrentProvider();
|
const tokenRegistryWeb3WrapperProvider = (zeroEx.tokenRegistry as any)._web3Wrapper.getCurrentProvider();
|
||||||
expect((tokenRegistryWeb3WrapperProvider).zeroExTestId).to.be.a('number');
|
expect(tokenRegistryWeb3WrapperProvider.zeroExTestId).to.be.a('number');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('#isValidSignature', () => {
|
describe('#isValidSignature', () => {
|
||||||
@@ -58,22 +59,25 @@ describe('ZeroEx library', () => {
|
|||||||
s: '0x40349190569279751135161d22529dc25add4f6069af05be04cacbda2ace2254',
|
s: '0x40349190569279751135161d22529dc25add4f6069af05be04cacbda2ace2254',
|
||||||
};
|
};
|
||||||
const address = '0x5409ed021d9299bf6814279a6a1411a7e866a631';
|
const address = '0x5409ed021d9299bf6814279a6a1411a7e866a631';
|
||||||
it('should return false if the data doesn\'t pertain to the signature & address', async () => {
|
it("should return false if the data doesn't pertain to the signature & address", async () => {
|
||||||
expect(ZeroEx.isValidSignature('0x0', signature, address)).to.be.false();
|
expect(ZeroEx.isValidSignature('0x0', signature, address)).to.be.false();
|
||||||
return expect(
|
return expect(
|
||||||
(zeroEx.exchange as any)._isValidSignatureUsingContractCallAsync('0x0', signature, address),
|
(zeroEx.exchange as any)._isValidSignatureUsingContractCallAsync('0x0', signature, address),
|
||||||
).to.become(false);
|
).to.become(false);
|
||||||
});
|
});
|
||||||
it('should return false if the address doesn\'t pertain to the signature & data', async () => {
|
it("should return false if the address doesn't pertain to the signature & data", async () => {
|
||||||
const validUnrelatedAddress = '0x8b0292b11a196601ed2ce54b665cafeca0347d42';
|
const validUnrelatedAddress = '0x8b0292b11a196601ed2ce54b665cafeca0347d42';
|
||||||
expect(ZeroEx.isValidSignature(dataHex, signature, validUnrelatedAddress)).to.be.false();
|
expect(ZeroEx.isValidSignature(dataHex, signature, validUnrelatedAddress)).to.be.false();
|
||||||
return expect(
|
return expect(
|
||||||
(zeroEx.exchange as any)._isValidSignatureUsingContractCallAsync(dataHex, signature,
|
(zeroEx.exchange as any)._isValidSignatureUsingContractCallAsync(
|
||||||
validUnrelatedAddress),
|
dataHex,
|
||||||
|
signature,
|
||||||
|
validUnrelatedAddress,
|
||||||
|
),
|
||||||
).to.become(false);
|
).to.become(false);
|
||||||
});
|
});
|
||||||
it('should return false if the signature doesn\'t pertain to the dataHex & address', async () => {
|
it("should return false if the signature doesn't pertain to the dataHex & address", async () => {
|
||||||
const wrongSignature = _.assign({}, signature, {v: 28});
|
const wrongSignature = _.assign({}, signature, { v: 28 });
|
||||||
expect(ZeroEx.isValidSignature(dataHex, wrongSignature, address)).to.be.false();
|
expect(ZeroEx.isValidSignature(dataHex, wrongSignature, address)).to.be.false();
|
||||||
return expect(
|
return expect(
|
||||||
(zeroEx.exchange as any)._isValidSignatureUsingContractCallAsync(dataHex, wrongSignature, address),
|
(zeroEx.exchange as any)._isValidSignatureUsingContractCallAsync(dataHex, wrongSignature, address),
|
||||||
@@ -117,8 +121,9 @@ describe('ZeroEx library', () => {
|
|||||||
it('should throw if invalid baseUnit amount supplied as argument', () => {
|
it('should throw if invalid baseUnit amount supplied as argument', () => {
|
||||||
const invalidBaseUnitAmount = new BigNumber(1000000000.4);
|
const invalidBaseUnitAmount = new BigNumber(1000000000.4);
|
||||||
const decimals = 6;
|
const decimals = 6;
|
||||||
expect(() => ZeroEx.toUnitAmount(invalidBaseUnitAmount, decimals))
|
expect(() => ZeroEx.toUnitAmount(invalidBaseUnitAmount, decimals)).to.throw(
|
||||||
.to.throw('amount should be in baseUnits (no decimals), found value: 1000000000.4');
|
'amount should be in baseUnits (no decimals), found value: 1000000000.4',
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('Should return the expected unit amount for the decimals passed in', () => {
|
it('Should return the expected unit amount for the decimals passed in', () => {
|
||||||
const baseUnitAmount = new BigNumber(1000000000);
|
const baseUnitAmount = new BigNumber(1000000000);
|
||||||
@@ -139,8 +144,9 @@ describe('ZeroEx library', () => {
|
|||||||
it('should throw if unitAmount has more decimals then specified as the max decimal precision', () => {
|
it('should throw if unitAmount has more decimals then specified as the max decimal precision', () => {
|
||||||
const unitAmount = new BigNumber(0.823091);
|
const unitAmount = new BigNumber(0.823091);
|
||||||
const decimals = 5;
|
const decimals = 5;
|
||||||
expect(() => ZeroEx.toBaseUnitAmount(unitAmount, decimals))
|
expect(() => ZeroEx.toBaseUnitAmount(unitAmount, decimals)).to.throw(
|
||||||
.to.throw('Invalid unit amount: 0.823091 - Too many decimal places');
|
'Invalid unit amount: 0.823091 - Too many decimal places',
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('#getOrderHashHex', () => {
|
describe('#getOrderHashHex', () => {
|
||||||
@@ -167,10 +173,10 @@ describe('ZeroEx library', () => {
|
|||||||
it('throws a readable error message if taker format is invalid', async () => {
|
it('throws a readable error message if taker format is invalid', async () => {
|
||||||
const orderWithInvalidtakerFormat = {
|
const orderWithInvalidtakerFormat = {
|
||||||
...order,
|
...order,
|
||||||
taker: null as any as string,
|
taker: (null as any) as string,
|
||||||
};
|
};
|
||||||
// tslint:disable-next-line:max-line-length
|
const expectedErrorMessage =
|
||||||
const expectedErrorMessage = 'Order taker must be of type string. If you want anyone to be able to fill an order - pass ZeroEx.NULL_ADDRESS';
|
'Order taker must be of type string. If you want anyone to be able to fill an order - pass ZeroEx.NULL_ADDRESS';
|
||||||
expect(() => ZeroEx.getOrderHashHex(orderWithInvalidtakerFormat)).to.throw(expectedErrorMessage);
|
expect(() => ZeroEx.getOrderHashHex(orderWithInvalidtakerFormat)).to.throw(expectedErrorMessage);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -193,43 +199,53 @@ describe('ZeroEx library', () => {
|
|||||||
r: '0x61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc33',
|
r: '0x61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc33',
|
||||||
s: '0x40349190569279751135161d22529dc25add4f6069af05be04cacbda2ace2254',
|
s: '0x40349190569279751135161d22529dc25add4f6069af05be04cacbda2ace2254',
|
||||||
};
|
};
|
||||||
const ecSignature = await zeroEx.signOrderHashAsync(orderHash, makerAddress);
|
const ecSignature = await zeroEx.signOrderHashAsync(
|
||||||
|
orderHash,
|
||||||
|
makerAddress,
|
||||||
|
SHOULD_ADD_PERSONAL_MESSAGE_PREFIX,
|
||||||
|
);
|
||||||
expect(ecSignature).to.deep.equal(expectedECSignature);
|
expect(ecSignature).to.deep.equal(expectedECSignature);
|
||||||
});
|
});
|
||||||
it('should return the correct ECSignature for signatureHex concatenated as R + S + V', async () => {
|
it('should return the correct ECSignature for signatureHex concatenated as R + S + V', async () => {
|
||||||
const orderHash = '0x34decbedc118904df65f379a175bb39ca18209d6ce41d5ed549d54e6e0a95004';
|
const orderHash = '0x34decbedc118904df65f379a175bb39ca18209d6ce41d5ed549d54e6e0a95004';
|
||||||
// tslint:disable-next-line: max-line-length
|
const signature =
|
||||||
const signature = '0x22109d11d79cb8bf96ed88625e1cd9558800c4073332a9a02857499883ee5ce3050aa3cc1f2c435e67e114cdce54b9527b4f50548342401bc5d2b77adbdacb021b';
|
'0x22109d11d79cb8bf96ed88625e1cd9558800c4073332a9a02857499883ee5ce3050aa3cc1f2c435e67e114cdce54b9527b4f50548342401bc5d2b77adbdacb021b';
|
||||||
const expectedECSignature = {
|
const expectedECSignature = {
|
||||||
v: 27,
|
v: 27,
|
||||||
r: '0x22109d11d79cb8bf96ed88625e1cd9558800c4073332a9a02857499883ee5ce3',
|
r: '0x22109d11d79cb8bf96ed88625e1cd9558800c4073332a9a02857499883ee5ce3',
|
||||||
s: '0x050aa3cc1f2c435e67e114cdce54b9527b4f50548342401bc5d2b77adbdacb02',
|
s: '0x050aa3cc1f2c435e67e114cdce54b9527b4f50548342401bc5d2b77adbdacb02',
|
||||||
};
|
};
|
||||||
stubs = [
|
stubs = [
|
||||||
Sinon.stub((zeroEx as any)._web3Wrapper, 'signTransactionAsync')
|
Sinon.stub((zeroEx as any)._web3Wrapper, 'signTransactionAsync').returns(Promise.resolve(signature)),
|
||||||
.returns(Promise.resolve(signature)),
|
|
||||||
Sinon.stub(ZeroEx, 'isValidSignature').returns(true),
|
Sinon.stub(ZeroEx, 'isValidSignature').returns(true),
|
||||||
];
|
];
|
||||||
|
|
||||||
const ecSignature = await zeroEx.signOrderHashAsync(orderHash, makerAddress);
|
const ecSignature = await zeroEx.signOrderHashAsync(
|
||||||
|
orderHash,
|
||||||
|
makerAddress,
|
||||||
|
SHOULD_ADD_PERSONAL_MESSAGE_PREFIX,
|
||||||
|
);
|
||||||
expect(ecSignature).to.deep.equal(expectedECSignature);
|
expect(ecSignature).to.deep.equal(expectedECSignature);
|
||||||
});
|
});
|
||||||
it('should return the correct ECSignature for signatureHex concatenated as V + R + S', async () => {
|
it('should return the correct ECSignature for signatureHex concatenated as V + R + S', async () => {
|
||||||
const orderHash = '0xc793e33ffded933b76f2f48d9aa3339fc090399d5e7f5dec8d3660f5480793f7';
|
const orderHash = '0xc793e33ffded933b76f2f48d9aa3339fc090399d5e7f5dec8d3660f5480793f7';
|
||||||
// tslint:disable-next-line: max-line-length
|
const signature =
|
||||||
const signature = '0x1bc80bedc6756722672753413efdd749b5adbd4fd552595f59c13427407ee9aee02dea66f25a608bbae457e020fb6decb763deb8b7192abab624997242da248960';
|
'0x1bc80bedc6756722672753413efdd749b5adbd4fd552595f59c13427407ee9aee02dea66f25a608bbae457e020fb6decb763deb8b7192abab624997242da248960';
|
||||||
const expectedECSignature = {
|
const expectedECSignature = {
|
||||||
v: 27,
|
v: 27,
|
||||||
r: '0xc80bedc6756722672753413efdd749b5adbd4fd552595f59c13427407ee9aee0',
|
r: '0xc80bedc6756722672753413efdd749b5adbd4fd552595f59c13427407ee9aee0',
|
||||||
s: '0x2dea66f25a608bbae457e020fb6decb763deb8b7192abab624997242da248960',
|
s: '0x2dea66f25a608bbae457e020fb6decb763deb8b7192abab624997242da248960',
|
||||||
};
|
};
|
||||||
stubs = [
|
stubs = [
|
||||||
Sinon.stub((zeroEx as any)._web3Wrapper, 'signTransactionAsync')
|
Sinon.stub((zeroEx as any)._web3Wrapper, 'signTransactionAsync').returns(Promise.resolve(signature)),
|
||||||
.returns(Promise.resolve(signature)),
|
|
||||||
Sinon.stub(ZeroEx, 'isValidSignature').returns(true),
|
Sinon.stub(ZeroEx, 'isValidSignature').returns(true),
|
||||||
];
|
];
|
||||||
|
|
||||||
const ecSignature = await zeroEx.signOrderHashAsync(orderHash, makerAddress);
|
const ecSignature = await zeroEx.signOrderHashAsync(
|
||||||
|
orderHash,
|
||||||
|
makerAddress,
|
||||||
|
SHOULD_ADD_PERSONAL_MESSAGE_PREFIX,
|
||||||
|
);
|
||||||
expect(ecSignature).to.deep.equal(expectedECSignature);
|
expect(ecSignature).to.deep.equal(expectedECSignature);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -271,8 +287,9 @@ describe('ZeroEx library', () => {
|
|||||||
networkId: constants.TESTRPC_NETWORK_ID,
|
networkId: constants.TESTRPC_NETWORK_ID,
|
||||||
};
|
};
|
||||||
const zeroExWithWrongTokenRegistryAddress = new ZeroEx(web3.currentProvider, zeroExConfig);
|
const zeroExWithWrongTokenRegistryAddress = new ZeroEx(web3.currentProvider, zeroExConfig);
|
||||||
expect(zeroExWithWrongTokenRegistryAddress.tokenRegistry.getContractAddress())
|
expect(zeroExWithWrongTokenRegistryAddress.tokenRegistry.getContractAddress()).to.be.equal(
|
||||||
.to.be.equal(ZeroEx.NULL_ADDRESS);
|
ZeroEx.NULL_ADDRESS,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import HDWalletProvider = require('truffle-hdwallet-provider');
|
import HDWalletProvider = require('truffle-hdwallet-provider');
|
||||||
|
|
||||||
import {ZeroEx} from '../src';
|
import { ZeroEx } from '../src';
|
||||||
|
|
||||||
import {chaiSetup} from './utils/chai_setup';
|
import { chaiSetup } from './utils/chai_setup';
|
||||||
import {constants} from './utils/constants';
|
import { constants } from './utils/constants';
|
||||||
|
|
||||||
chaiSetup.configure();
|
chaiSetup.configure();
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
|
import { web3Factory } from '@0xproject/dev-utils';
|
||||||
import * as chai from 'chai';
|
import * as chai from 'chai';
|
||||||
import 'mocha';
|
import 'mocha';
|
||||||
|
|
||||||
import {ZeroEx} from '../src';
|
import { ZeroEx } from '../src';
|
||||||
import {assert} from '../src/utils/assert';
|
import { assert } from '../src/utils/assert';
|
||||||
|
|
||||||
import {constants} from './utils/constants';
|
import { constants } from './utils/constants';
|
||||||
import {web3Factory} from './utils/web3_factory';
|
|
||||||
|
|
||||||
const expect = chai.expect;
|
const expect = chai.expect;
|
||||||
|
|
||||||
@@ -19,22 +19,25 @@ describe('Assertion library', () => {
|
|||||||
it('throws when address is invalid', async () => {
|
it('throws when address is invalid', async () => {
|
||||||
const address = '0xdeadbeef';
|
const address = '0xdeadbeef';
|
||||||
const varName = 'address';
|
const varName = 'address';
|
||||||
return expect(assert.isSenderAddressAsync(varName, address, (zeroEx as any)._web3Wrapper))
|
return expect(
|
||||||
.to.be.rejectedWith(`Expected ${varName} to be of type ETHAddressHex, encountered: ${address}`);
|
assert.isSenderAddressAsync(varName, address, (zeroEx as any)._web3Wrapper),
|
||||||
|
).to.be.rejectedWith(`Expected ${varName} to be of type ETHAddressHex, encountered: ${address}`);
|
||||||
});
|
});
|
||||||
it('throws when address is unavailable', async () => {
|
it('throws when address is unavailable', async () => {
|
||||||
const validUnrelatedAddress = '0x8b0292b11a196601eddce54b665cafeca0347d42';
|
const validUnrelatedAddress = '0x8b0292b11a196601eddce54b665cafeca0347d42';
|
||||||
const varName = 'address';
|
const varName = 'address';
|
||||||
return expect(assert.isSenderAddressAsync(varName, validUnrelatedAddress, (zeroEx as any)._web3Wrapper))
|
return expect(
|
||||||
.to.be.rejectedWith(
|
assert.isSenderAddressAsync(varName, validUnrelatedAddress, (zeroEx as any)._web3Wrapper),
|
||||||
`Specified ${varName} ${validUnrelatedAddress} isn't available through the supplied web3 provider`,
|
).to.be.rejectedWith(
|
||||||
);
|
`Specified ${varName} ${validUnrelatedAddress} isn't available through the supplied web3 provider`,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('doesn\'t throw if address is available', async () => {
|
it("doesn't throw if address is available", async () => {
|
||||||
const availableAddress = (await zeroEx.getAvailableAddressesAsync())[0];
|
const availableAddress = (await zeroEx.getAvailableAddressesAsync())[0];
|
||||||
const varName = 'address';
|
const varName = 'address';
|
||||||
return expect(assert.isSenderAddressAsync(varName, availableAddress, (zeroEx as any)._web3Wrapper))
|
return expect(
|
||||||
.to.become(undefined);
|
assert.isSenderAddressAsync(varName, availableAddress, (zeroEx as any)._web3Wrapper),
|
||||||
|
).to.become(undefined);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import {BlockchainLifecycle} from '@0xproject/dev-utils';
|
import { BlockchainLifecycle, devConstants, web3Factory } from '@0xproject/dev-utils';
|
||||||
import BigNumber from 'bignumber.js';
|
import { BigNumber } from '@0xproject/utils';
|
||||||
import * as chai from 'chai';
|
import * as chai from 'chai';
|
||||||
import 'mocha';
|
import 'mocha';
|
||||||
import * as Web3 from 'web3';
|
import * as Web3 from 'web3';
|
||||||
@@ -17,17 +17,16 @@ import {
|
|||||||
ZeroEx,
|
ZeroEx,
|
||||||
ZeroExError,
|
ZeroExError,
|
||||||
} from '../src';
|
} from '../src';
|
||||||
import {artifacts} from '../src/artifacts';
|
import { DoneCallback } from '../src/types';
|
||||||
import {DoneCallback} from '../src/types';
|
|
||||||
|
|
||||||
import {chaiSetup} from './utils/chai_setup';
|
import { chaiSetup } from './utils/chai_setup';
|
||||||
import {constants} from './utils/constants';
|
import { constants } from './utils/constants';
|
||||||
import {TokenUtils} from './utils/token_utils';
|
import { reportNodeCallbackErrors } from './utils/report_callback_errors';
|
||||||
import {web3Factory} from './utils/web3_factory';
|
import { TokenUtils } from './utils/token_utils';
|
||||||
|
|
||||||
chaiSetup.configure();
|
chaiSetup.configure();
|
||||||
const expect = chai.expect;
|
const expect = chai.expect;
|
||||||
const blockchainLifecycle = new BlockchainLifecycle(constants.RPC_URL);
|
const blockchainLifecycle = new BlockchainLifecycle();
|
||||||
|
|
||||||
// Since the address depositing/withdrawing ETH/WETH also needs to pay gas costs for the transaction,
|
// Since the address depositing/withdrawing ETH/WETH also needs to pay gas costs for the transaction,
|
||||||
// a small amount of ETH will be used to pay this gas cost. We therefore check that the difference between
|
// a small amount of ETH will be used to pay this gas cost. We therefore check that the difference between
|
||||||
@@ -60,7 +59,7 @@ describe('EtherTokenWrapper', () => {
|
|||||||
tokens = await zeroEx.tokenRegistry.getTokensAsync();
|
tokens = await zeroEx.tokenRegistry.getTokensAsync();
|
||||||
userAddresses = await zeroEx.getAvailableAddressesAsync();
|
userAddresses = await zeroEx.getAvailableAddressesAsync();
|
||||||
addressWithETH = userAddresses[0];
|
addressWithETH = userAddresses[0];
|
||||||
wethContractAddress = (zeroEx.etherToken as any)._getContractAddress(artifacts.EtherTokenArtifact);
|
wethContractAddress = zeroEx.etherToken.getContractAddressIfExists() as string;
|
||||||
depositWeiAmount = (zeroEx as any)._web3Wrapper.toWei(new BigNumber(5));
|
depositWeiAmount = (zeroEx as any)._web3Wrapper.toWei(new BigNumber(5));
|
||||||
decimalPlaces = 7;
|
decimalPlaces = 7;
|
||||||
addressWithoutFunds = userAddresses[1];
|
addressWithoutFunds = userAddresses[1];
|
||||||
@@ -71,6 +70,21 @@ describe('EtherTokenWrapper', () => {
|
|||||||
afterEach(async () => {
|
afterEach(async () => {
|
||||||
await blockchainLifecycle.revertAsync();
|
await blockchainLifecycle.revertAsync();
|
||||||
});
|
});
|
||||||
|
describe('#getContractAddressIfExists', async () => {
|
||||||
|
it('should return contract address if connected to a known network', () => {
|
||||||
|
const contractAddressIfExists = zeroEx.etherToken.getContractAddressIfExists();
|
||||||
|
expect(contractAddressIfExists).to.not.be.undefined();
|
||||||
|
});
|
||||||
|
it('should throw if connected to a private network and contract addresses are not specified', () => {
|
||||||
|
const UNKNOWN_NETWORK_NETWORK_ID = 10;
|
||||||
|
expect(
|
||||||
|
() =>
|
||||||
|
new ZeroEx(web3.currentProvider, {
|
||||||
|
networkId: UNKNOWN_NETWORK_NETWORK_ID,
|
||||||
|
} as any),
|
||||||
|
).to.throw();
|
||||||
|
});
|
||||||
|
});
|
||||||
describe('#depositAsync', () => {
|
describe('#depositAsync', () => {
|
||||||
it('should successfully deposit ETH and issue Wrapped ETH tokens', async () => {
|
it('should successfully deposit ETH and issue Wrapped ETH tokens', async () => {
|
||||||
const preETHBalance = await (zeroEx as any)._web3Wrapper.getBalanceInWeiAsync(addressWithETH);
|
const preETHBalance = await (zeroEx as any)._web3Wrapper.getBalanceInWeiAsync(addressWithETH);
|
||||||
@@ -153,118 +167,137 @@ describe('EtherTokenWrapper', () => {
|
|||||||
// Source: https://github.com/mochajs/mocha/issues/2407
|
// Source: https://github.com/mochajs/mocha/issues/2407
|
||||||
it('Should receive the Transfer event when tokens are transfered', (done: DoneCallback) => {
|
it('Should receive the Transfer event when tokens are transfered', (done: DoneCallback) => {
|
||||||
(async () => {
|
(async () => {
|
||||||
const callback = (err: Error, logEvent: DecodedLogEvent<TransferContractEventArgs>) => {
|
const callback = reportNodeCallbackErrors(done)(
|
||||||
expect(err).to.be.null();
|
(logEvent: DecodedLogEvent<TransferContractEventArgs>) => {
|
||||||
expect(logEvent).to.not.be.undefined();
|
expect(logEvent).to.not.be.undefined();
|
||||||
expect(logEvent.isRemoved).to.be.false();
|
expect(logEvent.isRemoved).to.be.false();
|
||||||
expect(logEvent.log.logIndex).to.be.equal(0);
|
expect(logEvent.log.logIndex).to.be.equal(0);
|
||||||
expect(logEvent.log.transactionIndex).to.be.equal(0);
|
expect(logEvent.log.transactionIndex).to.be.equal(0);
|
||||||
expect(logEvent.log.blockNumber).to.be.a('number');
|
expect(logEvent.log.blockNumber).to.be.a('number');
|
||||||
const args = logEvent.log.args;
|
const args = logEvent.log.args;
|
||||||
expect(args._from).to.be.equal(addressWithETH);
|
expect(args._from).to.be.equal(addressWithETH);
|
||||||
expect(args._to).to.be.equal(addressWithoutFunds);
|
expect(args._to).to.be.equal(addressWithoutFunds);
|
||||||
expect(args._value).to.be.bignumber.equal(transferAmount);
|
expect(args._value).to.be.bignumber.equal(transferAmount);
|
||||||
done();
|
},
|
||||||
};
|
);
|
||||||
await zeroEx.etherToken.depositAsync(etherTokenAddress, transferAmount, addressWithETH);
|
await zeroEx.etherToken.depositAsync(etherTokenAddress, transferAmount, addressWithETH);
|
||||||
zeroEx.etherToken.subscribe(
|
zeroEx.etherToken.subscribe(etherTokenAddress, EtherTokenEvents.Transfer, indexFilterValues, callback);
|
||||||
etherTokenAddress, EtherTokenEvents.Transfer, indexFilterValues, callback);
|
|
||||||
await zeroEx.token.transferAsync(
|
await zeroEx.token.transferAsync(
|
||||||
etherTokenAddress, addressWithETH, addressWithoutFunds, transferAmount,
|
etherTokenAddress,
|
||||||
|
addressWithETH,
|
||||||
|
addressWithoutFunds,
|
||||||
|
transferAmount,
|
||||||
);
|
);
|
||||||
})().catch(done);
|
})().catch(done);
|
||||||
});
|
});
|
||||||
it('Should receive the Approval event when allowance is being set', (done: DoneCallback) => {
|
it('Should receive the Approval event when allowance is being set', (done: DoneCallback) => {
|
||||||
(async () => {
|
(async () => {
|
||||||
const callback = (err: Error, logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
|
const callback = reportNodeCallbackErrors(done)(
|
||||||
expect(err).to.be.null();
|
(logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
|
||||||
expect(logEvent).to.not.be.undefined();
|
expect(logEvent).to.not.be.undefined();
|
||||||
expect(logEvent.isRemoved).to.be.false();
|
expect(logEvent.isRemoved).to.be.false();
|
||||||
const args = logEvent.log.args;
|
const args = logEvent.log.args;
|
||||||
expect(args._owner).to.be.equal(addressWithETH);
|
expect(args._owner).to.be.equal(addressWithETH);
|
||||||
expect(args._spender).to.be.equal(addressWithoutFunds);
|
expect(args._spender).to.be.equal(addressWithoutFunds);
|
||||||
expect(args._value).to.be.bignumber.equal(allowanceAmount);
|
expect(args._value).to.be.bignumber.equal(allowanceAmount);
|
||||||
done();
|
},
|
||||||
};
|
);
|
||||||
zeroEx.etherToken.subscribe(
|
zeroEx.etherToken.subscribe(etherTokenAddress, EtherTokenEvents.Approval, indexFilterValues, callback);
|
||||||
etherTokenAddress, EtherTokenEvents.Approval, indexFilterValues, callback);
|
|
||||||
await zeroEx.token.setAllowanceAsync(
|
await zeroEx.token.setAllowanceAsync(
|
||||||
etherTokenAddress, addressWithETH, addressWithoutFunds, allowanceAmount,
|
etherTokenAddress,
|
||||||
|
addressWithETH,
|
||||||
|
addressWithoutFunds,
|
||||||
|
allowanceAmount,
|
||||||
);
|
);
|
||||||
})().catch(done);
|
})().catch(done);
|
||||||
});
|
});
|
||||||
it('Should receive the Deposit event when ether is being deposited', (done: DoneCallback) => {
|
it('Should receive the Deposit event when ether is being deposited', (done: DoneCallback) => {
|
||||||
(async () => {
|
(async () => {
|
||||||
const callback = (err: Error, logEvent: DecodedLogEvent<DepositContractEventArgs>) => {
|
const callback = reportNodeCallbackErrors(done)(
|
||||||
expect(err).to.be.null();
|
(logEvent: DecodedLogEvent<DepositContractEventArgs>) => {
|
||||||
expect(logEvent).to.not.be.undefined();
|
expect(logEvent).to.not.be.undefined();
|
||||||
expect(logEvent.isRemoved).to.be.false();
|
expect(logEvent.isRemoved).to.be.false();
|
||||||
const args = logEvent.log.args;
|
const args = logEvent.log.args;
|
||||||
expect(args._owner).to.be.equal(addressWithETH);
|
expect(args._owner).to.be.equal(addressWithETH);
|
||||||
expect(args._value).to.be.bignumber.equal(depositAmount);
|
expect(args._value).to.be.bignumber.equal(depositAmount);
|
||||||
done();
|
},
|
||||||
};
|
|
||||||
zeroEx.etherToken.subscribe(
|
|
||||||
etherTokenAddress, EtherTokenEvents.Deposit, indexFilterValues, callback);
|
|
||||||
await zeroEx.etherToken.depositAsync(
|
|
||||||
etherTokenAddress, depositAmount, addressWithETH,
|
|
||||||
);
|
);
|
||||||
|
zeroEx.etherToken.subscribe(etherTokenAddress, EtherTokenEvents.Deposit, indexFilterValues, callback);
|
||||||
|
await zeroEx.etherToken.depositAsync(etherTokenAddress, depositAmount, addressWithETH);
|
||||||
})().catch(done);
|
})().catch(done);
|
||||||
});
|
});
|
||||||
it('Should receive the Withdrawal event when ether is being withdrawn', (done: DoneCallback) => {
|
it('Should receive the Withdrawal event when ether is being withdrawn', (done: DoneCallback) => {
|
||||||
(async () => {
|
(async () => {
|
||||||
const callback = (err: Error, logEvent: DecodedLogEvent<WithdrawalContractEventArgs>) => {
|
const callback = reportNodeCallbackErrors(done)(
|
||||||
expect(err).to.be.null();
|
(logEvent: DecodedLogEvent<WithdrawalContractEventArgs>) => {
|
||||||
expect(logEvent).to.not.be.undefined();
|
expect(logEvent).to.not.be.undefined();
|
||||||
expect(logEvent.isRemoved).to.be.false();
|
expect(logEvent.isRemoved).to.be.false();
|
||||||
const args = logEvent.log.args;
|
const args = logEvent.log.args;
|
||||||
expect(args._owner).to.be.equal(addressWithETH);
|
expect(args._owner).to.be.equal(addressWithETH);
|
||||||
expect(args._value).to.be.bignumber.equal(depositAmount);
|
expect(args._value).to.be.bignumber.equal(depositAmount);
|
||||||
done();
|
},
|
||||||
};
|
|
||||||
await zeroEx.etherToken.depositAsync(
|
|
||||||
etherTokenAddress, depositAmount, addressWithETH,
|
|
||||||
);
|
);
|
||||||
|
await zeroEx.etherToken.depositAsync(etherTokenAddress, depositAmount, addressWithETH);
|
||||||
zeroEx.etherToken.subscribe(
|
zeroEx.etherToken.subscribe(
|
||||||
etherTokenAddress, EtherTokenEvents.Withdrawal, indexFilterValues, callback);
|
etherTokenAddress,
|
||||||
await zeroEx.etherToken.withdrawAsync(
|
EtherTokenEvents.Withdrawal,
|
||||||
etherTokenAddress, withdrawalAmount, addressWithETH,
|
indexFilterValues,
|
||||||
|
callback,
|
||||||
);
|
);
|
||||||
|
await zeroEx.etherToken.withdrawAsync(etherTokenAddress, withdrawalAmount, addressWithETH);
|
||||||
})().catch(done);
|
})().catch(done);
|
||||||
});
|
});
|
||||||
it('should cancel outstanding subscriptions when ZeroEx.setProvider is called', (done: DoneCallback) => {
|
it('should cancel outstanding subscriptions when ZeroEx.setProvider is called', (done: DoneCallback) => {
|
||||||
(async () => {
|
(async () => {
|
||||||
const callbackNeverToBeCalled = (err: Error, logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
|
const callbackNeverToBeCalled = reportNodeCallbackErrors(done)(
|
||||||
done(new Error('Expected this subscription to have been cancelled'));
|
(logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
|
||||||
};
|
done(new Error('Expected this subscription to have been cancelled'));
|
||||||
zeroEx.etherToken.subscribe(
|
},
|
||||||
etherTokenAddress, EtherTokenEvents.Transfer, indexFilterValues, callbackNeverToBeCalled,
|
|
||||||
);
|
);
|
||||||
const callbackToBeCalled = (err: Error, logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
|
zeroEx.etherToken.subscribe(
|
||||||
done();
|
etherTokenAddress,
|
||||||
};
|
EtherTokenEvents.Transfer,
|
||||||
|
indexFilterValues,
|
||||||
|
callbackNeverToBeCalled,
|
||||||
|
);
|
||||||
|
const callbackToBeCalled = reportNodeCallbackErrors(done)();
|
||||||
const newProvider = web3Factory.getRpcProvider();
|
const newProvider = web3Factory.getRpcProvider();
|
||||||
zeroEx.setProvider(newProvider, constants.TESTRPC_NETWORK_ID);
|
zeroEx.setProvider(newProvider, constants.TESTRPC_NETWORK_ID);
|
||||||
await zeroEx.etherToken.depositAsync(etherTokenAddress, transferAmount, addressWithETH);
|
await zeroEx.etherToken.depositAsync(etherTokenAddress, transferAmount, addressWithETH);
|
||||||
zeroEx.etherToken.subscribe(
|
zeroEx.etherToken.subscribe(
|
||||||
etherTokenAddress, EtherTokenEvents.Transfer, indexFilterValues, callbackToBeCalled,
|
etherTokenAddress,
|
||||||
|
EtherTokenEvents.Transfer,
|
||||||
|
indexFilterValues,
|
||||||
|
callbackToBeCalled,
|
||||||
);
|
);
|
||||||
await zeroEx.token.transferAsync(
|
await zeroEx.token.transferAsync(
|
||||||
etherTokenAddress, addressWithETH, addressWithoutFunds, transferAmount,
|
etherTokenAddress,
|
||||||
|
addressWithETH,
|
||||||
|
addressWithoutFunds,
|
||||||
|
transferAmount,
|
||||||
);
|
);
|
||||||
})().catch(done);
|
})().catch(done);
|
||||||
});
|
});
|
||||||
it('Should cancel subscription when unsubscribe called', (done: DoneCallback) => {
|
it('Should cancel subscription when unsubscribe called', (done: DoneCallback) => {
|
||||||
(async () => {
|
(async () => {
|
||||||
const callbackNeverToBeCalled = (err: Error, logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
|
const callbackNeverToBeCalled = reportNodeCallbackErrors(done)(
|
||||||
done(new Error('Expected this subscription to have been cancelled'));
|
(logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
|
||||||
};
|
done(new Error('Expected this subscription to have been cancelled'));
|
||||||
|
},
|
||||||
|
);
|
||||||
await zeroEx.etherToken.depositAsync(etherTokenAddress, transferAmount, addressWithETH);
|
await zeroEx.etherToken.depositAsync(etherTokenAddress, transferAmount, addressWithETH);
|
||||||
const subscriptionToken = zeroEx.etherToken.subscribe(
|
const subscriptionToken = zeroEx.etherToken.subscribe(
|
||||||
etherTokenAddress, EtherTokenEvents.Transfer, indexFilterValues, callbackNeverToBeCalled);
|
etherTokenAddress,
|
||||||
|
EtherTokenEvents.Transfer,
|
||||||
|
indexFilterValues,
|
||||||
|
callbackNeverToBeCalled,
|
||||||
|
);
|
||||||
zeroEx.etherToken.unsubscribe(subscriptionToken);
|
zeroEx.etherToken.unsubscribe(subscriptionToken);
|
||||||
await zeroEx.token.transferAsync(
|
await zeroEx.token.transferAsync(
|
||||||
etherTokenAddress, addressWithETH, addressWithoutFunds, transferAmount,
|
etherTokenAddress,
|
||||||
|
addressWithETH,
|
||||||
|
addressWithoutFunds,
|
||||||
|
transferAmount,
|
||||||
);
|
);
|
||||||
done();
|
done();
|
||||||
})().catch(done);
|
})().catch(done);
|
||||||
@@ -291,7 +324,10 @@ describe('EtherTokenWrapper', () => {
|
|||||||
const eventName = EtherTokenEvents.Approval;
|
const eventName = EtherTokenEvents.Approval;
|
||||||
const indexFilterValues = {};
|
const indexFilterValues = {};
|
||||||
const logs = await zeroEx.etherToken.getLogsAsync<ApprovalContractEventArgs>(
|
const logs = await zeroEx.etherToken.getLogsAsync<ApprovalContractEventArgs>(
|
||||||
etherTokenAddress, eventName, blockRange, indexFilterValues,
|
etherTokenAddress,
|
||||||
|
eventName,
|
||||||
|
blockRange,
|
||||||
|
indexFilterValues,
|
||||||
);
|
);
|
||||||
expect(logs).to.have.length(1);
|
expect(logs).to.have.length(1);
|
||||||
const args = logs[0].args;
|
const args = logs[0].args;
|
||||||
@@ -305,7 +341,10 @@ describe('EtherTokenWrapper', () => {
|
|||||||
const eventName = EtherTokenEvents.Deposit;
|
const eventName = EtherTokenEvents.Deposit;
|
||||||
const indexFilterValues = {};
|
const indexFilterValues = {};
|
||||||
const logs = await zeroEx.etherToken.getLogsAsync<DepositContractEventArgs>(
|
const logs = await zeroEx.etherToken.getLogsAsync<DepositContractEventArgs>(
|
||||||
etherTokenAddress, eventName, blockRange, indexFilterValues,
|
etherTokenAddress,
|
||||||
|
eventName,
|
||||||
|
blockRange,
|
||||||
|
indexFilterValues,
|
||||||
);
|
);
|
||||||
expect(logs).to.have.length(1);
|
expect(logs).to.have.length(1);
|
||||||
const args = logs[0].args;
|
const args = logs[0].args;
|
||||||
@@ -319,7 +358,10 @@ describe('EtherTokenWrapper', () => {
|
|||||||
const differentEventName = EtherTokenEvents.Transfer;
|
const differentEventName = EtherTokenEvents.Transfer;
|
||||||
const indexFilterValues = {};
|
const indexFilterValues = {};
|
||||||
const logs = await zeroEx.etherToken.getLogsAsync(
|
const logs = await zeroEx.etherToken.getLogsAsync(
|
||||||
etherTokenAddress, differentEventName, blockRange, indexFilterValues,
|
etherTokenAddress,
|
||||||
|
differentEventName,
|
||||||
|
blockRange,
|
||||||
|
indexFilterValues,
|
||||||
);
|
);
|
||||||
expect(logs).to.have.length(0);
|
expect(logs).to.have.length(0);
|
||||||
});
|
});
|
||||||
@@ -333,7 +375,10 @@ describe('EtherTokenWrapper', () => {
|
|||||||
_owner: addressWithETH,
|
_owner: addressWithETH,
|
||||||
};
|
};
|
||||||
const logs = await zeroEx.etherToken.getLogsAsync<ApprovalContractEventArgs>(
|
const logs = await zeroEx.etherToken.getLogsAsync<ApprovalContractEventArgs>(
|
||||||
etherTokenAddress, eventName, blockRange, indexFilterValues,
|
etherTokenAddress,
|
||||||
|
eventName,
|
||||||
|
blockRange,
|
||||||
|
indexFilterValues,
|
||||||
);
|
);
|
||||||
expect(logs).to.have.length(1);
|
expect(logs).to.have.length(1);
|
||||||
const args = logs[0].args;
|
const args = logs[0].args;
|
||||||
|
|||||||
@@ -1,18 +1,17 @@
|
|||||||
import {Web3Wrapper} from '@0xproject/web3-wrapper';
|
import { web3Factory } from '@0xproject/dev-utils';
|
||||||
|
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||||
import * as chai from 'chai';
|
import * as chai from 'chai';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import 'mocha';
|
import 'mocha';
|
||||||
import * as Sinon from 'sinon';
|
import * as Sinon from 'sinon';
|
||||||
import * as Web3 from 'web3';
|
import * as Web3 from 'web3';
|
||||||
|
|
||||||
import {
|
import { LogEvent } from '../src';
|
||||||
LogEvent,
|
import { EventWatcher } from '../src/order_watcher/event_watcher';
|
||||||
} from '../src';
|
import { DoneCallback } from '../src/types';
|
||||||
import {EventWatcher} from '../src/order_watcher/event_watcher';
|
|
||||||
import {DoneCallback} from '../src/types';
|
|
||||||
|
|
||||||
import {chaiSetup} from './utils/chai_setup';
|
import { chaiSetup } from './utils/chai_setup';
|
||||||
import {web3Factory} from './utils/web3_factory';
|
import { reportNodeCallbackErrors } from './utils/report_callback_errors';
|
||||||
|
|
||||||
chaiSetup.configure();
|
chaiSetup.configure();
|
||||||
const expect = chai.expect;
|
const expect = chai.expect;
|
||||||
@@ -38,7 +37,7 @@ describe('EventWatcher', () => {
|
|||||||
blockNumber: null,
|
blockNumber: null,
|
||||||
data: '',
|
data: '',
|
||||||
logIndex: null,
|
logIndex: null,
|
||||||
topics: [ '0xf341246adaac6f497bc2a656f546ab9e182111d630394f0c57c710a59a2cb567' ],
|
topics: ['0xf341246adaac6f497bc2a656f546ab9e182111d630394f0c57c710a59a2cb567'],
|
||||||
transactionHash: '0x01ef3c048b18d9b09ea195b4ed94cf8dd5f3d857a1905ff886b152cfb1166f25',
|
transactionHash: '0x01ef3c048b18d9b09ea195b4ed94cf8dd5f3d857a1905ff886b152cfb1166f25',
|
||||||
transactionIndex: 0,
|
transactionIndex: 0,
|
||||||
};
|
};
|
||||||
@@ -48,7 +47,7 @@ describe('EventWatcher', () => {
|
|||||||
blockNumber: null,
|
blockNumber: null,
|
||||||
data: '',
|
data: '',
|
||||||
logIndex: null,
|
logIndex: null,
|
||||||
topics: [ '0xf341246adaac6f497bc2a656f546ab9e182111d630394f0c57c710a59a2cb567' ],
|
topics: ['0xf341246adaac6f497bc2a656f546ab9e182111d630394f0c57c710a59a2cb567'],
|
||||||
transactionHash: '0x01ef3c048b18d9b09ea195b4ed94cf8dd5f3d857a1905ff886b152cfb1166f25',
|
transactionHash: '0x01ef3c048b18d9b09ea195b4ed94cf8dd5f3d857a1905ff886b152cfb1166f25',
|
||||||
transactionIndex: 0,
|
transactionIndex: 0,
|
||||||
};
|
};
|
||||||
@@ -79,13 +78,14 @@ describe('EventWatcher', () => {
|
|||||||
const getLogsStub = Sinon.stub(web3Wrapper, 'getLogsAsync');
|
const getLogsStub = Sinon.stub(web3Wrapper, 'getLogsAsync');
|
||||||
getLogsStub.onCall(0).returns(logs);
|
getLogsStub.onCall(0).returns(logs);
|
||||||
stubs.push(getLogsStub);
|
stubs.push(getLogsStub);
|
||||||
const callback = (event: LogEvent) => {
|
const expectedToBeCalledOnce = false;
|
||||||
|
const callback = reportNodeCallbackErrors(done, expectedToBeCalledOnce)((event: LogEvent) => {
|
||||||
const expectedLogEvent = expectedLogEvents.shift();
|
const expectedLogEvent = expectedLogEvents.shift();
|
||||||
expect(event).to.be.deep.equal(expectedLogEvent);
|
expect(event).to.be.deep.equal(expectedLogEvent);
|
||||||
if (_.isEmpty(expectedLogEvents)) {
|
if (_.isEmpty(expectedLogEvents)) {
|
||||||
done();
|
done();
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
eventWatcher.subscribe(callback);
|
eventWatcher.subscribe(callback);
|
||||||
});
|
});
|
||||||
it('correctly computes the difference and emits only changes', (done: DoneCallback) => {
|
it('correctly computes the difference and emits only changes', (done: DoneCallback) => {
|
||||||
@@ -113,13 +113,14 @@ describe('EventWatcher', () => {
|
|||||||
getLogsStub.onCall(0).returns(initialLogs);
|
getLogsStub.onCall(0).returns(initialLogs);
|
||||||
getLogsStub.onCall(1).returns(changedLogs);
|
getLogsStub.onCall(1).returns(changedLogs);
|
||||||
stubs.push(getLogsStub);
|
stubs.push(getLogsStub);
|
||||||
const callback = (event: LogEvent) => {
|
const expectedToBeCalledOnce = false;
|
||||||
|
const callback = reportNodeCallbackErrors(done, expectedToBeCalledOnce)((event: LogEvent) => {
|
||||||
const expectedLogEvent = expectedLogEvents.shift();
|
const expectedLogEvent = expectedLogEvents.shift();
|
||||||
expect(event).to.be.deep.equal(expectedLogEvent);
|
expect(event).to.be.deep.equal(expectedLogEvent);
|
||||||
if (_.isEmpty(expectedLogEvents)) {
|
if (_.isEmpty(expectedLogEvents)) {
|
||||||
done();
|
done();
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
eventWatcher.subscribe(callback);
|
eventWatcher.subscribe(callback);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
import {BlockchainLifecycle} from '@0xproject/dev-utils';
|
import { BlockchainLifecycle, devConstants, web3Factory } from '@0xproject/dev-utils';
|
||||||
import BigNumber from 'bignumber.js';
|
import { BlockParamLiteral } from '@0xproject/types';
|
||||||
|
import { BigNumber } from '@0xproject/utils';
|
||||||
import * as chai from 'chai';
|
import * as chai from 'chai';
|
||||||
|
|
||||||
import {ExchangeContractErrs, Token, ZeroEx} from '../src';
|
import { ExchangeContractErrs, Token, ZeroEx } from '../src';
|
||||||
import {BlockParamLiteral, TradeSide, TransferType} from '../src/types';
|
import { TradeSide, TransferType } from '../src/types';
|
||||||
import {ExchangeTransferSimulator} from '../src/utils/exchange_transfer_simulator';
|
import { ExchangeTransferSimulator } from '../src/utils/exchange_transfer_simulator';
|
||||||
|
|
||||||
import {chaiSetup} from './utils/chai_setup';
|
import { chaiSetup } from './utils/chai_setup';
|
||||||
import {constants} from './utils/constants';
|
import { constants } from './utils/constants';
|
||||||
import {web3Factory} from './utils/web3_factory';
|
|
||||||
|
|
||||||
chaiSetup.configure();
|
chaiSetup.configure();
|
||||||
const expect = chai.expect;
|
const expect = chai.expect;
|
||||||
const blockchainLifecycle = new BlockchainLifecycle(constants.RPC_URL);
|
const blockchainLifecycle = new BlockchainLifecycle();
|
||||||
|
|
||||||
describe('ExchangeTransferSimulator', () => {
|
describe('ExchangeTransferSimulator', () => {
|
||||||
const web3 = web3Factory.create();
|
const web3 = web3Factory.create();
|
||||||
@@ -45,17 +45,31 @@ describe('ExchangeTransferSimulator', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
exchangeTransferSimulator = new ExchangeTransferSimulator(zeroEx.token, BlockParamLiteral.Latest);
|
exchangeTransferSimulator = new ExchangeTransferSimulator(zeroEx.token, BlockParamLiteral.Latest);
|
||||||
});
|
});
|
||||||
it('throws if the user doesn\'t have enough allowance', async () => {
|
it("throws if the user doesn't have enough allowance", async () => {
|
||||||
return expect(exchangeTransferSimulator.transferFromAsync(
|
return expect(
|
||||||
exampleTokenAddress, sender, recipient, transferAmount, TradeSide.Taker, TransferType.Trade,
|
exchangeTransferSimulator.transferFromAsync(
|
||||||
)).to.be.rejectedWith(ExchangeContractErrs.InsufficientTakerAllowance);
|
exampleTokenAddress,
|
||||||
|
sender,
|
||||||
|
recipient,
|
||||||
|
transferAmount,
|
||||||
|
TradeSide.Taker,
|
||||||
|
TransferType.Trade,
|
||||||
|
),
|
||||||
|
).to.be.rejectedWith(ExchangeContractErrs.InsufficientTakerAllowance);
|
||||||
});
|
});
|
||||||
it('throws if the user doesn\'t have enough balance', async () => {
|
it("throws if the user doesn't have enough balance", async () => {
|
||||||
txHash = await zeroEx.token.setProxyAllowanceAsync(exampleTokenAddress, sender, transferAmount);
|
txHash = await zeroEx.token.setProxyAllowanceAsync(exampleTokenAddress, sender, transferAmount);
|
||||||
await zeroEx.awaitTransactionMinedAsync(txHash);
|
await zeroEx.awaitTransactionMinedAsync(txHash);
|
||||||
return expect(exchangeTransferSimulator.transferFromAsync(
|
return expect(
|
||||||
exampleTokenAddress, sender, recipient, transferAmount, TradeSide.Maker, TransferType.Trade,
|
exchangeTransferSimulator.transferFromAsync(
|
||||||
)).to.be.rejectedWith(ExchangeContractErrs.InsufficientMakerBalance);
|
exampleTokenAddress,
|
||||||
|
sender,
|
||||||
|
recipient,
|
||||||
|
transferAmount,
|
||||||
|
TradeSide.Maker,
|
||||||
|
TransferType.Trade,
|
||||||
|
),
|
||||||
|
).to.be.rejectedWith(ExchangeContractErrs.InsufficientMakerBalance);
|
||||||
});
|
});
|
||||||
it('updates balances and proxyAllowance after transfer', async () => {
|
it('updates balances and proxyAllowance after transfer', async () => {
|
||||||
txHash = await zeroEx.token.transferAsync(exampleTokenAddress, coinbase, sender, transferAmount);
|
txHash = await zeroEx.token.transferAsync(exampleTokenAddress, coinbase, sender, transferAmount);
|
||||||
@@ -63,7 +77,12 @@ describe('ExchangeTransferSimulator', () => {
|
|||||||
txHash = await zeroEx.token.setProxyAllowanceAsync(exampleTokenAddress, sender, transferAmount);
|
txHash = await zeroEx.token.setProxyAllowanceAsync(exampleTokenAddress, sender, transferAmount);
|
||||||
await zeroEx.awaitTransactionMinedAsync(txHash);
|
await zeroEx.awaitTransactionMinedAsync(txHash);
|
||||||
await exchangeTransferSimulator.transferFromAsync(
|
await exchangeTransferSimulator.transferFromAsync(
|
||||||
exampleTokenAddress, sender, recipient, transferAmount, TradeSide.Taker, TransferType.Trade,
|
exampleTokenAddress,
|
||||||
|
sender,
|
||||||
|
recipient,
|
||||||
|
transferAmount,
|
||||||
|
TradeSide.Taker,
|
||||||
|
TransferType.Trade,
|
||||||
);
|
);
|
||||||
const store = (exchangeTransferSimulator as any)._store;
|
const store = (exchangeTransferSimulator as any)._store;
|
||||||
const senderBalance = await store.getBalanceAsync(exampleTokenAddress, sender);
|
const senderBalance = await store.getBalanceAsync(exampleTokenAddress, sender);
|
||||||
@@ -73,13 +92,18 @@ describe('ExchangeTransferSimulator', () => {
|
|||||||
expect(recipientBalance).to.be.bignumber.equal(transferAmount);
|
expect(recipientBalance).to.be.bignumber.equal(transferAmount);
|
||||||
expect(senderProxyAllowance).to.be.bignumber.equal(0);
|
expect(senderProxyAllowance).to.be.bignumber.equal(0);
|
||||||
});
|
});
|
||||||
it('doesn\'t update proxyAllowance after transfer if unlimited', async () => {
|
it("doesn't update proxyAllowance after transfer if unlimited", async () => {
|
||||||
txHash = await zeroEx.token.transferAsync(exampleTokenAddress, coinbase, sender, transferAmount);
|
txHash = await zeroEx.token.transferAsync(exampleTokenAddress, coinbase, sender, transferAmount);
|
||||||
await zeroEx.awaitTransactionMinedAsync(txHash);
|
await zeroEx.awaitTransactionMinedAsync(txHash);
|
||||||
txHash = await zeroEx.token.setUnlimitedProxyAllowanceAsync(exampleTokenAddress, sender);
|
txHash = await zeroEx.token.setUnlimitedProxyAllowanceAsync(exampleTokenAddress, sender);
|
||||||
await zeroEx.awaitTransactionMinedAsync(txHash);
|
await zeroEx.awaitTransactionMinedAsync(txHash);
|
||||||
await exchangeTransferSimulator.transferFromAsync(
|
await exchangeTransferSimulator.transferFromAsync(
|
||||||
exampleTokenAddress, sender, recipient, transferAmount, TradeSide.Taker, TransferType.Trade,
|
exampleTokenAddress,
|
||||||
|
sender,
|
||||||
|
recipient,
|
||||||
|
transferAmount,
|
||||||
|
TradeSide.Taker,
|
||||||
|
TransferType.Trade,
|
||||||
);
|
);
|
||||||
const store = (exchangeTransferSimulator as any)._store;
|
const store = (exchangeTransferSimulator as any)._store;
|
||||||
const senderBalance = await store.getBalanceAsync(exampleTokenAddress, sender);
|
const senderBalance = await store.getBalanceAsync(exampleTokenAddress, sender);
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,27 +1,25 @@
|
|||||||
import {BlockchainLifecycle} from '@0xproject/dev-utils';
|
import { BlockchainLifecycle, devConstants, web3Factory } from '@0xproject/dev-utils';
|
||||||
import BigNumber from 'bignumber.js';
|
import { BigNumber } from '@0xproject/utils';
|
||||||
import * as chai from 'chai';
|
import * as chai from 'chai';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import 'mocha';
|
import 'mocha';
|
||||||
import * as Sinon from 'sinon';
|
import * as Sinon from 'sinon';
|
||||||
import * as Web3 from 'web3';
|
import * as Web3 from 'web3';
|
||||||
|
|
||||||
import {ZeroEx} from '../src/0x';
|
import { ZeroEx } from '../src/0x';
|
||||||
import {ExpirationWatcher} from '../src/order_watcher/expiration_watcher';
|
import { ExpirationWatcher } from '../src/order_watcher/expiration_watcher';
|
||||||
import {DoneCallback, Token} from '../src/types';
|
import { DoneCallback, Token } from '../src/types';
|
||||||
import {constants} from '../src/utils/constants';
|
import { utils } from '../src/utils/utils';
|
||||||
import {utils} from '../src/utils/utils';
|
|
||||||
|
|
||||||
import {chaiSetup} from './utils/chai_setup';
|
import { chaiSetup } from './utils/chai_setup';
|
||||||
import {constants as testConstants} from './utils/constants';
|
import { constants } from './utils/constants';
|
||||||
import {FillScenarios} from './utils/fill_scenarios';
|
import { FillScenarios } from './utils/fill_scenarios';
|
||||||
import {reportCallbackErrors} from './utils/report_callback_errors';
|
import { reportNoErrorCallbackErrors } from './utils/report_callback_errors';
|
||||||
import {TokenUtils} from './utils/token_utils';
|
import { TokenUtils } from './utils/token_utils';
|
||||||
import {web3Factory} from './utils/web3_factory';
|
|
||||||
|
|
||||||
chaiSetup.configure();
|
chaiSetup.configure();
|
||||||
const expect = chai.expect;
|
const expect = chai.expect;
|
||||||
const blockchainLifecycle = new BlockchainLifecycle(testConstants.RPC_URL);
|
const blockchainLifecycle = new BlockchainLifecycle();
|
||||||
|
|
||||||
describe('ExpirationWatcher', () => {
|
describe('ExpirationWatcher', () => {
|
||||||
let web3: Web3;
|
let web3: Web3;
|
||||||
@@ -62,7 +60,7 @@ describe('ExpirationWatcher', () => {
|
|||||||
});
|
});
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await blockchainLifecycle.startAsync();
|
await blockchainLifecycle.startAsync();
|
||||||
const sinonTimerConfig = {shouldAdvanceTime: true} as any;
|
const sinonTimerConfig = { shouldAdvanceTime: true } as any;
|
||||||
// This constructor has incorrect types
|
// This constructor has incorrect types
|
||||||
timer = Sinon.useFakeTimers(sinonTimerConfig);
|
timer = Sinon.useFakeTimers(sinonTimerConfig);
|
||||||
currentUnixTimestampSec = utils.getCurrentUnixTimestampSec();
|
currentUnixTimestampSec = utils.getCurrentUnixTimestampSec();
|
||||||
@@ -78,31 +76,38 @@ describe('ExpirationWatcher', () => {
|
|||||||
const orderLifetimeSec = 60;
|
const orderLifetimeSec = 60;
|
||||||
const expirationUnixTimestampSec = currentUnixTimestampSec.plus(orderLifetimeSec);
|
const expirationUnixTimestampSec = currentUnixTimestampSec.plus(orderLifetimeSec);
|
||||||
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
makerTokenAddress,
|
||||||
|
takerTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
expirationUnixTimestampSec,
|
expirationUnixTimestampSec,
|
||||||
);
|
);
|
||||||
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
||||||
expirationWatcher.addOrder(orderHash, signedOrder.expirationUnixTimestampSec.times(1000));
|
expirationWatcher.addOrder(orderHash, signedOrder.expirationUnixTimestampSec.times(1000));
|
||||||
const callbackAsync = reportCallbackErrors(done)(async (hash: string) => {
|
const callbackAsync = reportNoErrorCallbackErrors(done)((hash: string) => {
|
||||||
expect(hash).to.be.equal(orderHash);
|
expect(hash).to.be.equal(orderHash);
|
||||||
expect(utils.getCurrentUnixTimestampSec()).to.be.bignumber.gte(expirationUnixTimestampSec);
|
expect(utils.getCurrentUnixTimestampSec()).to.be.bignumber.gte(expirationUnixTimestampSec);
|
||||||
done();
|
|
||||||
});
|
});
|
||||||
expirationWatcher.subscribe(callbackAsync);
|
expirationWatcher.subscribe(callbackAsync);
|
||||||
timer.tick(orderLifetimeSec * 1000);
|
timer.tick(orderLifetimeSec * 1000);
|
||||||
})().catch(done);
|
})().catch(done);
|
||||||
});
|
});
|
||||||
it('doesn\'t emit events before order expires', (done: DoneCallback) => {
|
it("doesn't emit events before order expires", (done: DoneCallback) => {
|
||||||
(async () => {
|
(async () => {
|
||||||
const orderLifetimeSec = 60;
|
const orderLifetimeSec = 60;
|
||||||
const expirationUnixTimestampSec = currentUnixTimestampSec.plus(orderLifetimeSec);
|
const expirationUnixTimestampSec = currentUnixTimestampSec.plus(orderLifetimeSec);
|
||||||
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
makerTokenAddress,
|
||||||
|
takerTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
expirationUnixTimestampSec,
|
expirationUnixTimestampSec,
|
||||||
);
|
);
|
||||||
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
||||||
expirationWatcher.addOrder(orderHash, signedOrder.expirationUnixTimestampSec.times(1000));
|
expirationWatcher.addOrder(orderHash, signedOrder.expirationUnixTimestampSec.times(1000));
|
||||||
const callbackAsync = reportCallbackErrors(done)(async (hash: string) => {
|
const callbackAsync = reportNoErrorCallbackErrors(done)(async (hash: string) => {
|
||||||
done(new Error('Emitted expiration went before the order actually expired'));
|
done(new Error('Emitted expiration went before the order actually expired'));
|
||||||
});
|
});
|
||||||
expirationWatcher.subscribe(callbackAsync);
|
expirationWatcher.subscribe(callbackAsync);
|
||||||
@@ -118,11 +123,19 @@ describe('ExpirationWatcher', () => {
|
|||||||
const order1ExpirationUnixTimestampSec = currentUnixTimestampSec.plus(order1Lifetime);
|
const order1ExpirationUnixTimestampSec = currentUnixTimestampSec.plus(order1Lifetime);
|
||||||
const order2ExpirationUnixTimestampSec = currentUnixTimestampSec.plus(order2Lifetime);
|
const order2ExpirationUnixTimestampSec = currentUnixTimestampSec.plus(order2Lifetime);
|
||||||
const signedOrder1 = await fillScenarios.createFillableSignedOrderAsync(
|
const signedOrder1 = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
makerTokenAddress,
|
||||||
|
takerTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
order1ExpirationUnixTimestampSec,
|
order1ExpirationUnixTimestampSec,
|
||||||
);
|
);
|
||||||
const signedOrder2 = await fillScenarios.createFillableSignedOrderAsync(
|
const signedOrder2 = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
makerTokenAddress,
|
||||||
|
takerTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
order2ExpirationUnixTimestampSec,
|
order2ExpirationUnixTimestampSec,
|
||||||
);
|
);
|
||||||
const orderHash1 = ZeroEx.getOrderHashHex(signedOrder1);
|
const orderHash1 = ZeroEx.getOrderHashHex(signedOrder1);
|
||||||
@@ -130,7 +143,8 @@ describe('ExpirationWatcher', () => {
|
|||||||
expirationWatcher.addOrder(orderHash2, signedOrder2.expirationUnixTimestampSec.times(1000));
|
expirationWatcher.addOrder(orderHash2, signedOrder2.expirationUnixTimestampSec.times(1000));
|
||||||
expirationWatcher.addOrder(orderHash1, signedOrder1.expirationUnixTimestampSec.times(1000));
|
expirationWatcher.addOrder(orderHash1, signedOrder1.expirationUnixTimestampSec.times(1000));
|
||||||
const expirationOrder = [orderHash1, orderHash2];
|
const expirationOrder = [orderHash1, orderHash2];
|
||||||
const callbackAsync = reportCallbackErrors(done)(async (hash: string) => {
|
const expectToBeCalledOnce = false;
|
||||||
|
const callbackAsync = reportNoErrorCallbackErrors(done, expectToBeCalledOnce)((hash: string) => {
|
||||||
const orderHash = expirationOrder.shift();
|
const orderHash = expirationOrder.shift();
|
||||||
expect(hash).to.be.equal(orderHash);
|
expect(hash).to.be.equal(orderHash);
|
||||||
if (_.isEmpty(expirationOrder)) {
|
if (_.isEmpty(expirationOrder)) {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import {BlockchainLifecycle} from '@0xproject/dev-utils';
|
import { BlockchainLifecycle, devConstants, web3Factory } from '@0xproject/dev-utils';
|
||||||
import BigNumber from 'bignumber.js';
|
import { BigNumber } from '@0xproject/utils';
|
||||||
import * as chai from 'chai';
|
import * as chai from 'chai';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import 'mocha';
|
import 'mocha';
|
||||||
@@ -15,20 +15,19 @@ import {
|
|||||||
ZeroEx,
|
ZeroEx,
|
||||||
ZeroExError,
|
ZeroExError,
|
||||||
} from '../src';
|
} from '../src';
|
||||||
import {DoneCallback} from '../src/types';
|
import { DoneCallback } from '../src/types';
|
||||||
|
|
||||||
import {chaiSetup} from './utils/chai_setup';
|
import { chaiSetup } from './utils/chai_setup';
|
||||||
import {constants} from './utils/constants';
|
import { constants } from './utils/constants';
|
||||||
import {FillScenarios} from './utils/fill_scenarios';
|
import { FillScenarios } from './utils/fill_scenarios';
|
||||||
import {reportCallbackErrors} from './utils/report_callback_errors';
|
import { reportNodeCallbackErrors } from './utils/report_callback_errors';
|
||||||
import {TokenUtils} from './utils/token_utils';
|
import { TokenUtils } from './utils/token_utils';
|
||||||
import {web3Factory} from './utils/web3_factory';
|
|
||||||
|
|
||||||
const TIMEOUT_MS = 150;
|
const TIMEOUT_MS = 150;
|
||||||
|
|
||||||
chaiSetup.configure();
|
chaiSetup.configure();
|
||||||
const expect = chai.expect;
|
const expect = chai.expect;
|
||||||
const blockchainLifecycle = new BlockchainLifecycle(constants.RPC_URL);
|
const blockchainLifecycle = new BlockchainLifecycle();
|
||||||
|
|
||||||
describe('OrderStateWatcher', () => {
|
describe('OrderStateWatcher', () => {
|
||||||
let web3: Web3;
|
let web3: Web3;
|
||||||
@@ -71,7 +70,11 @@ describe('OrderStateWatcher', () => {
|
|||||||
describe('#removeOrder', async () => {
|
describe('#removeOrder', async () => {
|
||||||
it('should successfully remove existing order', async () => {
|
it('should successfully remove existing order', async () => {
|
||||||
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerToken.address, takerToken.address, maker, taker, fillableAmount,
|
makerToken.address,
|
||||||
|
takerToken.address,
|
||||||
|
maker,
|
||||||
|
taker,
|
||||||
|
fillableAmount,
|
||||||
);
|
);
|
||||||
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
||||||
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
||||||
@@ -89,10 +92,18 @@ describe('OrderStateWatcher', () => {
|
|||||||
});
|
});
|
||||||
it('should no-op when removing a non-existing order', async () => {
|
it('should no-op when removing a non-existing order', async () => {
|
||||||
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerToken.address, takerToken.address, maker, taker, fillableAmount,
|
makerToken.address,
|
||||||
|
takerToken.address,
|
||||||
|
maker,
|
||||||
|
taker,
|
||||||
|
fillableAmount,
|
||||||
);
|
);
|
||||||
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
||||||
const nonExistentOrderHash = `0x${orderHash.substr(2).split('').reverse().join('')}`;
|
const nonExistentOrderHash = `0x${orderHash
|
||||||
|
.substr(2)
|
||||||
|
.split('')
|
||||||
|
.reverse()
|
||||||
|
.join('')}`;
|
||||||
zeroEx.orderStateWatcher.removeOrder(nonExistentOrderHash);
|
zeroEx.orderStateWatcher.removeOrder(nonExistentOrderHash);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -102,8 +113,7 @@ describe('OrderStateWatcher', () => {
|
|||||||
});
|
});
|
||||||
it('should fail when trying to subscribe twice', async () => {
|
it('should fail when trying to subscribe twice', async () => {
|
||||||
zeroEx.orderStateWatcher.subscribe(_.noop);
|
zeroEx.orderStateWatcher.subscribe(_.noop);
|
||||||
expect(() => zeroEx.orderStateWatcher.subscribe(_.noop))
|
expect(() => zeroEx.orderStateWatcher.subscribe(_.noop)).to.throw(ZeroExError.SubscriptionAlreadyPresent);
|
||||||
.to.throw(ZeroExError.SubscriptionAlreadyPresent);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('tests with cleanup', async () => {
|
describe('tests with cleanup', async () => {
|
||||||
@@ -115,16 +125,19 @@ describe('OrderStateWatcher', () => {
|
|||||||
it('should emit orderStateInvalid when maker allowance set to 0 for watched order', (done: DoneCallback) => {
|
it('should emit orderStateInvalid when maker allowance set to 0 for watched order', (done: DoneCallback) => {
|
||||||
(async () => {
|
(async () => {
|
||||||
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerToken.address, takerToken.address, maker, taker, fillableAmount,
|
makerToken.address,
|
||||||
|
takerToken.address,
|
||||||
|
maker,
|
||||||
|
taker,
|
||||||
|
fillableAmount,
|
||||||
);
|
);
|
||||||
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
||||||
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
||||||
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
|
const callback = reportNodeCallbackErrors(done)((orderState: OrderState) => {
|
||||||
expect(orderState.isValid).to.be.false();
|
expect(orderState.isValid).to.be.false();
|
||||||
const invalidOrderState = orderState as OrderStateInvalid;
|
const invalidOrderState = orderState as OrderStateInvalid;
|
||||||
expect(invalidOrderState.orderHash).to.be.equal(orderHash);
|
expect(invalidOrderState.orderHash).to.be.equal(orderHash);
|
||||||
expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.InsufficientMakerAllowance);
|
expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.InsufficientMakerAllowance);
|
||||||
done();
|
|
||||||
});
|
});
|
||||||
zeroEx.orderStateWatcher.subscribe(callback);
|
zeroEx.orderStateWatcher.subscribe(callback);
|
||||||
await zeroEx.token.setProxyAllowanceAsync(makerToken.address, maker, new BigNumber(0));
|
await zeroEx.token.setProxyAllowanceAsync(makerToken.address, maker, new BigNumber(0));
|
||||||
@@ -133,10 +146,14 @@ describe('OrderStateWatcher', () => {
|
|||||||
it('should not emit an orderState event when irrelevant Transfer event received', (done: DoneCallback) => {
|
it('should not emit an orderState event when irrelevant Transfer event received', (done: DoneCallback) => {
|
||||||
(async () => {
|
(async () => {
|
||||||
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerToken.address, takerToken.address, maker, taker, fillableAmount,
|
makerToken.address,
|
||||||
|
takerToken.address,
|
||||||
|
maker,
|
||||||
|
taker,
|
||||||
|
fillableAmount,
|
||||||
);
|
);
|
||||||
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
||||||
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
|
const callback = reportNodeCallbackErrors(done)((orderState: OrderState) => {
|
||||||
throw new Error('OrderState callback fired for irrelevant order');
|
throw new Error('OrderState callback fired for irrelevant order');
|
||||||
});
|
});
|
||||||
zeroEx.orderStateWatcher.subscribe(callback);
|
zeroEx.orderStateWatcher.subscribe(callback);
|
||||||
@@ -152,16 +169,19 @@ describe('OrderStateWatcher', () => {
|
|||||||
it('should emit orderStateInvalid when maker moves balance backing watched order', (done: DoneCallback) => {
|
it('should emit orderStateInvalid when maker moves balance backing watched order', (done: DoneCallback) => {
|
||||||
(async () => {
|
(async () => {
|
||||||
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerToken.address, takerToken.address, maker, taker, fillableAmount,
|
makerToken.address,
|
||||||
|
takerToken.address,
|
||||||
|
maker,
|
||||||
|
taker,
|
||||||
|
fillableAmount,
|
||||||
);
|
);
|
||||||
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
||||||
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
||||||
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
|
const callback = reportNodeCallbackErrors(done)((orderState: OrderState) => {
|
||||||
expect(orderState.isValid).to.be.false();
|
expect(orderState.isValid).to.be.false();
|
||||||
const invalidOrderState = orderState as OrderStateInvalid;
|
const invalidOrderState = orderState as OrderStateInvalid;
|
||||||
expect(invalidOrderState.orderHash).to.be.equal(orderHash);
|
expect(invalidOrderState.orderHash).to.be.equal(orderHash);
|
||||||
expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.InsufficientMakerBalance);
|
expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.InsufficientMakerBalance);
|
||||||
done();
|
|
||||||
});
|
});
|
||||||
zeroEx.orderStateWatcher.subscribe(callback);
|
zeroEx.orderStateWatcher.subscribe(callback);
|
||||||
const anyRecipient = taker;
|
const anyRecipient = taker;
|
||||||
@@ -172,30 +192,40 @@ describe('OrderStateWatcher', () => {
|
|||||||
it('should emit orderStateInvalid when watched order fully filled', (done: DoneCallback) => {
|
it('should emit orderStateInvalid when watched order fully filled', (done: DoneCallback) => {
|
||||||
(async () => {
|
(async () => {
|
||||||
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerToken.address, takerToken.address, maker, taker, fillableAmount,
|
makerToken.address,
|
||||||
|
takerToken.address,
|
||||||
|
maker,
|
||||||
|
taker,
|
||||||
|
fillableAmount,
|
||||||
);
|
);
|
||||||
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
||||||
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
||||||
|
|
||||||
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
|
const callback = reportNodeCallbackErrors(done)((orderState: OrderState) => {
|
||||||
expect(orderState.isValid).to.be.false();
|
expect(orderState.isValid).to.be.false();
|
||||||
const invalidOrderState = orderState as OrderStateInvalid;
|
const invalidOrderState = orderState as OrderStateInvalid;
|
||||||
expect(invalidOrderState.orderHash).to.be.equal(orderHash);
|
expect(invalidOrderState.orderHash).to.be.equal(orderHash);
|
||||||
expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.OrderRemainingFillAmountZero);
|
expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.OrderRemainingFillAmountZero);
|
||||||
done();
|
|
||||||
});
|
});
|
||||||
zeroEx.orderStateWatcher.subscribe(callback);
|
zeroEx.orderStateWatcher.subscribe(callback);
|
||||||
|
|
||||||
const shouldThrowOnInsufficientBalanceOrAllowance = true;
|
const shouldThrowOnInsufficientBalanceOrAllowance = true;
|
||||||
await zeroEx.exchange.fillOrderAsync(
|
await zeroEx.exchange.fillOrderAsync(
|
||||||
signedOrder, fillableAmount, shouldThrowOnInsufficientBalanceOrAllowance, taker,
|
signedOrder,
|
||||||
|
fillableAmount,
|
||||||
|
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||||
|
taker,
|
||||||
);
|
);
|
||||||
})().catch(done);
|
})().catch(done);
|
||||||
});
|
});
|
||||||
it('should emit orderStateValid when watched order partially filled', (done: DoneCallback) => {
|
it('should emit orderStateValid when watched order partially filled', (done: DoneCallback) => {
|
||||||
(async () => {
|
(async () => {
|
||||||
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerToken.address, takerToken.address, maker, taker, fillableAmount,
|
makerToken.address,
|
||||||
|
takerToken.address,
|
||||||
|
maker,
|
||||||
|
taker,
|
||||||
|
fillableAmount,
|
||||||
);
|
);
|
||||||
|
|
||||||
const makerBalance = await zeroEx.token.getBalanceAsync(makerToken.address, maker);
|
const makerBalance = await zeroEx.token.getBalanceAsync(makerToken.address, maker);
|
||||||
@@ -203,7 +233,7 @@ describe('OrderStateWatcher', () => {
|
|||||||
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
||||||
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
||||||
|
|
||||||
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
|
const callback = reportNodeCallbackErrors(done)((orderState: OrderState) => {
|
||||||
expect(orderState.isValid).to.be.true();
|
expect(orderState.isValid).to.be.true();
|
||||||
const validOrderState = orderState as OrderStateValid;
|
const validOrderState = orderState as OrderStateValid;
|
||||||
expect(validOrderState.orderHash).to.be.equal(orderHash);
|
expect(validOrderState.orderHash).to.be.equal(orderHash);
|
||||||
@@ -211,16 +241,20 @@ describe('OrderStateWatcher', () => {
|
|||||||
const remainingMakerBalance = makerBalance.sub(fillAmountInBaseUnits);
|
const remainingMakerBalance = makerBalance.sub(fillAmountInBaseUnits);
|
||||||
const remainingFillable = fillableAmount.minus(fillAmountInBaseUnits);
|
const remainingFillable = fillableAmount.minus(fillAmountInBaseUnits);
|
||||||
expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
|
expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
|
||||||
remainingFillable);
|
remainingFillable,
|
||||||
|
);
|
||||||
expect(orderRelevantState.remainingFillableTakerTokenAmount).to.be.bignumber.equal(
|
expect(orderRelevantState.remainingFillableTakerTokenAmount).to.be.bignumber.equal(
|
||||||
remainingFillable);
|
remainingFillable,
|
||||||
|
);
|
||||||
expect(orderRelevantState.makerBalance).to.be.bignumber.equal(remainingMakerBalance);
|
expect(orderRelevantState.makerBalance).to.be.bignumber.equal(remainingMakerBalance);
|
||||||
done();
|
|
||||||
});
|
});
|
||||||
zeroEx.orderStateWatcher.subscribe(callback);
|
zeroEx.orderStateWatcher.subscribe(callback);
|
||||||
const shouldThrowOnInsufficientBalanceOrAllowance = true;
|
const shouldThrowOnInsufficientBalanceOrAllowance = true;
|
||||||
await zeroEx.exchange.fillOrderAsync(
|
await zeroEx.exchange.fillOrderAsync(
|
||||||
signedOrder, fillAmountInBaseUnits, shouldThrowOnInsufficientBalanceOrAllowance, taker,
|
signedOrder,
|
||||||
|
fillAmountInBaseUnits,
|
||||||
|
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||||
|
taker,
|
||||||
);
|
);
|
||||||
})().catch(done);
|
})().catch(done);
|
||||||
});
|
});
|
||||||
@@ -229,11 +263,16 @@ describe('OrderStateWatcher', () => {
|
|||||||
const makerFee = ZeroEx.toBaseUnitAmount(new BigNumber(2), 18);
|
const makerFee = ZeroEx.toBaseUnitAmount(new BigNumber(2), 18);
|
||||||
const takerFee = ZeroEx.toBaseUnitAmount(new BigNumber(0), 18);
|
const takerFee = ZeroEx.toBaseUnitAmount(new BigNumber(0), 18);
|
||||||
signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
|
signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
|
||||||
makerToken.address, takerToken.address, makerFee, takerFee, maker, taker, fillableAmount,
|
makerToken.address,
|
||||||
taker);
|
takerToken.address,
|
||||||
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
|
makerFee,
|
||||||
done();
|
takerFee,
|
||||||
});
|
maker,
|
||||||
|
taker,
|
||||||
|
fillableAmount,
|
||||||
|
taker,
|
||||||
|
);
|
||||||
|
const callback = reportNodeCallbackErrors(done)();
|
||||||
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
||||||
zeroEx.orderStateWatcher.subscribe(callback);
|
zeroEx.orderStateWatcher.subscribe(callback);
|
||||||
await zeroEx.token.setProxyAllowanceAsync(zrxTokenAddress, maker, new BigNumber(0));
|
await zeroEx.token.setProxyAllowanceAsync(zrxTokenAddress, maker, new BigNumber(0));
|
||||||
@@ -245,47 +284,60 @@ describe('OrderStateWatcher', () => {
|
|||||||
const takerFillableAmount = ZeroEx.toBaseUnitAmount(new BigNumber(10), decimals);
|
const takerFillableAmount = ZeroEx.toBaseUnitAmount(new BigNumber(10), decimals);
|
||||||
const makerFillableAmount = ZeroEx.toBaseUnitAmount(new BigNumber(20), decimals);
|
const makerFillableAmount = ZeroEx.toBaseUnitAmount(new BigNumber(20), decimals);
|
||||||
signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync(
|
signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync(
|
||||||
makerToken.address, takerToken.address, maker, taker, makerFillableAmount,
|
makerToken.address,
|
||||||
|
takerToken.address,
|
||||||
|
maker,
|
||||||
|
taker,
|
||||||
|
makerFillableAmount,
|
||||||
takerFillableAmount,
|
takerFillableAmount,
|
||||||
);
|
);
|
||||||
const fillAmountInBaseUnits = ZeroEx.toBaseUnitAmount(new BigNumber(2), decimals);
|
const fillAmountInBaseUnits = ZeroEx.toBaseUnitAmount(new BigNumber(2), decimals);
|
||||||
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
||||||
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
||||||
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
|
const callback = reportNodeCallbackErrors(done)((orderState: OrderState) => {
|
||||||
expect(orderState.isValid).to.be.true();
|
expect(orderState.isValid).to.be.true();
|
||||||
const validOrderState = orderState as OrderStateValid;
|
const validOrderState = orderState as OrderStateValid;
|
||||||
expect(validOrderState.orderHash).to.be.equal(orderHash);
|
expect(validOrderState.orderHash).to.be.equal(orderHash);
|
||||||
const orderRelevantState = validOrderState.orderRelevantState;
|
const orderRelevantState = validOrderState.orderRelevantState;
|
||||||
expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
|
expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
|
||||||
ZeroEx.toBaseUnitAmount(new BigNumber(16), decimals));
|
ZeroEx.toBaseUnitAmount(new BigNumber(16), decimals),
|
||||||
|
);
|
||||||
expect(orderRelevantState.remainingFillableTakerTokenAmount).to.be.bignumber.equal(
|
expect(orderRelevantState.remainingFillableTakerTokenAmount).to.be.bignumber.equal(
|
||||||
ZeroEx.toBaseUnitAmount(new BigNumber(8), decimals));
|
ZeroEx.toBaseUnitAmount(new BigNumber(8), decimals),
|
||||||
done();
|
);
|
||||||
});
|
});
|
||||||
zeroEx.orderStateWatcher.subscribe(callback);
|
zeroEx.orderStateWatcher.subscribe(callback);
|
||||||
const shouldThrowOnInsufficientBalanceOrAllowance = true;
|
const shouldThrowOnInsufficientBalanceOrAllowance = true;
|
||||||
await zeroEx.exchange.fillOrderAsync(
|
await zeroEx.exchange.fillOrderAsync(
|
||||||
signedOrder, fillAmountInBaseUnits, shouldThrowOnInsufficientBalanceOrAllowance, taker,
|
signedOrder,
|
||||||
|
fillAmountInBaseUnits,
|
||||||
|
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||||
|
taker,
|
||||||
);
|
);
|
||||||
})().catch(done);
|
})().catch(done);
|
||||||
});
|
});
|
||||||
it('should equal approved amount when approved amount is lowest', (done: DoneCallback) => {
|
it('should equal approved amount when approved amount is lowest', (done: DoneCallback) => {
|
||||||
(async () => {
|
(async () => {
|
||||||
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerToken.address, takerToken.address, maker, taker, fillableAmount,
|
makerToken.address,
|
||||||
|
takerToken.address,
|
||||||
|
maker,
|
||||||
|
taker,
|
||||||
|
fillableAmount,
|
||||||
);
|
);
|
||||||
|
|
||||||
const changedMakerApprovalAmount = ZeroEx.toBaseUnitAmount(new BigNumber(3), decimals);
|
const changedMakerApprovalAmount = ZeroEx.toBaseUnitAmount(new BigNumber(3), decimals);
|
||||||
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
||||||
|
|
||||||
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
|
const callback = reportNodeCallbackErrors(done)((orderState: OrderState) => {
|
||||||
const validOrderState = orderState as OrderStateValid;
|
const validOrderState = orderState as OrderStateValid;
|
||||||
const orderRelevantState = validOrderState.orderRelevantState;
|
const orderRelevantState = validOrderState.orderRelevantState;
|
||||||
expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
|
expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
|
||||||
changedMakerApprovalAmount);
|
changedMakerApprovalAmount,
|
||||||
|
);
|
||||||
expect(orderRelevantState.remainingFillableTakerTokenAmount).to.be.bignumber.equal(
|
expect(orderRelevantState.remainingFillableTakerTokenAmount).to.be.bignumber.equal(
|
||||||
changedMakerApprovalAmount);
|
changedMakerApprovalAmount,
|
||||||
done();
|
);
|
||||||
});
|
});
|
||||||
zeroEx.orderStateWatcher.subscribe(callback);
|
zeroEx.orderStateWatcher.subscribe(callback);
|
||||||
await zeroEx.token.setProxyAllowanceAsync(makerToken.address, maker, changedMakerApprovalAmount);
|
await zeroEx.token.setProxyAllowanceAsync(makerToken.address, maker, changedMakerApprovalAmount);
|
||||||
@@ -294,7 +346,11 @@ describe('OrderStateWatcher', () => {
|
|||||||
it('should equal balance amount when balance amount is lowest', (done: DoneCallback) => {
|
it('should equal balance amount when balance amount is lowest', (done: DoneCallback) => {
|
||||||
(async () => {
|
(async () => {
|
||||||
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerToken.address, takerToken.address, maker, taker, fillableAmount,
|
makerToken.address,
|
||||||
|
takerToken.address,
|
||||||
|
maker,
|
||||||
|
taker,
|
||||||
|
fillableAmount,
|
||||||
);
|
);
|
||||||
|
|
||||||
const makerBalance = await zeroEx.token.getBalanceAsync(makerToken.address, maker);
|
const makerBalance = await zeroEx.token.getBalanceAsync(makerToken.address, maker);
|
||||||
@@ -303,19 +359,19 @@ describe('OrderStateWatcher', () => {
|
|||||||
const transferAmount = makerBalance.sub(remainingAmount);
|
const transferAmount = makerBalance.sub(remainingAmount);
|
||||||
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
||||||
|
|
||||||
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
|
const callback = reportNodeCallbackErrors(done)((orderState: OrderState) => {
|
||||||
expect(orderState.isValid).to.be.true();
|
expect(orderState.isValid).to.be.true();
|
||||||
const validOrderState = orderState as OrderStateValid;
|
const validOrderState = orderState as OrderStateValid;
|
||||||
const orderRelevantState = validOrderState.orderRelevantState;
|
const orderRelevantState = validOrderState.orderRelevantState;
|
||||||
expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
|
expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
|
||||||
remainingAmount);
|
remainingAmount,
|
||||||
|
);
|
||||||
expect(orderRelevantState.remainingFillableTakerTokenAmount).to.be.bignumber.equal(
|
expect(orderRelevantState.remainingFillableTakerTokenAmount).to.be.bignumber.equal(
|
||||||
remainingAmount);
|
remainingAmount,
|
||||||
done();
|
);
|
||||||
});
|
});
|
||||||
zeroEx.orderStateWatcher.subscribe(callback);
|
zeroEx.orderStateWatcher.subscribe(callback);
|
||||||
await zeroEx.token.transferAsync(
|
await zeroEx.token.transferAsync(makerToken.address, maker, ZeroEx.NULL_ADDRESS, transferAmount);
|
||||||
makerToken.address, maker, ZeroEx.NULL_ADDRESS, transferAmount);
|
|
||||||
})().catch(done);
|
})().catch(done);
|
||||||
});
|
});
|
||||||
it('should equal remaining amount when partially cancelled and order has fees', (done: DoneCallback) => {
|
it('should equal remaining amount when partially cancelled and order has fees', (done: DoneCallback) => {
|
||||||
@@ -324,20 +380,27 @@ describe('OrderStateWatcher', () => {
|
|||||||
const makerFee = ZeroEx.toBaseUnitAmount(new BigNumber(5), decimals);
|
const makerFee = ZeroEx.toBaseUnitAmount(new BigNumber(5), decimals);
|
||||||
const feeRecipient = taker;
|
const feeRecipient = taker;
|
||||||
signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
|
signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
|
||||||
makerToken.address, takerToken.address, makerFee, takerFee, maker,
|
makerToken.address,
|
||||||
taker, fillableAmount, feeRecipient);
|
takerToken.address,
|
||||||
|
makerFee,
|
||||||
|
takerFee,
|
||||||
|
maker,
|
||||||
|
taker,
|
||||||
|
fillableAmount,
|
||||||
|
feeRecipient,
|
||||||
|
);
|
||||||
|
|
||||||
const remainingTokenAmount = ZeroEx.toBaseUnitAmount(new BigNumber(4), decimals);
|
const remainingTokenAmount = ZeroEx.toBaseUnitAmount(new BigNumber(4), decimals);
|
||||||
const transferTokenAmount = makerFee.sub(remainingTokenAmount);
|
const transferTokenAmount = makerFee.sub(remainingTokenAmount);
|
||||||
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
||||||
|
|
||||||
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
|
const callback = reportNodeCallbackErrors(done)((orderState: OrderState) => {
|
||||||
expect(orderState.isValid).to.be.true();
|
expect(orderState.isValid).to.be.true();
|
||||||
const validOrderState = orderState as OrderStateValid;
|
const validOrderState = orderState as OrderStateValid;
|
||||||
const orderRelevantState = validOrderState.orderRelevantState;
|
const orderRelevantState = validOrderState.orderRelevantState;
|
||||||
expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
|
expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
|
||||||
remainingTokenAmount);
|
remainingTokenAmount,
|
||||||
done();
|
);
|
||||||
});
|
});
|
||||||
zeroEx.orderStateWatcher.subscribe(callback);
|
zeroEx.orderStateWatcher.subscribe(callback);
|
||||||
await zeroEx.exchange.cancelOrderAsync(signedOrder, transferTokenAmount);
|
await zeroEx.exchange.cancelOrderAsync(signedOrder, transferTokenAmount);
|
||||||
@@ -349,8 +412,15 @@ describe('OrderStateWatcher', () => {
|
|||||||
const makerFee = ZeroEx.toBaseUnitAmount(new BigNumber(5), decimals);
|
const makerFee = ZeroEx.toBaseUnitAmount(new BigNumber(5), decimals);
|
||||||
const feeRecipient = taker;
|
const feeRecipient = taker;
|
||||||
signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
|
signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
|
||||||
makerToken.address, takerToken.address, makerFee, takerFee, maker,
|
makerToken.address,
|
||||||
taker, fillableAmount, feeRecipient);
|
takerToken.address,
|
||||||
|
makerFee,
|
||||||
|
takerFee,
|
||||||
|
maker,
|
||||||
|
taker,
|
||||||
|
fillableAmount,
|
||||||
|
feeRecipient,
|
||||||
|
);
|
||||||
|
|
||||||
const remainingFeeAmount = ZeroEx.toBaseUnitAmount(new BigNumber(3), decimals);
|
const remainingFeeAmount = ZeroEx.toBaseUnitAmount(new BigNumber(3), decimals);
|
||||||
|
|
||||||
@@ -358,17 +428,21 @@ describe('OrderStateWatcher', () => {
|
|||||||
const transferTokenAmount = makerFee.sub(remainingTokenAmount);
|
const transferTokenAmount = makerFee.sub(remainingTokenAmount);
|
||||||
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
||||||
|
|
||||||
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
|
const callback = reportNodeCallbackErrors(done)((orderState: OrderState) => {
|
||||||
const validOrderState = orderState as OrderStateValid;
|
const validOrderState = orderState as OrderStateValid;
|
||||||
const orderRelevantState = validOrderState.orderRelevantState;
|
const orderRelevantState = validOrderState.orderRelevantState;
|
||||||
expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
|
expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
|
||||||
remainingFeeAmount);
|
remainingFeeAmount,
|
||||||
done();
|
);
|
||||||
});
|
});
|
||||||
zeroEx.orderStateWatcher.subscribe(callback);
|
zeroEx.orderStateWatcher.subscribe(callback);
|
||||||
await zeroEx.token.setProxyAllowanceAsync(zrxTokenAddress, maker, remainingFeeAmount);
|
await zeroEx.token.setProxyAllowanceAsync(zrxTokenAddress, maker, remainingFeeAmount);
|
||||||
await zeroEx.token.transferAsync(
|
await zeroEx.token.transferAsync(
|
||||||
makerToken.address, maker, ZeroEx.NULL_ADDRESS, transferTokenAmount);
|
makerToken.address,
|
||||||
|
maker,
|
||||||
|
ZeroEx.NULL_ADDRESS,
|
||||||
|
transferTokenAmount,
|
||||||
|
);
|
||||||
})().catch(done);
|
})().catch(done);
|
||||||
});
|
});
|
||||||
it('should calculate full amount when all available and non-divisible', (done: DoneCallback) => {
|
it('should calculate full amount when all available and non-divisible', (done: DoneCallback) => {
|
||||||
@@ -377,38 +451,51 @@ describe('OrderStateWatcher', () => {
|
|||||||
const makerFee = ZeroEx.toBaseUnitAmount(new BigNumber(2), decimals);
|
const makerFee = ZeroEx.toBaseUnitAmount(new BigNumber(2), decimals);
|
||||||
const feeRecipient = taker;
|
const feeRecipient = taker;
|
||||||
signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
|
signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
|
||||||
makerToken.address, takerToken.address, makerFee, takerFee, maker,
|
makerToken.address,
|
||||||
taker, fillableAmount, feeRecipient);
|
takerToken.address,
|
||||||
|
makerFee,
|
||||||
|
takerFee,
|
||||||
|
maker,
|
||||||
|
taker,
|
||||||
|
fillableAmount,
|
||||||
|
feeRecipient,
|
||||||
|
);
|
||||||
|
|
||||||
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
||||||
|
|
||||||
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
|
const callback = reportNodeCallbackErrors(done)((orderState: OrderState) => {
|
||||||
const validOrderState = orderState as OrderStateValid;
|
const validOrderState = orderState as OrderStateValid;
|
||||||
const orderRelevantState = validOrderState.orderRelevantState;
|
const orderRelevantState = validOrderState.orderRelevantState;
|
||||||
expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
|
expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
|
||||||
fillableAmount);
|
fillableAmount,
|
||||||
done();
|
);
|
||||||
});
|
});
|
||||||
zeroEx.orderStateWatcher.subscribe(callback);
|
zeroEx.orderStateWatcher.subscribe(callback);
|
||||||
await zeroEx.token.setProxyAllowanceAsync(
|
await zeroEx.token.setProxyAllowanceAsync(
|
||||||
makerToken.address, maker, ZeroEx.toBaseUnitAmount(new BigNumber(100), decimals));
|
makerToken.address,
|
||||||
|
maker,
|
||||||
|
ZeroEx.toBaseUnitAmount(new BigNumber(100), decimals),
|
||||||
|
);
|
||||||
})().catch(done);
|
})().catch(done);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('should emit orderStateInvalid when watched order cancelled', (done: DoneCallback) => {
|
it('should emit orderStateInvalid when watched order cancelled', (done: DoneCallback) => {
|
||||||
(async () => {
|
(async () => {
|
||||||
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerToken.address, takerToken.address, maker, taker, fillableAmount,
|
makerToken.address,
|
||||||
|
takerToken.address,
|
||||||
|
maker,
|
||||||
|
taker,
|
||||||
|
fillableAmount,
|
||||||
);
|
);
|
||||||
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
||||||
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
||||||
|
|
||||||
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
|
const callback = reportNodeCallbackErrors(done)((orderState: OrderState) => {
|
||||||
expect(orderState.isValid).to.be.false();
|
expect(orderState.isValid).to.be.false();
|
||||||
const invalidOrderState = orderState as OrderStateInvalid;
|
const invalidOrderState = orderState as OrderStateInvalid;
|
||||||
expect(invalidOrderState.orderHash).to.be.equal(orderHash);
|
expect(invalidOrderState.orderHash).to.be.equal(orderHash);
|
||||||
expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.OrderRemainingFillAmountZero);
|
expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.OrderRemainingFillAmountZero);
|
||||||
done();
|
|
||||||
});
|
});
|
||||||
zeroEx.orderStateWatcher.subscribe(callback);
|
zeroEx.orderStateWatcher.subscribe(callback);
|
||||||
|
|
||||||
@@ -419,41 +506,48 @@ describe('OrderStateWatcher', () => {
|
|||||||
(async () => {
|
(async () => {
|
||||||
const remainingFillableAmountInBaseUnits = new BigNumber(100);
|
const remainingFillableAmountInBaseUnits = new BigNumber(100);
|
||||||
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerToken.address, takerToken.address, maker, taker, fillableAmount,
|
makerToken.address,
|
||||||
|
takerToken.address,
|
||||||
|
maker,
|
||||||
|
taker,
|
||||||
|
fillableAmount,
|
||||||
);
|
);
|
||||||
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
||||||
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
||||||
|
|
||||||
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
|
const callback = reportNodeCallbackErrors(done)((orderState: OrderState) => {
|
||||||
expect(orderState.isValid).to.be.false();
|
expect(orderState.isValid).to.be.false();
|
||||||
const invalidOrderState = orderState as OrderStateInvalid;
|
const invalidOrderState = orderState as OrderStateInvalid;
|
||||||
expect(invalidOrderState.orderHash).to.be.equal(orderHash);
|
expect(invalidOrderState.orderHash).to.be.equal(orderHash);
|
||||||
expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.OrderFillRoundingError);
|
expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.OrderFillRoundingError);
|
||||||
done();
|
|
||||||
});
|
});
|
||||||
zeroEx.orderStateWatcher.subscribe(callback);
|
zeroEx.orderStateWatcher.subscribe(callback);
|
||||||
await zeroEx.exchange.cancelOrderAsync(
|
await zeroEx.exchange.cancelOrderAsync(
|
||||||
signedOrder, fillableAmount.minus(remainingFillableAmountInBaseUnits),
|
signedOrder,
|
||||||
|
fillableAmount.minus(remainingFillableAmountInBaseUnits),
|
||||||
);
|
);
|
||||||
})().catch(done);
|
})().catch(done);
|
||||||
});
|
});
|
||||||
it('should emit orderStateValid when watched order partially cancelled', (done: DoneCallback) => {
|
it('should emit orderStateValid when watched order partially cancelled', (done: DoneCallback) => {
|
||||||
(async () => {
|
(async () => {
|
||||||
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerToken.address, takerToken.address, maker, taker, fillableAmount,
|
makerToken.address,
|
||||||
|
takerToken.address,
|
||||||
|
maker,
|
||||||
|
taker,
|
||||||
|
fillableAmount,
|
||||||
);
|
);
|
||||||
|
|
||||||
const cancelAmountInBaseUnits = new BigNumber(2);
|
const cancelAmountInBaseUnits = new BigNumber(2);
|
||||||
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
||||||
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
||||||
|
|
||||||
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
|
const callback = reportNodeCallbackErrors(done)((orderState: OrderState) => {
|
||||||
expect(orderState.isValid).to.be.true();
|
expect(orderState.isValid).to.be.true();
|
||||||
const validOrderState = orderState as OrderStateValid;
|
const validOrderState = orderState as OrderStateValid;
|
||||||
expect(validOrderState.orderHash).to.be.equal(orderHash);
|
expect(validOrderState.orderHash).to.be.equal(orderHash);
|
||||||
const orderRelevantState = validOrderState.orderRelevantState;
|
const orderRelevantState = validOrderState.orderRelevantState;
|
||||||
expect(orderRelevantState.cancelledTakerTokenAmount).to.be.bignumber.equal(cancelAmountInBaseUnits);
|
expect(orderRelevantState.cancelledTakerTokenAmount).to.be.bignumber.equal(cancelAmountInBaseUnits);
|
||||||
done();
|
|
||||||
});
|
});
|
||||||
zeroEx.orderStateWatcher.subscribe(callback);
|
zeroEx.orderStateWatcher.subscribe(callback);
|
||||||
await zeroEx.exchange.cancelOrderAsync(signedOrder, cancelAmountInBaseUnits);
|
await zeroEx.exchange.cancelOrderAsync(signedOrder, cancelAmountInBaseUnits);
|
||||||
|
|||||||
@@ -1,23 +1,23 @@
|
|||||||
import {BlockchainLifecycle} from '@0xproject/dev-utils';
|
import { BlockchainLifecycle, devConstants, web3Factory } from '@0xproject/dev-utils';
|
||||||
import BigNumber from 'bignumber.js';
|
import { BlockParamLiteral } from '@0xproject/types';
|
||||||
|
import { BigNumber } from '@0xproject/utils';
|
||||||
import * as chai from 'chai';
|
import * as chai from 'chai';
|
||||||
import * as Sinon from 'sinon';
|
import * as Sinon from 'sinon';
|
||||||
import * as Web3 from 'web3';
|
import * as Web3 from 'web3';
|
||||||
|
|
||||||
import {ExchangeContractErrs, SignedOrder, Token, ZeroEx, ZeroExError} from '../src';
|
import { ExchangeContractErrs, SignedOrder, Token, ZeroEx, ZeroExError } from '../src';
|
||||||
import {BlockParamLiteral, TradeSide, TransferType} from '../src/types';
|
import { TradeSide, TransferType } from '../src/types';
|
||||||
import {ExchangeTransferSimulator} from '../src/utils/exchange_transfer_simulator';
|
import { ExchangeTransferSimulator } from '../src/utils/exchange_transfer_simulator';
|
||||||
import {OrderValidationUtils} from '../src/utils/order_validation_utils';
|
import { OrderValidationUtils } from '../src/utils/order_validation_utils';
|
||||||
|
|
||||||
import {chaiSetup} from './utils/chai_setup';
|
import { chaiSetup } from './utils/chai_setup';
|
||||||
import {constants} from './utils/constants';
|
import { constants } from './utils/constants';
|
||||||
import {FillScenarios} from './utils/fill_scenarios';
|
import { FillScenarios } from './utils/fill_scenarios';
|
||||||
import {TokenUtils} from './utils/token_utils';
|
import { TokenUtils } from './utils/token_utils';
|
||||||
import {web3Factory} from './utils/web3_factory';
|
|
||||||
|
|
||||||
chaiSetup.configure();
|
chaiSetup.configure();
|
||||||
const expect = chai.expect;
|
const expect = chai.expect;
|
||||||
const blockchainLifecycle = new BlockchainLifecycle(constants.RPC_URL);
|
const blockchainLifecycle = new BlockchainLifecycle();
|
||||||
|
|
||||||
describe('OrderValidation', () => {
|
describe('OrderValidation', () => {
|
||||||
let web3: Web3;
|
let web3: Web3;
|
||||||
@@ -62,108 +62,152 @@ describe('OrderValidation', () => {
|
|||||||
describe('validateOrderFillableOrThrowAsync', () => {
|
describe('validateOrderFillableOrThrowAsync', () => {
|
||||||
it('should succeed if the order is fillable', async () => {
|
it('should succeed if the order is fillable', async () => {
|
||||||
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
makerTokenAddress,
|
||||||
);
|
takerTokenAddress,
|
||||||
await zeroEx.exchange.validateOrderFillableOrThrowAsync(
|
makerAddress,
|
||||||
signedOrder,
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
);
|
);
|
||||||
|
await zeroEx.exchange.validateOrderFillableOrThrowAsync(signedOrder);
|
||||||
});
|
});
|
||||||
it('should succeed if the order is asymmetric and fillable', async () => {
|
it('should succeed if the order is asymmetric and fillable', async () => {
|
||||||
const makerFillableAmount = fillableAmount;
|
const makerFillableAmount = fillableAmount;
|
||||||
const takerFillableAmount = fillableAmount.minus(4);
|
const takerFillableAmount = fillableAmount.minus(4);
|
||||||
const signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync(
|
const signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress,
|
makerTokenAddress,
|
||||||
makerFillableAmount, takerFillableAmount,
|
takerTokenAddress,
|
||||||
);
|
makerAddress,
|
||||||
await zeroEx.exchange.validateOrderFillableOrThrowAsync(
|
takerAddress,
|
||||||
signedOrder,
|
makerFillableAmount,
|
||||||
|
takerFillableAmount,
|
||||||
);
|
);
|
||||||
|
await zeroEx.exchange.validateOrderFillableOrThrowAsync(signedOrder);
|
||||||
});
|
});
|
||||||
it('should throw when the order is fully filled or cancelled', async () => {
|
it('should throw when the order is fully filled or cancelled', async () => {
|
||||||
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
makerTokenAddress,
|
||||||
|
takerTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
);
|
);
|
||||||
await zeroEx.exchange.cancelOrderAsync(signedOrder, fillableAmount);
|
await zeroEx.exchange.cancelOrderAsync(signedOrder, fillableAmount);
|
||||||
return expect(zeroEx.exchange.validateOrderFillableOrThrowAsync(
|
return expect(zeroEx.exchange.validateOrderFillableOrThrowAsync(signedOrder)).to.be.rejectedWith(
|
||||||
signedOrder,
|
ExchangeContractErrs.OrderRemainingFillAmountZero,
|
||||||
)).to.be.rejectedWith(ExchangeContractErrs.OrderRemainingFillAmountZero);
|
);
|
||||||
});
|
});
|
||||||
it('should throw when order is expired', async () => {
|
it('should throw when order is expired', async () => {
|
||||||
const expirationInPast = new BigNumber(1496826058); // 7th Jun 2017
|
const expirationInPast = new BigNumber(1496826058); // 7th Jun 2017
|
||||||
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress,
|
makerTokenAddress,
|
||||||
fillableAmount, expirationInPast,
|
takerTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
|
expirationInPast,
|
||||||
|
);
|
||||||
|
return expect(zeroEx.exchange.validateOrderFillableOrThrowAsync(signedOrder)).to.be.rejectedWith(
|
||||||
|
ExchangeContractErrs.OrderFillExpired,
|
||||||
);
|
);
|
||||||
return expect(zeroEx.exchange.validateOrderFillableOrThrowAsync(
|
|
||||||
signedOrder,
|
|
||||||
)).to.be.rejectedWith(ExchangeContractErrs.OrderFillExpired);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('validateFillOrderAndThrowIfInvalidAsync', () => {
|
describe('validateFillOrderAndThrowIfInvalidAsync', () => {
|
||||||
it('should throw when the fill amount is zero', async () => {
|
it('should throw when the fill amount is zero', async () => {
|
||||||
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
makerTokenAddress,
|
||||||
|
takerTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
);
|
);
|
||||||
const zeroFillAmount = new BigNumber(0);
|
const zeroFillAmount = new BigNumber(0);
|
||||||
return expect(zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(
|
return expect(
|
||||||
signedOrder, zeroFillAmount, takerAddress,
|
zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(signedOrder, zeroFillAmount, takerAddress),
|
||||||
)).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
||||||
});
|
});
|
||||||
it('should throw when the signature is invalid', async () => {
|
it('should throw when the signature is invalid', async () => {
|
||||||
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
makerTokenAddress,
|
||||||
|
takerTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
);
|
);
|
||||||
// 27 <--> 28
|
// 27 <--> 28
|
||||||
signedOrder.ecSignature.v = (28 - signedOrder.ecSignature.v) + 27;
|
signedOrder.ecSignature.v = 28 - signedOrder.ecSignature.v + 27;
|
||||||
return expect(zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(
|
return expect(
|
||||||
signedOrder, fillableAmount, takerAddress,
|
zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(signedOrder, fillableAmount, takerAddress),
|
||||||
)).to.be.rejectedWith(ZeroExError.InvalidSignature);
|
).to.be.rejectedWith(ZeroExError.InvalidSignature);
|
||||||
});
|
});
|
||||||
it('should throw when the order is fully filled or cancelled', async () => {
|
it('should throw when the order is fully filled or cancelled', async () => {
|
||||||
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
makerTokenAddress,
|
||||||
|
takerTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
);
|
);
|
||||||
await zeroEx.exchange.cancelOrderAsync(signedOrder, fillableAmount);
|
await zeroEx.exchange.cancelOrderAsync(signedOrder, fillableAmount);
|
||||||
return expect(zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(
|
return expect(
|
||||||
signedOrder, fillableAmount, takerAddress,
|
zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(signedOrder, fillableAmount, takerAddress),
|
||||||
)).to.be.rejectedWith(ExchangeContractErrs.OrderRemainingFillAmountZero);
|
).to.be.rejectedWith(ExchangeContractErrs.OrderRemainingFillAmountZero);
|
||||||
});
|
});
|
||||||
it('should throw when sender is not a taker', async () => {
|
it('should throw when sender is not a taker', async () => {
|
||||||
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
makerTokenAddress,
|
||||||
|
takerTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
);
|
);
|
||||||
const nonTakerAddress = userAddresses[6];
|
const nonTakerAddress = userAddresses[6];
|
||||||
return expect(zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(
|
return expect(
|
||||||
signedOrder, fillTakerAmount, nonTakerAddress,
|
zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(signedOrder, fillTakerAmount, nonTakerAddress),
|
||||||
)).to.be.rejectedWith(ExchangeContractErrs.TransactionSenderIsNotFillOrderTaker);
|
).to.be.rejectedWith(ExchangeContractErrs.TransactionSenderIsNotFillOrderTaker);
|
||||||
});
|
});
|
||||||
it('should throw when order is expired', async () => {
|
it('should throw when order is expired', async () => {
|
||||||
const expirationInPast = new BigNumber(1496826058); // 7th Jun 2017
|
const expirationInPast = new BigNumber(1496826058); // 7th Jun 2017
|
||||||
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress,
|
makerTokenAddress,
|
||||||
fillableAmount, expirationInPast,
|
takerTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
|
expirationInPast,
|
||||||
);
|
);
|
||||||
return expect(zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(
|
return expect(
|
||||||
signedOrder, fillTakerAmount, takerAddress,
|
zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(signedOrder, fillTakerAmount, takerAddress),
|
||||||
)).to.be.rejectedWith(ExchangeContractErrs.OrderFillExpired);
|
).to.be.rejectedWith(ExchangeContractErrs.OrderFillExpired);
|
||||||
});
|
});
|
||||||
it('should throw when there a rounding error would have occurred', async () => {
|
it('should throw when there a rounding error would have occurred', async () => {
|
||||||
const makerAmount = new BigNumber(3);
|
const makerAmount = new BigNumber(3);
|
||||||
const takerAmount = new BigNumber(5);
|
const takerAmount = new BigNumber(5);
|
||||||
const signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync(
|
const signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress,
|
makerTokenAddress,
|
||||||
makerAmount, takerAmount,
|
takerTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
makerAmount,
|
||||||
|
takerAmount,
|
||||||
);
|
);
|
||||||
const fillTakerAmountThatCausesRoundingError = new BigNumber(3);
|
const fillTakerAmountThatCausesRoundingError = new BigNumber(3);
|
||||||
return expect(zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(
|
return expect(
|
||||||
signedOrder, fillTakerAmountThatCausesRoundingError, takerAddress,
|
zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(
|
||||||
)).to.be.rejectedWith(ExchangeContractErrs.OrderFillRoundingError);
|
signedOrder,
|
||||||
|
fillTakerAmountThatCausesRoundingError,
|
||||||
|
takerAddress,
|
||||||
|
),
|
||||||
|
).to.be.rejectedWith(ExchangeContractErrs.OrderFillRoundingError);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('#validateFillOrKillOrderAndThrowIfInvalidAsync', () => {
|
describe('#validateFillOrKillOrderAndThrowIfInvalidAsync', () => {
|
||||||
it('should throw if remaining fillAmount is less then the desired fillAmount', async () => {
|
it('should throw if remaining fillAmount is less then the desired fillAmount', async () => {
|
||||||
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
makerTokenAddress,
|
||||||
|
takerTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
);
|
);
|
||||||
const tooLargeFillAmount = new BigNumber(7);
|
const tooLargeFillAmount = new BigNumber(7);
|
||||||
const fillAmountDifference = tooLargeFillAmount.minus(fillableAmount);
|
const fillAmountDifference = tooLargeFillAmount.minus(fillableAmount);
|
||||||
@@ -172,9 +216,13 @@ describe('OrderValidation', () => {
|
|||||||
await zeroEx.token.transferAsync(makerTokenAddress, coinbase, makerAddress, fillAmountDifference);
|
await zeroEx.token.transferAsync(makerTokenAddress, coinbase, makerAddress, fillAmountDifference);
|
||||||
await zeroEx.token.setProxyAllowanceAsync(makerTokenAddress, makerAddress, tooLargeFillAmount);
|
await zeroEx.token.setProxyAllowanceAsync(makerTokenAddress, makerAddress, tooLargeFillAmount);
|
||||||
|
|
||||||
return expect(zeroEx.exchange.validateFillOrKillOrderThrowIfInvalidAsync(
|
return expect(
|
||||||
signedOrder, tooLargeFillAmount, takerAddress,
|
zeroEx.exchange.validateFillOrKillOrderThrowIfInvalidAsync(
|
||||||
)).to.be.rejectedWith(ExchangeContractErrs.InsufficientRemainingFillAmount);
|
signedOrder,
|
||||||
|
tooLargeFillAmount,
|
||||||
|
takerAddress,
|
||||||
|
),
|
||||||
|
).to.be.rejectedWith(ExchangeContractErrs.InsufficientRemainingFillAmount);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('validateCancelOrderAndThrowIfInvalidAsync', () => {
|
describe('validateCancelOrderAndThrowIfInvalidAsync', () => {
|
||||||
@@ -186,27 +234,38 @@ describe('OrderValidation', () => {
|
|||||||
makerTokenAddress = makerToken.address;
|
makerTokenAddress = makerToken.address;
|
||||||
takerTokenAddress = takerToken.address;
|
takerTokenAddress = takerToken.address;
|
||||||
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
makerTokenAddress,
|
||||||
|
takerTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it('should throw when cancel amount is zero', async () => {
|
it('should throw when cancel amount is zero', async () => {
|
||||||
const zeroCancelAmount = new BigNumber(0);
|
const zeroCancelAmount = new BigNumber(0);
|
||||||
return expect(zeroEx.exchange.validateCancelOrderThrowIfInvalidAsync(signedOrder, zeroCancelAmount))
|
return expect(
|
||||||
.to.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero);
|
zeroEx.exchange.validateCancelOrderThrowIfInvalidAsync(signedOrder, zeroCancelAmount),
|
||||||
|
).to.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero);
|
||||||
});
|
});
|
||||||
it('should throw when order is expired', async () => {
|
it('should throw when order is expired', async () => {
|
||||||
const expirationInPast = new BigNumber(1496826058); // 7th Jun 2017
|
const expirationInPast = new BigNumber(1496826058); // 7th Jun 2017
|
||||||
const expiredSignedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
const expiredSignedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress,
|
makerTokenAddress,
|
||||||
fillableAmount, expirationInPast,
|
takerTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
|
expirationInPast,
|
||||||
);
|
);
|
||||||
return expect(zeroEx.exchange.validateCancelOrderThrowIfInvalidAsync(expiredSignedOrder, cancelAmount))
|
return expect(
|
||||||
.to.be.rejectedWith(ExchangeContractErrs.OrderCancelExpired);
|
zeroEx.exchange.validateCancelOrderThrowIfInvalidAsync(expiredSignedOrder, cancelAmount),
|
||||||
|
).to.be.rejectedWith(ExchangeContractErrs.OrderCancelExpired);
|
||||||
});
|
});
|
||||||
it('should throw when order is already cancelled or filled', async () => {
|
it('should throw when order is already cancelled or filled', async () => {
|
||||||
await zeroEx.exchange.cancelOrderAsync(signedOrder, fillableAmount);
|
await zeroEx.exchange.cancelOrderAsync(signedOrder, fillableAmount);
|
||||||
return expect(zeroEx.exchange.validateCancelOrderThrowIfInvalidAsync(signedOrder, fillableAmount))
|
return expect(
|
||||||
.to.be.rejectedWith(ExchangeContractErrs.OrderAlreadyCancelledOrFilled);
|
zeroEx.exchange.validateCancelOrderThrowIfInvalidAsync(signedOrder, fillableAmount),
|
||||||
|
).to.be.rejectedWith(ExchangeContractErrs.OrderAlreadyCancelledOrFilled);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('#validateFillOrderBalancesAllowancesThrowIfInvalidAsync', () => {
|
describe('#validateFillOrderBalancesAllowancesThrowIfInvalidAsync', () => {
|
||||||
@@ -224,82 +283,159 @@ describe('OrderValidation', () => {
|
|||||||
const makerFee = new BigNumber(2);
|
const makerFee = new BigNumber(2);
|
||||||
const takerFee = new BigNumber(2);
|
const takerFee = new BigNumber(2);
|
||||||
const signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
|
const signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerFee, takerFee,
|
makerTokenAddress,
|
||||||
makerAddress, takerAddress, fillableAmount, feeRecipient,
|
takerTokenAddress,
|
||||||
|
makerFee,
|
||||||
|
takerFee,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
|
feeRecipient,
|
||||||
);
|
);
|
||||||
await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
|
await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
|
||||||
exchangeTransferSimulator, signedOrder, fillableAmount, takerAddress, zrxTokenAddress,
|
exchangeTransferSimulator,
|
||||||
|
signedOrder,
|
||||||
|
fillableAmount,
|
||||||
|
takerAddress,
|
||||||
|
zrxTokenAddress,
|
||||||
);
|
);
|
||||||
expect(transferFromAsync.callCount).to.be.equal(4);
|
expect(transferFromAsync.callCount).to.be.equal(4);
|
||||||
expect(
|
expect(
|
||||||
transferFromAsync.getCall(0).calledWith(
|
transferFromAsync
|
||||||
makerTokenAddress, makerAddress, takerAddress, bigNumberMatch(fillableAmount),
|
.getCall(0)
|
||||||
TradeSide.Maker, TransferType.Trade,
|
.calledWith(
|
||||||
),
|
makerTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
bigNumberMatch(fillableAmount),
|
||||||
|
TradeSide.Maker,
|
||||||
|
TransferType.Trade,
|
||||||
|
),
|
||||||
).to.be.true();
|
).to.be.true();
|
||||||
expect(
|
expect(
|
||||||
transferFromAsync.getCall(1).calledWith(
|
transferFromAsync
|
||||||
takerTokenAddress, takerAddress, makerAddress, bigNumberMatch(fillableAmount),
|
.getCall(1)
|
||||||
TradeSide.Taker, TransferType.Trade,
|
.calledWith(
|
||||||
),
|
takerTokenAddress,
|
||||||
|
takerAddress,
|
||||||
|
makerAddress,
|
||||||
|
bigNumberMatch(fillableAmount),
|
||||||
|
TradeSide.Taker,
|
||||||
|
TransferType.Trade,
|
||||||
|
),
|
||||||
).to.be.true();
|
).to.be.true();
|
||||||
expect(
|
expect(
|
||||||
transferFromAsync.getCall(2).calledWith(
|
transferFromAsync
|
||||||
zrxTokenAddress, makerAddress, feeRecipient, bigNumberMatch(makerFee),
|
.getCall(2)
|
||||||
TradeSide.Maker, TransferType.Fee,
|
.calledWith(
|
||||||
),
|
zrxTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
feeRecipient,
|
||||||
|
bigNumberMatch(makerFee),
|
||||||
|
TradeSide.Maker,
|
||||||
|
TransferType.Fee,
|
||||||
|
),
|
||||||
).to.be.true();
|
).to.be.true();
|
||||||
expect(
|
expect(
|
||||||
transferFromAsync.getCall(3).calledWith(
|
transferFromAsync
|
||||||
zrxTokenAddress, takerAddress, feeRecipient, bigNumberMatch(takerFee),
|
.getCall(3)
|
||||||
TradeSide.Taker, TransferType.Fee,
|
.calledWith(
|
||||||
),
|
zrxTokenAddress,
|
||||||
|
takerAddress,
|
||||||
|
feeRecipient,
|
||||||
|
bigNumberMatch(takerFee),
|
||||||
|
TradeSide.Taker,
|
||||||
|
TransferType.Fee,
|
||||||
|
),
|
||||||
).to.be.true();
|
).to.be.true();
|
||||||
});
|
});
|
||||||
it('should call exchangeTransferSimulator.transferFrom with correct values for an open order', async () => {
|
it('should call exchangeTransferSimulator.transferFrom with correct values for an open order', async () => {
|
||||||
const makerFee = new BigNumber(2);
|
const makerFee = new BigNumber(2);
|
||||||
const takerFee = new BigNumber(2);
|
const takerFee = new BigNumber(2);
|
||||||
const signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
|
const signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerFee, takerFee,
|
makerTokenAddress,
|
||||||
makerAddress, ZeroEx.NULL_ADDRESS, fillableAmount, feeRecipient,
|
takerTokenAddress,
|
||||||
|
makerFee,
|
||||||
|
takerFee,
|
||||||
|
makerAddress,
|
||||||
|
ZeroEx.NULL_ADDRESS,
|
||||||
|
fillableAmount,
|
||||||
|
feeRecipient,
|
||||||
);
|
);
|
||||||
await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
|
await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
|
||||||
exchangeTransferSimulator, signedOrder, fillableAmount, takerAddress, zrxTokenAddress,
|
exchangeTransferSimulator,
|
||||||
|
signedOrder,
|
||||||
|
fillableAmount,
|
||||||
|
takerAddress,
|
||||||
|
zrxTokenAddress,
|
||||||
);
|
);
|
||||||
expect(transferFromAsync.callCount).to.be.equal(4);
|
expect(transferFromAsync.callCount).to.be.equal(4);
|
||||||
expect(
|
expect(
|
||||||
transferFromAsync.getCall(0).calledWith(
|
transferFromAsync
|
||||||
makerTokenAddress, makerAddress, takerAddress, bigNumberMatch(fillableAmount),
|
.getCall(0)
|
||||||
TradeSide.Maker, TransferType.Trade,
|
.calledWith(
|
||||||
),
|
makerTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
bigNumberMatch(fillableAmount),
|
||||||
|
TradeSide.Maker,
|
||||||
|
TransferType.Trade,
|
||||||
|
),
|
||||||
).to.be.true();
|
).to.be.true();
|
||||||
expect(
|
expect(
|
||||||
transferFromAsync.getCall(1).calledWith(
|
transferFromAsync
|
||||||
takerTokenAddress, takerAddress, makerAddress, bigNumberMatch(fillableAmount),
|
.getCall(1)
|
||||||
TradeSide.Taker, TransferType.Trade,
|
.calledWith(
|
||||||
),
|
takerTokenAddress,
|
||||||
|
takerAddress,
|
||||||
|
makerAddress,
|
||||||
|
bigNumberMatch(fillableAmount),
|
||||||
|
TradeSide.Taker,
|
||||||
|
TransferType.Trade,
|
||||||
|
),
|
||||||
).to.be.true();
|
).to.be.true();
|
||||||
expect(
|
expect(
|
||||||
transferFromAsync.getCall(2).calledWith(
|
transferFromAsync
|
||||||
zrxTokenAddress, makerAddress, feeRecipient, bigNumberMatch(makerFee),
|
.getCall(2)
|
||||||
TradeSide.Maker, TransferType.Fee,
|
.calledWith(
|
||||||
),
|
zrxTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
feeRecipient,
|
||||||
|
bigNumberMatch(makerFee),
|
||||||
|
TradeSide.Maker,
|
||||||
|
TransferType.Fee,
|
||||||
|
),
|
||||||
).to.be.true();
|
).to.be.true();
|
||||||
expect(
|
expect(
|
||||||
transferFromAsync.getCall(3).calledWith(
|
transferFromAsync
|
||||||
zrxTokenAddress, takerAddress, feeRecipient, bigNumberMatch(takerFee),
|
.getCall(3)
|
||||||
TradeSide.Taker, TransferType.Fee,
|
.calledWith(
|
||||||
),
|
zrxTokenAddress,
|
||||||
|
takerAddress,
|
||||||
|
feeRecipient,
|
||||||
|
bigNumberMatch(takerFee),
|
||||||
|
TradeSide.Taker,
|
||||||
|
TransferType.Fee,
|
||||||
|
),
|
||||||
).to.be.true();
|
).to.be.true();
|
||||||
});
|
});
|
||||||
it('should correctly round the fillMakerTokenAmount', async () => {
|
it('should correctly round the fillMakerTokenAmount', async () => {
|
||||||
const makerTokenAmount = new BigNumber(3);
|
const makerTokenAmount = new BigNumber(3);
|
||||||
const takerTokenAmount = new BigNumber(1);
|
const takerTokenAmount = new BigNumber(1);
|
||||||
const signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync(
|
const signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, makerTokenAmount, takerTokenAmount,
|
makerTokenAddress,
|
||||||
|
takerTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
makerTokenAmount,
|
||||||
|
takerTokenAmount,
|
||||||
);
|
);
|
||||||
await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
|
await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
|
||||||
exchangeTransferSimulator, signedOrder, takerTokenAmount, takerAddress, zrxTokenAddress,
|
exchangeTransferSimulator,
|
||||||
|
signedOrder,
|
||||||
|
takerTokenAmount,
|
||||||
|
takerAddress,
|
||||||
|
zrxTokenAddress,
|
||||||
);
|
);
|
||||||
expect(transferFromAsync.callCount).to.be.equal(4);
|
expect(transferFromAsync.callCount).to.be.equal(4);
|
||||||
const makerFillAmount = transferFromAsync.getCall(0).args[3];
|
const makerFillAmount = transferFromAsync.getCall(0).args[3];
|
||||||
@@ -309,12 +445,22 @@ describe('OrderValidation', () => {
|
|||||||
const makerFee = new BigNumber(2);
|
const makerFee = new BigNumber(2);
|
||||||
const takerFee = new BigNumber(4);
|
const takerFee = new BigNumber(4);
|
||||||
const signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
|
const signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerFee, takerFee, makerAddress, takerAddress,
|
makerTokenAddress,
|
||||||
fillableAmount, ZeroEx.NULL_ADDRESS,
|
takerTokenAddress,
|
||||||
|
makerFee,
|
||||||
|
takerFee,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
|
ZeroEx.NULL_ADDRESS,
|
||||||
);
|
);
|
||||||
const fillTakerTokenAmount = fillableAmount.div(2).round(0);
|
const fillTakerTokenAmount = fillableAmount.div(2).round(0);
|
||||||
await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
|
await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
|
||||||
exchangeTransferSimulator, signedOrder, fillTakerTokenAmount, takerAddress, zrxTokenAddress,
|
exchangeTransferSimulator,
|
||||||
|
signedOrder,
|
||||||
|
fillTakerTokenAmount,
|
||||||
|
takerAddress,
|
||||||
|
zrxTokenAddress,
|
||||||
);
|
);
|
||||||
const makerPartialFee = makerFee.div(2);
|
const makerPartialFee = makerFee.div(2);
|
||||||
const takerPartialFee = takerFee.div(2);
|
const takerPartialFee = takerFee.div(2);
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import BigNumber from 'bignumber.js';
|
import { BigNumber } from '@0xproject/utils';
|
||||||
import * as chai from 'chai';
|
import * as chai from 'chai';
|
||||||
import 'mocha';
|
import 'mocha';
|
||||||
|
|
||||||
import {ZeroEx} from '../src/0x';
|
import { ZeroEx } from '../src/0x';
|
||||||
import {RemainingFillableCalculator} from '../src/order_watcher/remaining_fillable_calculator';
|
import { RemainingFillableCalculator } from '../src/order_watcher/remaining_fillable_calculator';
|
||||||
import {ECSignature, SignedOrder} from '../src/types';
|
import { ECSignature, SignedOrder } from '../src/types';
|
||||||
|
|
||||||
import {chaiSetup} from './utils/chai_setup';
|
import { chaiSetup } from './utils/chai_setup';
|
||||||
|
|
||||||
chaiSetup.configure();
|
chaiSetup.configure();
|
||||||
const expect = chai.expect;
|
const expect = chai.expect;
|
||||||
@@ -26,29 +26,34 @@ describe('RemainingFillableCalculator', () => {
|
|||||||
const decimals: number = 4;
|
const decimals: number = 4;
|
||||||
const zero: BigNumber = new BigNumber(0);
|
const zero: BigNumber = new BigNumber(0);
|
||||||
const zeroAddress = '0x0';
|
const zeroAddress = '0x0';
|
||||||
const signature: ECSignature = {v: 27, r: '', s: ''};
|
const signature: ECSignature = { v: 27, r: '', s: '' };
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
[makerAmount, takerAmount, makerFeeAmount] = [ZeroEx.toBaseUnitAmount(new BigNumber(50), decimals),
|
[makerAmount, takerAmount, makerFeeAmount] = [
|
||||||
ZeroEx.toBaseUnitAmount(new BigNumber(5), decimals),
|
ZeroEx.toBaseUnitAmount(new BigNumber(50), decimals),
|
||||||
ZeroEx.toBaseUnitAmount(new BigNumber(1), decimals)];
|
ZeroEx.toBaseUnitAmount(new BigNumber(5), decimals),
|
||||||
|
ZeroEx.toBaseUnitAmount(new BigNumber(1), decimals),
|
||||||
|
];
|
||||||
[transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount] = [
|
[transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount] = [
|
||||||
ZeroEx.toBaseUnitAmount(new BigNumber(50), decimals),
|
ZeroEx.toBaseUnitAmount(new BigNumber(50), decimals),
|
||||||
ZeroEx.toBaseUnitAmount(new BigNumber(5), decimals)];
|
ZeroEx.toBaseUnitAmount(new BigNumber(5), decimals),
|
||||||
|
];
|
||||||
});
|
});
|
||||||
function buildSignedOrder(): SignedOrder {
|
function buildSignedOrder(): SignedOrder {
|
||||||
return { ecSignature: signature,
|
return {
|
||||||
exchangeContractAddress: zeroAddress,
|
ecSignature: signature,
|
||||||
feeRecipient: zeroAddress,
|
exchangeContractAddress: zeroAddress,
|
||||||
maker: zeroAddress,
|
feeRecipient: zeroAddress,
|
||||||
taker: zeroAddress,
|
maker: zeroAddress,
|
||||||
makerFee: makerFeeAmount,
|
taker: zeroAddress,
|
||||||
takerFee: zero,
|
makerFee: makerFeeAmount,
|
||||||
makerTokenAmount: makerAmount,
|
takerFee: zero,
|
||||||
takerTokenAmount: takerAmount,
|
makerTokenAmount: makerAmount,
|
||||||
makerTokenAddress: makerToken,
|
takerTokenAmount: takerAmount,
|
||||||
takerTokenAddress: takerToken,
|
makerTokenAddress: makerToken,
|
||||||
salt: zero,
|
takerTokenAddress: takerToken,
|
||||||
expirationUnixTimestampSec: zero };
|
salt: zero,
|
||||||
|
expirationUnixTimestampSec: zero,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
describe('Maker token is NOT ZRX', () => {
|
describe('Maker token is NOT ZRX', () => {
|
||||||
before(async () => {
|
before(async () => {
|
||||||
@@ -57,23 +62,38 @@ describe('RemainingFillableCalculator', () => {
|
|||||||
it('calculates the correct amount when unfilled and funds available', () => {
|
it('calculates the correct amount when unfilled and funds available', () => {
|
||||||
signedOrder = buildSignedOrder();
|
signedOrder = buildSignedOrder();
|
||||||
remainingMakerTokenAmount = signedOrder.makerTokenAmount;
|
remainingMakerTokenAmount = signedOrder.makerTokenAmount;
|
||||||
calculator = new RemainingFillableCalculator(signedOrder, isMakerTokenZRX,
|
calculator = new RemainingFillableCalculator(
|
||||||
transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount, remainingMakerTokenAmount);
|
signedOrder,
|
||||||
|
isMakerTokenZRX,
|
||||||
|
transferrableMakerTokenAmount,
|
||||||
|
transferrableMakerFeeTokenAmount,
|
||||||
|
remainingMakerTokenAmount,
|
||||||
|
);
|
||||||
expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(remainingMakerTokenAmount);
|
expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(remainingMakerTokenAmount);
|
||||||
});
|
});
|
||||||
it('calculates the correct amount when partially filled and funds available', () => {
|
it('calculates the correct amount when partially filled and funds available', () => {
|
||||||
signedOrder = buildSignedOrder();
|
signedOrder = buildSignedOrder();
|
||||||
remainingMakerTokenAmount = ZeroEx.toBaseUnitAmount(new BigNumber(1), decimals);
|
remainingMakerTokenAmount = ZeroEx.toBaseUnitAmount(new BigNumber(1), decimals);
|
||||||
calculator = new RemainingFillableCalculator(signedOrder, isMakerTokenZRX,
|
calculator = new RemainingFillableCalculator(
|
||||||
transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount, remainingMakerTokenAmount);
|
signedOrder,
|
||||||
|
isMakerTokenZRX,
|
||||||
|
transferrableMakerTokenAmount,
|
||||||
|
transferrableMakerFeeTokenAmount,
|
||||||
|
remainingMakerTokenAmount,
|
||||||
|
);
|
||||||
expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(remainingMakerTokenAmount);
|
expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(remainingMakerTokenAmount);
|
||||||
});
|
});
|
||||||
it('calculates the amount to be 0 when all fee funds are transferred', () => {
|
it('calculates the amount to be 0 when all fee funds are transferred', () => {
|
||||||
signedOrder = buildSignedOrder();
|
signedOrder = buildSignedOrder();
|
||||||
transferrableMakerFeeTokenAmount = zero;
|
transferrableMakerFeeTokenAmount = zero;
|
||||||
remainingMakerTokenAmount = signedOrder.makerTokenAmount;
|
remainingMakerTokenAmount = signedOrder.makerTokenAmount;
|
||||||
calculator = new RemainingFillableCalculator(signedOrder, isMakerTokenZRX,
|
calculator = new RemainingFillableCalculator(
|
||||||
transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount, remainingMakerTokenAmount);
|
signedOrder,
|
||||||
|
isMakerTokenZRX,
|
||||||
|
transferrableMakerTokenAmount,
|
||||||
|
transferrableMakerFeeTokenAmount,
|
||||||
|
remainingMakerTokenAmount,
|
||||||
|
);
|
||||||
expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(zero);
|
expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(zero);
|
||||||
});
|
});
|
||||||
it('calculates the correct amount when balance is less than remaining fillable', () => {
|
it('calculates the correct amount when balance is less than remaining fillable', () => {
|
||||||
@@ -81,41 +101,58 @@ describe('RemainingFillableCalculator', () => {
|
|||||||
const partiallyFilledAmount = ZeroEx.toBaseUnitAmount(new BigNumber(2), decimals);
|
const partiallyFilledAmount = ZeroEx.toBaseUnitAmount(new BigNumber(2), decimals);
|
||||||
remainingMakerTokenAmount = signedOrder.makerTokenAmount.minus(partiallyFilledAmount);
|
remainingMakerTokenAmount = signedOrder.makerTokenAmount.minus(partiallyFilledAmount);
|
||||||
transferrableMakerTokenAmount = remainingMakerTokenAmount.minus(partiallyFilledAmount);
|
transferrableMakerTokenAmount = remainingMakerTokenAmount.minus(partiallyFilledAmount);
|
||||||
calculator = new RemainingFillableCalculator(signedOrder, isMakerTokenZRX,
|
calculator = new RemainingFillableCalculator(
|
||||||
transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount, remainingMakerTokenAmount);
|
signedOrder,
|
||||||
|
isMakerTokenZRX,
|
||||||
|
transferrableMakerTokenAmount,
|
||||||
|
transferrableMakerFeeTokenAmount,
|
||||||
|
remainingMakerTokenAmount,
|
||||||
|
);
|
||||||
expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(transferrableMakerTokenAmount);
|
expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(transferrableMakerTokenAmount);
|
||||||
});
|
});
|
||||||
describe('Order to Fee Ratio is < 1', () => {
|
describe('Order to Fee Ratio is < 1', () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
[makerAmount, takerAmount, makerFeeAmount] = [ZeroEx.toBaseUnitAmount(new BigNumber(3), decimals),
|
[makerAmount, takerAmount, makerFeeAmount] = [
|
||||||
ZeroEx.toBaseUnitAmount(new BigNumber(6), decimals),
|
ZeroEx.toBaseUnitAmount(new BigNumber(3), decimals),
|
||||||
ZeroEx.toBaseUnitAmount(new BigNumber(6), decimals)];
|
ZeroEx.toBaseUnitAmount(new BigNumber(6), decimals),
|
||||||
|
ZeroEx.toBaseUnitAmount(new BigNumber(6), decimals),
|
||||||
|
];
|
||||||
});
|
});
|
||||||
it('calculates the correct amount when funds unavailable', () => {
|
it('calculates the correct amount when funds unavailable', () => {
|
||||||
signedOrder = buildSignedOrder();
|
signedOrder = buildSignedOrder();
|
||||||
remainingMakerTokenAmount = signedOrder.makerTokenAmount;
|
remainingMakerTokenAmount = signedOrder.makerTokenAmount;
|
||||||
const transferredAmount = ZeroEx.toBaseUnitAmount(new BigNumber(2), decimals);
|
const transferredAmount = ZeroEx.toBaseUnitAmount(new BigNumber(2), decimals);
|
||||||
transferrableMakerTokenAmount = remainingMakerTokenAmount.minus(transferredAmount);
|
transferrableMakerTokenAmount = remainingMakerTokenAmount.minus(transferredAmount);
|
||||||
calculator = new RemainingFillableCalculator(signedOrder, isMakerTokenZRX,
|
calculator = new RemainingFillableCalculator(
|
||||||
transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount,
|
signedOrder,
|
||||||
remainingMakerTokenAmount);
|
isMakerTokenZRX,
|
||||||
|
transferrableMakerTokenAmount,
|
||||||
|
transferrableMakerFeeTokenAmount,
|
||||||
|
remainingMakerTokenAmount,
|
||||||
|
);
|
||||||
expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(transferrableMakerTokenAmount);
|
expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(transferrableMakerTokenAmount);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('Ratio is not evenly divisble', () => {
|
describe('Ratio is not evenly divisble', () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
[makerAmount, takerAmount, makerFeeAmount] = [ZeroEx.toBaseUnitAmount(new BigNumber(3), decimals),
|
[makerAmount, takerAmount, makerFeeAmount] = [
|
||||||
ZeroEx.toBaseUnitAmount(new BigNumber(7), decimals),
|
ZeroEx.toBaseUnitAmount(new BigNumber(3), decimals),
|
||||||
ZeroEx.toBaseUnitAmount(new BigNumber(7), decimals)];
|
ZeroEx.toBaseUnitAmount(new BigNumber(7), decimals),
|
||||||
|
ZeroEx.toBaseUnitAmount(new BigNumber(7), decimals),
|
||||||
|
];
|
||||||
});
|
});
|
||||||
it('calculates the correct amount when funds unavailable', () => {
|
it('calculates the correct amount when funds unavailable', () => {
|
||||||
signedOrder = buildSignedOrder();
|
signedOrder = buildSignedOrder();
|
||||||
remainingMakerTokenAmount = signedOrder.makerTokenAmount;
|
remainingMakerTokenAmount = signedOrder.makerTokenAmount;
|
||||||
const transferredAmount = ZeroEx.toBaseUnitAmount(new BigNumber(2), decimals);
|
const transferredAmount = ZeroEx.toBaseUnitAmount(new BigNumber(2), decimals);
|
||||||
transferrableMakerTokenAmount = remainingMakerTokenAmount.minus(transferredAmount);
|
transferrableMakerTokenAmount = remainingMakerTokenAmount.minus(transferredAmount);
|
||||||
calculator = new RemainingFillableCalculator(signedOrder, isMakerTokenZRX,
|
calculator = new RemainingFillableCalculator(
|
||||||
transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount,
|
signedOrder,
|
||||||
remainingMakerTokenAmount);
|
isMakerTokenZRX,
|
||||||
|
transferrableMakerTokenAmount,
|
||||||
|
transferrableMakerFeeTokenAmount,
|
||||||
|
remainingMakerTokenAmount,
|
||||||
|
);
|
||||||
const calculatedFillableAmount = calculator.computeRemainingMakerFillable();
|
const calculatedFillableAmount = calculator.computeRemainingMakerFillable();
|
||||||
expect(calculatedFillableAmount.lessThanOrEqualTo(transferrableMakerTokenAmount)).to.be.true();
|
expect(calculatedFillableAmount.lessThanOrEqualTo(transferrableMakerTokenAmount)).to.be.true();
|
||||||
expect(calculatedFillableAmount).to.be.bignumber.greaterThan(new BigNumber(0));
|
expect(calculatedFillableAmount).to.be.bignumber.greaterThan(new BigNumber(0));
|
||||||
@@ -134,15 +171,25 @@ describe('RemainingFillableCalculator', () => {
|
|||||||
transferrableMakerTokenAmount = makerAmount.plus(makerFeeAmount);
|
transferrableMakerTokenAmount = makerAmount.plus(makerFeeAmount);
|
||||||
transferrableMakerFeeTokenAmount = transferrableMakerTokenAmount;
|
transferrableMakerFeeTokenAmount = transferrableMakerTokenAmount;
|
||||||
remainingMakerTokenAmount = signedOrder.makerTokenAmount;
|
remainingMakerTokenAmount = signedOrder.makerTokenAmount;
|
||||||
calculator = new RemainingFillableCalculator(signedOrder, isMakerTokenZRX,
|
calculator = new RemainingFillableCalculator(
|
||||||
transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount, remainingMakerTokenAmount);
|
signedOrder,
|
||||||
|
isMakerTokenZRX,
|
||||||
|
transferrableMakerTokenAmount,
|
||||||
|
transferrableMakerFeeTokenAmount,
|
||||||
|
remainingMakerTokenAmount,
|
||||||
|
);
|
||||||
expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(remainingMakerTokenAmount);
|
expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(remainingMakerTokenAmount);
|
||||||
});
|
});
|
||||||
it('calculates the correct amount when partially filled and funds available', () => {
|
it('calculates the correct amount when partially filled and funds available', () => {
|
||||||
signedOrder = buildSignedOrder();
|
signedOrder = buildSignedOrder();
|
||||||
remainingMakerTokenAmount = ZeroEx.toBaseUnitAmount(new BigNumber(1), decimals);
|
remainingMakerTokenAmount = ZeroEx.toBaseUnitAmount(new BigNumber(1), decimals);
|
||||||
calculator = new RemainingFillableCalculator(signedOrder, isMakerTokenZRX,
|
calculator = new RemainingFillableCalculator(
|
||||||
transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount, remainingMakerTokenAmount);
|
signedOrder,
|
||||||
|
isMakerTokenZRX,
|
||||||
|
transferrableMakerTokenAmount,
|
||||||
|
transferrableMakerFeeTokenAmount,
|
||||||
|
remainingMakerTokenAmount,
|
||||||
|
);
|
||||||
expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(remainingMakerTokenAmount);
|
expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(remainingMakerTokenAmount);
|
||||||
});
|
});
|
||||||
it('calculates the amount to be 0 when all fee funds are transferred', () => {
|
it('calculates the amount to be 0 when all fee funds are transferred', () => {
|
||||||
@@ -150,8 +197,13 @@ describe('RemainingFillableCalculator', () => {
|
|||||||
transferrableMakerTokenAmount = zero;
|
transferrableMakerTokenAmount = zero;
|
||||||
transferrableMakerFeeTokenAmount = zero;
|
transferrableMakerFeeTokenAmount = zero;
|
||||||
remainingMakerTokenAmount = signedOrder.makerTokenAmount;
|
remainingMakerTokenAmount = signedOrder.makerTokenAmount;
|
||||||
calculator = new RemainingFillableCalculator(signedOrder, isMakerTokenZRX,
|
calculator = new RemainingFillableCalculator(
|
||||||
transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount, remainingMakerTokenAmount);
|
signedOrder,
|
||||||
|
isMakerTokenZRX,
|
||||||
|
transferrableMakerTokenAmount,
|
||||||
|
transferrableMakerFeeTokenAmount,
|
||||||
|
remainingMakerTokenAmount,
|
||||||
|
);
|
||||||
expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(zero);
|
expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(zero);
|
||||||
});
|
});
|
||||||
it('calculates the correct amount when balance is less than remaining fillable', () => {
|
it('calculates the correct amount when balance is less than remaining fillable', () => {
|
||||||
@@ -163,8 +215,13 @@ describe('RemainingFillableCalculator', () => {
|
|||||||
|
|
||||||
const orderToFeeRatio = signedOrder.makerTokenAmount.dividedToIntegerBy(signedOrder.makerFee);
|
const orderToFeeRatio = signedOrder.makerTokenAmount.dividedToIntegerBy(signedOrder.makerFee);
|
||||||
const expectedFillableAmount = new BigNumber(450980);
|
const expectedFillableAmount = new BigNumber(450980);
|
||||||
calculator = new RemainingFillableCalculator(signedOrder, isMakerTokenZRX,
|
calculator = new RemainingFillableCalculator(
|
||||||
transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount, remainingMakerTokenAmount);
|
signedOrder,
|
||||||
|
isMakerTokenZRX,
|
||||||
|
transferrableMakerTokenAmount,
|
||||||
|
transferrableMakerFeeTokenAmount,
|
||||||
|
remainingMakerTokenAmount,
|
||||||
|
);
|
||||||
const calculatedFillableAmount = calculator.computeRemainingMakerFillable();
|
const calculatedFillableAmount = calculator.computeRemainingMakerFillable();
|
||||||
const numberOfFillsInRatio = calculatedFillableAmount.dividedToIntegerBy(orderToFeeRatio);
|
const numberOfFillsInRatio = calculatedFillableAmount.dividedToIntegerBy(orderToFeeRatio);
|
||||||
const calculatedFillableAmountPlusFees = calculatedFillableAmount.plus(numberOfFillsInRatio);
|
const calculatedFillableAmountPlusFees = calculatedFillableAmount.plus(numberOfFillsInRatio);
|
||||||
|
|||||||
@@ -1,28 +1,19 @@
|
|||||||
import {BlockchainLifecycle} from '@0xproject/dev-utils';
|
import { BlockchainLifecycle, devConstants, web3Factory } from '@0xproject/dev-utils';
|
||||||
import BigNumber from 'bignumber.js';
|
import { BigNumber } from '@0xproject/utils';
|
||||||
import * as chai from 'chai';
|
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import 'mocha';
|
import 'mocha';
|
||||||
import * as Sinon from 'sinon';
|
import * as Sinon from 'sinon';
|
||||||
import * as Web3 from 'web3';
|
import * as Web3 from 'web3';
|
||||||
|
|
||||||
import {
|
import { ApprovalContractEventArgs, DecodedLogEvent, Token, TokenEvents, ZeroEx } from '../src';
|
||||||
ApprovalContractEventArgs,
|
import { DoneCallback } from '../src/types';
|
||||||
DecodedLogEvent,
|
|
||||||
Token,
|
|
||||||
TokenEvents,
|
|
||||||
ZeroEx,
|
|
||||||
} from '../src';
|
|
||||||
import {DoneCallback} from '../src/types';
|
|
||||||
|
|
||||||
import {chaiSetup} from './utils/chai_setup';
|
import { chaiSetup } from './utils/chai_setup';
|
||||||
import {constants} from './utils/constants';
|
import { constants } from './utils/constants';
|
||||||
import {reportCallbackErrors} from './utils/report_callback_errors';
|
import { assertNodeCallbackError } from './utils/report_callback_errors';
|
||||||
import {web3Factory} from './utils/web3_factory';
|
|
||||||
|
|
||||||
chaiSetup.configure();
|
chaiSetup.configure();
|
||||||
const expect = chai.expect;
|
const blockchainLifecycle = new BlockchainLifecycle();
|
||||||
const blockchainLifecycle = new BlockchainLifecycle(constants.RPC_URL);
|
|
||||||
|
|
||||||
describe('SubscriptionTest', () => {
|
describe('SubscriptionTest', () => {
|
||||||
let web3: Web3;
|
let web3: Web3;
|
||||||
@@ -65,50 +56,26 @@ describe('SubscriptionTest', () => {
|
|||||||
it('Should receive the Error when an error occurs while fetching the block', (done: DoneCallback) => {
|
it('Should receive the Error when an error occurs while fetching the block', (done: DoneCallback) => {
|
||||||
(async () => {
|
(async () => {
|
||||||
const errMsg = 'Error fetching block';
|
const errMsg = 'Error fetching block';
|
||||||
const callback = reportCallbackErrors(done)(
|
const callback = assertNodeCallbackError(done, errMsg);
|
||||||
(err: Error, logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
|
stubs = [Sinon.stub((zeroEx as any)._web3Wrapper, 'getBlockAsync').throws(new Error(errMsg))];
|
||||||
expect(err.message).to.be.equal(errMsg);
|
zeroEx.token.subscribe(tokenAddress, TokenEvents.Approval, indexFilterValues, callback);
|
||||||
expect(logEvent).to.be.undefined();
|
|
||||||
done();
|
|
||||||
},
|
|
||||||
);
|
|
||||||
stubs = [
|
|
||||||
Sinon.stub((zeroEx as any)._web3Wrapper, 'getBlockAsync')
|
|
||||||
.throws(new Error(errMsg)),
|
|
||||||
];
|
|
||||||
zeroEx.token.subscribe(
|
|
||||||
tokenAddress, TokenEvents.Approval, indexFilterValues, callback);
|
|
||||||
await zeroEx.token.setAllowanceAsync(tokenAddress, coinbase, addressWithoutFunds, allowanceAmount);
|
await zeroEx.token.setAllowanceAsync(tokenAddress, coinbase, addressWithoutFunds, allowanceAmount);
|
||||||
})().catch(done);
|
})().catch(done);
|
||||||
});
|
});
|
||||||
it('Should receive the Error when an error occurs while reconciling the new block', (done: DoneCallback) => {
|
it('Should receive the Error when an error occurs while reconciling the new block', (done: DoneCallback) => {
|
||||||
(async () => {
|
(async () => {
|
||||||
const errMsg = 'Error fetching logs';
|
const errMsg = 'Error fetching logs';
|
||||||
const callback = reportCallbackErrors(done)(
|
const callback = assertNodeCallbackError(done, errMsg);
|
||||||
(err: Error, logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
|
stubs = [Sinon.stub((zeroEx as any)._web3Wrapper, 'getLogsAsync').throws(new Error(errMsg))];
|
||||||
expect(err.message).to.be.equal(errMsg);
|
zeroEx.token.subscribe(tokenAddress, TokenEvents.Approval, indexFilterValues, callback);
|
||||||
expect(logEvent).to.be.undefined();
|
|
||||||
done();
|
|
||||||
},
|
|
||||||
);
|
|
||||||
stubs = [
|
|
||||||
Sinon.stub((zeroEx as any)._web3Wrapper, 'getLogsAsync')
|
|
||||||
.throws(new Error(errMsg)),
|
|
||||||
];
|
|
||||||
zeroEx.token.subscribe(
|
|
||||||
tokenAddress, TokenEvents.Approval, indexFilterValues, callback);
|
|
||||||
await zeroEx.token.setAllowanceAsync(tokenAddress, coinbase, addressWithoutFunds, allowanceAmount);
|
await zeroEx.token.setAllowanceAsync(tokenAddress, coinbase, addressWithoutFunds, allowanceAmount);
|
||||||
})().catch(done);
|
})().catch(done);
|
||||||
});
|
});
|
||||||
it('Should allow unsubscribeAll to be called successfully after an error', (done: DoneCallback) => {
|
it('Should allow unsubscribeAll to be called successfully after an error', (done: DoneCallback) => {
|
||||||
(async () => {
|
(async () => {
|
||||||
const callback = (err: Error, logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => _.noop;
|
const callback = (err: Error | null, logEvent?: DecodedLogEvent<ApprovalContractEventArgs>) => _.noop;
|
||||||
zeroEx.token.subscribe(
|
zeroEx.token.subscribe(tokenAddress, TokenEvents.Approval, indexFilterValues, callback);
|
||||||
tokenAddress, TokenEvents.Approval, indexFilterValues, callback);
|
stubs = [Sinon.stub((zeroEx as any)._web3Wrapper, 'getBlockAsync').throws(new Error('JSON RPC error'))];
|
||||||
stubs = [
|
|
||||||
Sinon.stub((zeroEx as any)._web3Wrapper, 'getBlockAsync')
|
|
||||||
.throws(new Error('JSON RPC error')),
|
|
||||||
];
|
|
||||||
zeroEx.token.unsubscribeAll();
|
zeroEx.token.unsubscribeAll();
|
||||||
done();
|
done();
|
||||||
})().catch(done);
|
})().catch(done);
|
||||||
|
|||||||
@@ -1,28 +1,27 @@
|
|||||||
import {BlockchainLifecycle} from '@0xproject/dev-utils';
|
import { BlockchainLifecycle, devConstants, web3Factory } from '@0xproject/dev-utils';
|
||||||
import {schemas, SchemaValidator} from '@0xproject/json-schemas';
|
import { schemas, SchemaValidator } from '@0xproject/json-schemas';
|
||||||
import * as chai from 'chai';
|
import * as chai from 'chai';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import 'mocha';
|
import 'mocha';
|
||||||
|
|
||||||
import {Token, ZeroEx} from '../src';
|
import { Token, ZeroEx } from '../src';
|
||||||
|
|
||||||
import {chaiSetup} from './utils/chai_setup';
|
import { chaiSetup } from './utils/chai_setup';
|
||||||
import {constants} from './utils/constants';
|
import { constants } from './utils/constants';
|
||||||
import {web3Factory} from './utils/web3_factory';
|
|
||||||
|
|
||||||
chaiSetup.configure();
|
chaiSetup.configure();
|
||||||
const expect = chai.expect;
|
const expect = chai.expect;
|
||||||
const blockchainLifecycle = new BlockchainLifecycle(constants.RPC_URL);
|
const blockchainLifecycle = new BlockchainLifecycle();
|
||||||
|
|
||||||
const TOKEN_REGISTRY_SIZE_AFTER_MIGRATION = 7;
|
const TOKEN_REGISTRY_SIZE_AFTER_MIGRATION = 7;
|
||||||
|
|
||||||
describe('TokenRegistryWrapper', () => {
|
describe('TokenRegistryWrapper', () => {
|
||||||
let zeroEx: ZeroEx;
|
let zeroEx: ZeroEx;
|
||||||
let tokens: Token[];
|
let tokens: Token[];
|
||||||
const tokenAddressBySymbol: {[symbol: string]: string} = {};
|
const tokenAddressBySymbol: { [symbol: string]: string } = {};
|
||||||
const tokenAddressByName: {[symbol: string]: string} = {};
|
const tokenAddressByName: { [symbol: string]: string } = {};
|
||||||
const tokenBySymbol: {[symbol: string]: Token} = {};
|
const tokenBySymbol: { [symbol: string]: Token } = {};
|
||||||
const tokenByName: {[symbol: string]: Token} = {};
|
const tokenByName: { [symbol: string]: Token } = {};
|
||||||
const registeredSymbol = 'ZRX';
|
const registeredSymbol = 'ZRX';
|
||||||
const registeredName = '0x Protocol Token';
|
const registeredName = '0x Protocol Token';
|
||||||
const unregisteredSymbol = 'MAL';
|
const unregisteredSymbol = 'MAL';
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
|
import { web3Factory } from '@0xproject/dev-utils';
|
||||||
import * as chai from 'chai';
|
import * as chai from 'chai';
|
||||||
|
|
||||||
import {ZeroEx} from '../src';
|
import { ZeroEx } from '../src';
|
||||||
|
|
||||||
import {chaiSetup} from './utils/chai_setup';
|
import { chaiSetup } from './utils/chai_setup';
|
||||||
import {constants} from './utils/constants';
|
import { constants } from './utils/constants';
|
||||||
import {web3Factory} from './utils/web3_factory';
|
|
||||||
|
|
||||||
chaiSetup.configure();
|
chaiSetup.configure();
|
||||||
const expect = chai.expect;
|
const expect = chai.expect;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import {BlockchainLifecycle} from '@0xproject/dev-utils';
|
import { BlockchainLifecycle, devConstants, web3Factory } from '@0xproject/dev-utils';
|
||||||
import {Web3Wrapper} from '@0xproject/web3-wrapper';
|
import { BigNumber } from '@0xproject/utils';
|
||||||
import BigNumber from 'bignumber.js';
|
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||||
import * as chai from 'chai';
|
import * as chai from 'chai';
|
||||||
import 'mocha';
|
import 'mocha';
|
||||||
import * as Web3 from 'web3';
|
import * as Web3 from 'web3';
|
||||||
@@ -16,16 +16,16 @@ import {
|
|||||||
ZeroEx,
|
ZeroEx,
|
||||||
ZeroExError,
|
ZeroExError,
|
||||||
} from '../src';
|
} from '../src';
|
||||||
import {DoneCallback} from '../src/types';
|
import { DoneCallback } from '../src/types';
|
||||||
|
|
||||||
import {chaiSetup} from './utils/chai_setup';
|
import { chaiSetup } from './utils/chai_setup';
|
||||||
import {constants} from './utils/constants';
|
import { constants } from './utils/constants';
|
||||||
import {TokenUtils} from './utils/token_utils';
|
import { reportNodeCallbackErrors } from './utils/report_callback_errors';
|
||||||
import {web3Factory} from './utils/web3_factory';
|
import { TokenUtils } from './utils/token_utils';
|
||||||
|
|
||||||
chaiSetup.configure();
|
chaiSetup.configure();
|
||||||
const expect = chai.expect;
|
const expect = chai.expect;
|
||||||
const blockchainLifecycle = new BlockchainLifecycle(constants.RPC_URL);
|
const blockchainLifecycle = new BlockchainLifecycle();
|
||||||
|
|
||||||
describe('TokenWrapper', () => {
|
describe('TokenWrapper', () => {
|
||||||
let web3: Web3;
|
let web3: Web3;
|
||||||
@@ -74,17 +74,17 @@ describe('TokenWrapper', () => {
|
|||||||
it('should fail to transfer tokens if fromAddress has an insufficient balance', async () => {
|
it('should fail to transfer tokens if fromAddress has an insufficient balance', async () => {
|
||||||
const fromAddress = addressWithoutFunds;
|
const fromAddress = addressWithoutFunds;
|
||||||
const toAddress = coinbase;
|
const toAddress = coinbase;
|
||||||
return expect(zeroEx.token.transferAsync(
|
return expect(
|
||||||
token.address, fromAddress, toAddress, transferAmount,
|
zeroEx.token.transferAsync(token.address, fromAddress, toAddress, transferAmount),
|
||||||
)).to.be.rejectedWith(ZeroExError.InsufficientBalanceForTransfer);
|
).to.be.rejectedWith(ZeroExError.InsufficientBalanceForTransfer);
|
||||||
});
|
});
|
||||||
it('should throw a CONTRACT_DOES_NOT_EXIST error for a non-existent token contract', async () => {
|
it('should throw a CONTRACT_DOES_NOT_EXIST error for a non-existent token contract', async () => {
|
||||||
const nonExistentTokenAddress = '0x9dd402f14d67e001d8efbe6583e51bf9706aa065';
|
const nonExistentTokenAddress = '0x9dd402f14d67e001d8efbe6583e51bf9706aa065';
|
||||||
const fromAddress = coinbase;
|
const fromAddress = coinbase;
|
||||||
const toAddress = coinbase;
|
const toAddress = coinbase;
|
||||||
return expect(zeroEx.token.transferAsync(
|
return expect(
|
||||||
nonExistentTokenAddress, fromAddress, toAddress, transferAmount,
|
zeroEx.token.transferAsync(nonExistentTokenAddress, fromAddress, toAddress, transferAmount),
|
||||||
)).to.be.rejectedWith(ZeroExError.TokenContractDoesNotExist);
|
).to.be.rejectedWith(ZeroExError.TokenContractDoesNotExist);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('#transferFromAsync', () => {
|
describe('#transferFromAsync', () => {
|
||||||
@@ -103,24 +103,22 @@ describe('TokenWrapper', () => {
|
|||||||
const fromAddressBalance = await zeroEx.token.getBalanceAsync(token.address, fromAddress);
|
const fromAddressBalance = await zeroEx.token.getBalanceAsync(token.address, fromAddress);
|
||||||
expect(fromAddressBalance).to.be.bignumber.greaterThan(transferAmount);
|
expect(fromAddressBalance).to.be.bignumber.greaterThan(transferAmount);
|
||||||
|
|
||||||
const fromAddressAllowance = await zeroEx.token.getAllowanceAsync(token.address, fromAddress,
|
const fromAddressAllowance = await zeroEx.token.getAllowanceAsync(token.address, fromAddress, toAddress);
|
||||||
toAddress);
|
|
||||||
expect(fromAddressAllowance).to.be.bignumber.equal(0);
|
expect(fromAddressAllowance).to.be.bignumber.equal(0);
|
||||||
|
|
||||||
return expect(zeroEx.token.transferFromAsync(
|
return expect(
|
||||||
token.address, fromAddress, toAddress, senderAddress, transferAmount,
|
zeroEx.token.transferFromAsync(token.address, fromAddress, toAddress, senderAddress, transferAmount),
|
||||||
)).to.be.rejectedWith(ZeroExError.InsufficientAllowanceForTransfer);
|
).to.be.rejectedWith(ZeroExError.InsufficientAllowanceForTransfer);
|
||||||
});
|
});
|
||||||
it('[regression] should fail to transfer tokens if set allowance for toAddress instead of senderAddress',
|
it('[regression] should fail to transfer tokens if set allowance for toAddress instead of senderAddress', async () => {
|
||||||
async () => {
|
|
||||||
const fromAddress = coinbase;
|
const fromAddress = coinbase;
|
||||||
const transferAmount = new BigNumber(42);
|
const transferAmount = new BigNumber(42);
|
||||||
|
|
||||||
await zeroEx.token.setAllowanceAsync(token.address, fromAddress, toAddress, transferAmount);
|
await zeroEx.token.setAllowanceAsync(token.address, fromAddress, toAddress, transferAmount);
|
||||||
|
|
||||||
return expect(zeroEx.token.transferFromAsync(
|
return expect(
|
||||||
token.address, fromAddress, toAddress, senderAddress, transferAmount,
|
zeroEx.token.transferFromAsync(token.address, fromAddress, toAddress, senderAddress, transferAmount),
|
||||||
)).to.be.rejectedWith(ZeroExError.InsufficientAllowanceForTransfer);
|
).to.be.rejectedWith(ZeroExError.InsufficientAllowanceForTransfer);
|
||||||
});
|
});
|
||||||
it('should fail to transfer tokens if fromAddress has insufficient balance', async () => {
|
it('should fail to transfer tokens if fromAddress has insufficient balance', async () => {
|
||||||
const fromAddress = addressWithoutFunds;
|
const fromAddress = addressWithoutFunds;
|
||||||
@@ -130,13 +128,16 @@ describe('TokenWrapper', () => {
|
|||||||
expect(fromAddressBalance).to.be.bignumber.equal(0);
|
expect(fromAddressBalance).to.be.bignumber.equal(0);
|
||||||
|
|
||||||
await zeroEx.token.setAllowanceAsync(token.address, fromAddress, senderAddress, transferAmount);
|
await zeroEx.token.setAllowanceAsync(token.address, fromAddress, senderAddress, transferAmount);
|
||||||
const fromAddressAllowance = await zeroEx.token.getAllowanceAsync(token.address, fromAddress,
|
const fromAddressAllowance = await zeroEx.token.getAllowanceAsync(
|
||||||
senderAddress);
|
token.address,
|
||||||
|
fromAddress,
|
||||||
|
senderAddress,
|
||||||
|
);
|
||||||
expect(fromAddressAllowance).to.be.bignumber.equal(transferAmount);
|
expect(fromAddressAllowance).to.be.bignumber.equal(transferAmount);
|
||||||
|
|
||||||
return expect(zeroEx.token.transferFromAsync(
|
return expect(
|
||||||
token.address, fromAddress, toAddress, senderAddress, transferAmount,
|
zeroEx.token.transferFromAsync(token.address, fromAddress, toAddress, senderAddress, transferAmount),
|
||||||
)).to.be.rejectedWith(ZeroExError.InsufficientBalanceForTransfer);
|
).to.be.rejectedWith(ZeroExError.InsufficientBalanceForTransfer);
|
||||||
});
|
});
|
||||||
it('should successfully transfer tokens', async () => {
|
it('should successfully transfer tokens', async () => {
|
||||||
const fromAddress = coinbase;
|
const fromAddress = coinbase;
|
||||||
@@ -147,17 +148,22 @@ describe('TokenWrapper', () => {
|
|||||||
const transferAmount = new BigNumber(42);
|
const transferAmount = new BigNumber(42);
|
||||||
await zeroEx.token.setAllowanceAsync(token.address, fromAddress, senderAddress, transferAmount);
|
await zeroEx.token.setAllowanceAsync(token.address, fromAddress, senderAddress, transferAmount);
|
||||||
|
|
||||||
await zeroEx.token.transferFromAsync(token.address, fromAddress, toAddress, senderAddress,
|
await zeroEx.token.transferFromAsync(token.address, fromAddress, toAddress, senderAddress, transferAmount);
|
||||||
transferAmount);
|
|
||||||
const postBalance = await zeroEx.token.getBalanceAsync(token.address, toAddress);
|
const postBalance = await zeroEx.token.getBalanceAsync(token.address, toAddress);
|
||||||
return expect(postBalance).to.be.bignumber.equal(transferAmount);
|
return expect(postBalance).to.be.bignumber.equal(transferAmount);
|
||||||
});
|
});
|
||||||
it('should throw a CONTRACT_DOES_NOT_EXIST error for a non-existent token contract', async () => {
|
it('should throw a CONTRACT_DOES_NOT_EXIST error for a non-existent token contract', async () => {
|
||||||
const fromAddress = coinbase;
|
const fromAddress = coinbase;
|
||||||
const nonExistentTokenAddress = '0x9dd402f14d67e001d8efbe6583e51bf9706aa065';
|
const nonExistentTokenAddress = '0x9dd402f14d67e001d8efbe6583e51bf9706aa065';
|
||||||
return expect(zeroEx.token.transferFromAsync(
|
return expect(
|
||||||
nonExistentTokenAddress, fromAddress, toAddress, senderAddress, new BigNumber(42),
|
zeroEx.token.transferFromAsync(
|
||||||
)).to.be.rejectedWith(ZeroExError.TokenContractDoesNotExist);
|
nonExistentTokenAddress,
|
||||||
|
fromAddress,
|
||||||
|
toAddress,
|
||||||
|
senderAddress,
|
||||||
|
new BigNumber(42),
|
||||||
|
),
|
||||||
|
).to.be.rejectedWith(ZeroExError.TokenContractDoesNotExist);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('#getBalanceAsync', () => {
|
describe('#getBalanceAsync', () => {
|
||||||
@@ -172,8 +178,9 @@ describe('TokenWrapper', () => {
|
|||||||
it('should throw a CONTRACT_DOES_NOT_EXIST error for a non-existent token contract', async () => {
|
it('should throw a CONTRACT_DOES_NOT_EXIST error for a non-existent token contract', async () => {
|
||||||
const nonExistentTokenAddress = '0x9dd402f14d67e001d8efbe6583e51bf9706aa065';
|
const nonExistentTokenAddress = '0x9dd402f14d67e001d8efbe6583e51bf9706aa065';
|
||||||
const ownerAddress = coinbase;
|
const ownerAddress = coinbase;
|
||||||
return expect(zeroEx.token.getBalanceAsync(nonExistentTokenAddress, ownerAddress))
|
return expect(zeroEx.token.getBalanceAsync(nonExistentTokenAddress, ownerAddress)).to.be.rejectedWith(
|
||||||
.to.be.rejectedWith(ZeroExError.TokenContractDoesNotExist);
|
ZeroExError.TokenContractDoesNotExist,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('should return a balance of 0 for a non-existent owner address', async () => {
|
it('should return a balance of 0 for a non-existent owner address', async () => {
|
||||||
const token = tokens[0];
|
const token = tokens[0];
|
||||||
@@ -191,22 +198,25 @@ describe('TokenWrapper', () => {
|
|||||||
zeroExWithoutAccounts = new ZeroEx(web3WithoutAccounts.currentProvider, config);
|
zeroExWithoutAccounts = new ZeroEx(web3WithoutAccounts.currentProvider, config);
|
||||||
});
|
});
|
||||||
it('should return balance even when called with Web3 provider instance without addresses', async () => {
|
it('should return balance even when called with Web3 provider instance without addresses', async () => {
|
||||||
const token = tokens[0];
|
const token = tokens[0];
|
||||||
const ownerAddress = coinbase;
|
const ownerAddress = coinbase;
|
||||||
const balance = await zeroExWithoutAccounts.token.getBalanceAsync(token.address, ownerAddress);
|
const balance = await zeroExWithoutAccounts.token.getBalanceAsync(token.address, ownerAddress);
|
||||||
const expectedBalance = new BigNumber('1000000000000000000000000000');
|
const expectedBalance = new BigNumber('1000000000000000000000000000');
|
||||||
return expect(balance).to.be.bignumber.equal(expectedBalance);
|
return expect(balance).to.be.bignumber.equal(expectedBalance);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('#setAllowanceAsync', () => {
|
describe('#setAllowanceAsync', () => {
|
||||||
it('should set the spender\'s allowance', async () => {
|
it("should set the spender's allowance", async () => {
|
||||||
const token = tokens[0];
|
const token = tokens[0];
|
||||||
const ownerAddress = coinbase;
|
const ownerAddress = coinbase;
|
||||||
const spenderAddress = addressWithoutFunds;
|
const spenderAddress = addressWithoutFunds;
|
||||||
|
|
||||||
const allowanceBeforeSet = await zeroEx.token.getAllowanceAsync(token.address, ownerAddress,
|
const allowanceBeforeSet = await zeroEx.token.getAllowanceAsync(
|
||||||
spenderAddress);
|
token.address,
|
||||||
|
ownerAddress,
|
||||||
|
spenderAddress,
|
||||||
|
);
|
||||||
const expectedAllowanceBeforeAllowanceSet = new BigNumber(0);
|
const expectedAllowanceBeforeAllowanceSet = new BigNumber(0);
|
||||||
expect(allowanceBeforeSet).to.be.bignumber.equal(expectedAllowanceBeforeAllowanceSet);
|
expect(allowanceBeforeSet).to.be.bignumber.equal(expectedAllowanceBeforeAllowanceSet);
|
||||||
|
|
||||||
@@ -219,7 +229,7 @@ describe('TokenWrapper', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('#setUnlimitedAllowanceAsync', () => {
|
describe('#setUnlimitedAllowanceAsync', () => {
|
||||||
it('should set the unlimited spender\'s allowance', async () => {
|
it("should set the unlimited spender's allowance", async () => {
|
||||||
const token = tokens[0];
|
const token = tokens[0];
|
||||||
const ownerAddress = coinbase;
|
const ownerAddress = coinbase;
|
||||||
const spenderAddress = addressWithoutFunds;
|
const spenderAddress = addressWithoutFunds;
|
||||||
@@ -241,10 +251,18 @@ describe('TokenWrapper', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
await zeroEx.token.transferFromAsync(
|
await zeroEx.token.transferFromAsync(
|
||||||
zrx.address, coinbase, userWithNormalAllowance, userWithNormalAllowance, transferAmount,
|
zrx.address,
|
||||||
|
coinbase,
|
||||||
|
userWithNormalAllowance,
|
||||||
|
userWithNormalAllowance,
|
||||||
|
transferAmount,
|
||||||
);
|
);
|
||||||
await zeroEx.token.transferFromAsync(
|
await zeroEx.token.transferFromAsync(
|
||||||
zrx.address, coinbase, userWithUnlimitedAllowance, userWithUnlimitedAllowance, transferAmount,
|
zrx.address,
|
||||||
|
coinbase,
|
||||||
|
userWithUnlimitedAllowance,
|
||||||
|
userWithUnlimitedAllowance,
|
||||||
|
transferAmount,
|
||||||
);
|
);
|
||||||
|
|
||||||
const finalBalanceWithNormalAllowance = await web3Wrapper.getBalanceInWeiAsync(userWithNormalAllowance);
|
const finalBalanceWithNormalAllowance = await web3Wrapper.getBalanceInWeiAsync(userWithNormalAllowance);
|
||||||
@@ -300,7 +318,9 @@ describe('TokenWrapper', () => {
|
|||||||
await zeroEx.token.setAllowanceAsync(token.address, ownerAddress, spenderAddress, amountInBaseUnits);
|
await zeroEx.token.setAllowanceAsync(token.address, ownerAddress, spenderAddress, amountInBaseUnits);
|
||||||
|
|
||||||
const allowance = await zeroExWithoutAccounts.token.getAllowanceAsync(
|
const allowance = await zeroExWithoutAccounts.token.getAllowanceAsync(
|
||||||
token.address, ownerAddress, spenderAddress,
|
token.address,
|
||||||
|
ownerAddress,
|
||||||
|
spenderAddress,
|
||||||
);
|
);
|
||||||
const expectedAllowance = amountInBaseUnits;
|
const expectedAllowance = amountInBaseUnits;
|
||||||
return expect(allowance).to.be.bignumber.equal(expectedAllowance);
|
return expect(allowance).to.be.bignumber.equal(expectedAllowance);
|
||||||
@@ -366,65 +386,66 @@ describe('TokenWrapper', () => {
|
|||||||
// Source: https://github.com/mochajs/mocha/issues/2407
|
// Source: https://github.com/mochajs/mocha/issues/2407
|
||||||
it('Should receive the Transfer event when tokens are transfered', (done: DoneCallback) => {
|
it('Should receive the Transfer event when tokens are transfered', (done: DoneCallback) => {
|
||||||
(async () => {
|
(async () => {
|
||||||
const callback = (err: Error, logEvent: DecodedLogEvent<TransferContractEventArgs>) => {
|
const callback = reportNodeCallbackErrors(done)(
|
||||||
expect(logEvent).to.not.be.undefined();
|
(logEvent: DecodedLogEvent<TransferContractEventArgs>) => {
|
||||||
expect(logEvent.isRemoved).to.be.false();
|
expect(logEvent.isRemoved).to.be.false();
|
||||||
expect(logEvent.log.logIndex).to.be.equal(0);
|
expect(logEvent.log.logIndex).to.be.equal(0);
|
||||||
expect(logEvent.log.transactionIndex).to.be.equal(0);
|
expect(logEvent.log.transactionIndex).to.be.equal(0);
|
||||||
expect(logEvent.log.blockNumber).to.be.a('number');
|
expect(logEvent.log.blockNumber).to.be.a('number');
|
||||||
const args = logEvent.log.args;
|
const args = logEvent.log.args;
|
||||||
expect(args._from).to.be.equal(coinbase);
|
expect(args._from).to.be.equal(coinbase);
|
||||||
expect(args._to).to.be.equal(addressWithoutFunds);
|
expect(args._to).to.be.equal(addressWithoutFunds);
|
||||||
expect(args._value).to.be.bignumber.equal(transferAmount);
|
expect(args._value).to.be.bignumber.equal(transferAmount);
|
||||||
done();
|
},
|
||||||
};
|
);
|
||||||
zeroEx.token.subscribe(
|
zeroEx.token.subscribe(tokenAddress, TokenEvents.Transfer, indexFilterValues, callback);
|
||||||
tokenAddress, TokenEvents.Transfer, indexFilterValues, callback);
|
|
||||||
await zeroEx.token.transferAsync(tokenAddress, coinbase, addressWithoutFunds, transferAmount);
|
await zeroEx.token.transferAsync(tokenAddress, coinbase, addressWithoutFunds, transferAmount);
|
||||||
})().catch(done);
|
})().catch(done);
|
||||||
});
|
});
|
||||||
it('Should receive the Approval event when allowance is being set', (done: DoneCallback) => {
|
it('Should receive the Approval event when allowance is being set', (done: DoneCallback) => {
|
||||||
(async () => {
|
(async () => {
|
||||||
const callback = (err: Error, logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
|
const callback = reportNodeCallbackErrors(done)(
|
||||||
expect(logEvent).to.not.be.undefined();
|
(logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
|
||||||
expect(logEvent.isRemoved).to.be.false();
|
expect(logEvent).to.not.be.undefined();
|
||||||
const args = logEvent.log.args;
|
expect(logEvent.isRemoved).to.be.false();
|
||||||
expect(args._owner).to.be.equal(coinbase);
|
const args = logEvent.log.args;
|
||||||
expect(args._spender).to.be.equal(addressWithoutFunds);
|
expect(args._owner).to.be.equal(coinbase);
|
||||||
expect(args._value).to.be.bignumber.equal(allowanceAmount);
|
expect(args._spender).to.be.equal(addressWithoutFunds);
|
||||||
done();
|
expect(args._value).to.be.bignumber.equal(allowanceAmount);
|
||||||
};
|
},
|
||||||
zeroEx.token.subscribe(
|
);
|
||||||
tokenAddress, TokenEvents.Approval, indexFilterValues, callback);
|
zeroEx.token.subscribe(tokenAddress, TokenEvents.Approval, indexFilterValues, callback);
|
||||||
await zeroEx.token.setAllowanceAsync(tokenAddress, coinbase, addressWithoutFunds, allowanceAmount);
|
await zeroEx.token.setAllowanceAsync(tokenAddress, coinbase, addressWithoutFunds, allowanceAmount);
|
||||||
})().catch(done);
|
})().catch(done);
|
||||||
});
|
});
|
||||||
it('Outstanding subscriptions are cancelled when zeroEx.setProvider called', (done: DoneCallback) => {
|
it('Outstanding subscriptions are cancelled when zeroEx.setProvider called', (done: DoneCallback) => {
|
||||||
(async () => {
|
(async () => {
|
||||||
const callbackNeverToBeCalled = (err: Error, logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
|
const callbackNeverToBeCalled = reportNodeCallbackErrors(done)(
|
||||||
done(new Error('Expected this subscription to have been cancelled'));
|
(logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
|
||||||
};
|
done(new Error('Expected this subscription to have been cancelled'));
|
||||||
zeroEx.token.subscribe(
|
},
|
||||||
tokenAddress, TokenEvents.Transfer, indexFilterValues, callbackNeverToBeCalled,
|
|
||||||
);
|
);
|
||||||
const callbackToBeCalled = (err: Error, logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
|
zeroEx.token.subscribe(tokenAddress, TokenEvents.Transfer, indexFilterValues, callbackNeverToBeCalled);
|
||||||
done();
|
const callbackToBeCalled = reportNodeCallbackErrors(done)();
|
||||||
};
|
|
||||||
const newProvider = web3Factory.getRpcProvider();
|
const newProvider = web3Factory.getRpcProvider();
|
||||||
zeroEx.setProvider(newProvider, constants.TESTRPC_NETWORK_ID);
|
zeroEx.setProvider(newProvider, constants.TESTRPC_NETWORK_ID);
|
||||||
zeroEx.token.subscribe(
|
zeroEx.token.subscribe(tokenAddress, TokenEvents.Transfer, indexFilterValues, callbackToBeCalled);
|
||||||
tokenAddress, TokenEvents.Transfer, indexFilterValues, callbackToBeCalled,
|
|
||||||
);
|
|
||||||
await zeroEx.token.transferAsync(tokenAddress, coinbase, addressWithoutFunds, transferAmount);
|
await zeroEx.token.transferAsync(tokenAddress, coinbase, addressWithoutFunds, transferAmount);
|
||||||
})().catch(done);
|
})().catch(done);
|
||||||
});
|
});
|
||||||
it('Should cancel subscription when unsubscribe called', (done: DoneCallback) => {
|
it('Should cancel subscription when unsubscribe called', (done: DoneCallback) => {
|
||||||
(async () => {
|
(async () => {
|
||||||
const callbackNeverToBeCalled = (err: Error, logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
|
const callbackNeverToBeCalled = reportNodeCallbackErrors(done)(
|
||||||
done(new Error('Expected this subscription to have been cancelled'));
|
(logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
|
||||||
};
|
done(new Error('Expected this subscription to have been cancelled'));
|
||||||
|
},
|
||||||
|
);
|
||||||
const subscriptionToken = zeroEx.token.subscribe(
|
const subscriptionToken = zeroEx.token.subscribe(
|
||||||
tokenAddress, TokenEvents.Transfer, indexFilterValues, callbackNeverToBeCalled);
|
tokenAddress,
|
||||||
|
TokenEvents.Transfer,
|
||||||
|
indexFilterValues,
|
||||||
|
callbackNeverToBeCalled,
|
||||||
|
);
|
||||||
zeroEx.token.unsubscribe(subscriptionToken);
|
zeroEx.token.unsubscribe(subscriptionToken);
|
||||||
await zeroEx.token.transferAsync(tokenAddress, coinbase, addressWithoutFunds, transferAmount);
|
await zeroEx.token.transferAsync(tokenAddress, coinbase, addressWithoutFunds, transferAmount);
|
||||||
done();
|
done();
|
||||||
@@ -450,7 +471,10 @@ describe('TokenWrapper', () => {
|
|||||||
const eventName = TokenEvents.Approval;
|
const eventName = TokenEvents.Approval;
|
||||||
const indexFilterValues = {};
|
const indexFilterValues = {};
|
||||||
const logs = await zeroEx.token.getLogsAsync<ApprovalContractEventArgs>(
|
const logs = await zeroEx.token.getLogsAsync<ApprovalContractEventArgs>(
|
||||||
tokenAddress, eventName, blockRange, indexFilterValues,
|
tokenAddress,
|
||||||
|
eventName,
|
||||||
|
blockRange,
|
||||||
|
indexFilterValues,
|
||||||
);
|
);
|
||||||
expect(logs).to.have.length(1);
|
expect(logs).to.have.length(1);
|
||||||
const args = logs[0].args;
|
const args = logs[0].args;
|
||||||
@@ -465,7 +489,10 @@ describe('TokenWrapper', () => {
|
|||||||
const differentEventName = TokenEvents.Transfer;
|
const differentEventName = TokenEvents.Transfer;
|
||||||
const indexFilterValues = {};
|
const indexFilterValues = {};
|
||||||
const logs = await zeroEx.token.getLogsAsync(
|
const logs = await zeroEx.token.getLogsAsync(
|
||||||
tokenAddress, differentEventName, blockRange, indexFilterValues,
|
tokenAddress,
|
||||||
|
differentEventName,
|
||||||
|
blockRange,
|
||||||
|
indexFilterValues,
|
||||||
);
|
);
|
||||||
expect(logs).to.have.length(0);
|
expect(logs).to.have.length(0);
|
||||||
});
|
});
|
||||||
@@ -479,7 +506,10 @@ describe('TokenWrapper', () => {
|
|||||||
_owner: coinbase,
|
_owner: coinbase,
|
||||||
};
|
};
|
||||||
const logs = await zeroEx.token.getLogsAsync<ApprovalContractEventArgs>(
|
const logs = await zeroEx.token.getLogsAsync<ApprovalContractEventArgs>(
|
||||||
tokenAddress, eventName, blockRange, indexFilterValues,
|
tokenAddress,
|
||||||
|
eventName,
|
||||||
|
blockRange,
|
||||||
|
indexFilterValues,
|
||||||
);
|
);
|
||||||
expect(logs).to.have.length(1);
|
expect(logs).to.have.length(1);
|
||||||
const args = logs[0].args;
|
const args = logs[0].args;
|
||||||
@@ -487,3 +517,4 @@ describe('TokenWrapper', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
// tslint:disable:max-file-line-count
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
export const constants = {
|
export const constants = {
|
||||||
NULL_ADDRESS: '0x0000000000000000000000000000000000000000',
|
NULL_ADDRESS: '0x0000000000000000000000000000000000000000',
|
||||||
RPC_URL: 'http://localhost:8545/',
|
|
||||||
ROPSTEN_NETWORK_ID: 3,
|
ROPSTEN_NETWORK_ID: 3,
|
||||||
KOVAN_NETWORK_ID: 42,
|
KOVAN_NETWORK_ID: 42,
|
||||||
TESTRPC_NETWORK_ID: 50,
|
TESTRPC_NETWORK_ID: 50,
|
||||||
KOVAN_RPC_URL: 'https://kovan.infura.io/',
|
KOVAN_RPC_URL: 'https://kovan.infura.io/',
|
||||||
ROPSTEN_RPC_URL: 'https://ropsten.infura.io/',
|
ROPSTEN_RPC_URL: 'https://ropsten.infura.io/',
|
||||||
ZRX_DECIMALS: 18,
|
ZRX_DECIMALS: 18,
|
||||||
GAS_ESTIMATE: 500000,
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import {Web3Wrapper} from '@0xproject/web3-wrapper';
|
import { BigNumber } from '@0xproject/utils';
|
||||||
import BigNumber from 'bignumber.js';
|
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||||
|
|
||||||
import {SignedOrder, Token, ZeroEx} from '../../src';
|
import { SignedOrder, Token, ZeroEx } from '../../src';
|
||||||
import {artifacts} from '../../src/artifacts';
|
import { artifacts } from '../../src/artifacts';
|
||||||
import {DummyTokenContract} from '../../src/contract_wrappers/generated/dummy_token';
|
import { DummyTokenContract } from '../../src/contract_wrappers/generated/dummy_token';
|
||||||
import {orderFactory} from '../utils/order_factory';
|
import { orderFactory } from '../utils/order_factory';
|
||||||
|
|
||||||
import {constants} from './constants';
|
import { constants } from './constants';
|
||||||
|
|
||||||
const INITIAL_COINBASE_TOKEN_SUPPLY_IN_UNITS = new BigNumber(100);
|
const INITIAL_COINBASE_TOKEN_SUPPLY_IN_UNITS = new BigNumber(100);
|
||||||
|
|
||||||
@@ -17,8 +17,13 @@ export class FillScenarios {
|
|||||||
private _coinbase: string;
|
private _coinbase: string;
|
||||||
private _zrxTokenAddress: string;
|
private _zrxTokenAddress: string;
|
||||||
private _exchangeContractAddress: string;
|
private _exchangeContractAddress: string;
|
||||||
constructor(zeroEx: ZeroEx, userAddresses: string[],
|
constructor(
|
||||||
tokens: Token[], zrxTokenAddress: string, exchangeContractAddress: string) {
|
zeroEx: ZeroEx,
|
||||||
|
userAddresses: string[],
|
||||||
|
tokens: Token[],
|
||||||
|
zrxTokenAddress: string,
|
||||||
|
exchangeContractAddress: string,
|
||||||
|
) {
|
||||||
this._zeroEx = zeroEx;
|
this._zeroEx = zeroEx;
|
||||||
this._userAddresses = userAddresses;
|
this._userAddresses = userAddresses;
|
||||||
this._tokens = tokens;
|
this._tokens = tokens;
|
||||||
@@ -30,11 +35,8 @@ export class FillScenarios {
|
|||||||
const web3Wrapper = (this._zeroEx as any)._web3Wrapper as Web3Wrapper;
|
const web3Wrapper = (this._zeroEx as any)._web3Wrapper as Web3Wrapper;
|
||||||
for (const token of this._tokens) {
|
for (const token of this._tokens) {
|
||||||
if (token.symbol !== 'ZRX' && token.symbol !== 'WETH') {
|
if (token.symbol !== 'ZRX' && token.symbol !== 'WETH') {
|
||||||
const contractInstance = web3Wrapper.getContractInstance(
|
|
||||||
artifacts.DummyTokenArtifact.abi, token.address,
|
|
||||||
);
|
|
||||||
const defaults = {};
|
const defaults = {};
|
||||||
const dummyToken = new DummyTokenContract(contractInstance, defaults);
|
const dummyToken = new DummyTokenContract(web3Wrapper, artifacts.DummyTokenArtifact.abi, token.address);
|
||||||
const tokenSupply = ZeroEx.toBaseUnitAmount(INITIAL_COINBASE_TOKEN_SUPPLY_IN_UNITS, token.decimals);
|
const tokenSupply = ZeroEx.toBaseUnitAmount(INITIAL_COINBASE_TOKEN_SUPPLY_IN_UNITS, token.decimals);
|
||||||
const txHash = await dummyToken.setBalance.sendTransactionAsync(this._coinbase, tokenSupply, {
|
const txHash = await dummyToken.setBalance.sendTransactionAsync(this._coinbase, tokenSupply, {
|
||||||
from: this._coinbase,
|
from: this._coinbase,
|
||||||
@@ -43,61 +45,110 @@ export class FillScenarios {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public async createFillableSignedOrderAsync(makerTokenAddress: string, takerTokenAddress: string,
|
public async createFillableSignedOrderAsync(
|
||||||
makerAddress: string, takerAddress: string,
|
makerTokenAddress: string,
|
||||||
fillableAmount: BigNumber,
|
takerTokenAddress: string,
|
||||||
expirationUnixTimestampSec?: BigNumber):
|
makerAddress: string,
|
||||||
Promise<SignedOrder> {
|
takerAddress: string,
|
||||||
|
fillableAmount: BigNumber,
|
||||||
|
expirationUnixTimestampSec?: BigNumber,
|
||||||
|
): Promise<SignedOrder> {
|
||||||
return this.createAsymmetricFillableSignedOrderAsync(
|
return this.createAsymmetricFillableSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress,
|
makerTokenAddress,
|
||||||
fillableAmount, fillableAmount, expirationUnixTimestampSec,
|
takerTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
|
fillableAmount,
|
||||||
|
expirationUnixTimestampSec,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
public async createFillableSignedOrderWithFeesAsync(
|
public async createFillableSignedOrderWithFeesAsync(
|
||||||
makerTokenAddress: string, takerTokenAddress: string,
|
makerTokenAddress: string,
|
||||||
makerFee: BigNumber, takerFee: BigNumber,
|
takerTokenAddress: string,
|
||||||
makerAddress: string, takerAddress: string,
|
makerFee: BigNumber,
|
||||||
|
takerFee: BigNumber,
|
||||||
|
makerAddress: string,
|
||||||
|
takerAddress: string,
|
||||||
fillableAmount: BigNumber,
|
fillableAmount: BigNumber,
|
||||||
feeRecepient: string, expirationUnixTimestampSec?: BigNumber,
|
feeRecepient: string,
|
||||||
|
expirationUnixTimestampSec?: BigNumber,
|
||||||
): Promise<SignedOrder> {
|
): Promise<SignedOrder> {
|
||||||
return this._createAsymmetricFillableSignedOrderWithFeesAsync(
|
return this._createAsymmetricFillableSignedOrderWithFeesAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerFee, takerFee, makerAddress, takerAddress,
|
makerTokenAddress,
|
||||||
fillableAmount, fillableAmount, feeRecepient, expirationUnixTimestampSec,
|
takerTokenAddress,
|
||||||
|
makerFee,
|
||||||
|
takerFee,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
|
fillableAmount,
|
||||||
|
feeRecepient,
|
||||||
|
expirationUnixTimestampSec,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
public async createAsymmetricFillableSignedOrderAsync(
|
public async createAsymmetricFillableSignedOrderAsync(
|
||||||
makerTokenAddress: string, takerTokenAddress: string, makerAddress: string, takerAddress: string,
|
makerTokenAddress: string,
|
||||||
makerFillableAmount: BigNumber, takerFillableAmount: BigNumber,
|
takerTokenAddress: string,
|
||||||
expirationUnixTimestampSec?: BigNumber): Promise<SignedOrder> {
|
makerAddress: string,
|
||||||
|
takerAddress: string,
|
||||||
|
makerFillableAmount: BigNumber,
|
||||||
|
takerFillableAmount: BigNumber,
|
||||||
|
expirationUnixTimestampSec?: BigNumber,
|
||||||
|
): Promise<SignedOrder> {
|
||||||
const makerFee = new BigNumber(0);
|
const makerFee = new BigNumber(0);
|
||||||
const takerFee = new BigNumber(0);
|
const takerFee = new BigNumber(0);
|
||||||
const feeRecepient = constants.NULL_ADDRESS;
|
const feeRecepient = constants.NULL_ADDRESS;
|
||||||
return this._createAsymmetricFillableSignedOrderWithFeesAsync(
|
return this._createAsymmetricFillableSignedOrderWithFeesAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerFee, takerFee, makerAddress, takerAddress,
|
makerTokenAddress,
|
||||||
makerFillableAmount, takerFillableAmount, feeRecepient, expirationUnixTimestampSec,
|
takerTokenAddress,
|
||||||
|
makerFee,
|
||||||
|
takerFee,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
makerFillableAmount,
|
||||||
|
takerFillableAmount,
|
||||||
|
feeRecepient,
|
||||||
|
expirationUnixTimestampSec,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
public async createPartiallyFilledSignedOrderAsync(makerTokenAddress: string, takerTokenAddress: string,
|
public async createPartiallyFilledSignedOrderAsync(
|
||||||
takerAddress: string, fillableAmount: BigNumber,
|
makerTokenAddress: string,
|
||||||
partialFillAmount: BigNumber) {
|
takerTokenAddress: string,
|
||||||
|
takerAddress: string,
|
||||||
|
fillableAmount: BigNumber,
|
||||||
|
partialFillAmount: BigNumber,
|
||||||
|
) {
|
||||||
const [makerAddress] = this._userAddresses;
|
const [makerAddress] = this._userAddresses;
|
||||||
const signedOrder = await this.createAsymmetricFillableSignedOrderAsync(
|
const signedOrder = await this.createAsymmetricFillableSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress,
|
makerTokenAddress,
|
||||||
fillableAmount, fillableAmount,
|
takerTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
|
fillableAmount,
|
||||||
);
|
);
|
||||||
const shouldThrowOnInsufficientBalanceOrAllowance = false;
|
const shouldThrowOnInsufficientBalanceOrAllowance = false;
|
||||||
await this._zeroEx.exchange.fillOrderAsync(
|
await this._zeroEx.exchange.fillOrderAsync(
|
||||||
signedOrder, partialFillAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress,
|
signedOrder,
|
||||||
|
partialFillAmount,
|
||||||
|
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||||
|
takerAddress,
|
||||||
);
|
);
|
||||||
return signedOrder;
|
return signedOrder;
|
||||||
}
|
}
|
||||||
private async _createAsymmetricFillableSignedOrderWithFeesAsync(
|
private async _createAsymmetricFillableSignedOrderWithFeesAsync(
|
||||||
makerTokenAddress: string, takerTokenAddress: string,
|
makerTokenAddress: string,
|
||||||
makerFee: BigNumber, takerFee: BigNumber,
|
takerTokenAddress: string,
|
||||||
makerAddress: string, takerAddress: string,
|
makerFee: BigNumber,
|
||||||
makerFillableAmount: BigNumber, takerFillableAmount: BigNumber,
|
takerFee: BigNumber,
|
||||||
feeRecepient: string, expirationUnixTimestampSec?: BigNumber): Promise<SignedOrder> {
|
makerAddress: string,
|
||||||
|
takerAddress: string,
|
||||||
|
makerFillableAmount: BigNumber,
|
||||||
|
takerFillableAmount: BigNumber,
|
||||||
|
feeRecepient: string,
|
||||||
|
expirationUnixTimestampSec?: BigNumber,
|
||||||
|
): Promise<SignedOrder> {
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
this._increaseBalanceAndAllowanceAsync(makerTokenAddress, makerAddress, makerFillableAmount),
|
this._increaseBalanceAndAllowanceAsync(makerTokenAddress, makerAddress, makerFillableAmount),
|
||||||
this._increaseBalanceAndAllowanceAsync(takerTokenAddress, takerAddress, takerFillableAmount),
|
this._increaseBalanceAndAllowanceAsync(takerTokenAddress, takerAddress, takerFillableAmount),
|
||||||
@@ -107,14 +158,27 @@ export class FillScenarios {
|
|||||||
this._increaseBalanceAndAllowanceAsync(this._zrxTokenAddress, takerAddress, takerFee),
|
this._increaseBalanceAndAllowanceAsync(this._zrxTokenAddress, takerAddress, takerFee),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const signedOrder = await orderFactory.createSignedOrderAsync(this._zeroEx,
|
const signedOrder = await orderFactory.createSignedOrderAsync(
|
||||||
makerAddress, takerAddress, makerFee, takerFee,
|
this._zeroEx,
|
||||||
makerFillableAmount, makerTokenAddress, takerFillableAmount, takerTokenAddress,
|
makerAddress,
|
||||||
this._exchangeContractAddress, feeRecepient, expirationUnixTimestampSec);
|
takerAddress,
|
||||||
|
makerFee,
|
||||||
|
takerFee,
|
||||||
|
makerFillableAmount,
|
||||||
|
makerTokenAddress,
|
||||||
|
takerFillableAmount,
|
||||||
|
takerTokenAddress,
|
||||||
|
this._exchangeContractAddress,
|
||||||
|
feeRecepient,
|
||||||
|
expirationUnixTimestampSec,
|
||||||
|
);
|
||||||
return signedOrder;
|
return signedOrder;
|
||||||
}
|
}
|
||||||
private async _increaseBalanceAndAllowanceAsync(
|
private async _increaseBalanceAndAllowanceAsync(
|
||||||
tokenAddress: string, address: string, amount: BigNumber): Promise<void> {
|
tokenAddress: string,
|
||||||
|
address: string,
|
||||||
|
amount: BigNumber,
|
||||||
|
): Promise<void> {
|
||||||
if (amount.isZero() || address === ZeroEx.NULL_ADDRESS) {
|
if (amount.isZero() || address === ZeroEx.NULL_ADDRESS) {
|
||||||
return; // noop
|
return; // noop
|
||||||
}
|
}
|
||||||
@@ -123,16 +187,12 @@ export class FillScenarios {
|
|||||||
this._increaseAllowanceAsync(tokenAddress, address, amount),
|
this._increaseAllowanceAsync(tokenAddress, address, amount),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
private async _increaseBalanceAsync(
|
private async _increaseBalanceAsync(tokenAddress: string, address: string, amount: BigNumber): Promise<void> {
|
||||||
tokenAddress: string, address: string, amount: BigNumber): Promise<void> {
|
|
||||||
await this._zeroEx.token.transferAsync(tokenAddress, this._coinbase, address, amount);
|
await this._zeroEx.token.transferAsync(tokenAddress, this._coinbase, address, amount);
|
||||||
}
|
}
|
||||||
private async _increaseAllowanceAsync(
|
private async _increaseAllowanceAsync(tokenAddress: string, address: string, amount: BigNumber): Promise<void> {
|
||||||
tokenAddress: string, address: string, amount: BigNumber): Promise<void> {
|
|
||||||
const oldMakerAllowance = await this._zeroEx.token.getProxyAllowanceAsync(tokenAddress, address);
|
const oldMakerAllowance = await this._zeroEx.token.getProxyAllowanceAsync(tokenAddress, address);
|
||||||
const newMakerAllowance = oldMakerAllowance.plus(amount);
|
const newMakerAllowance = oldMakerAllowance.plus(amount);
|
||||||
await this._zeroEx.token.setProxyAllowanceAsync(
|
await this._zeroEx.token.setProxyAllowanceAsync(tokenAddress, address, newMakerAllowance);
|
||||||
tokenAddress, address, newMakerAllowance,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import BigNumber from 'bignumber.js';
|
import { BigNumber } from '@0xproject/utils';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import {SignedOrder, ZeroEx} from '../../src';
|
import { SignedOrder, ZeroEx } from '../../src';
|
||||||
|
|
||||||
|
const SHOULD_ADD_PERSONAL_MESSAGE_PREFIX = false;
|
||||||
|
|
||||||
export const orderFactory = {
|
export const orderFactory = {
|
||||||
async createSignedOrderAsync(
|
async createSignedOrderAsync(
|
||||||
@@ -16,11 +18,12 @@ export const orderFactory = {
|
|||||||
takerTokenAddress: string,
|
takerTokenAddress: string,
|
||||||
exchangeContractAddress: string,
|
exchangeContractAddress: string,
|
||||||
feeRecipient: string,
|
feeRecipient: string,
|
||||||
expirationUnixTimestampSecIfExists?: BigNumber): Promise<SignedOrder> {
|
expirationUnixTimestampSecIfExists?: BigNumber,
|
||||||
|
): Promise<SignedOrder> {
|
||||||
const defaultExpirationUnixTimestampSec = new BigNumber(2524604400); // Close to infinite
|
const defaultExpirationUnixTimestampSec = new BigNumber(2524604400); // Close to infinite
|
||||||
const expirationUnixTimestampSec = _.isUndefined(expirationUnixTimestampSecIfExists) ?
|
const expirationUnixTimestampSec = _.isUndefined(expirationUnixTimestampSecIfExists)
|
||||||
defaultExpirationUnixTimestampSec :
|
? defaultExpirationUnixTimestampSec
|
||||||
expirationUnixTimestampSecIfExists;
|
: expirationUnixTimestampSecIfExists;
|
||||||
const order = {
|
const order = {
|
||||||
maker,
|
maker,
|
||||||
taker,
|
taker,
|
||||||
@@ -36,8 +39,8 @@ export const orderFactory = {
|
|||||||
expirationUnixTimestampSec,
|
expirationUnixTimestampSec,
|
||||||
};
|
};
|
||||||
const orderHash = ZeroEx.getOrderHashHex(order);
|
const orderHash = ZeroEx.getOrderHashHex(order);
|
||||||
const ecSignature = await zeroEx.signOrderHashAsync(orderHash, maker);
|
const ecSignature = await zeroEx.signOrderHashAsync(orderHash, maker, SHOULD_ADD_PERSONAL_MESSAGE_PREFIX);
|
||||||
const signedOrder: SignedOrder = _.assign(order, {ecSignature});
|
const signedOrder: SignedOrder = _.assign(order, { ecSignature });
|
||||||
return signedOrder;
|
return signedOrder;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,10 +1,22 @@
|
|||||||
import {DoneCallback} from '../../src/types';
|
import * as chai from 'chai';
|
||||||
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
export const reportCallbackErrors = (done: DoneCallback) => {
|
import { DoneCallback } from '../../src/types';
|
||||||
return (f: (...args: any[]) => void) => {
|
|
||||||
const wrapped = async (...args: any[]) => {
|
const expect = chai.expect;
|
||||||
|
|
||||||
|
export const reportNoErrorCallbackErrors = (done: DoneCallback, expectToBeCalledOnce = true) => {
|
||||||
|
return <T>(f?: (value: T) => void) => {
|
||||||
|
const wrapped = (value: T) => {
|
||||||
|
if (_.isUndefined(f)) {
|
||||||
|
done();
|
||||||
|
return;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
f(...args);
|
f(value);
|
||||||
|
if (expectToBeCalledOnce) {
|
||||||
|
done();
|
||||||
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
done(err);
|
done(err);
|
||||||
}
|
}
|
||||||
@@ -12,3 +24,43 @@ export const reportCallbackErrors = (done: DoneCallback) => {
|
|||||||
return wrapped;
|
return wrapped;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const reportNodeCallbackErrors = (done: DoneCallback, expectToBeCalledOnce = true) => {
|
||||||
|
return <T>(f?: (value: T) => void) => {
|
||||||
|
const wrapped = (error: Error | null, value: T | undefined) => {
|
||||||
|
if (!_.isNull(error)) {
|
||||||
|
done(error);
|
||||||
|
} else {
|
||||||
|
if (_.isUndefined(f)) {
|
||||||
|
done();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
f(value as T);
|
||||||
|
if (expectToBeCalledOnce) {
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
done(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return wrapped;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const assertNodeCallbackError = (done: DoneCallback, errMsg: string) => {
|
||||||
|
const wrapped = <T>(error: Error | null, value: T | undefined) => {
|
||||||
|
if (_.isNull(error)) {
|
||||||
|
done(new Error('Expected callback to receive an error'));
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
expect(error.message).to.be.equal(errMsg);
|
||||||
|
done();
|
||||||
|
} catch (err) {
|
||||||
|
done(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return wrapped;
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import {InternalZeroExError, Token} from '../../src/types';
|
import { InternalZeroExError, Token } from '../../src/types';
|
||||||
|
|
||||||
const PROTOCOL_TOKEN_SYMBOL = 'ZRX';
|
const PROTOCOL_TOKEN_SYMBOL = 'ZRX';
|
||||||
const WETH_TOKEN_SYMBOL = 'WETH';
|
const WETH_TOKEN_SYMBOL = 'WETH';
|
||||||
@@ -11,14 +11,14 @@ export class TokenUtils {
|
|||||||
this._tokens = tokens;
|
this._tokens = tokens;
|
||||||
}
|
}
|
||||||
public getProtocolTokenOrThrow(): Token {
|
public getProtocolTokenOrThrow(): Token {
|
||||||
const zrxToken = _.find(this._tokens, {symbol: PROTOCOL_TOKEN_SYMBOL});
|
const zrxToken = _.find(this._tokens, { symbol: PROTOCOL_TOKEN_SYMBOL });
|
||||||
if (_.isUndefined(zrxToken)) {
|
if (_.isUndefined(zrxToken)) {
|
||||||
throw new Error(InternalZeroExError.ZrxNotInTokenRegistry);
|
throw new Error(InternalZeroExError.ZrxNotInTokenRegistry);
|
||||||
}
|
}
|
||||||
return zrxToken;
|
return zrxToken;
|
||||||
}
|
}
|
||||||
public getWethTokenOrThrow(): Token {
|
public getWethTokenOrThrow(): Token {
|
||||||
const wethToken = _.find(this._tokens, {symbol: WETH_TOKEN_SYMBOL});
|
const wethToken = _.find(this._tokens, { symbol: WETH_TOKEN_SYMBOL });
|
||||||
if (_.isUndefined(wethToken)) {
|
if (_.isUndefined(wethToken)) {
|
||||||
throw new Error(InternalZeroExError.WethNotInTokenRegistry);
|
throw new Error(InternalZeroExError.WethNotInTokenRegistry);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,17 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"extends": "../../tsconfig",
|
||||||
"module": "commonjs",
|
"compilerOptions": {
|
||||||
"target": "es5",
|
"outDir": "lib",
|
||||||
"lib": [ "es2015", "dom" ],
|
"noImplicitThis": false
|
||||||
"outDir": "lib",
|
},
|
||||||
"sourceMap": true,
|
"include": [
|
||||||
"declaration": true,
|
"./src/**/*",
|
||||||
"noImplicitAny": true,
|
"./test/**/*",
|
||||||
"experimentalDecorators": true,
|
"../../node_modules/types-bn/index.d.ts",
|
||||||
"strictNullChecks": true
|
"../../node_modules/types-ethereumjs-util/index.d.ts",
|
||||||
},
|
"../../node_modules/ethers-typescript-typings/index.d.ts",
|
||||||
"include": [
|
"../../node_modules/web3-typescript-typings/index.d.ts",
|
||||||
"./src/**/*",
|
"../../node_modules/chai-typescript-typings/index.d.ts",
|
||||||
"./test/**/*",
|
"../../node_modules/chai-as-promised-typescript-typings/index.d.ts"
|
||||||
"../../node_modules/types-bn/index.d.ts",
|
]
|
||||||
"../../node_modules/types-ethereumjs-util/index.d.ts",
|
|
||||||
"../../node_modules/web3-typescript-typings/index.d.ts",
|
|
||||||
"../../node_modules/chai-typescript-typings/index.d.ts",
|
|
||||||
"../../node_modules/chai-as-promised-typescript-typings/index.d.ts"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
{
|
{
|
||||||
"extends": [
|
"extends": ["@0xproject/tslint-config"]
|
||||||
"@0xproject/tslint-config"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,10 +7,10 @@ const path = require('path');
|
|||||||
const production = process.env.NODE_ENV === 'production';
|
const production = process.env.NODE_ENV === 'production';
|
||||||
|
|
||||||
let entry = {
|
let entry = {
|
||||||
'index': './src/index.ts',
|
index: './src/index.ts',
|
||||||
};
|
};
|
||||||
if (production) {
|
if (production) {
|
||||||
entry = _.assign({}, entry, {'index.min': './src/index.ts'});
|
entry = _.assign({}, entry, { 'index.min': './src/index.ts' });
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|||||||
5
packages/abi-gen/.npmignore
Normal file
5
packages/abi-gen/.npmignore
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
.*
|
||||||
|
yarn-error.log
|
||||||
|
/src/
|
||||||
|
/scripts/
|
||||||
|
tsconfig.json
|
||||||
@@ -1,4 +1,22 @@
|
|||||||
# CHANGELOG
|
# CHANGELOG
|
||||||
|
|
||||||
vx.x.x
|
## v0.2.4 - _March 4, 2018_
|
||||||
------------------------
|
|
||||||
|
* Add a `backend` parameter that allows you to specify the Ethereum library you use in your templates (`web3` or `ethers`). Ethers auto-converts small ints to numbers whereas Web3 doesn't. Defaults to `web3` (#413)
|
||||||
|
* Add support for [tuple types](https://solidity.readthedocs.io/en/develop/abi-spec.html#handling-tuple-types) (#413)
|
||||||
|
* Add `hasReturnValue` to context data (#413)
|
||||||
|
|
||||||
|
## v0.2.1 - _February 9, 2018_
|
||||||
|
|
||||||
|
* Fix publishing issue where .npmignore was not properly excluding undesired content (#389)
|
||||||
|
|
||||||
|
## v0.2.0 - _February 7, 2018_
|
||||||
|
|
||||||
|
* Added CLI options for explicit specifying location of partials and main template (#346)
|
||||||
|
* Added CLI option to specify networkId, adding support for the JSON artifact format found in @0xproject/contracts (#388)
|
||||||
|
|
||||||
|
## v0.1.0 - _January 11, 2018_
|
||||||
|
|
||||||
|
* Fixed array typings with union types (#295)
|
||||||
|
* Add event ABIs to context data passed to templates (#302)
|
||||||
|
* Add constructor ABIs to context data passed to templates (#304)
|
||||||
|
|||||||
@@ -4,12 +4,15 @@ 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.
|
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.
|
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.js/tree/development/packages/0x.js/src/contract_wrappers/generated) check out 0x.js.
|
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.js/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 those files.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
`yarn add -g @0xproject/abi-gen`
|
`yarn add -g @0xproject/abi-gen`
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
```
|
```
|
||||||
abi-gen
|
abi-gen
|
||||||
Options:
|
Options:
|
||||||
@@ -19,8 +22,10 @@ Options:
|
|||||||
--templates Folder where to search for templates [string] [required]
|
--templates Folder where to search for templates [string] [required]
|
||||||
--output Folder where to put the output files [string] [required]
|
--output Folder where to put the output files [string] [required]
|
||||||
```
|
```
|
||||||
|
|
||||||
## ABI files
|
## ABI files
|
||||||
You're required to pass a [glob](https://en.wikipedia.org/wiki/Glob_(programming)) template where your abi files are located.
|
|
||||||
|
You're required to pass a [glob](<https://en.wikipedia.org/wiki/Glob_(programming)>) template where your abi files are located.
|
||||||
TL;DR - here is the example from 0x.js.
|
TL;DR - here is the example from 0x.js.
|
||||||
|
|
||||||
`--abiGlob 'src/artifacts/@(Exchange|Token|TokenTransferProxy|EtherToken|TokenRegistry).json`
|
`--abiGlob 'src/artifacts/@(Exchange|Token|TokenTransferProxy|EtherToken|TokenRegistry).json`
|
||||||
@@ -28,12 +33,18 @@ TL;DR - here is the example from 0x.js.
|
|||||||
We could've just used `--abiGlob 'src/artifacts/*.json` but we wanted to exclude some of the abi files.
|
We could've just used `--abiGlob 'src/artifacts/*.json` but we wanted to exclude some of the abi files.
|
||||||
|
|
||||||
The abi file should be either a [Truffle](http://truffleframework.com/) contract artifact (a JSON object with an abi key) or a JSON abi array.
|
The abi file should be either a [Truffle](http://truffleframework.com/) contract artifact (a JSON object with an abi key) or a JSON abi array.
|
||||||
|
|
||||||
## How to write custom templates?
|
## How to write custom templates?
|
||||||
The best way to get started is to copy [0x.js templates](https://github.com/0xProject/0x.js/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/0x.js/contract_templates) and start adjusting them for your needs.
|
||||||
We use [handlebars](http://handlebarsjs.com/) template engine under the hood.
|
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.
|
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.
|
||||||
|
|
||||||
## Which data/context do I get in my templates?
|
## Which data/context do I get in my templates?
|
||||||
|
|
||||||
For now you don't get much on top of methods abi, some useful helpers and a contract name because it was enough for our use-case, but if you need something else - create a PR.
|
For now you don't get much on top of methods abi, some useful helpers and a contract name because it was enough for our use-case, but if you need something else - create a PR.
|
||||||
See the [type definition](https://github.com/0xProject/0x.js/tree/development/packages/abi-gen/src/types.ts) of what we pass to the render method.
|
See the [type definition](https://github.com/0xProject/0x-monorepo/tree/development/packages/abi-gen/src/types.ts) of what we pass to the render method.
|
||||||
|
|
||||||
## Output files
|
## Output files
|
||||||
|
|
||||||
Output files will be generated within an output folder with names converted to camel case and taken from abi file names. If you already have some files in that folder they will be overwritten.
|
Output files will be generated within an output folder with names converted to camel case and taken from abi file names. If you already have some files in that folder they will be overwritten.
|
||||||
|
|||||||
@@ -1,48 +1,49 @@
|
|||||||
{
|
{
|
||||||
"name": "@0xproject/abi-gen",
|
"name": "@0xproject/abi-gen",
|
||||||
"version": "0.0.4",
|
"version": "0.2.5",
|
||||||
"description": "Generate contract wrappers from ABI and handlebars templates",
|
"description": "Generate contract wrappers from ABI and handlebars templates",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"types": "lib/index.d.ts",
|
"types": "lib/index.d.ts",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"lint": "tslint --project . 'src/**/*.ts'",
|
"build:watch": "tsc -w",
|
||||||
"clean": "shx rm -rf lib",
|
"lint": "tslint --project . 'src/**/*.ts'",
|
||||||
"build": "tsc"
|
"clean": "shx rm -rf lib",
|
||||||
},
|
"build": "tsc"
|
||||||
"bin": {
|
},
|
||||||
"abi-gen": "lib/index.js"
|
"bin": {
|
||||||
},
|
"abi-gen": "lib/index.js"
|
||||||
"repository": {
|
},
|
||||||
"type": "git",
|
"repository": {
|
||||||
"url": "https://github.com/0xProject/0x.js.git"
|
"type": "git",
|
||||||
},
|
"url": "https://github.com/0xProject/0x-monorepo.git"
|
||||||
"license": "Apache-2.0",
|
},
|
||||||
"bugs": {
|
"license": "Apache-2.0",
|
||||||
"url": "https://github.com/0xProject/0x.js/issues"
|
"bugs": {
|
||||||
},
|
"url": "https://github.com/0xProject/0x-monorepo/issues"
|
||||||
"homepage": "https://github.com/0xProject/0x.js/packages/abi-gen/README.md",
|
},
|
||||||
"dependencies": {
|
"homepage": "https://github.com/0xProject/0x-monorepo/packages/abi-gen/README.md",
|
||||||
"bignumber.js": "~4.1.0",
|
"dependencies": {
|
||||||
"chalk": "^2.3.0",
|
"@0xproject/utils": "^0.4.1",
|
||||||
"glob": "^7.1.2",
|
"chalk": "^2.3.0",
|
||||||
"handlebars": "^4.0.11",
|
"glob": "^7.1.2",
|
||||||
"lodash": "^4.17.4",
|
"handlebars": "^4.0.11",
|
||||||
"mkdirp": "^0.5.1",
|
"lodash": "^4.17.4",
|
||||||
"to-snake-case": "^1.0.0",
|
"mkdirp": "^0.5.1",
|
||||||
"web3": "^0.20.0",
|
"to-snake-case": "^1.0.0",
|
||||||
"yargs": "^10.0.3"
|
"web3": "^0.20.0",
|
||||||
},
|
"yargs": "^10.0.3"
|
||||||
"devDependencies": {
|
},
|
||||||
"@0xproject/tslint-config": "^0.4.0",
|
"devDependencies": {
|
||||||
"@types/glob": "^5.0.33",
|
"@0xproject/tslint-config": "^0.4.10",
|
||||||
"@types/handlebars": "^4.0.36",
|
"@types/glob": "^5.0.33",
|
||||||
"@types/mkdirp": "^0.5.1",
|
"@types/handlebars": "^4.0.36",
|
||||||
"@types/node": "^8.0.53",
|
"@types/mkdirp": "^0.5.1",
|
||||||
"@types/yargs": "^10.0.0",
|
"@types/node": "^8.0.53",
|
||||||
"npm-run-all": "^4.1.2",
|
"@types/yargs": "^10.0.0",
|
||||||
"shx": "^0.2.2",
|
"npm-run-all": "^4.1.2",
|
||||||
"tslint": "5.8.0",
|
"shx": "^0.2.2",
|
||||||
"typescript": "~2.6.1",
|
"tslint": "5.8.0",
|
||||||
"web3-typescript-typings": "^0.7.2"
|
"typescript": "2.7.1",
|
||||||
}
|
"web3-typescript-typings": "^0.10.0"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,13 +2,4 @@ const postpublish_utils = require('../../../scripts/postpublish_utils');
|
|||||||
const packageJSON = require('../package.json');
|
const packageJSON = require('../package.json');
|
||||||
|
|
||||||
const subPackageName = packageJSON.name;
|
const subPackageName = packageJSON.name;
|
||||||
|
postpublish_utils.standardPostPublishAsync(subPackageName);
|
||||||
postpublish_utils.getLatestTagAndVersionAsync(subPackageName)
|
|
||||||
.then(function(result) {
|
|
||||||
const releaseName = postpublish_utils.getReleaseName(subPackageName, result.version);
|
|
||||||
const assets = [];
|
|
||||||
return postpublish_utils.publishReleaseNotes(result.tag, releaseName, assets);
|
|
||||||
})
|
|
||||||
.catch (function(err) {
|
|
||||||
throw err;
|
|
||||||
});
|
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import chalk from 'chalk';
|
import chalk from 'chalk';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import {sync as globSync} from 'glob';
|
import { sync as globSync } from 'glob';
|
||||||
import * as Handlebars from 'handlebars';
|
import * as Handlebars from 'handlebars';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import * as mkdirp from 'mkdirp';
|
import * as mkdirp from 'mkdirp';
|
||||||
@@ -11,48 +11,85 @@ import * as yargs from 'yargs';
|
|||||||
import toSnakeCase = require('to-snake-case');
|
import toSnakeCase = require('to-snake-case');
|
||||||
import * as Web3 from 'web3';
|
import * as Web3 from 'web3';
|
||||||
|
|
||||||
import {ContextData, ParamKind} from './types';
|
import { ContextData, ContractsBackend, ParamKind } from './types';
|
||||||
import {utils} from './utils';
|
import { utils } from './utils';
|
||||||
|
|
||||||
|
const ABI_TYPE_CONSTRUCTOR = 'constructor';
|
||||||
const ABI_TYPE_METHOD = 'function';
|
const ABI_TYPE_METHOD = 'function';
|
||||||
const MAIN_TEMPLATE_NAME = 'contract.mustache';
|
const ABI_TYPE_EVENT = 'event';
|
||||||
|
const DEFAULT_NETWORK_ID = 50;
|
||||||
|
const DEFAULT_BACKEND = 'web3';
|
||||||
|
|
||||||
const args = yargs
|
const args = yargs
|
||||||
.option('abiGlob', {
|
.option('abis', {
|
||||||
describe: 'Glob pattern to search for ABI JSON files',
|
describe: 'Glob pattern to search for ABI JSON files',
|
||||||
type: 'string',
|
type: 'string',
|
||||||
demand: true,
|
demandOption: true,
|
||||||
})
|
|
||||||
.option('templates', {
|
|
||||||
describe: 'Folder where to search for templates',
|
|
||||||
type: 'string',
|
|
||||||
demand: true,
|
|
||||||
})
|
})
|
||||||
.option('output', {
|
.option('output', {
|
||||||
|
alias: ['o', 'out'],
|
||||||
describe: 'Folder where to put the output files',
|
describe: 'Folder where to put the output files',
|
||||||
type: 'string',
|
type: 'string',
|
||||||
demand: true,
|
normalize: true,
|
||||||
|
demandOption: true,
|
||||||
})
|
})
|
||||||
.argv;
|
.option('partials', {
|
||||||
|
describe: 'Glob pattern for the partial template files',
|
||||||
|
type: 'string',
|
||||||
|
implies: 'template',
|
||||||
|
})
|
||||||
|
.option('template', {
|
||||||
|
describe: 'Path for the main template file that will be used to generate each contract',
|
||||||
|
type: 'string',
|
||||||
|
demandOption: true,
|
||||||
|
normalize: true,
|
||||||
|
})
|
||||||
|
.option('backend', {
|
||||||
|
describe: `The backing Ethereum library your app uses. Either 'web3' or 'ethers'. Ethers auto-converts small ints to numbers whereas Web3 doesn't.`,
|
||||||
|
type: 'string',
|
||||||
|
choices: [ContractsBackend.Web3, ContractsBackend.Ethers],
|
||||||
|
default: DEFAULT_BACKEND,
|
||||||
|
})
|
||||||
|
.option('network-id', {
|
||||||
|
describe: 'ID of the network where contract ABIs are nested in artifacts',
|
||||||
|
type: 'number',
|
||||||
|
default: DEFAULT_NETWORK_ID,
|
||||||
|
})
|
||||||
|
.example(
|
||||||
|
"$0 --abis 'src/artifacts/**/*.json' --out 'src/contracts/generated/' --partials 'src/templates/partials/**/*.handlebars' --template 'src/templates/contract.handlebars'",
|
||||||
|
'Full usage example',
|
||||||
|
).argv;
|
||||||
|
|
||||||
|
function registerPartials(partialsGlob: string) {
|
||||||
|
const partialTemplateFileNames = globSync(partialsGlob);
|
||||||
|
utils.log(`Found ${chalk.green(`${partialTemplateFileNames.length}`)} ${chalk.bold('partial')} templates`);
|
||||||
|
for (const partialTemplateFileName of partialTemplateFileNames) {
|
||||||
|
const namedContent = utils.getNamedContent(partialTemplateFileName);
|
||||||
|
Handlebars.registerPartial(namedContent.name, namedContent.content);
|
||||||
|
}
|
||||||
|
return partialsGlob;
|
||||||
|
}
|
||||||
|
|
||||||
function writeOutputFile(name: string, renderedTsCode: string): void {
|
function writeOutputFile(name: string, renderedTsCode: string): void {
|
||||||
const fileName = toSnakeCase(name);
|
let fileName = toSnakeCase(name);
|
||||||
|
if (fileName === 'z_r_x_token') {
|
||||||
|
fileName = 'zrx_token';
|
||||||
|
}
|
||||||
const filePath = `${args.output}/${fileName}.ts`;
|
const filePath = `${args.output}/${fileName}.ts`;
|
||||||
fs.writeFileSync(filePath, renderedTsCode);
|
fs.writeFileSync(filePath, renderedTsCode);
|
||||||
utils.log(`Created: ${chalk.bold(filePath)}`);
|
utils.log(`Created: ${chalk.bold(filePath)}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
Handlebars.registerHelper('parameterType', utils.solTypeToTsType.bind(utils, ParamKind.Input));
|
Handlebars.registerHelper('parameterType', utils.solTypeToTsType.bind(utils, ParamKind.Input, args.backend));
|
||||||
Handlebars.registerHelper('returnType', utils.solTypeToTsType.bind(utils, ParamKind.Output));
|
Handlebars.registerHelper('returnType', utils.solTypeToTsType.bind(utils, ParamKind.Output, args.backend));
|
||||||
const partialTemplateFileNames = globSync(`${args.templates}/partials/**/*.mustache`);
|
|
||||||
for (const partialTemplateFileName of partialTemplateFileNames) {
|
|
||||||
const namedContent = utils.getNamedContent(partialTemplateFileName);
|
|
||||||
Handlebars.registerPartial(namedContent.name, namedContent.content);
|
|
||||||
}
|
|
||||||
|
|
||||||
const mainTemplate = utils.getNamedContent(`${args.templates}/${MAIN_TEMPLATE_NAME}`);
|
if (args.partials) {
|
||||||
|
registerPartials(args.partials);
|
||||||
|
}
|
||||||
|
const mainTemplate = utils.getNamedContent(args.template);
|
||||||
const template = Handlebars.compile<ContextData>(mainTemplate.content);
|
const template = Handlebars.compile<ContextData>(mainTemplate.content);
|
||||||
const abiFileNames = globSync(args.abiGlob);
|
const abiFileNames = globSync(args.abis);
|
||||||
|
|
||||||
if (_.isEmpty(abiFileNames)) {
|
if (_.isEmpty(abiFileNames)) {
|
||||||
utils.log(`${chalk.red(`No ABI files found.`)}`);
|
utils.log(`${chalk.red(`No ABI files found.`)}`);
|
||||||
utils.log(`Please make sure you've passed the correct folder name and that the files have
|
utils.log(`Please make sure you've passed the correct folder name and that the files have
|
||||||
@@ -66,32 +103,51 @@ for (const abiFileName of abiFileNames) {
|
|||||||
const namedContent = utils.getNamedContent(abiFileName);
|
const namedContent = utils.getNamedContent(abiFileName);
|
||||||
utils.log(`Processing: ${chalk.bold(namedContent.name)}...`);
|
utils.log(`Processing: ${chalk.bold(namedContent.name)}...`);
|
||||||
const parsedContent = JSON.parse(namedContent.content);
|
const parsedContent = JSON.parse(namedContent.content);
|
||||||
const ABI = _.isArray(parsedContent) ?
|
let ABI;
|
||||||
parsedContent : // ABI file
|
if (_.isArray(parsedContent)) {
|
||||||
parsedContent.abi; // Truffle contracts file
|
ABI = parsedContent; // ABI file
|
||||||
|
} else if (!_.isUndefined(parsedContent.abi)) {
|
||||||
|
ABI = parsedContent.abi; // Truffle artifact
|
||||||
|
} else if (!_.isUndefined(parsedContent.networks) && !_.isUndefined(parsedContent.networks[args.networkId])) {
|
||||||
|
ABI = parsedContent.networks[args.networkId].abi; // 0x contracts package artifact
|
||||||
|
}
|
||||||
if (_.isUndefined(ABI)) {
|
if (_.isUndefined(ABI)) {
|
||||||
utils.log(`${chalk.red(`ABI not found in ${abiFileName}.`)}`);
|
utils.log(`${chalk.red(`ABI not found in ${abiFileName}.`)}`);
|
||||||
utils.log(`Please make sure your ABI file is either an array with ABI entries or an object with the abi key`);
|
utils.log(
|
||||||
|
`Please make sure your ABI file is either an array with ABI entries or a truffle artifact or 0x deployer artifact`,
|
||||||
|
);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let ctor = ABI.find((abi: Web3.AbiDefinition) => abi.type === ABI_TYPE_CONSTRUCTOR) as Web3.ConstructorAbi;
|
||||||
|
if (_.isUndefined(ctor)) {
|
||||||
|
ctor = utils.getEmptyConstructor(); // The constructor exists, but it's implicit in JSON's ABI definition
|
||||||
|
}
|
||||||
|
|
||||||
const methodAbis = ABI.filter((abi: Web3.AbiDefinition) => abi.type === ABI_TYPE_METHOD) as Web3.MethodAbi[];
|
const methodAbis = ABI.filter((abi: Web3.AbiDefinition) => abi.type === ABI_TYPE_METHOD) as Web3.MethodAbi[];
|
||||||
const methodsData = _.map(methodAbis, methodAbi => {
|
const methodsData = _.map(methodAbis, methodAbi => {
|
||||||
_.map(methodAbi.inputs, input => {
|
_.map(methodAbi.inputs, (input, i: number) => {
|
||||||
if (_.isEmpty(input.name)) {
|
if (_.isEmpty(input.name)) {
|
||||||
// Auto-generated getters don't have parameter names
|
// Auto-generated getters don't have parameter names
|
||||||
input.name = 'index';
|
input.name = `index_${i}`;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// This will make templates simpler
|
// This will make templates simpler
|
||||||
const methodData = {
|
const methodData = {
|
||||||
...methodAbi,
|
...methodAbi,
|
||||||
singleReturnValue: methodAbi.outputs.length === 1,
|
singleReturnValue: methodAbi.outputs.length === 1,
|
||||||
|
hasReturnValue: methodAbi.outputs.length !== 0,
|
||||||
};
|
};
|
||||||
return methodData;
|
return methodData;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const eventAbis = ABI.filter((abi: Web3.AbiDefinition) => abi.type === ABI_TYPE_EVENT) as Web3.EventAbi[];
|
||||||
|
|
||||||
const contextData = {
|
const contextData = {
|
||||||
contractName: namedContent.name,
|
contractName: namedContent.name,
|
||||||
|
ctor,
|
||||||
methods: methodsData,
|
methods: methodsData,
|
||||||
|
events: eventAbis,
|
||||||
};
|
};
|
||||||
const renderedTsCode = template(contextData);
|
const renderedTsCode = template(contextData);
|
||||||
writeOutputFile(namedContent.name, renderedTsCode);
|
writeOutputFile(namedContent.name, renderedTsCode);
|
||||||
|
|||||||
@@ -5,11 +5,25 @@ export enum ParamKind {
|
|||||||
Output = 'output',
|
Output = 'output',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum AbiType {
|
||||||
|
Function = 'function',
|
||||||
|
Constructor = 'constructor',
|
||||||
|
Event = 'event',
|
||||||
|
Fallback = 'fallback',
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum ContractsBackend {
|
||||||
|
Web3 = 'web3',
|
||||||
|
Ethers = 'ethers',
|
||||||
|
}
|
||||||
|
|
||||||
export interface Method extends Web3.MethodAbi {
|
export interface Method extends Web3.MethodAbi {
|
||||||
singleReturnValue: boolean;
|
singleReturnValue: boolean;
|
||||||
|
hasReturnValue: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ContextData {
|
export interface ContextData {
|
||||||
contractName: string;
|
contractName: string;
|
||||||
methods: Method[];
|
methods: Method[];
|
||||||
|
events: Web3.EventAbi[];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,39 +1,78 @@
|
|||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
import * as Web3 from 'web3';
|
||||||
|
|
||||||
import {ParamKind} from './types';
|
import { AbiType, ContractsBackend, ParamKind } from './types';
|
||||||
|
|
||||||
export const utils = {
|
export const utils = {
|
||||||
solTypeToTsType(paramKind: ParamKind, solType: string): string {
|
solTypeToTsType(
|
||||||
|
paramKind: ParamKind,
|
||||||
|
backend: ContractsBackend,
|
||||||
|
solType: string,
|
||||||
|
components?: Web3.DataItem[],
|
||||||
|
): string {
|
||||||
const trailingArrayRegex = /\[\d*\]$/;
|
const trailingArrayRegex = /\[\d*\]$/;
|
||||||
if (solType.match(trailingArrayRegex)) {
|
if (solType.match(trailingArrayRegex)) {
|
||||||
const arrayItemSolType = solType.replace(trailingArrayRegex, '');
|
const arrayItemSolType = solType.replace(trailingArrayRegex, '');
|
||||||
const arrayItemTsType = utils.solTypeToTsType(paramKind, arrayItemSolType);
|
const arrayItemTsType = utils.solTypeToTsType(paramKind, backend, arrayItemSolType, components);
|
||||||
const arrayTsType = `${arrayItemTsType}[]`;
|
const arrayTsType =
|
||||||
|
utils.isUnionType(arrayItemTsType) || utils.isObjectType(arrayItemTsType)
|
||||||
|
? `Array<${arrayItemTsType}>`
|
||||||
|
: `${arrayItemTsType}[]`;
|
||||||
return arrayTsType;
|
return arrayTsType;
|
||||||
} else {
|
} else {
|
||||||
const solTypeRegexToTsType = [
|
const solTypeRegexToTsType = [
|
||||||
{regex: '^string$', tsType: 'string'},
|
{ regex: '^string$', tsType: 'string' },
|
||||||
{regex: '^address$', tsType: 'string'},
|
{ regex: '^address$', tsType: 'string' },
|
||||||
{regex: '^bool$', tsType: 'boolean'},
|
{ regex: '^bool$', tsType: 'boolean' },
|
||||||
{regex: '^u?int\\d*$', tsType: 'BigNumber'},
|
{ regex: '^u?int\\d*$', tsType: 'BigNumber' },
|
||||||
{regex: '^bytes\\d*$', tsType: 'string'},
|
{ regex: '^bytes\\d*$', tsType: 'string' },
|
||||||
];
|
];
|
||||||
if (paramKind === ParamKind.Input) {
|
if (paramKind === ParamKind.Input) {
|
||||||
// web3 allows to pass those an non-bignumbers and that's nice
|
// web3 and ethers allow to pass those as numbers instead of bignumbers
|
||||||
// but it always returns stuff as BigNumbers
|
solTypeRegexToTsType.unshift({
|
||||||
solTypeRegexToTsType.unshift({regex: '^u?int(8|16|32)?$', tsType: 'number|BigNumber'});
|
regex: '^u?int(8|16|32)?$',
|
||||||
|
tsType: 'number|BigNumber',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (backend === ContractsBackend.Ethers && paramKind === ParamKind.Output) {
|
||||||
|
// ethers-contracts automatically converts small BigNumbers to numbers
|
||||||
|
solTypeRegexToTsType.unshift({
|
||||||
|
regex: '^u?int(8|16|32|48)?$',
|
||||||
|
tsType: 'number',
|
||||||
|
});
|
||||||
}
|
}
|
||||||
for (const regexAndTxType of solTypeRegexToTsType) {
|
for (const regexAndTxType of solTypeRegexToTsType) {
|
||||||
const {regex, tsType} = regexAndTxType;
|
const { regex, tsType } = regexAndTxType;
|
||||||
if (solType.match(regex)) {
|
if (solType.match(regex)) {
|
||||||
return tsType;
|
return tsType;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const TUPLE_TYPE_REGEX = '^tuple$';
|
||||||
|
if (solType.match(TUPLE_TYPE_REGEX)) {
|
||||||
|
const componentsType = _.map(components, component => {
|
||||||
|
const componentValueType = utils.solTypeToTsType(
|
||||||
|
paramKind,
|
||||||
|
backend,
|
||||||
|
component.type,
|
||||||
|
component.components,
|
||||||
|
);
|
||||||
|
const componentType = `${component.name}: ${componentValueType}`;
|
||||||
|
return componentType;
|
||||||
|
});
|
||||||
|
const tsType = `{${componentsType}}`;
|
||||||
|
return tsType;
|
||||||
|
}
|
||||||
throw new Error(`Unknown Solidity type found: ${solType}`);
|
throw new Error(`Unknown Solidity type found: ${solType}`);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
isUnionType(tsType: string): boolean {
|
||||||
|
return tsType === 'number|BigNumber';
|
||||||
|
},
|
||||||
|
isObjectType(tsType: string): boolean {
|
||||||
|
return /^{.*}$/.test(tsType);
|
||||||
|
},
|
||||||
log(...args: any[]): void {
|
log(...args: any[]): void {
|
||||||
console.log(...args); // tslint:disable-line:no-console
|
console.log(...args); // tslint:disable-line:no-console
|
||||||
},
|
},
|
||||||
@@ -41,7 +80,7 @@ export const utils = {
|
|||||||
const name = path.parse(filename).name;
|
const name = path.parse(filename).name;
|
||||||
return name;
|
return name;
|
||||||
},
|
},
|
||||||
getNamedContent(filename: string): {name: string; content: string} {
|
getNamedContent(filename: string): { name: string; content: string } {
|
||||||
const name = utils.getPartialNameFromFileName(filename);
|
const name = utils.getPartialNameFromFileName(filename);
|
||||||
try {
|
try {
|
||||||
const content = fs.readFileSync(filename).toString();
|
const content = fs.readFileSync(filename).toString();
|
||||||
@@ -53,4 +92,12 @@ export const utils = {
|
|||||||
throw new Error(`Failed to read ${filename}: ${err}`);
|
throw new Error(`Failed to read ${filename}: ${err}`);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
getEmptyConstructor(): Web3.ConstructorAbi {
|
||||||
|
return {
|
||||||
|
type: AbiType.Constructor,
|
||||||
|
stateMutability: 'nonpayable',
|
||||||
|
payable: false,
|
||||||
|
inputs: [],
|
||||||
|
};
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,17 +1,7 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"extends": "../../tsconfig",
|
||||||
"module": "commonjs",
|
"compilerOptions": {
|
||||||
"target": "es5",
|
"outDir": "lib"
|
||||||
"lib": ["es2015", "dom"],
|
},
|
||||||
"outDir": "lib",
|
"include": ["./src/**/*", "./test/**/*", "../../node_modules/web3-typescript-typings/index.d.ts"]
|
||||||
"sourceMap": true,
|
|
||||||
"declaration": true,
|
|
||||||
"noImplicitAny": true,
|
|
||||||
"strictNullChecks": true
|
|
||||||
},
|
|
||||||
"include": [
|
|
||||||
"./src/**/*",
|
|
||||||
"./test/**/*",
|
|
||||||
"../../node_modules/web3-typescript-typings/index.d.ts"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
{
|
{
|
||||||
"extends": [
|
"extends": ["@0xproject/tslint-config"]
|
||||||
"@0xproject/tslint-config"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|||||||
6
packages/assert/.npmignore
Normal file
6
packages/assert/.npmignore
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
.*
|
||||||
|
yarn-error.log
|
||||||
|
/src/
|
||||||
|
/scripts/
|
||||||
|
test/
|
||||||
|
tsconfig.json
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user