Compare commits
1605 Commits
@0x/react-
...
monorepo@4
Author | SHA1 | Date | |
---|---|---|---|
|
442de09bbe | ||
|
9131ca1562 | ||
|
92d45a19d1 | ||
|
65af195054 | ||
|
9f47f90c6e | ||
|
472f89bd3d | ||
|
1ddf1087dd | ||
|
dbbd0c5c92 | ||
|
dc6d6024dc | ||
|
febf3489ba | ||
|
cfb200e793 | ||
|
92150b78fc | ||
|
c31f527116 | ||
|
e68c67a01d | ||
|
ea781b8850 | ||
|
ba7c8d9244 | ||
|
a67b34700e | ||
|
abdf91c691 | ||
|
9b540fd8e5 | ||
|
5ec1ae5f7f | ||
|
bed5b275e4 | ||
|
56af9b2aab | ||
|
01e7850cd3 | ||
|
b399aa25aa | ||
|
0a84ee7488 | ||
|
7c7085c932 | ||
|
bbe9862aa6 | ||
|
080c6d3146 | ||
|
2effc3e267 | ||
|
970e670467 | ||
|
36240de897 | ||
|
e4e1c82ad2 | ||
|
9b521aeef5 | ||
|
1fa93fc8ce | ||
|
12177270df | ||
|
d20ed2247f | ||
|
f7fd9789ba | ||
|
75ba724c28 | ||
|
bc3093e635 | ||
|
5d3d596909 | ||
|
5b4d4d5537 | ||
|
521679c87c | ||
|
2a9e03b61e | ||
|
fb003903c7 | ||
|
fbfb6eb45e | ||
|
58be23ac97 | ||
|
90fcf59a32 | ||
|
e74b24bbdb | ||
|
6b5b8fe8e0 | ||
|
0a5ecec3e2 | ||
|
b6f4c5c7da | ||
|
a6ec2a8c54 | ||
|
2fa8b8d1d0 | ||
|
b786836db6 | ||
|
8e5f0f9c5c | ||
|
99e32869e6 | ||
|
04729c44b4 | ||
|
2a2260de45 | ||
|
a7c3996627 | ||
|
6dbcdad1ff | ||
|
f94bdc496a | ||
|
97369c969c | ||
|
72e68c43e3 | ||
|
473537e6e7 | ||
|
ca3e0b26c6 | ||
|
2716374b25 | ||
|
ace968a4fc | ||
|
e6f3693813 | ||
|
531ed54961 | ||
|
5eb316f5d8 | ||
|
97e21106e5 | ||
|
6e4cb0246c | ||
|
125a940560 | ||
|
a7f847bf3e | ||
|
b3978b641c | ||
|
94dc272335 | ||
|
d456710441 | ||
|
e886ef8c4b | ||
|
86a9375d04 | ||
|
f832e035da | ||
|
5656605355 | ||
|
5c4a992b87 | ||
|
0abf1c71f6 | ||
|
85be2fbf19 | ||
|
69de1d05ef | ||
|
237014e823 | ||
|
85a8c6160f | ||
|
e2535027e9 | ||
|
87d157b805 | ||
|
56d48758d3 | ||
|
abfb358250 | ||
|
657b698e1e | ||
|
8ddf925a8f | ||
|
c8eaa63cce | ||
|
b2edd84b0e | ||
|
bc27ee0deb | ||
|
c5632490f2 | ||
|
89ea7b2a2d | ||
|
b3bcd726b8 | ||
|
293dadc22a | ||
|
040b402b6d | ||
|
5c24596d81 | ||
|
552007cafb | ||
|
d2ef88f638 | ||
|
bce7ae78bc | ||
|
90ee70db23 | ||
|
84c8b83694 | ||
|
112724d881 | ||
|
e2510ed28f | ||
|
768e1d541c | ||
|
a650d695ce | ||
|
0eef07307e | ||
|
d69b3a0244 | ||
|
fa5acd07b0 | ||
|
fa612fe173 | ||
|
e10b30886f | ||
|
441b5ac6f1 | ||
|
96a8762704 | ||
|
09eac39040 | ||
|
b96236cdb3 | ||
|
f6525efe95 | ||
|
9728267eac | ||
|
f097259266 | ||
|
38346a9aae | ||
|
ca0ab38521 | ||
|
d2a4fd5706 | ||
|
afe200c4e1 | ||
|
00f5b94d0a | ||
|
1de92659ee | ||
|
25722d8154 | ||
|
bb4ce9b3ad | ||
|
b524ac7af2 | ||
|
dea6f35b04 | ||
|
f3a2e3b6f3 | ||
|
f91781a060 | ||
|
22fd23643c | ||
|
a1266a3341 | ||
|
34ff7fae9c | ||
|
d45c13bfa8 | ||
|
dccca95c2c | ||
|
fc684ad063 | ||
|
6a0f5f39ee | ||
|
4417c76b13 | ||
|
8799f9bb90 | ||
|
6d673ac942 | ||
|
8d6219296a | ||
|
cb9ec18f96 | ||
|
1883f4d272 | ||
|
93b9c251ed | ||
|
3ad72d96f4 | ||
|
4f977aa51d | ||
|
a2df428afb | ||
|
e45a0ffdbf | ||
|
51355209a2 | ||
|
4b0d01ad72 | ||
|
a655f4b193 | ||
|
7af2c751dc | ||
|
d882133e44 | ||
|
7e7880aea0 | ||
|
18f028fb08 | ||
|
14c97b3ec3 | ||
|
58a382d9b6 | ||
|
2be9b1ff08 | ||
|
1cdd82178f | ||
|
dbf1de2e69 | ||
|
ba986432ec | ||
|
3bb147b0f1 | ||
|
0556defa58 | ||
|
4217d0cd7d | ||
|
5863a29a91 | ||
|
df0de07184 | ||
|
28a5ed6a9a | ||
|
c040ad0850 | ||
|
8007ef6c0b | ||
|
a332c5e5c2 | ||
|
bab7569ed9 | ||
|
16bd0ce7ec | ||
|
61a906e9e7 | ||
|
8c9d48477d | ||
|
9f68ac7bbe | ||
|
4e341582ae | ||
|
37a1271af2 | ||
|
743c4c36eb | ||
|
3f7bd24250 | ||
|
33e41dd500 | ||
|
989b5b0a98 | ||
|
a4ab038aa8 | ||
|
e81f92bffa | ||
|
003075a8a5 | ||
|
b4aca370de | ||
|
c854c99f20 | ||
|
0e0e05e0e0 | ||
|
88595718c3 | ||
|
f104d91595 | ||
|
07c1a0121f | ||
|
67521da5c1 | ||
|
9bd71aeeff | ||
|
59d7efa78a | ||
|
102b7154e0 | ||
|
abbb6793cc | ||
|
7b117081d3 | ||
|
342ecae34d | ||
|
b40551e2df | ||
|
ffa57c3703 | ||
|
630ecb98e1 | ||
|
ae27695d25 | ||
|
45d8b522f4 | ||
|
aa5c2c249d | ||
|
1ae9eedf9f | ||
|
622b9f662e | ||
|
e295eeb893 | ||
|
67df5a433d | ||
|
18e55830b5 | ||
|
7664f6a4fd | ||
|
cf553f2afe | ||
|
6cc0e6d55c | ||
|
a6628cd363 | ||
|
6271133350 | ||
|
55589698cf | ||
|
ee0a226c43 | ||
|
d760b355ec | ||
|
4c9bdcd787 | ||
|
b7a8c871d2 | ||
|
230236d4d7 | ||
|
2372925347 | ||
|
df48539d41 | ||
|
90a1947c88 | ||
|
44d9cc53b8 | ||
|
293e099cb3 | ||
|
e34aa4d859 | ||
|
50110b3725 | ||
|
e5815538e4 | ||
|
4fbc544b16 | ||
|
0aa7cbac92 | ||
|
8b24b7c57c | ||
|
ed4573fe2c | ||
|
7468be8f17 | ||
|
0dcada8e06 | ||
|
b255edc577 | ||
|
4ac1db1247 | ||
|
2c24cff950 | ||
|
2107285a00 | ||
|
095cec4342 | ||
|
53529439c5 | ||
|
3cf9cf98dc | ||
|
43cc7b6626 | ||
|
5defa94902 | ||
|
e0116da559 | ||
|
c385627030 | ||
|
031eb8d6a0 | ||
|
c5f85a365b | ||
|
a6fa15c94a | ||
|
14767f1a51 | ||
|
d34d8cac5d | ||
|
1e0aa55368 | ||
|
bb691aa4ed | ||
|
64e84a3510 | ||
|
62f5c58d83 | ||
|
4cf3172c90 | ||
|
8452c05952 | ||
|
8925317c95 | ||
|
248a3998cf | ||
|
be3142a96a | ||
|
4626921bb6 | ||
|
2593f1b8d7 | ||
|
4e80c395b1 | ||
|
1f59c99532 | ||
|
a77e5a1a12 | ||
|
35f7dd71e9 | ||
|
c4036d7d0f | ||
|
6e0d622a15 | ||
|
0e8f0d1d53 | ||
|
c126d01fe3 | ||
|
6d66476d35 | ||
|
039b95c8c1 | ||
|
30ccddf0d5 | ||
|
024e503657 | ||
|
37e5a8a8b7 | ||
|
592c171557 | ||
|
9df0ae90bc | ||
|
33e06fdf40 | ||
|
cce07acf9a | ||
|
d32f77ebb9 | ||
|
35cb769456 | ||
|
9fdd6e56a7 | ||
|
2a0ba501e0 | ||
|
90d4a2b590 | ||
|
f7581d60da | ||
|
2cc03216bd | ||
|
cd4e679db7 | ||
|
28713bdb38 | ||
|
c0b469fdd9 | ||
|
47db165afc | ||
|
f95401ad33 | ||
|
5209729eb1 | ||
|
31bbb0696c | ||
|
6ab8415198 | ||
|
5a6b538a13 | ||
|
42e63b32e3 | ||
|
072c80f475 | ||
|
fb623cf63b | ||
|
5e4defefb0 | ||
|
8d76053210 | ||
|
b7d8362fb1 | ||
|
73e8563413 | ||
|
312d864936 | ||
|
67caa377a4 | ||
|
8234bd5409 | ||
|
3b8598b54b | ||
|
934d3b5d79 | ||
|
5932589776 | ||
|
19e65965c8 | ||
|
8490c31fb7 | ||
|
f242c4206f | ||
|
88240f6401 | ||
|
7065a098e3 | ||
|
6fc80cd776 | ||
|
4611c65aa3 | ||
|
d6866a6dae | ||
|
68be8ef861 | ||
|
0c298b7be4 | ||
|
6eb8256555 | ||
|
240e3558fa | ||
|
8988650c8b | ||
|
28bad6567b | ||
|
1be948bd55 | ||
|
c2b355c25e | ||
|
d12e881e62 | ||
|
85edc297f6 | ||
|
96d89ddade | ||
|
5b4b4123e5 | ||
|
6382f98608 | ||
|
a12b9e82f6 | ||
|
5d0e715d9a | ||
|
896c8d17c1 | ||
|
ee4185ab46 | ||
|
7661cfc85e | ||
|
f510f9df99 | ||
|
7cafe396de | ||
|
6bb2ef9238 | ||
|
737d1dc54d | ||
|
9b4d1a1e38 | ||
|
8c5ff663a9 | ||
|
67422db4bd | ||
|
7d5388edee | ||
|
51b1cab72a | ||
|
e3dcb7107b | ||
|
f7ceb4cf58 | ||
|
e53f28c570 | ||
|
5c083ba16b | ||
|
4d5bfb5cc2 | ||
|
2adeed38d8 | ||
|
21a193e516 | ||
|
926fcb296f | ||
|
f6f441cbe6 | ||
|
b9fa158092 | ||
|
8570616d97 | ||
|
373ebdbe38 | ||
|
a1410409ff | ||
|
32eab3acff | ||
|
d9b5884834 | ||
|
76a4468b85 | ||
|
361dc29338 | ||
|
dbdd2fb7d0 | ||
|
b07892bb48 | ||
|
6d45beccad | ||
|
f0581285d0 | ||
|
04d4e797aa | ||
|
ceddc01985 | ||
|
1955c846f2 | ||
|
1efde6f59b | ||
|
6af0cf87e1 | ||
|
101fd78cb2 | ||
|
91d432aa56 | ||
|
dde2baf204 | ||
|
96cb278cae | ||
|
51777ed61d | ||
|
2b4c557a3f | ||
|
84321c41f3 | ||
|
f9dfecaf13 | ||
|
d1f73da675 | ||
|
94c7bf47db | ||
|
4e8d653f1f | ||
|
c5b63ca441 | ||
|
ea668d1376 | ||
|
086c70bcdc | ||
|
461c7efc26 | ||
|
c145349af0 | ||
|
df445eb53c | ||
|
eadad19cb5 | ||
|
d410c44b07 | ||
|
9fa9a30c4d | ||
|
bdc8f9aa2a | ||
|
6db28c5300 | ||
|
0dc9fc4ef7 | ||
|
41ec26c927 | ||
|
51def6ee6b | ||
|
377b87071a | ||
|
1782418f92 | ||
|
f3f78f63ec | ||
|
a2cb815454 | ||
|
ef200b1ce6 | ||
|
f6c173a97e | ||
|
ef403108fb | ||
|
8a06dccbbf | ||
|
4590d07e7f | ||
|
ba89429aec | ||
|
ee38031696 | ||
|
8948029dd7 | ||
|
e78ddd4d5a | ||
|
f179dc3ca7 | ||
|
166a6c85fd | ||
|
c7c07a7c01 | ||
|
f083cafcc7 | ||
|
fab3a90d5a | ||
|
a04c54b4d8 | ||
|
388c7afb50 | ||
|
51f2711796 | ||
|
907aa7a844 | ||
|
9695be13c3 | ||
|
f452fc5bc7 | ||
|
106df4cdaf | ||
|
ed6d83c0a7 | ||
|
66480ccb1e | ||
|
7a10f03496 | ||
|
64c168eafc | ||
|
44e516ac65 | ||
|
d018f6d9cc | ||
|
d5e15b05fb | ||
|
59fad5845c | ||
|
545101f7a5 | ||
|
2abd8fe4ee | ||
|
3c578cfda9 | ||
|
6878705676 | ||
|
597b2f38f5 | ||
|
9697d66b66 | ||
|
8906c30f37 | ||
|
9cd859a68a | ||
|
33c6e40b70 | ||
|
5744a7f61b | ||
|
f9a6c45a03 | ||
|
f8e84260b5 | ||
|
5a45bc5e7b | ||
|
80f03ef987 | ||
|
e48887bc6f | ||
|
52272cd290 | ||
|
ac1786585e | ||
|
f4a95c295c | ||
|
142d29ba57 | ||
|
d84c740274 | ||
|
1c413e632b | ||
|
9a1d2c055e | ||
|
803086da57 | ||
|
2a242e357f | ||
|
1647400a49 | ||
|
41a8dd3e28 | ||
|
81690d1ce5 | ||
|
f846e2f6e0 | ||
|
bfc8a3ccee | ||
|
daf334a588 | ||
|
4d0c59649e | ||
|
a1737f8d93 | ||
|
455f244ec5 | ||
|
6f7e27bd7f | ||
|
ea57367473 | ||
|
088c471b78 | ||
|
9fda63cf74 | ||
|
4cf900631c | ||
|
fed79b2fde | ||
|
d2e29fb081 | ||
|
b4b1d54e49 | ||
|
a852a4077d | ||
|
1c0bf710a4 | ||
|
f4e9103b6f | ||
|
f8e95ae483 | ||
|
70df5a0a17 | ||
|
79dac62646 | ||
|
5bd185e831 | ||
|
687749460d | ||
|
193cd67d6b | ||
|
8d54772389 | ||
|
0f8acedf02 | ||
|
ddf3bb7c04 | ||
|
3a8f3e01b6 | ||
|
167a3fbc11 | ||
|
f9d436cd21 | ||
|
2e7d363f2c | ||
|
1534505652 | ||
|
9e5e1f568b | ||
|
65579c0236 | ||
|
be045dad9b | ||
|
885c22676b | ||
|
a1186f052d | ||
|
0e76d66f24 | ||
|
2b523a36c5 | ||
|
723dd2bcde | ||
|
a900593c88 | ||
|
756dc1e95e | ||
|
68faaaba5f | ||
|
48fdb567cb | ||
|
bd5a0616c4 | ||
|
0690e68a83 | ||
|
fb99b5ce9d | ||
|
aa8dfa88e1 | ||
|
99941972a3 | ||
|
8a5609718a | ||
|
aeefdeaef7 | ||
|
7b4e536e86 | ||
|
52f733626e | ||
|
c8c68fb75a | ||
|
1364880812 | ||
|
ddc1f34c30 | ||
|
cdca07d829 | ||
|
59b7e25389 | ||
|
87ab8f036c | ||
|
b151b6fe69 | ||
|
8f911206f7 | ||
|
3496725db6 | ||
|
ed588decc6 | ||
|
50e0336018 | ||
|
d07e6cb1d6 | ||
|
ca86f18e7d | ||
|
72e94b3307 | ||
|
7c33c91d59 | ||
|
0f1197c14b | ||
|
4858c0c484 | ||
|
5865b4848d | ||
|
c9af7dc9e5 | ||
|
6e023e6ea3 | ||
|
9176e1f53b | ||
|
0dbe2a91a8 | ||
|
8afac3a92c | ||
|
07a0170f34 | ||
|
1dc67b2874 | ||
|
f09e577885 | ||
|
2c58b8a886 | ||
|
cb53cd05e6 | ||
|
982d59d45d | ||
|
b76a14d51d | ||
|
e8231767ec | ||
|
2b7dabeb6e | ||
|
dde3a0366b | ||
|
8e071db074 | ||
|
93422eab55 | ||
|
74e07b63de | ||
|
7dd0b3a5da | ||
|
b59f20482e | ||
|
98aa7a2c54 | ||
|
7527c61af5 | ||
|
bc6492e352 | ||
|
5c4a2461b8 | ||
|
183edee4ac | ||
|
c513082071 | ||
|
23a6dfac3c | ||
|
e368106932 | ||
|
785981ce58 | ||
|
60bbb9b520 | ||
|
fb81570678 | ||
|
56b82bbc8b | ||
|
05217bb1a2 | ||
|
075fa315e7 | ||
|
fc5f0c9863 | ||
|
13e89d027c | ||
|
ea8f35b743 | ||
|
9365a3bc75 | ||
|
363095f2fe | ||
|
b57b6c04cc | ||
|
e1d77d6e10 | ||
|
da51f6e56f | ||
|
5d0f82c3c6 | ||
|
1878a0c4b0 | ||
|
b538fabdef | ||
|
01716e0d51 | ||
|
7cd3f3cead | ||
|
9d9b5edc9c | ||
|
09a0ca659e | ||
|
1d189d112e | ||
|
829b7cb712 | ||
|
fb8267d85e | ||
|
d842078997 | ||
|
7f574949a4 | ||
|
caeb59a9ae | ||
|
ea95de7d9d | ||
|
52f2ee6e79 | ||
|
ad3d20b342 | ||
|
4fa4f13813 | ||
|
f5f01c0c3e | ||
|
3b9e8e669f | ||
|
99d90bb665 | ||
|
9d8c423b98 | ||
|
d24b2a5a69 | ||
|
aa63632fff | ||
|
d86f5c4fbd | ||
|
0a69752d20 | ||
|
f6ebdd1a3f | ||
|
e2f222b08f | ||
|
50924d62cb | ||
|
da5e8b09d9 | ||
|
fff1e2cfa7 | ||
|
1544e5ed9f | ||
|
4912affbe8 | ||
|
c52ab47185 | ||
|
f082a3f768 | ||
|
27c229a146 | ||
|
43c2b81604 | ||
|
2a133f2c55 | ||
|
4570bc2729 | ||
|
8702a35467 | ||
|
07f80500fa | ||
|
97fc4257a0 | ||
|
25f1b7701f | ||
|
6b889aeeed | ||
|
8e0dcb204f | ||
|
0dc000183a | ||
|
90e1028d2f | ||
|
ed3737c1f1 | ||
|
c9dc69bed6 | ||
|
cd7e41bd5b | ||
|
c46d2f8f9d | ||
|
eb1317a59a | ||
|
98325e1cfb | ||
|
356b7df534 | ||
|
2340813149 | ||
|
8923817b2f | ||
|
7aacf1f5a4 | ||
|
405667fa83 | ||
|
0a3162915f | ||
|
8bcbb64a01 | ||
|
ceafe5ed84 | ||
|
f788fea095 | ||
|
88094002d3 | ||
|
e57a5a6f82 | ||
|
d1ceb2e561 | ||
|
ec2bb616e1 | ||
|
bf56a2c7c4 | ||
|
52b9f4ef3b | ||
|
7845fdbd9c | ||
|
6d2da94f8a | ||
|
20deb01e01 | ||
|
3d9fc6c865 | ||
|
1d5473eece | ||
|
4b4db3802a | ||
|
5eeb848974 | ||
|
5df789bd05 | ||
|
74959cf354 | ||
|
39ceff3d6e | ||
|
fa501e9c93 | ||
|
94c90cc49a | ||
|
d8e03b87d6 | ||
|
f06c17cccc | ||
|
ffff1d5fff | ||
|
fa389f18cd | ||
|
7d5aeacb1c | ||
|
0df51c37d1 | ||
|
bb2581612a | ||
|
3844ce9b60 | ||
|
0c5fa5892c | ||
|
b04a9b9296 | ||
|
2bf831132a | ||
|
6e62b108a9 | ||
|
6262e06afd | ||
|
b1f4bb722d | ||
|
c5db8f25d3 | ||
|
965b1ff32f | ||
|
7f7403cf72 | ||
|
088ca6ce7c | ||
|
5df160ffb9 | ||
|
80efe70247 | ||
|
6c4c666d9b | ||
|
1175a18ccc | ||
|
19f662c196 | ||
|
78a6d23659 | ||
|
f4dc8b12f7 | ||
|
5cff911035 | ||
|
b3fa0c8dac | ||
|
5f7ed71937 | ||
|
b1a73f5c74 | ||
|
318e7d5b57 | ||
|
a939433bd2 | ||
|
42be1a429f | ||
|
96b8100a78 | ||
|
e2b0c4d116 | ||
|
b4cdb14b9b | ||
|
ee7d6fb3af | ||
|
286474ca76 | ||
|
5cbe04acab | ||
|
585c789124 | ||
|
d37680610b | ||
|
e6c1c2a658 | ||
|
36736f82d4 | ||
|
7b72b0c762 | ||
|
184acd874e | ||
|
8a761ce2bc | ||
|
bc8981cbb2 | ||
|
26c9cd3cb2 | ||
|
25f66f96b6 | ||
|
0948ed7a87 | ||
|
bc64c9566c | ||
|
d068956b69 | ||
|
1e5bc143be | ||
|
ec72a4b68c | ||
|
1f4af537c0 | ||
|
91c4191985 | ||
|
1d6e66d937 | ||
|
79d31895fb | ||
|
1d4d254496 | ||
|
528d882ec4 | ||
|
2471d4098f | ||
|
33b36eaf07 | ||
|
27bf0d8a16 | ||
|
b5372ade3c | ||
|
eec9957831 | ||
|
1b7c9b0775 | ||
|
a4d9434290 | ||
|
e001988dbe | ||
|
54c9709bf0 | ||
|
cc0fb833fe | ||
|
96ebad7568 | ||
|
3fb74be4ba | ||
|
86acca5e1c | ||
|
cb2b45bf04 | ||
|
3652b8270a | ||
|
0a05ef36a6 | ||
|
11c864e20d | ||
|
c46870d296 | ||
|
6e54514013 | ||
|
4200064eab | ||
|
e72742f1f7 | ||
|
253bf4df6a | ||
|
dbc4417b19 | ||
|
74bbebeb01 | ||
|
40c0eebd38 | ||
|
5d6fabf528 | ||
|
928b253c81 | ||
|
b4c7f4f57f | ||
|
fc09968062 | ||
|
89755fe3c2 | ||
|
8fd7a9e1f5 | ||
|
5e6d1779cb | ||
|
c580f4ddcb | ||
|
7be2dab9d5 | ||
|
86f1697934 | ||
|
d578b4959d | ||
|
9f5eeed309 | ||
|
14ea4ee1d3 | ||
|
6d523835ae | ||
|
e18be3160e | ||
|
02e14f88d2 | ||
|
096c4c8f2b | ||
|
d050a1bd53 | ||
|
924c2705b2 | ||
|
6c86cc8ab8 | ||
|
6ef5f28f81 | ||
|
dc21c79f2b | ||
|
beffcd990c | ||
|
b88ff0a19f | ||
|
8d93413a5d | ||
|
c622498e50 | ||
|
a0ea0415dd | ||
|
a39e0f13be | ||
|
190d9244cc | ||
|
d56df4fdaf | ||
|
7226944dfd | ||
|
9d8ab43f91 | ||
|
7aee687e6b | ||
|
4138c580bc | ||
|
a3f12cd4de | ||
|
a208cba4e8 | ||
|
8d0b6702c0 | ||
|
9abd1b79e1 | ||
|
bd725eee86 | ||
|
88c18bd2e6 | ||
|
9dc32c2bca | ||
|
bdd287559c | ||
|
194f785939 | ||
|
086568bddf | ||
|
3506c0e501 | ||
|
93eb31f7a0 | ||
|
934117bfe4 | ||
|
7c33f94836 | ||
|
74d0eb40c5 | ||
|
23987c0fa1 | ||
|
cc1b71651d | ||
|
5e1892f383 | ||
|
93d1f2255e | ||
|
727ced0684 | ||
|
0ff13edb58 | ||
|
0341ced3f3 | ||
|
4f6c95b0ca | ||
|
c4ee6836fa | ||
|
55ed406746 | ||
|
f93e77e77c | ||
|
3ac6da7db1 | ||
|
3e93442a43 | ||
|
a617c801bc | ||
|
7d9ab27b9d | ||
|
c686c241c0 | ||
|
a1889e2a23 | ||
|
37a1483359 | ||
|
80811c9cca | ||
|
14d342c3e0 | ||
|
394105b860 | ||
|
1752aa63da | ||
|
9636fd1b76 | ||
|
16f69ad718 | ||
|
03ca825639 | ||
|
c995586063 | ||
|
8dd738629a | ||
|
a286228b20 | ||
|
f14603ca4d | ||
|
4e33d2b481 | ||
|
b74b4eb053 | ||
|
57dc5b6fc0 | ||
|
5febb595e9 | ||
|
1a44d86c59 | ||
|
2bea70a0a6 | ||
|
41f90c697b | ||
|
7d2b5a28e3 | ||
|
7b1471ffe8 | ||
|
8b3b4d983f | ||
|
ac971685b3 | ||
|
4034eb7655 | ||
|
ccd8d4ac30 | ||
|
84f1d1107a | ||
|
c0637a744b | ||
|
701ea77a79 | ||
|
b68f3eb772 | ||
|
47e8bc8e43 | ||
|
51b1de041e | ||
|
eb137cf576 | ||
|
897ba6591d | ||
|
10eb819c75 | ||
|
aa4fcebdc7 | ||
|
ac166ce32e | ||
|
f88ff698a4 | ||
|
dcad94df4c | ||
|
a699a12161 | ||
|
49a1f84e16 | ||
|
23675b4901 | ||
|
950c56d7b8 | ||
|
4b166828b8 | ||
|
c1698aa634 | ||
|
ae6f7cc454 | ||
|
506c736d4f | ||
|
0dbb866918 | ||
|
e82f807d7c | ||
|
b586ecdf92 | ||
|
ff8029402d | ||
|
92361ae811 | ||
|
cba8dc8a75 | ||
|
ef1e5eacbd | ||
|
7ba47c47bb | ||
|
f8f3a3b3cc | ||
|
b6e79fd9e0 | ||
|
b39f511755 | ||
|
43d1f61d28 | ||
|
37e3f481dd | ||
|
5acf053f8b | ||
|
b3038787ea | ||
|
b9305f6ab7 | ||
|
21cbf05362 | ||
|
a3718803a0 | ||
|
6742142ca5 | ||
|
b7e06a2282 | ||
|
4c65bbbb8f | ||
|
105da3f814 | ||
|
4a5b72a5ab | ||
|
2d6c46b83c | ||
|
6f5787b2c4 | ||
|
f96711bac3 | ||
|
ddd246a945 | ||
|
d14d38dabd | ||
|
3ca876c574 | ||
|
6d2f4b91a9 | ||
|
6739261a7e | ||
|
72c45d9ea9 | ||
|
75df8a0e8b | ||
|
f3c28afedd | ||
|
80ab797d3a | ||
|
d6dff5f86a | ||
|
4a715c30fd | ||
|
65bb8bdb5e | ||
|
5237e9c2ed | ||
|
6bab2f70b9 | ||
|
a0a41b1b5d | ||
|
f07dc5ae6d | ||
|
8cb6c2b51b | ||
|
1f87bd8cf6 | ||
|
a2aeca7b66 | ||
|
e394c4fe1d | ||
|
5c655eeda7 | ||
|
d932448563 | ||
|
7f782b6af0 | ||
|
a3f4264790 | ||
|
b818a62d74 | ||
|
e69cdfb7b5 | ||
|
45da317e15 | ||
|
c21cf55b86 | ||
|
2dfdc19c9e | ||
|
012134001a | ||
|
0f869b0545 | ||
|
774971c98c | ||
|
25b6e7092f | ||
|
62412b8551 | ||
|
374d513090 | ||
|
a72463dbdb | ||
|
b159d4e0ec | ||
|
1402a3dfae | ||
|
64865bc10f | ||
|
ef00ac6f51 | ||
|
7a7c66b0ec | ||
|
0166c29625 | ||
|
9c35d53694 | ||
|
8701f9a7b0 | ||
|
427c2cd164 | ||
|
8c0dfc1936 | ||
|
392e89fcbb | ||
|
44c1947740 | ||
|
5719eb28f7 | ||
|
ce7027d11f | ||
|
3ba98e2192 | ||
|
1ae3592e45 | ||
|
dc04d025af | ||
|
5262d3b1f2 | ||
|
7d9afce13b | ||
|
c99b71f354 | ||
|
0133bec07d | ||
|
bd7bde9bb0 | ||
|
a6e5d126c3 | ||
|
8e7ea4695b | ||
|
cc5ea80aa3 | ||
|
d1026a64ba | ||
|
dda44500c5 | ||
|
7b81bd831f | ||
|
44312478fa | ||
|
92f56c63ac | ||
|
3d69063bf6 | ||
|
4e03c754e7 | ||
|
87eaa91410 | ||
|
8f5c92b143 | ||
|
77cc1a95bb | ||
|
27cb0386a3 | ||
|
42d6284cf7 | ||
|
893e9f2731 | ||
|
7a6339ae38 | ||
|
fbb27b1fb2 | ||
|
7f8dc8bb1b | ||
|
c47b42d7c1 | ||
|
3bdcf7857f | ||
|
80a25e4b38 | ||
|
4d7e5b4e5d | ||
|
659ae0dcca | ||
|
7a52168cd8 | ||
|
566953d5e1 | ||
|
a849af8a48 | ||
|
cc235aac38 | ||
|
ec24bf8401 | ||
|
9ebb096025 | ||
|
f8b925c9ad | ||
|
a20d547814 | ||
|
3dcb874e08 | ||
|
6b952c4236 | ||
|
9e1a94266e | ||
|
179f093c26 | ||
|
6438241144 | ||
|
c185618224 | ||
|
b0e7b82dd9 | ||
|
cae0e02bc6 | ||
|
83c1b7aec5 | ||
|
78d0ab1aa2 | ||
|
21122f0137 | ||
|
c282c2fcc4 | ||
|
e6acc0416a | ||
|
ea6547cb75 | ||
|
e839e698f9 | ||
|
b7603bef19 | ||
|
fb221e4ca9 | ||
|
1f8c09779d | ||
|
f9e73d2a6f | ||
|
08eb0b91b6 | ||
|
f2c5a8e2f1 | ||
|
55ebf405a0 | ||
|
92d4c1d09e | ||
|
3454bbfd65 | ||
|
b2dd5495bc | ||
|
69d4e330cf | ||
|
9eff857416 | ||
|
37dbb4d06f | ||
|
a9895c55f9 | ||
|
682b0dd8f4 | ||
|
72a30260d8 | ||
|
00dbddc1aa | ||
|
a365ab11d2 | ||
|
48021a227f | ||
|
0a618f6f4d | ||
|
d0b2ee7fc1 | ||
|
b411e2250a | ||
|
740b73276f | ||
|
e0348f9c04 | ||
|
2e704ac01a | ||
|
00f86ca0f7 | ||
|
549f5e4655 | ||
|
ebdc539da7 | ||
|
2f50cca480 | ||
|
0a944244cf | ||
|
9aff0dfed0 | ||
|
40ac4509ca | ||
|
4e7031e96d | ||
|
0af1bf11c8 | ||
|
d579ba1eda | ||
|
f327d7b4d9 | ||
|
04226106a2 | ||
|
a138ee7e83 | ||
|
1cc043d7a9 | ||
|
a8a6baf964 | ||
|
243a099858 | ||
|
5c29b918df | ||
|
feb715a08b | ||
|
1b4c477ddb | ||
|
8b659dbd77 | ||
|
8721d4ed7a | ||
|
14ad091e83 | ||
|
ce013489ec | ||
|
8c21a700ba | ||
|
87ffa5d7ab | ||
|
7198b441e0 | ||
|
3d211c415b | ||
|
4061731245 | ||
|
96fdb9b766 | ||
|
1aa3f9d69f | ||
|
dea89c4e22 | ||
|
c6af5131b0 | ||
|
9986717671 | ||
|
5cad2ad174 | ||
|
24fd2d9730 | ||
|
0397ff8b22 | ||
|
1a25862086 | ||
|
b771020f88 | ||
|
b42cf0c797 | ||
|
8076333795 | ||
|
b0a2c10e11 | ||
|
303bbc42f4 | ||
|
10e93bb01f | ||
|
a948305e7a | ||
|
26280e4aba | ||
|
55bbe1954b | ||
|
2cbb82eb04 | ||
|
96134003e1 | ||
|
599a3f9b96 | ||
|
688d277b30 | ||
|
329c68f610 | ||
|
6fb333f200 | ||
|
410a924495 | ||
|
53cc9e9bed | ||
|
ccad046eb6 | ||
|
954c3b9272 | ||
|
9cb89725c9 | ||
|
830d0f3b21 | ||
|
8248fbb231 | ||
|
dca2a4e9c2 | ||
|
21d4807206 | ||
|
5e22a862b7 | ||
|
bb440b683a | ||
|
d959b3e234 | ||
|
aeff948c9a | ||
|
7945d2ea62 | ||
|
af2546bc58 | ||
|
3a19faa5ff | ||
|
bbe1a843ef | ||
|
91e7485ecc | ||
|
6c00dd6f39 | ||
|
ada78d140b | ||
|
6aca4e8272 | ||
|
dd093daf91 | ||
|
9ab55ccec0 | ||
|
71a015f2aa | ||
|
b0de2a388f | ||
|
40610830da | ||
|
60bc27c616 | ||
|
2207f09ce2 | ||
|
fe523e1f3f | ||
|
9e9104578c | ||
|
4e6919a6e5 | ||
|
d71fa65359 | ||
|
75d3f24835 | ||
|
2b7f94c00f | ||
|
cd73a047ef | ||
|
57e7119c0d | ||
|
8ad114c5e5 | ||
|
340493a0b1 | ||
|
01e1e5ac3b | ||
|
cb9f7a0664 | ||
|
3e4b77757e | ||
|
110d05f645 | ||
|
36f22ba069 | ||
|
b7d804e949 | ||
|
f576f78b4a | ||
|
dfe5752411 | ||
|
b1a8a5521e | ||
|
323195f4ad | ||
|
c43ba6b3c7 | ||
|
b552c2bd0c | ||
|
ae9614ba36 | ||
|
871ec6cfbc | ||
|
3c7dca37f5 | ||
|
8d0192c1eb | ||
|
ac5a3fae9b | ||
|
9e01f4c9a3 | ||
|
8acb25f577 | ||
|
eec40080a0 | ||
|
18489161c6 | ||
|
4da419cf75 | ||
|
d63576f495 | ||
|
f0213f9a8e | ||
|
e8d0aff333 | ||
|
79f5e36edb | ||
|
a872763413 | ||
|
55ebb04f03 | ||
|
6d312f0230 | ||
|
240a8a50d3 | ||
|
672a4b93ba | ||
|
ea4155e5fa | ||
|
d12b99883b | ||
|
1498e013d0 | ||
|
a1e985a1ca | ||
|
cd44dc7beb | ||
|
db21ae3af1 | ||
|
8c146ce231 | ||
|
703cea6173 | ||
|
1ce84f9bb2 | ||
|
48bfe92740 | ||
|
e592b27f77 | ||
|
1107b84949 | ||
|
7a03df946d | ||
|
d8a3fc0be0 | ||
|
2601d16efb | ||
|
098a531de8 | ||
|
239116eec4 | ||
|
e966641d14 | ||
|
e9fe7dcf54 | ||
|
7086bd32ee | ||
|
50bfbda79a | ||
|
50df67e751 | ||
|
247266b969 | ||
|
0bffc3d10e | ||
|
a882a39937 | ||
|
6b1fea602e | ||
|
afa24aa122 | ||
|
a5eb1bcc20 | ||
|
54aaee8e42 | ||
|
7934d77def | ||
|
cb8601676d | ||
|
98d9a9c648 | ||
|
da8c27c286 | ||
|
de1c296d28 | ||
|
f076cdb832 | ||
|
a192b309f3 | ||
|
c52d48d4db | ||
|
5edc3bfd33 | ||
|
cd4241fac8 | ||
|
3662ab2524 | ||
|
57986c0e1e | ||
|
5bf7b9b8f3 | ||
|
950dae0437 | ||
|
05ef537de0 | ||
|
68d7ce1968 | ||
|
59eca8d748 | ||
|
06304b30c9 | ||
|
03962352df | ||
|
1c03c9168b | ||
|
b6be92e40b | ||
|
06d4abf1ba | ||
|
9349e50bb4 | ||
|
bf672272ce | ||
|
b9fbb3a725 | ||
|
64d52e2113 | ||
|
e0475ce84e | ||
|
1785769916 | ||
|
c5e43f8da5 | ||
|
8a42cea978 | ||
|
8c69a8f1fb | ||
|
9194537085 | ||
|
91397bf8a5 | ||
|
a355001d13 | ||
|
a6046bd5bb | ||
|
7e4f2c6bdc | ||
|
958f4aa8e8 | ||
|
74dac18e47 | ||
|
bcb4808c96 | ||
|
64c5181c14 | ||
|
754be75dbf | ||
|
6f333f2b55 | ||
|
7f77347ea4 | ||
|
5d70fe053d | ||
|
8fda11ec3a | ||
|
a5b6ce6114 | ||
|
0d3fb79c05 | ||
|
e70d897282 | ||
|
c638823373 | ||
|
f8399fee2f | ||
|
52e63effea | ||
|
a219a8c911 | ||
|
de39ec3c97 | ||
|
665a855548 | ||
|
91d2cbfa0a | ||
|
68b0f71d26 | ||
|
91c89d90a5 | ||
|
980e3cb82f | ||
|
eefb1cfe5d | ||
|
5b0746a8ef | ||
|
0faa8b3231 | ||
|
450c72035f | ||
|
5a16e78b54 | ||
|
6d0c71ef30 | ||
|
e015f470dd | ||
|
d142413745 | ||
|
e339e1182d | ||
|
9bee3eba76 | ||
|
866c946b92 | ||
|
8f9a246f48 | ||
|
4668b0732c | ||
|
9ed30fbcca | ||
|
1fab30ef80 | ||
|
62eba1e820 | ||
|
78703ab370 | ||
|
f4e0f74a6d | ||
|
6f44944ffd | ||
|
074944247d | ||
|
593ed12d91 | ||
|
c0f4a35cfd | ||
|
800016b430 | ||
|
937235c4fd | ||
|
4b6ac96a8d | ||
|
502e9c7be4 | ||
|
91b0fd9517 | ||
|
6a3f295b1f | ||
|
d9b4b0e0f3 | ||
|
c342940b5d | ||
|
b19700221f | ||
|
ef041d1603 | ||
|
e47dd4a83e | ||
|
9ebe8d63c8 | ||
|
94d81bd562 | ||
|
34b2f4736e | ||
|
f8daacc19a | ||
|
d77efb611e | ||
|
de8dcf9a72 | ||
|
12d34707b7 | ||
|
ab631060a0 | ||
|
f496096ce1 | ||
|
fc2055cd93 | ||
|
ca22d87290 | ||
|
d6ba7298d4 | ||
|
ea11e8c62d | ||
|
a7fc5975c1 | ||
|
09813cb1d8 | ||
|
9e69257b0d | ||
|
e65096ee7a | ||
|
a1d4aa66bc | ||
|
6c941eebea | ||
|
435d9e47e3 | ||
|
5c12e664a9 | ||
|
46422ff783 | ||
|
3a13286585 | ||
|
c98c8b1ded | ||
|
de0b5772bf | ||
|
dbf62ae205 | ||
|
7962e4050c | ||
|
6bf9889429 | ||
|
7f8b9ef1f7 | ||
|
e91fffd005 | ||
|
7314fd7252 | ||
|
247a69aaec | ||
|
d78ac3f157 | ||
|
315584ef51 | ||
|
57e539ed41 | ||
|
db1babd5be | ||
|
bb63c5c86f | ||
|
82d6f2150b | ||
|
5f177108d1 | ||
|
46aa446a61 | ||
|
0883f7087b | ||
|
e782262572 | ||
|
2ba14d656e | ||
|
0c2848c418 | ||
|
47ef28f88f | ||
|
e81bd1b7f0 | ||
|
929eb45699 | ||
|
4456ba0f6a | ||
|
d6329a83d5 | ||
|
203baa4541 | ||
|
e13406cbf4 | ||
|
df213ac0d5 | ||
|
4d7db045e9 | ||
|
849b744185 | ||
|
7161e8fed9 | ||
|
1105d76861 | ||
|
9b6d738ab1 | ||
|
d586c1f67a | ||
|
fff4dd7e94 | ||
|
c2d9585150 | ||
|
3586dde480 | ||
|
d6b92e5786 | ||
|
ab24dcc290 | ||
|
189920eab9 | ||
|
83499176d9 | ||
|
5294c31997 | ||
|
f1354632a1 | ||
|
7fe27e903b | ||
|
f80768cae0 | ||
|
702dbbae54 | ||
|
fc3641b499 | ||
|
e59d47eac8 | ||
|
d99bdcf036 | ||
|
4616c51e19 | ||
|
d4c439b277 | ||
|
0af07bcf49 | ||
|
a41dfa9ae0 | ||
|
09e2157639 | ||
|
6f394128d4 | ||
|
bd03df8af0 | ||
|
ea61c7a5db | ||
|
a864328ecf | ||
|
2b87d20290 | ||
|
b68273e592 | ||
|
5c66f9117f | ||
|
64e2b91482 | ||
|
ecc417069d | ||
|
b461147389 | ||
|
1d0d4ca147 | ||
|
2103d5c3ed | ||
|
a21bca7cf4 | ||
|
200da7d22c | ||
|
a114cf5c2e | ||
|
4bc5881e9a | ||
|
a9d413728e | ||
|
e10d34cdfc | ||
|
96b9ffc847 | ||
|
9d850cea14 | ||
|
0e7329bcec | ||
|
b564f090f9 | ||
|
ec099dd009 | ||
|
0577a0dbc5 | ||
|
1bba985124 | ||
|
8bcb5b00ba | ||
|
d0fa615f32 | ||
|
ef6cffd9d9 | ||
|
aa4234a38c | ||
|
9b794c00ea | ||
|
03289293c3 | ||
|
0736ba7159 | ||
|
44ac385e8b | ||
|
512b483b6f | ||
|
5a9755da9b | ||
|
be39c5ba99 | ||
|
0c5b645e86 | ||
|
bcb2af2861 | ||
|
906bba7d75 | ||
|
b15531fe68 | ||
|
42e83ae643 | ||
|
b55f7aef7f | ||
|
04503200e5 | ||
|
2da7cadefa | ||
|
b8ea322541 | ||
|
a172ab158e | ||
|
5c13353fb2 | ||
|
d6645b8a91 | ||
|
029b8d5950 | ||
|
14c094d050 | ||
|
f196dc9e35 | ||
|
e7bdf4717d | ||
|
f479212410 | ||
|
ffb8b0a619 | ||
|
1f693ea121 | ||
|
3f545da9f8 | ||
|
f31d4ddffd | ||
|
2e79ce26cb | ||
|
ad1b5af4e5 | ||
|
feb551a02e | ||
|
a8d707b462 | ||
|
3bf5a4e83f | ||
|
50344fa24a | ||
|
bab1c92c70 | ||
|
8f73f53c95 | ||
|
9a51af46ee | ||
|
bb4d02e413 | ||
|
22ce3e2e29 | ||
|
acd364b71c | ||
|
ebaf9dd275 | ||
|
d2d89adbdd | ||
|
58a2dfbc4d | ||
|
173fc1dcef | ||
|
dd8bb6d08b | ||
|
dc7092e1eb | ||
|
c638151b73 | ||
|
978a58105c | ||
|
dcc439c2e3 | ||
|
a895dacd4e | ||
|
5a748fb4e5 | ||
|
fee67326ad | ||
|
a47901370b | ||
|
d4d917f350 | ||
|
aed8b083b5 | ||
|
e6ab6f38ba | ||
|
5934e5a57b | ||
|
29d63cdf97 | ||
|
62e6b22789 | ||
|
0ed1819143 | ||
|
406b5739be | ||
|
fbbca8e283 | ||
|
0f7abcd59b | ||
|
2164b34bf9 | ||
|
b0ebc6fa14 | ||
|
6daa79ec12 | ||
|
acd570b2b3 | ||
|
0d65c9da4a | ||
|
67dd062a2f | ||
|
0c0bcb44d3 | ||
|
b213cb3974 | ||
|
5b187935dc | ||
|
d70d07366f | ||
|
9a0bd05c4c | ||
|
666075a87e | ||
|
b28f26916f | ||
|
a2ad15be0d | ||
|
a630312074 | ||
|
bc538c71fc | ||
|
880540f4b8 | ||
|
8a8b904a29 | ||
|
ebd4dbc6c6 | ||
|
1f9ea7ed1b | ||
|
5b0d554f7b | ||
|
71c050375b | ||
|
1f22ce6061 | ||
|
3ae434c31e | ||
|
063871e549 | ||
|
2d2255e9af | ||
|
93e967c3b3 | ||
|
b71577cc52 | ||
|
27cb966991 | ||
|
457cb1dc84 | ||
|
7c733662e2 | ||
|
52474a0b8e | ||
|
2a6b358717 | ||
|
c5d252ba4a | ||
|
9b1f56c968 | ||
|
13d456fda1 | ||
|
a9e3d489d6 | ||
|
707a93e9f9 | ||
|
bb7dd23738 | ||
|
59206c387e | ||
|
20f1526c7d | ||
|
addfe85f08 | ||
|
58177060a4 | ||
|
3027e6bc0d | ||
|
41e01e9806 | ||
|
0835cf0ea2 | ||
|
1f7fbcf52c | ||
|
2802aed79c | ||
|
78498b7019 | ||
|
1ca23b35ab | ||
|
8b91727364 | ||
|
8f61f6d0f9 | ||
|
180d1ca63a | ||
|
e59669c949 | ||
|
687e6ccdd3 | ||
|
3bc45395cc | ||
|
e95aa617b6 | ||
|
637ab1076a | ||
|
a13099bde3 | ||
|
1600820dea | ||
|
993c5f4b4a | ||
|
af27dd6fe4 | ||
|
02f37fa2d9 | ||
|
2b4febe337 | ||
|
9f35096fa9 | ||
|
39fa26b2f3 | ||
|
7de7fe7823 | ||
|
5053c19599 | ||
|
f35cf03030 | ||
|
91a08b9fdd | ||
|
cef254fa8c | ||
|
e2b115a15c | ||
|
f6cf3de1c4 | ||
|
ef5ba0375a | ||
|
dfa9e435af | ||
|
fc0e7b1132 | ||
|
b99252baae | ||
|
7196046e2f | ||
|
96bcc7e332 | ||
|
d5dbd8cd68 | ||
|
bce62056d9 | ||
|
331cca37e2 | ||
|
a1cff862c9 | ||
|
79126f3b4a | ||
|
77d6594ecb | ||
|
7625935222 | ||
|
0f01e31cc3 | ||
|
1eb19ca1ec | ||
|
6222c952c3 | ||
|
b9c983b4d6 | ||
|
208ee935c8 | ||
|
ec01893e9c | ||
|
f4cc14f438 | ||
|
e5b09ba2fd | ||
|
105dcd73e4 | ||
|
63cb312c7f | ||
|
85d1dba1ef | ||
|
e1c237a8e4 | ||
|
9608d6fc71 | ||
|
7479a7db58 | ||
|
6e3378d79f | ||
|
1375d694ac | ||
|
045336042f | ||
|
0a1425d8d8 | ||
|
7daf995e0d | ||
|
8b05db3510 | ||
|
c2fd6745ee | ||
|
a747abcb73 | ||
|
92a4b09b05 | ||
|
6c76731408 | ||
|
3d88b7f289 | ||
|
d3e6f78fdb | ||
|
16ddd21a5f | ||
|
6c43fa8f72 | ||
|
8a4e5dfb68 | ||
|
f83c4c51c7 | ||
|
7a726e2740 | ||
|
5415d1589e | ||
|
3c000e70e3 | ||
|
06b2f12b10 | ||
|
1b23c430fc | ||
|
ca894935f2 | ||
|
23bfad6c40 | ||
|
850c441c70 | ||
|
53f8e1b3b4 | ||
|
dc434bdff0 | ||
|
0afd490aec | ||
|
c8520c45cb | ||
|
ec6b47ded0 | ||
|
36d94b894a | ||
|
a18a11da92 | ||
|
4bad973877 | ||
|
38e12c2405 | ||
|
f9a7cc94e1 | ||
|
3382077768 | ||
|
b9cbc87882 | ||
|
d05d5ac10d | ||
|
a1fe30e210 | ||
|
56ca19dc9b | ||
|
969674a5ce | ||
|
d2a418b368 | ||
|
081859f334 | ||
|
1cc06dd9e6 | ||
|
d642082058 | ||
|
d3aebd0b79 | ||
|
7b90f095ff | ||
|
df6c1ae059 | ||
|
5578c70cd6 | ||
|
3e2c93f5a0 | ||
|
471a4e981a | ||
|
6b4112527f | ||
|
3a9f8a7296 | ||
|
bbb3e5afcc | ||
|
708f4e9bb8 | ||
|
0b9e9eb0e4 | ||
|
743c43f768 | ||
|
7b51eddc03 | ||
|
6f92f0a7b5 | ||
|
b773d5e592 | ||
|
a0bc97b589 | ||
|
d146e15ff3 | ||
|
037e63ab49 | ||
|
8b80d28029 | ||
|
d3739488ae | ||
|
c5d6b925e4 | ||
|
856f4b473b | ||
|
b95d73d176 | ||
|
462a5face9 | ||
|
b50187f59c | ||
|
9b0020a884 | ||
|
ec12e46e3f | ||
|
35d8525f55 | ||
|
faf80f8595 | ||
|
271adcdb7e | ||
|
717a3bce8c | ||
|
c6ae7b8d3f | ||
|
93672c01af | ||
|
921d9d7ed5 | ||
|
b2e1be5cfe | ||
|
95a80a0e75 | ||
|
e2a16f3f33 | ||
|
70c9908249 | ||
|
ffa2f4554b | ||
|
22a3124662 | ||
|
35b5051148 | ||
|
094aabfcee | ||
|
f5db4be521 | ||
|
d79c754a5b | ||
|
934570d12f | ||
|
748e3c0c53 | ||
|
728617fed2 | ||
|
05d45e7146 | ||
|
d2dd5f93d2 | ||
|
ac1ffe53df |
@@ -18,6 +18,7 @@ jobs:
|
|||||||
name: yarn
|
name: yarn
|
||||||
command: yarn --frozen-lockfile install || yarn --frozen-lockfile install
|
command: yarn --frozen-lockfile install || yarn --frozen-lockfile install
|
||||||
- run: yarn build:ci:no_website
|
- run: yarn build:ci:no_website
|
||||||
|
- run: yarn build:ts
|
||||||
- save_cache:
|
- save_cache:
|
||||||
key: repo-{{ .Environment.CIRCLE_SHA1 }}
|
key: repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||||
paths:
|
paths:
|
||||||
@@ -40,7 +41,12 @@ jobs:
|
|||||||
- restore_cache:
|
- restore_cache:
|
||||||
keys:
|
keys:
|
||||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||||
- run: yarn wsrun test:circleci contracts
|
- run: yarn wsrun test:circleci @0x/contracts-multisig
|
||||||
|
- run: yarn wsrun test:circleci @0x/contracts-utils
|
||||||
|
- run: yarn wsrun test:circleci @0x/contracts-libs
|
||||||
|
- run: yarn wsrun test:circleci @0x/contracts-tokens
|
||||||
|
- run: yarn wsrun test:circleci @0x/contracts-extensions
|
||||||
|
- run: yarn wsrun test:circleci @0x/contracts-protocol
|
||||||
test-contracts-geth:
|
test-contracts-geth:
|
||||||
docker:
|
docker:
|
||||||
- image: circleci/node:9
|
- image: circleci/node:9
|
||||||
@@ -52,7 +58,12 @@ jobs:
|
|||||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||||
# HACK(albrow): we need to sleep 10 seconds to ensure the devnet is
|
# HACK(albrow): we need to sleep 10 seconds to ensure the devnet is
|
||||||
# initialized
|
# initialized
|
||||||
- run: sleep 10 && TEST_PROVIDER=geth yarn wsrun test contracts
|
- run: sleep 10 && TEST_PROVIDER=geth yarn wsrun test @0x/contracts-multisig
|
||||||
|
- run: TEST_PROVIDER=geth yarn wsrun test @0x/contracts-utils
|
||||||
|
- run: TEST_PROVIDER=geth yarn wsrun test @0x/contracts-libs
|
||||||
|
- run: TEST_PROVIDER=geth yarn wsrun test @0x/contracts-tokens
|
||||||
|
- run: TEST_PROVIDER=geth yarn wsrun test @0x/contracts-extensions
|
||||||
|
- run: TEST_PROVIDER=geth yarn wsrun test @0x/contracts-protocol
|
||||||
test-publish:
|
test-publish:
|
||||||
resource_class: medium+
|
resource_class: medium+
|
||||||
docker:
|
docker:
|
||||||
@@ -73,6 +84,20 @@ jobs:
|
|||||||
keys:
|
keys:
|
||||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||||
- run: yarn test:generate_docs:circleci
|
- run: yarn test:generate_docs:circleci
|
||||||
|
test-pipeline:
|
||||||
|
docker:
|
||||||
|
- image: circleci/node:9
|
||||||
|
- image: postgres:11-alpine
|
||||||
|
working_directory: ~/repo
|
||||||
|
steps:
|
||||||
|
- restore_cache:
|
||||||
|
keys:
|
||||||
|
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||||
|
- run: ZEROEX_DATA_PIPELINE_TEST_DB_URL='postgresql://postgres@localhost/postgres' yarn wsrun test:circleci @0x/pipeline
|
||||||
|
- save_cache:
|
||||||
|
key: coverage-pipeline-{{ .Environment.CIRCLE_SHA1 }}
|
||||||
|
paths:
|
||||||
|
- ~/repo/packages/pipeline/coverage/lcov.info
|
||||||
test-rest:
|
test-rest:
|
||||||
docker:
|
docker:
|
||||||
- image: circleci/node:9
|
- image: circleci/node:9
|
||||||
@@ -81,6 +106,7 @@ jobs:
|
|||||||
- restore_cache:
|
- restore_cache:
|
||||||
keys:
|
keys:
|
||||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||||
|
- run: yarn wsrun test:circleci @0x/contracts-test-utils
|
||||||
- run: yarn wsrun test:circleci @0x/abi-gen
|
- run: yarn wsrun test:circleci @0x/abi-gen
|
||||||
- run: yarn wsrun test:circleci @0x/assert
|
- run: yarn wsrun test:circleci @0x/assert
|
||||||
- run: yarn wsrun test:circleci @0x/base-contract
|
- run: yarn wsrun test:circleci @0x/base-contract
|
||||||
@@ -165,6 +191,9 @@ jobs:
|
|||||||
- image: 0xorg/ganache-cli
|
- image: 0xorg/ganache-cli
|
||||||
command: |
|
command: |
|
||||||
ganache-cli --gasLimit 10000000 --noVMErrorsOnRPCResponse --db /snapshot --noVMErrorsOnRPCResponse -p 8545 --networkId 50 -m "concert load couple harbor equip island argue ramp clarify fence smart topic"
|
ganache-cli --gasLimit 10000000 --noVMErrorsOnRPCResponse --db /snapshot --noVMErrorsOnRPCResponse -p 8545 --networkId 50 -m "concert load couple harbor equip island argue ramp clarify fence smart topic"
|
||||||
|
- image: 0xorg/launch-kit-ci
|
||||||
|
command: |
|
||||||
|
yarn start:ts -p 3000:3000
|
||||||
steps:
|
steps:
|
||||||
- checkout
|
- checkout
|
||||||
- run: sudo chown -R circleci:circleci /usr/local/bin
|
- run: sudo chown -R circleci:circleci /usr/local/bin
|
||||||
@@ -176,6 +205,11 @@ jobs:
|
|||||||
cd python-packages/order_utils
|
cd python-packages/order_utils
|
||||||
python -m ensurepip
|
python -m ensurepip
|
||||||
python -m pip install -e .[dev]
|
python -m pip install -e .[dev]
|
||||||
|
- run:
|
||||||
|
command: |
|
||||||
|
cd python-packages/sra_client
|
||||||
|
python -m ensurepip
|
||||||
|
python -m pip install -e .
|
||||||
- save_cache:
|
- save_cache:
|
||||||
key: deps9-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }}
|
key: deps9-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }}
|
||||||
paths:
|
paths:
|
||||||
@@ -189,10 +223,18 @@ jobs:
|
|||||||
command: |
|
command: |
|
||||||
cd python-packages/order_utils
|
cd python-packages/order_utils
|
||||||
coverage run setup.py test
|
coverage run setup.py test
|
||||||
|
- run:
|
||||||
|
command: |
|
||||||
|
cd python-packages/sra_client
|
||||||
|
coverage run setup.py test
|
||||||
- save_cache:
|
- save_cache:
|
||||||
key: coverage-python-order-utils-{{ .Environment.CIRCLE_SHA1 }}
|
key: coverage-python-order-utils-{{ .Environment.CIRCLE_SHA1 }}
|
||||||
paths:
|
paths:
|
||||||
- ~/repo/python-packages/order_utils/.coverage
|
- ~/repo/python-packages/order_utils/.coverage
|
||||||
|
- save_cache:
|
||||||
|
key: coverage-python-sra-client-{{ .Environment.CIRCLE_SHA1 }}
|
||||||
|
paths:
|
||||||
|
- ~/repo/python-packages/sra_client/.coverage
|
||||||
test-rest-python:
|
test-rest-python:
|
||||||
working_directory: ~/repo
|
working_directory: ~/repo
|
||||||
docker:
|
docker:
|
||||||
@@ -331,6 +373,9 @@ workflows:
|
|||||||
- test-contracts-geth:
|
- test-contracts-geth:
|
||||||
requires:
|
requires:
|
||||||
- build
|
- build
|
||||||
|
- test-pipeline:
|
||||||
|
requires:
|
||||||
|
- build
|
||||||
- test-rest:
|
- test-rest:
|
||||||
requires:
|
requires:
|
||||||
- build
|
- build
|
||||||
|
2
.github/stale.yml
vendored
2
.github/stale.yml
vendored
@@ -1,7 +1,7 @@
|
|||||||
# Number of days of inactivity before an issue becomes stale
|
# Number of days of inactivity before an issue becomes stale
|
||||||
daysUntilStale: 30
|
daysUntilStale: 30
|
||||||
# Number of days of inactivity before a stale issue is closed
|
# Number of days of inactivity before a stale issue is closed
|
||||||
daysUntilClose: 7
|
daysUntilClose: 30
|
||||||
# Issues with these labels will never be considered stale
|
# Issues with these labels will never be considered stale
|
||||||
exemptLabels:
|
exemptLabels:
|
||||||
- pinned
|
- pinned
|
||||||
|
22
.gitignore
vendored
22
.gitignore
vendored
@@ -11,6 +11,10 @@ pids
|
|||||||
*.seed
|
*.seed
|
||||||
*.pid.lock
|
*.pid.lock
|
||||||
|
|
||||||
|
# SQLite database files
|
||||||
|
*.db
|
||||||
|
*.sqlite
|
||||||
|
|
||||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||||
lib-cov
|
lib-cov
|
||||||
|
|
||||||
@@ -79,13 +83,27 @@ packages/react-docs/example/public/bundle*
|
|||||||
packages/testnet-faucets/server/
|
packages/testnet-faucets/server/
|
||||||
|
|
||||||
# generated contract artifacts/
|
# generated contract artifacts/
|
||||||
packages/contracts/generated-artifacts/
|
contracts/protocol/generated-artifacts/
|
||||||
|
contracts/multisig/generated-artifacts/
|
||||||
|
contracts/utils/generated-artifacts/
|
||||||
|
contracts/libs/generated-artifacts/
|
||||||
|
contracts/interfaces/generated-artifacts/
|
||||||
|
contracts/tokens/generated-artifacts/
|
||||||
|
contracts/examples/generated-artifacts/
|
||||||
|
contracts/extensions/generated-artifacts/
|
||||||
packages/sol-cov/test/fixtures/artifacts/
|
packages/sol-cov/test/fixtures/artifacts/
|
||||||
packages/metacoin/artifacts/
|
packages/metacoin/artifacts/
|
||||||
|
|
||||||
# generated contract wrappers
|
# generated contract wrappers
|
||||||
packages/abi-gen-wrappers/wrappers
|
packages/abi-gen-wrappers/wrappers
|
||||||
packages/contracts/generated-wrappers/
|
contracts/protocol/generated-wrappers/
|
||||||
|
contracts/multisig/generated-wrappers/
|
||||||
|
contracts/utils/generated-wrappers/
|
||||||
|
contracts/libs/generated-wrappers/
|
||||||
|
contracts/interfaces/generated-wrappers/
|
||||||
|
contracts/tokens/generated-wrappers/
|
||||||
|
contracts/examples/generated-wrappers/
|
||||||
|
contracts/extensions/generated-wrappers/
|
||||||
packages/metacoin/src/contract_wrappers
|
packages/metacoin/src/contract_wrappers
|
||||||
|
|
||||||
# solc-bin in sol-compiler
|
# solc-bin in sol-compiler
|
||||||
|
@@ -1,7 +1,21 @@
|
|||||||
lib
|
lib
|
||||||
.nyc_output
|
.nyc_output
|
||||||
/packages/contracts/generated-wrappers
|
/contracts/protocol/generated-wrappers
|
||||||
/packages/contracts/generated-artifacts
|
/contracts/protocol/generated-artifacts
|
||||||
|
/contracts/multisig/generated-wrappers
|
||||||
|
/contracts/multisig/generated-artifacts
|
||||||
|
/contracts/utils/generated-wrappers
|
||||||
|
/contracts/utils/generated-artifacts
|
||||||
|
/contracts/libs/generated-wrappers
|
||||||
|
/contracts/libs/generated-artifacts
|
||||||
|
/contracts/interfaces/generated-wrappers
|
||||||
|
/contracts/interfaces/generated-artifacts
|
||||||
|
/contracts/tokens/generated-wrappers
|
||||||
|
/contracts/tokens/generated-artifacts
|
||||||
|
/contracts/examples/generated-wrappers
|
||||||
|
/contracts/examples/generated-artifacts
|
||||||
|
/contracts/extensions/generated-wrappers
|
||||||
|
/contracts/extensions/generated-artifacts
|
||||||
/packages/abi-gen-wrappers/src/generated-wrappers
|
/packages/abi-gen-wrappers/src/generated-wrappers
|
||||||
/packages/contract-artifacts/artifacts
|
/packages/contract-artifacts/artifacts
|
||||||
/python-packages/order_utils/src/zero_ex/contract_artifacts/artifacts
|
/python-packages/order_utils/src/zero_ex/contract_artifacts/artifacts
|
||||||
|
@@ -14,7 +14,7 @@ packages/website/ @BMillman19 @fragosti @fabioberger @steveklebanoff
|
|||||||
packages/abi-gen/ @LogvinovLeon
|
packages/abi-gen/ @LogvinovLeon
|
||||||
packages/base-contract/ @LogvinovLeon
|
packages/base-contract/ @LogvinovLeon
|
||||||
packages/connect/ @fragosti
|
packages/connect/ @fragosti
|
||||||
packages/contract_templates/ @LogvinovLeon
|
packages/abi-gen-templates/ @LogvinovLeon
|
||||||
packages/contract-addresses/ @albrow
|
packages/contract-addresses/ @albrow
|
||||||
packages/contract-artifacts/ @albrow
|
packages/contract-artifacts/ @albrow
|
||||||
packages/dev-utils/ @LogvinovLeon @fabioberger
|
packages/dev-utils/ @LogvinovLeon @fabioberger
|
||||||
@@ -32,4 +32,4 @@ packages/web3-wrapper/ @LogvinovLeon @fabioberger
|
|||||||
python-packages/ @feuGeneA
|
python-packages/ @feuGeneA
|
||||||
|
|
||||||
# Protocol/smart contracts
|
# Protocol/smart contracts
|
||||||
packages/contracts/test/ @albrow
|
contracts/core/test/ @albrow
|
||||||
|
@@ -79,7 +79,20 @@ If using the Atom text editor, we recommend you install the following packages:
|
|||||||
* VSCode: [prettier-vscode](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode)
|
* VSCode: [prettier-vscode](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode)
|
||||||
* Atom: [prettier-atom](https://atom.io/packages/prettier-atom)
|
* Atom: [prettier-atom](https://atom.io/packages/prettier-atom)
|
||||||
|
|
||||||
## Fix `submit-coverage` CI failure
|
## Unenforced coding conventions
|
||||||
|
|
||||||
|
A few of our coding conventions are not yet enforced by the linter/auto-formatter. Be careful to follow these conventions in your PR's.
|
||||||
|
|
||||||
|
1. Unused anonymous function parameters should be named with an underscore + number (e.g \_1, \_2, etc...)
|
||||||
|
1. There should be a new-line between methods in a class and between test cases.
|
||||||
|
1. If a string literal has the same value in two or more places, it should be a single constant referenced in both places.
|
||||||
|
1. Do not import from a project's `index.ts` (e.g import { Token } from '../src';). Always import from the source file itself.
|
||||||
|
1. Generic error variables should be named `err` instead of `e` or `error`.
|
||||||
|
1. If you _must_ cast a variable to any - try to type it back as fast as possible. (e.g., `const cw = ((zeroEx as any)._contractWrappers as ContractWrappers);`). This ensures subsequent code is type-safe.
|
||||||
|
1. Our enum conventions coincide with the recommended Typescript conventions, using capitalized keys, and all-caps snake-case values. Eg `GetStats = 'GET_STATS'`
|
||||||
|
1. All public, exported methods/functions/classes must have associated Javadoc-style comments.
|
||||||
|
|
||||||
|
### Fix `submit-coverage` CI failure
|
||||||
|
|
||||||
If you simply fork the repo and then create a PR from it, your PR will fail the `submit-coverage` check on CI. This is because the 0x CircleCI configuration sets the `COVERALLS_REPO_TOKEN` environment variable to the token for `0xProject/0x-monorepo`, but when running the check against your fork the token needs to match your repo's name `your-username/0x-monorepo`.
|
If you simply fork the repo and then create a PR from it, your PR will fail the `submit-coverage` check on CI. This is because the 0x CircleCI configuration sets the `COVERALLS_REPO_TOKEN` environment variable to the token for `0xProject/0x-monorepo`, but when running the check against your fork the token needs to match your repo's name `your-username/0x-monorepo`.
|
||||||
|
|
||||||
|
10
README.md
10
README.md
@@ -25,8 +25,9 @@ Visit our [developer portal](https://0xproject.com/docs/order-utils) for a compr
|
|||||||
### Python Packages
|
### Python Packages
|
||||||
|
|
||||||
| Package | Version | Description |
|
| Package | Version | Description |
|
||||||
| --------------------------------------------------- | ----------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- |
|
| ------------------------------------------------ | ----------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
|
||||||
| [`0x-order-utils.py`](/python-packages/order_utils) | [](https://pypi.org/project/0x-order-utils/) | A set of utilities for generating, parsing, signing and validating 0x orders |
|
| [`0x-order-utils`](/python-packages/order_utils) | [](https://pypi.org/project/0x-order-utils/) | A set of utilities for generating, parsing, signing and validating 0x orders |
|
||||||
|
| [`0x-sra-client`](/python-packages/sra_client) | [](https://pypi.org/project/0x-sra-client/) | A Python client for interacting with servers conforming to the Standard Relayer API specification |
|
||||||
|
|
||||||
### Typescript/Javascript Packages
|
### Typescript/Javascript Packages
|
||||||
|
|
||||||
@@ -77,8 +78,9 @@ Visit our [developer portal](https://0xproject.com/docs/order-utils) for a compr
|
|||||||
#### Private Packages
|
#### Private Packages
|
||||||
|
|
||||||
| Package | Description |
|
| Package | Description |
|
||||||
| -------------------------------------------------- | ---------------------------------------------------------------- |
|
| -------------------------------------------------- | -------------------------------------------------------------------------------- |
|
||||||
| [`@0x/contracts`](/packages/contracts) | 0x protocol solidity smart contracts & tests |
|
| [`@0x/contracts`](/contracts/core) | 0x protocol solidity smart contracts & tests |
|
||||||
|
| [`@0x/instant`](/packages/instant) | A free and flexible way to offer simple crypto purchasing in any app or website. |
|
||||||
| [`@0x/testnet-faucets`](/packages/testnet-faucets) | A faucet micro-service that dispenses test ERC20 tokens or Ether |
|
| [`@0x/testnet-faucets`](/packages/testnet-faucets) | A faucet micro-service that dispenses test ERC20 tokens or Ether |
|
||||||
| [`@0x/website`](/packages/website) | 0x website |
|
| [`@0x/website`](/packages/website) | 0x website |
|
||||||
|
|
||||||
|
@@ -5,6 +5,7 @@
|
|||||||
"avoid-tx-origin": "warn",
|
"avoid-tx-origin": "warn",
|
||||||
"bracket-align": false,
|
"bracket-align": false,
|
||||||
"code-complexity": false,
|
"code-complexity": false,
|
||||||
|
"compiler-fixed": false,
|
||||||
"const-name-snakecase": "error",
|
"const-name-snakecase": "error",
|
||||||
"expression-indent": "error",
|
"expression-indent": "error",
|
||||||
"function-max-lines": false,
|
"function-max-lines": false,
|
48
contracts/TESTING.md
Normal file
48
contracts/TESTING.md
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
# Contracts testing options
|
||||||
|
|
||||||
|
## Revert stack traces
|
||||||
|
|
||||||
|
If you want to see helpful stack traces (incl. line number, code snippet) for smart contract reverts, run the tests with:
|
||||||
|
|
||||||
|
```
|
||||||
|
yarn test:trace
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note:** This currently slows down the test runs and is therefore not enabled by default.
|
||||||
|
|
||||||
|
## Backing Ethereum node
|
||||||
|
|
||||||
|
By default, our tests run against an in-process [Ganache](https://github.com/trufflesuite/ganache-core) instance. In order to run the tests against [Geth](https://github.com/ethereum/go-ethereum), first follow the instructions in the README for the devnet package to start the devnet Geth node. Then run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
TEST_PROVIDER=geth yarn test
|
||||||
|
```
|
||||||
|
|
||||||
|
## Code coverage
|
||||||
|
|
||||||
|
In order to see the Solidity code coverage output generated by `@0x/sol-cov`, run:
|
||||||
|
|
||||||
|
```
|
||||||
|
yarn test:coverage
|
||||||
|
```
|
||||||
|
|
||||||
|
## Gas profiler
|
||||||
|
|
||||||
|
In order to profile the gas costs for a specific smart contract call/transaction, you can run the tests in `profiler` mode.
|
||||||
|
|
||||||
|
**Note:** Traces emitted by ganache have incorrect gas costs so we recommend using Geth for profiling.
|
||||||
|
|
||||||
|
```
|
||||||
|
TEST_PROVIDER=geth yarn test:profiler
|
||||||
|
```
|
||||||
|
|
||||||
|
You'll see a warning that you need to explicitly enable and disable the profiler before and after the block of code you want to profile.
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { profiler } from './utils/profiler';
|
||||||
|
profiler.start();
|
||||||
|
// Some call to a smart contract
|
||||||
|
profiler.stop();
|
||||||
|
```
|
||||||
|
|
||||||
|
Without explicitly starting and stopping the profiler, the profiler output will be too busy, and therefore unusable.
|
11
contracts/examples/CHANGELOG.json
Normal file
11
contracts/examples/CHANGELOG.json
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"timestamp": 1544741676,
|
||||||
|
"version": "1.0.2",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
10
contracts/examples/CHANGELOG.md
Normal file
10
contracts/examples/CHANGELOG.md
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<!--
|
||||||
|
changelogUtils.file is auto-generated using the monorepo-scripts package. Don't edit directly.
|
||||||
|
Edit the package's CHANGELOG.json file only.
|
||||||
|
-->
|
||||||
|
|
||||||
|
CHANGELOG
|
||||||
|
|
||||||
|
## v1.0.2 - _December 13, 2018_
|
||||||
|
|
||||||
|
* Dependencies updated
|
56
contracts/examples/README.md
Normal file
56
contracts/examples/README.md
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
## Contract examples
|
||||||
|
|
||||||
|
Example smart contracts that interact with 0x protocol.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Contracts can be found in the [contracts](./contracts) directory.
|
||||||
|
This package contains example implementations of contracts that interact with the protocol but are _not_ intended for use in production. Examples include [filter](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#filter-contracts) contracts, a [Wallet](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#wallet) contract, and a [Validator](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#validator) contract, among others.
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
We strongly recommend that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository.
|
||||||
|
|
||||||
|
For proposals regarding the 0x protocol's smart contract architecture, message format, or additional functionality, go to the [0x Improvement Proposals (ZEIPs)](https://github.com/0xProject/ZEIPs) repository and follow the contribution guidelines provided therein.
|
||||||
|
|
||||||
|
Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started.
|
||||||
|
|
||||||
|
### Install Dependencies
|
||||||
|
|
||||||
|
If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yarn config set workspaces-experimental true
|
||||||
|
```
|
||||||
|
|
||||||
|
Then install dependencies
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yarn install
|
||||||
|
```
|
||||||
|
|
||||||
|
### Build
|
||||||
|
|
||||||
|
To build this package and all other monorepo packages that it depends on, run the following from the monorepo root directory:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
PKG=@0x/contracts-examples yarn build
|
||||||
|
```
|
||||||
|
|
||||||
|
Or continuously rebuild on change:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
PKG=@0x/contracts-examples yarn watch
|
||||||
|
```
|
||||||
|
|
||||||
|
### Clean
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yarn clean
|
||||||
|
```
|
||||||
|
|
||||||
|
### Lint
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yarn lint
|
||||||
|
```
|
22
contracts/examples/compiler.json
Normal file
22
contracts/examples/compiler.json
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"artifactsDir": "./generated-artifacts",
|
||||||
|
"contractsDir": "./contracts",
|
||||||
|
"compilerSettings": {
|
||||||
|
"optimizer": {
|
||||||
|
"enabled": true,
|
||||||
|
"runs": 1000000
|
||||||
|
},
|
||||||
|
"outputSelection": {
|
||||||
|
"*": {
|
||||||
|
"*": [
|
||||||
|
"abi",
|
||||||
|
"evm.bytecode.object",
|
||||||
|
"evm.bytecode.sourceMap",
|
||||||
|
"evm.deployedBytecode.object",
|
||||||
|
"evm.deployedBytecode.sourceMap"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"contracts": ["ExchangeWrapper", "Validator", "Wallet", "Whitelist"]
|
||||||
|
}
|
@@ -19,8 +19,8 @@
|
|||||||
pragma solidity 0.4.24;
|
pragma solidity 0.4.24;
|
||||||
pragma experimental ABIEncoderV2;
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
import "../../protocol/Exchange/interfaces/IExchange.sol";
|
import "@0x/contracts-interfaces/contracts/protocol/Exchange/IExchange.sol";
|
||||||
import "../../protocol/Exchange/libs/LibOrder.sol";
|
import "@0x/contracts-libs/contracts/libs/LibOrder.sol";
|
||||||
|
|
||||||
|
|
||||||
contract ExchangeWrapper {
|
contract ExchangeWrapper {
|
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
pragma solidity 0.4.24;
|
pragma solidity 0.4.24;
|
||||||
|
|
||||||
import "../../protocol/Exchange/interfaces/IValidator.sol";
|
import "@0x/contracts-interfaces/contracts/protocol/Exchange/IValidator.sol";
|
||||||
|
|
||||||
|
|
||||||
contract Validator is
|
contract Validator is
|
@@ -18,8 +18,8 @@
|
|||||||
|
|
||||||
pragma solidity 0.4.24;
|
pragma solidity 0.4.24;
|
||||||
|
|
||||||
import "../../protocol/Exchange/interfaces/IWallet.sol";
|
import "@0x/contracts-interfaces/contracts/protocol/Exchange/IWallet.sol";
|
||||||
import "../../utils/LibBytes/LibBytes.sol";
|
import "@0x/contracts-utils/contracts/utils/LibBytes/LibBytes.sol";
|
||||||
|
|
||||||
|
|
||||||
contract Wallet is
|
contract Wallet is
|
@@ -19,9 +19,9 @@
|
|||||||
pragma solidity 0.4.24;
|
pragma solidity 0.4.24;
|
||||||
pragma experimental ABIEncoderV2;
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
import "../../protocol/Exchange/interfaces/IExchange.sol";
|
import "@0x/contracts-interfaces/contracts/protocol/Exchange/IExchange.sol";
|
||||||
import "../../protocol/Exchange/libs/LibOrder.sol";
|
import "@0x/contracts-libs/contracts/libs/LibOrder.sol";
|
||||||
import "../../utils/Ownable/Ownable.sol";
|
import "@0x/contracts-utils/contracts/utils/Ownable/Ownable.sol";
|
||||||
|
|
||||||
|
|
||||||
contract Whitelist is
|
contract Whitelist is
|
83
contracts/examples/package.json
Normal file
83
contracts/examples/package.json
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
{
|
||||||
|
"name": "@0x/contracts-examples",
|
||||||
|
"version": "1.0.2",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.12"
|
||||||
|
},
|
||||||
|
"description": "Smart contract examples of 0x protocol",
|
||||||
|
"main": "lib/src/index.js",
|
||||||
|
"directories": {
|
||||||
|
"test": "test"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"build": "yarn pre_build && tsc -b",
|
||||||
|
"build:ci": "yarn build",
|
||||||
|
"pre_build": "run-s compile generate_contract_wrappers",
|
||||||
|
"compile": "sol-compiler",
|
||||||
|
"watch": "sol-compiler -w",
|
||||||
|
"clean": "shx rm -rf lib generated-artifacts generated-wrappers",
|
||||||
|
"generate_contract_wrappers": "abi-gen --abis ${npm_package_config_abis} --template ../../node_modules/@0x/abi-gen-templates/contract.handlebars --partials '../../node_modules/@0x/abi-gen-templates/partials/**/*.handlebars' --output generated-wrappers --backend ethers",
|
||||||
|
"lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
|
||||||
|
"lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol"
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"abis": "generated-artifacts/@(ExchangeWrapper|Validator|Wallet|Whitelist).json"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/0xProject/0x-monorepo.git"
|
||||||
|
},
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/0xProject/0x-monorepo/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/examples/README.md",
|
||||||
|
"devDependencies": {
|
||||||
|
"@0x/abi-gen": "^1.0.19",
|
||||||
|
"@0x/contracts-test-utils": "^1.0.2",
|
||||||
|
"@0x/dev-utils": "^1.0.21",
|
||||||
|
"@0x/sol-compiler": "^1.1.16",
|
||||||
|
"@0x/sol-cov": "^2.1.16",
|
||||||
|
"@0x/subproviders": "^2.1.8",
|
||||||
|
"@0x/tslint-config": "^2.0.0",
|
||||||
|
"@types/bn.js": "^4.11.0",
|
||||||
|
"@types/lodash": "4.14.104",
|
||||||
|
"@types/node": "*",
|
||||||
|
"@types/yargs": "^10.0.0",
|
||||||
|
"chai": "^4.0.1",
|
||||||
|
"chai-as-promised": "^7.1.0",
|
||||||
|
"chai-bignumber": "^2.0.1",
|
||||||
|
"dirty-chai": "^2.0.1",
|
||||||
|
"ethereumjs-abi": "0.6.5",
|
||||||
|
"make-promises-safe": "^1.1.0",
|
||||||
|
"mocha": "^4.1.0",
|
||||||
|
"npm-run-all": "^4.1.2",
|
||||||
|
"shx": "^0.2.2",
|
||||||
|
"solc": "^0.4.24",
|
||||||
|
"solhint": "^1.4.1",
|
||||||
|
"tslint": "5.11.0",
|
||||||
|
"typescript": "3.0.1",
|
||||||
|
"yargs": "^10.0.3"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@0x/base-contract": "^3.0.10",
|
||||||
|
"@0x/contracts-interfaces": "^1.0.2",
|
||||||
|
"@0x/contracts-libs": "^1.0.2",
|
||||||
|
"@0x/contracts-multisig": "^1.0.2",
|
||||||
|
"@0x/contracts-tokens": "^1.0.2",
|
||||||
|
"@0x/contracts-utils": "^1.0.2",
|
||||||
|
"@0x/order-utils": "^3.0.7",
|
||||||
|
"@0x/types": "^1.4.1",
|
||||||
|
"@0x/typescript-typings": "^3.0.6",
|
||||||
|
"@0x/utils": "^2.0.8",
|
||||||
|
"@0x/web3-wrapper": "^3.2.1",
|
||||||
|
"@types/js-combinatorics": "^0.5.29",
|
||||||
|
"bn.js": "^4.11.8",
|
||||||
|
"ethereum-types": "^1.1.4",
|
||||||
|
"ethereumjs-util": "^5.1.1",
|
||||||
|
"lodash": "^4.17.5"
|
||||||
|
},
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "public"
|
||||||
|
}
|
||||||
|
}
|
13
contracts/examples/src/artifacts/index.ts
Normal file
13
contracts/examples/src/artifacts/index.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import { ContractArtifact } from 'ethereum-types';
|
||||||
|
|
||||||
|
import * as ExchangeWrapper from '../../generated-artifacts/ExchangeWrapper.json';
|
||||||
|
import * as Validator from '../../generated-artifacts/Validator.json';
|
||||||
|
import * as Wallet from '../../generated-artifacts/Wallet.json';
|
||||||
|
import * as Whitelist from '../../generated-artifacts/Whitelist.json';
|
||||||
|
|
||||||
|
export const artifacts = {
|
||||||
|
ExchangeWrapper: ExchangeWrapper as ContractArtifact,
|
||||||
|
Validator: Validator as ContractArtifact,
|
||||||
|
Wallet: Wallet as ContractArtifact,
|
||||||
|
Whitelist: Whitelist as ContractArtifact,
|
||||||
|
};
|
2
contracts/examples/src/index.ts
Normal file
2
contracts/examples/src/index.ts
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
export * from './artifacts';
|
||||||
|
export * from './wrappers';
|
4
contracts/examples/src/wrappers/index.ts
Normal file
4
contracts/examples/src/wrappers/index.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
export * from '../../generated-wrappers/exchange_wrapper';
|
||||||
|
export * from '../../generated-wrappers/validator';
|
||||||
|
export * from '../../generated-wrappers/wallet';
|
||||||
|
export * from '../../generated-wrappers/whitelist';
|
16
contracts/examples/tsconfig.json
Normal file
16
contracts/examples/tsconfig.json
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../tsconfig",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "lib",
|
||||||
|
"rootDir": ".",
|
||||||
|
"resolveJsonModule": true
|
||||||
|
},
|
||||||
|
"include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
|
||||||
|
"files": [
|
||||||
|
"./generated-artifacts/ExchangeWrapper.json",
|
||||||
|
"./generated-artifacts/Validator.json",
|
||||||
|
"./generated-artifacts/Wallet.json",
|
||||||
|
"./generated-artifacts/Whitelist.json"
|
||||||
|
],
|
||||||
|
"exclude": ["./deploy/solc/solc_bin"]
|
||||||
|
}
|
28
contracts/extensions/CHANGELOG.json
Normal file
28
contracts/extensions/CHANGELOG.json
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"version": "1.1.0",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Added Balance Threshold Filter",
|
||||||
|
"pr": 1383
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"note": "Add OrderMatcher",
|
||||||
|
"pr": 1117
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"note": "Add OrderValidator",
|
||||||
|
"pr": 1464
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"timestamp": 1544741676,
|
||||||
|
"version": "1.0.2",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
10
contracts/extensions/CHANGELOG.md
Normal file
10
contracts/extensions/CHANGELOG.md
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<!--
|
||||||
|
changelogUtils.file is auto-generated using the monorepo-scripts package. Don't edit directly.
|
||||||
|
Edit the package's CHANGELOG.json file only.
|
||||||
|
-->
|
||||||
|
|
||||||
|
CHANGELOG
|
||||||
|
|
||||||
|
## v1.0.2 - _December 13, 2018_
|
||||||
|
|
||||||
|
* Dependencies updated
|
31
contracts/extensions/DEPLOYS.json
Normal file
31
contracts/extensions/DEPLOYS.json
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "Forwarder",
|
||||||
|
"version": "1.1.0",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Round up when calculating remaining amounts in marketBuy functions",
|
||||||
|
"pr": 1162,
|
||||||
|
"networks": {
|
||||||
|
"1": "0x5468a1dc173652ee28d249c271fa9933144746b1",
|
||||||
|
"3": "0x2240dab907db71e64d3e0dba4800c83b5c502d4e",
|
||||||
|
"42": "0x17992e4ffb22730138e4b62aaa6367fa9d3699a6"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Forwarder",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "protocol v2 deploy",
|
||||||
|
"networks": {
|
||||||
|
"1": "0x7afc2d5107af94c462a194d2c21b5bdd238709d6",
|
||||||
|
"3": "0x3983e204b12b3c02fb0638caf2cd406a62e0ead3",
|
||||||
|
"42": "0xd85e2fa7e7e252b27b01bf0d65c946959d2f45b8"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
69
contracts/extensions/README.md
Normal file
69
contracts/extensions/README.md
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
## Contract extensions
|
||||||
|
|
||||||
|
Smart contracts that implement extensions for the 0x protocol.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Contract extensions of the protocol can be found in the [contracts](./contracts) directory. This directory contains contracts that interact with the 2.0.0 contracts and will be used in production, such as the [Forwarder](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/forwarder-specification.md) contract.
|
||||||
|
|
||||||
|
## Bug bounty
|
||||||
|
|
||||||
|
A bug bounty for the 2.0.0 contracts is ongoing! Instructions can be found [here](https://0xproject.com/wiki#Bug-Bounty).
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
We strongly recommend that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository.
|
||||||
|
|
||||||
|
For proposals regarding the 0x protocol's smart contract architecture, message format, or additional functionality, go to the [0x Improvement Proposals (ZEIPs)](https://github.com/0xProject/ZEIPs) repository and follow the contribution guidelines provided therein.
|
||||||
|
|
||||||
|
Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started.
|
||||||
|
|
||||||
|
### Install Dependencies
|
||||||
|
|
||||||
|
If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yarn config set workspaces-experimental true
|
||||||
|
```
|
||||||
|
|
||||||
|
Then install dependencies
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yarn install
|
||||||
|
```
|
||||||
|
|
||||||
|
### Build
|
||||||
|
|
||||||
|
To build this package and all other monorepo packages that it depends on, run the following from the monorepo root directory:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
PKG=@0x/contracts-extensions yarn build
|
||||||
|
```
|
||||||
|
|
||||||
|
Or continuously rebuild on change:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
PKG=@0x/contracts-extensions yarn watch
|
||||||
|
```
|
||||||
|
|
||||||
|
### Clean
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yarn clean
|
||||||
|
```
|
||||||
|
|
||||||
|
### Lint
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yarn lint
|
||||||
|
```
|
||||||
|
|
||||||
|
### Run Tests
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yarn test
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Testing options
|
||||||
|
|
||||||
|
Contracts testing options like coverage, profiling, revert traces or backing node choosing - are described [here](../TESTING.md).
|
22
contracts/extensions/compiler.json
Normal file
22
contracts/extensions/compiler.json
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"artifactsDir": "./generated-artifacts",
|
||||||
|
"contractsDir": "./contracts",
|
||||||
|
"compilerSettings": {
|
||||||
|
"optimizer": {
|
||||||
|
"enabled": true,
|
||||||
|
"runs": 1000000
|
||||||
|
},
|
||||||
|
"outputSelection": {
|
||||||
|
"*": {
|
||||||
|
"*": [
|
||||||
|
"abi",
|
||||||
|
"evm.bytecode.object",
|
||||||
|
"evm.bytecode.sourceMap",
|
||||||
|
"evm.deployedBytecode.object",
|
||||||
|
"evm.deployedBytecode.sourceMap"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"contracts": ["BalanceThresholdFilter", "DutchAuction", "Forwarder", "OrderMatcher", "OrderValidator"]
|
||||||
|
}
|
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright 2018 ZeroEx Intl.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
pragma solidity 0.4.24;
|
||||||
|
|
||||||
|
import "@0x/contracts-interfaces/contracts/protocol/Exchange/IExchange.sol";
|
||||||
|
import "./interfaces/IThresholdAsset.sol";
|
||||||
|
import "./MixinBalanceThresholdFilterCore.sol";
|
||||||
|
|
||||||
|
|
||||||
|
contract BalanceThresholdFilter is
|
||||||
|
MixinBalanceThresholdFilterCore
|
||||||
|
{
|
||||||
|
|
||||||
|
/// @dev Constructs BalanceThresholdFilter.
|
||||||
|
/// @param exchange Address of 0x exchange.
|
||||||
|
/// @param thresholdAsset The asset that must be held by makers/takers.
|
||||||
|
/// @param balanceThreshold The minimum balance of `thresholdAsset` that must be held by makers/takers.
|
||||||
|
constructor(
|
||||||
|
address exchange,
|
||||||
|
address thresholdAsset,
|
||||||
|
uint256 balanceThreshold
|
||||||
|
)
|
||||||
|
public
|
||||||
|
{
|
||||||
|
EXCHANGE = IExchange(exchange);
|
||||||
|
THRESHOLD_ASSET = IThresholdAsset(thresholdAsset);
|
||||||
|
BALANCE_THRESHOLD = balanceThreshold;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,135 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright 2018 ZeroEx Intl.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
pragma solidity ^0.4.24;
|
||||||
|
|
||||||
|
import "@0x/contracts-libs/contracts/libs/LibExchangeSelectors.sol";
|
||||||
|
import "@0x/contracts-libs/contracts/libs/LibOrder.sol";
|
||||||
|
import "./mixins/MBalanceThresholdFilterCore.sol";
|
||||||
|
import "./MixinExchangeCalldata.sol";
|
||||||
|
|
||||||
|
|
||||||
|
contract MixinBalanceThresholdFilterCore is
|
||||||
|
MBalanceThresholdFilterCore,
|
||||||
|
MixinExchangeCalldata,
|
||||||
|
LibOrder,
|
||||||
|
LibExchangeSelectors
|
||||||
|
{
|
||||||
|
|
||||||
|
/// @dev Executes an Exchange transaction iff the maker and taker meet
|
||||||
|
/// the hold at least `BALANCE_THRESHOLD` of the asset `THRESHOLD_ASSET` OR
|
||||||
|
/// the exchange function is a cancellation.
|
||||||
|
/// Supported Exchange functions:
|
||||||
|
/// batchFillOrders
|
||||||
|
/// batchFillOrdersNoThrow
|
||||||
|
/// batchFillOrKillOrders
|
||||||
|
/// fillOrder
|
||||||
|
/// fillOrderNoThrow
|
||||||
|
/// fillOrKillOrder
|
||||||
|
/// marketBuyOrders
|
||||||
|
/// marketBuyOrdersNoThrow
|
||||||
|
/// marketSellOrders
|
||||||
|
/// marketSellOrdersNoThrow
|
||||||
|
/// matchOrders
|
||||||
|
/// cancelOrder
|
||||||
|
/// batchCancelOrders
|
||||||
|
/// cancelOrdersUpTo
|
||||||
|
/// Trying to call any other exchange function will throw.
|
||||||
|
/// @param salt Arbitrary number to ensure uniqueness of transaction hash.
|
||||||
|
/// @param signerAddress Address of transaction signer.
|
||||||
|
/// @param signedExchangeTransaction AbiV2 encoded calldata.
|
||||||
|
/// @param signature Proof of signer transaction by signer.
|
||||||
|
function executeTransaction(
|
||||||
|
uint256 salt,
|
||||||
|
address signerAddress,
|
||||||
|
bytes signedExchangeTransaction,
|
||||||
|
bytes signature
|
||||||
|
)
|
||||||
|
external
|
||||||
|
{
|
||||||
|
// Get accounts whose balances must be validated
|
||||||
|
address[] memory addressesToValidate = getAddressesToValidate(signerAddress);
|
||||||
|
|
||||||
|
// Validate account balances
|
||||||
|
uint256 balanceThreshold = BALANCE_THRESHOLD;
|
||||||
|
IThresholdAsset thresholdAsset = THRESHOLD_ASSET;
|
||||||
|
for (uint256 i = 0; i < addressesToValidate.length; ++i) {
|
||||||
|
uint256 addressBalance = thresholdAsset.balanceOf(addressesToValidate[i]);
|
||||||
|
require(
|
||||||
|
addressBalance >= balanceThreshold,
|
||||||
|
"AT_LEAST_ONE_ADDRESS_DOES_NOT_MEET_BALANCE_THRESHOLD"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
emit ValidatedAddresses(addressesToValidate);
|
||||||
|
|
||||||
|
// All addresses are valid. Execute exchange function.
|
||||||
|
EXCHANGE.executeTransaction(
|
||||||
|
salt,
|
||||||
|
signerAddress,
|
||||||
|
signedExchangeTransaction,
|
||||||
|
signature
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Constructs an array of addresses to be validated.
|
||||||
|
/// Addresses depend on which Exchange function is to be called
|
||||||
|
/// (defined by `signedExchangeTransaction` above).
|
||||||
|
/// @param signerAddress Address of transaction signer.
|
||||||
|
/// @return addressesToValidate Array of addresses to validate.
|
||||||
|
function getAddressesToValidate(address signerAddress)
|
||||||
|
internal pure
|
||||||
|
returns (address[] memory addressesToValidate)
|
||||||
|
{
|
||||||
|
bytes4 exchangeFunctionSelector = bytes4(exchangeCalldataload(0));
|
||||||
|
// solhint-disable expression-indent
|
||||||
|
if (
|
||||||
|
exchangeFunctionSelector == BATCH_FILL_ORDERS_SELECTOR ||
|
||||||
|
exchangeFunctionSelector == BATCH_FILL_ORDERS_NO_THROW_SELECTOR ||
|
||||||
|
exchangeFunctionSelector == BATCH_FILL_OR_KILL_ORDERS_SELECTOR ||
|
||||||
|
exchangeFunctionSelector == MARKET_BUY_ORDERS_SELECTOR ||
|
||||||
|
exchangeFunctionSelector == MARKET_BUY_ORDERS_NO_THROW_SELECTOR ||
|
||||||
|
exchangeFunctionSelector == MARKET_SELL_ORDERS_SELECTOR ||
|
||||||
|
exchangeFunctionSelector == MARKET_SELL_ORDERS_NO_THROW_SELECTOR
|
||||||
|
) {
|
||||||
|
addressesToValidate = loadMakerAddressesFromOrderArray(0);
|
||||||
|
addressesToValidate = addressesToValidate.append(signerAddress);
|
||||||
|
} else if (
|
||||||
|
exchangeFunctionSelector == FILL_ORDER_SELECTOR ||
|
||||||
|
exchangeFunctionSelector == FILL_ORDER_NO_THROW_SELECTOR ||
|
||||||
|
exchangeFunctionSelector == FILL_OR_KILL_ORDER_SELECTOR
|
||||||
|
) {
|
||||||
|
address makerAddress = loadMakerAddressFromOrder(0);
|
||||||
|
addressesToValidate = addressesToValidate.append(makerAddress);
|
||||||
|
addressesToValidate = addressesToValidate.append(signerAddress);
|
||||||
|
} else if (exchangeFunctionSelector == MATCH_ORDERS_SELECTOR) {
|
||||||
|
address leftMakerAddress = loadMakerAddressFromOrder(0);
|
||||||
|
addressesToValidate = addressesToValidate.append(leftMakerAddress);
|
||||||
|
address rightMakerAddress = loadMakerAddressFromOrder(1);
|
||||||
|
addressesToValidate = addressesToValidate.append(rightMakerAddress);
|
||||||
|
addressesToValidate = addressesToValidate.append(signerAddress);
|
||||||
|
} else if (
|
||||||
|
exchangeFunctionSelector != CANCEL_ORDER_SELECTOR &&
|
||||||
|
exchangeFunctionSelector != BATCH_CANCEL_ORDERS_SELECTOR &&
|
||||||
|
exchangeFunctionSelector != CANCEL_ORDERS_UP_TO_SELECTOR
|
||||||
|
) {
|
||||||
|
revert("INVALID_OR_BLOCKED_EXCHANGE_SELECTOR");
|
||||||
|
}
|
||||||
|
// solhint-enable expression-indent
|
||||||
|
return addressesToValidate;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,103 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
Copyright 2018 ZeroEx Intl.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
pragma solidity ^0.4.24;
|
||||||
|
|
||||||
|
import "./mixins/MExchangeCalldata.sol";
|
||||||
|
import "@0x/contracts-libs/contracts/libs/LibAddressArray.sol";
|
||||||
|
|
||||||
|
|
||||||
|
contract MixinExchangeCalldata is
|
||||||
|
MExchangeCalldata
|
||||||
|
{
|
||||||
|
|
||||||
|
using LibAddressArray for address[];
|
||||||
|
|
||||||
|
/// @dev Emulates the `calldataload` opcode on the embedded Exchange calldata,
|
||||||
|
/// which is accessed through `signedExchangeTransaction`.
|
||||||
|
/// @param offset Offset into the Exchange calldata.
|
||||||
|
/// @return value Corresponding 32 byte value stored at `offset`.
|
||||||
|
function exchangeCalldataload(uint256 offset)
|
||||||
|
internal pure
|
||||||
|
returns (bytes32 value)
|
||||||
|
{
|
||||||
|
assembly {
|
||||||
|
// Pointer to exchange transaction
|
||||||
|
// 0x04 for calldata selector
|
||||||
|
// 0x40 to access `signedExchangeTransaction`, which is the third parameter
|
||||||
|
let exchangeTxPtr := calldataload(0x44)
|
||||||
|
|
||||||
|
// Offset into Exchange calldata
|
||||||
|
// We compute this by adding 0x24 to the `exchangeTxPtr` computed above.
|
||||||
|
// 0x04 for calldata selector
|
||||||
|
// 0x20 for length field of `signedExchangeTransaction`
|
||||||
|
let exchangeCalldataOffset := add(exchangeTxPtr, add(0x24, offset))
|
||||||
|
value := calldataload(exchangeCalldataOffset)
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Convenience function that skips the 4 byte selector when loading
|
||||||
|
/// from the embedded Exchange calldata.
|
||||||
|
/// @param offset Offset into the Exchange calldata (minus the 4 byte selector)
|
||||||
|
/// @return value Corresponding 32 byte value stored at `offset` + 4.
|
||||||
|
function loadExchangeData(uint256 offset)
|
||||||
|
internal pure
|
||||||
|
returns (bytes32 value)
|
||||||
|
{
|
||||||
|
value = exchangeCalldataload(offset + 4);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Extracts the maker address from an order stored in the Exchange calldata
|
||||||
|
/// (which is embedded in `signedExchangeTransaction`).
|
||||||
|
/// @param orderParamIndex Index of the order in the Exchange function's signature.
|
||||||
|
/// @return makerAddress The extracted maker address.
|
||||||
|
function loadMakerAddressFromOrder(uint256 orderParamIndex)
|
||||||
|
internal pure
|
||||||
|
returns (address makerAddress)
|
||||||
|
{
|
||||||
|
uint256 orderOffsetInBytes = orderParamIndex * 32;
|
||||||
|
uint256 orderPtr = uint256(loadExchangeData(orderOffsetInBytes));
|
||||||
|
makerAddress = address(loadExchangeData(orderPtr));
|
||||||
|
return makerAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Extracts the maker addresses from an array of orders stored in the Exchange calldata
|
||||||
|
/// (which is embedded in `signedExchangeTransaction`).
|
||||||
|
/// @param orderArrayParamIndex Index of the order array in the Exchange function's signature
|
||||||
|
/// @return makerAddresses The extracted maker addresses.
|
||||||
|
function loadMakerAddressesFromOrderArray(uint256 orderArrayParamIndex)
|
||||||
|
internal pure
|
||||||
|
returns (address[] makerAddresses)
|
||||||
|
{
|
||||||
|
uint256 orderArrayOffsetInBytes = orderArrayParamIndex * 32;
|
||||||
|
uint256 orderArrayPtr = uint256(loadExchangeData(orderArrayOffsetInBytes));
|
||||||
|
uint256 orderArrayLength = uint256(loadExchangeData(orderArrayPtr));
|
||||||
|
uint256 orderArrayLengthInBytes = orderArrayLength * 32;
|
||||||
|
uint256 orderArrayElementPtr = orderArrayPtr + 32;
|
||||||
|
uint256 orderArrayElementEndPtr = orderArrayElementPtr + orderArrayLengthInBytes;
|
||||||
|
for (uint orderPtrOffset = orderArrayElementPtr; orderPtrOffset < orderArrayElementEndPtr; orderPtrOffset += 32) {
|
||||||
|
uint256 orderPtr = uint256(loadExchangeData(orderPtrOffset));
|
||||||
|
address makerAddress = address(loadExchangeData(orderPtr + orderArrayElementPtr));
|
||||||
|
makerAddresses = makerAddresses.append(makerAddress);
|
||||||
|
}
|
||||||
|
return makerAddresses;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,55 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
Copyright 2018 ZeroEx Intl.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
pragma solidity ^0.4.24;
|
||||||
|
|
||||||
|
|
||||||
|
contract IBalanceThresholdFilterCore {
|
||||||
|
|
||||||
|
/// @dev Executes an Exchange transaction iff the maker and taker meet
|
||||||
|
/// the hold at least `BALANCE_THRESHOLD` of the asset `THRESHOLD_ASSET` OR
|
||||||
|
/// the exchange function is a cancellation.
|
||||||
|
/// Supported Exchange functions:
|
||||||
|
/// - batchFillOrders
|
||||||
|
/// - batchFillOrdersNoThrow
|
||||||
|
/// - batchFillOrKillOrders
|
||||||
|
/// - fillOrder
|
||||||
|
/// - fillOrderNoThrow
|
||||||
|
/// - fillOrKillOrder
|
||||||
|
/// - marketBuyOrders
|
||||||
|
/// - marketBuyOrdersNoThrow
|
||||||
|
/// - marketSellOrders
|
||||||
|
/// - marketSellOrdersNoThrow
|
||||||
|
/// - matchOrders
|
||||||
|
/// - cancelOrder
|
||||||
|
/// - batchCancelOrders
|
||||||
|
/// - cancelOrdersUpTo
|
||||||
|
/// Trying to call any other exchange function will throw.
|
||||||
|
/// @param salt Arbitrary number to ensure uniqueness of transaction hash.
|
||||||
|
/// @param signerAddress Address of transaction signer.
|
||||||
|
/// @param signedExchangeTransaction AbiV2 encoded calldata.
|
||||||
|
/// @param signature Proof of signer transaction by signer.
|
||||||
|
function executeTransaction(
|
||||||
|
uint256 salt,
|
||||||
|
address signerAddress,
|
||||||
|
bytes signedExchangeTransaction,
|
||||||
|
bytes signature
|
||||||
|
)
|
||||||
|
external;
|
||||||
|
}
|
@@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright 2018 ZeroEx Intl.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
pragma solidity ^0.4.24;
|
||||||
|
|
||||||
|
|
||||||
|
contract IThresholdAsset {
|
||||||
|
|
||||||
|
/// @param _owner The address from which the balance will be retrieved
|
||||||
|
/// @return Balance of owner
|
||||||
|
function balanceOf(address _owner)
|
||||||
|
external
|
||||||
|
view
|
||||||
|
returns (uint256);
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright 2018 ZeroEx Intl.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
pragma solidity ^0.4.24;
|
||||||
|
|
||||||
|
import "@0x/contracts-interfaces/contracts/protocol/Exchange/IExchange.sol";
|
||||||
|
import "../interfaces/IThresholdAsset.sol";
|
||||||
|
import "../interfaces/IBalanceThresholdFilterCore.sol";
|
||||||
|
|
||||||
|
|
||||||
|
contract MBalanceThresholdFilterCore is
|
||||||
|
IBalanceThresholdFilterCore
|
||||||
|
{
|
||||||
|
|
||||||
|
// Points to 0x exchange contract
|
||||||
|
// solhint-disable var-name-mixedcase
|
||||||
|
IExchange internal EXCHANGE;
|
||||||
|
|
||||||
|
// The asset that must be held by makers/takers
|
||||||
|
IThresholdAsset internal THRESHOLD_ASSET;
|
||||||
|
|
||||||
|
// The minimum balance of `THRESHOLD_ASSET` that must be held by makers/takers
|
||||||
|
uint256 internal BALANCE_THRESHOLD;
|
||||||
|
// solhint-enable var-name-mixedcase
|
||||||
|
|
||||||
|
// Addresses that hold at least `BALANCE_THRESHOLD` of `THRESHOLD_ASSET`
|
||||||
|
event ValidatedAddresses (
|
||||||
|
address[] addresses
|
||||||
|
);
|
||||||
|
|
||||||
|
/// @dev Constructs an array of addresses to be validated.
|
||||||
|
/// Addresses depend on which Exchange function is to be called
|
||||||
|
/// (defined by `signedExchangeTransaction` above).
|
||||||
|
/// @param signerAddress Address of transaction signer.
|
||||||
|
/// @return addressesToValidate Array of addresses to validate.
|
||||||
|
function getAddressesToValidate(address signerAddress)
|
||||||
|
internal pure
|
||||||
|
returns (address[] memory addressesToValidate);
|
||||||
|
}
|
@@ -0,0 +1,56 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
Copyright 2018 ZeroEx Intl.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
pragma solidity ^0.4.24;
|
||||||
|
|
||||||
|
|
||||||
|
contract MExchangeCalldata {
|
||||||
|
|
||||||
|
/// @dev Emulates the `calldataload` opcode on the embedded Exchange calldata,
|
||||||
|
/// which is accessed through `signedExchangeTransaction`.
|
||||||
|
/// @param offset Offset into the Exchange calldata.
|
||||||
|
/// @return value Corresponding 32 byte value stored at `offset`.
|
||||||
|
function exchangeCalldataload(uint256 offset)
|
||||||
|
internal pure
|
||||||
|
returns (bytes32 value);
|
||||||
|
|
||||||
|
/// @dev Convenience function that skips the 4 byte selector when loading
|
||||||
|
/// from the embedded Exchange calldata.
|
||||||
|
/// @param offset Offset into the Exchange calldata (minus the 4 byte selector)
|
||||||
|
/// @return value Corresponding 32 byte value stored at `offset` + 4.
|
||||||
|
function loadExchangeData(uint256 offset)
|
||||||
|
internal pure
|
||||||
|
returns (bytes32 value);
|
||||||
|
|
||||||
|
/// @dev Extracts the maker address from an order stored in the Exchange calldata
|
||||||
|
/// (which is embedded in `signedExchangeTransaction`).
|
||||||
|
/// @param orderParamIndex Index of the order in the Exchange function's signature.
|
||||||
|
/// @return makerAddress The extracted maker address.
|
||||||
|
function loadMakerAddressFromOrder(uint256 orderParamIndex)
|
||||||
|
internal pure
|
||||||
|
returns (address makerAddress);
|
||||||
|
|
||||||
|
/// @dev Extracts the maker addresses from an array of orders stored in the Exchange calldata
|
||||||
|
/// (which is embedded in `signedExchangeTransaction`).
|
||||||
|
/// @param orderArrayParamIndex Index of the order array in the Exchange function's signature
|
||||||
|
/// @return makerAddresses The extracted maker addresses.
|
||||||
|
function loadMakerAddressesFromOrderArray(uint256 orderArrayParamIndex)
|
||||||
|
internal pure
|
||||||
|
returns (address[] makerAddresses);
|
||||||
|
}
|
205
contracts/extensions/contracts/DutchAuction/DutchAuction.sol
Normal file
205
contracts/extensions/contracts/DutchAuction/DutchAuction.sol
Normal file
@@ -0,0 +1,205 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright 2018 ZeroEx Intl.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
pragma solidity 0.4.24;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
import "@0x/contracts-interfaces/contracts/protocol/Exchange/IExchange.sol";
|
||||||
|
import "@0x/contracts-libs/contracts/libs/LibOrder.sol";
|
||||||
|
import "@0x/contracts-tokens/contracts/tokens/ERC20Token/IERC20Token.sol";
|
||||||
|
import "@0x/contracts-utils/contracts/utils/LibBytes/LibBytes.sol";
|
||||||
|
import "@0x/contracts-utils/contracts/utils/SafeMath/SafeMath.sol";
|
||||||
|
|
||||||
|
|
||||||
|
contract DutchAuction is
|
||||||
|
SafeMath
|
||||||
|
{
|
||||||
|
using LibBytes for bytes;
|
||||||
|
|
||||||
|
// solhint-disable var-name-mixedcase
|
||||||
|
IExchange internal EXCHANGE;
|
||||||
|
|
||||||
|
struct AuctionDetails {
|
||||||
|
uint256 beginTimeSeconds; // Auction begin unix timestamp: sellOrder.makerAssetData
|
||||||
|
uint256 endTimeSeconds; // Auction end unix timestamp: sellOrder.expiryTimeSeconds
|
||||||
|
uint256 beginAmount; // Auction begin amount: sellOrder.makerAssetData
|
||||||
|
uint256 endAmount; // Auction end amount: sellOrder.takerAssetAmount
|
||||||
|
uint256 currentAmount; // Calculated amount given block.timestamp
|
||||||
|
uint256 currentTimeSeconds; // block.timestamp
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor (address _exchange)
|
||||||
|
public
|
||||||
|
{
|
||||||
|
EXCHANGE = IExchange(_exchange);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Matches the buy and sell orders at an amount given the following: the current block time, the auction
|
||||||
|
/// start time and the auction begin amount. The sell order is a an order at the lowest amount
|
||||||
|
/// at the end of the auction. Excess from the match is transferred to the seller.
|
||||||
|
/// Over time the price moves from beginAmount to endAmount given the current block.timestamp.
|
||||||
|
/// sellOrder.expiryTimeSeconds is the end time of the auction.
|
||||||
|
/// sellOrder.takerAssetAmount is the end amount of the auction (lowest possible amount).
|
||||||
|
/// sellOrder.makerAssetData is the ABI encoded Asset Proxy data with the following data appended
|
||||||
|
/// buyOrder.makerAssetData is the buyers bid on the auction, must meet the amount for the current block timestamp
|
||||||
|
/// (uint256 beginTimeSeconds, uint256 beginAmount).
|
||||||
|
/// This function reverts in the following scenarios:
|
||||||
|
/// * Auction has not started (auctionDetails.currentTimeSeconds < auctionDetails.beginTimeSeconds)
|
||||||
|
/// * Auction has expired (auctionDetails.endTimeSeconds < auctionDetails.currentTimeSeconds)
|
||||||
|
/// * Amount is invalid: Buy order amount is too low (buyOrder.makerAssetAmount < auctionDetails.currentAmount)
|
||||||
|
/// * Amount is invalid: Invalid begin amount (auctionDetails.beginAmount > auctionDetails.endAmount)
|
||||||
|
/// * Any failure in the 0x Match Orders
|
||||||
|
/// @param buyOrder The Buyer's order. This order is for the current expected price of the auction.
|
||||||
|
/// @param sellOrder The Seller's order. This order is for the lowest amount (at the end of the auction).
|
||||||
|
/// @param buySignature Proof that order was created by the buyer.
|
||||||
|
/// @param sellSignature Proof that order was created by the seller.
|
||||||
|
/// @return matchedFillResults amounts filled and fees paid by maker and taker of matched orders.
|
||||||
|
function matchOrders(
|
||||||
|
LibOrder.Order memory buyOrder,
|
||||||
|
LibOrder.Order memory sellOrder,
|
||||||
|
bytes memory buySignature,
|
||||||
|
bytes memory sellSignature
|
||||||
|
)
|
||||||
|
public
|
||||||
|
returns (LibFillResults.MatchedFillResults memory matchedFillResults)
|
||||||
|
{
|
||||||
|
AuctionDetails memory auctionDetails = getAuctionDetails(sellOrder);
|
||||||
|
// Ensure the auction has not yet started
|
||||||
|
require(
|
||||||
|
auctionDetails.currentTimeSeconds >= auctionDetails.beginTimeSeconds,
|
||||||
|
"AUCTION_NOT_STARTED"
|
||||||
|
);
|
||||||
|
// Ensure the auction has not expired. This will fail later in 0x but we can save gas by failing early
|
||||||
|
require(
|
||||||
|
sellOrder.expirationTimeSeconds > auctionDetails.currentTimeSeconds,
|
||||||
|
"AUCTION_EXPIRED"
|
||||||
|
);
|
||||||
|
// Validate the buyer amount is greater than the current auction amount
|
||||||
|
require(
|
||||||
|
buyOrder.makerAssetAmount >= auctionDetails.currentAmount,
|
||||||
|
"INVALID_AMOUNT"
|
||||||
|
);
|
||||||
|
// Match orders, maximally filling `buyOrder`
|
||||||
|
matchedFillResults = EXCHANGE.matchOrders(
|
||||||
|
buyOrder,
|
||||||
|
sellOrder,
|
||||||
|
buySignature,
|
||||||
|
sellSignature
|
||||||
|
);
|
||||||
|
// The difference in sellOrder.takerAssetAmount and current amount is given as spread to the matcher
|
||||||
|
// This may include additional spread from the buyOrder.makerAssetAmount and the currentAmount.
|
||||||
|
// e.g currentAmount is 30, sellOrder.takerAssetAmount is 10 and buyOrder.makerAssetamount is 40.
|
||||||
|
// 10 (40-30) is returned to the buyer, 20 (30-10) sent to the seller and 10 has previously
|
||||||
|
// been transferred to the seller during matchOrders
|
||||||
|
uint256 leftMakerAssetSpreadAmount = matchedFillResults.leftMakerAssetSpreadAmount;
|
||||||
|
if (leftMakerAssetSpreadAmount > 0) {
|
||||||
|
// ERC20 Asset data itself is encoded as follows:
|
||||||
|
//
|
||||||
|
// | Area | Offset | Length | Contents |
|
||||||
|
// |----------|--------|---------|-------------------------------------|
|
||||||
|
// | Header | 0 | 4 | function selector |
|
||||||
|
// | Params | | 1 * 32 | function parameters: |
|
||||||
|
// | | 4 | 12 | 1. token address padding |
|
||||||
|
// | | 16 | 20 | 2. token address |
|
||||||
|
bytes memory assetData = sellOrder.takerAssetData;
|
||||||
|
address token = assetData.readAddress(16);
|
||||||
|
// Calculate the excess from the buy order. This can occur if the buyer sends in a higher
|
||||||
|
// amount than the calculated current amount
|
||||||
|
uint256 buyerExcessAmount = safeSub(buyOrder.makerAssetAmount, auctionDetails.currentAmount);
|
||||||
|
uint256 sellerExcessAmount = safeSub(leftMakerAssetSpreadAmount, buyerExcessAmount);
|
||||||
|
// Return the difference between auctionDetails.currentAmount and sellOrder.takerAssetAmount
|
||||||
|
// to the seller
|
||||||
|
if (sellerExcessAmount > 0) {
|
||||||
|
IERC20Token(token).transfer(sellOrder.makerAddress, sellerExcessAmount);
|
||||||
|
}
|
||||||
|
// Return the difference between buyOrder.makerAssetAmount and auctionDetails.currentAmount
|
||||||
|
// to the buyer
|
||||||
|
if (buyerExcessAmount > 0) {
|
||||||
|
IERC20Token(token).transfer(buyOrder.makerAddress, buyerExcessAmount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return matchedFillResults;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Calculates the Auction Details for the given order
|
||||||
|
/// @param order The sell order
|
||||||
|
/// @return AuctionDetails
|
||||||
|
function getAuctionDetails(
|
||||||
|
LibOrder.Order memory order
|
||||||
|
)
|
||||||
|
public
|
||||||
|
returns (AuctionDetails memory auctionDetails)
|
||||||
|
{
|
||||||
|
uint256 makerAssetDataLength = order.makerAssetData.length;
|
||||||
|
// It is unknown the encoded data of makerAssetData, we assume the last 64 bytes
|
||||||
|
// are the Auction Details encoding.
|
||||||
|
// Auction Details is encoded as follows:
|
||||||
|
//
|
||||||
|
// | Area | Offset | Length | Contents |
|
||||||
|
// |----------|--------|---------|-------------------------------------|
|
||||||
|
// | Params | | 2 * 32 | parameters: |
|
||||||
|
// | | -64 | 32 | 1. auction begin unix timestamp |
|
||||||
|
// | | -32 | 32 | 2. auction begin begin amount |
|
||||||
|
// ERC20 asset data length is 4+32, 64 for auction details results in min length 100
|
||||||
|
require(
|
||||||
|
makerAssetDataLength >= 100,
|
||||||
|
"INVALID_ASSET_DATA"
|
||||||
|
);
|
||||||
|
uint256 auctionBeginTimeSeconds = order.makerAssetData.readUint256(makerAssetDataLength - 64);
|
||||||
|
uint256 auctionBeginAmount = order.makerAssetData.readUint256(makerAssetDataLength - 32);
|
||||||
|
// Ensure the auction has a valid begin time
|
||||||
|
require(
|
||||||
|
order.expirationTimeSeconds > auctionBeginTimeSeconds,
|
||||||
|
"INVALID_BEGIN_TIME"
|
||||||
|
);
|
||||||
|
uint256 auctionDurationSeconds = order.expirationTimeSeconds-auctionBeginTimeSeconds;
|
||||||
|
// Ensure the auction goes from high to low
|
||||||
|
uint256 minAmount = order.takerAssetAmount;
|
||||||
|
require(
|
||||||
|
auctionBeginAmount > minAmount,
|
||||||
|
"INVALID_AMOUNT"
|
||||||
|
);
|
||||||
|
uint256 amountDelta = auctionBeginAmount-minAmount;
|
||||||
|
// solhint-disable-next-line not-rely-on-time
|
||||||
|
uint256 timestamp = block.timestamp;
|
||||||
|
auctionDetails.beginTimeSeconds = auctionBeginTimeSeconds;
|
||||||
|
auctionDetails.endTimeSeconds = order.expirationTimeSeconds;
|
||||||
|
auctionDetails.beginAmount = auctionBeginAmount;
|
||||||
|
auctionDetails.endAmount = minAmount;
|
||||||
|
auctionDetails.currentTimeSeconds = timestamp;
|
||||||
|
|
||||||
|
uint256 remainingDurationSeconds = order.expirationTimeSeconds-timestamp;
|
||||||
|
if (timestamp < auctionBeginTimeSeconds) {
|
||||||
|
// If the auction has not yet begun the current amount is the auctionBeginAmount
|
||||||
|
auctionDetails.currentAmount = auctionBeginAmount;
|
||||||
|
} else if (timestamp >= order.expirationTimeSeconds) {
|
||||||
|
// If the auction has ended the current amount is the minAmount.
|
||||||
|
// Auction end time is guaranteed by 0x Exchange due to the order expiration
|
||||||
|
auctionDetails.currentAmount = minAmount;
|
||||||
|
} else {
|
||||||
|
auctionDetails.currentAmount = safeAdd(
|
||||||
|
minAmount,
|
||||||
|
safeDiv(
|
||||||
|
safeMul(remainingDurationSeconds, amountDelta),
|
||||||
|
auctionDurationSeconds
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return auctionDetails;
|
||||||
|
}
|
||||||
|
}
|
@@ -16,12 +16,12 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pragma solidity 0.4.24;
|
pragma solidity ^0.4.24;
|
||||||
|
|
||||||
import "../../utils/LibBytes/LibBytes.sol";
|
import "@0x/contracts-utils/contracts/utils/LibBytes/LibBytes.sol";
|
||||||
import "../../utils/Ownable/Ownable.sol";
|
import "@0x/contracts-utils/contracts/utils/Ownable/Ownable.sol";
|
||||||
import "../../tokens/ERC20Token/IERC20Token.sol";
|
import "@0x/contracts-tokens/contracts/tokens/ERC20Token/IERC20Token.sol";
|
||||||
import "../../tokens/ERC721Token/IERC721Token.sol";
|
import "@0x/contracts-tokens/contracts/tokens/ERC721Token/IERC721Token.sol";
|
||||||
import "./libs/LibConstants.sol";
|
import "./libs/LibConstants.sol";
|
||||||
import "./mixins/MAssets.sol";
|
import "./mixins/MAssets.sol";
|
||||||
|
|
@@ -16,15 +16,15 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pragma solidity 0.4.24;
|
pragma solidity ^0.4.24;
|
||||||
pragma experimental ABIEncoderV2;
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
import "./libs/LibConstants.sol";
|
import "./libs/LibConstants.sol";
|
||||||
import "./mixins/MExchangeWrapper.sol";
|
import "./mixins/MExchangeWrapper.sol";
|
||||||
import "../../protocol/Exchange/libs/LibAbiEncoder.sol";
|
import "@0x/contracts-libs/contracts/libs/LibAbiEncoder.sol";
|
||||||
import "../../protocol/Exchange/libs/LibOrder.sol";
|
import "@0x/contracts-libs/contracts/libs/LibOrder.sol";
|
||||||
import "../../protocol/Exchange/libs/LibFillResults.sol";
|
import "@0x/contracts-libs/contracts/libs/LibFillResults.sol";
|
||||||
import "../../protocol/Exchange/libs/LibMath.sol";
|
import "@0x/contracts-libs/contracts/libs/LibMath.sol";
|
||||||
|
|
||||||
|
|
||||||
contract MixinExchangeWrapper is
|
contract MixinExchangeWrapper is
|
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pragma solidity 0.4.24;
|
pragma solidity ^0.4.24;
|
||||||
pragma experimental ABIEncoderV2;
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
import "./libs/LibConstants.sol";
|
import "./libs/LibConstants.sol";
|
||||||
@@ -24,10 +24,10 @@ import "./mixins/MWeth.sol";
|
|||||||
import "./mixins/MAssets.sol";
|
import "./mixins/MAssets.sol";
|
||||||
import "./mixins/MExchangeWrapper.sol";
|
import "./mixins/MExchangeWrapper.sol";
|
||||||
import "./interfaces/IForwarderCore.sol";
|
import "./interfaces/IForwarderCore.sol";
|
||||||
import "../../utils/LibBytes/LibBytes.sol";
|
import "@0x/contracts-utils/contracts/utils/LibBytes/LibBytes.sol";
|
||||||
import "../../protocol/Exchange/libs/LibOrder.sol";
|
import "@0x/contracts-libs/contracts/libs/LibOrder.sol";
|
||||||
import "../../protocol/Exchange/libs/LibFillResults.sol";
|
import "@0x/contracts-libs/contracts/libs/LibFillResults.sol";
|
||||||
import "../../protocol/Exchange/libs/LibMath.sol";
|
import "@0x/contracts-libs/contracts/libs/LibMath.sol";
|
||||||
|
|
||||||
|
|
||||||
contract MixinForwarderCore is
|
contract MixinForwarderCore is
|
@@ -16,9 +16,9 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pragma solidity 0.4.24;
|
pragma solidity ^0.4.24;
|
||||||
|
|
||||||
import "../../protocol/Exchange/libs/LibMath.sol";
|
import "@0x/contracts-libs/contracts/libs/LibMath.sol";
|
||||||
import "./libs/LibConstants.sol";
|
import "./libs/LibConstants.sol";
|
||||||
import "./mixins/MWeth.sol";
|
import "./mixins/MWeth.sol";
|
||||||
|
|
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pragma solidity 0.4.24;
|
pragma solidity ^0.4.24;
|
||||||
|
|
||||||
|
|
||||||
contract IAssets {
|
contract IAssets {
|
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pragma solidity 0.4.24;
|
pragma solidity ^0.4.24;
|
||||||
pragma experimental ABIEncoderV2;
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
import "./IForwarderCore.sol";
|
import "./IForwarderCore.sol";
|
@@ -16,11 +16,11 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pragma solidity 0.4.24;
|
pragma solidity ^0.4.24;
|
||||||
pragma experimental ABIEncoderV2;
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
import "../../../protocol/Exchange/libs/LibOrder.sol";
|
import "@0x/contracts-libs/contracts/libs/LibOrder.sol";
|
||||||
import "../../../protocol/Exchange/libs/LibFillResults.sol";
|
import "@0x/contracts-libs/contracts/libs/LibFillResults.sol";
|
||||||
|
|
||||||
|
|
||||||
contract IForwarderCore {
|
contract IForwarderCore {
|
@@ -16,12 +16,12 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pragma solidity 0.4.24;
|
pragma solidity ^0.4.24;
|
||||||
|
|
||||||
import "../../../utils/LibBytes/LibBytes.sol";
|
import "@0x/contracts-utils/contracts/utils/LibBytes/LibBytes.sol";
|
||||||
import "../../../protocol/Exchange/interfaces/IExchange.sol";
|
import "@0x/contracts-interfaces/contracts/protocol/Exchange/IExchange.sol";
|
||||||
import "../../../tokens/EtherToken/IEtherToken.sol";
|
import "@0x/contracts-tokens/contracts/tokens/EtherToken/IEtherToken.sol";
|
||||||
import "../../../tokens/ERC20Token/IERC20Token.sol";
|
import "@0x/contracts-tokens/contracts/tokens/ERC20Token/IERC20Token.sol";
|
||||||
|
|
||||||
|
|
||||||
contract LibConstants {
|
contract LibConstants {
|
@@ -17,7 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// solhint-disable
|
// solhint-disable
|
||||||
pragma solidity 0.4.24;
|
pragma solidity ^0.4.24;
|
||||||
|
|
||||||
|
|
||||||
/// This contract is intended to serve as a reference, but is not actually used for efficiency reasons.
|
/// This contract is intended to serve as a reference, but is not actually used for efficiency reasons.
|
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pragma solidity 0.4.24;
|
pragma solidity ^0.4.24;
|
||||||
|
|
||||||
import "../interfaces/IAssets.sol";
|
import "../interfaces/IAssets.sol";
|
||||||
|
|
@@ -16,11 +16,11 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pragma solidity 0.4.24;
|
pragma solidity ^0.4.24;
|
||||||
pragma experimental ABIEncoderV2;
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
import "../../../protocol/Exchange/libs/LibOrder.sol";
|
import "@0x/contracts-libs/contracts/libs/LibOrder.sol";
|
||||||
import "../../../protocol/Exchange/libs/LibFillResults.sol";
|
import "@0x/contracts-libs/contracts/libs/LibFillResults.sol";
|
||||||
|
|
||||||
|
|
||||||
contract MExchangeWrapper {
|
contract MExchangeWrapper {
|
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pragma solidity 0.4.24;
|
pragma solidity ^0.4.24;
|
||||||
|
|
||||||
|
|
||||||
contract MWeth {
|
contract MWeth {
|
195
contracts/extensions/contracts/OrderMatcher/MixinAssets.sol
Normal file
195
contracts/extensions/contracts/OrderMatcher/MixinAssets.sol
Normal file
@@ -0,0 +1,195 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright 2018 ZeroEx Intl.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
pragma solidity ^0.4.24;
|
||||||
|
|
||||||
|
import "@0x/contracts-utils/contracts/utils/LibBytes/LibBytes.sol";
|
||||||
|
import "@0x/contracts-utils/contracts/utils/Ownable/Ownable.sol";
|
||||||
|
import "@0x/contracts-tokens/contracts/tokens/ERC20Token/IERC20Token.sol";
|
||||||
|
import "@0x/contracts-tokens/contracts/tokens/ERC721Token/IERC721Token.sol";
|
||||||
|
import "./mixins/MAssets.sol";
|
||||||
|
import "./libs/LibConstants.sol";
|
||||||
|
|
||||||
|
|
||||||
|
contract MixinAssets is
|
||||||
|
MAssets,
|
||||||
|
Ownable,
|
||||||
|
LibConstants
|
||||||
|
{
|
||||||
|
using LibBytes for bytes;
|
||||||
|
|
||||||
|
/// @dev Withdraws assets from this contract. The contract requires a ZRX balance in order to
|
||||||
|
/// function optimally, and this function allows the ZRX to be withdrawn by owner. It may also be
|
||||||
|
/// used to withdraw assets that were accidentally sent to this contract.
|
||||||
|
/// @param assetData Byte array encoded for the respective asset proxy.
|
||||||
|
/// @param amount Amount of asset to withdraw.
|
||||||
|
function withdrawAsset(
|
||||||
|
bytes assetData,
|
||||||
|
uint256 amount
|
||||||
|
)
|
||||||
|
external
|
||||||
|
onlyOwner
|
||||||
|
{
|
||||||
|
transferAssetToSender(assetData, amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Approves or disapproves an AssetProxy to spend asset.
|
||||||
|
/// @param assetData Byte array encoded for the respective asset proxy.
|
||||||
|
/// @param amount Amount of asset to approve for respective proxy.
|
||||||
|
function approveAssetProxy(
|
||||||
|
bytes assetData,
|
||||||
|
uint256 amount
|
||||||
|
)
|
||||||
|
external
|
||||||
|
onlyOwner
|
||||||
|
{
|
||||||
|
bytes4 proxyId = assetData.readBytes4(0);
|
||||||
|
|
||||||
|
if (proxyId == ERC20_DATA_ID) {
|
||||||
|
approveERC20Token(assetData, amount);
|
||||||
|
} else if (proxyId == ERC721_DATA_ID) {
|
||||||
|
approveERC721Token(assetData, amount);
|
||||||
|
} else {
|
||||||
|
revert("UNSUPPORTED_ASSET_PROXY");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Transfers given amount of asset to sender.
|
||||||
|
/// @param assetData Byte array encoded for the respective asset proxy.
|
||||||
|
/// @param amount Amount of asset to transfer to sender.
|
||||||
|
function transferAssetToSender(
|
||||||
|
bytes memory assetData,
|
||||||
|
uint256 amount
|
||||||
|
)
|
||||||
|
internal
|
||||||
|
{
|
||||||
|
bytes4 proxyId = assetData.readBytes4(0);
|
||||||
|
|
||||||
|
if (proxyId == ERC20_DATA_ID) {
|
||||||
|
transferERC20Token(assetData, amount);
|
||||||
|
} else if (proxyId == ERC721_DATA_ID) {
|
||||||
|
transferERC721Token(assetData, amount);
|
||||||
|
} else {
|
||||||
|
revert("UNSUPPORTED_ASSET_PROXY");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Decodes ERC20 assetData and transfers given amount to sender.
|
||||||
|
/// @param assetData Byte array encoded for the respective asset proxy.
|
||||||
|
/// @param amount Amount of asset to transfer to sender.
|
||||||
|
function transferERC20Token(
|
||||||
|
bytes memory assetData,
|
||||||
|
uint256 amount
|
||||||
|
)
|
||||||
|
internal
|
||||||
|
{
|
||||||
|
// 4 byte id + 12 0 bytes before ABI encoded token address.
|
||||||
|
address token = assetData.readAddress(16);
|
||||||
|
|
||||||
|
// Transfer tokens.
|
||||||
|
// We do a raw call so we can check the success separate
|
||||||
|
// from the return data.
|
||||||
|
bool success = token.call(abi.encodeWithSelector(
|
||||||
|
ERC20_TRANSFER_SELECTOR,
|
||||||
|
msg.sender,
|
||||||
|
amount
|
||||||
|
));
|
||||||
|
require(
|
||||||
|
success,
|
||||||
|
"TRANSFER_FAILED"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Check return data.
|
||||||
|
// If there is no return data, we assume the token incorrectly
|
||||||
|
// does not return a bool. In this case we expect it to revert
|
||||||
|
// on failure, which was handled above.
|
||||||
|
// If the token does return data, we require that it is a single
|
||||||
|
// value that evaluates to true.
|
||||||
|
assembly {
|
||||||
|
if returndatasize {
|
||||||
|
success := 0
|
||||||
|
if eq(returndatasize, 32) {
|
||||||
|
// First 64 bytes of memory are reserved scratch space
|
||||||
|
returndatacopy(0, 0, 32)
|
||||||
|
success := mload(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
require(
|
||||||
|
success,
|
||||||
|
"TRANSFER_FAILED"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Decodes ERC721 assetData and transfers given amount to sender.
|
||||||
|
/// @param assetData Byte array encoded for the respective asset proxy.
|
||||||
|
/// @param amount Amount of asset to transfer to sender.
|
||||||
|
function transferERC721Token(
|
||||||
|
bytes memory assetData,
|
||||||
|
uint256 amount
|
||||||
|
)
|
||||||
|
internal
|
||||||
|
{
|
||||||
|
require(
|
||||||
|
amount == 1,
|
||||||
|
"INVALID_AMOUNT"
|
||||||
|
);
|
||||||
|
// Decode asset data.
|
||||||
|
// 4 byte id + 12 0 bytes before ABI encoded token address.
|
||||||
|
address token = assetData.readAddress(16);
|
||||||
|
// 4 byte id + 32 byte ABI encoded token address before token id.
|
||||||
|
uint256 tokenId = assetData.readUint256(36);
|
||||||
|
|
||||||
|
// Perform transfer.
|
||||||
|
IERC721Token(token).transferFrom(
|
||||||
|
address(this),
|
||||||
|
msg.sender,
|
||||||
|
tokenId
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Sets approval for ERC20 AssetProxy.
|
||||||
|
/// @param assetData Byte array encoded for the respective asset proxy.
|
||||||
|
/// @param amount Amount of asset to approve for respective proxy.
|
||||||
|
function approveERC20Token(
|
||||||
|
bytes memory assetData,
|
||||||
|
uint256 amount
|
||||||
|
)
|
||||||
|
internal
|
||||||
|
{
|
||||||
|
address token = assetData.readAddress(16);
|
||||||
|
require(
|
||||||
|
IERC20Token(token).approve(ERC20_PROXY_ADDRESS, amount),
|
||||||
|
"APPROVAL_FAILED"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Sets approval for ERC721 AssetProxy.
|
||||||
|
/// @param assetData Byte array encoded for the respective asset proxy.
|
||||||
|
/// @param amount Amount of asset to approve for respective proxy.
|
||||||
|
function approveERC721Token(
|
||||||
|
bytes memory assetData,
|
||||||
|
uint256 amount
|
||||||
|
)
|
||||||
|
internal
|
||||||
|
{
|
||||||
|
address token = assetData.readAddress(16);
|
||||||
|
bool approval = amount >= 1;
|
||||||
|
IERC721Token(token).setApprovalForAll(ERC721_PROXY_ADDRESS, approval);
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright 2018 ZeroEx Intl.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
pragma solidity ^0.4.24;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
import "./libs/LibConstants.sol";
|
||||||
|
import "@0x/contracts-libs/contracts/libs/LibOrder.sol";
|
||||||
|
import "@0x/contracts-libs/contracts/libs/LibFillResults.sol";
|
||||||
|
import "@0x/contracts-utils/contracts/utils/Ownable/Ownable.sol";
|
||||||
|
|
||||||
|
|
||||||
|
contract MixinMatchOrders is
|
||||||
|
Ownable,
|
||||||
|
LibConstants
|
||||||
|
{
|
||||||
|
/// @dev Match two complementary orders that have a profitable spread.
|
||||||
|
/// Each order is filled at their respective price point. However, the calculations are
|
||||||
|
/// carried out as though the orders are both being filled at the right order's price point.
|
||||||
|
/// The profit made by the left order is then used to fill the right order as much as possible.
|
||||||
|
/// This results in a spread being taken in terms of both assets. The spread is held within this contract.
|
||||||
|
/// @param leftOrder First order to match.
|
||||||
|
/// @param rightOrder Second order to match.
|
||||||
|
/// @param leftSignature Proof that order was created by the left maker.
|
||||||
|
/// @param rightSignature Proof that order was created by the right maker.
|
||||||
|
function matchOrders(
|
||||||
|
LibOrder.Order memory leftOrder,
|
||||||
|
LibOrder.Order memory rightOrder,
|
||||||
|
bytes memory leftSignature,
|
||||||
|
bytes memory rightSignature
|
||||||
|
)
|
||||||
|
public
|
||||||
|
onlyOwner
|
||||||
|
{
|
||||||
|
// Match orders, maximally filling `leftOrder`
|
||||||
|
LibFillResults.MatchedFillResults memory matchedFillResults = EXCHANGE.matchOrders(
|
||||||
|
leftOrder,
|
||||||
|
rightOrder,
|
||||||
|
leftSignature,
|
||||||
|
rightSignature
|
||||||
|
);
|
||||||
|
|
||||||
|
uint256 leftMakerAssetSpreadAmount = matchedFillResults.leftMakerAssetSpreadAmount;
|
||||||
|
uint256 rightOrderTakerAssetAmount = rightOrder.takerAssetAmount;
|
||||||
|
|
||||||
|
// Do not attempt to call `fillOrder` if no spread was taken or `rightOrder` has been completely filled
|
||||||
|
if (leftMakerAssetSpreadAmount == 0 || matchedFillResults.right.takerAssetFilledAmount == rightOrderTakerAssetAmount) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The `assetData` fields of the `rightOrder` could have been null for the `matchOrders` call. We reassign them before calling `fillOrder`.
|
||||||
|
rightOrder.makerAssetData = leftOrder.takerAssetData;
|
||||||
|
rightOrder.takerAssetData = leftOrder.makerAssetData;
|
||||||
|
|
||||||
|
// Query `rightOrder` info to check if it has been completely filled
|
||||||
|
// We need to make this check in case the `rightOrder` was partially filled before the `matchOrders` call
|
||||||
|
LibOrder.OrderInfo memory orderInfo = EXCHANGE.getOrderInfo(rightOrder);
|
||||||
|
|
||||||
|
// Do not attempt to call `fillOrder` if order has been completely filled
|
||||||
|
if (orderInfo.orderTakerAssetFilledAmount == rightOrderTakerAssetAmount) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We do not need to pass in a signature since it was already validated in the `matchOrders` call
|
||||||
|
EXCHANGE.fillOrder(
|
||||||
|
rightOrder,
|
||||||
|
leftMakerAssetSpreadAmount,
|
||||||
|
""
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
38
contracts/extensions/contracts/OrderMatcher/OrderMatcher.sol
Normal file
38
contracts/extensions/contracts/OrderMatcher/OrderMatcher.sol
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright 2018 ZeroEx Intl.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
pragma solidity 0.4.24;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
import "@0x/contracts-utils/contracts/utils/Ownable/Ownable.sol";
|
||||||
|
import "./libs/LibConstants.sol";
|
||||||
|
import "./MixinMatchOrders.sol";
|
||||||
|
import "./MixinAssets.sol";
|
||||||
|
|
||||||
|
|
||||||
|
// solhint-disable no-empty-blocks
|
||||||
|
contract OrderMatcher is
|
||||||
|
MixinMatchOrders,
|
||||||
|
MixinAssets
|
||||||
|
{
|
||||||
|
constructor (address _exchange)
|
||||||
|
public
|
||||||
|
LibConstants(_exchange)
|
||||||
|
Ownable()
|
||||||
|
{}
|
||||||
|
}
|
@@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright 2018 ZeroEx Intl.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
pragma solidity ^0.4.24;
|
||||||
|
|
||||||
|
|
||||||
|
contract IAssets {
|
||||||
|
|
||||||
|
/// @dev Withdraws assets from this contract. The contract requires a ZRX balance in order to
|
||||||
|
/// function optimally, and this function allows the ZRX to be withdrawn by owner. It may also be
|
||||||
|
/// used to withdraw assets that were accidentally sent to this contract.
|
||||||
|
/// @param assetData Byte array encoded for the respective asset proxy.
|
||||||
|
/// @param amount Amount of asset to withdraw.
|
||||||
|
function withdrawAsset(
|
||||||
|
bytes assetData,
|
||||||
|
uint256 amount
|
||||||
|
)
|
||||||
|
external;
|
||||||
|
|
||||||
|
/// @dev Approves or disapproves an AssetProxy to spend asset.
|
||||||
|
/// @param assetData Byte array encoded for the respective asset proxy.
|
||||||
|
/// @param amount Amount of asset to approve for respective proxy.
|
||||||
|
function approveAssetProxy(
|
||||||
|
bytes assetData,
|
||||||
|
uint256 amount
|
||||||
|
)
|
||||||
|
external;
|
||||||
|
}
|
@@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright 2018 ZeroEx Intl.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
pragma solidity ^0.4.24;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
import "@0x/contracts-libs/contracts/libs/LibOrder.sol";
|
||||||
|
|
||||||
|
|
||||||
|
contract IMatchOrders {
|
||||||
|
|
||||||
|
/// @dev Match two complementary orders that have a profitable spread.
|
||||||
|
/// Each order is filled at their respective price point. However, the calculations are
|
||||||
|
/// carried out as though the orders are both being filled at the right order's price point.
|
||||||
|
/// The profit made by the left order is then used to fill the right order as much as possible.
|
||||||
|
/// This results in a spread being taken in terms of both assets. The spread is held within this contract.
|
||||||
|
/// @param leftOrder First order to match.
|
||||||
|
/// @param rightOrder Second order to match.
|
||||||
|
/// @param leftSignature Proof that order was created by the left maker.
|
||||||
|
/// @param rightSignature Proof that order was created by the right maker.
|
||||||
|
function matchOrders(
|
||||||
|
LibOrder.Order memory leftOrder,
|
||||||
|
LibOrder.Order memory rightOrder,
|
||||||
|
bytes memory leftSignature,
|
||||||
|
bytes memory rightSignature
|
||||||
|
)
|
||||||
|
public;
|
||||||
|
}
|
@@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright 2018 ZeroEx Intl.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
pragma solidity ^0.4.24;
|
||||||
|
|
||||||
|
import "@0x/contract-utils/contracts/utils/Ownable/IOwnable.sol";
|
||||||
|
import "./IMatchOrders.sol";
|
||||||
|
import "./IAssets.sol";
|
||||||
|
|
||||||
|
|
||||||
|
// solhint-disable no-empty-blocks
|
||||||
|
contract IOrderMatcher is
|
||||||
|
IOwnable,
|
||||||
|
IMatchOrders,
|
||||||
|
IAssets
|
||||||
|
{}
|
@@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright 2018 ZeroEx Intl.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
pragma solidity ^0.4.24;
|
||||||
|
|
||||||
|
import "@0x/contracts-interfaces/contracts/protocol/Exchange/IExchange.sol";
|
||||||
|
|
||||||
|
|
||||||
|
contract LibConstants {
|
||||||
|
|
||||||
|
// bytes4(keccak256("transfer(address,uint256)"))
|
||||||
|
bytes4 constant internal ERC20_TRANSFER_SELECTOR = 0xa9059cbb;
|
||||||
|
// bytes4(keccak256("ERC20Token(address)"))
|
||||||
|
bytes4 constant internal ERC20_DATA_ID = 0xf47261b0;
|
||||||
|
// bytes4(keccak256("ERC721Token(address,uint256)"))
|
||||||
|
bytes4 constant internal ERC721_DATA_ID = 0x02571792;
|
||||||
|
|
||||||
|
// solhint-disable var-name-mixedcase
|
||||||
|
IExchange internal EXCHANGE;
|
||||||
|
address internal ERC20_PROXY_ADDRESS;
|
||||||
|
address internal ERC721_PROXY_ADDRESS;
|
||||||
|
// solhint-enable var-name-mixedcase
|
||||||
|
|
||||||
|
constructor (address _exchange)
|
||||||
|
public
|
||||||
|
{
|
||||||
|
EXCHANGE = IExchange(_exchange);
|
||||||
|
|
||||||
|
ERC20_PROXY_ADDRESS = EXCHANGE.getAssetProxy(ERC20_DATA_ID);
|
||||||
|
require(
|
||||||
|
ERC20_PROXY_ADDRESS != address(0),
|
||||||
|
"UNREGISTERED_ASSET_PROXY"
|
||||||
|
);
|
||||||
|
|
||||||
|
ERC721_PROXY_ADDRESS = EXCHANGE.getAssetProxy(ERC721_DATA_ID);
|
||||||
|
require(
|
||||||
|
ERC721_PROXY_ADDRESS != address(0),
|
||||||
|
"UNREGISTERED_ASSET_PROXY"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright 2018 ZeroEx Intl.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
pragma solidity ^0.4.24;
|
||||||
|
|
||||||
|
import "../interfaces/IAssets.sol";
|
||||||
|
|
||||||
|
|
||||||
|
contract MAssets is
|
||||||
|
IAssets
|
||||||
|
{
|
||||||
|
/// @dev Transfers given amount of asset to sender.
|
||||||
|
/// @param assetData Byte array encoded for the respective asset proxy.
|
||||||
|
/// @param amount Amount of asset to transfer to sender.
|
||||||
|
function transferAssetToSender(
|
||||||
|
bytes memory assetData,
|
||||||
|
uint256 amount
|
||||||
|
)
|
||||||
|
internal;
|
||||||
|
|
||||||
|
/// @dev Decodes ERC20 assetData and transfers given amount to sender.
|
||||||
|
/// @param assetData Byte array encoded for the respective asset proxy.
|
||||||
|
/// @param amount Amount of asset to transfer to sender.
|
||||||
|
function transferERC20Token(
|
||||||
|
bytes memory assetData,
|
||||||
|
uint256 amount
|
||||||
|
)
|
||||||
|
internal;
|
||||||
|
|
||||||
|
/// @dev Decodes ERC721 assetData and transfers given amount to sender.
|
||||||
|
/// @param assetData Byte array encoded for the respective asset proxy.
|
||||||
|
/// @param amount Amount of asset to transfer to sender.
|
||||||
|
function transferERC721Token(
|
||||||
|
bytes memory assetData,
|
||||||
|
uint256 amount
|
||||||
|
)
|
||||||
|
internal;
|
||||||
|
|
||||||
|
/// @dev Sets approval for ERC20 AssetProxy.
|
||||||
|
/// @param assetData Byte array encoded for the respective asset proxy.
|
||||||
|
/// @param amount Amount of asset to approve for respective proxy.
|
||||||
|
function approveERC20Token(
|
||||||
|
bytes memory assetData,
|
||||||
|
uint256 amount
|
||||||
|
)
|
||||||
|
internal;
|
||||||
|
|
||||||
|
/// @dev Sets approval for ERC721 AssetProxy.
|
||||||
|
/// @param assetData Byte array encoded for the respective asset proxy.
|
||||||
|
/// @param amount Amount of asset to approve for respective proxy.
|
||||||
|
function approveERC721Token(
|
||||||
|
bytes memory assetData,
|
||||||
|
uint256 amount
|
||||||
|
)
|
||||||
|
internal;
|
||||||
|
}
|
@@ -19,11 +19,11 @@
|
|||||||
pragma solidity 0.4.24;
|
pragma solidity 0.4.24;
|
||||||
pragma experimental ABIEncoderV2;
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
import "../../protocol/Exchange/interfaces/IExchange.sol";
|
import "@0x/contracts-interfaces/contracts/protocol/Exchange/IExchange.sol";
|
||||||
import "../../protocol/Exchange/libs/LibOrder.sol";
|
import "@0x/contracts-libs/contracts/libs/LibOrder.sol";
|
||||||
import "../../tokens/ERC20Token/IERC20Token.sol";
|
import "@0x/contracts-tokens/contracts/tokens/ERC20Token/IERC20Token.sol";
|
||||||
import "../../tokens/ERC721Token/IERC721Token.sol";
|
import "@0x/contracts-tokens/contracts/tokens/ERC721Token/IERC721Token.sol";
|
||||||
import "../../utils/LibBytes/LibBytes.sol";
|
import "@0x/contracts-utils/contracts/utils/LibBytes/LibBytes.sol";
|
||||||
|
|
||||||
|
|
||||||
contract OrderValidator {
|
contract OrderValidator {
|
94
contracts/extensions/package.json
Normal file
94
contracts/extensions/package.json
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
{
|
||||||
|
"name": "@0x/contracts-extensions",
|
||||||
|
"version": "1.0.2",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.12"
|
||||||
|
},
|
||||||
|
"description": "Smart contract extensions of 0x protocol",
|
||||||
|
"main": "lib/src/index.js",
|
||||||
|
"directories": {
|
||||||
|
"test": "test"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"build": "yarn pre_build && tsc -b",
|
||||||
|
"build:ci": "yarn build",
|
||||||
|
"pre_build": "run-s compile generate_contract_wrappers",
|
||||||
|
"test": "yarn run_mocha",
|
||||||
|
"rebuild_and_test": "run-s build test",
|
||||||
|
"test:coverage": "SOLIDITY_COVERAGE=true run-s build run_mocha coverage:report:text coverage:report:lcov",
|
||||||
|
"test:profiler": "SOLIDITY_PROFILER=true run-s build run_mocha profiler:report:html",
|
||||||
|
"test:trace": "SOLIDITY_REVERT_TRACE=true run-s build run_mocha",
|
||||||
|
"run_mocha": "mocha --require source-map-support/register --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit",
|
||||||
|
"compile": "sol-compiler",
|
||||||
|
"watch": "sol-compiler -w",
|
||||||
|
"clean": "shx rm -rf lib generated-artifacts generated-wrappers",
|
||||||
|
"generate_contract_wrappers": "abi-gen --abis ${npm_package_config_abis} --template ../../node_modules/@0x/abi-gen-templates/contract.handlebars --partials '../../node_modules/@0x/abi-gen-templates/partials/**/*.handlebars' --output generated-wrappers --backend ethers",
|
||||||
|
"lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
|
||||||
|
"coverage:report:text": "istanbul report text",
|
||||||
|
"coverage:report:html": "istanbul report html && open coverage/index.html",
|
||||||
|
"profiler:report:html": "istanbul report html && open coverage/index.html",
|
||||||
|
"coverage:report:lcov": "istanbul report lcov",
|
||||||
|
"test:circleci": "yarn test",
|
||||||
|
"lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol"
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"abis": "generated-artifacts/@(BalanceThresholdFilter|DutchAuction|Forwarder|OrderMatcher|OrderValidator).json"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/0xProject/0x-monorepo.git"
|
||||||
|
},
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/0xProject/0x-monorepo/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md",
|
||||||
|
"devDependencies": {
|
||||||
|
"@0x/abi-gen": "^1.0.19",
|
||||||
|
"@0x/contracts-test-utils": "^1.0.2",
|
||||||
|
"@0x/dev-utils": "^1.0.21",
|
||||||
|
"@0x/sol-compiler": "^1.1.16",
|
||||||
|
"@0x/sol-cov": "^2.1.16",
|
||||||
|
"@0x/subproviders": "^2.1.8",
|
||||||
|
"@0x/tslint-config": "^2.0.0",
|
||||||
|
"@types/bn.js": "^4.11.0",
|
||||||
|
"@types/lodash": "4.14.104",
|
||||||
|
"@types/node": "*",
|
||||||
|
"@types/yargs": "^10.0.0",
|
||||||
|
"chai": "^4.0.1",
|
||||||
|
"chai-as-promised": "^7.1.0",
|
||||||
|
"chai-bignumber": "^2.0.1",
|
||||||
|
"dirty-chai": "^2.0.1",
|
||||||
|
"ethereumjs-abi": "0.6.5",
|
||||||
|
"make-promises-safe": "^1.1.0",
|
||||||
|
"mocha": "^4.1.0",
|
||||||
|
"npm-run-all": "^4.1.2",
|
||||||
|
"shx": "^0.2.2",
|
||||||
|
"solc": "^0.4.24",
|
||||||
|
"solhint": "^1.4.1",
|
||||||
|
"tslint": "5.11.0",
|
||||||
|
"typescript": "3.0.1",
|
||||||
|
"yargs": "^10.0.3"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@0x/base-contract": "^3.0.10",
|
||||||
|
"@0x/contracts-interfaces": "^1.0.2",
|
||||||
|
"@0x/contracts-libs": "^1.0.2",
|
||||||
|
"@0x/contracts-protocol": "^2.1.59",
|
||||||
|
"@0x/contracts-tokens": "^1.0.2",
|
||||||
|
"@0x/contracts-utils": "^1.0.2",
|
||||||
|
"@0x/order-utils": "^3.0.7",
|
||||||
|
"@0x/types": "^1.4.1",
|
||||||
|
"@0x/typescript-typings": "^3.0.6",
|
||||||
|
"@0x/utils": "^2.0.8",
|
||||||
|
"@0x/web3-wrapper": "^3.2.1",
|
||||||
|
"@types/js-combinatorics": "^0.5.29",
|
||||||
|
"bn.js": "^4.11.8",
|
||||||
|
"ethereum-types": "^1.1.4",
|
||||||
|
"ethereumjs-util": "^5.1.1",
|
||||||
|
"lodash": "^4.17.5"
|
||||||
|
},
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "public"
|
||||||
|
}
|
||||||
|
}
|
15
contracts/extensions/src/artifacts/index.ts
Normal file
15
contracts/extensions/src/artifacts/index.ts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import { ContractArtifact } from 'ethereum-types';
|
||||||
|
|
||||||
|
import * as BalanceThresholdFilter from '../../generated-artifacts/BalanceThresholdFilter.json';
|
||||||
|
import * as DutchAuction from '../../generated-artifacts/DutchAuction.json';
|
||||||
|
import * as Forwarder from '../../generated-artifacts/Forwarder.json';
|
||||||
|
import * as OrderMatcher from '../../generated-artifacts/OrderMatcher.json';
|
||||||
|
import * as OrderValidator from '../../generated-artifacts/OrderValidator.json';
|
||||||
|
|
||||||
|
export const artifacts = {
|
||||||
|
BalanceThresholdFilter: BalanceThresholdFilter as ContractArtifact,
|
||||||
|
DutchAuction: DutchAuction as ContractArtifact,
|
||||||
|
Forwarder: Forwarder as ContractArtifact,
|
||||||
|
OrderMatcher: OrderMatcher as ContractArtifact,
|
||||||
|
OrderValidator: OrderValidator as ContractArtifact,
|
||||||
|
};
|
2
contracts/extensions/src/index.ts
Normal file
2
contracts/extensions/src/index.ts
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
export * from './artifacts';
|
||||||
|
export * from './wrappers';
|
5
contracts/extensions/src/wrappers/index.ts
Normal file
5
contracts/extensions/src/wrappers/index.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export * from '../../generated-wrappers/balance_threshold_filter';
|
||||||
|
export * from '../../generated-wrappers/dutch_auction';
|
||||||
|
export * from '../../generated-wrappers/forwarder';
|
||||||
|
export * from '../../generated-wrappers/order_matcher';
|
||||||
|
export * from '../../generated-wrappers/order_validator';
|
1644
contracts/extensions/test/extensions/balance_threshold_filter.ts
Normal file
1644
contracts/extensions/test/extensions/balance_threshold_filter.ts
Normal file
File diff suppressed because it is too large
Load Diff
458
contracts/extensions/test/extensions/dutch_auction.ts
Normal file
458
contracts/extensions/test/extensions/dutch_auction.ts
Normal file
@@ -0,0 +1,458 @@
|
|||||||
|
import {
|
||||||
|
artifacts as protocolArtifacts,
|
||||||
|
ERC20Wrapper,
|
||||||
|
ERC721Wrapper,
|
||||||
|
ExchangeContract,
|
||||||
|
ExchangeWrapper,
|
||||||
|
} from '@0x/contracts-protocol';
|
||||||
|
import {
|
||||||
|
chaiSetup,
|
||||||
|
constants,
|
||||||
|
ContractName,
|
||||||
|
ERC20BalancesByOwner,
|
||||||
|
expectTransactionFailedAsync,
|
||||||
|
getLatestBlockTimestampAsync,
|
||||||
|
OrderFactory,
|
||||||
|
provider,
|
||||||
|
txDefaults,
|
||||||
|
web3Wrapper,
|
||||||
|
} from '@0x/contracts-test-utils';
|
||||||
|
import {
|
||||||
|
artifacts as tokensArtifacts,
|
||||||
|
DummyERC20TokenContract,
|
||||||
|
DummyERC721TokenContract,
|
||||||
|
WETH9Contract,
|
||||||
|
} from '@0x/contracts-tokens';
|
||||||
|
import { BlockchainLifecycle } from '@0x/dev-utils';
|
||||||
|
import { assetDataUtils, generatePseudoRandomSalt } from '@0x/order-utils';
|
||||||
|
import { RevertReason, SignedOrder } from '@0x/types';
|
||||||
|
import { BigNumber } from '@0x/utils';
|
||||||
|
import { Web3Wrapper } from '@0x/web3-wrapper';
|
||||||
|
import * as chai from 'chai';
|
||||||
|
import ethAbi = require('ethereumjs-abi');
|
||||||
|
import * as ethUtil from 'ethereumjs-util';
|
||||||
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
|
import { DutchAuctionContract } from '../../generated-wrappers/dutch_auction';
|
||||||
|
import { artifacts } from '../../src/artifacts';
|
||||||
|
|
||||||
|
chaiSetup.configure();
|
||||||
|
const expect = chai.expect;
|
||||||
|
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||||
|
const DECIMALS_DEFAULT = 18;
|
||||||
|
|
||||||
|
describe(ContractName.DutchAuction, () => {
|
||||||
|
let makerAddress: string;
|
||||||
|
let owner: string;
|
||||||
|
let takerAddress: string;
|
||||||
|
let feeRecipientAddress: string;
|
||||||
|
let defaultMakerAssetAddress: string;
|
||||||
|
|
||||||
|
let zrxToken: DummyERC20TokenContract;
|
||||||
|
let erc20TokenA: DummyERC20TokenContract;
|
||||||
|
let erc721Token: DummyERC721TokenContract;
|
||||||
|
let dutchAuctionContract: DutchAuctionContract;
|
||||||
|
let wethContract: WETH9Contract;
|
||||||
|
|
||||||
|
let sellerOrderFactory: OrderFactory;
|
||||||
|
let buyerOrderFactory: OrderFactory;
|
||||||
|
let erc20Wrapper: ERC20Wrapper;
|
||||||
|
let erc20Balances: ERC20BalancesByOwner;
|
||||||
|
let currentBlockTimestamp: number;
|
||||||
|
let auctionBeginTimeSeconds: BigNumber;
|
||||||
|
let auctionEndTimeSeconds: BigNumber;
|
||||||
|
let auctionBeginAmount: BigNumber;
|
||||||
|
let auctionEndAmount: BigNumber;
|
||||||
|
let sellOrder: SignedOrder;
|
||||||
|
let buyOrder: SignedOrder;
|
||||||
|
let erc721MakerAssetIds: BigNumber[];
|
||||||
|
const tenMinutesInSeconds = 10 * 60;
|
||||||
|
|
||||||
|
function extendMakerAssetData(makerAssetData: string, beginTimeSeconds: BigNumber, beginAmount: BigNumber): string {
|
||||||
|
return ethUtil.bufferToHex(
|
||||||
|
Buffer.concat([
|
||||||
|
ethUtil.toBuffer(makerAssetData),
|
||||||
|
ethUtil.toBuffer(
|
||||||
|
(ethAbi as any).rawEncode(
|
||||||
|
['uint256', 'uint256'],
|
||||||
|
[beginTimeSeconds.toString(), beginAmount.toString()],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
await blockchainLifecycle.startAsync();
|
||||||
|
const accounts = await web3Wrapper.getAvailableAddressesAsync();
|
||||||
|
const usedAddresses = ([owner, makerAddress, takerAddress, feeRecipientAddress] = accounts);
|
||||||
|
|
||||||
|
erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner);
|
||||||
|
|
||||||
|
const numDummyErc20ToDeploy = 2;
|
||||||
|
[erc20TokenA, zrxToken] = await erc20Wrapper.deployDummyTokensAsync(
|
||||||
|
numDummyErc20ToDeploy,
|
||||||
|
constants.DUMMY_TOKEN_DECIMALS,
|
||||||
|
);
|
||||||
|
const erc20Proxy = await erc20Wrapper.deployProxyAsync();
|
||||||
|
await erc20Wrapper.setBalancesAndAllowancesAsync();
|
||||||
|
|
||||||
|
const erc721Wrapper = new ERC721Wrapper(provider, usedAddresses, owner);
|
||||||
|
[erc721Token] = await erc721Wrapper.deployDummyTokensAsync();
|
||||||
|
const erc721Proxy = await erc721Wrapper.deployProxyAsync();
|
||||||
|
await erc721Wrapper.setBalancesAndAllowancesAsync();
|
||||||
|
const erc721Balances = await erc721Wrapper.getBalancesAsync();
|
||||||
|
erc721MakerAssetIds = erc721Balances[makerAddress][erc721Token.address];
|
||||||
|
|
||||||
|
wethContract = await WETH9Contract.deployFrom0xArtifactAsync(tokensArtifacts.WETH9, provider, txDefaults);
|
||||||
|
erc20Wrapper.addDummyTokenContract(wethContract as any);
|
||||||
|
|
||||||
|
const zrxAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
|
||||||
|
const exchangeInstance = await ExchangeContract.deployFrom0xArtifactAsync(
|
||||||
|
protocolArtifacts.Exchange,
|
||||||
|
provider,
|
||||||
|
txDefaults,
|
||||||
|
zrxAssetData,
|
||||||
|
);
|
||||||
|
const exchangeWrapper = new ExchangeWrapper(exchangeInstance, provider);
|
||||||
|
await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner);
|
||||||
|
await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.address, owner);
|
||||||
|
|
||||||
|
await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchangeInstance.address, {
|
||||||
|
from: owner,
|
||||||
|
});
|
||||||
|
await erc721Proxy.addAuthorizedAddress.sendTransactionAsync(exchangeInstance.address, {
|
||||||
|
from: owner,
|
||||||
|
});
|
||||||
|
|
||||||
|
const dutchAuctionInstance = await DutchAuctionContract.deployFrom0xArtifactAsync(
|
||||||
|
artifacts.DutchAuction,
|
||||||
|
provider,
|
||||||
|
txDefaults,
|
||||||
|
exchangeInstance.address,
|
||||||
|
);
|
||||||
|
dutchAuctionContract = new DutchAuctionContract(
|
||||||
|
dutchAuctionInstance.abi,
|
||||||
|
dutchAuctionInstance.address,
|
||||||
|
provider,
|
||||||
|
);
|
||||||
|
|
||||||
|
defaultMakerAssetAddress = erc20TokenA.address;
|
||||||
|
const defaultTakerAssetAddress = wethContract.address;
|
||||||
|
|
||||||
|
// Set up taker WETH balance and allowance
|
||||||
|
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||||
|
await wethContract.deposit.sendTransactionAsync({
|
||||||
|
from: takerAddress,
|
||||||
|
value: Web3Wrapper.toBaseUnitAmount(new BigNumber(50), DECIMALS_DEFAULT),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||||
|
await wethContract.approve.sendTransactionAsync(
|
||||||
|
erc20Proxy.address,
|
||||||
|
constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS,
|
||||||
|
{ from: takerAddress },
|
||||||
|
),
|
||||||
|
);
|
||||||
|
web3Wrapper.abiDecoder.addABI(exchangeInstance.abi);
|
||||||
|
web3Wrapper.abiDecoder.addABI(zrxToken.abi);
|
||||||
|
erc20Wrapper.addTokenOwnerAddress(dutchAuctionContract.address);
|
||||||
|
|
||||||
|
currentBlockTimestamp = await getLatestBlockTimestampAsync();
|
||||||
|
// Default auction begins 10 minutes ago
|
||||||
|
auctionBeginTimeSeconds = new BigNumber(currentBlockTimestamp).minus(tenMinutesInSeconds);
|
||||||
|
// Default auction ends 10 from now
|
||||||
|
auctionEndTimeSeconds = new BigNumber(currentBlockTimestamp).plus(tenMinutesInSeconds);
|
||||||
|
auctionBeginAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(10), DECIMALS_DEFAULT);
|
||||||
|
auctionEndAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(1), DECIMALS_DEFAULT);
|
||||||
|
|
||||||
|
// Default sell order and buy order are exact mirrors
|
||||||
|
const sellerDefaultOrderParams = {
|
||||||
|
salt: generatePseudoRandomSalt(),
|
||||||
|
exchangeAddress: exchangeInstance.address,
|
||||||
|
makerAddress,
|
||||||
|
feeRecipientAddress,
|
||||||
|
// taker address or sender address should be set to the ducth auction contract
|
||||||
|
takerAddress: dutchAuctionContract.address,
|
||||||
|
makerAssetData: extendMakerAssetData(
|
||||||
|
assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
|
||||||
|
auctionBeginTimeSeconds,
|
||||||
|
auctionBeginAmount,
|
||||||
|
),
|
||||||
|
takerAssetData: assetDataUtils.encodeERC20AssetData(defaultTakerAssetAddress),
|
||||||
|
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(200), DECIMALS_DEFAULT),
|
||||||
|
takerAssetAmount: auctionEndAmount,
|
||||||
|
expirationTimeSeconds: auctionEndTimeSeconds,
|
||||||
|
makerFee: constants.ZERO_AMOUNT,
|
||||||
|
takerFee: constants.ZERO_AMOUNT,
|
||||||
|
};
|
||||||
|
// Default buy order is for the auction begin price
|
||||||
|
const buyerDefaultOrderParams = {
|
||||||
|
...sellerDefaultOrderParams,
|
||||||
|
makerAddress: takerAddress,
|
||||||
|
makerAssetData: sellerDefaultOrderParams.takerAssetData,
|
||||||
|
takerAssetData: sellerDefaultOrderParams.makerAssetData,
|
||||||
|
makerAssetAmount: auctionBeginAmount,
|
||||||
|
takerAssetAmount: sellerDefaultOrderParams.makerAssetAmount,
|
||||||
|
};
|
||||||
|
const makerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)];
|
||||||
|
const takerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(takerAddress)];
|
||||||
|
sellerOrderFactory = new OrderFactory(makerPrivateKey, sellerDefaultOrderParams);
|
||||||
|
buyerOrderFactory = new OrderFactory(takerPrivateKey, buyerDefaultOrderParams);
|
||||||
|
});
|
||||||
|
after(async () => {
|
||||||
|
await blockchainLifecycle.revertAsync();
|
||||||
|
});
|
||||||
|
beforeEach(async () => {
|
||||||
|
await blockchainLifecycle.startAsync();
|
||||||
|
erc20Balances = await erc20Wrapper.getBalancesAsync();
|
||||||
|
sellOrder = await sellerOrderFactory.newSignedOrderAsync();
|
||||||
|
buyOrder = await buyerOrderFactory.newSignedOrderAsync();
|
||||||
|
});
|
||||||
|
afterEach(async () => {
|
||||||
|
await blockchainLifecycle.revertAsync();
|
||||||
|
});
|
||||||
|
describe('matchOrders', () => {
|
||||||
|
it('should be worth the begin price at the begining of the auction', async () => {
|
||||||
|
auctionBeginTimeSeconds = new BigNumber(currentBlockTimestamp + 2);
|
||||||
|
sellOrder = await sellerOrderFactory.newSignedOrderAsync({
|
||||||
|
makerAssetData: extendMakerAssetData(
|
||||||
|
assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
|
||||||
|
auctionBeginTimeSeconds,
|
||||||
|
auctionBeginAmount,
|
||||||
|
),
|
||||||
|
});
|
||||||
|
const auctionDetails = await dutchAuctionContract.getAuctionDetails.callAsync(sellOrder);
|
||||||
|
expect(auctionDetails.currentAmount).to.be.bignumber.equal(auctionBeginAmount);
|
||||||
|
expect(auctionDetails.beginAmount).to.be.bignumber.equal(auctionBeginAmount);
|
||||||
|
});
|
||||||
|
it('should be be worth the end price at the end of the auction', async () => {
|
||||||
|
auctionBeginTimeSeconds = new BigNumber(currentBlockTimestamp - tenMinutesInSeconds * 2);
|
||||||
|
auctionEndTimeSeconds = new BigNumber(currentBlockTimestamp - tenMinutesInSeconds);
|
||||||
|
sellOrder = await sellerOrderFactory.newSignedOrderAsync({
|
||||||
|
makerAssetData: extendMakerAssetData(
|
||||||
|
assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
|
||||||
|
auctionBeginTimeSeconds,
|
||||||
|
auctionBeginAmount,
|
||||||
|
),
|
||||||
|
expirationTimeSeconds: auctionEndTimeSeconds,
|
||||||
|
});
|
||||||
|
const auctionDetails = await dutchAuctionContract.getAuctionDetails.callAsync(sellOrder);
|
||||||
|
expect(auctionDetails.currentAmount).to.be.bignumber.equal(auctionEndAmount);
|
||||||
|
expect(auctionDetails.beginAmount).to.be.bignumber.equal(auctionBeginAmount);
|
||||||
|
});
|
||||||
|
it('should match orders at current amount and send excess to buyer', async () => {
|
||||||
|
const beforeAuctionDetails = await dutchAuctionContract.getAuctionDetails.callAsync(sellOrder);
|
||||||
|
buyOrder = await buyerOrderFactory.newSignedOrderAsync({
|
||||||
|
makerAssetAmount: beforeAuctionDetails.currentAmount.times(2),
|
||||||
|
});
|
||||||
|
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||||
|
await dutchAuctionContract.matchOrders.sendTransactionAsync(
|
||||||
|
buyOrder,
|
||||||
|
sellOrder,
|
||||||
|
buyOrder.signature,
|
||||||
|
sellOrder.signature,
|
||||||
|
{
|
||||||
|
from: takerAddress,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
const afterAuctionDetails = await dutchAuctionContract.getAuctionDetails.callAsync(sellOrder);
|
||||||
|
const newBalances = await erc20Wrapper.getBalancesAsync();
|
||||||
|
expect(newBalances[dutchAuctionContract.address][wethContract.address]).to.be.bignumber.equal(
|
||||||
|
constants.ZERO_AMOUNT,
|
||||||
|
);
|
||||||
|
// HACK gte used here due to a bug in ganache where the timestamp can change
|
||||||
|
// between multiple calls to the same block. Which can move the amount in our case
|
||||||
|
// ref: https://github.com/trufflesuite/ganache-core/issues/111
|
||||||
|
expect(newBalances[makerAddress][wethContract.address]).to.be.bignumber.gte(
|
||||||
|
erc20Balances[makerAddress][wethContract.address].plus(afterAuctionDetails.currentAmount),
|
||||||
|
);
|
||||||
|
expect(newBalances[takerAddress][wethContract.address]).to.be.bignumber.gte(
|
||||||
|
erc20Balances[takerAddress][wethContract.address].minus(beforeAuctionDetails.currentAmount),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('maker fees on sellOrder are paid to the fee receipient', async () => {
|
||||||
|
sellOrder = await sellerOrderFactory.newSignedOrderAsync({
|
||||||
|
makerFee: new BigNumber(1),
|
||||||
|
});
|
||||||
|
const txHash = await dutchAuctionContract.matchOrders.sendTransactionAsync(
|
||||||
|
buyOrder,
|
||||||
|
sellOrder,
|
||||||
|
buyOrder.signature,
|
||||||
|
sellOrder.signature,
|
||||||
|
{
|
||||||
|
from: takerAddress,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||||
|
const afterAuctionDetails = await dutchAuctionContract.getAuctionDetails.callAsync(sellOrder);
|
||||||
|
const newBalances = await erc20Wrapper.getBalancesAsync();
|
||||||
|
expect(newBalances[makerAddress][wethContract.address]).to.be.bignumber.gte(
|
||||||
|
erc20Balances[makerAddress][wethContract.address].plus(afterAuctionDetails.currentAmount),
|
||||||
|
);
|
||||||
|
expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
|
||||||
|
erc20Balances[feeRecipientAddress][zrxToken.address].plus(sellOrder.makerFee),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('maker fees on buyOrder are paid to the fee receipient', async () => {
|
||||||
|
buyOrder = await buyerOrderFactory.newSignedOrderAsync({
|
||||||
|
makerFee: new BigNumber(1),
|
||||||
|
});
|
||||||
|
const txHash = await dutchAuctionContract.matchOrders.sendTransactionAsync(
|
||||||
|
buyOrder,
|
||||||
|
sellOrder,
|
||||||
|
buyOrder.signature,
|
||||||
|
sellOrder.signature,
|
||||||
|
{
|
||||||
|
from: takerAddress,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||||
|
const newBalances = await erc20Wrapper.getBalancesAsync();
|
||||||
|
const afterAuctionDetails = await dutchAuctionContract.getAuctionDetails.callAsync(sellOrder);
|
||||||
|
expect(newBalances[makerAddress][wethContract.address]).to.be.bignumber.gte(
|
||||||
|
erc20Balances[makerAddress][wethContract.address].plus(afterAuctionDetails.currentAmount),
|
||||||
|
);
|
||||||
|
expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
|
||||||
|
erc20Balances[feeRecipientAddress][zrxToken.address].plus(buyOrder.makerFee),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('should revert when auction expires', async () => {
|
||||||
|
auctionBeginTimeSeconds = new BigNumber(currentBlockTimestamp - tenMinutesInSeconds * 2);
|
||||||
|
auctionEndTimeSeconds = new BigNumber(currentBlockTimestamp - tenMinutesInSeconds);
|
||||||
|
sellOrder = await sellerOrderFactory.newSignedOrderAsync({
|
||||||
|
expirationTimeSeconds: auctionEndTimeSeconds,
|
||||||
|
makerAssetData: extendMakerAssetData(
|
||||||
|
assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
|
||||||
|
auctionBeginTimeSeconds,
|
||||||
|
auctionBeginAmount,
|
||||||
|
),
|
||||||
|
});
|
||||||
|
return expectTransactionFailedAsync(
|
||||||
|
dutchAuctionContract.matchOrders.sendTransactionAsync(
|
||||||
|
buyOrder,
|
||||||
|
sellOrder,
|
||||||
|
buyOrder.signature,
|
||||||
|
sellOrder.signature,
|
||||||
|
{
|
||||||
|
from: takerAddress,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
RevertReason.AuctionExpired,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('cannot be filled for less than the current price', async () => {
|
||||||
|
buyOrder = await buyerOrderFactory.newSignedOrderAsync({
|
||||||
|
makerAssetAmount: sellOrder.takerAssetAmount,
|
||||||
|
});
|
||||||
|
return expectTransactionFailedAsync(
|
||||||
|
dutchAuctionContract.matchOrders.sendTransactionAsync(
|
||||||
|
buyOrder,
|
||||||
|
sellOrder,
|
||||||
|
buyOrder.signature,
|
||||||
|
sellOrder.signature,
|
||||||
|
{
|
||||||
|
from: takerAddress,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
RevertReason.AuctionInvalidAmount,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('auction begin amount must be higher than final amount ', async () => {
|
||||||
|
sellOrder = await sellerOrderFactory.newSignedOrderAsync({
|
||||||
|
takerAssetAmount: auctionBeginAmount.plus(1),
|
||||||
|
});
|
||||||
|
return expectTransactionFailedAsync(
|
||||||
|
dutchAuctionContract.matchOrders.sendTransactionAsync(
|
||||||
|
buyOrder,
|
||||||
|
sellOrder,
|
||||||
|
buyOrder.signature,
|
||||||
|
sellOrder.signature,
|
||||||
|
{
|
||||||
|
from: takerAddress,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
RevertReason.AuctionInvalidAmount,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('begin time is less than end time', async () => {
|
||||||
|
auctionBeginTimeSeconds = new BigNumber(auctionEndTimeSeconds).plus(tenMinutesInSeconds);
|
||||||
|
sellOrder = await sellerOrderFactory.newSignedOrderAsync({
|
||||||
|
expirationTimeSeconds: auctionEndTimeSeconds,
|
||||||
|
makerAssetData: extendMakerAssetData(
|
||||||
|
assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
|
||||||
|
auctionBeginTimeSeconds,
|
||||||
|
auctionBeginAmount,
|
||||||
|
),
|
||||||
|
});
|
||||||
|
return expectTransactionFailedAsync(
|
||||||
|
dutchAuctionContract.matchOrders.sendTransactionAsync(
|
||||||
|
buyOrder,
|
||||||
|
sellOrder,
|
||||||
|
buyOrder.signature,
|
||||||
|
sellOrder.signature,
|
||||||
|
{
|
||||||
|
from: takerAddress,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
RevertReason.AuctionInvalidBeginTime,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('asset data contains auction parameters', async () => {
|
||||||
|
sellOrder = await sellerOrderFactory.newSignedOrderAsync({
|
||||||
|
makerAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
|
||||||
|
});
|
||||||
|
return expectTransactionFailedAsync(
|
||||||
|
dutchAuctionContract.matchOrders.sendTransactionAsync(
|
||||||
|
buyOrder,
|
||||||
|
sellOrder,
|
||||||
|
buyOrder.signature,
|
||||||
|
sellOrder.signature,
|
||||||
|
{
|
||||||
|
from: takerAddress,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
RevertReason.InvalidAssetData,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
describe('ERC721', () => {
|
||||||
|
it('should match orders when ERC721', async () => {
|
||||||
|
const makerAssetId = erc721MakerAssetIds[0];
|
||||||
|
sellOrder = await sellerOrderFactory.newSignedOrderAsync({
|
||||||
|
makerAssetAmount: new BigNumber(1),
|
||||||
|
makerAssetData: extendMakerAssetData(
|
||||||
|
assetDataUtils.encodeERC721AssetData(erc721Token.address, makerAssetId),
|
||||||
|
auctionBeginTimeSeconds,
|
||||||
|
auctionBeginAmount,
|
||||||
|
),
|
||||||
|
});
|
||||||
|
buyOrder = await buyerOrderFactory.newSignedOrderAsync({
|
||||||
|
takerAssetAmount: new BigNumber(1),
|
||||||
|
takerAssetData: sellOrder.makerAssetData,
|
||||||
|
});
|
||||||
|
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||||
|
await dutchAuctionContract.matchOrders.sendTransactionAsync(
|
||||||
|
buyOrder,
|
||||||
|
sellOrder,
|
||||||
|
buyOrder.signature,
|
||||||
|
sellOrder.signature,
|
||||||
|
{
|
||||||
|
from: takerAddress,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
const afterAuctionDetails = await dutchAuctionContract.getAuctionDetails.callAsync(sellOrder);
|
||||||
|
const newBalances = await erc20Wrapper.getBalancesAsync();
|
||||||
|
// HACK gte used here due to a bug in ganache where the timestamp can change
|
||||||
|
// between multiple calls to the same block. Which can move the amount in our case
|
||||||
|
// ref: https://github.com/trufflesuite/ganache-core/issues/111
|
||||||
|
expect(newBalances[makerAddress][wethContract.address]).to.be.bignumber.gte(
|
||||||
|
erc20Balances[makerAddress][wethContract.address].plus(afterAuctionDetails.currentAmount),
|
||||||
|
);
|
||||||
|
const newOwner = await erc721Token.ownerOf.callAsync(makerAssetId);
|
||||||
|
expect(newOwner).to.be.bignumber.equal(takerAddress);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@@ -1,3 +1,29 @@
|
|||||||
|
import {
|
||||||
|
artifacts as protocolArtifacts,
|
||||||
|
ERC20Wrapper,
|
||||||
|
ERC721Wrapper,
|
||||||
|
ExchangeContract,
|
||||||
|
ExchangeWrapper,
|
||||||
|
} from '@0x/contracts-protocol';
|
||||||
|
import {
|
||||||
|
chaiSetup,
|
||||||
|
constants,
|
||||||
|
ContractName,
|
||||||
|
ERC20BalancesByOwner,
|
||||||
|
expectContractCreationFailedAsync,
|
||||||
|
expectTransactionFailedAsync,
|
||||||
|
OrderFactory,
|
||||||
|
provider,
|
||||||
|
sendTransactionResult,
|
||||||
|
txDefaults,
|
||||||
|
web3Wrapper,
|
||||||
|
} from '@0x/contracts-test-utils';
|
||||||
|
import {
|
||||||
|
artifacts as tokenArtifacts,
|
||||||
|
DummyERC20TokenContract,
|
||||||
|
DummyERC721TokenContract,
|
||||||
|
WETH9Contract,
|
||||||
|
} from '@0x/contracts-tokens';
|
||||||
import { BlockchainLifecycle } from '@0x/dev-utils';
|
import { BlockchainLifecycle } from '@0x/dev-utils';
|
||||||
import { assetDataUtils } from '@0x/order-utils';
|
import { assetDataUtils } from '@0x/order-utils';
|
||||||
import { RevertReason, SignedOrder } from '@0x/types';
|
import { RevertReason, SignedOrder } from '@0x/types';
|
||||||
@@ -6,26 +32,10 @@ import { Web3Wrapper } from '@0x/web3-wrapper';
|
|||||||
import * as chai from 'chai';
|
import * as chai from 'chai';
|
||||||
import { TransactionReceiptWithDecodedLogs } from 'ethereum-types';
|
import { TransactionReceiptWithDecodedLogs } from 'ethereum-types';
|
||||||
|
|
||||||
import { DummyERC20TokenContract } from '../../generated-wrappers/dummy_erc20_token';
|
|
||||||
import { DummyERC721TokenContract } from '../../generated-wrappers/dummy_erc721_token';
|
|
||||||
import { ExchangeContract } from '../../generated-wrappers/exchange';
|
|
||||||
import { ForwarderContract } from '../../generated-wrappers/forwarder';
|
import { ForwarderContract } from '../../generated-wrappers/forwarder';
|
||||||
import { WETH9Contract } from '../../generated-wrappers/weth9';
|
|
||||||
import { artifacts } from '../../src/artifacts';
|
import { artifacts } from '../../src/artifacts';
|
||||||
import {
|
|
||||||
expectContractCreationFailedAsync,
|
|
||||||
expectTransactionFailedAsync,
|
|
||||||
sendTransactionResult,
|
|
||||||
} from '../utils/assertions';
|
|
||||||
import { chaiSetup } from '../utils/chai_setup';
|
|
||||||
import { constants } from '../utils/constants';
|
|
||||||
import { ERC20Wrapper } from '../utils/erc20_wrapper';
|
|
||||||
import { ERC721Wrapper } from '../utils/erc721_wrapper';
|
|
||||||
import { ExchangeWrapper } from '../utils/exchange_wrapper';
|
|
||||||
import { ForwarderWrapper } from '../utils/forwarder_wrapper';
|
import { ForwarderWrapper } from '../utils/forwarder_wrapper';
|
||||||
import { OrderFactory } from '../utils/order_factory';
|
|
||||||
import { ContractName, ERC20BalancesByOwner } from '../utils/types';
|
|
||||||
import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper';
|
|
||||||
|
|
||||||
chaiSetup.configure();
|
chaiSetup.configure();
|
||||||
const expect = chai.expect;
|
const expect = chai.expect;
|
||||||
@@ -38,7 +48,6 @@ describe(ContractName.Forwarder, () => {
|
|||||||
let owner: string;
|
let owner: string;
|
||||||
let takerAddress: string;
|
let takerAddress: string;
|
||||||
let feeRecipientAddress: string;
|
let feeRecipientAddress: string;
|
||||||
let otherAddress: string;
|
|
||||||
let defaultMakerAssetAddress: string;
|
let defaultMakerAssetAddress: string;
|
||||||
let zrxAssetData: string;
|
let zrxAssetData: string;
|
||||||
let wethAssetData: string;
|
let wethAssetData: string;
|
||||||
@@ -68,7 +77,7 @@ describe(ContractName.Forwarder, () => {
|
|||||||
before(async () => {
|
before(async () => {
|
||||||
await blockchainLifecycle.startAsync();
|
await blockchainLifecycle.startAsync();
|
||||||
const accounts = await web3Wrapper.getAvailableAddressesAsync();
|
const accounts = await web3Wrapper.getAvailableAddressesAsync();
|
||||||
const usedAddresses = ([owner, makerAddress, takerAddress, feeRecipientAddress, otherAddress] = accounts);
|
const usedAddresses = ([owner, makerAddress, takerAddress, feeRecipientAddress] = accounts);
|
||||||
|
|
||||||
const txHash = await web3Wrapper.sendTransactionAsync({ from: accounts[0], to: accounts[0], value: 0 });
|
const txHash = await web3Wrapper.sendTransactionAsync({ from: accounts[0], to: accounts[0], value: 0 });
|
||||||
const transaction = await web3Wrapper.getTransactionByHashAsync(txHash);
|
const transaction = await web3Wrapper.getTransactionByHashAsync(txHash);
|
||||||
@@ -91,14 +100,14 @@ describe(ContractName.Forwarder, () => {
|
|||||||
const erc721Balances = await erc721Wrapper.getBalancesAsync();
|
const erc721Balances = await erc721Wrapper.getBalancesAsync();
|
||||||
erc721MakerAssetIds = erc721Balances[makerAddress][erc721Token.address];
|
erc721MakerAssetIds = erc721Balances[makerAddress][erc721Token.address];
|
||||||
|
|
||||||
wethContract = await WETH9Contract.deployFrom0xArtifactAsync(artifacts.WETH9, provider, txDefaults);
|
wethContract = await WETH9Contract.deployFrom0xArtifactAsync(tokenArtifacts.WETH9, provider, txDefaults);
|
||||||
weth = new DummyERC20TokenContract(wethContract.abi, wethContract.address, provider);
|
weth = new DummyERC20TokenContract(wethContract.abi, wethContract.address, provider);
|
||||||
erc20Wrapper.addDummyTokenContract(weth);
|
erc20Wrapper.addDummyTokenContract(weth);
|
||||||
|
|
||||||
wethAssetData = assetDataUtils.encodeERC20AssetData(wethContract.address);
|
wethAssetData = assetDataUtils.encodeERC20AssetData(wethContract.address);
|
||||||
zrxAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
|
zrxAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
|
||||||
const exchangeInstance = await ExchangeContract.deployFrom0xArtifactAsync(
|
const exchangeInstance = await ExchangeContract.deployFrom0xArtifactAsync(
|
||||||
artifacts.Exchange,
|
protocolArtifacts.Exchange,
|
||||||
provider,
|
provider,
|
||||||
txDefaults,
|
txDefaults,
|
||||||
zrxAssetData,
|
zrxAssetData,
|
||||||
@@ -169,7 +178,7 @@ describe(ContractName.Forwarder, () => {
|
|||||||
describe('constructor', () => {
|
describe('constructor', () => {
|
||||||
it('should revert if assetProxy is unregistered', async () => {
|
it('should revert if assetProxy is unregistered', async () => {
|
||||||
const exchangeInstance = await ExchangeContract.deployFrom0xArtifactAsync(
|
const exchangeInstance = await ExchangeContract.deployFrom0xArtifactAsync(
|
||||||
artifacts.Exchange,
|
protocolArtifacts.Exchange,
|
||||||
provider,
|
provider,
|
||||||
txDefaults,
|
txDefaults,
|
||||||
zrxAssetData,
|
zrxAssetData,
|
818
contracts/extensions/test/extensions/order_matcher.ts
Normal file
818
contracts/extensions/test/extensions/order_matcher.ts
Normal file
@@ -0,0 +1,818 @@
|
|||||||
|
import {
|
||||||
|
artifacts as protocolArtifacts,
|
||||||
|
ERC20ProxyContract,
|
||||||
|
ERC20Wrapper,
|
||||||
|
ERC721ProxyContract,
|
||||||
|
ExchangeContract,
|
||||||
|
ExchangeFillEventArgs,
|
||||||
|
ExchangeWrapper,
|
||||||
|
} from '@0x/contracts-protocol';
|
||||||
|
import {
|
||||||
|
chaiSetup,
|
||||||
|
constants,
|
||||||
|
ERC20BalancesByOwner,
|
||||||
|
expectContractCreationFailedAsync,
|
||||||
|
expectTransactionFailedAsync,
|
||||||
|
LogDecoder,
|
||||||
|
OrderFactory,
|
||||||
|
provider,
|
||||||
|
sendTransactionResult,
|
||||||
|
txDefaults,
|
||||||
|
web3Wrapper,
|
||||||
|
} from '@0x/contracts-test-utils';
|
||||||
|
import { artifacts as tokenArtifacts, DummyERC20TokenContract, DummyERC721TokenContract } from '@0x/contracts-tokens';
|
||||||
|
import { BlockchainLifecycle } from '@0x/dev-utils';
|
||||||
|
import { assetDataUtils } from '@0x/order-utils';
|
||||||
|
import { RevertReason } from '@0x/types';
|
||||||
|
import { BigNumber } from '@0x/utils';
|
||||||
|
import { Web3Wrapper } from '@0x/web3-wrapper';
|
||||||
|
import * as chai from 'chai';
|
||||||
|
import { LogWithDecodedArgs } from 'ethereum-types';
|
||||||
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
|
import { OrderMatcherContract } from '../../generated-wrappers/order_matcher';
|
||||||
|
import { artifacts } from '../../src/artifacts';
|
||||||
|
|
||||||
|
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||||
|
chaiSetup.configure();
|
||||||
|
const expect = chai.expect;
|
||||||
|
// tslint:disable:no-unnecessary-type-assertion
|
||||||
|
describe('OrderMatcher', () => {
|
||||||
|
let makerAddressLeft: string;
|
||||||
|
let makerAddressRight: string;
|
||||||
|
let owner: string;
|
||||||
|
let takerAddress: string;
|
||||||
|
let feeRecipientAddressLeft: string;
|
||||||
|
let feeRecipientAddressRight: string;
|
||||||
|
|
||||||
|
let erc20TokenA: DummyERC20TokenContract;
|
||||||
|
let erc20TokenB: DummyERC20TokenContract;
|
||||||
|
let zrxToken: DummyERC20TokenContract;
|
||||||
|
let exchange: ExchangeContract;
|
||||||
|
let erc20Proxy: ERC20ProxyContract;
|
||||||
|
let erc721Proxy: ERC721ProxyContract;
|
||||||
|
let orderMatcher: OrderMatcherContract;
|
||||||
|
|
||||||
|
let erc20BalancesByOwner: ERC20BalancesByOwner;
|
||||||
|
let exchangeWrapper: ExchangeWrapper;
|
||||||
|
let erc20Wrapper: ERC20Wrapper;
|
||||||
|
let orderFactoryLeft: OrderFactory;
|
||||||
|
let orderFactoryRight: OrderFactory;
|
||||||
|
|
||||||
|
let leftMakerAssetData: string;
|
||||||
|
let leftTakerAssetData: string;
|
||||||
|
let defaultERC20MakerAssetAddress: string;
|
||||||
|
let defaultERC20TakerAssetAddress: string;
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
await blockchainLifecycle.startAsync();
|
||||||
|
});
|
||||||
|
after(async () => {
|
||||||
|
await blockchainLifecycle.revertAsync();
|
||||||
|
});
|
||||||
|
before(async () => {
|
||||||
|
// Create accounts
|
||||||
|
const accounts = await web3Wrapper.getAvailableAddressesAsync();
|
||||||
|
// Hack(albrow): Both Prettier and TSLint insert a trailing comma below
|
||||||
|
// but that is invalid syntax as of TypeScript version >= 2.8. We don't
|
||||||
|
// have the right fine-grained configuration options in TSLint,
|
||||||
|
// Prettier, or TypeScript, to reconcile this, so we will just have to
|
||||||
|
// wait for them to sort it out. We disable TSLint and Prettier for
|
||||||
|
// this part of the code for now. This occurs several times in this
|
||||||
|
// file. See https://github.com/prettier/prettier/issues/4624.
|
||||||
|
// prettier-ignore
|
||||||
|
const usedAddresses = ([
|
||||||
|
owner,
|
||||||
|
makerAddressLeft,
|
||||||
|
makerAddressRight,
|
||||||
|
takerAddress,
|
||||||
|
feeRecipientAddressLeft,
|
||||||
|
// tslint:disable-next-line:trailing-comma
|
||||||
|
feeRecipientAddressRight
|
||||||
|
] = _.slice(accounts, 0, 6));
|
||||||
|
// Create wrappers
|
||||||
|
erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner);
|
||||||
|
// Deploy ERC20 token & ERC20 proxy
|
||||||
|
const numDummyErc20ToDeploy = 3;
|
||||||
|
[erc20TokenA, erc20TokenB, zrxToken] = await erc20Wrapper.deployDummyTokensAsync(
|
||||||
|
numDummyErc20ToDeploy,
|
||||||
|
constants.DUMMY_TOKEN_DECIMALS,
|
||||||
|
);
|
||||||
|
erc20Proxy = await erc20Wrapper.deployProxyAsync();
|
||||||
|
await erc20Wrapper.setBalancesAndAllowancesAsync();
|
||||||
|
// Deploy ERC721 proxy
|
||||||
|
erc721Proxy = await ERC721ProxyContract.deployFrom0xArtifactAsync(
|
||||||
|
protocolArtifacts.ERC721Proxy,
|
||||||
|
provider,
|
||||||
|
txDefaults,
|
||||||
|
);
|
||||||
|
// Depoy exchange
|
||||||
|
exchange = await ExchangeContract.deployFrom0xArtifactAsync(
|
||||||
|
protocolArtifacts.Exchange,
|
||||||
|
provider,
|
||||||
|
txDefaults,
|
||||||
|
assetDataUtils.encodeERC20AssetData(zrxToken.address),
|
||||||
|
);
|
||||||
|
exchangeWrapper = new ExchangeWrapper(exchange, provider);
|
||||||
|
await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner);
|
||||||
|
await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.address, owner);
|
||||||
|
// Authorize ERC20 trades by exchange
|
||||||
|
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||||
|
await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, {
|
||||||
|
from: owner,
|
||||||
|
}),
|
||||||
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
|
);
|
||||||
|
// Deploy OrderMatcher
|
||||||
|
orderMatcher = await OrderMatcherContract.deployFrom0xArtifactAsync(
|
||||||
|
artifacts.OrderMatcher,
|
||||||
|
provider,
|
||||||
|
txDefaults,
|
||||||
|
exchange.address,
|
||||||
|
);
|
||||||
|
// Set default addresses
|
||||||
|
defaultERC20MakerAssetAddress = erc20TokenA.address;
|
||||||
|
defaultERC20TakerAssetAddress = erc20TokenB.address;
|
||||||
|
leftMakerAssetData = assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress);
|
||||||
|
leftTakerAssetData = assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress);
|
||||||
|
// Set OrderMatcher balances and allowances
|
||||||
|
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||||
|
await erc20TokenA.setBalance.sendTransactionAsync(orderMatcher.address, constants.INITIAL_ERC20_BALANCE, {
|
||||||
|
from: owner,
|
||||||
|
}),
|
||||||
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
|
);
|
||||||
|
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||||
|
await erc20TokenB.setBalance.sendTransactionAsync(orderMatcher.address, constants.INITIAL_ERC20_BALANCE, {
|
||||||
|
from: owner,
|
||||||
|
}),
|
||||||
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
|
);
|
||||||
|
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||||
|
await orderMatcher.approveAssetProxy.sendTransactionAsync(
|
||||||
|
leftMakerAssetData,
|
||||||
|
constants.INITIAL_ERC20_ALLOWANCE,
|
||||||
|
),
|
||||||
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
|
);
|
||||||
|
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||||
|
await orderMatcher.approveAssetProxy.sendTransactionAsync(
|
||||||
|
leftTakerAssetData,
|
||||||
|
constants.INITIAL_ERC20_ALLOWANCE,
|
||||||
|
),
|
||||||
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
|
);
|
||||||
|
// Create default order parameters
|
||||||
|
const defaultOrderParamsLeft = {
|
||||||
|
...constants.STATIC_ORDER_PARAMS,
|
||||||
|
makerAddress: makerAddressLeft,
|
||||||
|
exchangeAddress: exchange.address,
|
||||||
|
makerAssetData: leftMakerAssetData,
|
||||||
|
takerAssetData: leftTakerAssetData,
|
||||||
|
feeRecipientAddress: feeRecipientAddressLeft,
|
||||||
|
makerFee: constants.ZERO_AMOUNT,
|
||||||
|
takerFee: constants.ZERO_AMOUNT,
|
||||||
|
};
|
||||||
|
const defaultOrderParamsRight = {
|
||||||
|
...constants.STATIC_ORDER_PARAMS,
|
||||||
|
makerAddress: makerAddressRight,
|
||||||
|
exchangeAddress: exchange.address,
|
||||||
|
makerAssetData: leftTakerAssetData,
|
||||||
|
takerAssetData: leftMakerAssetData,
|
||||||
|
feeRecipientAddress: feeRecipientAddressRight,
|
||||||
|
makerFee: constants.ZERO_AMOUNT,
|
||||||
|
takerFee: constants.ZERO_AMOUNT,
|
||||||
|
};
|
||||||
|
const privateKeyLeft = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddressLeft)];
|
||||||
|
orderFactoryLeft = new OrderFactory(privateKeyLeft, defaultOrderParamsLeft);
|
||||||
|
const privateKeyRight = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddressRight)];
|
||||||
|
orderFactoryRight = new OrderFactory(privateKeyRight, defaultOrderParamsRight);
|
||||||
|
});
|
||||||
|
beforeEach(async () => {
|
||||||
|
await blockchainLifecycle.startAsync();
|
||||||
|
});
|
||||||
|
afterEach(async () => {
|
||||||
|
await blockchainLifecycle.revertAsync();
|
||||||
|
});
|
||||||
|
describe('constructor', () => {
|
||||||
|
it('should revert if assetProxy is unregistered', async () => {
|
||||||
|
const exchangeInstance = await ExchangeContract.deployFrom0xArtifactAsync(
|
||||||
|
protocolArtifacts.Exchange,
|
||||||
|
provider,
|
||||||
|
txDefaults,
|
||||||
|
constants.NULL_BYTES,
|
||||||
|
);
|
||||||
|
return expectContractCreationFailedAsync(
|
||||||
|
(OrderMatcherContract.deployFrom0xArtifactAsync(
|
||||||
|
artifacts.OrderMatcher,
|
||||||
|
provider,
|
||||||
|
txDefaults,
|
||||||
|
exchangeInstance.address,
|
||||||
|
) as any) as sendTransactionResult,
|
||||||
|
RevertReason.UnregisteredAssetProxy,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('matchOrders', () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
erc20BalancesByOwner = await erc20Wrapper.getBalancesAsync();
|
||||||
|
});
|
||||||
|
it('should revert if not called by owner', async () => {
|
||||||
|
// Create orders to match
|
||||||
|
const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
|
||||||
|
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
|
||||||
|
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||||
|
});
|
||||||
|
const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
|
||||||
|
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||||
|
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
|
||||||
|
});
|
||||||
|
const data = exchange.matchOrders.getABIEncodedTransactionData(
|
||||||
|
signedOrderLeft,
|
||||||
|
signedOrderRight,
|
||||||
|
signedOrderLeft.signature,
|
||||||
|
signedOrderRight.signature,
|
||||||
|
);
|
||||||
|
await expectTransactionFailedAsync(
|
||||||
|
web3Wrapper.sendTransactionAsync({
|
||||||
|
data,
|
||||||
|
to: orderMatcher.address,
|
||||||
|
from: takerAddress,
|
||||||
|
gas: constants.MAX_MATCH_ORDERS_GAS,
|
||||||
|
}),
|
||||||
|
RevertReason.OnlyContractOwner,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('should transfer the correct amounts when orders completely fill each other', async () => {
|
||||||
|
// Create orders to match
|
||||||
|
const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
|
||||||
|
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
|
||||||
|
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||||
|
});
|
||||||
|
const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
|
||||||
|
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||||
|
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
|
||||||
|
});
|
||||||
|
// Match signedOrderLeft with signedOrderRight
|
||||||
|
const expectedTransferAmounts = {
|
||||||
|
// Left Maker
|
||||||
|
amountSoldByLeftMaker: signedOrderLeft.makerAssetAmount,
|
||||||
|
amountBoughtByLeftMaker: signedOrderLeft.takerAssetAmount,
|
||||||
|
// Right Maker
|
||||||
|
amountSoldByRightMaker: signedOrderRight.makerAssetAmount,
|
||||||
|
amountBoughtByRightMaker: signedOrderRight.takerAssetAmount,
|
||||||
|
// Taker
|
||||||
|
leftMakerAssetSpreadAmount: signedOrderLeft.makerAssetAmount.minus(signedOrderRight.takerAssetAmount),
|
||||||
|
};
|
||||||
|
const initialLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
|
||||||
|
const data = exchange.matchOrders.getABIEncodedTransactionData(
|
||||||
|
signedOrderLeft,
|
||||||
|
signedOrderRight,
|
||||||
|
signedOrderLeft.signature,
|
||||||
|
signedOrderRight.signature,
|
||||||
|
);
|
||||||
|
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||||
|
await web3Wrapper.sendTransactionAsync({
|
||||||
|
data,
|
||||||
|
to: orderMatcher.address,
|
||||||
|
from: owner,
|
||||||
|
gas: constants.MAX_MATCH_ORDERS_GAS,
|
||||||
|
}),
|
||||||
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
|
);
|
||||||
|
const newLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
|
||||||
|
const newErc20Balances = await erc20Wrapper.getBalancesAsync();
|
||||||
|
expect(newErc20Balances[makerAddressLeft][defaultERC20MakerAssetAddress]).to.be.bignumber.equal(
|
||||||
|
erc20BalancesByOwner[makerAddressLeft][defaultERC20MakerAssetAddress].minus(
|
||||||
|
expectedTransferAmounts.amountSoldByLeftMaker,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
expect(newErc20Balances[makerAddressRight][defaultERC20TakerAssetAddress]).to.be.bignumber.equal(
|
||||||
|
erc20BalancesByOwner[makerAddressRight][defaultERC20TakerAssetAddress].minus(
|
||||||
|
expectedTransferAmounts.amountSoldByRightMaker,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
expect(newErc20Balances[makerAddressLeft][defaultERC20TakerAssetAddress]).to.be.bignumber.equal(
|
||||||
|
erc20BalancesByOwner[makerAddressLeft][defaultERC20TakerAssetAddress].plus(
|
||||||
|
expectedTransferAmounts.amountBoughtByLeftMaker,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
expect(newErc20Balances[makerAddressRight][defaultERC20MakerAssetAddress]).to.be.bignumber.equal(
|
||||||
|
erc20BalancesByOwner[makerAddressRight][defaultERC20MakerAssetAddress].plus(
|
||||||
|
expectedTransferAmounts.amountBoughtByRightMaker,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
expect(newLeftMakerAssetTakerBalance).to.be.bignumber.equal(
|
||||||
|
initialLeftMakerAssetTakerBalance.plus(expectedTransferAmounts.leftMakerAssetSpreadAmount),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('should transfer the correct amounts when orders completely fill each other and taker doesnt take a profit', async () => {
|
||||||
|
// Create orders to match
|
||||||
|
const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
|
||||||
|
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
|
||||||
|
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||||
|
});
|
||||||
|
const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
|
||||||
|
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||||
|
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
|
||||||
|
});
|
||||||
|
// Match signedOrderLeft with signedOrderRight
|
||||||
|
const expectedTransferAmounts = {
|
||||||
|
// Left Maker
|
||||||
|
amountSoldByLeftMaker: signedOrderLeft.makerAssetAmount,
|
||||||
|
amountBoughtByLeftMaker: signedOrderLeft.takerAssetAmount,
|
||||||
|
// Right Maker
|
||||||
|
amountSoldByRightMaker: signedOrderRight.makerAssetAmount,
|
||||||
|
amountBoughtByRightMaker: signedOrderRight.takerAssetAmount,
|
||||||
|
};
|
||||||
|
const initialLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
|
||||||
|
const data = exchange.matchOrders.getABIEncodedTransactionData(
|
||||||
|
signedOrderLeft,
|
||||||
|
signedOrderRight,
|
||||||
|
signedOrderLeft.signature,
|
||||||
|
signedOrderRight.signature,
|
||||||
|
);
|
||||||
|
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||||
|
await web3Wrapper.sendTransactionAsync({
|
||||||
|
data,
|
||||||
|
to: orderMatcher.address,
|
||||||
|
from: owner,
|
||||||
|
gas: constants.MAX_MATCH_ORDERS_GAS,
|
||||||
|
}),
|
||||||
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
|
);
|
||||||
|
const newLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
|
||||||
|
const newErc20Balances = await erc20Wrapper.getBalancesAsync();
|
||||||
|
expect(newErc20Balances[makerAddressLeft][defaultERC20MakerAssetAddress]).to.be.bignumber.equal(
|
||||||
|
erc20BalancesByOwner[makerAddressLeft][defaultERC20MakerAssetAddress].minus(
|
||||||
|
expectedTransferAmounts.amountSoldByLeftMaker,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
expect(newErc20Balances[makerAddressRight][defaultERC20TakerAssetAddress]).to.be.bignumber.equal(
|
||||||
|
erc20BalancesByOwner[makerAddressRight][defaultERC20TakerAssetAddress].minus(
|
||||||
|
expectedTransferAmounts.amountSoldByRightMaker,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
expect(newErc20Balances[makerAddressLeft][defaultERC20TakerAssetAddress]).to.be.bignumber.equal(
|
||||||
|
erc20BalancesByOwner[makerAddressLeft][defaultERC20TakerAssetAddress].plus(
|
||||||
|
expectedTransferAmounts.amountBoughtByLeftMaker,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
expect(newErc20Balances[makerAddressRight][defaultERC20MakerAssetAddress]).to.be.bignumber.equal(
|
||||||
|
erc20BalancesByOwner[makerAddressRight][defaultERC20MakerAssetAddress].plus(
|
||||||
|
expectedTransferAmounts.amountBoughtByRightMaker,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
expect(newLeftMakerAssetTakerBalance).to.be.bignumber.equal(initialLeftMakerAssetTakerBalance);
|
||||||
|
});
|
||||||
|
it('should transfer the correct amounts when left order is completely filled and right order would be partially filled', async () => {
|
||||||
|
// Create orders to match
|
||||||
|
const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
|
||||||
|
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
|
||||||
|
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||||
|
});
|
||||||
|
const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
|
||||||
|
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(20), 18),
|
||||||
|
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(4), 18),
|
||||||
|
});
|
||||||
|
// Match signedOrderLeft with signedOrderRight
|
||||||
|
const expectedTransferAmounts = {
|
||||||
|
// Left Maker
|
||||||
|
amountSoldByLeftMaker: signedOrderLeft.makerAssetAmount,
|
||||||
|
amountBoughtByLeftMaker: signedOrderLeft.takerAssetAmount,
|
||||||
|
// Right Maker
|
||||||
|
amountSoldByRightMaker: signedOrderRight.makerAssetAmount,
|
||||||
|
amountBoughtByRightMaker: signedOrderRight.takerAssetAmount,
|
||||||
|
// Taker
|
||||||
|
leftMakerAssetSpreadAmount: signedOrderLeft.makerAssetAmount.minus(signedOrderRight.takerAssetAmount),
|
||||||
|
leftTakerAssetSpreadAmount: signedOrderRight.makerAssetAmount.minus(signedOrderLeft.takerAssetAmount),
|
||||||
|
};
|
||||||
|
const initialLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
|
||||||
|
const initialLeftTakerAssetTakerBalance = await erc20TokenB.balanceOf.callAsync(orderMatcher.address);
|
||||||
|
// Match signedOrderLeft with signedOrderRight
|
||||||
|
const data = exchange.matchOrders.getABIEncodedTransactionData(
|
||||||
|
signedOrderLeft,
|
||||||
|
signedOrderRight,
|
||||||
|
signedOrderLeft.signature,
|
||||||
|
signedOrderRight.signature,
|
||||||
|
);
|
||||||
|
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||||
|
await web3Wrapper.sendTransactionAsync({
|
||||||
|
data,
|
||||||
|
to: orderMatcher.address,
|
||||||
|
from: owner,
|
||||||
|
gas: constants.MAX_MATCH_ORDERS_GAS,
|
||||||
|
}),
|
||||||
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
|
);
|
||||||
|
const newLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
|
||||||
|
const newLeftTakerAssetTakerBalance = await erc20TokenB.balanceOf.callAsync(orderMatcher.address);
|
||||||
|
const newErc20Balances = await erc20Wrapper.getBalancesAsync();
|
||||||
|
expect(newErc20Balances[makerAddressLeft][defaultERC20MakerAssetAddress]).to.be.bignumber.equal(
|
||||||
|
erc20BalancesByOwner[makerAddressLeft][defaultERC20MakerAssetAddress].minus(
|
||||||
|
expectedTransferAmounts.amountSoldByLeftMaker,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
expect(newErc20Balances[makerAddressRight][defaultERC20TakerAssetAddress]).to.be.bignumber.equal(
|
||||||
|
erc20BalancesByOwner[makerAddressRight][defaultERC20TakerAssetAddress].minus(
|
||||||
|
expectedTransferAmounts.amountSoldByRightMaker,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
expect(newErc20Balances[makerAddressLeft][defaultERC20TakerAssetAddress]).to.be.bignumber.equal(
|
||||||
|
erc20BalancesByOwner[makerAddressLeft][defaultERC20TakerAssetAddress].plus(
|
||||||
|
expectedTransferAmounts.amountBoughtByLeftMaker,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
expect(newErc20Balances[makerAddressRight][defaultERC20MakerAssetAddress]).to.be.bignumber.equal(
|
||||||
|
erc20BalancesByOwner[makerAddressRight][defaultERC20MakerAssetAddress].plus(
|
||||||
|
expectedTransferAmounts.amountBoughtByRightMaker,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
expect(newLeftMakerAssetTakerBalance).to.be.bignumber.equal(
|
||||||
|
initialLeftMakerAssetTakerBalance.plus(expectedTransferAmounts.leftMakerAssetSpreadAmount),
|
||||||
|
);
|
||||||
|
expect(newLeftTakerAssetTakerBalance).to.be.bignumber.equal(
|
||||||
|
initialLeftTakerAssetTakerBalance.plus(expectedTransferAmounts.leftTakerAssetSpreadAmount),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('should not call fillOrder when rightOrder is completely filled after matchOrders call and orders were never partially filled', async () => {
|
||||||
|
// Create orders to match
|
||||||
|
const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
|
||||||
|
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
|
||||||
|
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||||
|
});
|
||||||
|
const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
|
||||||
|
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||||
|
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
|
||||||
|
});
|
||||||
|
const data = exchange.matchOrders.getABIEncodedTransactionData(
|
||||||
|
signedOrderLeft,
|
||||||
|
signedOrderRight,
|
||||||
|
signedOrderLeft.signature,
|
||||||
|
signedOrderRight.signature,
|
||||||
|
);
|
||||||
|
const logDecoder = new LogDecoder(web3Wrapper, { ...artifacts, ...tokenArtifacts, ...protocolArtifacts });
|
||||||
|
const txReceipt = await logDecoder.getTxWithDecodedLogsAsync(
|
||||||
|
await web3Wrapper.sendTransactionAsync({
|
||||||
|
data,
|
||||||
|
to: orderMatcher.address,
|
||||||
|
from: owner,
|
||||||
|
gas: constants.MAX_MATCH_ORDERS_GAS,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
const fillLogs = _.filter(
|
||||||
|
txReceipt.logs,
|
||||||
|
log => (log as LogWithDecodedArgs<ExchangeFillEventArgs>).event === 'Fill',
|
||||||
|
);
|
||||||
|
// Only 2 Fill logs should exist for `matchOrders` call. `fillOrder` should not have been called and should not have emitted a Fill event.
|
||||||
|
expect(fillLogs.length).to.be.equal(2);
|
||||||
|
});
|
||||||
|
it('should not call fillOrder when rightOrder is completely filled after matchOrders call and orders were initially partially filled', async () => {
|
||||||
|
// Create orders to match
|
||||||
|
const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
|
||||||
|
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
|
||||||
|
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||||
|
});
|
||||||
|
const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
|
||||||
|
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||||
|
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
|
||||||
|
});
|
||||||
|
await exchangeWrapper.fillOrderAsync(signedOrderLeft, takerAddress, {
|
||||||
|
takerAssetFillAmount: signedOrderLeft.takerAssetAmount.dividedToIntegerBy(5),
|
||||||
|
});
|
||||||
|
await exchangeWrapper.fillOrderAsync(signedOrderRight, takerAddress, {
|
||||||
|
takerAssetFillAmount: signedOrderRight.takerAssetAmount.dividedToIntegerBy(5),
|
||||||
|
});
|
||||||
|
const data = exchange.matchOrders.getABIEncodedTransactionData(
|
||||||
|
signedOrderLeft,
|
||||||
|
signedOrderRight,
|
||||||
|
signedOrderLeft.signature,
|
||||||
|
signedOrderRight.signature,
|
||||||
|
);
|
||||||
|
const logDecoder = new LogDecoder(web3Wrapper, { ...artifacts, ...tokenArtifacts, ...protocolArtifacts });
|
||||||
|
const txReceipt = await logDecoder.getTxWithDecodedLogsAsync(
|
||||||
|
await web3Wrapper.sendTransactionAsync({
|
||||||
|
data,
|
||||||
|
to: orderMatcher.address,
|
||||||
|
from: owner,
|
||||||
|
gas: constants.MAX_MATCH_ORDERS_GAS,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
const fillLogs = _.filter(
|
||||||
|
txReceipt.logs,
|
||||||
|
log => (log as LogWithDecodedArgs<ExchangeFillEventArgs>).event === 'Fill',
|
||||||
|
);
|
||||||
|
// Only 2 Fill logs should exist for `matchOrders` call. `fillOrder` should not have been called and should not have emitted a Fill event.
|
||||||
|
expect(fillLogs.length).to.be.equal(2);
|
||||||
|
});
|
||||||
|
it('should only take a spread in rightMakerAsset if entire leftMakerAssetSpread amount can be used to fill rightOrder after matchOrders call', async () => {
|
||||||
|
// Create orders to match
|
||||||
|
const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
|
||||||
|
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||||
|
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(0.9), 18),
|
||||||
|
});
|
||||||
|
const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
|
||||||
|
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
|
||||||
|
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(990), 18),
|
||||||
|
});
|
||||||
|
const initialLeftMakerAssetSpreadAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(1.09), 18);
|
||||||
|
const leftTakerAssetSpreadAmount = initialLeftMakerAssetSpreadAmount
|
||||||
|
.times(signedOrderRight.makerAssetAmount)
|
||||||
|
.dividedToIntegerBy(signedOrderRight.takerAssetAmount);
|
||||||
|
// Match signedOrderLeft with signedOrderRight
|
||||||
|
const expectedTransferAmounts = {
|
||||||
|
// Left Maker
|
||||||
|
amountSoldByLeftMaker: signedOrderLeft.makerAssetAmount,
|
||||||
|
amountBoughtByLeftMaker: signedOrderLeft.takerAssetAmount,
|
||||||
|
// Right Maker
|
||||||
|
amountSoldByRightMaker: signedOrderLeft.takerAssetAmount.plus(leftTakerAssetSpreadAmount),
|
||||||
|
amountBoughtByRightMaker: signedOrderLeft.makerAssetAmount,
|
||||||
|
// Taker
|
||||||
|
leftMakerAssetSpreadAmount: constants.ZERO_AMOUNT,
|
||||||
|
leftTakerAssetSpreadAmount,
|
||||||
|
};
|
||||||
|
const initialLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
|
||||||
|
const initialLeftTakerAssetTakerBalance = await erc20TokenB.balanceOf.callAsync(orderMatcher.address);
|
||||||
|
// Match signedOrderLeft with signedOrderRight
|
||||||
|
const data = exchange.matchOrders.getABIEncodedTransactionData(
|
||||||
|
signedOrderLeft,
|
||||||
|
signedOrderRight,
|
||||||
|
signedOrderLeft.signature,
|
||||||
|
signedOrderRight.signature,
|
||||||
|
);
|
||||||
|
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||||
|
await web3Wrapper.sendTransactionAsync({
|
||||||
|
data,
|
||||||
|
to: orderMatcher.address,
|
||||||
|
from: owner,
|
||||||
|
gas: constants.MAX_MATCH_ORDERS_GAS,
|
||||||
|
}),
|
||||||
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
|
);
|
||||||
|
const newLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
|
||||||
|
const newLeftTakerAssetTakerBalance = await erc20TokenB.balanceOf.callAsync(orderMatcher.address);
|
||||||
|
const newErc20Balances = await erc20Wrapper.getBalancesAsync();
|
||||||
|
expect(newErc20Balances[makerAddressLeft][defaultERC20MakerAssetAddress]).to.be.bignumber.equal(
|
||||||
|
erc20BalancesByOwner[makerAddressLeft][defaultERC20MakerAssetAddress].minus(
|
||||||
|
expectedTransferAmounts.amountSoldByLeftMaker,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
expect(newErc20Balances[makerAddressRight][defaultERC20TakerAssetAddress]).to.be.bignumber.equal(
|
||||||
|
erc20BalancesByOwner[makerAddressRight][defaultERC20TakerAssetAddress].minus(
|
||||||
|
expectedTransferAmounts.amountSoldByRightMaker,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
expect(newErc20Balances[makerAddressLeft][defaultERC20TakerAssetAddress]).to.be.bignumber.equal(
|
||||||
|
erc20BalancesByOwner[makerAddressLeft][defaultERC20TakerAssetAddress].plus(
|
||||||
|
expectedTransferAmounts.amountBoughtByLeftMaker,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
expect(newErc20Balances[makerAddressRight][defaultERC20MakerAssetAddress]).to.be.bignumber.equal(
|
||||||
|
erc20BalancesByOwner[makerAddressRight][defaultERC20MakerAssetAddress].plus(
|
||||||
|
expectedTransferAmounts.amountBoughtByRightMaker,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
expect(newLeftMakerAssetTakerBalance).to.be.bignumber.equal(
|
||||||
|
initialLeftMakerAssetTakerBalance.plus(expectedTransferAmounts.leftMakerAssetSpreadAmount),
|
||||||
|
);
|
||||||
|
expect(newLeftTakerAssetTakerBalance).to.be.bignumber.equal(
|
||||||
|
initialLeftTakerAssetTakerBalance.plus(expectedTransferAmounts.leftTakerAssetSpreadAmount),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it("should succeed if rightOrder's makerAssetData and takerAssetData are not provided", async () => {
|
||||||
|
// Create orders to match
|
||||||
|
const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
|
||||||
|
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
|
||||||
|
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||||
|
});
|
||||||
|
const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
|
||||||
|
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(20), 18),
|
||||||
|
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(4), 18),
|
||||||
|
});
|
||||||
|
// Match signedOrderLeft with signedOrderRight
|
||||||
|
const expectedTransferAmounts = {
|
||||||
|
// Left Maker
|
||||||
|
amountSoldByLeftMaker: signedOrderLeft.makerAssetAmount,
|
||||||
|
amountBoughtByLeftMaker: signedOrderLeft.takerAssetAmount,
|
||||||
|
// Right Maker
|
||||||
|
amountSoldByRightMaker: signedOrderRight.makerAssetAmount,
|
||||||
|
amountBoughtByRightMaker: signedOrderRight.takerAssetAmount,
|
||||||
|
// Taker
|
||||||
|
leftMakerAssetSpreadAmount: signedOrderLeft.makerAssetAmount.minus(signedOrderRight.takerAssetAmount),
|
||||||
|
leftTakerAssetSpreadAmount: signedOrderRight.makerAssetAmount.minus(signedOrderLeft.takerAssetAmount),
|
||||||
|
};
|
||||||
|
const initialLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
|
||||||
|
const initialLeftTakerAssetTakerBalance = await erc20TokenB.balanceOf.callAsync(orderMatcher.address);
|
||||||
|
// Match signedOrderLeft with signedOrderRight
|
||||||
|
signedOrderRight.makerAssetData = constants.NULL_BYTES;
|
||||||
|
signedOrderRight.takerAssetData = constants.NULL_BYTES;
|
||||||
|
const data = exchange.matchOrders.getABIEncodedTransactionData(
|
||||||
|
signedOrderLeft,
|
||||||
|
signedOrderRight,
|
||||||
|
signedOrderLeft.signature,
|
||||||
|
signedOrderRight.signature,
|
||||||
|
);
|
||||||
|
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||||
|
await web3Wrapper.sendTransactionAsync({
|
||||||
|
data,
|
||||||
|
to: orderMatcher.address,
|
||||||
|
from: owner,
|
||||||
|
gas: constants.MAX_MATCH_ORDERS_GAS,
|
||||||
|
}),
|
||||||
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
|
);
|
||||||
|
const newLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
|
||||||
|
const newLeftTakerAssetTakerBalance = await erc20TokenB.balanceOf.callAsync(orderMatcher.address);
|
||||||
|
const newErc20Balances = await erc20Wrapper.getBalancesAsync();
|
||||||
|
expect(newErc20Balances[makerAddressLeft][defaultERC20MakerAssetAddress]).to.be.bignumber.equal(
|
||||||
|
erc20BalancesByOwner[makerAddressLeft][defaultERC20MakerAssetAddress].minus(
|
||||||
|
expectedTransferAmounts.amountSoldByLeftMaker,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
expect(newErc20Balances[makerAddressRight][defaultERC20TakerAssetAddress]).to.be.bignumber.equal(
|
||||||
|
erc20BalancesByOwner[makerAddressRight][defaultERC20TakerAssetAddress].minus(
|
||||||
|
expectedTransferAmounts.amountSoldByRightMaker,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
expect(newErc20Balances[makerAddressLeft][defaultERC20TakerAssetAddress]).to.be.bignumber.equal(
|
||||||
|
erc20BalancesByOwner[makerAddressLeft][defaultERC20TakerAssetAddress].plus(
|
||||||
|
expectedTransferAmounts.amountBoughtByLeftMaker,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
expect(newErc20Balances[makerAddressRight][defaultERC20MakerAssetAddress]).to.be.bignumber.equal(
|
||||||
|
erc20BalancesByOwner[makerAddressRight][defaultERC20MakerAssetAddress].plus(
|
||||||
|
expectedTransferAmounts.amountBoughtByRightMaker,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
expect(newLeftMakerAssetTakerBalance).to.be.bignumber.equal(
|
||||||
|
initialLeftMakerAssetTakerBalance.plus(expectedTransferAmounts.leftMakerAssetSpreadAmount),
|
||||||
|
);
|
||||||
|
expect(newLeftTakerAssetTakerBalance).to.be.bignumber.equal(
|
||||||
|
initialLeftTakerAssetTakerBalance.plus(expectedTransferAmounts.leftTakerAssetSpreadAmount),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('should revert with the correct reason if matchOrders call reverts', async () => {
|
||||||
|
// Create orders to match
|
||||||
|
const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
|
||||||
|
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
|
||||||
|
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||||
|
});
|
||||||
|
const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
|
||||||
|
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||||
|
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
|
||||||
|
});
|
||||||
|
signedOrderRight.signature = `0xff${signedOrderRight.signature.slice(4)}`;
|
||||||
|
const data = exchange.matchOrders.getABIEncodedTransactionData(
|
||||||
|
signedOrderLeft,
|
||||||
|
signedOrderRight,
|
||||||
|
signedOrderLeft.signature,
|
||||||
|
signedOrderRight.signature,
|
||||||
|
);
|
||||||
|
await expectTransactionFailedAsync(
|
||||||
|
web3Wrapper.sendTransactionAsync({
|
||||||
|
data,
|
||||||
|
to: orderMatcher.address,
|
||||||
|
from: owner,
|
||||||
|
gas: constants.MAX_MATCH_ORDERS_GAS,
|
||||||
|
}),
|
||||||
|
RevertReason.InvalidOrderSignature,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('should revert with the correct reason if fillOrder call reverts', async () => {
|
||||||
|
// Create orders to match
|
||||||
|
const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
|
||||||
|
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
|
||||||
|
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||||
|
});
|
||||||
|
const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
|
||||||
|
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(20), 18),
|
||||||
|
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(4), 18),
|
||||||
|
});
|
||||||
|
// Matcher will not have enough allowance to fill rightOrder
|
||||||
|
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||||
|
await orderMatcher.approveAssetProxy.sendTransactionAsync(leftMakerAssetData, constants.ZERO_AMOUNT, {
|
||||||
|
from: owner,
|
||||||
|
}),
|
||||||
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
|
);
|
||||||
|
const data = exchange.matchOrders.getABIEncodedTransactionData(
|
||||||
|
signedOrderLeft,
|
||||||
|
signedOrderRight,
|
||||||
|
signedOrderLeft.signature,
|
||||||
|
signedOrderRight.signature,
|
||||||
|
);
|
||||||
|
await expectTransactionFailedAsync(
|
||||||
|
web3Wrapper.sendTransactionAsync({
|
||||||
|
data,
|
||||||
|
to: orderMatcher.address,
|
||||||
|
from: owner,
|
||||||
|
gas: constants.MAX_MATCH_ORDERS_GAS,
|
||||||
|
}),
|
||||||
|
RevertReason.TransferFailed,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('withdrawAsset', () => {
|
||||||
|
it('should allow owner to withdraw ERC20 tokens', async () => {
|
||||||
|
const erc20AWithdrawAmount = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
|
||||||
|
expect(erc20AWithdrawAmount).to.be.bignumber.gt(constants.ZERO_AMOUNT);
|
||||||
|
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||||
|
await orderMatcher.withdrawAsset.sendTransactionAsync(leftMakerAssetData, erc20AWithdrawAmount, {
|
||||||
|
from: owner,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
const newBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
|
||||||
|
expect(newBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
|
||||||
|
});
|
||||||
|
it('should allow owner to withdraw ERC721 tokens', async () => {
|
||||||
|
const erc721Token = await DummyERC721TokenContract.deployFrom0xArtifactAsync(
|
||||||
|
tokenArtifacts.DummyERC721Token,
|
||||||
|
provider,
|
||||||
|
txDefaults,
|
||||||
|
constants.DUMMY_TOKEN_NAME,
|
||||||
|
constants.DUMMY_TOKEN_SYMBOL,
|
||||||
|
);
|
||||||
|
const tokenId = new BigNumber(1);
|
||||||
|
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||||
|
await erc721Token.mint.sendTransactionAsync(orderMatcher.address, tokenId, { from: owner }),
|
||||||
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
|
);
|
||||||
|
const assetData = assetDataUtils.encodeERC721AssetData(erc721Token.address, tokenId);
|
||||||
|
const withdrawAmount = new BigNumber(1);
|
||||||
|
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||||
|
await orderMatcher.withdrawAsset.sendTransactionAsync(assetData, withdrawAmount, { from: owner }),
|
||||||
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
|
);
|
||||||
|
const erc721Owner = await erc721Token.ownerOf.callAsync(tokenId);
|
||||||
|
expect(erc721Owner).to.be.equal(owner);
|
||||||
|
});
|
||||||
|
it('should revert if not called by owner', async () => {
|
||||||
|
const erc20AWithdrawAmount = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
|
||||||
|
expect(erc20AWithdrawAmount).to.be.bignumber.gt(constants.ZERO_AMOUNT);
|
||||||
|
await expectTransactionFailedAsync(
|
||||||
|
orderMatcher.withdrawAsset.sendTransactionAsync(leftMakerAssetData, erc20AWithdrawAmount, {
|
||||||
|
from: takerAddress,
|
||||||
|
}),
|
||||||
|
RevertReason.OnlyContractOwner,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('approveAssetProxy', () => {
|
||||||
|
it('should be able to set an allowance for ERC20 tokens', async () => {
|
||||||
|
const allowance = new BigNumber(55465465426546);
|
||||||
|
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||||
|
await orderMatcher.approveAssetProxy.sendTransactionAsync(leftMakerAssetData, allowance, {
|
||||||
|
from: owner,
|
||||||
|
}),
|
||||||
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
|
);
|
||||||
|
const newAllowance = await erc20TokenA.allowance.callAsync(orderMatcher.address, erc20Proxy.address);
|
||||||
|
expect(newAllowance).to.be.bignumber.equal(allowance);
|
||||||
|
});
|
||||||
|
it('should be able to approve an ERC721 token by passing in allowance = 1', async () => {
|
||||||
|
const erc721Token = await DummyERC721TokenContract.deployFrom0xArtifactAsync(
|
||||||
|
tokenArtifacts.DummyERC721Token,
|
||||||
|
provider,
|
||||||
|
txDefaults,
|
||||||
|
constants.DUMMY_TOKEN_NAME,
|
||||||
|
constants.DUMMY_TOKEN_SYMBOL,
|
||||||
|
);
|
||||||
|
const assetData = assetDataUtils.encodeERC721AssetData(erc721Token.address, constants.ZERO_AMOUNT);
|
||||||
|
const allowance = new BigNumber(1);
|
||||||
|
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||||
|
await orderMatcher.approveAssetProxy.sendTransactionAsync(assetData, allowance, { from: owner }),
|
||||||
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
|
);
|
||||||
|
const isApproved = await erc721Token.isApprovedForAll.callAsync(orderMatcher.address, erc721Proxy.address);
|
||||||
|
expect(isApproved).to.be.equal(true);
|
||||||
|
});
|
||||||
|
it('should be able to approve an ERC721 token by passing in allowance > 1', async () => {
|
||||||
|
const erc721Token = await DummyERC721TokenContract.deployFrom0xArtifactAsync(
|
||||||
|
tokenArtifacts.DummyERC721Token,
|
||||||
|
provider,
|
||||||
|
txDefaults,
|
||||||
|
constants.DUMMY_TOKEN_NAME,
|
||||||
|
constants.DUMMY_TOKEN_SYMBOL,
|
||||||
|
);
|
||||||
|
const assetData = assetDataUtils.encodeERC721AssetData(erc721Token.address, constants.ZERO_AMOUNT);
|
||||||
|
const allowance = new BigNumber(2);
|
||||||
|
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||||
|
await orderMatcher.approveAssetProxy.sendTransactionAsync(assetData, allowance, { from: owner }),
|
||||||
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
|
);
|
||||||
|
const isApproved = await erc721Token.isApprovedForAll.callAsync(orderMatcher.address, erc721Proxy.address);
|
||||||
|
expect(isApproved).to.be.equal(true);
|
||||||
|
});
|
||||||
|
it('should revert if not called by owner', async () => {
|
||||||
|
const approval = new BigNumber(1);
|
||||||
|
await expectTransactionFailedAsync(
|
||||||
|
orderMatcher.approveAssetProxy.sendTransactionAsync(leftMakerAssetData, approval, {
|
||||||
|
from: takerAddress,
|
||||||
|
}),
|
||||||
|
RevertReason.OnlyContractOwner,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
// tslint:disable:max-file-line-count
|
||||||
|
// tslint:enable:no-unnecessary-type-assertion
|
@@ -1,3 +1,22 @@
|
|||||||
|
import {
|
||||||
|
artifacts as protocolArtifacts,
|
||||||
|
ERC20ProxyContract,
|
||||||
|
ERC20Wrapper,
|
||||||
|
ERC721ProxyContract,
|
||||||
|
ERC721Wrapper,
|
||||||
|
ExchangeContract,
|
||||||
|
ExchangeWrapper,
|
||||||
|
} from '@0x/contracts-protocol';
|
||||||
|
import {
|
||||||
|
chaiSetup,
|
||||||
|
constants,
|
||||||
|
OrderFactory,
|
||||||
|
OrderStatus,
|
||||||
|
provider,
|
||||||
|
txDefaults,
|
||||||
|
web3Wrapper,
|
||||||
|
} from '@0x/contracts-test-utils';
|
||||||
|
import { DummyERC20TokenContract, DummyERC721TokenContract } from '@0x/contracts-tokens';
|
||||||
import { BlockchainLifecycle } from '@0x/dev-utils';
|
import { BlockchainLifecycle } from '@0x/dev-utils';
|
||||||
import { assetDataUtils, orderHashUtils } from '@0x/order-utils';
|
import { assetDataUtils, orderHashUtils } from '@0x/order-utils';
|
||||||
import { SignedOrder } from '@0x/types';
|
import { SignedOrder } from '@0x/types';
|
||||||
@@ -5,21 +24,8 @@ import { BigNumber } from '@0x/utils';
|
|||||||
import * as chai from 'chai';
|
import * as chai from 'chai';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import { DummyERC20TokenContract } from '../../generated-wrappers/dummy_erc20_token';
|
|
||||||
import { DummyERC721TokenContract } from '../../generated-wrappers/dummy_erc721_token';
|
|
||||||
import { ERC20ProxyContract } from '../../generated-wrappers/erc20_proxy';
|
|
||||||
import { ERC721ProxyContract } from '../../generated-wrappers/erc721_proxy';
|
|
||||||
import { ExchangeContract } from '../../generated-wrappers/exchange';
|
|
||||||
import { OrderValidatorContract } from '../../generated-wrappers/order_validator';
|
import { OrderValidatorContract } from '../../generated-wrappers/order_validator';
|
||||||
import { artifacts } from '../../src/artifacts';
|
import { artifacts } from '../../src/artifacts/index';
|
||||||
import { chaiSetup } from '../utils/chai_setup';
|
|
||||||
import { constants } from '../utils/constants';
|
|
||||||
import { ERC20Wrapper } from '../utils/erc20_wrapper';
|
|
||||||
import { ERC721Wrapper } from '../utils/erc721_wrapper';
|
|
||||||
import { ExchangeWrapper } from '../utils/exchange_wrapper';
|
|
||||||
import { OrderFactory } from '../utils/order_factory';
|
|
||||||
import { OrderStatus } from '../utils/types';
|
|
||||||
import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper';
|
|
||||||
|
|
||||||
chaiSetup.configure();
|
chaiSetup.configure();
|
||||||
const expect = chai.expect;
|
const expect = chai.expect;
|
||||||
@@ -75,7 +81,7 @@ describe('OrderValidator', () => {
|
|||||||
|
|
||||||
const zrxAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
|
const zrxAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
|
||||||
exchange = await ExchangeContract.deployFrom0xArtifactAsync(
|
exchange = await ExchangeContract.deployFrom0xArtifactAsync(
|
||||||
artifacts.Exchange,
|
protocolArtifacts.Exchange,
|
||||||
provider,
|
provider,
|
||||||
txDefaults,
|
txDefaults,
|
||||||
zrxAssetData,
|
zrxAssetData,
|
17
contracts/extensions/test/global_hooks.ts
Normal file
17
contracts/extensions/test/global_hooks.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import { env, EnvVars } from '@0x/dev-utils';
|
||||||
|
|
||||||
|
import { coverage, profiler, provider } from '@0x/contracts-test-utils';
|
||||||
|
before('start web3 provider', () => {
|
||||||
|
provider.start();
|
||||||
|
});
|
||||||
|
after('generate coverage report', async () => {
|
||||||
|
if (env.parseBoolean(EnvVars.SolidityCoverage)) {
|
||||||
|
const coverageSubprovider = coverage.getCoverageSubproviderSingleton();
|
||||||
|
await coverageSubprovider.writeCoverageAsync();
|
||||||
|
}
|
||||||
|
if (env.parseBoolean(EnvVars.SolidityProfiler)) {
|
||||||
|
const profilerSubprovider = profiler.getProfilerSubproviderSingleton();
|
||||||
|
await profilerSubprovider.writeProfilerOutputAsync();
|
||||||
|
}
|
||||||
|
provider.stop();
|
||||||
|
});
|
283
contracts/extensions/test/utils/balance_threshold_wrapper.ts
Normal file
283
contracts/extensions/test/utils/balance_threshold_wrapper.ts
Normal file
@@ -0,0 +1,283 @@
|
|||||||
|
import { artifacts as protocolArtifacts, ExchangeContract } from '@0x/contracts-protocol';
|
||||||
|
import {
|
||||||
|
FillResults,
|
||||||
|
formatters,
|
||||||
|
LogDecoder,
|
||||||
|
OrderInfo,
|
||||||
|
orderUtils,
|
||||||
|
TransactionFactory,
|
||||||
|
} from '@0x/contracts-test-utils';
|
||||||
|
import { artifacts as tokensArtifacts } from '@0x/contracts-tokens';
|
||||||
|
import { SignedOrder } from '@0x/types';
|
||||||
|
import { BigNumber } from '@0x/utils';
|
||||||
|
import { Web3Wrapper } from '@0x/web3-wrapper';
|
||||||
|
import { Provider, TransactionReceiptWithDecodedLogs } from 'ethereum-types';
|
||||||
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
|
import { BalanceThresholdFilterContract } from '../../generated-wrappers/balance_threshold_filter';
|
||||||
|
import { artifacts } from '../../src/artifacts';
|
||||||
|
|
||||||
|
export class BalanceThresholdWrapper {
|
||||||
|
private readonly _balanceThresholdFilter: BalanceThresholdFilterContract;
|
||||||
|
private readonly _signerTransactionFactory: TransactionFactory;
|
||||||
|
private readonly _exchange: ExchangeContract;
|
||||||
|
private readonly _web3Wrapper: Web3Wrapper;
|
||||||
|
private readonly _logDecoder: LogDecoder;
|
||||||
|
constructor(
|
||||||
|
balanceThresholdFilter: BalanceThresholdFilterContract,
|
||||||
|
exchangeContract: ExchangeContract,
|
||||||
|
signerTransactionFactory: TransactionFactory,
|
||||||
|
provider: Provider,
|
||||||
|
) {
|
||||||
|
this._balanceThresholdFilter = balanceThresholdFilter;
|
||||||
|
this._exchange = exchangeContract;
|
||||||
|
this._signerTransactionFactory = signerTransactionFactory;
|
||||||
|
this._web3Wrapper = new Web3Wrapper(provider);
|
||||||
|
this._logDecoder = new LogDecoder(this._web3Wrapper, {
|
||||||
|
...artifacts,
|
||||||
|
...tokensArtifacts,
|
||||||
|
...protocolArtifacts,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
public async fillOrderAsync(
|
||||||
|
signedOrder: SignedOrder,
|
||||||
|
from: string,
|
||||||
|
opts: { takerAssetFillAmount?: BigNumber } = {},
|
||||||
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
|
const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount);
|
||||||
|
const data = this._exchange.fillOrder.getABIEncodedTransactionData(
|
||||||
|
params.order,
|
||||||
|
params.takerAssetFillAmount,
|
||||||
|
params.signature,
|
||||||
|
);
|
||||||
|
const txReceipt = this._executeTransactionAsync(data, from);
|
||||||
|
return txReceipt;
|
||||||
|
}
|
||||||
|
public async fillOrKillOrderAsync(
|
||||||
|
signedOrder: SignedOrder,
|
||||||
|
from: string,
|
||||||
|
opts: { takerAssetFillAmount?: BigNumber } = {},
|
||||||
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
|
const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount);
|
||||||
|
const data = this._exchange.fillOrKillOrder.getABIEncodedTransactionData(
|
||||||
|
params.order,
|
||||||
|
params.takerAssetFillAmount,
|
||||||
|
params.signature,
|
||||||
|
);
|
||||||
|
const txReceipt = this._executeTransactionAsync(data, from);
|
||||||
|
return txReceipt;
|
||||||
|
}
|
||||||
|
public async fillOrderNoThrowAsync(
|
||||||
|
signedOrder: SignedOrder,
|
||||||
|
from: string,
|
||||||
|
opts: { takerAssetFillAmount?: BigNumber; gas?: number } = {},
|
||||||
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
|
const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount);
|
||||||
|
const data = this._exchange.fillOrderNoThrow.getABIEncodedTransactionData(
|
||||||
|
params.order,
|
||||||
|
params.takerAssetFillAmount,
|
||||||
|
params.signature,
|
||||||
|
);
|
||||||
|
const txReceipt = this._executeTransactionAsync(data, from, opts.gas);
|
||||||
|
return txReceipt;
|
||||||
|
}
|
||||||
|
public async batchFillOrdersAsync(
|
||||||
|
orders: SignedOrder[],
|
||||||
|
from: string,
|
||||||
|
opts: { takerAssetFillAmounts?: BigNumber[] } = {},
|
||||||
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
|
const params = formatters.createBatchFill(orders, opts.takerAssetFillAmounts);
|
||||||
|
const data = this._exchange.batchFillOrders.getABIEncodedTransactionData(
|
||||||
|
params.orders,
|
||||||
|
params.takerAssetFillAmounts,
|
||||||
|
params.signatures,
|
||||||
|
);
|
||||||
|
const txReceipt = this._executeTransactionAsync(data, from);
|
||||||
|
return txReceipt;
|
||||||
|
}
|
||||||
|
public async batchFillOrKillOrdersAsync(
|
||||||
|
orders: SignedOrder[],
|
||||||
|
from: string,
|
||||||
|
opts: { takerAssetFillAmounts?: BigNumber[] } = {},
|
||||||
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
|
const params = formatters.createBatchFill(orders, opts.takerAssetFillAmounts);
|
||||||
|
const data = this._exchange.batchFillOrKillOrders.getABIEncodedTransactionData(
|
||||||
|
params.orders,
|
||||||
|
params.takerAssetFillAmounts,
|
||||||
|
params.signatures,
|
||||||
|
);
|
||||||
|
const txReceipt = this._executeTransactionAsync(data, from);
|
||||||
|
return txReceipt;
|
||||||
|
}
|
||||||
|
public async batchFillOrdersNoThrowAsync(
|
||||||
|
orders: SignedOrder[],
|
||||||
|
from: string,
|
||||||
|
opts: { takerAssetFillAmounts?: BigNumber[]; gas?: number } = {},
|
||||||
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
|
const params = formatters.createBatchFill(orders, opts.takerAssetFillAmounts);
|
||||||
|
const data = this._exchange.batchFillOrKillOrders.getABIEncodedTransactionData(
|
||||||
|
params.orders,
|
||||||
|
params.takerAssetFillAmounts,
|
||||||
|
params.signatures,
|
||||||
|
);
|
||||||
|
const txReceipt = this._executeTransactionAsync(data, from, opts.gas);
|
||||||
|
return txReceipt;
|
||||||
|
}
|
||||||
|
public async marketSellOrdersAsync(
|
||||||
|
orders: SignedOrder[],
|
||||||
|
from: string,
|
||||||
|
opts: { takerAssetFillAmount: BigNumber },
|
||||||
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
|
const params = formatters.createMarketSellOrders(orders, opts.takerAssetFillAmount);
|
||||||
|
const data = this._exchange.marketSellOrders.getABIEncodedTransactionData(
|
||||||
|
params.orders,
|
||||||
|
params.takerAssetFillAmount,
|
||||||
|
params.signatures,
|
||||||
|
);
|
||||||
|
const txReceipt = this._executeTransactionAsync(data, from);
|
||||||
|
return txReceipt;
|
||||||
|
}
|
||||||
|
public async marketSellOrdersNoThrowAsync(
|
||||||
|
orders: SignedOrder[],
|
||||||
|
from: string,
|
||||||
|
opts: { takerAssetFillAmount: BigNumber; gas?: number },
|
||||||
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
|
const params = formatters.createMarketSellOrders(orders, opts.takerAssetFillAmount);
|
||||||
|
const data = this._exchange.marketSellOrdersNoThrow.getABIEncodedTransactionData(
|
||||||
|
params.orders,
|
||||||
|
params.takerAssetFillAmount,
|
||||||
|
params.signatures,
|
||||||
|
);
|
||||||
|
const txReceipt = this._executeTransactionAsync(data, from, opts.gas);
|
||||||
|
return txReceipt;
|
||||||
|
}
|
||||||
|
public async marketBuyOrdersAsync(
|
||||||
|
orders: SignedOrder[],
|
||||||
|
from: string,
|
||||||
|
opts: { makerAssetFillAmount: BigNumber },
|
||||||
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
|
const params = formatters.createMarketBuyOrders(orders, opts.makerAssetFillAmount);
|
||||||
|
const data = this._exchange.marketBuyOrders.getABIEncodedTransactionData(
|
||||||
|
params.orders,
|
||||||
|
params.makerAssetFillAmount,
|
||||||
|
params.signatures,
|
||||||
|
);
|
||||||
|
const txReceipt = this._executeTransactionAsync(data, from);
|
||||||
|
return txReceipt;
|
||||||
|
}
|
||||||
|
public async marketBuyOrdersNoThrowAsync(
|
||||||
|
orders: SignedOrder[],
|
||||||
|
from: string,
|
||||||
|
opts: { makerAssetFillAmount: BigNumber; gas?: number },
|
||||||
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
|
const params = formatters.createMarketBuyOrders(orders, opts.makerAssetFillAmount);
|
||||||
|
const data = this._exchange.marketBuyOrdersNoThrow.getABIEncodedTransactionData(
|
||||||
|
params.orders,
|
||||||
|
params.makerAssetFillAmount,
|
||||||
|
params.signatures,
|
||||||
|
);
|
||||||
|
const txReceipt = this._executeTransactionAsync(data, from, opts.gas);
|
||||||
|
return txReceipt;
|
||||||
|
}
|
||||||
|
public async cancelOrderAsync(signedOrder: SignedOrder, from: string): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
|
const params = orderUtils.createCancel(signedOrder);
|
||||||
|
const data = this._exchange.cancelOrder.getABIEncodedTransactionData(params.order);
|
||||||
|
const txReceipt = this._executeTransactionAsync(data, from);
|
||||||
|
return txReceipt;
|
||||||
|
}
|
||||||
|
public async batchCancelOrdersAsync(
|
||||||
|
orders: SignedOrder[],
|
||||||
|
from: string,
|
||||||
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
|
const params = formatters.createBatchCancel(orders);
|
||||||
|
const data = this._exchange.batchCancelOrders.getABIEncodedTransactionData(params.orders);
|
||||||
|
const txReceipt = this._executeTransactionAsync(data, from);
|
||||||
|
return txReceipt;
|
||||||
|
}
|
||||||
|
public async cancelOrdersUpToAsync(salt: BigNumber, from: string): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
|
const data = this._exchange.cancelOrdersUpTo.getABIEncodedTransactionData(salt);
|
||||||
|
const txReceipt = this._executeTransactionAsync(data, from);
|
||||||
|
return txReceipt;
|
||||||
|
}
|
||||||
|
public async getTakerAssetFilledAmountAsync(orderHashHex: string): Promise<BigNumber> {
|
||||||
|
const filledAmount = await this._exchange.filled.callAsync(orderHashHex);
|
||||||
|
return filledAmount;
|
||||||
|
}
|
||||||
|
public async isCancelledAsync(orderHashHex: string): Promise<boolean> {
|
||||||
|
const isCancelled = await this._exchange.cancelled.callAsync(orderHashHex);
|
||||||
|
return isCancelled;
|
||||||
|
}
|
||||||
|
public async getOrderEpochAsync(makerAddress: string, senderAddress: string): Promise<BigNumber> {
|
||||||
|
const orderEpoch = await this._exchange.orderEpoch.callAsync(makerAddress, senderAddress);
|
||||||
|
return orderEpoch;
|
||||||
|
}
|
||||||
|
public async getOrderInfoAsync(signedOrder: SignedOrder): Promise<OrderInfo> {
|
||||||
|
const orderInfo = await this._exchange.getOrderInfo.callAsync(signedOrder);
|
||||||
|
return orderInfo;
|
||||||
|
}
|
||||||
|
public async getOrdersInfoAsync(signedOrders: SignedOrder[]): Promise<OrderInfo[]> {
|
||||||
|
const ordersInfo = (await this._exchange.getOrdersInfo.callAsync(signedOrders)) as OrderInfo[];
|
||||||
|
return ordersInfo;
|
||||||
|
}
|
||||||
|
public async matchOrdersAsync(
|
||||||
|
signedOrderLeft: SignedOrder,
|
||||||
|
signedOrderRight: SignedOrder,
|
||||||
|
from: string,
|
||||||
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
|
const params = orderUtils.createMatchOrders(signedOrderLeft, signedOrderRight);
|
||||||
|
const data = await this._exchange.matchOrders.getABIEncodedTransactionData(
|
||||||
|
params.left,
|
||||||
|
params.right,
|
||||||
|
params.leftSignature,
|
||||||
|
params.rightSignature,
|
||||||
|
);
|
||||||
|
const txReceipt = this._executeTransactionAsync(data, from);
|
||||||
|
return txReceipt;
|
||||||
|
}
|
||||||
|
public async getFillOrderResultsAsync(
|
||||||
|
signedOrder: SignedOrder,
|
||||||
|
from: string,
|
||||||
|
opts: { takerAssetFillAmount?: BigNumber } = {},
|
||||||
|
): Promise<FillResults> {
|
||||||
|
const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount);
|
||||||
|
const fillResults = await this._exchange.fillOrder.callAsync(
|
||||||
|
params.order,
|
||||||
|
params.takerAssetFillAmount,
|
||||||
|
params.signature,
|
||||||
|
{ from },
|
||||||
|
);
|
||||||
|
return fillResults;
|
||||||
|
}
|
||||||
|
public abiEncodeFillOrder(signedOrder: SignedOrder, opts: { takerAssetFillAmount?: BigNumber } = {}): string {
|
||||||
|
const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount);
|
||||||
|
const data = this._exchange.fillOrder.getABIEncodedTransactionData(
|
||||||
|
params.order,
|
||||||
|
params.takerAssetFillAmount,
|
||||||
|
params.signature,
|
||||||
|
);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
public getBalanceThresholdAddress(): string {
|
||||||
|
return this._balanceThresholdFilter.address;
|
||||||
|
}
|
||||||
|
public getExchangeAddress(): string {
|
||||||
|
return this._exchange.address;
|
||||||
|
}
|
||||||
|
private async _executeTransactionAsync(
|
||||||
|
abiEncodedExchangeTxData: string,
|
||||||
|
from: string,
|
||||||
|
gas?: number,
|
||||||
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
|
const signedExchangeTx = this._signerTransactionFactory.newSignedTransaction(abiEncodedExchangeTxData);
|
||||||
|
const txOpts = _.isUndefined(gas) ? { from } : { from, gas };
|
||||||
|
const txHash = await this._balanceThresholdFilter.executeTransaction.sendTransactionAsync(
|
||||||
|
signedExchangeTx.salt,
|
||||||
|
signedExchangeTx.signerAddress,
|
||||||
|
signedExchangeTx.data,
|
||||||
|
signedExchangeTx.signature,
|
||||||
|
txOpts,
|
||||||
|
);
|
||||||
|
const txReceipt = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
|
||||||
|
return txReceipt;
|
||||||
|
}
|
||||||
|
}
|
@@ -1,3 +1,6 @@
|
|||||||
|
import { artifacts as protocolArtifacts } from '@0x/contracts-protocol';
|
||||||
|
import { constants, formatters, LogDecoder, MarketSellOrders } from '@0x/contracts-test-utils';
|
||||||
|
import { artifacts as tokensArtifacts } from '@0x/contracts-tokens';
|
||||||
import { SignedOrder } from '@0x/types';
|
import { SignedOrder } from '@0x/types';
|
||||||
import { BigNumber } from '@0x/utils';
|
import { BigNumber } from '@0x/utils';
|
||||||
import { Web3Wrapper } from '@0x/web3-wrapper';
|
import { Web3Wrapper } from '@0x/web3-wrapper';
|
||||||
@@ -5,11 +8,7 @@ import { Provider, TransactionReceiptWithDecodedLogs, TxDataPayable } from 'ethe
|
|||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import { ForwarderContract } from '../../generated-wrappers/forwarder';
|
import { ForwarderContract } from '../../generated-wrappers/forwarder';
|
||||||
|
import { artifacts } from '../../src/artifacts';
|
||||||
import { constants } from './constants';
|
|
||||||
import { formatters } from './formatters';
|
|
||||||
import { LogDecoder } from './log_decoder';
|
|
||||||
import { MarketSellOrders } from './types';
|
|
||||||
|
|
||||||
export class ForwarderWrapper {
|
export class ForwarderWrapper {
|
||||||
private readonly _web3Wrapper: Web3Wrapper;
|
private readonly _web3Wrapper: Web3Wrapper;
|
||||||
@@ -61,7 +60,11 @@ export class ForwarderWrapper {
|
|||||||
constructor(contractInstance: ForwarderContract, provider: Provider) {
|
constructor(contractInstance: ForwarderContract, provider: Provider) {
|
||||||
this._forwarderContract = contractInstance;
|
this._forwarderContract = contractInstance;
|
||||||
this._web3Wrapper = new Web3Wrapper(provider);
|
this._web3Wrapper = new Web3Wrapper(provider);
|
||||||
this._logDecoder = new LogDecoder(this._web3Wrapper);
|
this._logDecoder = new LogDecoder(this._web3Wrapper, {
|
||||||
|
...artifacts,
|
||||||
|
...tokensArtifacts,
|
||||||
|
...protocolArtifacts,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
public async marketSellOrdersWithEthAsync(
|
public async marketSellOrdersWithEthAsync(
|
||||||
orders: SignedOrder[],
|
orders: SignedOrder[],
|
17
contracts/extensions/tsconfig.json
Normal file
17
contracts/extensions/tsconfig.json
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../tsconfig",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "lib",
|
||||||
|
"rootDir": ".",
|
||||||
|
"resolveJsonModule": true
|
||||||
|
},
|
||||||
|
"include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
|
||||||
|
"files": [
|
||||||
|
"./generated-artifacts/BalanceThresholdFilter.json",
|
||||||
|
"./generated-artifacts/DutchAuction.json",
|
||||||
|
"./generated-artifacts/Forwarder.json",
|
||||||
|
"./generated-artifacts/OrderMatcher.json",
|
||||||
|
"./generated-artifacts/OrderValidator.json"
|
||||||
|
],
|
||||||
|
"exclude": ["./deploy/solc/solc_bin"]
|
||||||
|
}
|
6
contracts/extensions/tslint.json
Normal file
6
contracts/extensions/tslint.json
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"extends": ["@0x/tslint-config"],
|
||||||
|
"rules": {
|
||||||
|
"custom-no-magic-numbers": false
|
||||||
|
}
|
||||||
|
}
|
11
contracts/interfaces/CHANGELOG.json
Normal file
11
contracts/interfaces/CHANGELOG.json
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"timestamp": 1544741676,
|
||||||
|
"version": "1.0.2",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
10
contracts/interfaces/CHANGELOG.md
Normal file
10
contracts/interfaces/CHANGELOG.md
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<!--
|
||||||
|
changelogUtils.file is auto-generated using the monorepo-scripts package. Don't edit directly.
|
||||||
|
Edit the package's CHANGELOG.json file only.
|
||||||
|
-->
|
||||||
|
|
||||||
|
CHANGELOG
|
||||||
|
|
||||||
|
## v1.0.2 - _December 13, 2018_
|
||||||
|
|
||||||
|
* Dependencies updated
|
72
contracts/interfaces/README.md
Normal file
72
contracts/interfaces/README.md
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
## Contract interfaces
|
||||||
|
|
||||||
|
Smart contract interfaces of the 0x protocol.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Contracts that make up and interact with version 2.0.0 of the protocol can be found in the [contracts](./contracts) directory. The contents of this directory are broken down into the following subdirectories:
|
||||||
|
|
||||||
|
* [protocol](./contracts/protocol)
|
||||||
|
* This directory contains the contract interfaces that make up version 2.0.0. A full specification can be found [here](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md).
|
||||||
|
|
||||||
|
## Bug bounty
|
||||||
|
|
||||||
|
A bug bounty for the 2.0.0 contracts is ongoing! Instructions can be found [here](https://0xproject.com/wiki#Bug-Bounty).
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
We strongly recommend that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository.
|
||||||
|
|
||||||
|
For proposals regarding the 0x protocol's smart contract architecture, message format, or additional functionality, go to the [0x Improvement Proposals (ZEIPs)](https://github.com/0xProject/ZEIPs) repository and follow the contribution guidelines provided therein.
|
||||||
|
|
||||||
|
Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started.
|
||||||
|
|
||||||
|
### Install Dependencies
|
||||||
|
|
||||||
|
If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yarn config set workspaces-experimental true
|
||||||
|
```
|
||||||
|
|
||||||
|
Then install dependencies
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yarn install
|
||||||
|
```
|
||||||
|
|
||||||
|
### Build
|
||||||
|
|
||||||
|
To build this package and all other monorepo packages that it depends on, run the following from the monorepo root directory:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
PKG=@0x/contracts-interfaces yarn build
|
||||||
|
```
|
||||||
|
|
||||||
|
Or continuously rebuild on change:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
PKG=@0x/contracts-interfaces yarn watch
|
||||||
|
```
|
||||||
|
|
||||||
|
### Clean
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yarn clean
|
||||||
|
```
|
||||||
|
|
||||||
|
### Lint
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yarn lint
|
||||||
|
```
|
||||||
|
|
||||||
|
### Run Tests
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yarn test
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Testing options
|
||||||
|
|
||||||
|
Contracts testing options like coverage, profiling, revert traces or backing node choosing - are described [here](../TESTING.md).
|
35
contracts/interfaces/compiler.json
Normal file
35
contracts/interfaces/compiler.json
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"artifactsDir": "./generated-artifacts",
|
||||||
|
"contractsDir": "./contracts",
|
||||||
|
"compilerSettings": {
|
||||||
|
"optimizer": {
|
||||||
|
"enabled": true,
|
||||||
|
"runs": 1000000
|
||||||
|
},
|
||||||
|
"outputSelection": {
|
||||||
|
"*": {
|
||||||
|
"*": [
|
||||||
|
"abi",
|
||||||
|
"evm.bytecode.object",
|
||||||
|
"evm.bytecode.sourceMap",
|
||||||
|
"evm.deployedBytecode.object",
|
||||||
|
"evm.deployedBytecode.sourceMap"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"contracts": [
|
||||||
|
"IAssetData",
|
||||||
|
"IAssetProxy",
|
||||||
|
"IAuthorizable",
|
||||||
|
"IAssetProxyDispatcher",
|
||||||
|
"IExchange",
|
||||||
|
"IExchangeCore",
|
||||||
|
"IMatchOrders",
|
||||||
|
"ISignatureValidator",
|
||||||
|
"ITransactions",
|
||||||
|
"IValidator",
|
||||||
|
"IWallet",
|
||||||
|
"IWrapperFunctions"
|
||||||
|
]
|
||||||
|
}
|
@@ -17,7 +17,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// solhint-disable
|
// solhint-disable
|
||||||
pragma solidity 0.4.24;
|
pragma solidity ^0.4.24;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
|
||||||
// @dev Interface of the asset proxy's assetData.
|
// @dev Interface of the asset proxy's assetData.
|
||||||
@@ -26,15 +27,18 @@ pragma solidity 0.4.24;
|
|||||||
interface IAssetData {
|
interface IAssetData {
|
||||||
|
|
||||||
function ERC20Token(address tokenContract)
|
function ERC20Token(address tokenContract)
|
||||||
external
|
external;
|
||||||
pure;
|
|
||||||
|
|
||||||
function ERC721Token(
|
function ERC721Token(
|
||||||
address tokenContract,
|
address tokenContract,
|
||||||
uint256 tokenId,
|
uint256 tokenId
|
||||||
bytes receiverData
|
|
||||||
)
|
)
|
||||||
external
|
external;
|
||||||
pure;
|
|
||||||
|
function MultiAsset(
|
||||||
|
uint256[] amounts,
|
||||||
|
bytes[] nestedAssetData
|
||||||
|
)
|
||||||
|
external;
|
||||||
|
|
||||||
}
|
}
|
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pragma solidity 0.4.24;
|
pragma solidity ^0.4.24;
|
||||||
|
|
||||||
import "./IAuthorizable.sol";
|
import "./IAuthorizable.sol";
|
||||||
|
|
@@ -16,9 +16,9 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pragma solidity 0.4.24;
|
pragma solidity ^0.4.24;
|
||||||
|
|
||||||
import "../../../utils/Ownable/IOwnable.sol";
|
import "@0x/contracts-utils/contracts/utils/Ownable/IOwnable.sol";
|
||||||
|
|
||||||
|
|
||||||
contract IAuthorizable is
|
contract IAuthorizable is
|
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pragma solidity 0.4.24;
|
pragma solidity ^0.4.24;
|
||||||
|
|
||||||
|
|
||||||
contract IAssetProxyDispatcher {
|
contract IAssetProxyDispatcher {
|
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pragma solidity 0.4.24;
|
pragma solidity ^0.4.24;
|
||||||
pragma experimental ABIEncoderV2;
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
import "./IExchangeCore.sol";
|
import "./IExchangeCore.sol";
|
@@ -16,11 +16,11 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pragma solidity 0.4.24;
|
pragma solidity ^0.4.24;
|
||||||
pragma experimental ABIEncoderV2;
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
import "../libs/LibOrder.sol";
|
import "@0x/contracts-libs/contracts/libs/LibOrder.sol";
|
||||||
import "../libs/LibFillResults.sol";
|
import "@0x/contracts-libs/contracts/libs/LibFillResults.sol";
|
||||||
|
|
||||||
|
|
||||||
contract IExchangeCore {
|
contract IExchangeCore {
|
@@ -15,11 +15,11 @@
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
pragma solidity 0.4.24;
|
pragma solidity ^0.4.24;
|
||||||
pragma experimental ABIEncoderV2;
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
import "../libs/LibOrder.sol";
|
import "@0x/contracts-libs/contracts/libs/LibOrder.sol";
|
||||||
import "../libs/LibFillResults.sol";
|
import "@0x/contracts-libs/contracts/libs/LibFillResults.sol";
|
||||||
|
|
||||||
|
|
||||||
contract IMatchOrders {
|
contract IMatchOrders {
|
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pragma solidity 0.4.24;
|
pragma solidity ^0.4.24;
|
||||||
|
|
||||||
|
|
||||||
contract ISignatureValidator {
|
contract ISignatureValidator {
|
@@ -15,7 +15,7 @@
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
pragma solidity 0.4.24;
|
pragma solidity ^0.4.24;
|
||||||
|
|
||||||
|
|
||||||
contract ITransactions {
|
contract ITransactions {
|
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pragma solidity 0.4.24;
|
pragma solidity ^0.4.24;
|
||||||
|
|
||||||
|
|
||||||
contract IValidator {
|
contract IValidator {
|
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pragma solidity 0.4.24;
|
pragma solidity ^0.4.24;
|
||||||
|
|
||||||
|
|
||||||
contract IWallet {
|
contract IWallet {
|
@@ -16,11 +16,11 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pragma solidity 0.4.24;
|
pragma solidity ^0.4.24;
|
||||||
pragma experimental ABIEncoderV2;
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
import "../libs/LibOrder.sol";
|
import "@0x/contracts-libs/contracts/libs/LibOrder.sol";
|
||||||
import "../libs/LibFillResults.sol";
|
import "@0x/contracts-libs/contracts/libs/LibFillResults.sol";
|
||||||
|
|
||||||
|
|
||||||
contract IWrapperFunctions {
|
contract IWrapperFunctions {
|
57
contracts/interfaces/package.json
Normal file
57
contracts/interfaces/package.json
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
{
|
||||||
|
"name": "@0x/contracts-interfaces",
|
||||||
|
"version": "1.0.2",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.12"
|
||||||
|
},
|
||||||
|
"description": "Smart contract interfaces of 0x protocol",
|
||||||
|
"main": "lib/src/index.js",
|
||||||
|
"scripts": {
|
||||||
|
"build": "yarn pre_build && tsc -b",
|
||||||
|
"build:ci": "yarn build",
|
||||||
|
"pre_build": "run-s compile generate_contract_wrappers",
|
||||||
|
"compile": "sol-compiler",
|
||||||
|
"watch": "sol-compiler -w",
|
||||||
|
"clean": "shx rm -rf lib generated-artifacts generated-wrappers",
|
||||||
|
"generate_contract_wrappers": "abi-gen --abis ${npm_package_config_abis} --template ../../node_modules/@0x/abi-gen-templates/contract.handlebars --partials '../../node_modules/@0x/abi-gen-templates/partials/**/*.handlebars' --output generated-wrappers --backend ethers",
|
||||||
|
"lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
|
||||||
|
"lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol"
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"abis": "generated-artifacts/@(IAssetData|IAssetProxy|IAuthorizable|IAssetProxyDispatcher|IExchange|IExchangeCore|IMatchOrders|ISignatureValidator|ITransactions|IValidator|IWallet|IWrapperFunctions).json"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/0xProject/0x-monorepo.git"
|
||||||
|
},
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/0xProject/0x-monorepo/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/interfaces/README.md",
|
||||||
|
"devDependencies": {
|
||||||
|
"@0x/abi-gen": "^1.0.19",
|
||||||
|
"@0x/sol-compiler": "^1.1.16",
|
||||||
|
"@0x/tslint-config": "^2.0.0",
|
||||||
|
"npm-run-all": "^4.1.2",
|
||||||
|
"shx": "^0.2.2",
|
||||||
|
"solhint": "^1.4.1",
|
||||||
|
"tslint": "5.11.0",
|
||||||
|
"typescript": "3.0.1",
|
||||||
|
"yargs": "^10.0.3"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@0x/base-contract": "^3.0.10",
|
||||||
|
"@0x/contracts-libs": "^1.0.2",
|
||||||
|
"@0x/contracts-utils": "^1.0.2",
|
||||||
|
"@0x/types": "^1.4.1",
|
||||||
|
"@0x/typescript-typings": "^3.0.6",
|
||||||
|
"@0x/utils": "^2.0.8",
|
||||||
|
"@0x/web3-wrapper": "^3.2.1",
|
||||||
|
"ethereum-types": "^1.1.4",
|
||||||
|
"lodash": "^4.17.5"
|
||||||
|
},
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "public"
|
||||||
|
}
|
||||||
|
}
|
29
contracts/interfaces/src/artifacts/index.ts
Normal file
29
contracts/interfaces/src/artifacts/index.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import { ContractArtifact } from 'ethereum-types';
|
||||||
|
|
||||||
|
import * as IAssetData from '../../generated-artifacts/IAssetData.json';
|
||||||
|
import * as IAssetProxy from '../../generated-artifacts/IAssetProxy.json';
|
||||||
|
import * as IAssetProxyDispatcher from '../../generated-artifacts/IAssetProxyDispatcher.json';
|
||||||
|
import * as IAuthorizable from '../../generated-artifacts/IAuthorizable.json';
|
||||||
|
import * as IExchange from '../../generated-artifacts/IExchange.json';
|
||||||
|
import * as IExchangeCore from '../../generated-artifacts/IExchangeCore.json';
|
||||||
|
import * as IMatchOrders from '../../generated-artifacts/IMatchOrders.json';
|
||||||
|
import * as ISignatureValidator from '../../generated-artifacts/ISignatureValidator.json';
|
||||||
|
import * as ITransactions from '../../generated-artifacts/ITransactions.json';
|
||||||
|
import * as IValidator from '../../generated-artifacts/IValidator.json';
|
||||||
|
import * as IWallet from '../../generated-artifacts/IWallet.json';
|
||||||
|
import * as IWrapperFunctions from '../../generated-artifacts/IWrapperFunctions.json';
|
||||||
|
|
||||||
|
export const artifacts = {
|
||||||
|
IAssetProxyDispatcher: IAssetProxyDispatcher as ContractArtifact,
|
||||||
|
IAuthorizable: IAuthorizable as ContractArtifact,
|
||||||
|
IExchange: IExchange as ContractArtifact,
|
||||||
|
IExchangeCore: IExchangeCore as ContractArtifact,
|
||||||
|
IMatchOrders: IMatchOrders as ContractArtifact,
|
||||||
|
ISignatureValidator: ISignatureValidator as ContractArtifact,
|
||||||
|
ITransactions: ITransactions as ContractArtifact,
|
||||||
|
IWrapperFunctions: IWrapperFunctions as ContractArtifact,
|
||||||
|
IAssetData: IAssetData as ContractArtifact,
|
||||||
|
IAssetProxy: IAssetProxy as ContractArtifact,
|
||||||
|
IValidator: IValidator as ContractArtifact,
|
||||||
|
IWallet: IWallet as ContractArtifact,
|
||||||
|
};
|
2
contracts/interfaces/src/index.ts
Normal file
2
contracts/interfaces/src/index.ts
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
export * from './artifacts';
|
||||||
|
export * from './wrappers';
|
12
contracts/interfaces/src/wrappers/index.ts
Normal file
12
contracts/interfaces/src/wrappers/index.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
export * from '../../generated-wrappers/i_asset_data';
|
||||||
|
export * from '../../generated-wrappers/i_asset_proxy';
|
||||||
|
export * from '../../generated-wrappers/i_asset_proxy_dispatcher';
|
||||||
|
export * from '../../generated-wrappers/i_exchange';
|
||||||
|
export * from '../../generated-wrappers/i_exchange_core';
|
||||||
|
export * from '../../generated-wrappers/i_match_orders';
|
||||||
|
export * from '../../generated-wrappers/i_signature_validator';
|
||||||
|
export * from '../../generated-wrappers/i_transactions';
|
||||||
|
export * from '../../generated-wrappers/i_authorizable';
|
||||||
|
export * from '../../generated-wrappers/i_wrapper_functions';
|
||||||
|
export * from '../../generated-wrappers/i_validator';
|
||||||
|
export * from '../../generated-wrappers/i_wallet';
|
24
contracts/interfaces/tsconfig.json
Normal file
24
contracts/interfaces/tsconfig.json
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../tsconfig",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "lib",
|
||||||
|
"rootDir": ".",
|
||||||
|
"resolveJsonModule": true
|
||||||
|
},
|
||||||
|
"include": ["./src/**/*", "./generated-wrappers/**/*"],
|
||||||
|
"files": [
|
||||||
|
"./generated-artifacts/IAssetData.json",
|
||||||
|
"./generated-artifacts/IAssetProxy.json",
|
||||||
|
"./generated-artifacts/IAuthorizable.json",
|
||||||
|
"./generated-artifacts/IAssetProxyDispatcher.json",
|
||||||
|
"./generated-artifacts/IExchange.json",
|
||||||
|
"./generated-artifacts/IExchangeCore.json",
|
||||||
|
"./generated-artifacts/IMatchOrders.json",
|
||||||
|
"./generated-artifacts/ISignatureValidator.json",
|
||||||
|
"./generated-artifacts/ITransactions.json",
|
||||||
|
"./generated-artifacts/IValidator.json",
|
||||||
|
"./generated-artifacts/IWallet.json",
|
||||||
|
"./generated-artifacts/IWrapperFunctions.json"
|
||||||
|
],
|
||||||
|
"exclude": ["./deploy/solc/solc_bin"]
|
||||||
|
}
|
6
contracts/interfaces/tslint.json
Normal file
6
contracts/interfaces/tslint.json
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"extends": ["@0x/tslint-config"],
|
||||||
|
"rules": {
|
||||||
|
"custom-no-magic-numbers": false
|
||||||
|
}
|
||||||
|
}
|
11
contracts/libs/CHANGELOG.json
Normal file
11
contracts/libs/CHANGELOG.json
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"timestamp": 1544741676,
|
||||||
|
"version": "1.0.2",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
10
contracts/libs/CHANGELOG.md
Normal file
10
contracts/libs/CHANGELOG.md
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<!--
|
||||||
|
changelogUtils.file is auto-generated using the monorepo-scripts package. Don't edit directly.
|
||||||
|
Edit the package's CHANGELOG.json file only.
|
||||||
|
-->
|
||||||
|
|
||||||
|
CHANGELOG
|
||||||
|
|
||||||
|
## v1.0.2 - _December 13, 2018_
|
||||||
|
|
||||||
|
* Dependencies updated
|
70
contracts/libs/README.md
Normal file
70
contracts/libs/README.md
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
## Contracts libs
|
||||||
|
|
||||||
|
Smart contracts libs used in the 0x protocol.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Contracts can be found in the [contracts](./contracts) directory. The contents of this directory are broken down into the following subdirectories:
|
||||||
|
|
||||||
|
* [libs](./contracts/protocol)
|
||||||
|
* This directory contains the libs.
|
||||||
|
* [test](./contracts/test)
|
||||||
|
* This directory contains mocks and other contracts that are used solely for testing contracts within the other directories.
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
We strongly recommend that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository.
|
||||||
|
|
||||||
|
For proposals regarding the 0x protocol's smart contract architecture, message format, or additional functionality, go to the [0x Improvement Proposals (ZEIPs)](https://github.com/0xProject/ZEIPs) repository and follow the contribution guidelines provided therein.
|
||||||
|
|
||||||
|
Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started.
|
||||||
|
|
||||||
|
### Install Dependencies
|
||||||
|
|
||||||
|
If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yarn config set workspaces-experimental true
|
||||||
|
```
|
||||||
|
|
||||||
|
Then install dependencies
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yarn install
|
||||||
|
```
|
||||||
|
|
||||||
|
### Build
|
||||||
|
|
||||||
|
To build this package and all other monorepo packages that it depends on, run the following from the monorepo root directory:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
PKG=@0x/contracts-libs yarn build
|
||||||
|
```
|
||||||
|
|
||||||
|
Or continuously rebuild on change:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
PKG=@0x/contracts-libs yarn watch
|
||||||
|
```
|
||||||
|
|
||||||
|
### Clean
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yarn clean
|
||||||
|
```
|
||||||
|
|
||||||
|
### Lint
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yarn lint
|
||||||
|
```
|
||||||
|
|
||||||
|
### Run Tests
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yarn test
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Testing options
|
||||||
|
|
||||||
|
Contracts testing options like coverage, profiling, revert traces or backing node choosing - are described [here](../TESTING.md).
|
31
contracts/libs/compiler.json
Normal file
31
contracts/libs/compiler.json
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"artifactsDir": "./generated-artifacts",
|
||||||
|
"contractsDir": "./contracts",
|
||||||
|
"compilerSettings": {
|
||||||
|
"optimizer": {
|
||||||
|
"enabled": true,
|
||||||
|
"runs": 1000000
|
||||||
|
},
|
||||||
|
"outputSelection": {
|
||||||
|
"*": {
|
||||||
|
"*": [
|
||||||
|
"abi",
|
||||||
|
"evm.bytecode.object",
|
||||||
|
"evm.bytecode.sourceMap",
|
||||||
|
"evm.deployedBytecode.object",
|
||||||
|
"evm.deployedBytecode.sourceMap"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"contracts": [
|
||||||
|
"TestLibs",
|
||||||
|
"LibOrder",
|
||||||
|
"LibMath",
|
||||||
|
"LibFillResults",
|
||||||
|
"LibAbiEncoder",
|
||||||
|
"LibEIP712",
|
||||||
|
"LibAssetProxyErrors",
|
||||||
|
"LibConstants"
|
||||||
|
]
|
||||||
|
}
|
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pragma solidity 0.4.24;
|
pragma solidity ^0.4.24;
|
||||||
pragma experimental ABIEncoderV2;
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
import "./LibOrder.sol";
|
import "./LibOrder.sol";
|
84
contracts/libs/contracts/libs/LibAddressArray.sol
Normal file
84
contracts/libs/contracts/libs/LibAddressArray.sol
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright 2018 ZeroEx Intl.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
pragma solidity ^0.4.24;
|
||||||
|
|
||||||
|
import "@0x/contracts-utils/contracts/utils/LibBytes/LibBytes.sol";
|
||||||
|
|
||||||
|
|
||||||
|
library LibAddressArray {
|
||||||
|
|
||||||
|
/// @dev Append a new address to an array of addresses.
|
||||||
|
/// The `addressArray` may need to be reallocated to make space
|
||||||
|
/// for the new address. Because of this we return the resulting
|
||||||
|
/// memory location of `addressArray`.
|
||||||
|
/// @param addressToAppend Address to append.
|
||||||
|
/// @return Array of addresses: [... addressArray, addressToAppend]
|
||||||
|
function append(address[] memory addressArray, address addressToAppend)
|
||||||
|
internal pure
|
||||||
|
returns (address[])
|
||||||
|
{
|
||||||
|
// Get stats on address array and free memory
|
||||||
|
uint256 freeMemPtr = 0;
|
||||||
|
uint256 addressArrayBeginPtr = 0;
|
||||||
|
uint256 addressArrayEndPtr = 0;
|
||||||
|
uint256 addressArrayLength = addressArray.length;
|
||||||
|
uint256 addressArrayMemSizeInBytes = 32 + (32 * addressArrayLength);
|
||||||
|
assembly {
|
||||||
|
freeMemPtr := mload(0x40)
|
||||||
|
addressArrayBeginPtr := addressArray
|
||||||
|
addressArrayEndPtr := add(addressArray, addressArrayMemSizeInBytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cases for `freeMemPtr`:
|
||||||
|
// `freeMemPtr` == `addressArrayEndPtr`: Nothing occupies memory after `addressArray`
|
||||||
|
// `freeMemPtr` > `addressArrayEndPtr`: Some value occupies memory after `addressArray`
|
||||||
|
// `freeMemPtr` < `addressArrayEndPtr`: Memory has not been managed properly.
|
||||||
|
require(
|
||||||
|
freeMemPtr >= addressArrayEndPtr,
|
||||||
|
"INVALID_FREE_MEMORY_PTR"
|
||||||
|
);
|
||||||
|
|
||||||
|
// If free memory begins at the end of `addressArray`
|
||||||
|
// then we can append `addressToAppend` directly.
|
||||||
|
// Otherwise, we must copy the array to free memory
|
||||||
|
// before appending new values to it.
|
||||||
|
if (freeMemPtr > addressArrayEndPtr) {
|
||||||
|
LibBytes.memCopy(freeMemPtr, addressArrayBeginPtr, addressArrayMemSizeInBytes);
|
||||||
|
assembly {
|
||||||
|
addressArray := freeMemPtr
|
||||||
|
addressArrayBeginPtr := addressArray
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append `addressToAppend`
|
||||||
|
addressArrayLength += 1;
|
||||||
|
addressArrayMemSizeInBytes += 32;
|
||||||
|
addressArrayEndPtr = addressArrayBeginPtr + addressArrayMemSizeInBytes;
|
||||||
|
freeMemPtr = addressArrayEndPtr;
|
||||||
|
assembly {
|
||||||
|
// Store new array length
|
||||||
|
mstore(addressArray, addressArrayLength)
|
||||||
|
|
||||||
|
// Update `freeMemPtr`
|
||||||
|
mstore(0x40, freeMemPtr)
|
||||||
|
}
|
||||||
|
addressArray[addressArrayLength - 1] = addressToAppend;
|
||||||
|
return addressArray;
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user