Compare commits
1742 Commits
@0x/sol-do
...
@0x/contra
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c03a014740 | ||
|
|
84e6d788aa | ||
|
|
cd296b8767 | ||
|
|
5946d32a7d | ||
|
|
842dd8572b | ||
|
|
33e260f9db | ||
|
|
c44f8d0060 | ||
|
|
411548a33e | ||
|
|
9a17ce1383 | ||
|
|
2b120d0669 | ||
|
|
6d877d5242 | ||
|
|
e4abd690e7 | ||
|
|
2a194384b6 | ||
|
|
1e069e6f8a | ||
|
|
a019bb913d | ||
|
|
9ce73931f7 | ||
|
|
97020df178 | ||
|
|
dfb7b3de8f | ||
|
|
9e152912fe | ||
|
|
b2c2f1e1aa | ||
|
|
629c7d8e92 | ||
|
|
62f24d4356 | ||
|
|
ae281c33ca | ||
|
|
5d034dd106 | ||
|
|
c1f8df0eca | ||
|
|
76dda9eeda | ||
|
|
a9b84a92ac | ||
|
|
0f7e881899 | ||
|
|
6045f777ab | ||
|
|
5a15044ead | ||
|
|
a69d76e487 | ||
|
|
3adfcdffa8 | ||
|
|
164a5d44d9 | ||
|
|
70ddab0231 | ||
|
|
7bf009fbf6 | ||
|
|
525bc8197b | ||
|
|
24397c51a8 | ||
|
|
06b3464756 | ||
|
|
bbaa90bd9a | ||
|
|
5c683cbc0f | ||
|
|
95345f18bc | ||
|
|
4c3fbe83ac | ||
|
|
7caa43d02c | ||
|
|
3d4c03c9df | ||
|
|
22e1ed35d3 | ||
|
|
dabe6fd793 | ||
|
|
3cc639c8d0 | ||
|
|
22c8e0b6db | ||
|
|
f3ca4293bc | ||
|
|
db3e076d03 | ||
|
|
1a6759820a | ||
|
|
61c5e7b948 | ||
|
|
5fd78ef32f | ||
|
|
14ff9b827c | ||
|
|
598dc2cd71 | ||
|
|
08e1c5109f | ||
|
|
6f7a843742 | ||
|
|
c9c9615bb5 | ||
|
|
f98609686d | ||
|
|
5b8bbc34e8 | ||
|
|
49cb00a9ab | ||
|
|
74b240fb88 | ||
|
|
514f9d2621 | ||
|
|
fa78d1092a | ||
|
|
297342092b | ||
|
|
076f263a86 | ||
|
|
0c56207abc | ||
|
|
23953d8a5a | ||
|
|
c6919eb25a | ||
|
|
d509604b52 | ||
|
|
a74a3450eb | ||
|
|
72c5399b9d | ||
|
|
b29196b983 | ||
|
|
ce76a7033d | ||
|
|
3f4bb933d1 | ||
|
|
501b7b9b65 | ||
|
|
c0ea88e864 | ||
|
|
48f8bea460 | ||
|
|
f4e5b6e38d | ||
|
|
477cb0a48d | ||
|
|
d6bc0a3368 | ||
|
|
e544a804c2 | ||
|
|
96e0ad7899 | ||
|
|
5a1fee5d31 | ||
|
|
3557a5e5a9 | ||
|
|
0bd43d5265 | ||
|
|
8fd7c1b386 | ||
|
|
50068750f5 | ||
|
|
a7a905de4c | ||
|
|
f283108586 | ||
|
|
9afe05095a | ||
|
|
3dab892978 | ||
|
|
e40ddb800e | ||
|
|
72a74e7c66 | ||
|
|
e8ae64673f | ||
|
|
2451f419c8 | ||
|
|
2394eb62aa | ||
|
|
f9078bb1c3 | ||
|
|
bf25c81f1c | ||
|
|
03ecc530c3 | ||
|
|
d52b1d24d0 | ||
|
|
5083fab06a | ||
|
|
1249bf9ccc | ||
|
|
681f6b3f07 | ||
|
|
d3ca1fe96b | ||
|
|
9e4f5815e4 | ||
|
|
c3c27eaedc | ||
|
|
4bf6a23d23 | ||
|
|
aaaf0d02de | ||
|
|
825cc4d035 | ||
|
|
c2d44e5c10 | ||
|
|
0efd0860c8 | ||
|
|
a890a06664 | ||
|
|
5befb87071 | ||
|
|
12ba4c373a | ||
|
|
7fd25be02e | ||
|
|
aa688c4a92 | ||
|
|
fb437551c9 | ||
|
|
6fa1de7889 | ||
|
|
7a42df9a65 | ||
|
|
15a508f3ea | ||
|
|
b3c20ff909 | ||
|
|
682c07cb73 | ||
|
|
602605ab4b | ||
|
|
0eff2548d5 | ||
|
|
93ee681204 | ||
|
|
d7bea98075 | ||
|
|
437a3b048d | ||
|
|
f55a9454b5 | ||
|
|
3b03ad0db4 | ||
|
|
27d679e1f1 | ||
|
|
1e16d59c23 | ||
|
|
1e7c9bbb1f | ||
|
|
edda1edc50 | ||
|
|
d1eb6279b4 | ||
|
|
4ace79d947 | ||
|
|
e5eee96487 | ||
|
|
907adf9145 | ||
|
|
c046fe6220 | ||
|
|
84bf20de41 | ||
|
|
f5a6f74d9a | ||
|
|
7c7fc51ccf | ||
|
|
fa22f6de0d | ||
|
|
4f41214af2 | ||
|
|
607b7169bc | ||
|
|
1253490a38 | ||
|
|
0a37a588e8 | ||
|
|
23ee108089 | ||
|
|
64feeeea75 | ||
|
|
2ebef23b8c | ||
|
|
cc9f43ba3b | ||
|
|
5f1c139176 | ||
|
|
9eea7de340 | ||
|
|
4480f84efa | ||
|
|
5a8b8afff1 | ||
|
|
67c95bc0b7 | ||
|
|
e70ec02be8 | ||
|
|
db81a94adb | ||
|
|
475b608338 | ||
|
|
27e36b112e | ||
|
|
f698721484 | ||
|
|
0c08353b2c | ||
|
|
a074b49732 | ||
|
|
43b75c7953 | ||
|
|
84a78eafc4 | ||
|
|
3c1ab889dd | ||
|
|
012fff46f6 | ||
|
|
6307ebc3a2 | ||
|
|
88d7e73eba | ||
|
|
9653eb9e70 | ||
|
|
ad337271d3 | ||
|
|
7591e99316 | ||
|
|
ca20df4752 | ||
|
|
841e4ee666 | ||
|
|
e2ee3414ea | ||
|
|
5306cc03e9 | ||
|
|
85f5d32de2 | ||
|
|
ab698cec14 | ||
|
|
b463a39bfa | ||
|
|
018e25345b | ||
|
|
b60fa8a7d7 | ||
|
|
048d8dee60 | ||
|
|
927fe2b58b | ||
|
|
89948b360c | ||
|
|
561b60a24d | ||
|
|
4f82543bdf | ||
|
|
3133c509f9 | ||
|
|
426c15692d | ||
|
|
8c87a77faa | ||
|
|
d2018f07a2 | ||
|
|
d2e57d8163 | ||
|
|
7403c0255a | ||
|
|
75dcd687e2 | ||
|
|
afd4805421 | ||
|
|
6aa582d140 | ||
|
|
534d92fa00 | ||
|
|
37aae134ab | ||
|
|
36bd8f68c9 | ||
|
|
c3ad42221e | ||
|
|
602ac1f626 | ||
|
|
3126795efe | ||
|
|
dbcb221a59 | ||
|
|
6bbc179f52 | ||
|
|
48e7a391c8 | ||
|
|
2334e64d0c | ||
|
|
14f920ee84 | ||
|
|
e10a81023a | ||
|
|
f4709ed1cb | ||
|
|
e2e14a977a | ||
|
|
866f958a10 | ||
|
|
717db99b38 | ||
|
|
02006118c7 | ||
|
|
9816019bc5 | ||
|
|
9c821dbfc3 | ||
|
|
af1b890423 | ||
|
|
673835d2de | ||
|
|
500b57e935 | ||
|
|
3f7d0580c1 | ||
|
|
a71c356bba | ||
|
|
c3a95b7fb1 | ||
|
|
f01540fb35 | ||
|
|
689a8881c2 | ||
|
|
99f5be8378 | ||
|
|
8de0282d92 | ||
|
|
f99804d56a | ||
|
|
f13d27b749 | ||
|
|
465fd59cbc | ||
|
|
5fdabe6612 | ||
|
|
861871134b | ||
|
|
c246d98093 | ||
|
|
02076dba1b | ||
|
|
7b136a5ad8 | ||
|
|
0c4a67fa35 | ||
|
|
668aeb77f7 | ||
|
|
135ae392d5 | ||
|
|
88ba04307c | ||
|
|
e4b8000a48 | ||
|
|
b9df108314 | ||
|
|
6106185bf6 | ||
|
|
3a3e289864 | ||
|
|
6558632f10 | ||
|
|
376ee6bdff | ||
|
|
fc5d759131 | ||
|
|
7c16bb3df8 | ||
|
|
5df74d35d0 | ||
|
|
72fc0c845a | ||
|
|
b995715a2c | ||
|
|
857b5c97b0 | ||
|
|
178d9c280a | ||
|
|
2416deba25 | ||
|
|
0ce6243653 | ||
|
|
40dc10729b | ||
|
|
0571244e9e | ||
|
|
3213131cad | ||
|
|
61bf93aac2 | ||
|
|
a9d0cec6d1 | ||
|
|
b5e3f0b90c | ||
|
|
61f1fe42b0 | ||
|
|
1cfdc49021 | ||
|
|
c4d58277cf | ||
|
|
9ac66c2130 | ||
|
|
6366163006 | ||
|
|
85fde8f9a5 | ||
|
|
a03d0800b0 | ||
|
|
9cb21006a7 | ||
|
|
649202f1c4 | ||
|
|
b798556774 | ||
|
|
03bc15fbdf | ||
|
|
b2dfd8740c | ||
|
|
3182c12b4d | ||
|
|
f783625d60 | ||
|
|
891aa8e8bf | ||
|
|
4b508d255d | ||
|
|
1cad43bf5d | ||
|
|
a0cd727832 | ||
|
|
ab90e15015 | ||
|
|
52cbddf054 | ||
|
|
db98ff8cb7 | ||
|
|
1d8dd2f89c | ||
|
|
0ae1c926d3 | ||
|
|
1fcab58e2f | ||
|
|
a8cbd1a16c | ||
|
|
3aaa0ad6b2 | ||
|
|
e34bc77157 | ||
|
|
088b331f19 | ||
|
|
56f2dec441 | ||
|
|
ac8b08d3cf | ||
|
|
c4ead689a9 | ||
|
|
07ab10b000 | ||
|
|
c969a8652a | ||
|
|
fb21ca5404 | ||
|
|
bbfa9c34ab | ||
|
|
7161bbe836 | ||
|
|
ef65aa5bf6 | ||
|
|
2cf31f05a1 | ||
|
|
2b1a1ba0db | ||
|
|
05b25c6229 | ||
|
|
2db52c6983 | ||
|
|
4803e2f68c | ||
|
|
7030572f1d | ||
|
|
6e2eb9c5bb | ||
|
|
eb27e260e0 | ||
|
|
c72aa653e8 | ||
|
|
4d04b72674 | ||
|
|
e3b92d2c8b | ||
|
|
4aa5a89cd7 | ||
|
|
c6b9ea5723 | ||
|
|
2dc0bff1ea | ||
|
|
408e66e8b4 | ||
|
|
40fe12a86b | ||
|
|
1adb56f092 | ||
|
|
629d48c766 | ||
|
|
c8886febb9 | ||
|
|
efe598c8fd | ||
|
|
32218ce25e | ||
|
|
f7ae697475 | ||
|
|
6e954385ce | ||
|
|
f8df89b506 | ||
|
|
a3ff406461 | ||
|
|
221de054f4 | ||
|
|
98e6aa4bac | ||
|
|
199808dc44 | ||
|
|
5d8e35fb68 | ||
|
|
36546480b1 | ||
|
|
cd9e408ea3 | ||
|
|
7698f21517 | ||
|
|
10724e5745 | ||
|
|
dde76a4dbb | ||
|
|
86ff5c53bb | ||
|
|
efef5f122f | ||
|
|
83c942ad8c | ||
|
|
31e90e314c | ||
|
|
33caae705e | ||
|
|
961273a2ff | ||
|
|
46e512a27c | ||
|
|
290a04a0ad | ||
|
|
12ff4ec438 | ||
|
|
1c15ecacb0 | ||
|
|
c6d738ed0c | ||
|
|
f089f5d87f | ||
|
|
78e3cd39d1 | ||
|
|
1588c1f362 | ||
|
|
a35d1b8a9d | ||
|
|
32923ec7e1 | ||
|
|
5a3bd716ad | ||
|
|
84862f15c1 | ||
|
|
9e42dce5c4 | ||
|
|
a360109013 | ||
|
|
68d6b3a033 | ||
|
|
733c3046bc | ||
|
|
23d4b6bf1c | ||
|
|
39bd0c5459 | ||
|
|
c13ffb2072 | ||
|
|
38bcab1f86 | ||
|
|
a24f01c90f | ||
|
|
708e34602b | ||
|
|
d60c8ddd5a | ||
|
|
eea63292f0 | ||
|
|
a97342a594 | ||
|
|
00f55be83e | ||
|
|
90ed283b20 | ||
|
|
61272961a8 | ||
|
|
507690f9db | ||
|
|
90ad5eb6c4 | ||
|
|
7bc9701c81 | ||
|
|
a7d502a501 | ||
|
|
fbe99b41f8 | ||
|
|
66e2d93e9c | ||
|
|
4672c72fef | ||
|
|
ac6b03cd4a | ||
|
|
d7de191947 | ||
|
|
de7f1fc207 | ||
|
|
99de5a3814 | ||
|
|
4cf566cad8 | ||
|
|
6138955f93 | ||
|
|
a57cf68ee4 | ||
|
|
20edcd1ae5 | ||
|
|
5333befd89 | ||
|
|
235e406620 | ||
|
|
5f570b772d | ||
|
|
f2507cb94a | ||
|
|
f84b375cde | ||
|
|
32d11d1ba5 | ||
|
|
5c9b6eb078 | ||
|
|
f53a512e70 | ||
|
|
ec08715090 | ||
|
|
79e0a9ef37 | ||
|
|
1ce8a33937 | ||
|
|
b3053dfb91 | ||
|
|
3da05f2812 | ||
|
|
0ba79b060d | ||
|
|
c4bcc26e29 | ||
|
|
630108ccb6 | ||
|
|
1ab33aa132 | ||
|
|
ee456ea6e7 | ||
|
|
e7541ac2af | ||
|
|
d34d46b7fd | ||
|
|
08ae43aad3 | ||
|
|
eb141075c7 | ||
|
|
bd3387a408 | ||
|
|
e1a48e80e1 | ||
|
|
bf899d40a0 | ||
|
|
dc66f1b886 | ||
|
|
3753b1a7d0 | ||
|
|
05c5acdb15 | ||
|
|
ca63bcc9b0 | ||
|
|
3733d503db | ||
|
|
ab28e42c22 | ||
|
|
7e53b4f834 | ||
|
|
3bb60fee19 | ||
|
|
9f7840e12b | ||
|
|
f41e13b574 | ||
|
|
4049143630 | ||
|
|
705f46717f | ||
|
|
a6cf8ae0b6 | ||
|
|
dba6972281 | ||
|
|
52d36f5a8b | ||
|
|
889b58a914 | ||
|
|
43810835d7 | ||
|
|
4b9867f167 | ||
|
|
e9c91e59bd | ||
|
|
d8844f6970 | ||
|
|
1cdc6e7184 | ||
|
|
36ad373f03 | ||
|
|
78dfb6d525 | ||
|
|
79254de7bc | ||
|
|
1d6aef5cd6 | ||
|
|
f9d02c9e27 | ||
|
|
228246089e | ||
|
|
b6319ba3d8 | ||
|
|
2636384ead | ||
|
|
0425f76284 | ||
|
|
d93e72f56a | ||
|
|
195d543ce3 | ||
|
|
9cda9f69cd | ||
|
|
7b0a1c3630 | ||
|
|
a8f3a47240 | ||
|
|
db0f3a8780 | ||
|
|
514db24ceb | ||
|
|
e738743c89 | ||
|
|
f471e1a8a3 | ||
|
|
a2f0d5eedf | ||
|
|
2f9b894d71 | ||
|
|
bab34c2d21 | ||
|
|
a68421b0f8 | ||
|
|
e9b0ac8820 | ||
|
|
4f78f55c2a | ||
|
|
156093127b | ||
|
|
47d91bb4e0 | ||
|
|
cc31445189 | ||
|
|
af78238507 | ||
|
|
b30f87f50c | ||
|
|
3cd03ed0f1 | ||
|
|
e7ad7c3af7 | ||
|
|
7e8b56eef4 | ||
|
|
458a014e6d | ||
|
|
9b6703398e | ||
|
|
71700e69af | ||
|
|
14d6330b40 | ||
|
|
d31d646ecc | ||
|
|
270d7a3f19 | ||
|
|
e078f3d479 | ||
|
|
6aa8f17ed5 | ||
|
|
8e73ae3614 | ||
|
|
89117beda2 | ||
|
|
e27e6baabe | ||
|
|
15ce90c0ec | ||
|
|
39e157499d | ||
|
|
d22c0641fb | ||
|
|
82806b6fcb | ||
|
|
fe293d91ee | ||
|
|
7842bb4cad | ||
|
|
6f7e156f49 | ||
|
|
0d19cac487 | ||
|
|
f30dfcc572 | ||
|
|
3df39d8cfe | ||
|
|
ece93fed78 | ||
|
|
3a2c6ae9d6 | ||
|
|
2ed71b36b6 | ||
|
|
ae9c301795 | ||
|
|
68206ffb6e | ||
|
|
25a3c18bfe | ||
|
|
d28476e9f7 | ||
|
|
7cd30610f9 | ||
|
|
ceb90989d0 | ||
|
|
bb39d63d37 | ||
|
|
213709d020 | ||
|
|
d0e9081852 | ||
|
|
71cde281b9 | ||
|
|
c03f1586e6 | ||
|
|
10aceb164d | ||
|
|
34f516a417 | ||
|
|
5dd686f22f | ||
|
|
5f47ad3363 | ||
|
|
e166e9762a | ||
|
|
341c5782e5 | ||
|
|
d5180d3ebc | ||
|
|
2c73bbd689 | ||
|
|
b10522479c | ||
|
|
2b39ae4800 | ||
|
|
788bdba8cd | ||
|
|
222fd5d822 | ||
|
|
eedfc64a8c | ||
|
|
78170b26e9 | ||
|
|
f966b6f4df | ||
|
|
053b55fbbf | ||
|
|
84a55a2d84 | ||
|
|
498a50b229 | ||
|
|
766888ec41 | ||
|
|
466d962c07 | ||
|
|
ae2a6fb685 | ||
|
|
5afe2616a4 | ||
|
|
72c869649a | ||
|
|
34138fc3b5 | ||
|
|
f67d2b96ac | ||
|
|
d877d3686c | ||
|
|
8260615b4e | ||
|
|
c3f6d48966 | ||
|
|
02f979bc74 | ||
|
|
de1c71aacc | ||
|
|
ca2aa72e0f | ||
|
|
9a16f5736e | ||
|
|
82774df715 | ||
|
|
314f53c0b3 | ||
|
|
6553ee0130 | ||
|
|
d7918ea047 | ||
|
|
4aa9c85503 | ||
|
|
f172591059 | ||
|
|
dfa7e30e42 | ||
|
|
3fe2013398 | ||
|
|
391d501ce6 | ||
|
|
9edaa3a64e | ||
|
|
6e4e313792 | ||
|
|
e6dcf92ec8 | ||
|
|
f359de2cac | ||
|
|
2d29014091 | ||
|
|
0450e430f1 | ||
|
|
b6700af6a8 | ||
|
|
bcee7546ae | ||
|
|
4dac620156 | ||
|
|
74d9df2fb0 | ||
|
|
9d1615fa23 | ||
|
|
b1b9949e72 | ||
|
|
957ef5ab77 | ||
|
|
07a681c77e | ||
|
|
145ec8ede1 | ||
|
|
5f5a158060 | ||
|
|
3e99c95791 | ||
|
|
4f83521be8 | ||
|
|
aae93bb6a7 | ||
|
|
b5eb1c9ee8 | ||
|
|
9d3755db36 | ||
|
|
762e0aec2d | ||
|
|
ff9c9241d8 | ||
|
|
5c1ffe7fc8 | ||
|
|
b1c3c60def | ||
|
|
8763713596 | ||
|
|
3e823cc9e3 | ||
|
|
1c84709db3 | ||
|
|
9150d6bd2a | ||
|
|
10f29b66b8 | ||
|
|
259aec52a9 | ||
|
|
6554bf9f08 | ||
|
|
d8558f5956 | ||
|
|
18bc701e8b | ||
|
|
a47795fd3f | ||
|
|
a55e8b268c | ||
|
|
e8106f04b5 | ||
|
|
bdc1dbf08a | ||
|
|
06eeb2088b | ||
|
|
7da9ec2c75 | ||
|
|
297ff10c14 | ||
|
|
1305f4314d | ||
|
|
55474c0599 | ||
|
|
687c79ae81 | ||
|
|
829a353b14 | ||
|
|
aced474dc5 | ||
|
|
7c08d5f198 | ||
|
|
c546787994 | ||
|
|
31fa530845 | ||
|
|
120714ecfc | ||
|
|
615874d2ec | ||
|
|
67b195c942 | ||
|
|
75689cee96 | ||
|
|
8ba77e95a4 | ||
|
|
7967a8416c | ||
|
|
934fbca860 | ||
|
|
e78c8038c7 | ||
|
|
f64a42ebb5 | ||
|
|
9164cff234 | ||
|
|
017f98e87e | ||
|
|
f33d8670aa | ||
|
|
e79db7de89 | ||
|
|
845a42e73a | ||
|
|
e58c25aa18 | ||
|
|
8ec44b63b1 | ||
|
|
41907936a1 | ||
|
|
406d2cefc5 | ||
|
|
41cdbc0ec4 | ||
|
|
c6ec261c5c | ||
|
|
a2db1a3275 | ||
|
|
1e8f2f0e83 | ||
|
|
8491abe142 | ||
|
|
d4302538bf | ||
|
|
c34e3765ef | ||
|
|
1f86bc06ef | ||
|
|
7e892fac2d | ||
|
|
23789b0692 | ||
|
|
89adbe4127 | ||
|
|
11940fb98e | ||
|
|
13ae335811 | ||
|
|
b2dc6ad2fa | ||
|
|
85ca926fd0 | ||
|
|
676698a59b | ||
|
|
22408ecd58 | ||
|
|
d36acc7ec7 | ||
|
|
a5a68acfec | ||
|
|
7431651666 | ||
|
|
4f91bfd907 | ||
|
|
8d2086870b | ||
|
|
1511ef1a98 | ||
|
|
4e030ce1e8 | ||
|
|
2507ad274b | ||
|
|
fb1c149eb9 | ||
|
|
d4662f428a | ||
|
|
73c779c13a | ||
|
|
b8cc164af1 | ||
|
|
64a391b5f8 | ||
|
|
21a202dd16 | ||
|
|
187dd2fdc3 | ||
|
|
c18f3f0b33 | ||
|
|
7162935028 | ||
|
|
9215a73b6c | ||
|
|
edd840794c | ||
|
|
c30a6eb1aa | ||
|
|
233642af29 | ||
|
|
7dffd0a03e | ||
|
|
f7bc3ff49d | ||
|
|
53aabe3cdb | ||
|
|
09b8d7cfc9 | ||
|
|
1512afc7e6 | ||
|
|
dde0c76112 | ||
|
|
f14b6f2ba2 | ||
|
|
4fced276c4 | ||
|
|
7590471d62 | ||
|
|
0b6bcf6739 | ||
|
|
3a5ce86ed9 | ||
|
|
7b298939e2 | ||
|
|
f1f6aa7d80 | ||
|
|
7ce7dd7252 | ||
|
|
01aa556ede | ||
|
|
48ad39c1c7 | ||
|
|
9cab034448 | ||
|
|
0d7a22634c | ||
|
|
3e3bc5c06d | ||
|
|
2a81e468c7 | ||
|
|
0ba67a363e | ||
|
|
deae846864 | ||
|
|
3a0d48ad77 | ||
|
|
81d4803b4d | ||
|
|
e936c7c507 | ||
|
|
ad868af96e | ||
|
|
cd14a45414 | ||
|
|
f7cd7110ea | ||
|
|
44262bf747 | ||
|
|
0fbbabe208 | ||
|
|
b39189fde3 | ||
|
|
18fc1d78f4 | ||
|
|
d44a91d10b | ||
|
|
5e9829b2d8 | ||
|
|
2176deae36 | ||
|
|
7c5035aa39 | ||
|
|
5707993995 | ||
|
|
f81697527c | ||
|
|
967eff4c58 | ||
|
|
d5d07dd34e | ||
|
|
b91cc3781d | ||
|
|
87ed0071c4 | ||
|
|
0fed48630c | ||
|
|
7b3e7c98ac | ||
|
|
09f44b0375 | ||
|
|
ebfa62637e | ||
|
|
cb2cc05cac | ||
|
|
f9c9131d81 | ||
|
|
1be9a1cbc7 | ||
|
|
b7fda8ecf0 | ||
|
|
db16392821 | ||
|
|
7127f541c3 | ||
|
|
32793cc008 | ||
|
|
fbaf55cb25 | ||
|
|
b8d51fc4e8 | ||
|
|
0c6e05d220 | ||
|
|
4066c17a0f | ||
|
|
429f2bb8dd | ||
|
|
112f4fc4f0 | ||
|
|
ecfbd6280f | ||
|
|
bf84409839 | ||
|
|
a7ce72cae0 | ||
|
|
28402ff7d8 | ||
|
|
e1d213d1a3 | ||
|
|
c610dd96f5 | ||
|
|
2ba3818b65 | ||
|
|
0e1a5a375a | ||
|
|
cfc3daeb65 | ||
|
|
6359f1950e | ||
|
|
d2f581853d | ||
|
|
030cb285da | ||
|
|
af45409959 | ||
|
|
d9a9bc35e3 | ||
|
|
c911c3352c | ||
|
|
654abbac25 | ||
|
|
46d5f42c9d | ||
|
|
1509da1215 | ||
|
|
98a99d96aa | ||
|
|
d62d81af17 | ||
|
|
dba67eb927 | ||
|
|
548c30d6a0 | ||
|
|
1b8b9186a8 | ||
|
|
a8cfcfb371 | ||
|
|
f7a414bc29 | ||
|
|
e05cd1d66b | ||
|
|
511cd90c44 | ||
|
|
8fb2d8da88 | ||
|
|
2fce332ed7 | ||
|
|
b23f1eb145 | ||
|
|
f694072b5a | ||
|
|
10de266e0f | ||
|
|
71811ed04f | ||
|
|
e9638ef95e | ||
|
|
5226bb5596 | ||
|
|
b9984b6df4 | ||
|
|
9c11835fee | ||
|
|
d9e13d6b99 | ||
|
|
dede076835 | ||
|
|
c929782e0d | ||
|
|
a43c7e36f8 | ||
|
|
b95cec9c32 | ||
|
|
9a7d9abe3c | ||
|
|
c77b620453 | ||
|
|
b348084e2a | ||
|
|
ff1811ef90 | ||
|
|
39cf4a7576 | ||
|
|
21b67625a6 | ||
|
|
fb0311e675 | ||
|
|
8a14b4afff | ||
|
|
e42701599a | ||
|
|
352b1b43f2 | ||
|
|
2922ebd095 | ||
|
|
a9e72085dd | ||
|
|
ed3d194c90 | ||
|
|
125c53827b | ||
|
|
38781807cd | ||
|
|
c046943269 | ||
|
|
fe36cd86bb | ||
|
|
401410089c | ||
|
|
fa23337519 | ||
|
|
ae5421f76e | ||
|
|
a2e2b429d5 | ||
|
|
ac852b23b3 | ||
|
|
e12389a002 | ||
|
|
da18e42d2a | ||
|
|
93bdaba8ee | ||
|
|
4cb08a61d5 | ||
|
|
133692ca92 | ||
|
|
4bcc4b3cf8 | ||
|
|
4eb20ca4b6 | ||
|
|
69f7343be5 | ||
|
|
19b28a58d6 | ||
|
|
3c33a93b9c | ||
|
|
f2e16dfb21 | ||
|
|
0f689e8051 | ||
|
|
5b44e6ef64 | ||
|
|
49e4ade66f | ||
|
|
3bae27d039 | ||
|
|
a77f0c606d | ||
|
|
f1de64dcaf | ||
|
|
feb672c3cd | ||
|
|
a90b463a7d | ||
|
|
5f5f25c978 | ||
|
|
351ea8bc1c | ||
|
|
b34edcbf87 | ||
|
|
160519e1fe | ||
|
|
44d626e12e | ||
|
|
efb9dc51c9 | ||
|
|
deb51434fd | ||
|
|
501070bfb0 | ||
|
|
712958d8c8 | ||
|
|
4d8d944fe5 | ||
|
|
0042e42160 | ||
|
|
85509ea251 | ||
|
|
6063854d06 | ||
|
|
456f8a90b1 | ||
|
|
980246d07a | ||
|
|
141c30b173 | ||
|
|
22f9b03fce | ||
|
|
be2db504b9 | ||
|
|
cac6f5234f | ||
|
|
eb6b32b6ee | ||
|
|
07acc9529e | ||
|
|
f7f0152573 | ||
|
|
153533f1d5 | ||
|
|
11622c586a | ||
|
|
7396bb508a | ||
|
|
7df6530f3a | ||
|
|
80787456fa | ||
|
|
4446ac1ca3 | ||
|
|
220039ab00 | ||
|
|
12f2250ab5 | ||
|
|
0c33aa16a1 | ||
|
|
72908b02fe | ||
|
|
223aa04424 | ||
|
|
e53248cca6 | ||
|
|
c11d661b39 | ||
|
|
4212a08337 | ||
|
|
c0553fa9eb | ||
|
|
7f26fafed7 | ||
|
|
3e9309c003 | ||
|
|
1017707475 | ||
|
|
e8ff5da209 | ||
|
|
03ed3ac1b0 | ||
|
|
2c97208e74 | ||
|
|
a458e81f8d | ||
|
|
83289bc801 | ||
|
|
ba2ac6a7b5 | ||
|
|
245b6da577 | ||
|
|
8875f924b0 | ||
|
|
ad7868ebe1 | ||
|
|
5effc6ec90 | ||
|
|
4cc9ceabd2 | ||
|
|
464c918134 | ||
|
|
2456adcb68 | ||
|
|
45bc967f30 | ||
|
|
d6d4d29257 | ||
|
|
33fdfdc8c0 | ||
|
|
80c8712b2a | ||
|
|
957e3eb93c | ||
|
|
110e1afa8e | ||
|
|
1da8f68871 | ||
|
|
513ddb4cca | ||
|
|
3bdfcb8542 | ||
|
|
aee758eca2 | ||
|
|
47ef7fffce | ||
|
|
58d6256607 | ||
|
|
b854fcdb72 | ||
|
|
27ca75d94f | ||
|
|
bb15f78af0 | ||
|
|
ccc9e18132 | ||
|
|
d55108ab60 | ||
|
|
84adbcb683 | ||
|
|
0cb5e4553b | ||
|
|
264407b707 | ||
|
|
eb5ec58453 | ||
|
|
39c2a757be | ||
|
|
8cdc05f582 | ||
|
|
5f4778c852 | ||
|
|
70add44fc1 | ||
|
|
fa617d2e9d | ||
|
|
3c795d365d | ||
|
|
93872ad7a3 | ||
|
|
227676c150 | ||
|
|
5f23833b43 | ||
|
|
121d51b414 | ||
|
|
0e196a59d9 | ||
|
|
63bfd23310 | ||
|
|
aadcf8fed0 | ||
|
|
37390e03b4 | ||
|
|
98fc780ade | ||
|
|
1670b21123 | ||
|
|
5602aacbd2 | ||
|
|
6ddbea207f | ||
|
|
261bced822 | ||
|
|
a80d1f861c | ||
|
|
c541340ef5 | ||
|
|
434af0ae64 | ||
|
|
c6379ca1d4 | ||
|
|
cdbcada49b | ||
|
|
282930cb9b | ||
|
|
b09c751942 | ||
|
|
b2047b90b3 | ||
|
|
0c8aec30bd | ||
|
|
fafaa3e69b | ||
|
|
d19bb3de8d | ||
|
|
481136166c | ||
|
|
4df81a0b9e | ||
|
|
da1e9c2d97 | ||
|
|
4b5a02c246 | ||
|
|
0e1572cfd7 | ||
|
|
343caa1ff6 | ||
|
|
403fb3826d | ||
|
|
3cdccb7b4e | ||
|
|
d9be78cdb4 | ||
|
|
16dc8255e1 | ||
|
|
2086bfff25 | ||
|
|
b9a68c0b8e | ||
|
|
74647f0e88 | ||
|
|
6e29c8bea9 | ||
|
|
b36373ab81 | ||
|
|
dc437aacf1 | ||
|
|
e19dae9b28 | ||
|
|
424cbd4831 | ||
|
|
350feed993 | ||
|
|
7ca4aa0ff4 | ||
|
|
bf00e67245 | ||
|
|
c5a6e49681 | ||
|
|
a509af2875 | ||
|
|
1f789bf396 | ||
|
|
0ccbc7d3d2 | ||
|
|
f3c6f26f85 | ||
|
|
338c358df2 | ||
|
|
4bdaa48303 | ||
|
|
36267746da | ||
|
|
7775541eed | ||
|
|
5029be4c83 | ||
|
|
277dbacf68 | ||
|
|
0fdfb03f3c | ||
|
|
17d81bf014 | ||
|
|
568e9be07e | ||
|
|
99b0a95f8a | ||
|
|
0fdd31892a | ||
|
|
7a682604f9 | ||
|
|
ce96e35d7d | ||
|
|
b7fb5394a7 | ||
|
|
aaa62beca7 | ||
|
|
2b58a7242b | ||
|
|
5ed919df79 | ||
|
|
baf6372179 | ||
|
|
1a9063a55b | ||
|
|
87999f402f | ||
|
|
109d466260 | ||
|
|
37597eca75 | ||
|
|
5fd767b739 | ||
|
|
0e7a473116 | ||
|
|
05bf55dca8 | ||
|
|
cc12ad8d86 | ||
|
|
847a7f470c | ||
|
|
95bebd6d1d | ||
|
|
8179a964ea | ||
|
|
d0805d4bbb | ||
|
|
f901c401b7 | ||
|
|
6ccadcb928 | ||
|
|
58b6c25d5c | ||
|
|
9cbab26202 | ||
|
|
74bcb468ca | ||
|
|
07a6ba88f4 | ||
|
|
49dff49993 | ||
|
|
68207aac80 | ||
|
|
64652b2ff0 | ||
|
|
659e8991de | ||
|
|
9f495b6dc9 | ||
|
|
d8498134ad | ||
|
|
17b2320b0d | ||
|
|
36c457f483 | ||
|
|
b8ec7f5e26 | ||
|
|
dbc5c0d5d8 | ||
|
|
fa886aa849 | ||
|
|
32e1ae2b18 | ||
|
|
61f03b0ea2 | ||
|
|
c47825a820 | ||
|
|
2d7cb63c7b | ||
|
|
c3d4c13936 | ||
|
|
3f51b9322f | ||
|
|
b604e2bd4e | ||
|
|
bcd92473d1 | ||
|
|
6f5bf9d146 | ||
|
|
490094939f | ||
|
|
d0d7d2772f | ||
|
|
59091896b4 | ||
|
|
3eb1429a25 | ||
|
|
bc7504c469 | ||
|
|
99dc4b8e07 | ||
|
|
807904bb86 | ||
|
|
7b8c8348f4 | ||
|
|
9c5ac26170 | ||
|
|
5db065644c | ||
|
|
0cc3a99169 | ||
|
|
2b1545145b | ||
|
|
49b7c9c8a4 | ||
|
|
114119f7c8 | ||
|
|
b4ef866c10 | ||
|
|
15f75a08d5 | ||
|
|
29f9c5473d | ||
|
|
ea1528aea6 | ||
|
|
18ce19a84d | ||
|
|
b0fd78d68d | ||
|
|
8186d6277e | ||
|
|
599af2b1a9 | ||
|
|
82de5adbe9 | ||
|
|
82b0f85258 | ||
|
|
cded58c30d | ||
|
|
da17b49b81 | ||
|
|
4728cdfa7c | ||
|
|
d97b30dcee | ||
|
|
fa8e8ad52d | ||
|
|
7495ac8111 | ||
|
|
08619e2c06 | ||
|
|
5d4bbd5b37 | ||
|
|
9d2aef5006 | ||
|
|
bcc3e5ebb0 | ||
|
|
e5df51a83a | ||
|
|
97fb843f01 | ||
|
|
8afb044877 | ||
|
|
7f869868c9 | ||
|
|
31275228ac | ||
|
|
7181be8768 | ||
|
|
3b446e887a | ||
|
|
431196c391 | ||
|
|
9608d8fb46 | ||
|
|
d574ca1628 | ||
|
|
8be60e2ff5 | ||
|
|
3c0fd540b1 | ||
|
|
23a7dc9a8a | ||
|
|
f97e6892b6 | ||
|
|
7742901e5c | ||
|
|
de68cb25d0 | ||
|
|
77d7afe505 | ||
|
|
68fb6c2c27 | ||
|
|
a47c031ad1 | ||
|
|
817049456c | ||
|
|
e1a061789f | ||
|
|
28573ba772 | ||
|
|
880b9413f6 | ||
|
|
9a7c4b21a9 | ||
|
|
ac56038eca | ||
|
|
4dd2fb6903 | ||
|
|
0baec61f06 | ||
|
|
d4751788d1 | ||
|
|
ae68c061d1 | ||
|
|
b0387245f0 | ||
|
|
c2d06a4a23 | ||
|
|
270108abb7 | ||
|
|
e76c33232d | ||
|
|
58ff2dc492 | ||
|
|
13c45a0e96 | ||
|
|
90cb86911a | ||
|
|
be7b1a1bd4 | ||
|
|
132a3c6705 | ||
|
|
5e73257557 | ||
|
|
e83346fbbb | ||
|
|
2dd47a2103 | ||
|
|
f31e530b6e | ||
|
|
eb50f3fa9c | ||
|
|
8417fe4fdb | ||
|
|
0f1c15a6ca | ||
|
|
9345c4fb7f | ||
|
|
5e0758917b | ||
|
|
f56839ec6b | ||
|
|
cbb23a42e2 | ||
|
|
5a59c286d0 | ||
|
|
2e8c600d7a | ||
|
|
e851cb1cbc | ||
|
|
3da03da32a | ||
|
|
3ec8924e7f | ||
|
|
a04722b612 | ||
|
|
f9a7857a90 | ||
|
|
58f772c74e | ||
|
|
a425c7e260 | ||
|
|
809885afd0 | ||
|
|
bf9b4b993f | ||
|
|
d94a26f0f4 | ||
|
|
bd9c9cedca | ||
|
|
651e94bd94 | ||
|
|
162b6f1a74 | ||
|
|
865a253eb5 | ||
|
|
9b3781abf1 | ||
|
|
d89243a0d3 | ||
|
|
b4cefc64b4 | ||
|
|
2fd26587e5 | ||
|
|
282a351859 | ||
|
|
a84b848ea9 | ||
|
|
d329320fc2 | ||
|
|
bc096554b5 | ||
|
|
5902d878d8 | ||
|
|
4a133ca36f | ||
|
|
f7252f919a | ||
|
|
e05a03a842 | ||
|
|
dcce8276b8 | ||
|
|
fd47947e55 | ||
|
|
ae151df2eb | ||
|
|
79de188683 | ||
|
|
6e5c788e13 | ||
|
|
f53606007d | ||
|
|
a4ac418bc9 | ||
|
|
a8c09d0bdb | ||
|
|
871105a48a | ||
|
|
3b61129ade | ||
|
|
f471c79b59 | ||
|
|
dfd9443f74 | ||
|
|
a36ff9e365 | ||
|
|
12e65bbf26 | ||
|
|
ab9841e60b | ||
|
|
7a52f12e57 | ||
|
|
11fd4506ac | ||
|
|
0c9c68030e | ||
|
|
55d6eddbb2 | ||
|
|
8341e60edb | ||
|
|
6273a1ca73 | ||
|
|
1b83ebdf89 | ||
|
|
fef7f0506f | ||
|
|
f44eb4e383 | ||
|
|
05df485c4a | ||
|
|
44857c526b | ||
|
|
b8ad5d5d32 | ||
|
|
e3e0d00e21 | ||
|
|
a9b1ea9690 | ||
|
|
8e5dd0f8d9 | ||
|
|
3b0c8f6d92 | ||
|
|
21058c2227 | ||
|
|
f3b8ae0781 | ||
|
|
d590b004c1 | ||
|
|
02e21141c6 | ||
|
|
f839a3087d | ||
|
|
f458815541 | ||
|
|
7ba754d2a4 | ||
|
|
09706e4ae2 | ||
|
|
d18de4c541 | ||
|
|
001c7bfdbc | ||
|
|
d4e04dc712 | ||
|
|
8650cb5217 | ||
|
|
0eaaddeb95 | ||
|
|
1cf8663f20 | ||
|
|
5130259552 | ||
|
|
ba5e19a015 | ||
|
|
c0400fa986 | ||
|
|
51179d10ce | ||
|
|
78752f9178 | ||
|
|
762db417d7 | ||
|
|
85bdccbc06 | ||
|
|
9f8cb99340 | ||
|
|
87b90bb04b | ||
|
|
e961d88277 | ||
|
|
5754c11e34 | ||
|
|
7bd88c1bb8 | ||
|
|
445b686c6c | ||
|
|
0cb7b75214 | ||
|
|
a08399dfee | ||
|
|
4016808fa4 | ||
|
|
8635849977 | ||
|
|
1a9ed4d4fe | ||
|
|
e7b3246dd0 | ||
|
|
19589aec57 | ||
|
|
4d33ff0417 | ||
|
|
93a5ab5b33 | ||
|
|
59ada06cdf | ||
|
|
ae650849b0 | ||
|
|
3e8f9a6b53 | ||
|
|
79362b0dba | ||
|
|
3e3df06d57 | ||
|
|
6b220eb1c5 | ||
|
|
a1c61cae11 | ||
|
|
d48a917bf3 | ||
|
|
646b6dafb2 | ||
|
|
8d10f33a3f | ||
|
|
5d603b2f80 | ||
|
|
0e1b08ff54 | ||
|
|
befc22d718 | ||
|
|
4a62e80967 | ||
|
|
ee9ef9f2c1 | ||
|
|
93dcb68437 | ||
|
|
0691cc7909 | ||
|
|
d82f34fe59 | ||
|
|
d2313b30af | ||
|
|
329719472a | ||
|
|
a2fcab47d4 | ||
|
|
4ab5951c25 | ||
|
|
403cabb201 | ||
|
|
3da7c5d3e2 | ||
|
|
c5e0de51aa | ||
|
|
c581f1bba4 | ||
|
|
b8ac9c2edd | ||
|
|
1027ee2481 | ||
|
|
2f311f7821 | ||
|
|
a98c95b514 | ||
|
|
5bbbae5b23 | ||
|
|
f9c9b9f924 | ||
|
|
5921208ea6 | ||
|
|
f89c78abd1 | ||
|
|
74d3b9334c | ||
|
|
919fc66b9d | ||
|
|
400fb5a5bb | ||
|
|
3bb4f9085c | ||
|
|
714c6cec3c | ||
|
|
cb69921202 | ||
|
|
277a0adac9 | ||
|
|
02d14f504f | ||
|
|
1ab7664a60 | ||
|
|
1be46ffb7e | ||
|
|
6ca52aed0d | ||
|
|
74e20970e2 | ||
|
|
93f2b6b4d8 | ||
|
|
00e616b57a | ||
|
|
e436673304 | ||
|
|
ce04d3ce41 | ||
|
|
4e46bf4697 | ||
|
|
9b95508f99 | ||
|
|
c8c24456c1 | ||
|
|
80a6e82e1b | ||
|
|
80cec20d38 | ||
|
|
26cb22020d | ||
|
|
09d05d09c9 | ||
|
|
160c91f908 | ||
|
|
58f41bcd42 | ||
|
|
0235429995 | ||
|
|
f79697e117 | ||
|
|
6f0019c71e | ||
|
|
1a04a18245 | ||
|
|
0cf3ff8209 | ||
|
|
7f56091fbd | ||
|
|
391f9b31f6 | ||
|
|
1d7c0f504a | ||
|
|
9cdc62f918 | ||
|
|
6027d0481e | ||
|
|
277fb92f9e | ||
|
|
79b6c3c1af | ||
|
|
ad17174119 | ||
|
|
6c2692eec0 | ||
|
|
08640e8575 | ||
|
|
4a2575136f | ||
|
|
e792afad17 | ||
|
|
5ecc4b027d | ||
|
|
bc540f0cf0 | ||
|
|
a24b14c465 | ||
|
|
c3f36c3123 | ||
|
|
1d34da7557 | ||
|
|
27d74a4327 | ||
|
|
8a20cc682c | ||
|
|
9b20359e7b | ||
|
|
8866d0ccef | ||
|
|
7fa91a9971 | ||
|
|
28d1f3eef0 | ||
|
|
f321cf6655 | ||
|
|
14ade737da | ||
|
|
41b1b1f141 | ||
|
|
25dfd47d32 | ||
|
|
6afa9c8b92 | ||
|
|
2fc449da4c | ||
|
|
5dd3b8cf9d | ||
|
|
e834fa0050 | ||
|
|
9a97401606 | ||
|
|
410a3fef18 | ||
|
|
969b9814d5 | ||
|
|
2275e27b87 | ||
|
|
62b06cd204 | ||
|
|
350934ca21 | ||
|
|
6332673434 | ||
|
|
f217840998 | ||
|
|
089ec35ceb | ||
|
|
fecd0b809e | ||
|
|
4707a46561 | ||
|
|
616533c5a8 | ||
|
|
c5b2991821 | ||
|
|
c36d0fdc7c | ||
|
|
544e09cf4b | ||
|
|
c110dc9e6a | ||
|
|
3bf37d6afd | ||
|
|
b80ae5796b | ||
|
|
2083632299 | ||
|
|
3ca2f8ac9e | ||
|
|
7172432084 | ||
|
|
0e6afd147f | ||
|
|
46275a4f43 | ||
|
|
1dca378e03 | ||
|
|
06669594b1 | ||
|
|
c09ac58ac0 | ||
|
|
e01d32ef1a | ||
|
|
5ea3bcf59e | ||
|
|
aa8b14b7ee | ||
|
|
e1722cf739 | ||
|
|
7a7f70e15d | ||
|
|
b3c3ec16e5 | ||
|
|
149f863951 | ||
|
|
684d09faac | ||
|
|
8a42691c80 | ||
|
|
d591b3dd98 | ||
|
|
a90fb4d8b6 | ||
|
|
ebd08d9c63 | ||
|
|
71731d223b | ||
|
|
726ea5e01e | ||
|
|
16c7d2964b | ||
|
|
5a6e494bda | ||
|
|
88c6d89fbb | ||
|
|
de12da18da | ||
|
|
8d10736934 | ||
|
|
2328e02d82 | ||
|
|
87cd5fca90 | ||
|
|
b70cb726c5 | ||
|
|
295811ed5a | ||
|
|
4bc55551c6 | ||
|
|
2b8c6dc8f9 | ||
|
|
8b27380feb | ||
|
|
8de3a90851 | ||
|
|
f8bb94d721 | ||
|
|
0c6d06e7bb | ||
|
|
b0aa5d3af2 | ||
|
|
27d09713fd | ||
|
|
ff18852879 | ||
|
|
e515c91e5e | ||
|
|
1d5800c4f7 | ||
|
|
de8f190945 | ||
|
|
f371e3c8d3 | ||
|
|
b15a6290a7 | ||
|
|
0f151db355 | ||
|
|
fa99b75d1f | ||
|
|
4a299c1f39 | ||
|
|
30a2015a68 | ||
|
|
c7c8a4891f | ||
|
|
fe9fc6b459 | ||
|
|
2113fb490d | ||
|
|
0afedbd252 | ||
|
|
3dec38450a | ||
|
|
d7a00b05e3 | ||
|
|
ff2cc8c887 | ||
|
|
0571a96cea | ||
|
|
b7b457b076 | ||
|
|
d2c12005b2 | ||
|
|
25f26d7e5f | ||
|
|
9d5724e1a0 | ||
|
|
784d23ec87 | ||
|
|
709689a7ee | ||
|
|
35d5d3d995 | ||
|
|
630a8d8a4e | ||
|
|
54eb1d9055 | ||
|
|
cb63caea61 | ||
|
|
8e046bb022 | ||
|
|
189b53b8c4 | ||
|
|
9b7277d464 | ||
|
|
551a65c069 | ||
|
|
4c21a697f4 | ||
|
|
a8506c07ae | ||
|
|
b0feb85b5c | ||
|
|
f371eba8ad | ||
|
|
265fa52ace | ||
|
|
c1f5322d38 | ||
|
|
4415e00b38 | ||
|
|
d4e46c5a9c | ||
|
|
bf5b9949fe | ||
|
|
3c11a2b1da | ||
|
|
1248868169 | ||
|
|
930b95a548 | ||
|
|
27c9f68c7c | ||
|
|
358d4d86a7 | ||
|
|
d55eea2239 | ||
|
|
4507954ea5 | ||
|
|
8e0a83f8d8 | ||
|
|
b6ec09e6cf | ||
|
|
ed4e90623d | ||
|
|
38cdb48748 | ||
|
|
71bfe9b745 | ||
|
|
9e7645a167 | ||
|
|
6dccc37143 | ||
|
|
3310310d8c | ||
|
|
abb499aad8 | ||
|
|
1afc09b08a | ||
|
|
0e86d72f05 | ||
|
|
c9857a2764 | ||
|
|
701ba3902c | ||
|
|
bb3ec970a9 | ||
|
|
1d023e6db5 | ||
|
|
1bd906ecb3 | ||
|
|
7cbffdb86b | ||
|
|
b979196ffd | ||
|
|
2949db5f49 | ||
|
|
47c3ed9705 | ||
|
|
51ca3109eb | ||
|
|
2bcb79dc44 | ||
|
|
ecec985649 | ||
|
|
994908549d | ||
|
|
e00f059a4a | ||
|
|
6808e0d531 | ||
|
|
410c95308a | ||
|
|
bec1f23616 | ||
|
|
34596b7f83 | ||
|
|
5ca7169ee5 | ||
|
|
3300aaa1b9 | ||
|
|
54afc8a4a1 | ||
|
|
f19f4310f4 | ||
|
|
444125a7e1 | ||
|
|
56cbb69401 | ||
|
|
70870ffcd2 | ||
|
|
a556d91673 | ||
|
|
8ecbde8e1e | ||
|
|
a24b293818 | ||
|
|
cab5ebf94b | ||
|
|
a54b5baef2 | ||
|
|
c324fe204e | ||
|
|
37d972ed9e | ||
|
|
e4a3b1cb05 | ||
|
|
49538f272e | ||
|
|
1283232144 | ||
|
|
2f9891f0aa | ||
|
|
865a2b1fb0 | ||
|
|
1fde62eeb6 | ||
|
|
6754cd48e2 | ||
|
|
ccb477687a | ||
|
|
be0e6c8925 | ||
|
|
1c2cb947c0 | ||
|
|
4663eec950 | ||
|
|
fff3c1eb36 | ||
|
|
4b7434d1e8 | ||
|
|
8cc35a60e6 | ||
|
|
130653a1aa | ||
|
|
1dcbebd130 | ||
|
|
faf306ad23 | ||
|
|
d11cdcd5d2 | ||
|
|
0e59bd0bf3 | ||
|
|
c0c6154ec1 | ||
|
|
cb5384c2fb | ||
|
|
038c836fe5 | ||
|
|
6b0f3570b9 | ||
|
|
71de0d04f3 | ||
|
|
99debff5d2 | ||
|
|
3bac6fcb27 | ||
|
|
4b842b81a0 | ||
|
|
e2e4d048ab | ||
|
|
5574c368cd | ||
|
|
0d34f7b92e | ||
|
|
5be0632e01 | ||
|
|
79ea0bf9f4 | ||
|
|
b1929cb688 | ||
|
|
5ad98700e5 | ||
|
|
a54624b697 | ||
|
|
ca34c865af | ||
|
|
dde57b1eca | ||
|
|
264b06938e | ||
|
|
99edb303e2 | ||
|
|
104cc24dfc | ||
|
|
fcbcbac889 | ||
|
|
b86d19028c | ||
|
|
4f17a251d3 | ||
|
|
731a823cc2 | ||
|
|
3d79fe2bf4 | ||
|
|
474399154f | ||
|
|
19f5153d0e | ||
|
|
ce11271866 | ||
|
|
86cf353296 | ||
|
|
36df5dc721 | ||
|
|
1e44a9c942 | ||
|
|
8685cf9036 | ||
|
|
2232870b09 | ||
|
|
b68acd101e | ||
|
|
173ba9b2b5 | ||
|
|
64ed1f87d3 | ||
|
|
1ca085ec4a | ||
|
|
e332b7535c | ||
|
|
79eb613b3e | ||
|
|
5a79ec28d1 | ||
|
|
97e65a02c0 | ||
|
|
e87c786b77 | ||
|
|
251d30d47f | ||
|
|
761d0a0f18 | ||
|
|
ae4b1e74f9 | ||
|
|
ac44618e58 | ||
|
|
d634cbf924 | ||
|
|
21db0e6275 | ||
|
|
ce426fd3f4 | ||
|
|
b5d4c91207 | ||
|
|
b43263be77 | ||
|
|
207cf7ca24 | ||
|
|
00e34758c4 | ||
|
|
7a3f878c11 | ||
|
|
b8439598bc | ||
|
|
7fb0818923 | ||
|
|
a7c435adc4 | ||
|
|
dd90aabad6 | ||
|
|
5bded1946e | ||
|
|
3642e96154 | ||
|
|
9da09ee3a6 | ||
|
|
141c140f53 | ||
|
|
84b660d2ef | ||
|
|
6beedba957 | ||
|
|
d73982819b | ||
|
|
6ac5bcc907 | ||
|
|
389d4d10f1 | ||
|
|
89dcbd0229 | ||
|
|
ad8caa2b51 | ||
|
|
9c42241269 | ||
|
|
38dd45cce2 | ||
|
|
aa90253c62 | ||
|
|
41576652dc | ||
|
|
74830854ca | ||
|
|
2542b1b44d | ||
|
|
51f5e60224 | ||
|
|
bb5885e2bb | ||
|
|
d51bbb0008 | ||
|
|
49e898b189 | ||
|
|
42c4fe5705 | ||
|
|
4b5f2c36b9 | ||
|
|
935dca67e6 | ||
|
|
d431790e19 | ||
|
|
56310b7bd4 | ||
|
|
f15e21faad | ||
|
|
44aa6a2b38 | ||
|
|
9f32347c01 | ||
|
|
3d5b229c46 | ||
|
|
5863ccc0a0 | ||
|
|
d220a16b99 | ||
|
|
79784fc8ee | ||
|
|
a83bc53c6a | ||
|
|
85de0b91b1 | ||
|
|
d91c6e5702 | ||
|
|
ab7689d188 | ||
|
|
c81455c760 | ||
|
|
39bfc97a7a | ||
|
|
88aac78282 | ||
|
|
863e830d24 | ||
|
|
6c705728a4 | ||
|
|
7f00279ffb | ||
|
|
c198d0079e | ||
|
|
1135d5a971 | ||
|
|
e299fa27a0 | ||
|
|
46e0bc940a | ||
|
|
9a552012f2 | ||
|
|
6498d385ee | ||
|
|
dd00f2016f | ||
|
|
64d25e6522 | ||
|
|
1462ab08de | ||
|
|
a8e93a594d | ||
|
|
dea30b37ef | ||
|
|
39571dda0b | ||
|
|
c7d801b6c2 | ||
|
|
57731be689 | ||
|
|
f00524e518 | ||
|
|
5567c40bae | ||
|
|
5d1a7613dd | ||
|
|
fa768dc112 | ||
|
|
27fb51d37f | ||
|
|
d02db3864e | ||
|
|
a26c3036a7 | ||
|
|
0af346aad8 | ||
|
|
c3c8ee7292 | ||
|
|
5fbdfa66d9 | ||
|
|
15b75715ee | ||
|
|
1fd92b6cbd | ||
|
|
2918b5d74e | ||
|
|
669c5be344 | ||
|
|
e1b40ec46e | ||
|
|
15767538eb | ||
|
|
de2b16c464 | ||
|
|
d5e6b38450 | ||
|
|
a636e87a4f | ||
|
|
50d5b4fa37 | ||
|
|
f6d26392fb | ||
|
|
2705bcce15 | ||
|
|
379a31ece6 | ||
|
|
daa593d225 | ||
|
|
ed8340affa | ||
|
|
b3c1e72577 | ||
|
|
3da09d140a | ||
|
|
51f254bbb1 | ||
|
|
30ee456d4c | ||
|
|
460d5f2517 | ||
|
|
5da1fc8445 | ||
|
|
1166b43946 | ||
|
|
0a6903c4c3 | ||
|
|
62fae9af93 | ||
|
|
509a1c2eb5 | ||
|
|
8b94bbbc5e | ||
|
|
bb923d2b7d | ||
|
|
38adc72954 | ||
|
|
362c7c57fa | ||
|
|
6529b7eebf | ||
|
|
439c98a6e5 | ||
|
|
32258ef666 | ||
|
|
176e088d4e | ||
|
|
4fe57ba025 | ||
|
|
2818e56932 | ||
|
|
5428a19617 | ||
|
|
b58cbca61a | ||
|
|
5fc6a03784 | ||
|
|
eb4ad0ba1b | ||
|
|
72cdd1ea50 | ||
|
|
18769f0b8f | ||
|
|
b7d92c3c12 | ||
|
|
b976101dca | ||
|
|
8943b670a4 | ||
|
|
c92ff7c622 | ||
|
|
301b5e1721 | ||
|
|
4e50b9b479 | ||
|
|
f8b7b8cc28 | ||
|
|
2a6ea74be7 | ||
|
|
6d6a0c12cd | ||
|
|
784a03300a | ||
|
|
392f578567 | ||
|
|
a91b1d2dd2 | ||
|
|
400b3d961e | ||
|
|
4f128470bd | ||
|
|
fe06f41136 | ||
|
|
f81a99565e | ||
|
|
81e146650b | ||
|
|
bd4e04d331 | ||
|
|
7663d2c64b | ||
|
|
443c3c2802 | ||
|
|
17a546af5d | ||
|
|
71faf46735 | ||
|
|
ac28744df6 | ||
|
|
adaf304b4e | ||
|
|
16b13f9768 | ||
|
|
d64bf98dc0 | ||
|
|
71f57d13fa | ||
|
|
469c10e45f | ||
|
|
62def596af | ||
|
|
aa10844d9e | ||
|
|
be52079182 | ||
|
|
255aca8789 | ||
|
|
117f4a282d | ||
|
|
e1ea65525f | ||
|
|
d0a3495b5f | ||
|
|
9e9e0d6592 | ||
|
|
cb5f9ba97d | ||
|
|
34538f2ced | ||
|
|
2575644920 | ||
|
|
b4b43a9e9e | ||
|
|
df97b20913 | ||
|
|
9e3cc379ed | ||
|
|
c1d78a94a2 | ||
|
|
7f4cbba076 | ||
|
|
bdca84fe72 | ||
|
|
cf8fd7103b | ||
|
|
8e8cdbd413 | ||
|
|
30f01681d4 | ||
|
|
ecf1ad8da1 | ||
|
|
42dc112a13 | ||
|
|
58276cefce | ||
|
|
4b6501a739 | ||
|
|
724085e068 | ||
|
|
21fab3ef9f | ||
|
|
db8837f4ce | ||
|
|
5781cdf6da | ||
|
|
874eb1602f | ||
|
|
82149917b7 | ||
|
|
f11d8a5bd8 | ||
|
|
f0d7d10fe7 | ||
|
|
9d4d9ce978 | ||
|
|
96a38602b8 | ||
|
|
90d3558d31 | ||
|
|
e491a56dd0 | ||
|
|
4d8eb61924 | ||
|
|
17fab541c6 | ||
|
|
91de35e8e9 | ||
|
|
f61964676a | ||
|
|
41a34c19bb | ||
|
|
d90810d127 | ||
|
|
7f3d281faa | ||
|
|
812c306805 | ||
|
|
fc1c59f374 | ||
|
|
35eac1e3ff | ||
|
|
e16041d7fa | ||
|
|
b8fc84ecc8 | ||
|
|
572c576e15 | ||
|
|
9df7f80fbb | ||
|
|
f003400135 | ||
|
|
ca7616c1d2 | ||
|
|
a4a2bfdf35 | ||
|
|
eb6bbb6e78 | ||
|
|
4d0172f634 | ||
|
|
3b61e0e126 | ||
|
|
1540a91835 | ||
|
|
2bcce9eed0 | ||
|
|
1e53564386 | ||
|
|
d1c72706ef | ||
|
|
bd9e531257 | ||
|
|
48436424db | ||
|
|
4f10d7f859 | ||
|
|
80e5a29444 | ||
|
|
0ec8a4a160 | ||
|
|
810bf7af0c | ||
|
|
e7825206bf | ||
|
|
2b887c336a | ||
|
|
48ecd32d5d | ||
|
|
1f5a0987cb | ||
|
|
f33a9d162a | ||
|
|
c2919bcdb0 | ||
|
|
120d554a6b | ||
|
|
44f268a7ee | ||
|
|
3c7a0bcd85 | ||
|
|
8e2e9e9331 | ||
|
|
91c26fc046 | ||
|
|
afcfe58add | ||
|
|
8d423be223 | ||
|
|
03b7314550 | ||
|
|
1a7e425780 | ||
|
|
8bc5faff3c | ||
|
|
2676278a66 | ||
|
|
6376b3baf3 | ||
|
|
e569abe740 | ||
|
|
71be9ef92a | ||
|
|
4990c4903d | ||
|
|
9d468e2383 | ||
|
|
109cac013c | ||
|
|
0d8a9921cd | ||
|
|
2a5f5f7312 | ||
|
|
fe54fbefbb | ||
|
|
fc824b8d06 | ||
|
|
d91a7b6d0e | ||
|
|
aa4b3f93fa | ||
|
|
efe8225d18 | ||
|
|
b2c0f8c158 | ||
|
|
66dce8794d | ||
|
|
30d54407e6 | ||
|
|
6324a92ec5 | ||
|
|
67e7b5c124 | ||
|
|
35099d9b2f | ||
|
|
e07f7b54e0 | ||
|
|
5c409929b4 | ||
|
|
1a504fdde9 | ||
|
|
4b06fd511b | ||
|
|
def6727286 | ||
|
|
bedaa0db16 | ||
|
|
90640a4fcf | ||
|
|
0142d07f10 | ||
|
|
c9d85cfc7d | ||
|
|
64304c1991 | ||
|
|
993adc3578 | ||
|
|
8813bd26f6 | ||
|
|
35925de320 | ||
|
|
3b426a3f07 | ||
|
|
5104fd5dcf | ||
|
|
a5a9ca9e46 | ||
|
|
ba0f07e3b2 | ||
|
|
8614475324 | ||
|
|
744dda144b | ||
|
|
13d47915f4 | ||
|
|
3059b85e41 | ||
|
|
184ea4a67f | ||
|
|
8032f536ed | ||
|
|
fba3870ef1 | ||
|
|
2915ee08ea | ||
|
|
86b76a3e75 | ||
|
|
bc1dca3f6f | ||
|
|
5db1820123 | ||
|
|
657c35fb86 | ||
|
|
9432a84468 | ||
|
|
15a5bc02ef | ||
|
|
f011be9347 | ||
|
|
b6094fdb34 | ||
|
|
9e6ab9f585 | ||
|
|
869d2c02fa | ||
|
|
3b1dca0e70 | ||
|
|
595358fa69 | ||
|
|
8a8ec79c6c | ||
|
|
6252446bd3 | ||
|
|
403ceebff9 | ||
|
|
4767882ed3 |
@@ -4,26 +4,16 @@ jobs:
|
||||
build:
|
||||
resource_class: medium+
|
||||
docker:
|
||||
- image: nikolaik/python-nodejs:python3.7-nodejs8
|
||||
- image: nikolaik/python-nodejs:python3.7-nodejs10
|
||||
environment:
|
||||
CONTRACTS_COMMIT_HASH: '9ed05f5'
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- checkout
|
||||
- run: echo 'export PATH=$HOME/CIRCLE_PROJECT_REPONAME/node_modules/.bin:$PATH' >> $BASH_ENV
|
||||
# HACK(feuGeneA): commented out this hack as we're changing
|
||||
# from a circleci-maintained container to a different
|
||||
# container, and this hack may not apply anymore, as
|
||||
# suggested by the non-existance of `/home/circleci/.bashrc`
|
||||
# when running the command below.
|
||||
# - run:
|
||||
# # HACK(albrow): Without this, yarn commands will sometimes
|
||||
# # fail with a "permission denied" error.
|
||||
# name: Set npm path
|
||||
# command: npm set prefix=/home/circleci/npm && echo 'export PATH=$HOME/circleci/npm/bin:$PATH' >> /home/circleci/.bashrc
|
||||
- run:
|
||||
name: install-yarn
|
||||
command: npm install --global yarn@1.17.0
|
||||
command: npm install --force --global yarn@1.17.0
|
||||
- run:
|
||||
name: yarn
|
||||
command: yarn --frozen-lockfile --ignore-engines install || yarn --frozen-lockfile --ignore-engines install
|
||||
@@ -37,55 +27,61 @@ jobs:
|
||||
- store_artifacts:
|
||||
path: ~/repo/packages/abi-gen/test-cli/output
|
||||
- store_artifacts:
|
||||
path: ~/repo/packages/abi-gen-wrappers/generated_docs
|
||||
test-contracts-ganache:
|
||||
path: ~/repo/packages/contract-wrappers/generated_docs
|
||||
test-exchange-ganache:
|
||||
resource_class: medium+
|
||||
docker:
|
||||
- image: nikolaik/python-nodejs:python3.7-nodejs8
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run: yarn wsrun test:circleci @0x/contracts-multisig @0x/contracts-utils @0x/contracts-exchange-libs @0x/contracts-erc20 @0x/contracts-erc721 @0x/contracts-erc1155 @0x/contracts-extensions @0x/contracts-asset-proxy @0x/contracts-exchange @0x/contracts-exchange-forwarder @0x/contracts-coordinator @0x/contracts-tests @0x/contracts-staking
|
||||
test-exchange-ganache-3.0:
|
||||
resource_class: medium+
|
||||
docker:
|
||||
- image: nikolaik/python-nodejs:python3.7-nodejs8
|
||||
- image: nikolaik/python-nodejs:python3.7-nodejs10
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run: yarn wsrun test:circleci @0x/contracts-exchange
|
||||
test-integrations-ganache-3.0:
|
||||
test-integrations-ganache:
|
||||
resource_class: medium+
|
||||
docker:
|
||||
- image: nikolaik/python-nodejs:python3.7-nodejs8
|
||||
- image: nikolaik/python-nodejs:python3.7-nodejs10
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run: yarn wsrun test:circleci @0x/contracts-integrations
|
||||
test-contracts-rest-ganache-3.0:
|
||||
test-contracts-staking-ganache:
|
||||
resource_class: medium+
|
||||
docker:
|
||||
- image: nikolaik/python-nodejs:python3.7-nodejs8
|
||||
- image: nikolaik/python-nodejs:python3.7-nodejs10
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run: yarn wsrun test:circleci @0x/contracts-multisig @0x/contracts-utils @0x/contracts-exchange-libs @0x/contracts-erc20 @0x/contracts-erc721 @0x/contracts-erc1155 @0x/contracts-asset-proxy @0x/contracts-exchange-forwarder @0x/contracts-tests @0x/contracts-staking @0x/contracts-coordinator
|
||||
# TODO(dorothy-zbornak): Re-enable after updating this package for
|
||||
# 3.0. At that time, also remove exclusion from monorepo
|
||||
# package.json's test script.
|
||||
# - run: yarn wsrun test:circleci @0x/contracts-extensions
|
||||
- run: yarn wsrun test:circleci @0x/contracts-staking
|
||||
test-contracts-extra-ganache:
|
||||
resource_class: medium+
|
||||
docker:
|
||||
- image: nikolaik/python-nodejs:python3.7-nodejs10
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run: yarn wsrun test:circleci @0x/contracts-exchange-forwarder @0x/contracts-coordinator
|
||||
test-contracts-rest-ganache:
|
||||
resource_class: medium+
|
||||
docker:
|
||||
- image: nikolaik/python-nodejs:python3.7-nodejs10
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run: yarn wsrun test:circleci @0x/contracts-multisig @0x/contracts-utils @0x/contracts-exchange-libs @0x/contracts-erc20 @0x/contracts-erc721 @0x/contracts-erc1155 @0x/contracts-asset-proxy @0x/contracts-broker @0x/contracts-zero-ex
|
||||
test-publish:
|
||||
resource_class: medium+
|
||||
docker:
|
||||
- image: nikolaik/python-nodejs:python3.7-nodejs8
|
||||
- image: nikolaik/python-nodejs:python3.7-nodejs10
|
||||
- image: 0xorg/verdaccio
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
@@ -93,256 +89,52 @@ jobs:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run:
|
||||
command: yarn test:publish:circleci
|
||||
no_output_timeout: 1800
|
||||
command: yarn test:publish:circleci
|
||||
no_output_timeout: 1800
|
||||
- store_artifacts:
|
||||
path: ~/.npm/_logs
|
||||
test-doc-generation:
|
||||
docker:
|
||||
- image: nikolaik/python-nodejs:python3.7-nodejs8
|
||||
- image: nikolaik/python-nodejs:python3.7-nodejs10
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run:
|
||||
command: yarn test:generate_docs:circleci
|
||||
no_output_timeout: 1200
|
||||
command: yarn test:generate_docs:circleci
|
||||
no_output_timeout: 1200
|
||||
test-rest:
|
||||
docker:
|
||||
- image: nikolaik/python-nodejs:python3.7-nodejs8
|
||||
- image: nikolaik/python-nodejs:python3.7-nodejs10
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run: yarn wsrun test:circleci @0x/contracts-test-utils
|
||||
- run: yarn wsrun test:circleci @0x/abi-gen
|
||||
# TODO (xianny): Needs to be updated for 3.0
|
||||
# - run: yarn wsrun test:circleci @0x/asset-buyer
|
||||
# TODO: Needs to be updated for 3.0. At that time, also remove
|
||||
# exclusion from monorepo package.json's test script.
|
||||
# - run: yarn wsrun test:circleci @0x/asset-swapper
|
||||
- run: yarn wsrun test:circleci @0x/contract-artifacts
|
||||
- run: yarn wsrun test:circleci @0x/assert
|
||||
- run: yarn wsrun test:circleci @0x/base-contract
|
||||
# TODO (xianny): Needs to be updated for 3.0
|
||||
# - run: yarn wsrun test:circleci @0x/connect
|
||||
- run: yarn wsrun test:circleci @0x/contract-wrappers
|
||||
- run: yarn wsrun test:circleci @0x/dev-utils
|
||||
- run: yarn wsrun test:circleci @0x/json-schemas
|
||||
- run: yarn wsrun test:circleci @0x/contract-wrappers-test
|
||||
- run: yarn wsrun test:circleci @0x/migrations
|
||||
- run: yarn wsrun test:circleci @0x/order-utils
|
||||
# TODO: Needs to be updated for 3.0. At that time, also remove
|
||||
# exclusion from monorepo package.json's test script.
|
||||
# - run: yarn wsrun test:circleci @0x/orderbook
|
||||
- run: yarn wsrun test:circleci @0x/sol-compiler
|
||||
- run: yarn wsrun test:circleci @0x/sol-tracing-utils
|
||||
- run: yarn wsrun test:circleci @0x/sol-doc
|
||||
- run: yarn wsrun test:circleci @0x/subproviders
|
||||
- run: yarn wsrun test:circleci @0x/web3-wrapper
|
||||
- run: yarn wsrun test:circleci @0x/utils
|
||||
- run: yarn wsrun test:circleci @0x/instant
|
||||
- run: yarn wsrun test:circleci @0x/asset-swapper
|
||||
- save_cache:
|
||||
key: coverage-abi-gen-{{ .Environment.CIRCLE_SHA1 }}
|
||||
key: coverage-contract-wrappers-test-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- ~/repo/packages/abi-gen/coverage/lcov.info
|
||||
- save_cache:
|
||||
key: coverage-assert-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- ~/repo/packages/assert/coverage/lcov.info
|
||||
- save_cache:
|
||||
key: coverage-asset-buyer-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- ~/repo/packages/asset-buyer/coverage/lcov.info
|
||||
- save_cache:
|
||||
key: coverage-base-contract-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- ~/repo/packages/base-contract/coverage/lcov.info
|
||||
- save_cache:
|
||||
key: coverage-connect-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- ~/repo/packages/connect/coverage/lcov.info
|
||||
- save_cache:
|
||||
key: coverage-contract-wrappers-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- ~/repo/packages/contract-wrappers/coverage/lcov.info
|
||||
- save_cache:
|
||||
key: coverage-dev-utils-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- ~/repo/packages/dev-utils/coverage/lcov.info
|
||||
- save_cache:
|
||||
key: coverage-json-schemas-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- ~/repo/packages/json-schemas/coverage/lcov.info
|
||||
- ~/repo/packages/contract-wrappers-test/coverage/lcov.info
|
||||
- save_cache:
|
||||
key: coverage-order-utils-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- ~/repo/packages/order-utils/coverage/lcov.info
|
||||
- save_cache:
|
||||
key: coverage-sol-compiler-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- ~/repo/packages/sol-compiler/coverage/lcov.info
|
||||
- save_cache:
|
||||
key: coverage-sol-tracing-utils-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- ~/repo/packages/sol-tracing-utils/coverage/lcov.info
|
||||
- save_cache:
|
||||
key: coverage-sol-doc-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- ~/repo/packages/sol-doc/coverage/lcov.info
|
||||
- save_cache:
|
||||
key: coverage-subproviders-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- ~/repo/packages/subproviders/coverage/lcov.info
|
||||
- save_cache:
|
||||
key: coverage-web3-wrapper-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- ~/repo/packages/web3-wrapper/coverage/lcov.info
|
||||
test-python:
|
||||
working_directory: ~/repo
|
||||
docker:
|
||||
- image: nikolaik/python-nodejs:python3.7-nodejs8
|
||||
- image: 0xorg/ganache-cli:4.4.0-beta.1
|
||||
environment:
|
||||
VERSION: 4.4.0-beta.1
|
||||
SNAPSHOT_NAME: 0x_ganache_snapshot-v3-beta
|
||||
- image: 0xorg/mesh:6.0.0-beta-0xv3
|
||||
environment:
|
||||
ETHEREUM_RPC_URL: 'http://localhost:8545'
|
||||
ETHEREUM_NETWORK_ID: '50'
|
||||
ETHEREUM_CHAIN_ID: '1337'
|
||||
USE_BOOTSTRAP_LIST: 'true'
|
||||
VERBOSITY: 3
|
||||
PRIVATE_KEY_PATH: ''
|
||||
BLOCK_POLLING_INTERVAL: '5s'
|
||||
P2P_LISTEN_PORT: '60557'
|
||||
command: |
|
||||
sh -c "waitForGanache () { until printf 'POST /\r\nContent-Length: 26\r\n\r\n{\"method\":\"net_listening\"}' | nc localhost 8545 | grep true; do continue; done }; waitForGanache && ./mesh"
|
||||
- image: 0xorg/launch-kit-backend:v3
|
||||
environment:
|
||||
RPC_URL: 'http://localhost:8545'
|
||||
NETWORK_ID: 50
|
||||
WHITELIST_ALL_TOKENS: True
|
||||
FEE_RECIPIENT: '0x0000000000000000000000000000000000000001'
|
||||
MAKER_FEE_UNIT_AMOUNT: 0
|
||||
TAKER_FEE_UNIT_AMOUNT: 0
|
||||
MESH_ENDPOINT: 'ws://localhost:60557'
|
||||
command: |
|
||||
sh -c "waitForMesh () { sleep 5; }; waitForMesh && node_modules/.bin/forever ts/lib/index.js"
|
||||
steps:
|
||||
- checkout
|
||||
- restore_cache:
|
||||
key: installed-py-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run:
|
||||
command: |
|
||||
cd python-packages
|
||||
python -m ensurepip
|
||||
./pre_install
|
||||
./install
|
||||
- save_cache:
|
||||
key: installed-py-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- '/usr/local/bin'
|
||||
- '/usr/local/lib/python3.7/site-packages'
|
||||
- run:
|
||||
command: |
|
||||
cd python-packages
|
||||
./parallel coverage run setup.py test
|
||||
./build_docs
|
||||
- run:
|
||||
command: |
|
||||
# copy generated wrappers into contract_wrappers/build,
|
||||
# JUST so CircleCI will persist them as build artifacts.
|
||||
cd python-packages/contract_wrappers/src/zero_ex
|
||||
for i in contract_wrappers/[^__]*/; do mkdir -p ../../build/$i; cp $i/__init__.py ../../build/$i; done
|
||||
- save_cache:
|
||||
key: coverage-python-contract-addresses-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- ~/repo/python-packages/contract_addresses/.coverage
|
||||
- save_cache:
|
||||
key: coverage-python-contract-artifacts-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- ~/repo/python-packages/contract_artifacts/.coverage
|
||||
- save_cache:
|
||||
key: coverage-python-contract-demo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- ~/repo/python-packages/contract_demo/.coverage
|
||||
- save_cache:
|
||||
key: coverage-python-json-schemas-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- ~/repo/python-packages/json_schemas/.coverage
|
||||
- save_cache:
|
||||
key: coverage-python-order-utils-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- ~/repo/python-packages/order_utils/.coverage
|
||||
- save_cache:
|
||||
key: coverage-python-sra-client-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- ~/repo/python-packages/sra_client/.coverage
|
||||
- store_artifacts:
|
||||
path: ~/repo/python-packages/contract_addresses/build
|
||||
- store_artifacts:
|
||||
path: ~/repo/python-packages/contract_artifacts/build
|
||||
- store_artifacts:
|
||||
path: ~/repo/python-packages/contract_wrappers/build
|
||||
- store_artifacts:
|
||||
path: ~/repo/python-packages/json_schemas/build
|
||||
- store_artifacts:
|
||||
path: ~/repo/python-packages/middlewares/build
|
||||
- store_artifacts:
|
||||
path: ~/repo/python-packages/order_utils/build
|
||||
- store_artifacts:
|
||||
path: ~/repo/python-packages/sra_client/build
|
||||
test-rest-python:
|
||||
working_directory: ~/repo
|
||||
docker:
|
||||
- image: nikolaik/python-nodejs:python3.7-nodejs8
|
||||
steps:
|
||||
- checkout
|
||||
- restore_cache:
|
||||
key: installed-py-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run:
|
||||
command: |
|
||||
cd python-packages/order_utils
|
||||
python -m ensurepip
|
||||
python -m pip install .
|
||||
- save_cache:
|
||||
key: installed-py-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- '/usr/local/bin'
|
||||
- '/usr/local/lib/python3.7/site-packages'
|
||||
- '.eggs'
|
||||
- '.mypy_cache'
|
||||
- '.pytest_cache'
|
||||
- '.tox'
|
||||
- run:
|
||||
command: |
|
||||
cd python-packages/order_utils
|
||||
tox
|
||||
static-tests-python:
|
||||
working_directory: ~/repo
|
||||
docker:
|
||||
- image: nikolaik/python-nodejs:python3.7-nodejs8
|
||||
steps:
|
||||
- checkout
|
||||
- restore_cache:
|
||||
key: installed-py-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run:
|
||||
command: |
|
||||
python -m ensurepip
|
||||
cd python-packages
|
||||
./pre_install
|
||||
./install
|
||||
./lint
|
||||
static-tests:
|
||||
resource_class: large
|
||||
working_directory: ~/repo
|
||||
docker:
|
||||
- image: nikolaik/python-nodejs:python3.7-nodejs8
|
||||
- image: nikolaik/python-nodejs:python3.7-nodejs10
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
@@ -351,11 +143,9 @@ jobs:
|
||||
- run: yarn prettier:ci
|
||||
- run: yarn deps_versions:ci
|
||||
- run: yarn diff_md_docs:ci
|
||||
- run: cd packages/0x.js && yarn build:umd:prod
|
||||
- run: yarn bundlewatch
|
||||
submit-coverage:
|
||||
docker:
|
||||
- image: nikolaik/python-nodejs:python3.7-nodejs8
|
||||
- image: nikolaik/python-nodejs:python3.7-nodejs10
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- restore_cache:
|
||||
@@ -363,80 +153,33 @@ jobs:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- coverage-abi-gen-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- coverage-assert-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- coverage-asset-buyer-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- coverage-base-contract-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- coverage-connect-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- coverage-contract-wrappers-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- coverage-dev-utils-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- coverage-json-schemas-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- coverage-contract-wrappers-test-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- coverage-order-utils-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- coverage-sol-compiler-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- coverage-sol-tracing-utils-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- coverage-sol-doc-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- coverage-subproviders-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- coverage-web3-wrapper-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- coverage-contracts-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- coverage-python-json-schemas-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- coverage-python-contract-addresses-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- coverage-python-contract-artifacts-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- coverage-python-contract-demo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- coverage-python-sra-client-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- coverage-python-order-utils-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run: yarn report_coverage
|
||||
workflows:
|
||||
version: 2
|
||||
main:
|
||||
jobs:
|
||||
- build
|
||||
- test-exchange-ganache-3.0:
|
||||
requires:
|
||||
- build
|
||||
- test-integrations-ganache-3.0:
|
||||
requires:
|
||||
- build
|
||||
- test-contracts-rest-ganache-3.0:
|
||||
# Disabled until we begin actively developing on these packages again.
|
||||
# - test-exchange-ganache:
|
||||
# requires:
|
||||
# - build
|
||||
# - test-integrations-ganache:
|
||||
# requires:
|
||||
# - build
|
||||
# - test-contracts-staking-ganache:
|
||||
# requires:
|
||||
# - build
|
||||
# - test-contracts-extra-ganache:
|
||||
# requires:
|
||||
# - build
|
||||
- test-contracts-rest-ganache:
|
||||
requires:
|
||||
- build
|
||||
- test-rest:
|
||||
@@ -451,17 +194,14 @@ workflows:
|
||||
- test-doc-generation:
|
||||
requires:
|
||||
- build
|
||||
- submit-coverage:
|
||||
requires:
|
||||
- test-contracts-rest-ganache-3.0
|
||||
- test-exchange-ganache-3.0
|
||||
- test-rest
|
||||
- static-tests
|
||||
- test-python:
|
||||
requires:
|
||||
- build
|
||||
- static-tests-python:
|
||||
requires:
|
||||
- build
|
||||
# skip python tox run for now, as we don't yet have multiple test environments to support.
|
||||
# - test-rest-python
|
||||
# Disabled until this repo has a coveralls API key
|
||||
# - submit-coverage:
|
||||
# requires:
|
||||
# # Disabled until we begin actively developing on these packages again.
|
||||
# # - test-exchange-ganache
|
||||
# # - test-integrations-ganache
|
||||
# # - test-contracts-staking-ganache
|
||||
# # - test-contracts-extra-ganache
|
||||
# - test-contracts-rest-ganache
|
||||
# - test-rest
|
||||
# - static-tests
|
||||
|
||||
4
.gitattributes
vendored
4
.gitattributes
vendored
@@ -2,7 +2,3 @@
|
||||
|
||||
# Automatically collapse generated files in GitHub.
|
||||
*.svg linguist-generated=true
|
||||
packages/contract-artifacts/artifacts/*json linguist-generated=true
|
||||
packages/abi-gen-wrappers/src/generated-wrappers/*.ts linguist-generated=true
|
||||
packages/contract-wrappers/src/generated-wrappers/*.ts linguist-generated=true
|
||||
|
||||
|
||||
29
.github/autolabeler.yml
vendored
29
.github/autolabeler.yml
vendored
@@ -1,36 +1,7 @@
|
||||
python: ['python-packages']
|
||||
contracts: ['contracts']
|
||||
@0x/sol-doc: ['packages/sol-doc']
|
||||
@0x/sol-resolver: ['packages/sol-resolver']
|
||||
@0x/contracts-gen: ['packages/contracts-gen']
|
||||
@0x/sra-spec: ['packages/sra-spec']
|
||||
@0x/subproviders: ['packages/subproviders']
|
||||
@0x/contract-addresses: ['packages/contract-addresses']
|
||||
@0x/migrations: ['packages/migrations']
|
||||
@0x/web3-wrapper: ['packages/web3-wrapper']
|
||||
@0x/sol-compiler: ['packages/sol-compiler']
|
||||
@0x/types: ['packages/types']
|
||||
@0x/instant: ['packages/instant']
|
||||
@0x/abi-gen-templates: ['packages/abi-gen-templates']
|
||||
@0x/abi-gen: ['packages/abi-gen']
|
||||
@0x/sol-coverage: ['packages/sol-coverage']
|
||||
@0x/sol-profiler: ['packages/sol-profiler']
|
||||
@0x/sol-trace: ['packages/sol-trace']
|
||||
@0x/sol-tracing-utils: ['packages/sol-tracing-utils']
|
||||
@0x/utils: ['packages/utils']
|
||||
@0x/tslint-config: ['packages/tslint-config']
|
||||
@0x/asset-buyer: ['packages/asset-buyer']
|
||||
@0x/order-utils: ['packages/order-utils']
|
||||
@0x/assert: ['packages/assert']
|
||||
@0x/base-contract: ['packages/base-contract']
|
||||
@0x/typescript-typings: ['packages/typescript-typings']
|
||||
0x.js: ['packages/0x.js']
|
||||
@0x/abi-gen-wrappers: ['packages/abi-gen-wrappers']
|
||||
@0x/contract-artifacts: ['packages/contract-artifacts']
|
||||
@0x/dev-utils: ['packages/dev-utils']
|
||||
@0x/contract-wrappers: ['packages/contract-wrappers']
|
||||
@0x/json-schemas: ['packages/json-schemas']
|
||||
@0x/ethereum-types: ['ethereum-types']
|
||||
@0x/connect: ['packages/connect']
|
||||
@0x/testnet-faucets: ['packages/testnet-faucets']
|
||||
@0x/monorepo-scripts: ['packages/monorepo-scripts']
|
||||
|
||||
53
.github/workflows/publish.yml
vendored
Normal file
53
.github/workflows/publish.yml
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
name: publish
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
ci_status:
|
||||
description: 'required CI status'
|
||||
default: 'success'
|
||||
required: true
|
||||
prerelease:
|
||||
description: 'prerelease name'
|
||||
required: false
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: 'check successful status'
|
||||
run: |
|
||||
REF_STATUS=$(curl -s \
|
||||
'https://api.github.com/repos/${{ github.repository }}/commits/${{ github.ref }}/status' \
|
||||
| jq .state)
|
||||
[[ "${REF_STATUS}" == '"${{ github.event.inputs.ci_status }}"' ]] || \
|
||||
(echo "::error ::${{ github.ref }} does not have a successful CI status" && false)
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 10
|
||||
- uses: actions/setup-python@v2
|
||||
- name: 'configure git'
|
||||
run: |
|
||||
git config --global user.email "github-actions@github.com"
|
||||
git config --global user.name "Github Actions"
|
||||
- name: 'install dependencies'
|
||||
run: |
|
||||
yarn -D
|
||||
- name: 'build and publish'
|
||||
run: |
|
||||
echo '//registry.npmjs.org/:_authToken=${NPM_TOKEN}' > .npmrc
|
||||
npm run run:publish:gha
|
||||
env:
|
||||
NPM_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
PUBLISH_PRERELEASE: ${{ github.event.inputs.prerelease }}
|
||||
- name: 'merge into main branch'
|
||||
if: github.event.inputs.prerelease == '' # unless it's a prerelease
|
||||
run: |
|
||||
git checkout main && \
|
||||
git merge ${{ github.ref }} && \
|
||||
git push
|
||||
92
.gitignore
vendored
92
.gitignore
vendored
@@ -78,28 +78,47 @@ TODO.md
|
||||
# VSCode file
|
||||
.vscode
|
||||
|
||||
# server cli
|
||||
packages/testnet-faucets/server/
|
||||
|
||||
# generated contract artifacts/
|
||||
contracts/broker/generated-artifacts/
|
||||
contracts/broker/test/generated-artifacts/
|
||||
contracts/erc20-bridge-sampler/generated-artifacts/
|
||||
contracts/erc20-bridge-sampler/test/generated-artifacts/
|
||||
contracts/integrations/generated-artifacts/
|
||||
contracts/integrations/test/generated-artifacts/
|
||||
contracts/staking/generated-artifacts/
|
||||
contracts/staking/test/generated-artifacts/
|
||||
contracts/coordinator/generated-artifacts/
|
||||
contracts/coordinator/test/generated-artifacts/
|
||||
contracts/exchange/generated-artifacts/
|
||||
contracts/exchange/test/generated-artifacts/
|
||||
contracts/asset-proxy/generated-artifacts/
|
||||
contracts/asset-proxy/test/generated-artifacts/
|
||||
contracts/multisig/generated-artifacts/
|
||||
contracts/multisig/test/generated-artifacts/
|
||||
contracts/utils/generated-artifacts/
|
||||
contracts/utils/test/generated-artifacts/
|
||||
contracts/exchange-libs/generated-artifacts/
|
||||
contracts/exchange-libs/test/generated-artifacts/
|
||||
contracts/erc20/generated-artifacts/
|
||||
contracts/erc20/test/generated-artifacts/
|
||||
contracts/erc721/generated-artifacts/
|
||||
contracts/erc721/test/generated-artifacts/
|
||||
contracts/erc1155/generated-artifacts/
|
||||
contracts/erc1155/test/generated-artifacts/
|
||||
contracts/extensions/generated-artifacts/
|
||||
contracts/extensions/test/generated-artifacts/
|
||||
contracts/exchange-forwarder/generated-artifacts/
|
||||
contracts/exchange-forwarder/test/generated-artifacts/
|
||||
contracts/dev-utils/generated-artifacts/
|
||||
packages/sol-tracing-utils/test/fixtures/artifacts/
|
||||
python-packages/contract_artifacts/src/zero_ex/contract_artifacts/artifacts/
|
||||
contracts/dev-utils/test/generated-artifacts/
|
||||
contracts/zero-ex/generated-artifacts/
|
||||
contracts/zero-ex/test/generated-artifacts/
|
||||
contracts/treasury/generated-artifacts/
|
||||
contracts/treasury/test/generated-artifacts/
|
||||
|
||||
# generated truffle contract artifacts/
|
||||
contracts/broker/build/
|
||||
contracts/erc20-bridge-sampler/build/
|
||||
contracts/staking/build/
|
||||
contracts/coordinator/build/
|
||||
contracts/exchange/build/
|
||||
@@ -115,62 +134,43 @@ contracts/exchange-forwarder/build/
|
||||
contracts/dev-utils/build/
|
||||
|
||||
# generated contract wrappers
|
||||
contracts/broker/generated-wrappers/
|
||||
contracts/broker/test/generated-wrappers/
|
||||
packages/python-contract-wrappers/generated/
|
||||
contracts/erc20-bridge-sampler/generated-wrappers/
|
||||
contracts/erc20-bridge-sampler/test/generated-wrappers/
|
||||
contracts/integrations/generated-wrappers/
|
||||
contracts/integrations/test/generated-wrappers/
|
||||
contracts/staking/generated-wrappers/
|
||||
contracts/staking/test/generated-wrappers/
|
||||
contracts/coordinator/generated-wrappers/
|
||||
contracts/coordinator/test/generated-wrappers/
|
||||
contracts/exchange/generated-wrappers/
|
||||
contracts/exchange/test/generated-wrappers/
|
||||
contracts/asset-proxy/generated-wrappers/
|
||||
contracts/asset-proxy/test/generated-wrappers/
|
||||
contracts/multisig/generated-wrappers/
|
||||
contracts/multisig/test/generated-wrappers/
|
||||
contracts/utils/generated-wrappers/
|
||||
contracts/utils/test/generated-wrappers/
|
||||
contracts/exchange-libs/generated-wrappers/
|
||||
contracts/exchange-libs/test/generated-wrappers/
|
||||
contracts/erc20/generated-wrappers/
|
||||
contracts/erc20/test/generated-wrappers/
|
||||
contracts/erc721/generated-wrappers/
|
||||
contracts/erc721/test/generated-wrappers/
|
||||
contracts/erc1155/generated-wrappers/
|
||||
contracts/erc1155/test/generated-wrappers/
|
||||
contracts/extensions/generated-wrappers/
|
||||
contracts/extensions/test/generated-wrappers/
|
||||
contracts/exchange-forwarder/generated-wrappers/
|
||||
contracts/exchange-forwarder/test/generated-wrappers/
|
||||
contracts/dev-utils/generated-wrappers/
|
||||
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/dev_utils/__init__.py
|
||||
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/erc20_token/__init__.py
|
||||
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/exchange/__init__.py
|
||||
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/asset_proxy_owner/__init__.py
|
||||
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/coordinator/__init__.py
|
||||
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/coordinator_registry/__init__.py
|
||||
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/dummy_erc20_token/__init__.py
|
||||
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/dummy_erc721_token/__init__.py
|
||||
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/dutch_auction/__init__.py
|
||||
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/erc1155_mintable/__init__.py
|
||||
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/erc1155_proxy/__init__.py
|
||||
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/erc20_proxy/__init__.py
|
||||
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/erc721_proxy/__init__.py
|
||||
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/erc721_token/__init__.py
|
||||
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/eth_balance_checker/__init__.py
|
||||
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/forwarder/__init__.py
|
||||
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/i_asset_proxy/__init__.py
|
||||
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/i_validator/__init__.py
|
||||
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/i_wallet/__init__.py
|
||||
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/multi_asset_proxy/__init__.py
|
||||
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/order_validator/__init__.py
|
||||
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/static_call_proxy/__init__.py
|
||||
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/weth9/__init__.py
|
||||
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/zrx_token/__init__.py
|
||||
|
||||
# solc-bin in sol-compiler
|
||||
packages/sol-compiler/solc_bin/
|
||||
|
||||
# python stuff
|
||||
.eggs
|
||||
.mypy_cache
|
||||
.tox
|
||||
python-packages/*/build
|
||||
python-packages/*/dist
|
||||
__pycache__
|
||||
python-packages/*/src/*.egg-info
|
||||
python-packages/*/.coverage
|
||||
|
||||
# python keeps package-local copies of json schemas and contract addresses
|
||||
python-packages/json_schemas/src/zero_ex/json_schemas/schemas
|
||||
python-packages/contract_addresses/src/zero_ex/contract_addresses/addresses.json
|
||||
contracts/dev-utils/test/generated-wrappers/
|
||||
contracts/zero-ex/generated-wrappers/
|
||||
contracts/zero-ex/test/generated-wrappers/
|
||||
contracts/treasury/generated-wrappers/
|
||||
contracts/treasury/test/generated-wrappers/
|
||||
|
||||
# Doc README copy
|
||||
packages/*/docs/README.md
|
||||
|
||||
@@ -1,33 +1,73 @@
|
||||
lib
|
||||
.nyc_output
|
||||
/contracts/broker/generated-wrappers
|
||||
/contracts/broker/test/generated-wrappers
|
||||
/contracts/broker/generated-artifacts
|
||||
/contracts/broker/test/generated-artifacts
|
||||
/contracts/integrations/generated-wrappers
|
||||
/contracts/integrations/test/generated-wrappers
|
||||
/contracts/integrations/generated-artifacts
|
||||
/contracts/integrations/test/generated-artifacts
|
||||
/contracts/staking/generated-wrappers
|
||||
/contracts/staking/test/generated-wrappers
|
||||
/contracts/staking/generated-artifacts
|
||||
/contracts/staking/test/generated-artifacts
|
||||
/contracts/coordinator/generated-wrappers
|
||||
/contracts/coordinator/test/generated-wrappers
|
||||
/contracts/coordinator/generated-artifacts
|
||||
/contracts/coordinator/test/generated-artifacts
|
||||
/contracts/exchange/generated-wrappers
|
||||
/contracts/exchange/test/generated-wrappers
|
||||
/contracts/exchange/generated-artifacts
|
||||
/contracts/exchange/test/generated-artifacts
|
||||
/contracts/asset-proxy/generated-wrappers
|
||||
/contracts/asset-proxy/test/generated-wrappers
|
||||
/contracts/asset-proxy/generated-artifacts
|
||||
/contracts/asset-proxy/test/generated-artifacts
|
||||
/contracts/multisig/generated-wrappers
|
||||
/contracts/multisig/test/generated-wrappers
|
||||
/contracts/multisig/generated-artifacts
|
||||
/contracts/multisig/test/generated-artifacts
|
||||
/contracts/utils/generated-wrappers
|
||||
/contracts/utils/test/generated-wrappers
|
||||
/contracts/utils/generated-artifacts
|
||||
/contracts/utils/test/generated-artifacts
|
||||
/contracts/exchange-libs/generated-wrappers
|
||||
/contracts/exchange-libs/test/generated-wrappers
|
||||
/contracts/exchange-libs/generated-artifacts
|
||||
/contracts/exchange-libs/test/generated-artifacts
|
||||
/contracts/erc20/generated-wrappers
|
||||
/contracts/erc20/test/generated-wrappers
|
||||
/contracts/erc20/generated-artifacts
|
||||
/contracts/erc20/test/generated-artifacts
|
||||
/contracts/erc721/generated-wrappers
|
||||
/contracts/erc721/test/generated-wrappers
|
||||
/contracts/erc721/generated-artifacts
|
||||
/contracts/erc721/test/generated-artifacts
|
||||
/contracts/erc1155/generated-wrappers
|
||||
/contracts/erc1155/test/generated-wrappers
|
||||
/contracts/erc1155/generated-artifacts
|
||||
/contracts/erc1155/test/generated-artifacts
|
||||
/contracts/extensions/generated-wrappers
|
||||
/contracts/extensions/test/generated-wrappers
|
||||
/contracts/extensions/generated-artifacts
|
||||
/contracts/extensions/test/generated-artifacts
|
||||
/contracts/exchange-forwarder/generated-wrappers
|
||||
/contracts/exchange-forwarder/test/generated-wrappers
|
||||
/contracts/exchange-forwarder/generated-artifacts
|
||||
/contracts/exchange-forwarder/test/generated-artifacts
|
||||
/contracts/dev-utils/generated-wrappers
|
||||
/contracts/dev-utils/test/generated-wrappers
|
||||
/contracts/dev-utils/generated-artifacts
|
||||
/contracts/dev-utils/test/generated-artifacts
|
||||
/contracts/zero-ex/generated-wrappers
|
||||
/contracts/zero-ex/test/generated-wrappers
|
||||
/contracts/zero-ex/generated-artifacts
|
||||
/contracts/zero-ex/test/generated-artifacts
|
||||
/contracts/treasury/generated-wrappers
|
||||
/contracts/treasury/test/generated-wrappers
|
||||
/contracts/treasury/generated-artifacts
|
||||
/contracts/treasury/test/generated-artifacts
|
||||
/contracts/staking/build/
|
||||
/contracts/coordinator/build/
|
||||
/contracts/exchange/build/
|
||||
@@ -40,18 +80,11 @@ lib
|
||||
/contracts/erc1155/build/
|
||||
/contracts/extensions/build/
|
||||
/contracts/exchange-forwarder/build/
|
||||
/contracts/dev-utils/build/
|
||||
/packages/abi-gen/test-cli/output
|
||||
/packages/json-schemas/schemas
|
||||
/python-packages/json_schemas/src/zero_ex/json_schemas/schemas
|
||||
/packages/sra-spec/public/
|
||||
/packages/asset-swapper/generated-artifacts
|
||||
/packages/asset-swapper/generated-wrappers
|
||||
/packages/asset-swapper/test/generated-artifacts
|
||||
/packages/asset-swapper/test/generated-wrappers
|
||||
package.json
|
||||
scripts/postpublish_utils.js
|
||||
packages/sol-coverage/test/fixtures/artifacts
|
||||
.pytest_cache
|
||||
.mypy_cache
|
||||
.tox
|
||||
packages/abi-gen/test-cli/fixtures/artifacts/AbiGenDummy.json
|
||||
packages/abi-gen/test-cli/fixtures/artifacts/LibDummy.json
|
||||
packages/abi-gen/test-cli/fixtures/artifacts/TestLibDummy.json
|
||||
packages/*/docs
|
||||
docs/
|
||||
*.sol
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"tabWidth": 4,
|
||||
"printWidth": 120,
|
||||
"trailingComma": all,
|
||||
"singleQuote": true
|
||||
"tabWidth": 4,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "all",
|
||||
"bracketSpacing": true
|
||||
}
|
||||
|
||||
23
.readthedocs.yaml
Normal file
23
.readthedocs.yaml
Normal file
@@ -0,0 +1,23 @@
|
||||
# Read the Docs configuration file
|
||||
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
|
||||
|
||||
# Required
|
||||
version: 2
|
||||
|
||||
# Build documentation in the docs/ directory with Sphinx
|
||||
sphinx:
|
||||
configuration: docs/conf.py
|
||||
|
||||
# Build documentation with MkDocs
|
||||
#mkdocs:
|
||||
# configuration: mkdocs.yml
|
||||
|
||||
# Optionally build your docs in additional formats such as PDF
|
||||
#formats:
|
||||
# - pdf
|
||||
|
||||
# Optionally set the version of Python and requirements required to build your docs
|
||||
python:
|
||||
version: 3.7
|
||||
install:
|
||||
- requirements: docs/requirements.txt
|
||||
34
CODEOWNERS
34
CODEOWNERS
@@ -5,34 +5,14 @@
|
||||
# https://git-scm.com/docs/gitignore#_pattern_format
|
||||
|
||||
# Website
|
||||
packages/asset-buyer/ @BMillman19 @fragosti @steveklebanoff
|
||||
packages/instant/ @BMillman19 @fragosti @steveklebanoff
|
||||
packages/asset-swapper/ @BMillman19 @fragosti @dave4506
|
||||
packages/instant/ @BMillman19 @fragosti @dave4506
|
||||
|
||||
# Dev tools & setup
|
||||
.circleci/ @LogvinovLeon
|
||||
packages/abi-gen/ @feuGeneA
|
||||
packages/base-contract/ @xianny
|
||||
packages/connect/ @fragosti
|
||||
packages/abi-gen-templates/ @feuGeneA @xianny
|
||||
packages/contract-addresses/ @albrow
|
||||
packages/contract-artifacts/ @albrow
|
||||
packages/dev-utils/ @LogvinovLeon @fabioberger
|
||||
packages/devnet/ @albrow
|
||||
packages/ethereum-types/ @LogvinovLeon
|
||||
packages/monorepo-scripts/ @fabioberger
|
||||
packages/order-utils/ @fabioberger @LogvinovLeon
|
||||
packages/python-contract-wrappers/ @feuGeneA
|
||||
packages/sol-compiler/ @LogvinovLeon
|
||||
packages/sol-coverage/ @LogvinovLeon
|
||||
packages/sol-profiler/ @LogvinovLeon
|
||||
packages/sol-trace/ @LogvinovLeon
|
||||
packages/sol-tracing-utils/ @LogvinovLeon
|
||||
packages/sol-resolver/ @LogvinovLeon
|
||||
packages/subproviders/ @fabioberger @dekz
|
||||
packages/verdaccio/ @albrow
|
||||
packages/web3-wrapper/ @LogvinovLeon @fabioberger
|
||||
python-packages/ @feuGeneA
|
||||
packages/utils/ @hysz
|
||||
.circleci/ @dorothy-zbornak
|
||||
packages/contract-addresses/ @abandeali1
|
||||
packages/contract-artifacts/ @abandeali1
|
||||
packages/order-utils/ @dorothy-zbornak
|
||||
|
||||
# Protocol/smart contracts
|
||||
contracts/ @abandeali1 @hysz
|
||||
contracts/ @abandeali1 @hysz @dorothy-zbornak @mzhu25
|
||||
|
||||
@@ -4,9 +4,9 @@ We welcome contributions from anyone on the internet and are grateful for even t
|
||||
|
||||
### Getting started
|
||||
|
||||
1. Fork `0xproject/0x-monorepo`
|
||||
1. Fork `0xproject/0x-tools`
|
||||
2. Clone your fork
|
||||
3. Follow the [installation & build steps](https://github.com/0xProject/0x-monorepo#install-dependencies) in the repo's top-level README.
|
||||
3. Follow the [installation & build steps](https://github.com/0xProject/0x-tools#install-dependencies) in the repo's top-level README.
|
||||
4. Setup the recommended [Development Tooling](#development-tooling).
|
||||
5. Open a PR with the `[WIP]` flag against the `development` branch and describe the change you are intending to undertake in the PR description. (see [our branch naming conventions](#branch-structure))
|
||||
|
||||
@@ -59,11 +59,11 @@ We strongly recommend you use the [VSCode](https://code.visualstudio.com/) text
|
||||
|
||||
#### Linter
|
||||
|
||||
We use [TSLint](https://palantir.github.io/tslint/) with [custom configs](https://github.com/0xProject/0x-monorepo/tree/development/packages/tslint-config) to keep our code-style consistent.
|
||||
We use [TSLint](https://palantir.github.io/tslint/) with [custom configs](https://github.com/0xProject/0x-tools/tree/development/packages/tslint-config) to keep our code-style consistent.
|
||||
|
||||
Use `yarn:lint` to lint the entire monorepo, and `PKG={PACKAGE_NAME} yarn lint` to lint a specific package.
|
||||
|
||||
If you want to change a rule, or add a custom rule, please make these changes to our [tslint-config](https://github.com/0xProject/0x-monorepo/tree/development/packages/tslint-config) package. All other packages have it as a dependency.
|
||||
If you want to change a rule, or add a custom rule, please make these changes to our [tslint-config](https://github.com/0xProject/0x-tools/tree/development/packages/tslint-config) package. All other packages have it as a dependency.
|
||||
|
||||
Integrate it into your text editor:
|
||||
|
||||
@@ -94,12 +94,12 @@ A few of our coding conventions are not yet enforced by the linter/auto-formatte
|
||||
|
||||
### Fix `submit-coverage` CI failure
|
||||
|
||||
If you simply fork the repo and then create a PR from it, your PR will fail the `submit-coverage` check on CI. This is because the 0x CircleCI configuration sets the `COVERALLS_REPO_TOKEN` environment variable to the token for `0xProject/0x-monorepo`, but when running the check against your fork the token needs to match your repo's name `your-username/0x-monorepo`.
|
||||
If you simply fork the repo and then create a PR from it, your PR will fail the `submit-coverage` check on CI. This is because the 0x CircleCI configuration sets the `COVERALLS_REPO_TOKEN` environment variable to the token for `0xProject/0x-tools`, but when running the check against your fork the token needs to match your repo's name `your-username/0x-tools`.
|
||||
|
||||
To facilitate this check, after creating your fork, but before creating the branch for your PR, do the following:
|
||||
|
||||
1. Log in to [coveralls.io](https://coveralls.io/), go to `Add Repos`, and enable your fork. Then go to the settings for that repo, and copy the `Repo Token` identifier.
|
||||
2. Log in to [CircleCI](https://circleci.com/login), go to `Add Projects`, click the `Set Up Project` button corresponding to your fork, and then click `Start Building`. (Aside from step 3 below, no actual set up is needed, since it will use the `.circleci/config.yml` file in 0x-monorepo, so you can ignore all of the instruction/explanation given on the page with the `Start Building` button.)
|
||||
2. Log in to [CircleCI](https://circleci.com/login), go to `Add Projects`, click the `Set Up Project` button corresponding to your fork, and then click `Start Building`. (Aside from step 3 below, no actual set up is needed, since it will use the `.circleci/config.yml` file in 0x-tools, so you can ignore all of the instruction/explanation given on the page with the `Start Building` button.)
|
||||
3. In CircleCI, configure your project to add an environment variable, with name `COVERALLS_REPO_TOKEN`, and for the value paste in the `Repo Token` you copied in step 1.
|
||||
|
||||
Now, when you push to your branch, CircleCI will automatically run all of the checks in your own instance, and the coverage check will work since it has the proper `Repo Token`, and the PR will magically refer to your own checks rather than running them in the 0x CircleCI instance.
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -1,4 +1,4 @@
|
||||
Copyright 2017 ZeroEx Intl.
|
||||
Copyright 2020 ZeroEx Labs
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
||||
79
README.md
79
README.md
@@ -8,7 +8,7 @@ This repository is a monorepo including the 0x protocol smart contracts and nume
|
||||
|
||||
[website-url]: https://0x.org
|
||||
|
||||
[](https://circleci.com/gh/0xProject/0x-monorepo)
|
||||
[](https://circleci.com/gh/0xProject/protocool)
|
||||
[](https://coveralls.io/github/0xProject/0x-monorepo?branch=development)
|
||||
[](https://discordapp.com/invite/d3FTX3M)
|
||||
[](https://opensource.org/licenses/Apache-2.0)
|
||||
@@ -17,17 +17,6 @@ This repository is a monorepo including the 0x protocol smart contracts and nume
|
||||
|
||||
Visit our [developer portal](https://0x.org/docs/tools/order-utils) for a comprehensive list of core & community maintained packages. All packages maintained with this monorepo are listed below.
|
||||
|
||||
### Python Packages
|
||||
|
||||
| Package | Version | Description |
|
||||
| -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
|
||||
| [`0x-contract-addresses`](/python-packages/contract_addresses) | [](https://pypi.org/project/0x-contract-addresses/) | A tiny utility library for getting known deployed contract addresses for a particular network |
|
||||
| [`0x-contract-artifacts`](/python-packages/contract_artifacts) | [](https://pypi.org/project/0x-contract-artifacts/) | 0x smart contract compilation artifacts |
|
||||
| [`0x-contract-wrappers`](/python-packages/contract_wrappers) | [](https://pypi.org/project/0x-contract-wrappers/) | 0x smart contract wrappers |
|
||||
| [`0x-json-schemas`](/python-packages/json_schemas) | [](https://pypi.org/project/0x-json-schemas/) | 0x-related JSON schemas |
|
||||
| [`0x-order-utils`](/python-packages/order_utils) | [](https://pypi.org/project/0x-order-utils/) | A set of utilities for generating, parsing, signing and validating 0x orders |
|
||||
| [`0x-sra-client`](/python-packages/sra_client) | [](https://pypi.org/project/0x-sra-client/) | A Python client for interacting with servers conforming to the Standard Relayer API specification |
|
||||
|
||||
### Solidity Packages
|
||||
|
||||
These packages are all under development. See [/contracts/README.md](/contracts/README.md) for a list of deployed packages.
|
||||
@@ -53,53 +42,13 @@ These packages are all under development. See [/contracts/README.md](/contracts/
|
||||
|
||||
#### 0x-specific packages
|
||||
|
||||
| Package | Version | Description |
|
||||
| -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
|
||||
| [`0x.js`](/packages/0x.js) | [](https://www.npmjs.com/package/0x.js) | An aggregate package combining many smaller utility packages for interacting with the 0x protocol |
|
||||
| [`@0x/contract-addresses`](/packages/contract-addresses) | [](https://www.npmjs.com/package/@0x/contract-addresses) | A tiny utility library for getting known deployed contract addresses for a particular network. |
|
||||
| [`@0x/contract-wrappers`](/packages/contract-wrappers) | [](https://www.npmjs.com/package/@0x/contract-wrappers) | JS/TS wrappers for interacting with the 0x smart contracts |
|
||||
| [`@0x/order-utils`](/packages/order-utils) | [](https://www.npmjs.com/package/@0x/order-utils) | A set of utilities for generating, parsing, signing and validating 0x orders |
|
||||
| [`@0x/json-schemas`](/packages/json-schemas) | [](https://www.npmjs.com/package/@0x/json-schemas) | 0x-related JSON schemas | |
|
||||
| [`@0x/migrations`](/packages/migrations) | [](https://www.npmjs.com/package/@0x/migrations) | Migration tool for deploying 0x smart contracts on private testnets |
|
||||
| [`@0x/contract-artifacts`](/packages/contract-artifacts) | [](https://www.npmjs.com/package/@0x/contract-artifacts) | 0x smart contract compilation artifacts |
|
||||
| [`@0x/abi-gen-wrappers`](/packages/abi-gen-wrappers) | [](https://www.npmjs.com/package/@0x/abi-gen-wrappers) | Low-level 0x smart contract wrappers generated using `@0x/abi-gen` |
|
||||
| [`@0x/sra-spec`](/packages/sra-spec) | [](https://www.npmjs.com/package/@0x/sra-spec) | OpenAPI specification for the Standard Relayer API |
|
||||
| [`@0x/connect`](/packages/connect) | [](https://www.npmjs.com/package/@0x/connect) | An HTTP/WS client for interacting with the Standard Relayer API |
|
||||
| [`@0x/asset-buyer`](/packages/asset-buyer) | [](https://www.npmjs.com/package/@0x/asset-buyer) | Convenience package for discovering and buying assets with Ether |
|
||||
| [`@0x/asset-swapper`](/packages/asset-swapper) | [](https://www.npmjs.com/package/@0x/asset-swapper) | Convenience package for discovering and performing swaps for any ERC20 Assets |
|
||||
|
||||
#### Ethereum tooling
|
||||
|
||||
| Package | Version | Description |
|
||||
| -------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| [`@0x/web3-wrapper`](/packages/web3-wrapper) | [](https://www.npmjs.com/package/@0x/web3-wrapper) | An Ethereum JSON RPC client |
|
||||
| [`@0x/sol-compiler`](/packages/sol-compiler) | [](https://www.npmjs.com/package/@0x/sol-compiler) | A wrapper around solc-js that adds smart re-compilation, ability to compile an entire project, Solidity version specific compilation, standard input description support and much more. |
|
||||
| [`@0x/sol-coverage`](/packages/sol-coverage) | [](https://www.npmjs.com/package/@0x/sol-coverage) | A solidity test coverage tool |
|
||||
| [`@0x/sol-profiler`](/packages/sol-profiler) | [](https://www.npmjs.com/package/@0x/sol-profiler) | A solidity gas cost profiler |
|
||||
| [`@0x/sol-trace`](/packages/sol-trace) | [](https://www.npmjs.com/package/@0x/sol-trace) | A solidity stack trace tool |
|
||||
| [`@0x/sol-resolver`](/packages/sol-resolver) | [](https://www.npmjs.com/package/@0x/sol-resolver) | Import resolver for smart contracts dependencies |
|
||||
| [`@0x/subproviders`](/packages/subproviders) | [](https://www.npmjs.com/package/@0x/subproviders) | Web3 provider middlewares (e.g. LedgerSubprovider) |
|
||||
| [`@0x/sol-doc`](/packages/sol-doc) | [](https://www.npmjs.com/package/@0x/sol-doc) | Solidity documentation generator |
|
||||
|
||||
#### Utilities
|
||||
|
||||
| Package | Version | Description |
|
||||
| -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------- |
|
||||
| [`@0x/abi-gen`](/packages/abi-gen) | [](https://www.npmjs.com/package/@0x/abi-gen) | Tool to generate TS wrappers from smart contract ABIs |
|
||||
| [`@0x/tslint-config`](/packages/tslint-config) | [](https://www.npmjs.com/package/@0x/tslint-config) | Custom TSLint rules used by the 0x core team |
|
||||
| [`@0x/types`](/packages/types) | [](https://www.npmjs.com/package/@0x/types) | Shared type declarations |
|
||||
| [`@0x/typescript-typings`](/packages/typescript-typings) | [](https://www.npmjs.com/package/@0x/typescript-typings) | Repository of types for external packages |
|
||||
| [`@0x/utils`](/packages/utils) | [](https://www.npmjs.com/package/@0x/utils) | Shared utilities |
|
||||
| [`@0x/assert`](/packages/assert) | [](https://www.npmjs.com/package/@0x/assert) | Type and schema assertions used by our packages |
|
||||
| [`@0x/base-contract`](/packages/base-contract) | [](https://www.npmjs.com/package/@0x/base-contract) | BaseContract used by auto-generated `abi-gen` wrapper contracts |
|
||||
| [`@0x/dev-utils`](/packages/dev-utils) | [](https://www.npmjs.com/package/@0x/dev-utils) | Dev utils to be shared across 0x packages |
|
||||
|
||||
#### Private Packages
|
||||
|
||||
| Package | Description |
|
||||
| -------------------------------------------------- | -------------------------------------------------------------------------------- |
|
||||
| [`@0x/instant`](/packages/instant) | A free and flexible way to offer simple crypto purchasing in any app or website. |
|
||||
| [`@0x/testnet-faucets`](/packages/testnet-faucets) | A faucet micro-service that dispenses test ERC20 tokens or Ether |
|
||||
| Package | Version | Description |
|
||||
| -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
|
||||
| [`@0x/contract-addresses`](/packages/contract-addresses) | [](https://www.npmjs.com/package/@0x/contract-addresses) | A tiny utility library for getting known deployed contract addresses for a particular network. |
|
||||
| [`@0x/contract-wrappers`](/packages/contract-wrappers) | [](https://www.npmjs.com/package/@0x/contract-wrappers) | JS/TS wrappers for interacting with the 0x smart contracts |
|
||||
| [`@0x/order-utils`](/packages/order-utils) | [](https://www.npmjs.com/package/@0x/order-utils) | A set of utilities for generating, parsing, signing and validating 0x orders |
|
||||
| [`@0x/migrations`](/packages/migrations) | [](https://www.npmjs.com/package/@0x/migrations) | Migration tool for deploying 0x smart contracts on private testnets |
|
||||
| [`@0x/contract-artifacts`](/packages/contract-artifacts) | [](https://www.npmjs.com/package/@0x/contract-artifacts) | 0x smart contract compilation artifacts | |
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -132,8 +81,6 @@ Then install dependencies
|
||||
yarn install
|
||||
```
|
||||
|
||||
You will also need to have Python 3 installed, in order to build and run the tests of `abi-gen`'s command-line interface, which is integrated with the yarn build, yarn test, and yarn lint commands described below. More specifically, your local pip should resolve to the Python 3 version of pip, not a Python 2.x version.
|
||||
|
||||
### Build
|
||||
|
||||
To build all packages:
|
||||
@@ -145,7 +92,7 @@ yarn build
|
||||
To build a specific package:
|
||||
|
||||
```bash
|
||||
PKG=@0x/web3-wrapper yarn build
|
||||
PKG=@0x/contract-wrappers yarn build
|
||||
```
|
||||
|
||||
To build all contracts packages:
|
||||
@@ -168,7 +115,7 @@ To watch a specific package and all it's dependent packages:
|
||||
PKG=[NPM_PACKAGE_NAME] yarn watch
|
||||
|
||||
e.g
|
||||
PKG=@0x/web3-wrapper yarn watch
|
||||
PKG=@0x/contract-wrappers yarn watch
|
||||
```
|
||||
|
||||
### Clean
|
||||
@@ -196,7 +143,7 @@ yarn rebuild
|
||||
To re-build (clean & build) a specific package & it's deps:
|
||||
|
||||
```bash
|
||||
PKG=0x.js yarn rebuild
|
||||
PKG=@0x/contract-wrappers yarn rebuild
|
||||
```
|
||||
|
||||
### Lint
|
||||
@@ -210,7 +157,7 @@ yarn lint
|
||||
Lint a specific package:
|
||||
|
||||
```bash
|
||||
PKG=0x.js yarn lint
|
||||
PKG=@0x/contract-wrappers yarn lint
|
||||
```
|
||||
|
||||
### Run Tests
|
||||
@@ -224,7 +171,7 @@ yarn test
|
||||
Run a specific package's test:
|
||||
|
||||
```bash
|
||||
PKG=@0x/web3-wrapper yarn test
|
||||
PKG=@0x/contract-wrappers yarn test
|
||||
```
|
||||
|
||||
Run all contracts packages tests:
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
"quotes": ["error", "double"],
|
||||
"separate-by-one-line-in-contract": "error",
|
||||
"space-after-comma": "error",
|
||||
"statement-indent": "error"
|
||||
"statement-indent": "error",
|
||||
"no-empty-blocks": false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,4 +13,4 @@
|
||||
|
||||
#### Development
|
||||
|
||||
Building solidity files will update the contract artifact in `{package-name}/generated-artifacts/{contract}.json`, but does not automatically update the `abi-gen-wrappers` package, which are generated from the artifact JSON. To ensure consistency, clean and rebuild `abi-gen-wrappers` after any changes to the artifact JSON.
|
||||
Building solidity files will update the contract artifact in `{package-name}/generated-artifacts/{contract}.json`, but does not automatically update the `contract-artifacts` or `contract-wrappers` packages, which are generated from the artifact JSON. See `contract-artifacts/README.md` for instructions on updating these packages.
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
*
|
||||
# Whitelist lib
|
||||
!lib/**/*
|
||||
# Blacklist tests and publish scripts
|
||||
# Whitelist Solidity contracts
|
||||
!contracts/src/**/*
|
||||
# Blacklist tests in lib
|
||||
/lib/test/*
|
||||
/lib/monorepo_scripts/
|
||||
# Package specific ignore
|
||||
!_bundles/**/*
|
||||
@@ -1,4 +1,506 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1619596077,
|
||||
"version": "3.7.10",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1617311315,
|
||||
"version": "3.7.9",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1616005394,
|
||||
"version": "3.7.8",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1614141718,
|
||||
"version": "3.7.7",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1612950500,
|
||||
"version": "3.7.6",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1611648096,
|
||||
"version": "3.7.5",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1610510890,
|
||||
"version": "3.7.4",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1609802516,
|
||||
"version": "3.7.3",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1608692071,
|
||||
"version": "3.7.2",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1608245516,
|
||||
"version": "3.7.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "3.7.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Fix Bancor support of ETH",
|
||||
"pr": 88
|
||||
}
|
||||
],
|
||||
"timestamp": 1608105788
|
||||
},
|
||||
{
|
||||
"timestamp": 1607485227,
|
||||
"version": "3.6.9",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1607381756,
|
||||
"version": "3.6.8",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1606961263,
|
||||
"version": "3.6.7",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1605763885,
|
||||
"version": "3.6.6",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1605302002,
|
||||
"version": "3.6.5",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1604385937,
|
||||
"version": "3.6.4",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1604376968,
|
||||
"version": "3.6.3",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1604355662,
|
||||
"version": "3.6.2",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1603851023,
|
||||
"version": "3.6.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "3.6.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Add `SwerveBridge` and `SnowSwapBridge` (duplicate of `CurveBridge`)",
|
||||
"pr": 2707
|
||||
}
|
||||
],
|
||||
"timestamp": 1603833198
|
||||
},
|
||||
{
|
||||
"version": "3.5.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Update `CurveBridge` to support more varied curves",
|
||||
"pr": 2633
|
||||
},
|
||||
{
|
||||
"note": "Export DexForwarderBridgeContract",
|
||||
"pr": 2656
|
||||
},
|
||||
{
|
||||
"note": "Add BancorBridge and IBancorNetwork, ",
|
||||
"pr": 2650
|
||||
},
|
||||
{
|
||||
"note": "Added `MStableBridge`",
|
||||
"pr": 2662
|
||||
},
|
||||
{
|
||||
"note": "Added `MooniswapBridge`",
|
||||
"pr": 2675
|
||||
},
|
||||
{
|
||||
"note": "Reworked `KyberBridge`",
|
||||
"pr": 2683
|
||||
},
|
||||
{
|
||||
"note": "Added `CreamBridge`",
|
||||
"pr": 2715
|
||||
},
|
||||
{
|
||||
"note": "Added `ShellBridge`",
|
||||
"pr": 2722
|
||||
},
|
||||
{
|
||||
"note": "Added `DODOBridge`",
|
||||
"pr": 2701
|
||||
}
|
||||
],
|
||||
"timestamp": 1603265572
|
||||
},
|
||||
{
|
||||
"version": "3.4.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Fix instability with DFB.",
|
||||
"pr": 2616
|
||||
},
|
||||
{
|
||||
"note": "Add `BalancerBridge`",
|
||||
"pr": 2613
|
||||
}
|
||||
],
|
||||
"timestamp": 1594788383
|
||||
},
|
||||
{
|
||||
"version": "3.3.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Use `LibERC20Token.approveIfBelow()` in DEX bridges for for approvals.",
|
||||
"pr": 2512
|
||||
},
|
||||
{
|
||||
"note": "Emit `ERC20BridgeTransfer` events in bridges.",
|
||||
"pr": 2512
|
||||
},
|
||||
{
|
||||
"note": "Change names of `ERC20BridgeTransfer` args to be less ambiguous.",
|
||||
"pr": 2524
|
||||
},
|
||||
{
|
||||
"note": "Added `MixinGasToken` allowing Gas Tokens to be freed",
|
||||
"pr": 2523
|
||||
},
|
||||
{
|
||||
"note": "Add `DexForwaderBridge` bridge contract.",
|
||||
"pr": 2525
|
||||
},
|
||||
{
|
||||
"note": "Add `UniswapV2Bridge` bridge contract.",
|
||||
"pr": 2590
|
||||
},
|
||||
{
|
||||
"note": "Add Gas Token freeing to `DexForwarderBridge` contract.",
|
||||
"pr": 2536
|
||||
}
|
||||
],
|
||||
"timestamp": 1592969527
|
||||
},
|
||||
{
|
||||
"timestamp": 1583220306,
|
||||
"version": "3.2.5",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1582837861,
|
||||
"version": "3.2.4",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1582677073,
|
||||
"version": "3.2.3",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1582623685,
|
||||
"version": "3.2.2",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1581748629,
|
||||
"version": "3.2.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "3.2.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Add more types and functions to `IDydx`",
|
||||
"pr": 2466
|
||||
},
|
||||
{
|
||||
"note": "Rename `DydxBrigeAction.accountId` to `DydxBridgeAction.accountIdx`",
|
||||
"pr": 2466
|
||||
},
|
||||
{
|
||||
"note": "Fix broken tests.",
|
||||
"pr": 2462
|
||||
},
|
||||
{
|
||||
"note": "Remove dependency on `@0x/contracts-dev-utils`",
|
||||
"pr": 2462
|
||||
},
|
||||
{
|
||||
"note": "Add asset data decoding functions",
|
||||
"pr": 2462
|
||||
},
|
||||
{
|
||||
"note": "Add `setOperators()` to `IDydx`",
|
||||
"pr": 2462
|
||||
}
|
||||
],
|
||||
"timestamp": 1581204851
|
||||
},
|
||||
{
|
||||
"timestamp": 1580988106,
|
||||
"version": "3.1.3",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1580811564,
|
||||
"version": "3.1.2",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1579682890,
|
||||
"version": "3.1.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "3.1.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Integration tests for DydxBridge with ERC20BridgeProxy.",
|
||||
"pr": 2401
|
||||
},
|
||||
{
|
||||
"note": "Fix `UniswapBridge` token -> token transfer call.",
|
||||
"pr": 2412
|
||||
},
|
||||
{
|
||||
"note": "Fix `KyberBridge` incorrect `minConversionRate` calculation.",
|
||||
"pr": 2412
|
||||
}
|
||||
],
|
||||
"timestamp": 1578272714
|
||||
},
|
||||
{
|
||||
"timestamp": 1576540892,
|
||||
"version": "3.0.2",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1575931811,
|
||||
"version": "3.0.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "3.0.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Implement `KyberBridge`.",
|
||||
"pr": 2352
|
||||
},
|
||||
{
|
||||
"note": "Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils",
|
||||
"pr": 2330
|
||||
},
|
||||
{
|
||||
"note": "ERC20Wrapper and ERC1155ProxyWrapper constructors now require an instance of DevUtilsContract",
|
||||
"pr": 2034
|
||||
},
|
||||
{
|
||||
"note": "Disallow the zero address from being made an authorized address in MixinAuthorizable, and created an archive directory that includes an old version of Ownable",
|
||||
"pr": 2019
|
||||
},
|
||||
{
|
||||
"note": "Remove `LibAssetProxyIds` contract",
|
||||
"pr": 2055
|
||||
},
|
||||
{
|
||||
"note": "Compile and export all contracts, artifacts, and wrappers by default",
|
||||
"pr": 2055
|
||||
},
|
||||
{
|
||||
"note": "Remove unused dependency on IAuthorizable in IAssetProxy",
|
||||
"pr": 1910
|
||||
},
|
||||
{
|
||||
"note": "Add `ERC20BridgeProxy`",
|
||||
"pr": 2220
|
||||
},
|
||||
{
|
||||
"note": "Add `Eth2DaiBridge`",
|
||||
"pr": 2221
|
||||
},
|
||||
{
|
||||
"note": "Add `UniswapBridge`",
|
||||
"pr": 2233
|
||||
},
|
||||
{
|
||||
"note": "Replaced `SafeMath` with `LibSafeMath`",
|
||||
"pr": 2254
|
||||
}
|
||||
],
|
||||
"timestamp": 1575296764
|
||||
},
|
||||
{
|
||||
"version": "2.3.0-beta.4",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Implement `KyberBridge`.",
|
||||
"pr": 2352
|
||||
},
|
||||
{
|
||||
"note": "Implement `DydxBridge`.",
|
||||
"pr": 2365
|
||||
}
|
||||
],
|
||||
"timestamp": 1575290197
|
||||
},
|
||||
{
|
||||
"version": "2.3.0-beta.3",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
],
|
||||
"timestamp": 1574238768
|
||||
},
|
||||
{
|
||||
"version": "2.3.0-beta.2",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils",
|
||||
"pr": 2330
|
||||
}
|
||||
],
|
||||
"timestamp": 1574030254
|
||||
},
|
||||
{
|
||||
"version": "2.3.0-beta.1",
|
||||
"changes": [
|
||||
|
||||
@@ -5,6 +5,199 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v3.7.10 - _April 28, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.7.9 - _April 1, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.7.8 - _March 17, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.7.7 - _February 24, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.7.6 - _February 10, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.7.5 - _January 26, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.7.4 - _January 13, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.7.3 - _January 4, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.7.2 - _December 23, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.7.1 - _December 17, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.7.0 - _December 16, 2020_
|
||||
|
||||
* Fix Bancor support of ETH (#88)
|
||||
|
||||
## v3.6.9 - _December 9, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.6.8 - _December 7, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.6.7 - _December 3, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.6.6 - _November 19, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.6.5 - _November 13, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.6.4 - _November 3, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.6.3 - _November 3, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.6.2 - _November 2, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.6.1 - _October 28, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.6.0 - _October 27, 2020_
|
||||
|
||||
* Add `SwerveBridge` and `SnowSwapBridge` (duplicate of `CurveBridge`) (#2707)
|
||||
|
||||
## v3.5.0 - _October 21, 2020_
|
||||
|
||||
* Update `CurveBridge` to support more varied curves (#2633)
|
||||
* Export DexForwarderBridgeContract (#2656)
|
||||
* Add BancorBridge and IBancorNetwork, (#2650)
|
||||
* Added `MStableBridge` (#2662)
|
||||
* Added `MooniswapBridge` (#2675)
|
||||
* Reworked `KyberBridge` (#2683)
|
||||
* Added `CreamBridge` (#2715)
|
||||
* Added `ShellBridge` (#2722)
|
||||
* Added `DODOBridge` (#2701)
|
||||
|
||||
## v3.4.0 - _July 15, 2020_
|
||||
|
||||
* Fix instability with DFB. (#2616)
|
||||
* Add `BalancerBridge` (#2613)
|
||||
|
||||
## v3.3.0 - _June 24, 2020_
|
||||
|
||||
* Use `LibERC20Token.approveIfBelow()` in DEX bridges for for approvals. (#2512)
|
||||
* Emit `ERC20BridgeTransfer` events in bridges. (#2512)
|
||||
* Change names of `ERC20BridgeTransfer` args to be less ambiguous. (#2524)
|
||||
* Added `MixinGasToken` allowing Gas Tokens to be freed (#2523)
|
||||
* Add `DexForwaderBridge` bridge contract. (#2525)
|
||||
* Add `UniswapV2Bridge` bridge contract. (#2590)
|
||||
* Add Gas Token freeing to `DexForwarderBridge` contract. (#2536)
|
||||
|
||||
## v3.2.5 - _March 3, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.2.4 - _February 27, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.2.3 - _February 26, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.2.2 - _February 25, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.2.1 - _February 15, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.2.0 - _February 8, 2020_
|
||||
|
||||
* Add more types and functions to `IDydx` (#2466)
|
||||
* Rename `DydxBrigeAction.accountId` to `DydxBridgeAction.accountIdx` (#2466)
|
||||
* Fix broken tests. (#2462)
|
||||
* Remove dependency on `@0x/contracts-dev-utils` (#2462)
|
||||
* Add asset data decoding functions (#2462)
|
||||
* Add `setOperators()` to `IDydx` (#2462)
|
||||
|
||||
## v3.1.3 - _February 6, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.1.2 - _February 4, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.1.1 - _January 22, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.1.0 - _January 6, 2020_
|
||||
|
||||
* Integration tests for DydxBridge with ERC20BridgeProxy. (#2401)
|
||||
* Fix `UniswapBridge` token -> token transfer call. (#2412)
|
||||
* Fix `KyberBridge` incorrect `minConversionRate` calculation. (#2412)
|
||||
|
||||
## v3.0.2 - _December 17, 2019_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.0.1 - _December 9, 2019_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.0.0 - _December 2, 2019_
|
||||
|
||||
* Implement `KyberBridge`. (#2352)
|
||||
* Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils (#2330)
|
||||
* ERC20Wrapper and ERC1155ProxyWrapper constructors now require an instance of DevUtilsContract (#2034)
|
||||
* Disallow the zero address from being made an authorized address in MixinAuthorizable, and created an archive directory that includes an old version of Ownable (#2019)
|
||||
* Remove `LibAssetProxyIds` contract (#2055)
|
||||
* Compile and export all contracts, artifacts, and wrappers by default (#2055)
|
||||
* Remove unused dependency on IAuthorizable in IAssetProxy (#1910)
|
||||
* Add `ERC20BridgeProxy` (#2220)
|
||||
* Add `Eth2DaiBridge` (#2221)
|
||||
* Add `UniswapBridge` (#2233)
|
||||
* Replaced `SafeMath` with `LibSafeMath` (#2254)
|
||||
|
||||
## v2.3.0-beta.4 - _December 2, 2019_
|
||||
|
||||
* Implement `KyberBridge`. (#2352)
|
||||
* Implement `DydxBridge`. (#2365)
|
||||
|
||||
## v2.3.0-beta.3 - _November 20, 2019_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v2.3.0-beta.2 - _November 17, 2019_
|
||||
|
||||
* Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils (#2330)
|
||||
|
||||
## v2.3.0-beta.1 - _November 7, 2019_
|
||||
|
||||
* ERC20Wrapper and ERC1155ProxyWrapper constructors now require an instance of DevUtilsContract (#2034)
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
{
|
||||
"artifactsDir": "./generated-artifacts",
|
||||
"artifactsDir": "./test/generated-artifacts",
|
||||
"contractsDir": "./contracts",
|
||||
"useDockerisedSolc": false,
|
||||
"isOfflineMode": false,
|
||||
"shouldSaveStandardInput": true,
|
||||
"compilerSettings": {
|
||||
"evmVersion": "constantinople",
|
||||
"evmVersion": "istanbul",
|
||||
"optimizer": {
|
||||
"enabled": true,
|
||||
"runs": 1000000,
|
||||
|
||||
103
contracts/asset-proxy/contracts/src/bridges/BalancerBridge.sol
Normal file
103
contracts/asset-proxy/contracts/src/bridges/BalancerBridge.sol
Normal file
@@ -0,0 +1,103 @@
|
||||
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
|
||||
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
|
||||
import "../interfaces/IERC20Bridge.sol";
|
||||
import "../interfaces/IBalancerPool.sol";
|
||||
|
||||
|
||||
contract BalancerBridge is
|
||||
IERC20Bridge,
|
||||
IWallet,
|
||||
DeploymentConstants
|
||||
{
|
||||
/// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of
|
||||
/// `toTokenAddress` tokens by selling the entirety of the `fromTokenAddress`
|
||||
/// token encoded in the bridge data, then transfers the bought
|
||||
/// tokens to `to`.
|
||||
/// @param toTokenAddress The token to buy and transfer to `to`.
|
||||
/// @param from The maker (this contract).
|
||||
/// @param to The recipient of the bought tokens.
|
||||
/// @param amount Minimum amount of `toTokenAddress` tokens to buy.
|
||||
/// @param bridgeData The abi-encoded addresses of the "from" token and Balancer pool.
|
||||
/// @return success The magic bytes if successful.
|
||||
function bridgeTransferFrom(
|
||||
address toTokenAddress,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes calldata bridgeData
|
||||
)
|
||||
external
|
||||
returns (bytes4 success)
|
||||
{
|
||||
// Decode the bridge data.
|
||||
(address fromTokenAddress, address poolAddress) = abi.decode(
|
||||
bridgeData,
|
||||
(address, address)
|
||||
);
|
||||
require(toTokenAddress != fromTokenAddress, "BalancerBridge/INVALID_PAIR");
|
||||
|
||||
uint256 fromTokenBalance = IERC20Token(fromTokenAddress).balanceOf(address(this));
|
||||
// Grant an allowance to the exchange to spend `fromTokenAddress` token.
|
||||
LibERC20Token.approveIfBelow(fromTokenAddress, poolAddress, fromTokenBalance);
|
||||
|
||||
// Sell all of this contract's `fromTokenAddress` token balance.
|
||||
(uint256 boughtAmount,) = IBalancerPool(poolAddress).swapExactAmountIn(
|
||||
fromTokenAddress, // tokenIn
|
||||
fromTokenBalance, // tokenAmountIn
|
||||
toTokenAddress, // tokenOut
|
||||
amount, // minAmountOut
|
||||
uint256(-1) // maxPrice
|
||||
);
|
||||
|
||||
// Transfer the converted `toToken`s to `to`.
|
||||
LibERC20Token.transfer(toTokenAddress, to, boughtAmount);
|
||||
|
||||
emit ERC20BridgeTransfer(
|
||||
fromTokenAddress,
|
||||
toTokenAddress,
|
||||
fromTokenBalance,
|
||||
boughtAmount,
|
||||
from,
|
||||
to
|
||||
);
|
||||
return BRIDGE_SUCCESS;
|
||||
}
|
||||
|
||||
/// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
|
||||
/// and sign for itself in orders. Always succeeds.
|
||||
/// @return magicValue Magic success bytes, always.
|
||||
function isValidSignature(
|
||||
bytes32,
|
||||
bytes calldata
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (bytes4 magicValue)
|
||||
{
|
||||
return LEGACY_WALLET_MAGIC_VALUE;
|
||||
}
|
||||
}
|
||||
144
contracts/asset-proxy/contracts/src/bridges/BancorBridge.sol
Normal file
144
contracts/asset-proxy/contracts/src/bridges/BancorBridge.sol
Normal file
@@ -0,0 +1,144 @@
|
||||
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
|
||||
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
|
||||
import "../interfaces/IERC20Bridge.sol";
|
||||
import "../interfaces/IBancorNetwork.sol";
|
||||
|
||||
|
||||
contract BancorBridge is
|
||||
IERC20Bridge,
|
||||
IWallet,
|
||||
DeploymentConstants
|
||||
{
|
||||
struct TransferState {
|
||||
address bancorNetworkAddress;
|
||||
address[] path;
|
||||
IEtherToken weth;
|
||||
}
|
||||
|
||||
/// @dev Bancor ETH pseudo-address.
|
||||
address constant public BANCOR_ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
|
||||
|
||||
// solhint-disable no-empty-blocks
|
||||
/// @dev Payable fallback to receive ETH from Bancor/WETH.
|
||||
function ()
|
||||
external
|
||||
payable
|
||||
{
|
||||
// Poor man's receive in 0.5.9
|
||||
require(msg.data.length == 0);
|
||||
}
|
||||
|
||||
/// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of
|
||||
/// `toTokenAddress` tokens by selling the entirety of the `fromTokenAddress`
|
||||
/// token encoded in the bridge data, then transfers the bought
|
||||
/// tokens to `to`.
|
||||
/// @param toTokenAddress The token to buy and transfer to `to`.
|
||||
/// @param from The maker (this contract).
|
||||
/// @param to The recipient of the bought tokens.
|
||||
/// @param amount Minimum amount of `toTokenAddress` tokens to buy.
|
||||
/// @param bridgeData The abi-encoded conversion path addresses and Bancor network address
|
||||
/// @return success The magic bytes if successful.
|
||||
function bridgeTransferFrom(
|
||||
address toTokenAddress,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes calldata bridgeData
|
||||
)
|
||||
external
|
||||
returns (bytes4 success)
|
||||
{
|
||||
// hold variables to get around stack depth limitations
|
||||
TransferState memory state;
|
||||
// Decode the bridge data.
|
||||
(
|
||||
state.path,
|
||||
state.bancorNetworkAddress
|
||||
// solhint-disable indent
|
||||
) = abi.decode(bridgeData, (address[], address));
|
||||
// solhint-enable indent
|
||||
state.weth = IEtherToken(_getWethAddress());
|
||||
|
||||
require(state.path.length >= 2, "BancorBridge/PATH_LENGTH_MUST_BE_GREATER_THAN_TWO");
|
||||
|
||||
// Grant an allowance to the Bancor Network to spend `fromTokenAddress` token.
|
||||
uint256 fromTokenBalance;
|
||||
uint256 payableAmount = 0;
|
||||
// If it's ETH in the path then withdraw from WETH
|
||||
// The Bancor path will have ETH as the 0xeee address
|
||||
// Bancor expects to be paid in ETH not WETH
|
||||
if (state.path[0] == BANCOR_ETH_ADDRESS) {
|
||||
fromTokenBalance = state.weth.balanceOf(address(this));
|
||||
state.weth.withdraw(fromTokenBalance);
|
||||
payableAmount = fromTokenBalance;
|
||||
} else {
|
||||
fromTokenBalance = IERC20Token(state.path[0]).balanceOf(address(this));
|
||||
LibERC20Token.approveIfBelow(state.path[0], state.bancorNetworkAddress, fromTokenBalance);
|
||||
}
|
||||
|
||||
// Convert the tokens
|
||||
uint256 boughtAmount = IBancorNetwork(state.bancorNetworkAddress).convertByPath.value(payableAmount)(
|
||||
state.path, // path originating with source token and terminating in destination token
|
||||
fromTokenBalance, // amount of source token to trade
|
||||
amount, // minimum amount of destination token expected to receive
|
||||
state.path[state.path.length-1] == BANCOR_ETH_ADDRESS ? address(this) : to, // beneficiary
|
||||
address(0), // affiliateAccount; no fee paid
|
||||
0 // affiliateFee; no fee paid
|
||||
);
|
||||
|
||||
if (state.path[state.path.length-1] == BANCOR_ETH_ADDRESS) {
|
||||
state.weth.deposit.value(boughtAmount)();
|
||||
state.weth.transfer(to, boughtAmount);
|
||||
}
|
||||
|
||||
emit ERC20BridgeTransfer(
|
||||
state.path[0] == BANCOR_ETH_ADDRESS ? address(state.weth) : state.path[0],
|
||||
toTokenAddress,
|
||||
fromTokenBalance,
|
||||
boughtAmount,
|
||||
from,
|
||||
to
|
||||
);
|
||||
return BRIDGE_SUCCESS;
|
||||
}
|
||||
|
||||
/// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
|
||||
/// and sign for itself in orders. Always succeeds.
|
||||
/// @return magicValue Magic success bytes, always.
|
||||
function isValidSignature(
|
||||
bytes32,
|
||||
bytes calldata
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (bytes4 magicValue)
|
||||
{
|
||||
return LEGACY_WALLET_MAGIC_VALUE;
|
||||
}
|
||||
|
||||
}
|
||||
75
contracts/asset-proxy/contracts/src/bridges/ChaiBridge.sol
Normal file
75
contracts/asset-proxy/contracts/src/bridges/ChaiBridge.sol
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "../interfaces/IERC20Bridge.sol";
|
||||
import "../interfaces/IChai.sol";
|
||||
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||
|
||||
|
||||
// solhint-disable space-after-comma
|
||||
contract ChaiBridge is
|
||||
IERC20Bridge,
|
||||
DeploymentConstants
|
||||
{
|
||||
/// @dev Withdraws `amount` of `from` address's Dai from the Chai contract.
|
||||
/// Transfers `amount` of Dai to `to` address.
|
||||
/// @param from Address to transfer asset from.
|
||||
/// @param to Address to transfer asset to.
|
||||
/// @param amount Amount of asset to transfer.
|
||||
/// @return success The magic bytes `0xdc1600f3` if successful.
|
||||
function bridgeTransferFrom(
|
||||
address /* tokenAddress */,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes calldata /* bridgeData */
|
||||
)
|
||||
external
|
||||
returns (bytes4 success)
|
||||
{
|
||||
// Ensure that only the `ERC20BridgeProxy` can call this function.
|
||||
require(
|
||||
msg.sender == _getERC20BridgeProxyAddress(),
|
||||
"ChaiBridge/ONLY_CALLABLE_BY_ERC20_BRIDGE_PROXY"
|
||||
);
|
||||
|
||||
// Withdraw `from` address's Dai.
|
||||
// NOTE: This contract must be approved to spend Chai on behalf of `from`.
|
||||
bytes memory drawCalldata = abi.encodeWithSelector(
|
||||
IChai(address(0)).draw.selector,
|
||||
from,
|
||||
amount
|
||||
);
|
||||
|
||||
(bool success,) = _getChaiAddress().call(drawCalldata);
|
||||
require(
|
||||
success,
|
||||
"ChaiBridge/DRAW_DAI_FAILED"
|
||||
);
|
||||
|
||||
// Transfer Dai to `to`
|
||||
// This will never fail if the `draw` call was successful
|
||||
IERC20Token(_getDaiAddress()).transfer(to, amount);
|
||||
|
||||
return BRIDGE_SUCCESS;
|
||||
}
|
||||
}
|
||||
103
contracts/asset-proxy/contracts/src/bridges/CreamBridge.sol
Normal file
103
contracts/asset-proxy/contracts/src/bridges/CreamBridge.sol
Normal file
@@ -0,0 +1,103 @@
|
||||
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
|
||||
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
|
||||
import "../interfaces/IERC20Bridge.sol";
|
||||
import "../interfaces/IBalancerPool.sol";
|
||||
|
||||
|
||||
contract CreamBridge is
|
||||
IERC20Bridge,
|
||||
IWallet,
|
||||
DeploymentConstants
|
||||
{
|
||||
/// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of
|
||||
/// `toTokenAddress` tokens by selling the entirety of the `fromTokenAddress`
|
||||
/// token encoded in the bridge data, then transfers the bought
|
||||
/// tokens to `to`.
|
||||
/// @param toTokenAddress The token to buy and transfer to `to`.
|
||||
/// @param from The maker (this contract).
|
||||
/// @param to The recipient of the bought tokens.
|
||||
/// @param amount Minimum amount of `toTokenAddress` tokens to buy.
|
||||
/// @param bridgeData The abi-encoded addresses of the "from" token and Balancer pool.
|
||||
/// @return success The magic bytes if successful.
|
||||
function bridgeTransferFrom(
|
||||
address toTokenAddress,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes calldata bridgeData
|
||||
)
|
||||
external
|
||||
returns (bytes4 success)
|
||||
{
|
||||
// Decode the bridge data.
|
||||
(address fromTokenAddress, address poolAddress) = abi.decode(
|
||||
bridgeData,
|
||||
(address, address)
|
||||
);
|
||||
require(toTokenAddress != fromTokenAddress, "CreamBridge/INVALID_PAIR");
|
||||
|
||||
uint256 fromTokenBalance = IERC20Token(fromTokenAddress).balanceOf(address(this));
|
||||
// Grant an allowance to the exchange to spend `fromTokenAddress` token.
|
||||
LibERC20Token.approveIfBelow(fromTokenAddress, poolAddress, fromTokenBalance);
|
||||
|
||||
// Sell all of this contract's `fromTokenAddress` token balance.
|
||||
(uint256 boughtAmount,) = IBalancerPool(poolAddress).swapExactAmountIn(
|
||||
fromTokenAddress, // tokenIn
|
||||
fromTokenBalance, // tokenAmountIn
|
||||
toTokenAddress, // tokenOut
|
||||
amount, // minAmountOut
|
||||
uint256(-1) // maxPrice
|
||||
);
|
||||
|
||||
// Transfer the converted `toToken`s to `to`.
|
||||
LibERC20Token.transfer(toTokenAddress, to, boughtAmount);
|
||||
|
||||
emit ERC20BridgeTransfer(
|
||||
fromTokenAddress,
|
||||
toTokenAddress,
|
||||
fromTokenBalance,
|
||||
boughtAmount,
|
||||
from,
|
||||
to
|
||||
);
|
||||
return BRIDGE_SUCCESS;
|
||||
}
|
||||
|
||||
/// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
|
||||
/// and sign for itself in orders. Always succeeds.
|
||||
/// @return magicValue Magic success bytes, always.
|
||||
function isValidSignature(
|
||||
bytes32,
|
||||
bytes calldata
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (bytes4 magicValue)
|
||||
{
|
||||
return LEGACY_WALLET_MAGIC_VALUE;
|
||||
}
|
||||
}
|
||||
136
contracts/asset-proxy/contracts/src/bridges/CryptoComBridge.sol
Normal file
136
contracts/asset-proxy/contracts/src/bridges/CryptoComBridge.sol
Normal file
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibAddressArray.sol";
|
||||
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
|
||||
import "../interfaces/IUniswapV2Router01.sol";
|
||||
import "../interfaces/IERC20Bridge.sol";
|
||||
|
||||
|
||||
// solhint-disable space-after-comma
|
||||
// solhint-disable not-rely-on-time
|
||||
contract CryptoComBridge is
|
||||
IERC20Bridge,
|
||||
IWallet,
|
||||
DeploymentConstants
|
||||
{
|
||||
struct TransferState {
|
||||
address[] path;
|
||||
address router;
|
||||
uint256 fromTokenBalance;
|
||||
}
|
||||
|
||||
/// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of
|
||||
/// `toTokenAddress` tokens by selling the entirety of the `fromTokenAddress`
|
||||
/// token encoded in the bridge data.
|
||||
/// @param toTokenAddress The token to buy and transfer to `to`.
|
||||
/// @param from The maker (this contract).
|
||||
/// @param to The recipient of the bought tokens.
|
||||
/// @param amount Minimum amount of `toTokenAddress` tokens to buy.
|
||||
/// @param bridgeData The abi-encoded path of token addresses. Last element must be toTokenAddress
|
||||
/// @return success The magic bytes if successful.
|
||||
function bridgeTransferFrom(
|
||||
address toTokenAddress,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes calldata bridgeData
|
||||
)
|
||||
external
|
||||
returns (bytes4 success)
|
||||
{
|
||||
// hold variables to get around stack depth limitations
|
||||
TransferState memory state;
|
||||
|
||||
// Decode the bridge data to get the `fromTokenAddress`.
|
||||
// solhint-disable indent
|
||||
(state.path, state.router) = abi.decode(bridgeData, (address[], address));
|
||||
// solhint-enable indent
|
||||
|
||||
require(state.path.length >= 2, "CryptoComBridge/PATH_LENGTH_MUST_BE_AT_LEAST_TWO");
|
||||
require(state.path[state.path.length - 1] == toTokenAddress, "CryptoComBridge/LAST_ELEMENT_OF_PATH_MUST_MATCH_OUTPUT_TOKEN");
|
||||
|
||||
// Just transfer the tokens if they're the same.
|
||||
if (state.path[0] == toTokenAddress) {
|
||||
LibERC20Token.transfer(state.path[0], to, amount);
|
||||
return BRIDGE_SUCCESS;
|
||||
}
|
||||
|
||||
// Get our balance of `fromTokenAddress` token.
|
||||
state.fromTokenBalance = IERC20Token(state.path[0]).balanceOf(address(this));
|
||||
|
||||
// Grant the SushiSwap router an allowance.
|
||||
LibERC20Token.approveIfBelow(
|
||||
state.path[0],
|
||||
state.router,
|
||||
state.fromTokenBalance
|
||||
);
|
||||
|
||||
// Buy as much `toTokenAddress` token with `fromTokenAddress` token
|
||||
// and transfer it to `to`.
|
||||
IUniswapV2Router01 router = IUniswapV2Router01(state.router);
|
||||
uint[] memory amounts = router.swapExactTokensForTokens(
|
||||
// Sell all tokens we hold.
|
||||
state.fromTokenBalance,
|
||||
// Minimum buy amount.
|
||||
amount,
|
||||
// Convert `fromTokenAddress` to `toTokenAddress`.
|
||||
state.path,
|
||||
// Recipient is `to`.
|
||||
to,
|
||||
// Expires after this block.
|
||||
block.timestamp
|
||||
);
|
||||
|
||||
emit ERC20BridgeTransfer(
|
||||
// input token
|
||||
state.path[0],
|
||||
// output token
|
||||
toTokenAddress,
|
||||
// input token amount
|
||||
state.fromTokenBalance,
|
||||
// output token amount
|
||||
amounts[amounts.length - 1],
|
||||
from,
|
||||
to
|
||||
);
|
||||
|
||||
return BRIDGE_SUCCESS;
|
||||
}
|
||||
|
||||
/// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
|
||||
/// and sign for itself in orders. Always succeeds.
|
||||
/// @return magicValue Success bytes, always.
|
||||
function isValidSignature(
|
||||
bytes32,
|
||||
bytes calldata
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (bytes4 magicValue)
|
||||
{
|
||||
return LEGACY_WALLET_MAGIC_VALUE;
|
||||
}
|
||||
}
|
||||
119
contracts/asset-proxy/contracts/src/bridges/CurveBridge.sol
Normal file
119
contracts/asset-proxy/contracts/src/bridges/CurveBridge.sol
Normal file
@@ -0,0 +1,119 @@
|
||||
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
|
||||
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
|
||||
import "../interfaces/IERC20Bridge.sol";
|
||||
import "../interfaces/ICurve.sol";
|
||||
|
||||
|
||||
// solhint-disable not-rely-on-time
|
||||
// solhint-disable space-after-comma
|
||||
contract CurveBridge is
|
||||
IERC20Bridge,
|
||||
IWallet,
|
||||
DeploymentConstants
|
||||
{
|
||||
struct CurveBridgeData {
|
||||
address curveAddress;
|
||||
bytes4 exchangeFunctionSelector;
|
||||
address fromTokenAddress;
|
||||
int128 fromCoinIdx;
|
||||
int128 toCoinIdx;
|
||||
}
|
||||
|
||||
/// @dev Callback for `ICurve`. Tries to buy `amount` of
|
||||
/// `toTokenAddress` tokens by selling the entirety of the opposing asset
|
||||
/// (DAI, USDC) to the Curve contract, then transfers the bought
|
||||
/// tokens to `to`.
|
||||
/// @param toTokenAddress The token to give to `to` (i.e DAI, USDC, USDT).
|
||||
/// @param from The maker (this contract).
|
||||
/// @param to The recipient of the bought tokens.
|
||||
/// @param amount Minimum amount of `toTokenAddress` tokens to buy.
|
||||
/// @param bridgeData The abi-encoeded "from" token address.
|
||||
/// @return success The magic bytes if successful.
|
||||
function bridgeTransferFrom(
|
||||
address toTokenAddress,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes calldata bridgeData
|
||||
)
|
||||
external
|
||||
returns (bytes4 success)
|
||||
{
|
||||
// Decode the bridge data to get the Curve metadata.
|
||||
CurveBridgeData memory data = abi.decode(bridgeData, (CurveBridgeData));
|
||||
|
||||
require(toTokenAddress != data.fromTokenAddress, "CurveBridge/INVALID_PAIR");
|
||||
uint256 fromTokenBalance = IERC20Token(data.fromTokenAddress).balanceOf(address(this));
|
||||
// Grant an allowance to the exchange to spend `fromTokenAddress` token.
|
||||
LibERC20Token.approveIfBelow(data.fromTokenAddress, data.curveAddress, fromTokenBalance);
|
||||
|
||||
// Try to sell all of this contract's `fromTokenAddress` token balance.
|
||||
{
|
||||
(bool didSucceed, bytes memory resultData) =
|
||||
data.curveAddress.call(abi.encodeWithSelector(
|
||||
data.exchangeFunctionSelector,
|
||||
data.fromCoinIdx,
|
||||
data.toCoinIdx,
|
||||
// dx
|
||||
fromTokenBalance,
|
||||
// min dy
|
||||
amount
|
||||
));
|
||||
if (!didSucceed) {
|
||||
assembly { revert(add(resultData, 32), mload(resultData)) }
|
||||
}
|
||||
}
|
||||
|
||||
uint256 toTokenBalance = IERC20Token(toTokenAddress).balanceOf(address(this));
|
||||
// Transfer the converted `toToken`s to `to`.
|
||||
LibERC20Token.transfer(toTokenAddress, to, toTokenBalance);
|
||||
|
||||
emit ERC20BridgeTransfer(
|
||||
data.fromTokenAddress,
|
||||
toTokenAddress,
|
||||
fromTokenBalance,
|
||||
toTokenBalance,
|
||||
from,
|
||||
to
|
||||
);
|
||||
return BRIDGE_SUCCESS;
|
||||
}
|
||||
|
||||
/// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
|
||||
/// and sign for itself in orders. Always succeeds.
|
||||
/// @return magicValue Magic success bytes, always.
|
||||
function isValidSignature(
|
||||
bytes32,
|
||||
bytes calldata
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (bytes4 magicValue)
|
||||
{
|
||||
return LEGACY_WALLET_MAGIC_VALUE;
|
||||
}
|
||||
}
|
||||
147
contracts/asset-proxy/contracts/src/bridges/DODOBridge.sol
Normal file
147
contracts/asset-proxy/contracts/src/bridges/DODOBridge.sol
Normal file
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
|
||||
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
|
||||
import "../interfaces/IERC20Bridge.sol";
|
||||
|
||||
|
||||
interface IDODOHelper {
|
||||
|
||||
function querySellQuoteToken(address dodo, uint256 amount) external view returns (uint256);
|
||||
}
|
||||
|
||||
|
||||
interface IDODO {
|
||||
|
||||
function sellBaseToken(uint256 amount, uint256 minReceiveQuote, bytes calldata data) external returns (uint256);
|
||||
|
||||
function buyBaseToken(uint256 amount, uint256 maxPayQuote, bytes calldata data) external returns (uint256);
|
||||
|
||||
}
|
||||
|
||||
|
||||
contract DODOBridge is
|
||||
IERC20Bridge,
|
||||
IWallet,
|
||||
DeploymentConstants
|
||||
{
|
||||
|
||||
struct TransferState {
|
||||
address fromTokenAddress;
|
||||
uint256 fromTokenBalance;
|
||||
address pool;
|
||||
bool isSellBase;
|
||||
}
|
||||
|
||||
/// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of
|
||||
/// `toTokenAddress` tokens by selling the entirety of the `fromTokenAddress`
|
||||
/// token encoded in the bridge data.
|
||||
/// @param toTokenAddress The token to buy and transfer to `to`.
|
||||
/// @param from The maker (this contract).
|
||||
/// @param to The recipient of the bought tokens.
|
||||
/// @param amount Minimum amount of `toTokenAddress` tokens to buy.
|
||||
/// @param bridgeData The abi-encoded path of token addresses. Last element must be toTokenAddress
|
||||
/// @return success The magic bytes if successful.
|
||||
function bridgeTransferFrom(
|
||||
address toTokenAddress,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes calldata bridgeData
|
||||
)
|
||||
external
|
||||
returns (bytes4 success)
|
||||
{
|
||||
TransferState memory state;
|
||||
// Decode the bridge data to get the `fromTokenAddress`.
|
||||
(state.fromTokenAddress, state.pool, state.isSellBase) = abi.decode(bridgeData, (address, address, bool));
|
||||
require(state.pool != address(0), "DODOBridge/InvalidPool");
|
||||
IDODO exchange = IDODO(state.pool);
|
||||
// Get our balance of `fromTokenAddress` token.
|
||||
state.fromTokenBalance = IERC20Token(state.fromTokenAddress).balanceOf(address(this));
|
||||
|
||||
// Grant the pool an allowance.
|
||||
LibERC20Token.approveIfBelow(
|
||||
state.fromTokenAddress,
|
||||
address(exchange),
|
||||
state.fromTokenBalance
|
||||
);
|
||||
|
||||
uint256 boughtAmount;
|
||||
if (state.isSellBase) {
|
||||
boughtAmount = exchange.sellBaseToken(
|
||||
// amount to sell
|
||||
state.fromTokenBalance,
|
||||
// min receive amount
|
||||
1,
|
||||
new bytes(0)
|
||||
);
|
||||
} else {
|
||||
// Need to re-calculate the sell quote amount into buyBase
|
||||
boughtAmount = IDODOHelper(_getDODOHelperAddress()).querySellQuoteToken(
|
||||
address(exchange),
|
||||
state.fromTokenBalance
|
||||
);
|
||||
exchange.buyBaseToken(
|
||||
// amount to buy
|
||||
boughtAmount,
|
||||
// max pay amount
|
||||
state.fromTokenBalance,
|
||||
new bytes(0)
|
||||
);
|
||||
}
|
||||
// Transfer funds to `to`
|
||||
IERC20Token(toTokenAddress).transfer(to, boughtAmount);
|
||||
|
||||
|
||||
emit ERC20BridgeTransfer(
|
||||
// input token
|
||||
state.fromTokenAddress,
|
||||
// output token
|
||||
toTokenAddress,
|
||||
// input token amount
|
||||
state.fromTokenBalance,
|
||||
// output token amount
|
||||
boughtAmount,
|
||||
from,
|
||||
to
|
||||
);
|
||||
|
||||
return BRIDGE_SUCCESS;
|
||||
}
|
||||
|
||||
/// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
|
||||
/// and sign for itself in orders. Always succeeds.
|
||||
/// @return magicValue Success bytes, always.
|
||||
function isValidSignature(
|
||||
bytes32,
|
||||
bytes calldata
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (bytes4 magicValue)
|
||||
{
|
||||
return LEGACY_WALLET_MAGIC_VALUE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol";
|
||||
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
|
||||
import "../interfaces/IERC20Bridge.sol";
|
||||
import "./MixinGasToken.sol";
|
||||
|
||||
|
||||
// solhint-disable space-after-comma, indent
|
||||
contract DexForwarderBridge is
|
||||
IERC20Bridge,
|
||||
IWallet,
|
||||
DeploymentConstants,
|
||||
MixinGasToken
|
||||
{
|
||||
using LibSafeMath for uint256;
|
||||
|
||||
/// @dev Data needed to reconstruct a bridge call.
|
||||
struct BridgeCall {
|
||||
address target;
|
||||
uint256 inputTokenAmount;
|
||||
uint256 outputTokenAmount;
|
||||
bytes bridgeData;
|
||||
}
|
||||
|
||||
/// @dev Intermediate state variables used by `bridgeTransferFrom()`, in
|
||||
/// struct form to get around stack limits.
|
||||
struct TransferFromState {
|
||||
address inputToken;
|
||||
uint256 initialInputTokenBalance;
|
||||
uint256 callInputTokenAmount;
|
||||
uint256 callOutputTokenAmount;
|
||||
uint256 totalInputTokenSold;
|
||||
BridgeCall[] calls;
|
||||
}
|
||||
|
||||
/// @dev Spends this contract's entire balance of input tokens by forwarding
|
||||
/// them to other bridges. Reverts if the entire balance is not spent.
|
||||
/// @param outputToken The token being bought.
|
||||
/// @param to The recipient of the bought tokens.
|
||||
/// @param bridgeData The abi-encoded input token address.
|
||||
/// @return success The magic bytes if successful.
|
||||
function bridgeTransferFrom(
|
||||
address outputToken,
|
||||
address /* from */,
|
||||
address to,
|
||||
uint256 /* amount */,
|
||||
bytes calldata bridgeData
|
||||
)
|
||||
external
|
||||
freesGasTokensFromCollector
|
||||
returns (bytes4 success)
|
||||
{
|
||||
require(
|
||||
msg.sender == _getERC20BridgeProxyAddress(),
|
||||
"DexForwarderBridge/SENDER_NOT_AUTHORIZED"
|
||||
);
|
||||
TransferFromState memory state;
|
||||
(
|
||||
state.inputToken,
|
||||
state.calls
|
||||
) = abi.decode(bridgeData, (address, BridgeCall[]));
|
||||
|
||||
state.initialInputTokenBalance =
|
||||
IERC20Token(state.inputToken).balanceOf(address(this));
|
||||
|
||||
for (uint256 i = 0; i < state.calls.length; ++i) {
|
||||
// Stop if the we've sold all our input tokens.
|
||||
if (state.totalInputTokenSold >= state.initialInputTokenBalance) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Compute token amounts.
|
||||
state.callInputTokenAmount = LibSafeMath.min256(
|
||||
state.calls[i].inputTokenAmount,
|
||||
state.initialInputTokenBalance.safeSub(state.totalInputTokenSold)
|
||||
);
|
||||
state.callOutputTokenAmount = LibMath.getPartialAmountFloor(
|
||||
state.callInputTokenAmount,
|
||||
state.calls[i].inputTokenAmount,
|
||||
state.calls[i].outputTokenAmount
|
||||
);
|
||||
|
||||
// Execute the call in a new context so we can recoup transferred
|
||||
// funds by reverting.
|
||||
(bool didSucceed, ) = address(this)
|
||||
.call(abi.encodeWithSelector(
|
||||
this.executeBridgeCall.selector,
|
||||
state.calls[i].target,
|
||||
to,
|
||||
state.inputToken,
|
||||
outputToken,
|
||||
state.callInputTokenAmount,
|
||||
state.callOutputTokenAmount,
|
||||
state.calls[i].bridgeData
|
||||
));
|
||||
|
||||
if (didSucceed) {
|
||||
// Increase the amount of tokens sold.
|
||||
state.totalInputTokenSold = state.totalInputTokenSold.safeAdd(
|
||||
state.callInputTokenAmount
|
||||
);
|
||||
}
|
||||
}
|
||||
// Always succeed.
|
||||
return BRIDGE_SUCCESS;
|
||||
}
|
||||
|
||||
/// @dev Transfers `inputToken` token to a bridge contract then calls
|
||||
/// its `bridgeTransferFrom()`. This is executed in separate context
|
||||
/// so we can revert the transfer on error. This can only be called
|
||||
// by this contract itself.
|
||||
/// @param bridge The bridge contract.
|
||||
/// @param to The recipient of `outputToken` tokens.
|
||||
/// @param inputToken The input token.
|
||||
/// @param outputToken The output token.
|
||||
/// @param inputTokenAmount The amount of input tokens to transfer to `bridge`.
|
||||
/// @param outputTokenAmount The amount of expected output tokens to be sent
|
||||
/// to `to` by `bridge`.
|
||||
function executeBridgeCall(
|
||||
address bridge,
|
||||
address to,
|
||||
address inputToken,
|
||||
address outputToken,
|
||||
uint256 inputTokenAmount,
|
||||
uint256 outputTokenAmount,
|
||||
bytes calldata bridgeData
|
||||
)
|
||||
external
|
||||
{
|
||||
// Must be called through `bridgeTransferFrom()`.
|
||||
require(msg.sender == address(this), "DexForwarderBridge/ONLY_SELF");
|
||||
// `bridge` must not be this contract.
|
||||
require(bridge != address(this));
|
||||
|
||||
// Get the starting balance of output tokens for `to`.
|
||||
uint256 initialRecipientBalance = IERC20Token(outputToken).balanceOf(to);
|
||||
|
||||
// Transfer input tokens to the bridge.
|
||||
LibERC20Token.transfer(inputToken, bridge, inputTokenAmount);
|
||||
|
||||
// Call the bridge.
|
||||
(bool didSucceed, bytes memory resultData) =
|
||||
bridge.call(abi.encodeWithSelector(
|
||||
IERC20Bridge(0).bridgeTransferFrom.selector,
|
||||
outputToken,
|
||||
bridge,
|
||||
to,
|
||||
outputTokenAmount,
|
||||
bridgeData
|
||||
));
|
||||
|
||||
// Revert if the call failed or not enough tokens were bought.
|
||||
// This will also undo the token transfer.
|
||||
require(
|
||||
didSucceed
|
||||
&& resultData.length == 32
|
||||
&& LibBytes.readBytes32(resultData, 0) == bytes32(BRIDGE_SUCCESS)
|
||||
&& IERC20Token(outputToken).balanceOf(to).safeSub(initialRecipientBalance) >= outputTokenAmount
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
|
||||
/// and sign for itself in orders. Always succeeds.
|
||||
/// @return magicValue Magic success bytes, always.
|
||||
function isValidSignature(
|
||||
bytes32,
|
||||
bytes calldata
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (bytes4 magicValue)
|
||||
{
|
||||
return LEGACY_WALLET_MAGIC_VALUE;
|
||||
}
|
||||
}
|
||||
242
contracts/asset-proxy/contracts/src/bridges/DydxBridge.sol
Normal file
242
contracts/asset-proxy/contracts/src/bridges/DydxBridge.sol
Normal file
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol";
|
||||
import "../interfaces/IERC20Bridge.sol";
|
||||
import "../interfaces/IDydxBridge.sol";
|
||||
import "../interfaces/IDydx.sol";
|
||||
|
||||
|
||||
contract DydxBridge is
|
||||
IERC20Bridge,
|
||||
IDydxBridge,
|
||||
DeploymentConstants
|
||||
{
|
||||
|
||||
using LibSafeMath for uint256;
|
||||
|
||||
/// @dev Callback for `IERC20Bridge`. Deposits or withdraws tokens from a dydx account.
|
||||
/// Notes:
|
||||
/// 1. This bridge must be set as an operator of the input dydx account.
|
||||
/// 2. This function may only be called in the context of the 0x Exchange.
|
||||
/// 3. The maker or taker of the 0x order must be the dydx account owner.
|
||||
/// 4. Deposits into dydx are made from the `from` address.
|
||||
/// 5. Withdrawals from dydx are made to the `to` address.
|
||||
/// 6. Calling this function must always withdraw at least `amount`,
|
||||
/// otherwise the `ERC20Bridge` will revert.
|
||||
/// @param from The sender of the tokens and owner of the dydx account.
|
||||
/// @param to The recipient of the tokens.
|
||||
/// @param amount Minimum amount of `toTokenAddress` tokens to deposit or withdraw.
|
||||
/// @param encodedBridgeData An abi-encoded `BridgeData` struct.
|
||||
/// @return success The magic bytes if successful.
|
||||
function bridgeTransferFrom(
|
||||
address, /* toTokenAddress */
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes calldata encodedBridgeData
|
||||
)
|
||||
external
|
||||
returns (bytes4 success)
|
||||
{
|
||||
// Ensure that only the `ERC20BridgeProxy` can call this function.
|
||||
require(
|
||||
msg.sender == _getERC20BridgeProxyAddress(),
|
||||
"DydxBridge/ONLY_CALLABLE_BY_ERC20_BRIDGE_PROXY"
|
||||
);
|
||||
|
||||
// Decode bridge data.
|
||||
(BridgeData memory bridgeData) = abi.decode(encodedBridgeData, (BridgeData));
|
||||
|
||||
// The dydx accounts are owned by the `from` address.
|
||||
IDydx.AccountInfo[] memory accounts = _createAccounts(from, bridgeData);
|
||||
|
||||
// Create dydx actions to run on the dydx accounts.
|
||||
IDydx.ActionArgs[] memory actions = _createActions(
|
||||
from,
|
||||
to,
|
||||
amount,
|
||||
bridgeData
|
||||
);
|
||||
|
||||
// Run operation. This will revert on failure.
|
||||
IDydx(_getDydxAddress()).operate(accounts, actions);
|
||||
|
||||
return BRIDGE_SUCCESS;
|
||||
}
|
||||
|
||||
/// @dev Creates an array of accounts for dydx to operate on.
|
||||
/// All accounts must belong to the same owner.
|
||||
/// @param accountOwner Owner of the dydx account.
|
||||
/// @param bridgeData A `BridgeData` struct.
|
||||
function _createAccounts(
|
||||
address accountOwner,
|
||||
BridgeData memory bridgeData
|
||||
)
|
||||
internal
|
||||
returns (IDydx.AccountInfo[] memory accounts)
|
||||
{
|
||||
uint256[] memory accountNumbers = bridgeData.accountNumbers;
|
||||
uint256 nAccounts = accountNumbers.length;
|
||||
accounts = new IDydx.AccountInfo[](nAccounts);
|
||||
for (uint256 i = 0; i < nAccounts; ++i) {
|
||||
accounts[i] = IDydx.AccountInfo({
|
||||
owner: accountOwner,
|
||||
number: accountNumbers[i]
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Creates an array of actions to carry out on dydx.
|
||||
/// @param depositFrom Deposit value from this address (owner of the dydx account).
|
||||
/// @param withdrawTo Withdraw value to this address.
|
||||
/// @param amount The amount of value available to operate on.
|
||||
/// @param bridgeData A `BridgeData` struct.
|
||||
function _createActions(
|
||||
address depositFrom,
|
||||
address withdrawTo,
|
||||
uint256 amount,
|
||||
BridgeData memory bridgeData
|
||||
)
|
||||
internal
|
||||
returns (IDydx.ActionArgs[] memory actions)
|
||||
{
|
||||
BridgeAction[] memory bridgeActions = bridgeData.actions;
|
||||
uint256 nBridgeActions = bridgeActions.length;
|
||||
actions = new IDydx.ActionArgs[](nBridgeActions);
|
||||
for (uint256 i = 0; i < nBridgeActions; ++i) {
|
||||
// Cache current bridge action.
|
||||
BridgeAction memory bridgeAction = bridgeActions[i];
|
||||
|
||||
// Scale amount, if conversion rate is set.
|
||||
uint256 scaledAmount;
|
||||
if (bridgeAction.conversionRateDenominator > 0) {
|
||||
scaledAmount = LibMath.safeGetPartialAmountFloor(
|
||||
bridgeAction.conversionRateNumerator,
|
||||
bridgeAction.conversionRateDenominator,
|
||||
amount
|
||||
);
|
||||
} else {
|
||||
scaledAmount = amount;
|
||||
}
|
||||
|
||||
// Construct dydx action.
|
||||
if (bridgeAction.actionType == BridgeActionType.Deposit) {
|
||||
// Deposit tokens from the account owner into their dydx account.
|
||||
actions[i] = _createDepositAction(
|
||||
depositFrom,
|
||||
scaledAmount,
|
||||
bridgeAction
|
||||
);
|
||||
} else if (bridgeAction.actionType == BridgeActionType.Withdraw) {
|
||||
// Withdraw tokens from dydx to the `otherAccount`.
|
||||
actions[i] = _createWithdrawAction(
|
||||
withdrawTo,
|
||||
scaledAmount,
|
||||
bridgeAction
|
||||
);
|
||||
} else {
|
||||
// If all values in the `Action` enum are handled then this
|
||||
// revert is unreachable: Solidity will revert when casting
|
||||
// from `uint8` to `Action`.
|
||||
revert("DydxBridge/UNRECOGNIZED_BRIDGE_ACTION");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Returns a dydx `DepositAction`.
|
||||
/// @param depositFrom Deposit tokens from this address who is also the account owner.
|
||||
/// @param amount of tokens to deposit.
|
||||
/// @param bridgeAction A `BridgeAction` struct.
|
||||
/// @return depositAction The encoded dydx action.
|
||||
function _createDepositAction(
|
||||
address depositFrom,
|
||||
uint256 amount,
|
||||
BridgeAction memory bridgeAction
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (
|
||||
IDydx.ActionArgs memory depositAction
|
||||
)
|
||||
{
|
||||
// Create dydx amount.
|
||||
IDydx.AssetAmount memory dydxAmount = IDydx.AssetAmount({
|
||||
sign: true, // true if positive.
|
||||
denomination: IDydx.AssetDenomination.Wei, // Wei => actual token amount held in account.
|
||||
ref: IDydx.AssetReference.Delta, // Delta => a relative amount.
|
||||
value: amount // amount to deposit.
|
||||
});
|
||||
|
||||
// Create dydx deposit action.
|
||||
depositAction = IDydx.ActionArgs({
|
||||
actionType: IDydx.ActionType.Deposit, // deposit tokens.
|
||||
amount: dydxAmount, // amount to deposit.
|
||||
accountIdx: bridgeAction.accountIdx, // index in the `accounts` when calling `operate`.
|
||||
primaryMarketId: bridgeAction.marketId, // indicates which token to deposit.
|
||||
otherAddress: depositFrom, // deposit from the account owner.
|
||||
// unused parameters
|
||||
secondaryMarketId: 0,
|
||||
otherAccountIdx: 0,
|
||||
data: hex''
|
||||
});
|
||||
}
|
||||
|
||||
/// @dev Returns a dydx `WithdrawAction`.
|
||||
/// @param withdrawTo Withdraw tokens to this address.
|
||||
/// @param amount of tokens to withdraw.
|
||||
/// @param bridgeAction A `BridgeAction` struct.
|
||||
/// @return withdrawAction The encoded dydx action.
|
||||
function _createWithdrawAction(
|
||||
address withdrawTo,
|
||||
uint256 amount,
|
||||
BridgeAction memory bridgeAction
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (
|
||||
IDydx.ActionArgs memory withdrawAction
|
||||
)
|
||||
{
|
||||
// Create dydx amount.
|
||||
IDydx.AssetAmount memory amountToWithdraw = IDydx.AssetAmount({
|
||||
sign: false, // false if negative.
|
||||
denomination: IDydx.AssetDenomination.Wei, // Wei => actual token amount held in account.
|
||||
ref: IDydx.AssetReference.Delta, // Delta => a relative amount.
|
||||
value: amount // amount to withdraw.
|
||||
});
|
||||
|
||||
// Create withdraw action.
|
||||
withdrawAction = IDydx.ActionArgs({
|
||||
actionType: IDydx.ActionType.Withdraw, // withdraw tokens.
|
||||
amount: amountToWithdraw, // amount to withdraw.
|
||||
accountIdx: bridgeAction.accountIdx, // index in the `accounts` when calling `operate`.
|
||||
primaryMarketId: bridgeAction.marketId, // indicates which token to withdraw.
|
||||
otherAddress: withdrawTo, // withdraw tokens to this address.
|
||||
// unused parameters
|
||||
secondaryMarketId: 0,
|
||||
otherAccountIdx: 0,
|
||||
data: hex''
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,7 @@ pragma experimental ABIEncoderV2;
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
|
||||
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
|
||||
import "../interfaces/IERC20Bridge.sol";
|
||||
import "../interfaces/IEth2Dai.sol";
|
||||
|
||||
@@ -29,23 +30,22 @@ import "../interfaces/IEth2Dai.sol";
|
||||
// solhint-disable space-after-comma
|
||||
contract Eth2DaiBridge is
|
||||
IERC20Bridge,
|
||||
IWallet
|
||||
IWallet,
|
||||
DeploymentConstants
|
||||
{
|
||||
/* Mainnet addresses */
|
||||
address constant public ETH2DAI_ADDRESS = 0x39755357759cE0d7f32dC8dC45414CCa409AE24e;
|
||||
|
||||
/// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of
|
||||
/// `toTokenAddress` tokens by selling the entirety of the opposing asset
|
||||
/// (DAI or WETH) to the Eth2Dai contract, then transfers the bought
|
||||
/// tokens to `to`.
|
||||
/// @param toTokenAddress The token to give to `to` (either DAI or WETH).
|
||||
/// @param from The maker (this contract).
|
||||
/// @param to The recipient of the bought tokens.
|
||||
/// @param amount Minimum amount of `toTokenAddress` tokens to buy.
|
||||
/// @param bridgeData The abi-encoeded "from" token address.
|
||||
/// @return success The magic bytes if successful.
|
||||
function bridgeTransferFrom(
|
||||
address toTokenAddress,
|
||||
address /* from */,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes calldata bridgeData
|
||||
@@ -56,19 +56,29 @@ contract Eth2DaiBridge is
|
||||
// Decode the bridge data to get the `fromTokenAddress`.
|
||||
(address fromTokenAddress) = abi.decode(bridgeData, (address));
|
||||
|
||||
IEth2Dai exchange = _getEth2DaiContract();
|
||||
IEth2Dai exchange = IEth2Dai(_getEth2DaiAddress());
|
||||
uint256 fromTokenBalance = IERC20Token(fromTokenAddress).balanceOf(address(this));
|
||||
// Grant an allowance to the exchange to spend `fromTokenAddress` token.
|
||||
LibERC20Token.approve(fromTokenAddress, address(exchange), uint256(-1));
|
||||
LibERC20Token.approveIfBelow(fromTokenAddress, address(exchange), fromTokenBalance);
|
||||
|
||||
// Try to sell all of this contract's `fromTokenAddress` token balance.
|
||||
uint256 boughtAmount = _getEth2DaiContract().sellAllAmount(
|
||||
address(fromTokenAddress),
|
||||
IERC20Token(fromTokenAddress).balanceOf(address(this)),
|
||||
uint256 boughtAmount = exchange.sellAllAmount(
|
||||
fromTokenAddress,
|
||||
fromTokenBalance,
|
||||
toTokenAddress,
|
||||
amount
|
||||
);
|
||||
// Transfer the converted `toToken`s to `to`.
|
||||
LibERC20Token.transfer(toTokenAddress, to, boughtAmount);
|
||||
|
||||
emit ERC20BridgeTransfer(
|
||||
fromTokenAddress,
|
||||
toTokenAddress,
|
||||
fromTokenBalance,
|
||||
boughtAmount,
|
||||
from,
|
||||
to
|
||||
);
|
||||
return BRIDGE_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -85,14 +95,4 @@ contract Eth2DaiBridge is
|
||||
{
|
||||
return LEGACY_WALLET_MAGIC_VALUE;
|
||||
}
|
||||
|
||||
/// @dev Overridable way to get the eth2dai contract.
|
||||
/// @return exchange The Eth2Dai exchange contract.
|
||||
function _getEth2DaiContract()
|
||||
internal
|
||||
view
|
||||
returns (IEth2Dai exchange)
|
||||
{
|
||||
return IEth2Dai(ETH2DAI_ADDRESS);
|
||||
}
|
||||
}
|
||||
|
||||
169
contracts/asset-proxy/contracts/src/bridges/KyberBridge.sol
Normal file
169
contracts/asset-proxy/contracts/src/bridges/KyberBridge.sol
Normal file
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
|
||||
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
|
||||
import "../interfaces/IERC20Bridge.sol";
|
||||
import "../interfaces/IKyberNetworkProxy.sol";
|
||||
|
||||
|
||||
// solhint-disable space-after-comma
|
||||
contract KyberBridge is
|
||||
IERC20Bridge,
|
||||
IWallet,
|
||||
DeploymentConstants
|
||||
{
|
||||
using LibSafeMath for uint256;
|
||||
|
||||
// @dev Structure used internally to get around stack limits.
|
||||
struct TradeState {
|
||||
IKyberNetworkProxy kyber;
|
||||
IEtherToken weth;
|
||||
address fromTokenAddress;
|
||||
uint256 fromTokenBalance;
|
||||
uint256 payableAmount;
|
||||
uint256 conversionRate;
|
||||
bytes hint;
|
||||
}
|
||||
|
||||
/// @dev Kyber ETH pseudo-address.
|
||||
address constant public KYBER_ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
|
||||
/// @dev `bridgeTransferFrom()` failure result.
|
||||
bytes4 constant private BRIDGE_FAILED = 0x0;
|
||||
/// @dev Precision of Kyber rates.
|
||||
uint256 constant private KYBER_RATE_BASE = 10 ** 18;
|
||||
|
||||
// solhint-disable no-empty-blocks
|
||||
/// @dev Payable fallback to receive ETH from Kyber/WETH.
|
||||
function ()
|
||||
external
|
||||
payable
|
||||
{
|
||||
// Poor man's receive in 0.5.9
|
||||
require(msg.data.length == 0);
|
||||
}
|
||||
|
||||
/// @dev Callback for `IKyberBridge`. Tries to buy `amount` of
|
||||
/// `toTokenAddress` tokens by selling the entirety of the opposing asset
|
||||
/// to the `KyberNetworkProxy` contract, then transfers the bought
|
||||
/// tokens to `to`.
|
||||
/// @param toTokenAddress The token to give to `to`.
|
||||
/// @param from The maker (this contract).
|
||||
/// @param to The recipient of the bought tokens.
|
||||
/// @param amount Minimum amount of `toTokenAddress` tokens to buy.
|
||||
/// @param bridgeData The abi-encoeded "from" token address.
|
||||
/// @return success The magic bytes if successful.
|
||||
function bridgeTransferFrom(
|
||||
address toTokenAddress,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes calldata bridgeData
|
||||
)
|
||||
external
|
||||
returns (bytes4 success)
|
||||
{
|
||||
TradeState memory state;
|
||||
state.kyber = IKyberNetworkProxy(_getKyberNetworkProxyAddress());
|
||||
state.weth = IEtherToken(_getWethAddress());
|
||||
// Decode the bridge data to get the `fromTokenAddress`.
|
||||
(state.fromTokenAddress, state.hint) = abi.decode(bridgeData, (address, bytes));
|
||||
// Query the balance of "from" tokens.
|
||||
state.fromTokenBalance = IERC20Token(state.fromTokenAddress).balanceOf(address(this));
|
||||
if (state.fromTokenBalance == 0) {
|
||||
// Return failure if no input tokens.
|
||||
return BRIDGE_FAILED;
|
||||
}
|
||||
if (state.fromTokenAddress == toTokenAddress) {
|
||||
// Just transfer the tokens if they're the same.
|
||||
LibERC20Token.transfer(state.fromTokenAddress, to, state.fromTokenBalance);
|
||||
return BRIDGE_SUCCESS;
|
||||
}
|
||||
if (state.fromTokenAddress == address(state.weth)) {
|
||||
// From WETH
|
||||
state.fromTokenAddress = KYBER_ETH_ADDRESS;
|
||||
state.payableAmount = state.fromTokenBalance;
|
||||
state.weth.withdraw(state.fromTokenBalance);
|
||||
} else {
|
||||
LibERC20Token.approveIfBelow(
|
||||
state.fromTokenAddress,
|
||||
address(state.kyber),
|
||||
state.fromTokenBalance
|
||||
);
|
||||
}
|
||||
bool isToTokenWeth = toTokenAddress == address(state.weth);
|
||||
|
||||
// Try to sell all of this contract's input token balance through
|
||||
// `KyberNetworkProxy.trade()`.
|
||||
uint256 boughtAmount = state.kyber.tradeWithHint.value(state.payableAmount)(
|
||||
// Input token.
|
||||
state.fromTokenAddress,
|
||||
// Sell amount.
|
||||
state.fromTokenBalance,
|
||||
// Output token.
|
||||
isToTokenWeth ? KYBER_ETH_ADDRESS : toTokenAddress,
|
||||
// Transfer to this contract if converting to ETH, otherwise
|
||||
// transfer directly to the recipient.
|
||||
isToTokenWeth ? address(uint160(address(this))) : address(uint160(to)),
|
||||
// Buy as much as possible.
|
||||
uint256(-1),
|
||||
// The minimum conversion rate
|
||||
1,
|
||||
// No affiliate address.
|
||||
address(0),
|
||||
state.hint
|
||||
);
|
||||
// Wrap ETH output and transfer to recipient.
|
||||
if (isToTokenWeth) {
|
||||
state.weth.deposit.value(boughtAmount)();
|
||||
state.weth.transfer(to, boughtAmount);
|
||||
}
|
||||
|
||||
emit ERC20BridgeTransfer(
|
||||
state.fromTokenAddress == KYBER_ETH_ADDRESS ? address(state.weth) : state.fromTokenAddress,
|
||||
toTokenAddress,
|
||||
state.fromTokenBalance,
|
||||
boughtAmount,
|
||||
from,
|
||||
to
|
||||
);
|
||||
return BRIDGE_SUCCESS;
|
||||
}
|
||||
|
||||
/// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
|
||||
/// and sign for itself in orders. Always succeeds.
|
||||
/// @return magicValue Magic success bytes, always.
|
||||
function isValidSignature(
|
||||
bytes32,
|
||||
bytes calldata
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (bytes4 magicValue)
|
||||
{
|
||||
return LEGACY_WALLET_MAGIC_VALUE;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
|
||||
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
|
||||
import "../interfaces/IERC20Bridge.sol";
|
||||
import "../interfaces/IMStable.sol";
|
||||
|
||||
|
||||
contract MStableBridge is
|
||||
IERC20Bridge,
|
||||
IWallet,
|
||||
DeploymentConstants
|
||||
{
|
||||
|
||||
/// @dev Swaps specified tokens against the mStable mUSD contract
|
||||
/// @param toTokenAddress The token to give to `to` (i.e DAI, USDC, USDT).
|
||||
/// @param from The maker (this contract).
|
||||
/// @param to The recipient of the bought tokens.
|
||||
/// @param amount Minimum amount of `toTokenAddress` tokens to buy.
|
||||
/// @param bridgeData The abi-encoded "from" token address.
|
||||
/// @return success The magic bytes if successful.
|
||||
// solhint-disable no-unused-vars
|
||||
function bridgeTransferFrom(
|
||||
address toTokenAddress,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes calldata bridgeData
|
||||
)
|
||||
external
|
||||
returns (bytes4 success)
|
||||
{
|
||||
// Decode the bridge data to get the `fromTokenAddress`.
|
||||
(address fromTokenAddress) = abi.decode(bridgeData, (address));
|
||||
|
||||
IMStable exchange = IMStable(_getMUsdAddress());
|
||||
uint256 fromTokenBalance = IERC20Token(fromTokenAddress).balanceOf(address(this));
|
||||
// Grant an allowance to the exchange to spend `fromTokenAddress` token.
|
||||
LibERC20Token.approveIfBelow(fromTokenAddress, address(exchange), fromTokenBalance);
|
||||
|
||||
// Try to sell all of this contract's `fromTokenAddress` token balance.
|
||||
uint256 boughtAmount = exchange.swap(
|
||||
fromTokenAddress,
|
||||
toTokenAddress,
|
||||
fromTokenBalance,
|
||||
to
|
||||
);
|
||||
|
||||
emit ERC20BridgeTransfer(
|
||||
fromTokenAddress,
|
||||
toTokenAddress,
|
||||
fromTokenBalance,
|
||||
boughtAmount,
|
||||
from,
|
||||
to
|
||||
);
|
||||
return BRIDGE_SUCCESS;
|
||||
}
|
||||
|
||||
/// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
|
||||
/// and sign for itself in orders. Always succeeds.
|
||||
/// @return magicValue Magic success bytes, always.
|
||||
function isValidSignature(
|
||||
bytes32,
|
||||
bytes calldata
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (bytes4 magicValue)
|
||||
{
|
||||
return LEGACY_WALLET_MAGIC_VALUE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.16;
|
||||
|
||||
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
|
||||
import "../interfaces/IGasToken.sol";
|
||||
|
||||
|
||||
contract MixinGasToken is
|
||||
DeploymentConstants
|
||||
{
|
||||
|
||||
/// @dev Frees gas tokens based on the amount of gas consumed in the function
|
||||
modifier freesGasTokens {
|
||||
uint256 gasBefore = gasleft();
|
||||
_;
|
||||
IGasToken gst = IGasToken(_getGstAddress());
|
||||
if (address(gst) != address(0)) {
|
||||
// (gasUsed + FREE_BASE) / (2 * REIMBURSE - FREE_TOKEN)
|
||||
// 14154 24000 6870
|
||||
uint256 value = (gasBefore - gasleft() + 14154) / 41130;
|
||||
gst.freeUpTo(value);
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Frees gas tokens using the balance of `from`. Amount freed is based
|
||||
/// on the gas consumed in the function
|
||||
modifier freesGasTokensFromCollector() {
|
||||
uint256 gasBefore = gasleft();
|
||||
_;
|
||||
IGasToken gst = IGasToken(_getGstAddress());
|
||||
if (address(gst) != address(0)) {
|
||||
// (gasUsed + FREE_BASE) / (2 * REIMBURSE - FREE_TOKEN)
|
||||
// 14154 24000 6870
|
||||
uint256 value = (gasBefore - gasleft() + 14154) / 41130;
|
||||
gst.freeFromUpTo(_getGstCollectorAddress(), value);
|
||||
}
|
||||
}
|
||||
}
|
||||
148
contracts/asset-proxy/contracts/src/bridges/MooniswapBridge.sol
Normal file
148
contracts/asset-proxy/contracts/src/bridges/MooniswapBridge.sol
Normal file
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
|
||||
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
|
||||
import "../interfaces/IERC20Bridge.sol";
|
||||
import "../interfaces/IMooniswap.sol";
|
||||
|
||||
|
||||
// solhint-disable space-after-comma
|
||||
// solhint-disable not-rely-on-time
|
||||
contract MooniswapBridge is
|
||||
IERC20Bridge,
|
||||
IWallet,
|
||||
DeploymentConstants
|
||||
{
|
||||
|
||||
struct TransferState {
|
||||
IMooniswap pool;
|
||||
uint256 fromTokenBalance;
|
||||
IEtherToken weth;
|
||||
uint256 boughtAmount;
|
||||
address fromTokenAddress;
|
||||
address toTokenAddress;
|
||||
}
|
||||
|
||||
// solhint-disable no-empty-blocks
|
||||
/// @dev Payable fallback to receive ETH from uniswap.
|
||||
function ()
|
||||
external
|
||||
payable
|
||||
{}
|
||||
|
||||
/// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of
|
||||
/// `toTokenAddress` tokens by selling the entirety of the `fromTokenAddress`
|
||||
/// token encoded in the bridge data.
|
||||
/// @param toTokenAddress The token to buy and transfer to `to`.
|
||||
/// @param from The maker (this contract).
|
||||
/// @param to The recipient of the bought tokens.
|
||||
/// @param amount Minimum amount of `toTokenAddress` tokens to buy.
|
||||
/// @param bridgeData The abi-encoded path of token addresses. Last element must be toTokenAddress
|
||||
/// @return success The magic bytes if successful.
|
||||
function bridgeTransferFrom(
|
||||
address toTokenAddress,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes calldata bridgeData
|
||||
)
|
||||
external
|
||||
returns (bytes4 success)
|
||||
{
|
||||
// State memory object to avoid stack overflows.
|
||||
TransferState memory state;
|
||||
// Decode the bridge data to get the `fromTokenAddress`.
|
||||
address fromTokenAddress = abi.decode(bridgeData, (address));
|
||||
// Get the weth contract.
|
||||
state.weth = IEtherToken(_getWethAddress());
|
||||
// Get our balance of `fromTokenAddress` token.
|
||||
state.fromTokenBalance = IERC20Token(fromTokenAddress).balanceOf(address(this));
|
||||
|
||||
state.fromTokenAddress = fromTokenAddress == address(state.weth) ? address(0) : fromTokenAddress;
|
||||
state.toTokenAddress = toTokenAddress == address(state.weth) ? address(0) : toTokenAddress;
|
||||
state.pool = IMooniswap(
|
||||
IMooniswapRegistry(_getMooniswapAddress()).pools(
|
||||
state.fromTokenAddress,
|
||||
state.toTokenAddress
|
||||
)
|
||||
);
|
||||
|
||||
// withdraw WETH to ETH
|
||||
if (state.fromTokenAddress == address(0)) {
|
||||
state.weth.withdraw(state.fromTokenBalance);
|
||||
} else {
|
||||
// Grant the pool an allowance.
|
||||
LibERC20Token.approveIfBelow(
|
||||
state.fromTokenAddress,
|
||||
address(state.pool),
|
||||
state.fromTokenBalance
|
||||
);
|
||||
}
|
||||
uint256 ethValue = state.fromTokenAddress == address(0) ? state.fromTokenBalance : 0;
|
||||
state.boughtAmount = state.pool.swap.value(ethValue)(
|
||||
state.fromTokenAddress,
|
||||
state.toTokenAddress,
|
||||
state.fromTokenBalance,
|
||||
amount,
|
||||
address(0)
|
||||
);
|
||||
// Deposit to WETH
|
||||
if (state.toTokenAddress == address(0)) {
|
||||
state.weth.deposit.value(state.boughtAmount)();
|
||||
}
|
||||
|
||||
// Transfer funds to `to`
|
||||
LibERC20Token.transfer(toTokenAddress, to, state.boughtAmount);
|
||||
|
||||
emit ERC20BridgeTransfer(
|
||||
// input token
|
||||
fromTokenAddress,
|
||||
// output token
|
||||
toTokenAddress,
|
||||
// input token amount
|
||||
state.fromTokenBalance,
|
||||
// output token amount
|
||||
state.boughtAmount,
|
||||
from,
|
||||
to
|
||||
);
|
||||
|
||||
return BRIDGE_SUCCESS;
|
||||
}
|
||||
|
||||
/// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
|
||||
/// and sign for itself in orders. Always succeeds.
|
||||
/// @return magicValue Success bytes, always.
|
||||
function isValidSignature(
|
||||
bytes32,
|
||||
bytes calldata
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (bytes4 magicValue)
|
||||
{
|
||||
return LEGACY_WALLET_MAGIC_VALUE;
|
||||
}
|
||||
}
|
||||
95
contracts/asset-proxy/contracts/src/bridges/ShellBridge.sol
Normal file
95
contracts/asset-proxy/contracts/src/bridges/ShellBridge.sol
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
|
||||
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
|
||||
import "../interfaces/IERC20Bridge.sol";
|
||||
import "../interfaces/IShell.sol";
|
||||
|
||||
|
||||
contract ShellBridge is
|
||||
IERC20Bridge,
|
||||
IWallet,
|
||||
DeploymentConstants
|
||||
{
|
||||
|
||||
/// @dev Swaps specified tokens against the Shell contract
|
||||
/// @param toTokenAddress The token to give to `to`.
|
||||
/// @param from The maker (this contract).
|
||||
/// @param to The recipient of the bought tokens.
|
||||
/// @param amount Minimum amount of `toTokenAddress` tokens to buy.
|
||||
/// @param bridgeData The abi-encoded "from" token address.
|
||||
/// @return success The magic bytes if successful.
|
||||
// solhint-disable no-unused-vars
|
||||
function bridgeTransferFrom(
|
||||
address toTokenAddress,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes calldata bridgeData
|
||||
)
|
||||
external
|
||||
returns (bytes4 success)
|
||||
{
|
||||
// Decode the bridge data to get the `fromTokenAddress` and `pool`.
|
||||
(address fromTokenAddress, address pool) = abi.decode(bridgeData, (address, address));
|
||||
|
||||
uint256 fromTokenBalance = IERC20Token(fromTokenAddress).balanceOf(address(this));
|
||||
// Grant an allowance to the exchange to spend `fromTokenAddress` token.
|
||||
LibERC20Token.approveIfBelow(fromTokenAddress, pool, fromTokenBalance);
|
||||
|
||||
// Try to sell all of this contract's `fromTokenAddress` token balance.
|
||||
uint256 boughtAmount = IShell(pool).originSwap(
|
||||
fromTokenAddress,
|
||||
toTokenAddress,
|
||||
fromTokenBalance,
|
||||
amount, // min amount
|
||||
block.timestamp + 1
|
||||
);
|
||||
LibERC20Token.transfer(toTokenAddress, to, boughtAmount);
|
||||
|
||||
emit ERC20BridgeTransfer(
|
||||
fromTokenAddress,
|
||||
toTokenAddress,
|
||||
fromTokenBalance,
|
||||
boughtAmount,
|
||||
from,
|
||||
to
|
||||
);
|
||||
return BRIDGE_SUCCESS;
|
||||
}
|
||||
|
||||
/// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
|
||||
/// and sign for itself in orders. Always succeeds.
|
||||
/// @return magicValue Magic success bytes, always.
|
||||
function isValidSignature(
|
||||
bytes32,
|
||||
bytes calldata
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (bytes4 magicValue)
|
||||
{
|
||||
return LEGACY_WALLET_MAGIC_VALUE;
|
||||
}
|
||||
}
|
||||
119
contracts/asset-proxy/contracts/src/bridges/SnowSwapBridge.sol
Normal file
119
contracts/asset-proxy/contracts/src/bridges/SnowSwapBridge.sol
Normal file
@@ -0,0 +1,119 @@
|
||||
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
|
||||
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
|
||||
import "../interfaces/IERC20Bridge.sol";
|
||||
import "../interfaces/ICurve.sol";
|
||||
|
||||
|
||||
// solhint-disable not-rely-on-time
|
||||
// solhint-disable space-after-comma
|
||||
contract SnowSwapBridge is
|
||||
IERC20Bridge,
|
||||
IWallet,
|
||||
DeploymentConstants
|
||||
{
|
||||
struct SnowSwapBridgeData {
|
||||
address curveAddress;
|
||||
bytes4 exchangeFunctionSelector;
|
||||
address fromTokenAddress;
|
||||
int128 fromCoinIdx;
|
||||
int128 toCoinIdx;
|
||||
}
|
||||
|
||||
/// @dev Callback for `ICurve`. Tries to buy `amount` of
|
||||
/// `toTokenAddress` tokens by selling the entirety of the opposing asset
|
||||
/// (DAI, USDC) to the Curve contract, then transfers the bought
|
||||
/// tokens to `to`.
|
||||
/// @param toTokenAddress The token to give to `to` (i.e DAI, USDC, USDT).
|
||||
/// @param from The maker (this contract).
|
||||
/// @param to The recipient of the bought tokens.
|
||||
/// @param amount Minimum amount of `toTokenAddress` tokens to buy.
|
||||
/// @param bridgeData The abi-encoeded "from" token address.
|
||||
/// @return success The magic bytes if successful.
|
||||
function bridgeTransferFrom(
|
||||
address toTokenAddress,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes calldata bridgeData
|
||||
)
|
||||
external
|
||||
returns (bytes4 success)
|
||||
{
|
||||
// Decode the bridge data to get the SnowSwap metadata.
|
||||
SnowSwapBridgeData memory data = abi.decode(bridgeData, (SnowSwapBridgeData));
|
||||
|
||||
require(toTokenAddress != data.fromTokenAddress, "SnowSwapBridge/INVALID_PAIR");
|
||||
uint256 fromTokenBalance = IERC20Token(data.fromTokenAddress).balanceOf(address(this));
|
||||
// Grant an allowance to the exchange to spend `fromTokenAddress` token.
|
||||
LibERC20Token.approveIfBelow(data.fromTokenAddress, data.curveAddress, fromTokenBalance);
|
||||
|
||||
// Try to sell all of this contract's `fromTokenAddress` token balance.
|
||||
{
|
||||
(bool didSucceed, bytes memory resultData) =
|
||||
data.curveAddress.call(abi.encodeWithSelector(
|
||||
data.exchangeFunctionSelector,
|
||||
data.fromCoinIdx,
|
||||
data.toCoinIdx,
|
||||
// dx
|
||||
fromTokenBalance,
|
||||
// min dy
|
||||
amount
|
||||
));
|
||||
if (!didSucceed) {
|
||||
assembly { revert(add(resultData, 32), mload(resultData)) }
|
||||
}
|
||||
}
|
||||
|
||||
uint256 toTokenBalance = IERC20Token(toTokenAddress).balanceOf(address(this));
|
||||
// Transfer the converted `toToken`s to `to`.
|
||||
LibERC20Token.transfer(toTokenAddress, to, toTokenBalance);
|
||||
|
||||
emit ERC20BridgeTransfer(
|
||||
data.fromTokenAddress,
|
||||
toTokenAddress,
|
||||
fromTokenBalance,
|
||||
toTokenBalance,
|
||||
from,
|
||||
to
|
||||
);
|
||||
return BRIDGE_SUCCESS;
|
||||
}
|
||||
|
||||
/// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
|
||||
/// and sign for itself in orders. Always succeeds.
|
||||
/// @return magicValue Magic success bytes, always.
|
||||
function isValidSignature(
|
||||
bytes32,
|
||||
bytes calldata
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (bytes4 magicValue)
|
||||
{
|
||||
return LEGACY_WALLET_MAGIC_VALUE;
|
||||
}
|
||||
}
|
||||
136
contracts/asset-proxy/contracts/src/bridges/SushiSwapBridge.sol
Normal file
136
contracts/asset-proxy/contracts/src/bridges/SushiSwapBridge.sol
Normal file
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibAddressArray.sol";
|
||||
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
|
||||
import "../interfaces/IUniswapV2Router01.sol";
|
||||
import "../interfaces/IERC20Bridge.sol";
|
||||
|
||||
|
||||
// solhint-disable space-after-comma
|
||||
// solhint-disable not-rely-on-time
|
||||
contract SushiSwapBridge is
|
||||
IERC20Bridge,
|
||||
IWallet,
|
||||
DeploymentConstants
|
||||
{
|
||||
struct TransferState {
|
||||
address[] path;
|
||||
address router;
|
||||
uint256 fromTokenBalance;
|
||||
}
|
||||
|
||||
/// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of
|
||||
/// `toTokenAddress` tokens by selling the entirety of the `fromTokenAddress`
|
||||
/// token encoded in the bridge data.
|
||||
/// @param toTokenAddress The token to buy and transfer to `to`.
|
||||
/// @param from The maker (this contract).
|
||||
/// @param to The recipient of the bought tokens.
|
||||
/// @param amount Minimum amount of `toTokenAddress` tokens to buy.
|
||||
/// @param bridgeData The abi-encoded path of token addresses. Last element must be toTokenAddress
|
||||
/// @return success The magic bytes if successful.
|
||||
function bridgeTransferFrom(
|
||||
address toTokenAddress,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes calldata bridgeData
|
||||
)
|
||||
external
|
||||
returns (bytes4 success)
|
||||
{
|
||||
// hold variables to get around stack depth limitations
|
||||
TransferState memory state;
|
||||
|
||||
// Decode the bridge data to get the `fromTokenAddress`.
|
||||
// solhint-disable indent
|
||||
(state.path, state.router) = abi.decode(bridgeData, (address[], address));
|
||||
// solhint-enable indent
|
||||
|
||||
require(state.path.length >= 2, "SushiSwapBridge/PATH_LENGTH_MUST_BE_AT_LEAST_TWO");
|
||||
require(state.path[state.path.length - 1] == toTokenAddress, "SushiSwapBridge/LAST_ELEMENT_OF_PATH_MUST_MATCH_OUTPUT_TOKEN");
|
||||
|
||||
// Just transfer the tokens if they're the same.
|
||||
if (state.path[0] == toTokenAddress) {
|
||||
LibERC20Token.transfer(state.path[0], to, amount);
|
||||
return BRIDGE_SUCCESS;
|
||||
}
|
||||
|
||||
// Get our balance of `fromTokenAddress` token.
|
||||
state.fromTokenBalance = IERC20Token(state.path[0]).balanceOf(address(this));
|
||||
|
||||
// Grant the SushiSwap router an allowance.
|
||||
LibERC20Token.approveIfBelow(
|
||||
state.path[0],
|
||||
state.router,
|
||||
state.fromTokenBalance
|
||||
);
|
||||
|
||||
// Buy as much `toTokenAddress` token with `fromTokenAddress` token
|
||||
// and transfer it to `to`.
|
||||
IUniswapV2Router01 router = IUniswapV2Router01(state.router);
|
||||
uint[] memory amounts = router.swapExactTokensForTokens(
|
||||
// Sell all tokens we hold.
|
||||
state.fromTokenBalance,
|
||||
// Minimum buy amount.
|
||||
amount,
|
||||
// Convert `fromTokenAddress` to `toTokenAddress`.
|
||||
state.path,
|
||||
// Recipient is `to`.
|
||||
to,
|
||||
// Expires after this block.
|
||||
block.timestamp
|
||||
);
|
||||
|
||||
emit ERC20BridgeTransfer(
|
||||
// input token
|
||||
state.path[0],
|
||||
// output token
|
||||
toTokenAddress,
|
||||
// input token amount
|
||||
state.fromTokenBalance,
|
||||
// output token amount
|
||||
amounts[amounts.length - 1],
|
||||
from,
|
||||
to
|
||||
);
|
||||
|
||||
return BRIDGE_SUCCESS;
|
||||
}
|
||||
|
||||
/// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
|
||||
/// and sign for itself in orders. Always succeeds.
|
||||
/// @return magicValue Success bytes, always.
|
||||
function isValidSignature(
|
||||
bytes32,
|
||||
bytes calldata
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (bytes4 magicValue)
|
||||
{
|
||||
return LEGACY_WALLET_MAGIC_VALUE;
|
||||
}
|
||||
}
|
||||
119
contracts/asset-proxy/contracts/src/bridges/SwerveBridge.sol
Normal file
119
contracts/asset-proxy/contracts/src/bridges/SwerveBridge.sol
Normal file
@@ -0,0 +1,119 @@
|
||||
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
|
||||
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
|
||||
import "../interfaces/IERC20Bridge.sol";
|
||||
import "../interfaces/ICurve.sol";
|
||||
|
||||
|
||||
// solhint-disable not-rely-on-time
|
||||
// solhint-disable space-after-comma
|
||||
contract SwerveBridge is
|
||||
IERC20Bridge,
|
||||
IWallet,
|
||||
DeploymentConstants
|
||||
{
|
||||
struct SwerveBridgeData {
|
||||
address curveAddress;
|
||||
bytes4 exchangeFunctionSelector;
|
||||
address fromTokenAddress;
|
||||
int128 fromCoinIdx;
|
||||
int128 toCoinIdx;
|
||||
}
|
||||
|
||||
/// @dev Callback for `ICurve`. Tries to buy `amount` of
|
||||
/// `toTokenAddress` tokens by selling the entirety of the opposing asset
|
||||
/// (DAI, USDC) to the Curve contract, then transfers the bought
|
||||
/// tokens to `to`.
|
||||
/// @param toTokenAddress The token to give to `to` (i.e DAI, USDC, USDT).
|
||||
/// @param from The maker (this contract).
|
||||
/// @param to The recipient of the bought tokens.
|
||||
/// @param amount Minimum amount of `toTokenAddress` tokens to buy.
|
||||
/// @param bridgeData The abi-encoeded "from" token address.
|
||||
/// @return success The magic bytes if successful.
|
||||
function bridgeTransferFrom(
|
||||
address toTokenAddress,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes calldata bridgeData
|
||||
)
|
||||
external
|
||||
returns (bytes4 success)
|
||||
{
|
||||
// Decode the bridge data to get the SwerveBridgeData metadata.
|
||||
SwerveBridgeData memory data = abi.decode(bridgeData, (SwerveBridgeData));
|
||||
|
||||
require(toTokenAddress != data.fromTokenAddress, "SwerveBridge/INVALID_PAIR");
|
||||
uint256 fromTokenBalance = IERC20Token(data.fromTokenAddress).balanceOf(address(this));
|
||||
// Grant an allowance to the exchange to spend `fromTokenAddress` token.
|
||||
LibERC20Token.approveIfBelow(data.fromTokenAddress, data.curveAddress, fromTokenBalance);
|
||||
|
||||
// Try to sell all of this contract's `fromTokenAddress` token balance.
|
||||
{
|
||||
(bool didSucceed, bytes memory resultData) =
|
||||
data.curveAddress.call(abi.encodeWithSelector(
|
||||
data.exchangeFunctionSelector,
|
||||
data.fromCoinIdx,
|
||||
data.toCoinIdx,
|
||||
// dx
|
||||
fromTokenBalance,
|
||||
// min dy
|
||||
amount
|
||||
));
|
||||
if (!didSucceed) {
|
||||
assembly { revert(add(resultData, 32), mload(resultData)) }
|
||||
}
|
||||
}
|
||||
|
||||
uint256 toTokenBalance = IERC20Token(toTokenAddress).balanceOf(address(this));
|
||||
// Transfer the converted `toToken`s to `to`.
|
||||
LibERC20Token.transfer(toTokenAddress, to, toTokenBalance);
|
||||
|
||||
emit ERC20BridgeTransfer(
|
||||
data.fromTokenAddress,
|
||||
toTokenAddress,
|
||||
fromTokenBalance,
|
||||
toTokenBalance,
|
||||
from,
|
||||
to
|
||||
);
|
||||
return BRIDGE_SUCCESS;
|
||||
}
|
||||
|
||||
/// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
|
||||
/// and sign for itself in orders. Always succeeds.
|
||||
/// @return magicValue Magic success bytes, always.
|
||||
function isValidSignature(
|
||||
bytes32,
|
||||
bytes calldata
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (bytes4 magicValue)
|
||||
{
|
||||
return LEGACY_WALLET_MAGIC_VALUE;
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,7 @@ import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
|
||||
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
|
||||
import "../interfaces/IUniswapExchangeFactory.sol";
|
||||
import "../interfaces/IUniswapExchange.sol";
|
||||
import "../interfaces/IERC20Bridge.sol";
|
||||
@@ -32,18 +33,16 @@ import "../interfaces/IERC20Bridge.sol";
|
||||
// solhint-disable not-rely-on-time
|
||||
contract UniswapBridge is
|
||||
IERC20Bridge,
|
||||
IWallet
|
||||
IWallet,
|
||||
DeploymentConstants
|
||||
{
|
||||
/* Mainnet addresses */
|
||||
address constant private UNISWAP_EXCHANGE_FACTORY_ADDRESS = 0xc0a47dFe034B400B47bDaD5FecDa2621de6c4d95;
|
||||
address constant private WETH_ADDRESS = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
|
||||
|
||||
// Struct to hold `bridgeTransferFrom()` local variables in memory and to avoid
|
||||
// stack overflows.
|
||||
struct WithdrawToState {
|
||||
struct TransferState {
|
||||
IUniswapExchange exchange;
|
||||
uint256 fromTokenBalance;
|
||||
IEtherToken weth;
|
||||
uint256 boughtAmount;
|
||||
}
|
||||
|
||||
// solhint-disable no-empty-blocks
|
||||
@@ -57,13 +56,14 @@ contract UniswapBridge is
|
||||
/// `toTokenAddress` tokens by selling the entirety of the `fromTokenAddress`
|
||||
/// token encoded in the bridge data.
|
||||
/// @param toTokenAddress The token to buy and transfer to `to`.
|
||||
/// @param from The maker (this contract).
|
||||
/// @param to The recipient of the bought tokens.
|
||||
/// @param amount Minimum amount of `toTokenAddress` tokens to buy.
|
||||
/// @param bridgeData The abi-encoded "from" token address.
|
||||
/// @return success The magic bytes if successful.
|
||||
function bridgeTransferFrom(
|
||||
address toTokenAddress,
|
||||
address /* from */,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes calldata bridgeData
|
||||
@@ -72,7 +72,7 @@ contract UniswapBridge is
|
||||
returns (bytes4 success)
|
||||
{
|
||||
// State memory object to avoid stack overflows.
|
||||
WithdrawToState memory state;
|
||||
TransferState memory state;
|
||||
// Decode the bridge data to get the `fromTokenAddress`.
|
||||
(address fromTokenAddress) = abi.decode(bridgeData, (address));
|
||||
|
||||
@@ -90,7 +90,7 @@ contract UniswapBridge is
|
||||
// Get our balance of `fromTokenAddress` token.
|
||||
state.fromTokenBalance = IERC20Token(fromTokenAddress).balanceOf(address(this));
|
||||
// Get the weth contract.
|
||||
state.weth = getWethContract();
|
||||
state.weth = IEtherToken(_getWethAddress());
|
||||
|
||||
// Convert from WETH to a token.
|
||||
if (fromTokenAddress == address(state.weth)) {
|
||||
@@ -98,7 +98,7 @@ contract UniswapBridge is
|
||||
state.weth.withdraw(state.fromTokenBalance);
|
||||
// Buy as much of `toTokenAddress` token with ETH as possible and
|
||||
// transfer it to `to`.
|
||||
state.exchange.ethToTokenTransferInput.value(state.fromTokenBalance)(
|
||||
state.boughtAmount = state.exchange.ethToTokenTransferInput.value(state.fromTokenBalance)(
|
||||
// Minimum buy amount.
|
||||
amount,
|
||||
// Expires after this block.
|
||||
@@ -110,9 +110,9 @@ contract UniswapBridge is
|
||||
// Convert from a token to WETH.
|
||||
} else if (toTokenAddress == address(state.weth)) {
|
||||
// Grant the exchange an allowance.
|
||||
_grantExchangeAllowance(state.exchange, fromTokenAddress);
|
||||
_grantExchangeAllowance(state.exchange, fromTokenAddress, state.fromTokenBalance);
|
||||
// Buy as much ETH with `fromTokenAddress` token as possible.
|
||||
uint256 ethBought = state.exchange.tokenToEthSwapInput(
|
||||
state.boughtAmount = state.exchange.tokenToEthSwapInput(
|
||||
// Sell all tokens we hold.
|
||||
state.fromTokenBalance,
|
||||
// Minimum buy amount.
|
||||
@@ -121,23 +121,23 @@ contract UniswapBridge is
|
||||
block.timestamp
|
||||
);
|
||||
// Wrap the ETH.
|
||||
state.weth.deposit.value(ethBought)();
|
||||
state.weth.deposit.value(state.boughtAmount)();
|
||||
// Transfer the WETH to `to`.
|
||||
IEtherToken(toTokenAddress).transfer(to, ethBought);
|
||||
IEtherToken(toTokenAddress).transfer(to, state.boughtAmount);
|
||||
|
||||
// Convert from one token to another.
|
||||
} else {
|
||||
// Grant the exchange an allowance.
|
||||
_grantExchangeAllowance(state.exchange, fromTokenAddress);
|
||||
_grantExchangeAllowance(state.exchange, fromTokenAddress, state.fromTokenBalance);
|
||||
// Buy as much `toTokenAddress` token with `fromTokenAddress` token
|
||||
// and transfer it to `to`.
|
||||
state.exchange.tokenToTokenTransferInput(
|
||||
state.boughtAmount = state.exchange.tokenToTokenTransferInput(
|
||||
// Sell all tokens we hold.
|
||||
state.fromTokenBalance,
|
||||
// Minimum buy amount.
|
||||
amount,
|
||||
// No minimum intermediate ETH buy amount.
|
||||
0,
|
||||
// Must buy at least 1 intermediate ETH.
|
||||
1,
|
||||
// Expires after this block.
|
||||
block.timestamp,
|
||||
// Recipient is `to`.
|
||||
@@ -146,6 +146,15 @@ contract UniswapBridge is
|
||||
toTokenAddress
|
||||
);
|
||||
}
|
||||
|
||||
emit ERC20BridgeTransfer(
|
||||
fromTokenAddress,
|
||||
toTokenAddress,
|
||||
state.fromTokenBalance,
|
||||
state.boughtAmount,
|
||||
from,
|
||||
to
|
||||
);
|
||||
return BRIDGE_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -163,34 +172,23 @@ contract UniswapBridge is
|
||||
return LEGACY_WALLET_MAGIC_VALUE;
|
||||
}
|
||||
|
||||
/// @dev Overridable way to get the weth contract.
|
||||
/// @return token The WETH contract.
|
||||
function getWethContract()
|
||||
public
|
||||
view
|
||||
returns (IEtherToken token)
|
||||
{
|
||||
return IEtherToken(WETH_ADDRESS);
|
||||
}
|
||||
|
||||
/// @dev Overridable way to get the uniswap exchange factory contract.
|
||||
/// @return factory The exchange factory contract.
|
||||
function getUniswapExchangeFactoryContract()
|
||||
public
|
||||
view
|
||||
returns (IUniswapExchangeFactory factory)
|
||||
{
|
||||
return IUniswapExchangeFactory(UNISWAP_EXCHANGE_FACTORY_ADDRESS);
|
||||
}
|
||||
|
||||
/// @dev Grants an unlimited allowance to the exchange for its token
|
||||
/// on behalf of this contract.
|
||||
/// @param exchange The Uniswap token exchange.
|
||||
/// @param tokenAddress The token address for the exchange.
|
||||
function _grantExchangeAllowance(IUniswapExchange exchange, address tokenAddress)
|
||||
/// @param minimumAllowance The minimum necessary allowance.
|
||||
function _grantExchangeAllowance(
|
||||
IUniswapExchange exchange,
|
||||
address tokenAddress,
|
||||
uint256 minimumAllowance
|
||||
)
|
||||
private
|
||||
{
|
||||
LibERC20Token.approve(tokenAddress, address(exchange), uint256(-1));
|
||||
LibERC20Token.approveIfBelow(
|
||||
tokenAddress,
|
||||
address(exchange),
|
||||
minimumAllowance
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Retrieves the uniswap exchange for a given token pair.
|
||||
@@ -209,10 +207,13 @@ contract UniswapBridge is
|
||||
{
|
||||
address exchangeTokenAddress = fromTokenAddress;
|
||||
// Whichever isn't WETH is the exchange token.
|
||||
if (fromTokenAddress == address(getWethContract())) {
|
||||
if (fromTokenAddress == _getWethAddress()) {
|
||||
exchangeTokenAddress = toTokenAddress;
|
||||
}
|
||||
exchange = getUniswapExchangeFactoryContract().getExchange(exchangeTokenAddress);
|
||||
exchange = IUniswapExchange(
|
||||
IUniswapExchangeFactory(_getUniswapExchangeFactoryAddress())
|
||||
.getExchange(exchangeTokenAddress)
|
||||
);
|
||||
require(address(exchange) != address(0), "NO_UNISWAP_EXCHANGE_FOR_TOKEN");
|
||||
return exchange;
|
||||
}
|
||||
|
||||
135
contracts/asset-proxy/contracts/src/bridges/UniswapV2Bridge.sol
Normal file
135
contracts/asset-proxy/contracts/src/bridges/UniswapV2Bridge.sol
Normal file
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibAddressArray.sol";
|
||||
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
|
||||
import "../interfaces/IUniswapV2Router01.sol";
|
||||
import "../interfaces/IERC20Bridge.sol";
|
||||
|
||||
|
||||
// solhint-disable space-after-comma
|
||||
// solhint-disable not-rely-on-time
|
||||
contract UniswapV2Bridge is
|
||||
IERC20Bridge,
|
||||
IWallet,
|
||||
DeploymentConstants
|
||||
{
|
||||
struct TransferState {
|
||||
address[] path;
|
||||
uint256 fromTokenBalance;
|
||||
}
|
||||
|
||||
/// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of
|
||||
/// `toTokenAddress` tokens by selling the entirety of the `fromTokenAddress`
|
||||
/// token encoded in the bridge data.
|
||||
/// @param toTokenAddress The token to buy and transfer to `to`.
|
||||
/// @param from The maker (this contract).
|
||||
/// @param to The recipient of the bought tokens.
|
||||
/// @param amount Minimum amount of `toTokenAddress` tokens to buy.
|
||||
/// @param bridgeData The abi-encoded path of token addresses. Last element must be toTokenAddress
|
||||
/// @return success The magic bytes if successful.
|
||||
function bridgeTransferFrom(
|
||||
address toTokenAddress,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes calldata bridgeData
|
||||
)
|
||||
external
|
||||
returns (bytes4 success)
|
||||
{
|
||||
// hold variables to get around stack depth limitations
|
||||
TransferState memory state;
|
||||
|
||||
// Decode the bridge data to get the `fromTokenAddress`.
|
||||
// solhint-disable indent
|
||||
state.path = abi.decode(bridgeData, (address[]));
|
||||
// solhint-enable indent
|
||||
|
||||
require(state.path.length >= 2, "UniswapV2Bridge/PATH_LENGTH_MUST_BE_AT_LEAST_TWO");
|
||||
require(state.path[state.path.length - 1] == toTokenAddress, "UniswapV2Bridge/LAST_ELEMENT_OF_PATH_MUST_MATCH_OUTPUT_TOKEN");
|
||||
|
||||
// Just transfer the tokens if they're the same.
|
||||
if (state.path[0] == toTokenAddress) {
|
||||
LibERC20Token.transfer(state.path[0], to, amount);
|
||||
return BRIDGE_SUCCESS;
|
||||
}
|
||||
|
||||
// Get our balance of `fromTokenAddress` token.
|
||||
state.fromTokenBalance = IERC20Token(state.path[0]).balanceOf(address(this));
|
||||
|
||||
// Grant the Uniswap router an allowance.
|
||||
LibERC20Token.approveIfBelow(
|
||||
state.path[0],
|
||||
_getUniswapV2Router01Address(),
|
||||
state.fromTokenBalance
|
||||
);
|
||||
|
||||
// Buy as much `toTokenAddress` token with `fromTokenAddress` token
|
||||
// and transfer it to `to`.
|
||||
IUniswapV2Router01 router = IUniswapV2Router01(_getUniswapV2Router01Address());
|
||||
uint[] memory amounts = router.swapExactTokensForTokens(
|
||||
// Sell all tokens we hold.
|
||||
state.fromTokenBalance,
|
||||
// Minimum buy amount.
|
||||
amount,
|
||||
// Convert `fromTokenAddress` to `toTokenAddress`.
|
||||
state.path,
|
||||
// Recipient is `to`.
|
||||
to,
|
||||
// Expires after this block.
|
||||
block.timestamp
|
||||
);
|
||||
|
||||
emit ERC20BridgeTransfer(
|
||||
// input token
|
||||
state.path[0],
|
||||
// output token
|
||||
toTokenAddress,
|
||||
// input token amount
|
||||
state.fromTokenBalance,
|
||||
// output token amount
|
||||
amounts[amounts.length - 1],
|
||||
from,
|
||||
to
|
||||
);
|
||||
|
||||
return BRIDGE_SUCCESS;
|
||||
}
|
||||
|
||||
/// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
|
||||
/// and sign for itself in orders. Always succeeds.
|
||||
/// @return magicValue Success bytes, always.
|
||||
function isValidSignature(
|
||||
bytes32,
|
||||
bytes calldata
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (bytes4 magicValue)
|
||||
{
|
||||
return LEGACY_WALLET_MAGIC_VALUE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
|
||||
interface IBalancerPool {
|
||||
/// @dev Sell `tokenAmountIn` of `tokenIn` and receive `tokenOut`.
|
||||
/// @param tokenIn The token being sold
|
||||
/// @param tokenAmountIn The amount of `tokenIn` to sell.
|
||||
/// @param tokenOut The token being bought.
|
||||
/// @param minAmountOut The minimum amount of `tokenOut` to buy.
|
||||
/// @param maxPrice The maximum value for `spotPriceAfter`.
|
||||
/// @return tokenAmountOut The amount of `tokenOut` bought.
|
||||
/// @return spotPriceAfter The new marginal spot price of the given
|
||||
/// token pair for this pool.
|
||||
function swapExactAmountIn(
|
||||
address tokenIn,
|
||||
uint tokenAmountIn,
|
||||
address tokenOut,
|
||||
uint minAmountOut,
|
||||
uint maxPrice
|
||||
) external returns (uint tokenAmountOut, uint spotPriceAfter);
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
|
||||
contract IContractRegistry {
|
||||
function addressOf(
|
||||
bytes32 contractName
|
||||
) external returns(address);
|
||||
}
|
||||
|
||||
|
||||
contract IBancorNetwork {
|
||||
function convertByPath(
|
||||
address[] calldata _path,
|
||||
uint256 _amount,
|
||||
uint256 _minReturn,
|
||||
address _beneficiary,
|
||||
address _affiliateAccount,
|
||||
uint256 _affiliateFee
|
||||
) external payable returns (uint256);
|
||||
}
|
||||
66
contracts/asset-proxy/contracts/src/interfaces/IChai.sol
Normal file
66
contracts/asset-proxy/contracts/src/interfaces/IChai.sol
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||
|
||||
|
||||
contract PotLike {
|
||||
function chi() external returns (uint256);
|
||||
function rho() external returns (uint256);
|
||||
function drip() external returns (uint256);
|
||||
function join(uint256) external;
|
||||
function exit(uint256) external;
|
||||
}
|
||||
|
||||
|
||||
// The actual Chai contract can be found here: https://github.com/dapphub/chai
|
||||
contract IChai is
|
||||
IERC20Token
|
||||
{
|
||||
/// @dev Withdraws Dai owned by `src`
|
||||
/// @param src Address that owns Dai.
|
||||
/// @param wad Amount of Dai to withdraw.
|
||||
function draw(
|
||||
address src,
|
||||
uint256 wad
|
||||
)
|
||||
external;
|
||||
|
||||
/// @dev Queries Dai balance of Chai holder.
|
||||
/// @param usr Address of Chai holder.
|
||||
/// @return Dai balance.
|
||||
function dai(address usr)
|
||||
external
|
||||
returns (uint256);
|
||||
|
||||
/// @dev Queries the Pot contract used by the Chai contract.
|
||||
function pot()
|
||||
external
|
||||
returns (PotLike);
|
||||
|
||||
/// @dev Deposits Dai in exchange for Chai
|
||||
/// @param dst Address to receive Chai.
|
||||
/// @param wad Amount of Dai to deposit.
|
||||
function join(
|
||||
address dst,
|
||||
uint256 wad
|
||||
)
|
||||
external;
|
||||
}
|
||||
70
contracts/asset-proxy/contracts/src/interfaces/ICurve.sol
Normal file
70
contracts/asset-proxy/contracts/src/interfaces/ICurve.sol
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
|
||||
// solhint-disable func-name-mixedcase
|
||||
interface ICurve {
|
||||
|
||||
/// @dev Sell `sellAmount` of `fromToken` token and receive `toToken` token.
|
||||
/// This function exists on later versions of Curve (USDC/DAI/USDT)
|
||||
/// @param i The token index being sold.
|
||||
/// @param j The token index being bought.
|
||||
/// @param sellAmount The amount of token being bought.
|
||||
/// @param minBuyAmount The minimum buy amount of the token being bought.
|
||||
function exchange_underlying(
|
||||
int128 i,
|
||||
int128 j,
|
||||
uint256 sellAmount,
|
||||
uint256 minBuyAmount
|
||||
)
|
||||
external;
|
||||
|
||||
/// @dev Get the amount of `toToken` by selling `sellAmount` of `fromToken`
|
||||
/// @param i The token index being sold.
|
||||
/// @param j The token index being bought.
|
||||
/// @param sellAmount The amount of token being bought.
|
||||
function get_dy_underlying(
|
||||
int128 i,
|
||||
int128 j,
|
||||
uint256 sellAmount
|
||||
)
|
||||
external
|
||||
returns (uint256 dy);
|
||||
|
||||
/// @dev Get the amount of `fromToken` by buying `buyAmount` of `toToken`
|
||||
/// @param i The token index being sold.
|
||||
/// @param j The token index being bought.
|
||||
/// @param buyAmount The amount of token being bought.
|
||||
function get_dx_underlying(
|
||||
int128 i,
|
||||
int128 j,
|
||||
uint256 buyAmount
|
||||
)
|
||||
external
|
||||
returns (uint256 dx);
|
||||
|
||||
/// @dev Get the underlying token address from the token index
|
||||
/// @param i The token index.
|
||||
function underlying_coins(
|
||||
int128 i
|
||||
)
|
||||
external
|
||||
returns (address tokenAddress);
|
||||
}
|
||||
192
contracts/asset-proxy/contracts/src/interfaces/IDydx.sol
Normal file
192
contracts/asset-proxy/contracts/src/interfaces/IDydx.sol
Normal file
@@ -0,0 +1,192 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
|
||||
interface IDydx {
|
||||
|
||||
/// @dev Represents the unique key that specifies an account
|
||||
struct AccountInfo {
|
||||
address owner; // The address that owns the account
|
||||
uint256 number; // A nonce that allows a single address to control many accounts
|
||||
}
|
||||
|
||||
enum ActionType {
|
||||
Deposit, // supply tokens
|
||||
Withdraw, // borrow tokens
|
||||
Transfer, // transfer balance between accounts
|
||||
Buy, // buy an amount of some token (externally)
|
||||
Sell, // sell an amount of some token (externally)
|
||||
Trade, // trade tokens against another account
|
||||
Liquidate, // liquidate an undercollateralized or expiring account
|
||||
Vaporize, // use excess tokens to zero-out a completely negative account
|
||||
Call // send arbitrary data to an address
|
||||
}
|
||||
|
||||
/// @dev Arguments that are passed to Solo in an ordered list as part of a single operation.
|
||||
/// Each ActionArgs has an actionType which specifies which action struct that this data will be
|
||||
/// parsed into before being processed.
|
||||
struct ActionArgs {
|
||||
ActionType actionType;
|
||||
uint256 accountIdx;
|
||||
AssetAmount amount;
|
||||
uint256 primaryMarketId;
|
||||
uint256 secondaryMarketId;
|
||||
address otherAddress;
|
||||
uint256 otherAccountIdx;
|
||||
bytes data;
|
||||
}
|
||||
|
||||
enum AssetDenomination {
|
||||
Wei, // the amount is denominated in wei
|
||||
Par // the amount is denominated in par
|
||||
}
|
||||
|
||||
enum AssetReference {
|
||||
Delta, // the amount is given as a delta from the current value
|
||||
Target // the amount is given as an exact number to end up at
|
||||
}
|
||||
|
||||
struct AssetAmount {
|
||||
bool sign; // true if positive
|
||||
AssetDenomination denomination;
|
||||
AssetReference ref;
|
||||
uint256 value;
|
||||
}
|
||||
|
||||
struct D256 {
|
||||
uint256 value;
|
||||
}
|
||||
|
||||
struct Value {
|
||||
uint256 value;
|
||||
}
|
||||
|
||||
struct Price {
|
||||
uint256 value;
|
||||
}
|
||||
|
||||
struct OperatorArg {
|
||||
address operator;
|
||||
bool trusted;
|
||||
}
|
||||
|
||||
/// @dev The global risk parameters that govern the health and security of the system
|
||||
struct RiskParams {
|
||||
// Required ratio of over-collateralization
|
||||
D256 marginRatio;
|
||||
// Percentage penalty incurred by liquidated accounts
|
||||
D256 liquidationSpread;
|
||||
// Percentage of the borrower's interest fee that gets passed to the suppliers
|
||||
D256 earningsRate;
|
||||
// The minimum absolute borrow value of an account
|
||||
// There must be sufficient incentivize to liquidate undercollateralized accounts
|
||||
Value minBorrowedValue;
|
||||
}
|
||||
|
||||
/// @dev The main entry-point to Solo that allows users and contracts to manage accounts.
|
||||
/// Take one or more actions on one or more accounts. The msg.sender must be the owner or
|
||||
/// operator of all accounts except for those being liquidated, vaporized, or traded with.
|
||||
/// One call to operate() is considered a singular "operation". Account collateralization is
|
||||
/// ensured only after the completion of the entire operation.
|
||||
/// @param accounts A list of all accounts that will be used in this operation. Cannot contain
|
||||
/// duplicates. In each action, the relevant account will be referred-to by its
|
||||
/// index in the list.
|
||||
/// @param actions An ordered list of all actions that will be taken in this operation. The
|
||||
/// actions will be processed in order.
|
||||
function operate(
|
||||
AccountInfo[] calldata accounts,
|
||||
ActionArgs[] calldata actions
|
||||
)
|
||||
external;
|
||||
|
||||
// @dev Approves/disapproves any number of operators. An operator is an external address that has the
|
||||
// same permissions to manipulate an account as the owner of the account. Operators are simply
|
||||
// addresses and therefore may either be externally-owned Ethereum accounts OR smart contracts.
|
||||
// Operators are also able to act as AutoTrader contracts on behalf of the account owner if the
|
||||
// operator is a smart contract and implements the IAutoTrader interface.
|
||||
// @param args A list of OperatorArgs which have an address and a boolean. The boolean value
|
||||
// denotes whether to approve (true) or revoke approval (false) for that address.
|
||||
function setOperators(OperatorArg[] calldata args) external;
|
||||
|
||||
/// @dev Return true if a particular address is approved as an operator for an owner's accounts.
|
||||
/// Approved operators can act on the accounts of the owner as if it were the operator's own.
|
||||
/// @param owner The owner of the accounts
|
||||
/// @param operator The possible operator
|
||||
/// @return isLocalOperator True if operator is approved for owner's accounts
|
||||
function getIsLocalOperator(
|
||||
address owner,
|
||||
address operator
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (bool isLocalOperator);
|
||||
|
||||
/// @dev Get the ERC20 token address for a market.
|
||||
/// @param marketId The market to query
|
||||
/// @return tokenAddress The token address
|
||||
function getMarketTokenAddress(
|
||||
uint256 marketId
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (address tokenAddress);
|
||||
|
||||
/// @dev Get all risk parameters in a single struct.
|
||||
/// @return riskParams All global risk parameters
|
||||
function getRiskParams()
|
||||
external
|
||||
view
|
||||
returns (RiskParams memory riskParams);
|
||||
|
||||
/// @dev Get the price of the token for a market.
|
||||
/// @param marketId The market to query
|
||||
/// @return price The price of each atomic unit of the token
|
||||
function getMarketPrice(
|
||||
uint256 marketId
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (Price memory price);
|
||||
|
||||
/// @dev Get the margin premium for a market. A margin premium makes it so that any positions that
|
||||
/// include the market require a higher collateralization to avoid being liquidated.
|
||||
/// @param marketId The market to query
|
||||
/// @return premium The market's margin premium
|
||||
function getMarketMarginPremium(uint256 marketId)
|
||||
external
|
||||
view
|
||||
returns (D256 memory premium);
|
||||
|
||||
/// @dev Get the total supplied and total borrowed values of an account adjusted by the marginPremium
|
||||
/// of each market. Supplied values are divided by (1 + marginPremium) for each market and
|
||||
/// borrowed values are multiplied by (1 + marginPremium) for each market. Comparing these
|
||||
/// adjusted values gives the margin-ratio of the account which will be compared to the global
|
||||
/// margin-ratio when determining if the account can be liquidated.
|
||||
/// @param account The account to query
|
||||
/// @return supplyValue The supplied value of the account (adjusted for marginPremium)
|
||||
/// @return borrowValue The borrowed value of the account (adjusted for marginPremium)
|
||||
function getAdjustedAccountValues(
|
||||
AccountInfo calldata account
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (Value memory supplyValue, Value memory borrowValue);
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
|
||||
interface IDydxBridge {
|
||||
|
||||
/// @dev This is the subset of `IDydx.ActionType` that are supported by the bridge.
|
||||
enum BridgeActionType {
|
||||
Deposit, // Deposit tokens into dydx account.
|
||||
Withdraw // Withdraw tokens from dydx account.
|
||||
}
|
||||
|
||||
struct BridgeAction {
|
||||
BridgeActionType actionType; // Action to run on dydx account.
|
||||
uint256 accountIdx; // Index in `BridgeData.accountNumbers` for this action.
|
||||
uint256 marketId; // Market to operate on.
|
||||
uint256 conversionRateNumerator; // Optional. If set, transfer amount is scaled by (conversionRateNumerator/conversionRateDenominator).
|
||||
uint256 conversionRateDenominator; // Optional. If set, transfer amount is scaled by (conversionRateNumerator/conversionRateDenominator).
|
||||
}
|
||||
|
||||
struct BridgeData {
|
||||
uint256[] accountNumbers; // Account number used to identify the owner's specific account.
|
||||
BridgeAction[] actions; // Actions to carry out on the owner's accounts.
|
||||
}
|
||||
}
|
||||
@@ -21,16 +21,32 @@ pragma solidity ^0.5.9;
|
||||
|
||||
contract IERC20Bridge {
|
||||
|
||||
// @dev Result of a successful bridge call.
|
||||
/// @dev Result of a successful bridge call.
|
||||
bytes4 constant internal BRIDGE_SUCCESS = 0xdc1600f3;
|
||||
|
||||
/// @dev Emitted when a trade occurs.
|
||||
/// @param inputToken The token the bridge is converting from.
|
||||
/// @param outputToken The token the bridge is converting to.
|
||||
/// @param inputTokenAmount Amount of input token.
|
||||
/// @param outputTokenAmount Amount of output token.
|
||||
/// @param from The `from` address in `bridgeTransferFrom()`
|
||||
/// @param to The `to` address in `bridgeTransferFrom()`
|
||||
event ERC20BridgeTransfer(
|
||||
address inputToken,
|
||||
address outputToken,
|
||||
uint256 inputTokenAmount,
|
||||
uint256 outputTokenAmount,
|
||||
address from,
|
||||
address to
|
||||
);
|
||||
|
||||
/// @dev Transfers `amount` of the ERC20 `tokenAddress` from `from` to `to`.
|
||||
/// @param tokenAddress The address of the ERC20 token to transfer.
|
||||
/// @param from Address to transfer asset from.
|
||||
/// @param to Address to transfer asset to.
|
||||
/// @param amount Amount of asset to transfer.
|
||||
/// @param bridgeData Arbitrary asset data needed by the bridge contract.
|
||||
/// @return success The magic bytes `0x37708e9b` if successful.
|
||||
/// @return success The magic bytes `0xdc1600f3` if successful.
|
||||
function bridgeTransferFrom(
|
||||
address tokenAddress,
|
||||
address from,
|
||||
|
||||
40
contracts/asset-proxy/contracts/src/interfaces/IGasToken.sol
Normal file
40
contracts/asset-proxy/contracts/src/interfaces/IGasToken.sol
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.15;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||
|
||||
|
||||
contract IGasToken is IERC20Token {
|
||||
|
||||
/// @dev Frees up to `value` sub-tokens
|
||||
/// @param value The amount of tokens to free
|
||||
/// @return How many tokens were freed
|
||||
function freeUpTo(uint256 value) external returns (uint256 freed);
|
||||
|
||||
/// @dev Frees up to `value` sub-tokens owned by `from`
|
||||
/// @param from The owner of tokens to spend
|
||||
/// @param value The amount of tokens to free
|
||||
/// @return How many tokens were freed
|
||||
function freeFromUpTo(address from, uint256 value) external returns (uint256 freed);
|
||||
|
||||
/// @dev Mints `value` amount of tokens
|
||||
/// @param value The amount of tokens to mint
|
||||
function mint(uint256 value) external;
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
|
||||
interface IKyberNetworkProxy {
|
||||
|
||||
/// @dev Sells `sellTokenAddress` tokens for `buyTokenAddress` tokens.
|
||||
/// @param sellTokenAddress Token to sell.
|
||||
/// @param sellAmount Amount of tokens to sell.
|
||||
/// @param buyTokenAddress Token to buy.
|
||||
/// @param recipientAddress Address to send bought tokens to.
|
||||
/// @param maxBuyTokenAmount A limit on the amount of tokens to buy.
|
||||
/// @param minConversionRate The minimal conversion rate. If actual rate
|
||||
/// is lower, trade is canceled.
|
||||
/// @param walletId The wallet ID to send part of the fees
|
||||
/// @return boughtAmount Amount of tokens bought.
|
||||
function trade(
|
||||
address sellTokenAddress,
|
||||
uint256 sellAmount,
|
||||
address buyTokenAddress,
|
||||
address payable recipientAddress,
|
||||
uint256 maxBuyTokenAmount,
|
||||
uint256 minConversionRate,
|
||||
address walletId
|
||||
)
|
||||
external
|
||||
payable
|
||||
returns (uint256 boughtAmount);
|
||||
|
||||
/// @dev Sells `sellTokenAddress` tokens for `buyTokenAddress` tokens
|
||||
/// using a hint for the reserve.
|
||||
/// @param sellTokenAddress Token to sell.
|
||||
/// @param sellAmount Amount of tokens to sell.
|
||||
/// @param buyTokenAddress Token to buy.
|
||||
/// @param recipientAddress Address to send bought tokens to.
|
||||
/// @param maxBuyTokenAmount A limit on the amount of tokens to buy.
|
||||
/// @param minConversionRate The minimal conversion rate. If actual rate
|
||||
/// is lower, trade is canceled.
|
||||
/// @param walletId The wallet ID to send part of the fees
|
||||
/// @param hint The hint for the selective inclusion (or exclusion) of reserves
|
||||
/// @return boughtAmount Amount of tokens bought.
|
||||
function tradeWithHint(
|
||||
address sellTokenAddress,
|
||||
uint256 sellAmount,
|
||||
address buyTokenAddress,
|
||||
address payable recipientAddress,
|
||||
uint256 maxBuyTokenAmount,
|
||||
uint256 minConversionRate,
|
||||
address payable walletId,
|
||||
bytes calldata hint
|
||||
)
|
||||
external
|
||||
payable
|
||||
returns (uint256 boughtAmount);
|
||||
}
|
||||
32
contracts/asset-proxy/contracts/src/interfaces/IMStable.sol
Normal file
32
contracts/asset-proxy/contracts/src/interfaces/IMStable.sol
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
|
||||
interface IMStable {
|
||||
|
||||
function swap(
|
||||
address _input,
|
||||
address _output,
|
||||
uint256 _quantity,
|
||||
address _recipient
|
||||
)
|
||||
external
|
||||
returns (uint256 output);
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
|
||||
interface IMooniswapRegistry {
|
||||
|
||||
function pools(address token1, address token2) external view returns(address);
|
||||
}
|
||||
|
||||
|
||||
interface IMooniswap {
|
||||
|
||||
function swap(
|
||||
address fromToken,
|
||||
address destToken,
|
||||
uint256 amount,
|
||||
uint256 minReturn,
|
||||
address referral
|
||||
)
|
||||
external
|
||||
payable
|
||||
returns(uint256 returnAmount);
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -19,13 +19,16 @@
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
|
||||
contract IThresholdAsset {
|
||||
interface IShell {
|
||||
|
||||
/// @param _owner The address from which the balance will be retrieved
|
||||
/// @return Balance of owner
|
||||
function balanceOf(address _owner)
|
||||
function originSwap(
|
||||
address from,
|
||||
address to,
|
||||
uint256 fromAmount,
|
||||
uint256 minTargetAmount,
|
||||
uint256 deadline
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (uint256);
|
||||
|
||||
returns (uint256 toAmount);
|
||||
}
|
||||
|
||||
@@ -67,11 +67,4 @@ interface IUniswapExchange {
|
||||
)
|
||||
external
|
||||
returns (uint256 tokensBought);
|
||||
|
||||
/// @dev Retrieves the token that is associated with this exchange.
|
||||
/// @return tokenAddress The token address.
|
||||
function toTokenAddress()
|
||||
external
|
||||
view
|
||||
returns (address tokenAddress);
|
||||
}
|
||||
|
||||
@@ -28,5 +28,5 @@ interface IUniswapExchangeFactory {
|
||||
function getExchange(address tokenAddress)
|
||||
external
|
||||
view
|
||||
returns (IUniswapExchange);
|
||||
returns (address);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
|
||||
interface IUniswapV2Router01 {
|
||||
|
||||
/// @dev Swaps an exact amount of input tokens for as many output tokens as possible, along the route determined by the path.
|
||||
/// The first element of path is the input token, the last is the output token, and any intermediate elements represent
|
||||
/// intermediate pairs to trade through (if, for example, a direct pair does not exist).
|
||||
/// @param amountIn The amount of input tokens to send.
|
||||
/// @param amountOutMin The minimum amount of output tokens that must be received for the transaction not to revert.
|
||||
/// @param path An array of token addresses. path.length must be >= 2. Pools for each consecutive pair of addresses must exist and have liquidity.
|
||||
/// @param to Recipient of the output tokens.
|
||||
/// @param deadline Unix timestamp after which the transaction will revert.
|
||||
/// @return amounts The input token amount and all subsequent output token amounts.
|
||||
function swapExactTokensForTokens(
|
||||
uint amountIn,
|
||||
uint amountOutMin,
|
||||
address[] calldata path,
|
||||
address to,
|
||||
uint deadline
|
||||
) external returns (uint[] memory amounts);
|
||||
}
|
||||
247
contracts/asset-proxy/contracts/test/TestBancorBridge.sol
Normal file
247
contracts/asset-proxy/contracts/test/TestBancorBridge.sol
Normal file
@@ -0,0 +1,247 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibAddressArray.sol";
|
||||
import "../src/bridges/BancorBridge.sol";
|
||||
import "../src/interfaces/IBancorNetwork.sol";
|
||||
|
||||
|
||||
contract TestEventsRaiser {
|
||||
|
||||
event TokenTransfer(
|
||||
address token,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
);
|
||||
|
||||
event TokenApprove(
|
||||
address spender,
|
||||
uint256 allowance
|
||||
);
|
||||
|
||||
event ConvertByPathInput(
|
||||
uint amountIn,
|
||||
uint amountOutMin,
|
||||
address toTokenAddress,
|
||||
address to,
|
||||
address feeRecipient,
|
||||
uint256 feeAmount
|
||||
);
|
||||
|
||||
function raiseTokenTransfer(
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
)
|
||||
external
|
||||
{
|
||||
emit TokenTransfer(
|
||||
msg.sender,
|
||||
from,
|
||||
to,
|
||||
amount
|
||||
);
|
||||
}
|
||||
|
||||
function raiseTokenApprove(address spender, uint256 allowance) external {
|
||||
emit TokenApprove(spender, allowance);
|
||||
}
|
||||
|
||||
function raiseConvertByPathInput(
|
||||
uint amountIn,
|
||||
uint amountOutMin,
|
||||
address toTokenAddress,
|
||||
address to,
|
||||
address feeRecipient,
|
||||
uint256 feeAmount
|
||||
) external
|
||||
{
|
||||
emit ConvertByPathInput(
|
||||
amountIn,
|
||||
amountOutMin,
|
||||
toTokenAddress,
|
||||
to,
|
||||
feeRecipient,
|
||||
feeAmount
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// @dev A minimalist ERC20 token.
|
||||
contract TestToken {
|
||||
|
||||
using LibSafeMath for uint256;
|
||||
|
||||
mapping (address => uint256) public balances;
|
||||
string private _nextRevertReason;
|
||||
|
||||
/// @dev Set the balance for `owner`.
|
||||
function setBalance(address owner, uint256 balance)
|
||||
external
|
||||
payable
|
||||
{
|
||||
balances[owner] = balance;
|
||||
}
|
||||
|
||||
/// @dev Just emits a TokenTransfer event on the caller
|
||||
function transfer(address to, uint256 amount)
|
||||
external
|
||||
returns (bool)
|
||||
{
|
||||
TestEventsRaiser(msg.sender).raiseTokenTransfer(msg.sender, to, amount);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// @dev Just emits a TokenApprove event on the caller
|
||||
function approve(address spender, uint256 allowance)
|
||||
external
|
||||
returns (bool)
|
||||
{
|
||||
TestEventsRaiser(msg.sender).raiseTokenApprove(spender, allowance);
|
||||
return true;
|
||||
}
|
||||
|
||||
function allowance(address, address) external view returns (uint256) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// @dev Retrieve the balance for `owner`.
|
||||
function balanceOf(address owner)
|
||||
external
|
||||
view
|
||||
returns (uint256)
|
||||
{
|
||||
return balances[owner];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// @dev Mock the BancorNetwork contract
|
||||
contract TestBancorNetwork is
|
||||
IBancorNetwork
|
||||
{
|
||||
string private _nextRevertReason;
|
||||
|
||||
/// @dev Set the revert reason for `swapExactTokensForTokens`.
|
||||
function setRevertReason(string calldata reason)
|
||||
external
|
||||
{
|
||||
_nextRevertReason = reason;
|
||||
}
|
||||
|
||||
function convertByPath(
|
||||
address[] calldata _path,
|
||||
uint256 _amount,
|
||||
uint256 _minReturn,
|
||||
address _beneficiary,
|
||||
address _affiliateAccount,
|
||||
uint256 _affiliateFee
|
||||
) external payable returns (uint256)
|
||||
{
|
||||
_revertIfReasonExists();
|
||||
|
||||
TestEventsRaiser(msg.sender).raiseConvertByPathInput(
|
||||
// tokens sold
|
||||
_amount,
|
||||
// tokens bought
|
||||
_minReturn,
|
||||
// output token
|
||||
_path[_path.length - 1],
|
||||
// recipient
|
||||
_beneficiary,
|
||||
// fee recipient
|
||||
_affiliateAccount,
|
||||
// fee amount
|
||||
_affiliateFee
|
||||
);
|
||||
}
|
||||
|
||||
function _revertIfReasonExists()
|
||||
private
|
||||
view
|
||||
{
|
||||
if (bytes(_nextRevertReason).length != 0) {
|
||||
revert(_nextRevertReason);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// @dev BancorBridge overridden to mock tokens and BancorNetwork
|
||||
contract TestBancorBridge is
|
||||
BancorBridge,
|
||||
TestEventsRaiser
|
||||
{
|
||||
|
||||
// Token address to TestToken instance.
|
||||
mapping (address => TestToken) private _testTokens;
|
||||
// TestRouter instance.
|
||||
TestBancorNetwork private _testNetwork;
|
||||
|
||||
constructor() public {
|
||||
_testNetwork = new TestBancorNetwork();
|
||||
}
|
||||
|
||||
function setNetworkRevertReason(string calldata revertReason)
|
||||
external
|
||||
{
|
||||
_testNetwork.setRevertReason(revertReason);
|
||||
}
|
||||
|
||||
/// @dev Sets the balance of this contract for an existing token.
|
||||
function setTokenBalance(address tokenAddress, uint256 balance)
|
||||
external
|
||||
{
|
||||
TestToken token = _testTokens[tokenAddress];
|
||||
token.setBalance(address(this), balance);
|
||||
}
|
||||
|
||||
/// @dev Create a new token
|
||||
/// @param tokenAddress The token address. If zero, one will be created.
|
||||
function createToken(
|
||||
address tokenAddress
|
||||
)
|
||||
external
|
||||
returns (TestToken token)
|
||||
{
|
||||
token = TestToken(tokenAddress);
|
||||
if (tokenAddress == address(0)) {
|
||||
token = new TestToken();
|
||||
}
|
||||
_testTokens[address(token)] = token;
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
function getNetworkAddress()
|
||||
external
|
||||
view
|
||||
returns (address)
|
||||
{
|
||||
return address(_testNetwork);
|
||||
}
|
||||
|
||||
}
|
||||
80
contracts/asset-proxy/contracts/test/TestChaiBridge.sol
Normal file
80
contracts/asset-proxy/contracts/test/TestChaiBridge.sol
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "../src/bridges/ChaiBridge.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/ERC20Token.sol";
|
||||
|
||||
|
||||
contract TestChaiDai is
|
||||
ERC20Token
|
||||
{
|
||||
address private constant ALWAYS_REVERT_ADDRESS = address(1);
|
||||
|
||||
function draw(
|
||||
address from,
|
||||
uint256 amount
|
||||
)
|
||||
external
|
||||
{
|
||||
if (from == ALWAYS_REVERT_ADDRESS) {
|
||||
revert();
|
||||
}
|
||||
balances[msg.sender] += amount;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
contract TestChaiBridge is
|
||||
ChaiBridge
|
||||
{
|
||||
address public testChaiDai;
|
||||
address private constant ALWAYS_REVERT_ADDRESS = address(1);
|
||||
|
||||
constructor()
|
||||
public
|
||||
{
|
||||
testChaiDai = address(new TestChaiDai());
|
||||
}
|
||||
|
||||
function _getDaiAddress()
|
||||
internal
|
||||
view
|
||||
returns (address)
|
||||
{
|
||||
return testChaiDai;
|
||||
}
|
||||
|
||||
function _getChaiAddress()
|
||||
internal
|
||||
view
|
||||
returns (address)
|
||||
{
|
||||
return testChaiDai;
|
||||
}
|
||||
|
||||
function _getERC20BridgeProxyAddress()
|
||||
internal
|
||||
view
|
||||
returns (address)
|
||||
{
|
||||
return msg.sender == ALWAYS_REVERT_ADDRESS ? address(0) : msg.sender;
|
||||
}
|
||||
}
|
||||
244
contracts/asset-proxy/contracts/test/TestDexForwarderBridge.sol
Normal file
244
contracts/asset-proxy/contracts/test/TestDexForwarderBridge.sol
Normal file
@@ -0,0 +1,244 @@
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "../src/bridges/DexForwarderBridge.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
|
||||
|
||||
|
||||
interface ITestDexForwarderBridge {
|
||||
event BridgeTransferFromCalled(
|
||||
address caller,
|
||||
uint256 inputTokenBalance,
|
||||
address inputToken,
|
||||
address outputToken,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
);
|
||||
|
||||
event TokenTransferCalled(
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
);
|
||||
|
||||
function emitBridgeTransferFromCalled(
|
||||
address caller,
|
||||
uint256 inputTokenBalance,
|
||||
address inputToken,
|
||||
address outputToken,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
) external;
|
||||
|
||||
function emitTokenTransferCalled(
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
) external;
|
||||
}
|
||||
|
||||
|
||||
interface ITestDexForwarderBridgeTestToken {
|
||||
|
||||
function transfer(address to, uint256 amount)
|
||||
external
|
||||
returns (bool);
|
||||
|
||||
function mint(address to, uint256 amount)
|
||||
external;
|
||||
|
||||
function balanceOf(address owner) external view returns (uint256);
|
||||
}
|
||||
|
||||
|
||||
contract TestDexForwarderBridgeTestBridge {
|
||||
|
||||
bytes4 private _returnCode;
|
||||
string private _revertError;
|
||||
uint256 private _transferAmount;
|
||||
ITestDexForwarderBridge private _testContract;
|
||||
|
||||
constructor(bytes4 returnCode, string memory revertError) public {
|
||||
_testContract = ITestDexForwarderBridge(msg.sender);
|
||||
_returnCode = returnCode;
|
||||
_revertError = revertError;
|
||||
}
|
||||
|
||||
function setTransferAmount(uint256 amount) external {
|
||||
_transferAmount = amount;
|
||||
}
|
||||
|
||||
function bridgeTransferFrom(
|
||||
address outputToken,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes memory bridgeData
|
||||
)
|
||||
public
|
||||
returns (bytes4 success)
|
||||
{
|
||||
if (bytes(_revertError).length != 0) {
|
||||
revert(_revertError);
|
||||
}
|
||||
address inputToken = abi.decode(bridgeData, (address));
|
||||
_testContract.emitBridgeTransferFromCalled(
|
||||
msg.sender,
|
||||
ITestDexForwarderBridgeTestToken(inputToken).balanceOf(address(this)),
|
||||
inputToken,
|
||||
outputToken,
|
||||
from,
|
||||
to,
|
||||
amount
|
||||
);
|
||||
ITestDexForwarderBridgeTestToken(outputToken).mint(to, _transferAmount);
|
||||
return _returnCode;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
contract TestDexForwarderBridgeTestToken {
|
||||
|
||||
using LibSafeMath for uint256;
|
||||
|
||||
mapping(address => uint256) public balanceOf;
|
||||
ITestDexForwarderBridge private _testContract;
|
||||
|
||||
constructor() public {
|
||||
_testContract = ITestDexForwarderBridge(msg.sender);
|
||||
}
|
||||
|
||||
function transfer(address to, uint256 amount)
|
||||
external
|
||||
returns (bool)
|
||||
{
|
||||
balanceOf[msg.sender] = balanceOf[msg.sender].safeSub(amount);
|
||||
balanceOf[to] = balanceOf[to].safeAdd(amount);
|
||||
_testContract.emitTokenTransferCalled(msg.sender, to, amount);
|
||||
return true;
|
||||
}
|
||||
|
||||
function mint(address owner, uint256 amount)
|
||||
external
|
||||
{
|
||||
balanceOf[owner] = balanceOf[owner].safeAdd(amount);
|
||||
}
|
||||
|
||||
function setBalance(address owner, uint256 amount)
|
||||
external
|
||||
{
|
||||
balanceOf[owner] = amount;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
contract TestDexForwarderBridge is
|
||||
ITestDexForwarderBridge,
|
||||
DexForwarderBridge
|
||||
{
|
||||
address private AUTHORIZED_ADDRESS; // solhint-disable-line var-name-mixedcase
|
||||
|
||||
function setAuthorized(address authorized)
|
||||
public
|
||||
{
|
||||
AUTHORIZED_ADDRESS = authorized;
|
||||
}
|
||||
|
||||
function createBridge(
|
||||
bytes4 returnCode,
|
||||
string memory revertError
|
||||
)
|
||||
public
|
||||
returns (address bridge)
|
||||
{
|
||||
return address(new TestDexForwarderBridgeTestBridge(returnCode, revertError));
|
||||
}
|
||||
|
||||
function createToken() public returns (address token) {
|
||||
return address(new TestDexForwarderBridgeTestToken());
|
||||
}
|
||||
|
||||
function setTokenBalance(address token, address owner, uint256 amount) public {
|
||||
TestDexForwarderBridgeTestToken(token).setBalance(owner, amount);
|
||||
}
|
||||
|
||||
function setBridgeTransferAmount(address bridge, uint256 amount) public {
|
||||
TestDexForwarderBridgeTestBridge(bridge).setTransferAmount(amount);
|
||||
}
|
||||
|
||||
function emitBridgeTransferFromCalled(
|
||||
address caller,
|
||||
uint256 inputTokenBalance,
|
||||
address inputToken,
|
||||
address outputToken,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
)
|
||||
public
|
||||
{
|
||||
emit BridgeTransferFromCalled(
|
||||
caller,
|
||||
inputTokenBalance,
|
||||
inputToken,
|
||||
outputToken,
|
||||
from,
|
||||
to,
|
||||
amount
|
||||
);
|
||||
}
|
||||
|
||||
function emitTokenTransferCalled(
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
)
|
||||
public
|
||||
{
|
||||
emit TokenTransferCalled(
|
||||
from,
|
||||
to,
|
||||
amount
|
||||
);
|
||||
}
|
||||
|
||||
function balanceOf(address token, address owner) public view returns (uint256) {
|
||||
return TestDexForwarderBridgeTestToken(token).balanceOf(owner);
|
||||
}
|
||||
|
||||
function _getGstAddress()
|
||||
internal
|
||||
view
|
||||
returns (address gst)
|
||||
{
|
||||
return address(0);
|
||||
}
|
||||
|
||||
function _getERC20BridgeProxyAddress()
|
||||
internal
|
||||
view
|
||||
returns (address erc20BridgeProxyAddress)
|
||||
{
|
||||
return AUTHORIZED_ADDRESS;
|
||||
}
|
||||
}
|
||||
246
contracts/asset-proxy/contracts/test/TestDydxBridge.sol
Normal file
246
contracts/asset-proxy/contracts/test/TestDydxBridge.sol
Normal file
@@ -0,0 +1,246 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||
import "../src/bridges/DydxBridge.sol";
|
||||
|
||||
|
||||
// solhint-disable no-empty-blocks
|
||||
contract TestDydxBridgeToken {
|
||||
|
||||
uint256 private constant INIT_HOLDER_BALANCE = 10 * 10**18; // 10 tokens
|
||||
mapping (address => uint256) private _balances;
|
||||
|
||||
/// @dev Sets initial balance of token holders.
|
||||
constructor(address[] memory holders)
|
||||
public
|
||||
{
|
||||
for (uint256 i = 0; i != holders.length; ++i) {
|
||||
_balances[holders[i]] = INIT_HOLDER_BALANCE;
|
||||
}
|
||||
_balances[msg.sender] = INIT_HOLDER_BALANCE;
|
||||
}
|
||||
|
||||
/// @dev Basic transferFrom implementation.
|
||||
function transferFrom(address from, address to, uint256 amount)
|
||||
external
|
||||
returns (bool)
|
||||
{
|
||||
if (_balances[from] < amount || _balances[to] + amount < _balances[to]) {
|
||||
return false;
|
||||
}
|
||||
_balances[from] -= amount;
|
||||
_balances[to] += amount;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// @dev Returns balance of `holder`.
|
||||
function balanceOf(address holder)
|
||||
external
|
||||
view
|
||||
returns (uint256)
|
||||
{
|
||||
return _balances[holder];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// solhint-disable space-after-comma
|
||||
contract TestDydxBridge is
|
||||
IDydx,
|
||||
DydxBridge
|
||||
{
|
||||
|
||||
address private constant ALWAYS_REVERT_ADDRESS = address(1);
|
||||
address private _testTokenAddress;
|
||||
bool private _shouldRevertOnOperate;
|
||||
|
||||
event OperateAccount(
|
||||
address owner,
|
||||
uint256 number
|
||||
);
|
||||
|
||||
event OperateAction(
|
||||
ActionType actionType,
|
||||
uint256 accountIdx,
|
||||
bool amountSign,
|
||||
AssetDenomination amountDenomination,
|
||||
AssetReference amountRef,
|
||||
uint256 amountValue,
|
||||
uint256 primaryMarketId,
|
||||
uint256 secondaryMarketId,
|
||||
address otherAddress,
|
||||
uint256 otherAccountId,
|
||||
bytes data
|
||||
);
|
||||
|
||||
constructor(address[] memory holders)
|
||||
public
|
||||
{
|
||||
// Deploy a test token. This represents the asset being deposited/withdrawn from dydx.
|
||||
_testTokenAddress = address(new TestDydxBridgeToken(holders));
|
||||
}
|
||||
|
||||
/// @dev Simulates `operate` in dydx contract.
|
||||
/// Emits events so that arguments can be validated client-side.
|
||||
function operate(
|
||||
AccountInfo[] calldata accounts,
|
||||
ActionArgs[] calldata actions
|
||||
)
|
||||
external
|
||||
{
|
||||
if (_shouldRevertOnOperate) {
|
||||
revert("TestDydxBridge/SHOULD_REVERT_ON_OPERATE");
|
||||
}
|
||||
|
||||
for (uint i = 0; i < accounts.length; ++i) {
|
||||
emit OperateAccount(
|
||||
accounts[i].owner,
|
||||
accounts[i].number
|
||||
);
|
||||
}
|
||||
|
||||
for (uint i = 0; i < actions.length; ++i) {
|
||||
emit OperateAction(
|
||||
actions[i].actionType,
|
||||
actions[i].accountIdx,
|
||||
actions[i].amount.sign,
|
||||
actions[i].amount.denomination,
|
||||
actions[i].amount.ref,
|
||||
actions[i].amount.value,
|
||||
actions[i].primaryMarketId,
|
||||
actions[i].secondaryMarketId,
|
||||
actions[i].otherAddress,
|
||||
actions[i].otherAccountIdx,
|
||||
actions[i].data
|
||||
);
|
||||
|
||||
if (actions[i].actionType == IDydx.ActionType.Withdraw) {
|
||||
require(
|
||||
IERC20Token(_testTokenAddress).transferFrom(
|
||||
address(this),
|
||||
actions[i].otherAddress,
|
||||
actions[i].amount.value
|
||||
),
|
||||
"TestDydxBridge/WITHDRAW_FAILED"
|
||||
);
|
||||
} else if (actions[i].actionType == IDydx.ActionType.Deposit) {
|
||||
require(
|
||||
IERC20Token(_testTokenAddress).transferFrom(
|
||||
actions[i].otherAddress,
|
||||
address(this),
|
||||
actions[i].amount.value
|
||||
),
|
||||
"TestDydxBridge/DEPOSIT_FAILED"
|
||||
);
|
||||
} else {
|
||||
revert("TestDydxBridge/UNSUPPORTED_ACTION");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev If `true` then subsequent calls to `operate` will revert.
|
||||
function setRevertOnOperate(bool shouldRevert)
|
||||
external
|
||||
{
|
||||
_shouldRevertOnOperate = shouldRevert;
|
||||
}
|
||||
|
||||
/// @dev Returns test token.
|
||||
function getTestToken()
|
||||
external
|
||||
returns (address)
|
||||
{
|
||||
return _testTokenAddress;
|
||||
}
|
||||
|
||||
/// @dev Unused.
|
||||
function setOperators(OperatorArg[] calldata args) external {}
|
||||
|
||||
/// @dev Unused.
|
||||
function getIsLocalOperator(
|
||||
address owner,
|
||||
address operator
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (bool isLocalOperator)
|
||||
{}
|
||||
|
||||
/// @dev Unused.
|
||||
function getMarketTokenAddress(
|
||||
uint256 marketId
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (address tokenAddress)
|
||||
{}
|
||||
|
||||
/// @dev Unused.
|
||||
function getRiskParams()
|
||||
external
|
||||
view
|
||||
returns (RiskParams memory riskParams)
|
||||
{}
|
||||
|
||||
/// @dev Unsused.
|
||||
function getMarketPrice(
|
||||
uint256 marketId
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (Price memory price)
|
||||
{}
|
||||
|
||||
/// @dev Unsused
|
||||
function getMarketMarginPremium(uint256 marketId)
|
||||
external
|
||||
view
|
||||
returns (IDydx.D256 memory premium)
|
||||
{}
|
||||
|
||||
/// @dev Unused.
|
||||
function getAdjustedAccountValues(
|
||||
AccountInfo calldata account
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (Value memory supplyValue, Value memory borrowValue)
|
||||
{}
|
||||
|
||||
/// @dev overrides `_getDydxAddress()` from `DeploymentConstants` to return this address.
|
||||
function _getDydxAddress()
|
||||
internal
|
||||
view
|
||||
returns (address)
|
||||
{
|
||||
return address(this);
|
||||
}
|
||||
|
||||
/// @dev overrides `_getERC20BridgeProxyAddress()` from `DeploymentConstants` for testing.
|
||||
function _getERC20BridgeProxyAddress()
|
||||
internal
|
||||
view
|
||||
returns (address)
|
||||
{
|
||||
return msg.sender == ALWAYS_REVERT_ADDRESS ? address(0) : msg.sender;
|
||||
}
|
||||
}
|
||||
@@ -110,6 +110,10 @@ contract TestToken {
|
||||
return true;
|
||||
}
|
||||
|
||||
function allowance(address, address) external view returns (uint256) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// @dev Retrieve the balance for `owner`.
|
||||
function balanceOf(address owner)
|
||||
external
|
||||
@@ -192,11 +196,11 @@ contract TestEth2DaiBridge is
|
||||
}
|
||||
|
||||
// @dev This contract will double as the Eth2Dai contract.
|
||||
function _getEth2DaiContract()
|
||||
function _getEth2DaiAddress()
|
||||
internal
|
||||
view
|
||||
returns (IEth2Dai)
|
||||
returns (address)
|
||||
{
|
||||
return IEth2Dai(address(this));
|
||||
return address(this);
|
||||
}
|
||||
}
|
||||
|
||||
355
contracts/asset-proxy/contracts/test/TestKyberBridge.sol
Normal file
355
contracts/asset-proxy/contracts/test/TestKyberBridge.sol
Normal file
@@ -0,0 +1,355 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||
import "../src/bridges/KyberBridge.sol";
|
||||
import "../src/interfaces/IKyberNetworkProxy.sol";
|
||||
|
||||
|
||||
// solhint-disable no-simple-event-func-name
|
||||
interface ITestContract {
|
||||
|
||||
function wethWithdraw(
|
||||
address payable ownerAddress,
|
||||
uint256 amount
|
||||
)
|
||||
external;
|
||||
|
||||
function wethDeposit(
|
||||
address ownerAddress
|
||||
)
|
||||
external
|
||||
payable;
|
||||
|
||||
function tokenTransfer(
|
||||
address ownerAddress,
|
||||
address recipientAddress,
|
||||
uint256 amount
|
||||
)
|
||||
external
|
||||
returns (bool success);
|
||||
|
||||
function tokenApprove(
|
||||
address ownerAddress,
|
||||
address spenderAddress,
|
||||
uint256 allowance
|
||||
)
|
||||
external
|
||||
returns (bool success);
|
||||
|
||||
function tokenBalanceOf(
|
||||
address ownerAddress
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (uint256 balance);
|
||||
}
|
||||
|
||||
|
||||
/// @dev A minimalist ERC20/WETH token.
|
||||
contract TestToken {
|
||||
|
||||
uint8 public decimals;
|
||||
ITestContract private _testContract;
|
||||
|
||||
constructor(uint8 decimals_) public {
|
||||
decimals = decimals_;
|
||||
_testContract = ITestContract(msg.sender);
|
||||
}
|
||||
|
||||
function approve(address spender, uint256 allowance)
|
||||
external
|
||||
returns (bool)
|
||||
{
|
||||
return _testContract.tokenApprove(
|
||||
msg.sender,
|
||||
spender,
|
||||
allowance
|
||||
);
|
||||
}
|
||||
|
||||
function transfer(address recipient, uint256 amount)
|
||||
external
|
||||
returns (bool)
|
||||
{
|
||||
return _testContract.tokenTransfer(
|
||||
msg.sender,
|
||||
recipient,
|
||||
amount
|
||||
);
|
||||
}
|
||||
|
||||
function withdraw(uint256 amount)
|
||||
external
|
||||
{
|
||||
return _testContract.wethWithdraw(msg.sender, amount);
|
||||
}
|
||||
|
||||
function deposit()
|
||||
external
|
||||
payable
|
||||
{
|
||||
return _testContract.wethDeposit.value(msg.value)(msg.sender);
|
||||
}
|
||||
|
||||
function allowance(address, address) external view returns (uint256) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
function balanceOf(address owner)
|
||||
external
|
||||
view
|
||||
returns (uint256)
|
||||
{
|
||||
return _testContract.tokenBalanceOf(owner);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// @dev KyberBridge overridden to mock tokens and implement IKyberBridge.
|
||||
contract TestKyberBridge is
|
||||
KyberBridge,
|
||||
ITestContract,
|
||||
IKyberNetworkProxy
|
||||
{
|
||||
event KyberBridgeTrade(
|
||||
uint256 msgValue,
|
||||
address sellTokenAddress,
|
||||
uint256 sellAmount,
|
||||
address buyTokenAddress,
|
||||
address payable recipientAddress,
|
||||
uint256 maxBuyTokenAmount,
|
||||
uint256 minConversionRate,
|
||||
address walletId
|
||||
);
|
||||
|
||||
event KyberBridgeWethWithdraw(
|
||||
address ownerAddress,
|
||||
uint256 amount
|
||||
);
|
||||
|
||||
event KyberBridgeWethDeposit(
|
||||
uint256 msgValue,
|
||||
address ownerAddress,
|
||||
uint256 amount
|
||||
);
|
||||
|
||||
event KyberBridgeTokenApprove(
|
||||
address tokenAddress,
|
||||
address ownerAddress,
|
||||
address spenderAddress,
|
||||
uint256 allowance
|
||||
);
|
||||
|
||||
event KyberBridgeTokenTransfer(
|
||||
address tokenAddress,
|
||||
address ownerAddress,
|
||||
address recipientAddress,
|
||||
uint256 amount
|
||||
);
|
||||
|
||||
IEtherToken public weth;
|
||||
mapping (address => mapping (address => uint256)) private _tokenBalances;
|
||||
uint256 private _nextFillAmount;
|
||||
|
||||
constructor() public {
|
||||
weth = IEtherToken(address(new TestToken(18)));
|
||||
}
|
||||
|
||||
/// @dev Implementation of `IKyberNetworkProxy.trade()`
|
||||
function trade(
|
||||
address sellTokenAddress,
|
||||
uint256 sellAmount,
|
||||
address buyTokenAddress,
|
||||
address payable recipientAddress,
|
||||
uint256 maxBuyTokenAmount,
|
||||
uint256 minConversionRate,
|
||||
address walletId
|
||||
)
|
||||
external
|
||||
payable
|
||||
returns(uint256 boughtAmount)
|
||||
{
|
||||
emit KyberBridgeTrade(
|
||||
msg.value,
|
||||
sellTokenAddress,
|
||||
sellAmount,
|
||||
buyTokenAddress,
|
||||
recipientAddress,
|
||||
maxBuyTokenAmount,
|
||||
minConversionRate,
|
||||
walletId
|
||||
);
|
||||
return _nextFillAmount;
|
||||
}
|
||||
|
||||
function tradeWithHint(
|
||||
address sellTokenAddress,
|
||||
uint256 sellAmount,
|
||||
address buyTokenAddress,
|
||||
address payable recipientAddress,
|
||||
uint256 maxBuyTokenAmount,
|
||||
uint256 minConversionRate,
|
||||
address payable walletId,
|
||||
bytes calldata hint
|
||||
)
|
||||
external
|
||||
payable
|
||||
returns (uint256 boughtAmount)
|
||||
{
|
||||
emit KyberBridgeTrade(
|
||||
msg.value,
|
||||
sellTokenAddress,
|
||||
sellAmount,
|
||||
buyTokenAddress,
|
||||
recipientAddress,
|
||||
maxBuyTokenAmount,
|
||||
minConversionRate,
|
||||
walletId
|
||||
);
|
||||
return _nextFillAmount;
|
||||
}
|
||||
|
||||
function createToken(uint8 decimals)
|
||||
external
|
||||
returns (address tokenAddress)
|
||||
{
|
||||
return address(new TestToken(decimals));
|
||||
}
|
||||
|
||||
function setNextFillAmount(uint256 amount)
|
||||
external
|
||||
payable
|
||||
{
|
||||
if (msg.value != 0) {
|
||||
require(amount == msg.value, "VALUE_AMOUNT_MISMATCH");
|
||||
grantTokensTo(address(weth), address(this), msg.value);
|
||||
}
|
||||
_nextFillAmount = amount;
|
||||
}
|
||||
|
||||
function wethDeposit(
|
||||
address ownerAddress
|
||||
)
|
||||
external
|
||||
payable
|
||||
{
|
||||
require(msg.sender == address(weth), "ONLY_WETH");
|
||||
grantTokensTo(address(weth), ownerAddress, msg.value);
|
||||
emit KyberBridgeWethDeposit(
|
||||
msg.value,
|
||||
ownerAddress,
|
||||
msg.value
|
||||
);
|
||||
}
|
||||
|
||||
function wethWithdraw(
|
||||
address payable ownerAddress,
|
||||
uint256 amount
|
||||
)
|
||||
external
|
||||
{
|
||||
require(msg.sender == address(weth), "ONLY_WETH");
|
||||
_tokenBalances[address(weth)][ownerAddress] -= amount;
|
||||
ownerAddress.transfer(amount);
|
||||
emit KyberBridgeWethWithdraw(
|
||||
ownerAddress,
|
||||
amount
|
||||
);
|
||||
}
|
||||
|
||||
function tokenApprove(
|
||||
address ownerAddress,
|
||||
address spenderAddress,
|
||||
uint256 allowance
|
||||
)
|
||||
external
|
||||
returns (bool success)
|
||||
{
|
||||
emit KyberBridgeTokenApprove(
|
||||
msg.sender,
|
||||
ownerAddress,
|
||||
spenderAddress,
|
||||
allowance
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
function tokenTransfer(
|
||||
address ownerAddress,
|
||||
address recipientAddress,
|
||||
uint256 amount
|
||||
)
|
||||
external
|
||||
returns (bool success)
|
||||
{
|
||||
_tokenBalances[msg.sender][ownerAddress] -= amount;
|
||||
_tokenBalances[msg.sender][recipientAddress] += amount;
|
||||
emit KyberBridgeTokenTransfer(
|
||||
msg.sender,
|
||||
ownerAddress,
|
||||
recipientAddress,
|
||||
amount
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
function tokenBalanceOf(
|
||||
address ownerAddress
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (uint256 balance)
|
||||
{
|
||||
return _tokenBalances[msg.sender][ownerAddress];
|
||||
}
|
||||
|
||||
function grantTokensTo(address tokenAddress, address ownerAddress, uint256 amount)
|
||||
public
|
||||
payable
|
||||
{
|
||||
_tokenBalances[tokenAddress][ownerAddress] += amount;
|
||||
if (tokenAddress != address(weth)) {
|
||||
// Send back ether if not WETH.
|
||||
msg.sender.transfer(msg.value);
|
||||
} else {
|
||||
require(msg.value == amount, "VALUE_AMOUNT_MISMATCH");
|
||||
}
|
||||
}
|
||||
|
||||
// @dev overridden to point to this contract.
|
||||
function _getKyberNetworkProxyAddress()
|
||||
internal
|
||||
view
|
||||
returns (address)
|
||||
{
|
||||
return address(this);
|
||||
}
|
||||
|
||||
// @dev overridden to point to test WETH.
|
||||
function _getWethAddress()
|
||||
internal
|
||||
view
|
||||
returns (address)
|
||||
{
|
||||
return address(weth);
|
||||
}
|
||||
}
|
||||
@@ -224,6 +224,10 @@ contract TestToken {
|
||||
TestEventsRaiser(msg.sender).raiseWethWithdraw(amount);
|
||||
}
|
||||
|
||||
function allowance(address, address) external view returns (uint256) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// @dev Retrieve the balance for `owner`.
|
||||
function balanceOf(address owner)
|
||||
external
|
||||
@@ -407,26 +411,26 @@ contract TestUniswapBridge is
|
||||
function getExchange(address tokenAddress)
|
||||
external
|
||||
view
|
||||
returns (IUniswapExchange)
|
||||
returns (address)
|
||||
{
|
||||
return IUniswapExchange(_testExchanges[tokenAddress]);
|
||||
return address(_testExchanges[tokenAddress]);
|
||||
}
|
||||
|
||||
// @dev Use `wethToken`.
|
||||
function getWethContract()
|
||||
public
|
||||
function _getWethAddress()
|
||||
internal
|
||||
view
|
||||
returns (IEtherToken)
|
||||
returns (address)
|
||||
{
|
||||
return IEtherToken(address(wethToken));
|
||||
return address(wethToken);
|
||||
}
|
||||
|
||||
// @dev This contract will double as the Uniswap contract.
|
||||
function getUniswapExchangeFactoryContract()
|
||||
public
|
||||
function _getUniswapExchangeFactoryAddress()
|
||||
internal
|
||||
view
|
||||
returns (IUniswapExchangeFactory)
|
||||
returns (address)
|
||||
{
|
||||
return IUniswapExchangeFactory(address(this));
|
||||
return address(this);
|
||||
}
|
||||
}
|
||||
|
||||
253
contracts/asset-proxy/contracts/test/TestUniswapV2Bridge.sol
Normal file
253
contracts/asset-proxy/contracts/test/TestUniswapV2Bridge.sol
Normal file
@@ -0,0 +1,253 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibAddressArray.sol";
|
||||
import "../src/bridges/UniswapV2Bridge.sol";
|
||||
import "../src/interfaces/IUniswapV2Router01.sol";
|
||||
|
||||
|
||||
contract TestEventsRaiser {
|
||||
|
||||
event TokenTransfer(
|
||||
address token,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
);
|
||||
|
||||
event TokenApprove(
|
||||
address spender,
|
||||
uint256 allowance
|
||||
);
|
||||
|
||||
event SwapExactTokensForTokensInput(
|
||||
uint amountIn,
|
||||
uint amountOutMin,
|
||||
address toTokenAddress,
|
||||
address to,
|
||||
uint deadline
|
||||
);
|
||||
|
||||
function raiseTokenTransfer(
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
)
|
||||
external
|
||||
{
|
||||
emit TokenTransfer(
|
||||
msg.sender,
|
||||
from,
|
||||
to,
|
||||
amount
|
||||
);
|
||||
}
|
||||
|
||||
function raiseTokenApprove(address spender, uint256 allowance) external {
|
||||
emit TokenApprove(spender, allowance);
|
||||
}
|
||||
|
||||
function raiseSwapExactTokensForTokensInput(
|
||||
uint amountIn,
|
||||
uint amountOutMin,
|
||||
address toTokenAddress,
|
||||
address to,
|
||||
uint deadline
|
||||
) external
|
||||
{
|
||||
emit SwapExactTokensForTokensInput(
|
||||
amountIn,
|
||||
amountOutMin,
|
||||
toTokenAddress,
|
||||
to,
|
||||
deadline
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// @dev A minimalist ERC20 token.
|
||||
contract TestToken {
|
||||
|
||||
using LibSafeMath for uint256;
|
||||
|
||||
mapping (address => uint256) public balances;
|
||||
string private _nextRevertReason;
|
||||
|
||||
/// @dev Set the balance for `owner`.
|
||||
function setBalance(address owner, uint256 balance)
|
||||
external
|
||||
payable
|
||||
{
|
||||
balances[owner] = balance;
|
||||
}
|
||||
|
||||
/// @dev Just emits a TokenTransfer event on the caller
|
||||
function transfer(address to, uint256 amount)
|
||||
external
|
||||
returns (bool)
|
||||
{
|
||||
TestEventsRaiser(msg.sender).raiseTokenTransfer(msg.sender, to, amount);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// @dev Just emits a TokenApprove event on the caller
|
||||
function approve(address spender, uint256 allowance)
|
||||
external
|
||||
returns (bool)
|
||||
{
|
||||
TestEventsRaiser(msg.sender).raiseTokenApprove(spender, allowance);
|
||||
return true;
|
||||
}
|
||||
|
||||
function allowance(address, address) external view returns (uint256) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// @dev Retrieve the balance for `owner`.
|
||||
function balanceOf(address owner)
|
||||
external
|
||||
view
|
||||
returns (uint256)
|
||||
{
|
||||
return balances[owner];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// @dev Mock the UniswapV2Router01 contract
|
||||
contract TestRouter is
|
||||
IUniswapV2Router01
|
||||
{
|
||||
string private _nextRevertReason;
|
||||
|
||||
/// @dev Set the revert reason for `swapExactTokensForTokens`.
|
||||
function setRevertReason(string calldata reason)
|
||||
external
|
||||
{
|
||||
_nextRevertReason = reason;
|
||||
}
|
||||
|
||||
function swapExactTokensForTokens(
|
||||
uint amountIn,
|
||||
uint amountOutMin,
|
||||
address[] calldata path,
|
||||
address to,
|
||||
uint deadline
|
||||
) external returns (uint[] memory amounts)
|
||||
{
|
||||
_revertIfReasonExists();
|
||||
|
||||
amounts = new uint[](path.length);
|
||||
amounts[0] = amountIn;
|
||||
amounts[amounts.length - 1] = amountOutMin;
|
||||
|
||||
TestEventsRaiser(msg.sender).raiseSwapExactTokensForTokensInput(
|
||||
// tokens sold
|
||||
amountIn,
|
||||
// tokens bought
|
||||
amountOutMin,
|
||||
// output token (toTokenAddress)
|
||||
path[path.length - 1],
|
||||
// recipient
|
||||
to,
|
||||
// deadline
|
||||
deadline
|
||||
);
|
||||
}
|
||||
|
||||
function _revertIfReasonExists()
|
||||
private
|
||||
view
|
||||
{
|
||||
if (bytes(_nextRevertReason).length != 0) {
|
||||
revert(_nextRevertReason);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// @dev UniswapV2Bridge overridden to mock tokens and Uniswap router
|
||||
contract TestUniswapV2Bridge is
|
||||
UniswapV2Bridge,
|
||||
TestEventsRaiser
|
||||
{
|
||||
|
||||
// Token address to TestToken instance.
|
||||
mapping (address => TestToken) private _testTokens;
|
||||
// TestRouter instance.
|
||||
TestRouter private _testRouter;
|
||||
|
||||
constructor() public {
|
||||
_testRouter = new TestRouter();
|
||||
}
|
||||
|
||||
function setRouterRevertReason(string calldata revertReason)
|
||||
external
|
||||
{
|
||||
_testRouter.setRevertReason(revertReason);
|
||||
}
|
||||
|
||||
/// @dev Sets the balance of this contract for an existing token.
|
||||
/// The wei attached will be the balance.
|
||||
function setTokenBalance(address tokenAddress, uint256 balance)
|
||||
external
|
||||
{
|
||||
TestToken token = _testTokens[tokenAddress];
|
||||
token.setBalance(address(this), balance);
|
||||
}
|
||||
|
||||
/// @dev Create a new token
|
||||
/// @param tokenAddress The token address. If zero, one will be created.
|
||||
function createToken(
|
||||
address tokenAddress
|
||||
)
|
||||
external
|
||||
returns (TestToken token)
|
||||
{
|
||||
token = TestToken(tokenAddress);
|
||||
if (tokenAddress == address(0)) {
|
||||
token = new TestToken();
|
||||
}
|
||||
_testTokens[address(token)] = token;
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
function getRouterAddress()
|
||||
external
|
||||
view
|
||||
returns (address)
|
||||
{
|
||||
return address(_testRouter);
|
||||
}
|
||||
|
||||
function _getUniswapV2Router01Address()
|
||||
internal
|
||||
view
|
||||
returns (address)
|
||||
{
|
||||
return address(_testRouter);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-asset-proxy",
|
||||
"version": "2.3.0-beta.1",
|
||||
"version": "3.7.10",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -12,7 +12,7 @@
|
||||
"scripts": {
|
||||
"build": "yarn pre_build && tsc -b",
|
||||
"build:ci": "yarn build",
|
||||
"pre_build": "run-s compile contracts:gen generate_contract_wrappers",
|
||||
"pre_build": "run-s compile contracts:gen generate_contract_wrappers contracts:copy",
|
||||
"test": "yarn run_mocha",
|
||||
"rebuild_and_test": "run-s build test",
|
||||
"test:coverage": "SOLIDITY_COVERAGE=true run-s build run_mocha coverage:report:text coverage:report:lcov",
|
||||
@@ -21,46 +21,53 @@
|
||||
"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 --debug --abis ${npm_package_config_abis} --output generated-wrappers --backend ethers",
|
||||
"lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
|
||||
"fix": "tslint --fix --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
|
||||
"clean": "shx rm -rf lib test/generated-artifacts test/generated-wrappers generated-artifacts generated-wrappers",
|
||||
"generate_contract_wrappers": "abi-gen --debug --abis ${npm_package_config_abis} --output test/generated-wrappers --backend ethers",
|
||||
"lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./test/generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
|
||||
"fix": "tslint --fix --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./test/generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
|
||||
"coverage:report:text": "istanbul report text",
|
||||
"coverage:report:html": "istanbul report html && open coverage/index.html",
|
||||
"profiler:report:html": "istanbul report html && open coverage/index.html",
|
||||
"coverage:report:lcov": "istanbul report lcov",
|
||||
"test:circleci": "yarn test",
|
||||
"contracts:gen": "contracts-gen",
|
||||
"contracts:gen": "contracts-gen generate",
|
||||
"contracts:copy": "contracts-gen copy",
|
||||
"lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol",
|
||||
"compile:truffle": "truffle compile"
|
||||
"compile:truffle": "truffle compile",
|
||||
"docs:md": "ts-doc-gen --sourceDir='$PROJECT_FILES' --output=$MD_FILE_DIR --fileExtension=mdx --tsconfig=./typedoc-tsconfig.json",
|
||||
"docs:json": "typedoc --excludePrivate --excludeExternals --excludeProtected --ignoreCompilerErrors --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES"
|
||||
},
|
||||
"config": {
|
||||
"abis": "./generated-artifacts/@(ERC1155Proxy|ERC20BridgeProxy|ERC20Proxy|ERC721Proxy|Eth2DaiBridge|IAssetData|IAssetProxy|IAssetProxyDispatcher|IAuthorizable|IERC20Bridge|IEth2Dai|IUniswapExchange|IUniswapExchangeFactory|MixinAssetProxyDispatcher|MixinAuthorizable|MultiAssetProxy|Ownable|StaticCallProxy|TestERC20Bridge|TestEth2DaiBridge|TestStaticCallTarget|TestUniswapBridge|UniswapBridge).json",
|
||||
"abis": "./test/generated-artifacts/@(BalancerBridge|BancorBridge|ChaiBridge|CreamBridge|CryptoComBridge|CurveBridge|DODOBridge|DexForwarderBridge|DydxBridge|ERC1155Proxy|ERC20BridgeProxy|ERC20Proxy|ERC721Proxy|Eth2DaiBridge|IAssetData|IAssetProxy|IAssetProxyDispatcher|IAuthorizable|IBalancerPool|IBancorNetwork|IChai|ICurve|IDydx|IDydxBridge|IERC20Bridge|IEth2Dai|IGasToken|IKyberNetworkProxy|IMStable|IMooniswap|IShell|IUniswapExchange|IUniswapExchangeFactory|IUniswapV2Router01|KyberBridge|MStableBridge|MixinAssetProxyDispatcher|MixinAuthorizable|MixinGasToken|MooniswapBridge|MultiAssetProxy|Ownable|ShellBridge|SnowSwapBridge|StaticCallProxy|SushiSwapBridge|SwerveBridge|TestBancorBridge|TestChaiBridge|TestDexForwarderBridge|TestDydxBridge|TestERC20Bridge|TestEth2DaiBridge|TestKyberBridge|TestStaticCallTarget|TestUniswapBridge|TestUniswapV2Bridge|UniswapBridge|UniswapV2Bridge).json",
|
||||
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually."
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/0xProject/0x-monorepo.git"
|
||||
"url": "https://github.com/0xProject/protocol.git"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/0xProject/0x-monorepo/issues"
|
||||
"url": "https://github.com/0xProject/protocol/issues"
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/protocol/README.md",
|
||||
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/protocol",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^4.4.0-beta.1",
|
||||
"@0x/contracts-gen": "^1.1.0-beta.1",
|
||||
"@0x/contracts-test-utils": "^3.2.0-beta.1",
|
||||
"@0x/dev-utils": "^2.4.0-beta.1",
|
||||
"@0x/sol-compiler": "^3.2.0-beta.1",
|
||||
"@0x/tslint-config": "^3.1.0-beta.1",
|
||||
"@0x/abi-gen": "^5.5.2",
|
||||
"@0x/contract-wrappers": "^13.16.0",
|
||||
"@0x/contracts-gen": "^2.0.37",
|
||||
"@0x/contracts-test-utils": "^5.3.25",
|
||||
"@0x/contracts-utils": "^4.7.7",
|
||||
"@0x/dev-utils": "^4.2.6",
|
||||
"@0x/sol-compiler": "^4.7.2",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
"@0x/tslint-config": "^4.1.4",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "*",
|
||||
"@types/node": "12.12.54",
|
||||
"chai": "^4.0.1",
|
||||
"chai-as-promised": "^7.1.0",
|
||||
"chai-bignumber": "^3.0.0",
|
||||
"dirty-chai": "^2.0.1",
|
||||
"ethereumjs-util": "^7.0.10",
|
||||
"make-promises-safe": "^1.1.0",
|
||||
"mocha": "^6.2.0",
|
||||
"npm-run-all": "^4.1.2",
|
||||
@@ -68,25 +75,25 @@
|
||||
"solhint": "^1.4.1",
|
||||
"truffle": "^5.0.32",
|
||||
"tslint": "5.11.0",
|
||||
"typescript": "3.0.1"
|
||||
"typedoc": "~0.16.11",
|
||||
"typescript": "4.2.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^5.5.0-beta.1",
|
||||
"@0x/contracts-dev-utils": "^0.1.0-beta.1",
|
||||
"@0x/contracts-erc1155": "^1.2.0-beta.1",
|
||||
"@0x/contracts-erc20": "^2.3.0-beta.1",
|
||||
"@0x/contracts-erc721": "^2.2.0-beta.1",
|
||||
"@0x/contracts-utils": "^3.3.0-beta.1",
|
||||
"@0x/order-utils": "^8.5.0-beta.1",
|
||||
"@0x/types": "^2.5.0-beta.1",
|
||||
"@0x/typescript-typings": "^4.4.0-beta.1",
|
||||
"@0x/utils": "^4.6.0-beta.1",
|
||||
"@0x/web3-wrapper": "^6.1.0-beta.1",
|
||||
"ethereum-types": "^2.2.0-beta.1",
|
||||
"ethereumjs-util": "^5.1.1",
|
||||
"@0x/base-contract": "^6.3.2",
|
||||
"@0x/contracts-erc1155": "^2.1.28",
|
||||
"@0x/contracts-erc20": "^3.3.7",
|
||||
"@0x/contracts-erc721": "^3.1.28",
|
||||
"@0x/contracts-exchange-libs": "^4.3.28",
|
||||
"@0x/order-utils": "^10.4.20",
|
||||
"@0x/types": "^3.3.3",
|
||||
"@0x/typescript-typings": "^5.2.0",
|
||||
"@0x/utils": "^6.4.2",
|
||||
"@0x/web3-wrapper": "^7.5.2",
|
||||
"ethereum-types": "^3.5.0",
|
||||
"lodash": "^4.17.11"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
},
|
||||
"gitHead": "4f91bfd907996b2f4dd383778b50c479c2602b56"
|
||||
}
|
||||
|
||||
@@ -5,6 +5,15 @@
|
||||
*/
|
||||
import { ContractArtifact } from 'ethereum-types';
|
||||
|
||||
import * as BalancerBridge from '../generated-artifacts/BalancerBridge.json';
|
||||
import * as BancorBridge from '../generated-artifacts/BancorBridge.json';
|
||||
import * as ChaiBridge from '../generated-artifacts/ChaiBridge.json';
|
||||
import * as CreamBridge from '../generated-artifacts/CreamBridge.json';
|
||||
import * as CryptoComBridge from '../generated-artifacts/CryptoComBridge.json';
|
||||
import * as CurveBridge from '../generated-artifacts/CurveBridge.json';
|
||||
import * as DexForwarderBridge from '../generated-artifacts/DexForwarderBridge.json';
|
||||
import * as DODOBridge from '../generated-artifacts/DODOBridge.json';
|
||||
import * as DydxBridge from '../generated-artifacts/DydxBridge.json';
|
||||
import * as ERC1155Proxy from '../generated-artifacts/ERC1155Proxy.json';
|
||||
import * as ERC20BridgeProxy from '../generated-artifacts/ERC20BridgeProxy.json';
|
||||
import * as ERC20Proxy from '../generated-artifacts/ERC20Proxy.json';
|
||||
@@ -14,20 +23,47 @@ 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 IBalancerPool from '../generated-artifacts/IBalancerPool.json';
|
||||
import * as IBancorNetwork from '../generated-artifacts/IBancorNetwork.json';
|
||||
import * as IChai from '../generated-artifacts/IChai.json';
|
||||
import * as ICurve from '../generated-artifacts/ICurve.json';
|
||||
import * as IDydx from '../generated-artifacts/IDydx.json';
|
||||
import * as IDydxBridge from '../generated-artifacts/IDydxBridge.json';
|
||||
import * as IERC20Bridge from '../generated-artifacts/IERC20Bridge.json';
|
||||
import * as IEth2Dai from '../generated-artifacts/IEth2Dai.json';
|
||||
import * as IGasToken from '../generated-artifacts/IGasToken.json';
|
||||
import * as IKyberNetworkProxy from '../generated-artifacts/IKyberNetworkProxy.json';
|
||||
import * as IMooniswap from '../generated-artifacts/IMooniswap.json';
|
||||
import * as IMStable from '../generated-artifacts/IMStable.json';
|
||||
import * as IShell from '../generated-artifacts/IShell.json';
|
||||
import * as IUniswapExchange from '../generated-artifacts/IUniswapExchange.json';
|
||||
import * as IUniswapExchangeFactory from '../generated-artifacts/IUniswapExchangeFactory.json';
|
||||
import * as IUniswapV2Router01 from '../generated-artifacts/IUniswapV2Router01.json';
|
||||
import * as KyberBridge from '../generated-artifacts/KyberBridge.json';
|
||||
import * as MixinAssetProxyDispatcher from '../generated-artifacts/MixinAssetProxyDispatcher.json';
|
||||
import * as MixinAuthorizable from '../generated-artifacts/MixinAuthorizable.json';
|
||||
import * as MixinGasToken from '../generated-artifacts/MixinGasToken.json';
|
||||
import * as MooniswapBridge from '../generated-artifacts/MooniswapBridge.json';
|
||||
import * as MStableBridge from '../generated-artifacts/MStableBridge.json';
|
||||
import * as MultiAssetProxy from '../generated-artifacts/MultiAssetProxy.json';
|
||||
import * as Ownable from '../generated-artifacts/Ownable.json';
|
||||
import * as ShellBridge from '../generated-artifacts/ShellBridge.json';
|
||||
import * as SnowSwapBridge from '../generated-artifacts/SnowSwapBridge.json';
|
||||
import * as StaticCallProxy from '../generated-artifacts/StaticCallProxy.json';
|
||||
import * as SushiSwapBridge from '../generated-artifacts/SushiSwapBridge.json';
|
||||
import * as SwerveBridge from '../generated-artifacts/SwerveBridge.json';
|
||||
import * as TestBancorBridge from '../generated-artifacts/TestBancorBridge.json';
|
||||
import * as TestChaiBridge from '../generated-artifacts/TestChaiBridge.json';
|
||||
import * as TestDexForwarderBridge from '../generated-artifacts/TestDexForwarderBridge.json';
|
||||
import * as TestDydxBridge from '../generated-artifacts/TestDydxBridge.json';
|
||||
import * as TestERC20Bridge from '../generated-artifacts/TestERC20Bridge.json';
|
||||
import * as TestEth2DaiBridge from '../generated-artifacts/TestEth2DaiBridge.json';
|
||||
import * as TestKyberBridge from '../generated-artifacts/TestKyberBridge.json';
|
||||
import * as TestStaticCallTarget from '../generated-artifacts/TestStaticCallTarget.json';
|
||||
import * as TestUniswapBridge from '../generated-artifacts/TestUniswapBridge.json';
|
||||
import * as TestUniswapV2Bridge from '../generated-artifacts/TestUniswapV2Bridge.json';
|
||||
import * as UniswapBridge from '../generated-artifacts/UniswapBridge.json';
|
||||
import * as UniswapV2Bridge from '../generated-artifacts/UniswapV2Bridge.json';
|
||||
export const artifacts = {
|
||||
MixinAssetProxyDispatcher: MixinAssetProxyDispatcher as ContractArtifact,
|
||||
MixinAuthorizable: MixinAuthorizable as ContractArtifact,
|
||||
@@ -38,18 +74,54 @@ export const artifacts = {
|
||||
ERC721Proxy: ERC721Proxy as ContractArtifact,
|
||||
MultiAssetProxy: MultiAssetProxy as ContractArtifact,
|
||||
StaticCallProxy: StaticCallProxy as ContractArtifact,
|
||||
BalancerBridge: BalancerBridge as ContractArtifact,
|
||||
BancorBridge: BancorBridge as ContractArtifact,
|
||||
ChaiBridge: ChaiBridge as ContractArtifact,
|
||||
CreamBridge: CreamBridge as ContractArtifact,
|
||||
CryptoComBridge: CryptoComBridge as ContractArtifact,
|
||||
CurveBridge: CurveBridge as ContractArtifact,
|
||||
DODOBridge: DODOBridge as ContractArtifact,
|
||||
DexForwarderBridge: DexForwarderBridge as ContractArtifact,
|
||||
DydxBridge: DydxBridge as ContractArtifact,
|
||||
Eth2DaiBridge: Eth2DaiBridge as ContractArtifact,
|
||||
KyberBridge: KyberBridge as ContractArtifact,
|
||||
MStableBridge: MStableBridge as ContractArtifact,
|
||||
MixinGasToken: MixinGasToken as ContractArtifact,
|
||||
MooniswapBridge: MooniswapBridge as ContractArtifact,
|
||||
ShellBridge: ShellBridge as ContractArtifact,
|
||||
SnowSwapBridge: SnowSwapBridge as ContractArtifact,
|
||||
SushiSwapBridge: SushiSwapBridge as ContractArtifact,
|
||||
SwerveBridge: SwerveBridge as ContractArtifact,
|
||||
UniswapBridge: UniswapBridge as ContractArtifact,
|
||||
UniswapV2Bridge: UniswapV2Bridge as ContractArtifact,
|
||||
IAssetData: IAssetData as ContractArtifact,
|
||||
IAssetProxy: IAssetProxy as ContractArtifact,
|
||||
IAssetProxyDispatcher: IAssetProxyDispatcher as ContractArtifact,
|
||||
IAuthorizable: IAuthorizable as ContractArtifact,
|
||||
IBalancerPool: IBalancerPool as ContractArtifact,
|
||||
IBancorNetwork: IBancorNetwork as ContractArtifact,
|
||||
IChai: IChai as ContractArtifact,
|
||||
ICurve: ICurve as ContractArtifact,
|
||||
IDydx: IDydx as ContractArtifact,
|
||||
IDydxBridge: IDydxBridge as ContractArtifact,
|
||||
IERC20Bridge: IERC20Bridge as ContractArtifact,
|
||||
IEth2Dai: IEth2Dai as ContractArtifact,
|
||||
IGasToken: IGasToken as ContractArtifact,
|
||||
IKyberNetworkProxy: IKyberNetworkProxy as ContractArtifact,
|
||||
IMStable: IMStable as ContractArtifact,
|
||||
IMooniswap: IMooniswap as ContractArtifact,
|
||||
IShell: IShell as ContractArtifact,
|
||||
IUniswapExchange: IUniswapExchange as ContractArtifact,
|
||||
IUniswapExchangeFactory: IUniswapExchangeFactory as ContractArtifact,
|
||||
IUniswapV2Router01: IUniswapV2Router01 as ContractArtifact,
|
||||
TestBancorBridge: TestBancorBridge as ContractArtifact,
|
||||
TestChaiBridge: TestChaiBridge as ContractArtifact,
|
||||
TestDexForwarderBridge: TestDexForwarderBridge as ContractArtifact,
|
||||
TestDydxBridge: TestDydxBridge as ContractArtifact,
|
||||
TestERC20Bridge: TestERC20Bridge as ContractArtifact,
|
||||
TestEth2DaiBridge: TestEth2DaiBridge as ContractArtifact,
|
||||
TestKyberBridge: TestKyberBridge as ContractArtifact,
|
||||
TestStaticCallTarget: TestStaticCallTarget as ContractArtifact,
|
||||
TestUniswapBridge: TestUniswapBridge as ContractArtifact,
|
||||
TestUniswapV2Bridge: TestUniswapV2Bridge as ContractArtifact,
|
||||
};
|
||||
|
||||
112
contracts/asset-proxy/src/asset_data.ts
Normal file
112
contracts/asset-proxy/src/asset_data.ts
Normal file
@@ -0,0 +1,112 @@
|
||||
import { AssetProxyId } from '@0x/types';
|
||||
import { BigNumber, hexUtils } from '@0x/utils';
|
||||
|
||||
import { IAssetDataContract } from './wrappers';
|
||||
|
||||
const assetDataIface = new IAssetDataContract('0x0000000000000000000000000000000000000000', { isEIP1193: true } as any);
|
||||
|
||||
/**
|
||||
* Get the proxy ID from encoded asset data.
|
||||
*/
|
||||
export function getAssetDataProxyId(encoded: string): AssetProxyId {
|
||||
// tslint:disable-next-line: no-unnecessary-type-assertion
|
||||
return hexUtils.slice(encoded, 0, 4) as AssetProxyId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode ERC20 asset data.
|
||||
*/
|
||||
export function decodeERC20AssetData(encoded: string): string {
|
||||
return assetDataIface.getABIDecodedTransactionData<string>('ERC20Token', encoded);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode ERC721 asset data.
|
||||
*/
|
||||
export function decodeERC721AssetData(encoded: string): [string, BigNumber] {
|
||||
return assetDataIface.getABIDecodedTransactionData<[string, BigNumber]>('ERC721Token', encoded);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode ERC1155 asset data.
|
||||
*/
|
||||
export function decodeERC1155AssetData(encoded: string): [string, BigNumber[], BigNumber[], string] {
|
||||
return assetDataIface.getABIDecodedTransactionData<[string, BigNumber[], BigNumber[], string]>(
|
||||
'ERC1155Assets',
|
||||
encoded,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode MultiAsset asset data.
|
||||
*/
|
||||
export function decodeMultiAssetData(encoded: string): [BigNumber[], string[]] {
|
||||
return assetDataIface.getABIDecodedTransactionData<[BigNumber[], string[]]>('MultiAsset', encoded);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode StaticCall asset data.
|
||||
*/
|
||||
export function decodeStaticCallAssetData(encoded: string): [string, string, string] {
|
||||
return assetDataIface.getABIDecodedTransactionData<[string, string, string]>('StaticCall', encoded);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode ERC20Bridge asset data.
|
||||
*/
|
||||
export function decodeERC20BridgeAssetData(encoded: string): [string, string, string] {
|
||||
return assetDataIface.getABIDecodedTransactionData<[string, string, string]>('ERC20Bridge', encoded);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode ERC20 asset data.
|
||||
*/
|
||||
export function encodeERC20AssetData(tokenAddress: string): string {
|
||||
return assetDataIface.ERC20Token(tokenAddress).getABIEncodedTransactionData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode ERC721 asset data.
|
||||
*/
|
||||
export function encodeERC721AssetData(tokenAddress: string, tokenId: BigNumber): string {
|
||||
return assetDataIface.ERC721Token(tokenAddress, tokenId).getABIEncodedTransactionData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode ERC1155 asset data.
|
||||
*/
|
||||
export function encodeERC1155AssetData(
|
||||
tokenAddress: string,
|
||||
tokenIds: BigNumber[],
|
||||
values: BigNumber[],
|
||||
callbackData: string,
|
||||
): string {
|
||||
return assetDataIface.ERC1155Assets(tokenAddress, tokenIds, values, callbackData).getABIEncodedTransactionData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode MultiAsset asset data.
|
||||
*/
|
||||
export function encodeMultiAssetData(values: BigNumber[], nestedAssetData: string[]): string {
|
||||
return assetDataIface.MultiAsset(values, nestedAssetData).getABIEncodedTransactionData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode StaticCall asset data.
|
||||
*/
|
||||
export function encodeStaticCallAssetData(
|
||||
staticCallTargetAddress: string,
|
||||
staticCallData: string,
|
||||
expectedReturnDataHash: string,
|
||||
): string {
|
||||
return assetDataIface
|
||||
.StaticCall(staticCallTargetAddress, staticCallData, expectedReturnDataHash)
|
||||
.getABIEncodedTransactionData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode ERC20Bridge asset data.
|
||||
*/
|
||||
export function encodeERC20BridgeAssetData(tokenAddress: string, bridgeAddress: string, bridgeData: string): string {
|
||||
return assetDataIface.ERC20Bridge(tokenAddress, bridgeAddress, bridgeData).getABIEncodedTransactionData();
|
||||
}
|
||||
27
contracts/asset-proxy/src/dex_forwarder_bridge.ts
Normal file
27
contracts/asset-proxy/src/dex_forwarder_bridge.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { AbiEncoder, BigNumber } from '@0x/utils';
|
||||
|
||||
export interface DexForwarderBridgeCall {
|
||||
target: string;
|
||||
inputTokenAmount: BigNumber;
|
||||
outputTokenAmount: BigNumber;
|
||||
bridgeData: string;
|
||||
}
|
||||
|
||||
export interface DexForwaderBridgeData {
|
||||
inputToken: string;
|
||||
calls: DexForwarderBridgeCall[];
|
||||
}
|
||||
|
||||
export const dexForwarderBridgeDataEncoder = AbiEncoder.create([
|
||||
{ name: 'inputToken', type: 'address' },
|
||||
{
|
||||
name: 'calls',
|
||||
type: 'tuple[]',
|
||||
components: [
|
||||
{ name: 'target', type: 'address' },
|
||||
{ name: 'inputTokenAmount', type: 'uint256' },
|
||||
{ name: 'outputTokenAmount', type: 'uint256' },
|
||||
{ name: 'bridgeData', type: 'bytes' },
|
||||
],
|
||||
},
|
||||
]);
|
||||
40
contracts/asset-proxy/src/dydx_bridge_encoder.ts
Normal file
40
contracts/asset-proxy/src/dydx_bridge_encoder.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { AbiEncoder, BigNumber } from '@0x/utils';
|
||||
|
||||
export enum DydxBridgeActionType {
|
||||
Deposit,
|
||||
Withdraw,
|
||||
}
|
||||
|
||||
export interface DydxBridgeAction {
|
||||
actionType: DydxBridgeActionType;
|
||||
accountIdx: BigNumber;
|
||||
marketId: BigNumber;
|
||||
conversionRateNumerator: BigNumber;
|
||||
conversionRateDenominator: BigNumber;
|
||||
}
|
||||
|
||||
export interface DydxBridgeData {
|
||||
accountNumbers: BigNumber[];
|
||||
actions: DydxBridgeAction[];
|
||||
}
|
||||
|
||||
export const dydxBridgeDataEncoder = AbiEncoder.create([
|
||||
{
|
||||
name: 'bridgeData',
|
||||
type: 'tuple',
|
||||
components: [
|
||||
{ name: 'accountNumbers', type: 'uint256[]' },
|
||||
{
|
||||
name: 'actions',
|
||||
type: 'tuple[]',
|
||||
components: [
|
||||
{ name: 'actionType', type: 'uint8' },
|
||||
{ name: 'accountIdx', type: 'uint256' },
|
||||
{ name: 'marketId', type: 'uint256' },
|
||||
{ name: 'conversionRateNumerator', type: 'uint256' },
|
||||
{ name: 'conversionRateDenominator', type: 'uint256' },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
@@ -1,4 +1,3 @@
|
||||
import { DevUtilsContract } from '@0x/contracts-dev-utils';
|
||||
import { artifacts as erc1155Artifacts, ERC1155MintableContract, Erc1155Wrapper } from '@0x/contracts-erc1155';
|
||||
import {
|
||||
constants,
|
||||
@@ -13,7 +12,9 @@ import { Web3Wrapper } from '@0x/web3-wrapper';
|
||||
import { Provider, TransactionReceiptWithDecodedLogs } from 'ethereum-types';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { artifacts, ERC1155ProxyContract, IAssetProxyContract } from '../../src';
|
||||
import { artifacts } from './artifacts';
|
||||
|
||||
import { ERC1155ProxyContract, IAssetDataContract, IAssetProxyContract } from './wrappers';
|
||||
|
||||
export class ERC1155ProxyWrapper {
|
||||
private readonly _tokenOwnerAddresses: string[];
|
||||
@@ -26,7 +27,7 @@ export class ERC1155ProxyWrapper {
|
||||
private readonly _logDecoder: LogDecoder;
|
||||
private readonly _dummyTokenWrappers: Erc1155Wrapper[];
|
||||
private readonly _assetProxyInterface: IAssetProxyContract;
|
||||
private readonly _devUtils: DevUtilsContract;
|
||||
private readonly _assetDataInterface: IAssetDataContract;
|
||||
private _proxyContract?: ERC1155ProxyContract;
|
||||
private _proxyIdIfExists?: string;
|
||||
private _initialTokenIdsByOwner: ERC1155HoldingsByOwner = { fungible: {}, nonFungible: {} };
|
||||
@@ -38,7 +39,7 @@ export class ERC1155ProxyWrapper {
|
||||
this._logDecoder = new LogDecoder(this._web3Wrapper, allArtifacts);
|
||||
this._dummyTokenWrappers = [];
|
||||
this._assetProxyInterface = new IAssetProxyContract(constants.NULL_ADDRESS, provider);
|
||||
this._devUtils = new DevUtilsContract(constants.NULL_ADDRESS, provider);
|
||||
this._assetDataInterface = new IAssetDataContract(constants.NULL_ADDRESS, provider);
|
||||
this._tokenOwnerAddresses = tokenOwnerAddresses;
|
||||
this._contractOwnerAddress = contractOwnerAddress;
|
||||
this._fungibleTokenIds = [];
|
||||
@@ -58,7 +59,7 @@ export class ERC1155ProxyWrapper {
|
||||
txDefaults,
|
||||
artifacts,
|
||||
);
|
||||
const erc1155Wrapper = new Erc1155Wrapper(erc1155Contract, this._provider, this._contractOwnerAddress);
|
||||
const erc1155Wrapper = new Erc1155Wrapper(erc1155Contract, this._contractOwnerAddress);
|
||||
this._dummyTokenWrappers.push(erc1155Wrapper);
|
||||
}
|
||||
return this._dummyTokenWrappers;
|
||||
@@ -74,7 +75,7 @@ export class ERC1155ProxyWrapper {
|
||||
txDefaults,
|
||||
artifacts,
|
||||
);
|
||||
this._proxyIdIfExists = await this._proxyContract.getProxyId.callAsync();
|
||||
this._proxyIdIfExists = await this._proxyContract.getProxyId().callAsync();
|
||||
return this._proxyContract;
|
||||
}
|
||||
/**
|
||||
@@ -111,19 +112,13 @@ export class ERC1155ProxyWrapper {
|
||||
this._validateProxyContractExistsOrThrow();
|
||||
const assetData =
|
||||
assetData_ === undefined
|
||||
? await this._devUtils.encodeERC1155AssetData.callAsync(
|
||||
contractAddress,
|
||||
tokensToTransfer,
|
||||
valuesToTransfer,
|
||||
receiverCallbackData,
|
||||
)
|
||||
? this._assetDataInterface
|
||||
.ERC1155Assets(contractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
|
||||
.getABIEncodedTransactionData()
|
||||
: assetData_;
|
||||
const data = this._assetProxyInterface.transferFrom.getABIEncodedTransactionData(
|
||||
assetData,
|
||||
from,
|
||||
to,
|
||||
valueMultiplier,
|
||||
);
|
||||
const data = this._assetProxyInterface
|
||||
.transferFrom(assetData, from, to, valueMultiplier)
|
||||
.getABIEncodedTransactionData();
|
||||
return data;
|
||||
}
|
||||
/**
|
||||
@@ -171,19 +166,13 @@ export class ERC1155ProxyWrapper {
|
||||
this._validateProxyContractExistsOrThrow();
|
||||
const assetData =
|
||||
assetData_ === undefined
|
||||
? await this._devUtils.encodeERC1155AssetData.callAsync(
|
||||
contractAddress,
|
||||
tokensToTransfer,
|
||||
valuesToTransfer,
|
||||
receiverCallbackData,
|
||||
)
|
||||
? this._assetDataInterface
|
||||
.ERC1155Assets(contractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
|
||||
.getABIEncodedTransactionData()
|
||||
: assetData_;
|
||||
const data = this._assetProxyInterface.transferFrom.getABIEncodedTransactionData(
|
||||
assetData,
|
||||
from,
|
||||
to,
|
||||
valueMultiplier,
|
||||
);
|
||||
const data = this._assetProxyInterface
|
||||
.transferFrom(assetData, from, to, valueMultiplier)
|
||||
.getABIEncodedTransactionData();
|
||||
const txHash = await this._web3Wrapper.sendTransactionAsync({
|
||||
to: (this._proxyContract as ERC1155ProxyContract).address,
|
||||
data,
|
||||
@@ -364,7 +353,7 @@ export class ERC1155ProxyWrapper {
|
||||
this._validateProxyContractExistsOrThrow();
|
||||
const tokenContract = this._getContractFromAddress(contractAddress);
|
||||
const operator = (this._proxyContract as ERC1155ProxyContract).address;
|
||||
const didApproveAll = await tokenContract.isApprovedForAll.callAsync(userAddress, operator);
|
||||
const didApproveAll = await tokenContract.isApprovedForAll(userAddress, operator).callAsync();
|
||||
return didApproveAll;
|
||||
}
|
||||
public getFungibleTokenIds(): BigNumber[] {
|
||||
@@ -1,18 +1,19 @@
|
||||
import { DevUtilsContract } from '@0x/contracts-dev-utils';
|
||||
import { artifacts as erc20Artifacts, DummyERC20TokenContract } from '@0x/contracts-erc20';
|
||||
import { constants, ERC20BalancesByOwner, txDefaults } from '@0x/contracts-test-utils';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import { ZeroExProvider } from 'ethereum-types';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { artifacts, ERC20ProxyContract } from '../../src';
|
||||
import { artifacts } from './artifacts';
|
||||
|
||||
import { ERC20ProxyContract, IAssetDataContract } from './wrappers';
|
||||
|
||||
export class ERC20Wrapper {
|
||||
private readonly _tokenOwnerAddresses: string[];
|
||||
private readonly _contractOwnerAddress: string;
|
||||
private readonly _provider: ZeroExProvider;
|
||||
private readonly _dummyTokenContracts: DummyERC20TokenContract[];
|
||||
private readonly _devUtils: DevUtilsContract;
|
||||
private readonly _assetDataInterface: IAssetDataContract;
|
||||
private _proxyContract?: ERC20ProxyContract;
|
||||
private _proxyIdIfExists?: string;
|
||||
/**
|
||||
@@ -27,7 +28,7 @@ export class ERC20Wrapper {
|
||||
this._provider = provider;
|
||||
this._tokenOwnerAddresses = tokenOwnerAddresses;
|
||||
this._contractOwnerAddress = contractOwnerAddress;
|
||||
this._devUtils = new DevUtilsContract(constants.NULL_ADDRESS, provider);
|
||||
this._assetDataInterface = new IAssetDataContract(constants.NULL_ADDRESS, provider);
|
||||
}
|
||||
public async deployDummyTokensAsync(
|
||||
numberToDeploy: number,
|
||||
@@ -56,7 +57,7 @@ export class ERC20Wrapper {
|
||||
txDefaults,
|
||||
artifacts,
|
||||
);
|
||||
this._proxyIdIfExists = await this._proxyContract.getProxyId.callAsync();
|
||||
this._proxyIdIfExists = await this._proxyContract.getProxyId().callAsync();
|
||||
return this._proxyContract;
|
||||
}
|
||||
public getProxyId(): string {
|
||||
@@ -68,43 +69,39 @@ export class ERC20Wrapper {
|
||||
this._validateProxyContractExistsOrThrow();
|
||||
for (const dummyTokenContract of this._dummyTokenContracts) {
|
||||
for (const tokenOwnerAddress of this._tokenOwnerAddresses) {
|
||||
await dummyTokenContract.setBalance.awaitTransactionSuccessAsync(
|
||||
tokenOwnerAddress,
|
||||
constants.INITIAL_ERC20_BALANCE,
|
||||
{ from: this._contractOwnerAddress },
|
||||
);
|
||||
await dummyTokenContract.approve.awaitTransactionSuccessAsync(
|
||||
(this._proxyContract as ERC20ProxyContract).address,
|
||||
constants.INITIAL_ERC20_ALLOWANCE,
|
||||
{ from: tokenOwnerAddress },
|
||||
);
|
||||
await dummyTokenContract
|
||||
.setBalance(tokenOwnerAddress, constants.INITIAL_ERC20_BALANCE)
|
||||
.awaitTransactionSuccessAsync({ from: this._contractOwnerAddress });
|
||||
await dummyTokenContract
|
||||
.approve((this._proxyContract as ERC20ProxyContract).address, constants.INITIAL_ERC20_ALLOWANCE)
|
||||
.awaitTransactionSuccessAsync({ from: tokenOwnerAddress });
|
||||
}
|
||||
}
|
||||
}
|
||||
public async getBalanceAsync(userAddress: string, assetData: string): Promise<BigNumber> {
|
||||
const tokenContract = await this._getTokenContractFromAssetDataAsync(assetData);
|
||||
const balance = new BigNumber(await tokenContract.balanceOf.callAsync(userAddress));
|
||||
const balance = new BigNumber(await tokenContract.balanceOf(userAddress).callAsync());
|
||||
return balance;
|
||||
}
|
||||
public async setBalanceAsync(userAddress: string, assetData: string, amount: BigNumber): Promise<void> {
|
||||
const tokenContract = await this._getTokenContractFromAssetDataAsync(assetData);
|
||||
await tokenContract.setBalance.awaitTransactionSuccessAsync(
|
||||
userAddress,
|
||||
amount,
|
||||
{ from: this._contractOwnerAddress },
|
||||
{ pollingIntervalMs: constants.AWAIT_TRANSACTION_MINED_MS },
|
||||
);
|
||||
await tokenContract
|
||||
.setBalance(userAddress, amount)
|
||||
.awaitTransactionSuccessAsync(
|
||||
{ from: this._contractOwnerAddress },
|
||||
{ pollingIntervalMs: constants.AWAIT_TRANSACTION_MINED_MS },
|
||||
);
|
||||
}
|
||||
public async getProxyAllowanceAsync(userAddress: string, assetData: string): Promise<BigNumber> {
|
||||
const tokenContract = await this._getTokenContractFromAssetDataAsync(assetData);
|
||||
const proxyAddress = (this._proxyContract as ERC20ProxyContract).address;
|
||||
const allowance = new BigNumber(await tokenContract.allowance.callAsync(userAddress, proxyAddress));
|
||||
const allowance = new BigNumber(await tokenContract.allowance(userAddress, proxyAddress).callAsync());
|
||||
return allowance;
|
||||
}
|
||||
public async setAllowanceAsync(userAddress: string, assetData: string, amount: BigNumber): Promise<void> {
|
||||
const tokenContract = await this._getTokenContractFromAssetDataAsync(assetData);
|
||||
const proxyAddress = (this._proxyContract as ERC20ProxyContract).address;
|
||||
await tokenContract.approve.awaitTransactionSuccessAsync(proxyAddress, amount, { from: userAddress });
|
||||
await tokenContract.approve(proxyAddress, amount).awaitTransactionSuccessAsync({ from: userAddress });
|
||||
}
|
||||
public async getBalancesAsync(): Promise<ERC20BalancesByOwner> {
|
||||
this._validateDummyTokenContractsExistOrThrow();
|
||||
@@ -113,7 +110,7 @@ export class ERC20Wrapper {
|
||||
const balanceInfo: Array<{ tokenOwnerAddress: string; tokenAddress: string }> = [];
|
||||
for (const dummyTokenContract of this._dummyTokenContracts) {
|
||||
for (const tokenOwnerAddress of this._tokenOwnerAddresses) {
|
||||
balances.push(await dummyTokenContract.balanceOf.callAsync(tokenOwnerAddress));
|
||||
balances.push(await dummyTokenContract.balanceOf(tokenOwnerAddress).callAsync());
|
||||
balanceInfo.push({
|
||||
tokenOwnerAddress,
|
||||
tokenAddress: dummyTokenContract.address,
|
||||
@@ -147,7 +144,7 @@ export class ERC20Wrapper {
|
||||
return tokenAddresses;
|
||||
}
|
||||
private async _getTokenContractFromAssetDataAsync(assetData: string): Promise<DummyERC20TokenContract> {
|
||||
const [proxyId, tokenAddress] = await this._devUtils.decodeERC20AssetData.callAsync(assetData); // tslint:disable-line:no-unused-variable
|
||||
const tokenAddress = this._assetDataInterface.getABIDecodedTransactionData<string>('ERC20Token', assetData); // tslint:disable-line:no-unused-variable
|
||||
const tokenContractIfExists = _.find(this._dummyTokenContracts, c => c.address === tokenAddress);
|
||||
if (tokenContractIfExists === undefined) {
|
||||
throw new Error(`Token: ${tokenAddress} was not deployed through ERC20Wrapper`);
|
||||
@@ -5,7 +5,9 @@ import { BigNumber } from '@0x/utils';
|
||||
import { ZeroExProvider } from 'ethereum-types';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { artifacts, ERC721ProxyContract } from '../../src';
|
||||
import { artifacts } from './artifacts';
|
||||
|
||||
import { ERC721ProxyContract } from './wrappers';
|
||||
|
||||
export class ERC721Wrapper {
|
||||
private readonly _tokenOwnerAddresses: string[];
|
||||
@@ -44,7 +46,7 @@ export class ERC721Wrapper {
|
||||
txDefaults,
|
||||
artifacts,
|
||||
);
|
||||
this._proxyIdIfExists = await this._proxyContract.getProxyId.callAsync();
|
||||
this._proxyIdIfExists = await this._proxyContract.getProxyId().callAsync();
|
||||
return this._proxyContract;
|
||||
}
|
||||
public getProxyId(): string {
|
||||
@@ -78,7 +80,7 @@ export class ERC721Wrapper {
|
||||
}
|
||||
public async doesTokenExistAsync(tokenAddress: string, tokenId: BigNumber): Promise<boolean> {
|
||||
const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
|
||||
const owner = await tokenContract.ownerOf.callAsync(tokenId);
|
||||
const owner = await tokenContract.ownerOf(tokenId).callAsync();
|
||||
const doesExist = owner !== constants.NULL_ADDRESS;
|
||||
return doesExist;
|
||||
}
|
||||
@@ -93,14 +95,14 @@ export class ERC721Wrapper {
|
||||
): Promise<void> {
|
||||
const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
|
||||
const proxyAddress = (this._proxyContract as ERC721ProxyContract).address;
|
||||
await tokenContract.setApprovalForAll.awaitTransactionSuccessAsync(proxyAddress, isApproved, {
|
||||
await tokenContract.setApprovalForAll(proxyAddress, isApproved).awaitTransactionSuccessAsync({
|
||||
from: ownerAddress,
|
||||
});
|
||||
}
|
||||
public async approveAsync(to: string, tokenAddress: string, tokenId: BigNumber): Promise<void> {
|
||||
const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
|
||||
const tokenOwner = await this.ownerOfAsync(tokenAddress, tokenId);
|
||||
await tokenContract.approve.awaitTransactionSuccessAsync(to, tokenId, { from: tokenOwner });
|
||||
await tokenContract.approve(to, tokenId).awaitTransactionSuccessAsync({ from: tokenOwner });
|
||||
}
|
||||
public async transferFromAsync(
|
||||
tokenAddress: string,
|
||||
@@ -109,28 +111,28 @@ export class ERC721Wrapper {
|
||||
userAddress: string,
|
||||
): Promise<void> {
|
||||
const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
|
||||
await tokenContract.transferFrom.awaitTransactionSuccessAsync(currentOwner, userAddress, tokenId, {
|
||||
await tokenContract.transferFrom(currentOwner, userAddress, tokenId).awaitTransactionSuccessAsync({
|
||||
from: currentOwner,
|
||||
});
|
||||
}
|
||||
public async mintAsync(tokenAddress: string, tokenId: BigNumber, userAddress: string): Promise<void> {
|
||||
const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
|
||||
await tokenContract.mint.awaitTransactionSuccessAsync(userAddress, tokenId, {
|
||||
await tokenContract.mint(userAddress, tokenId).awaitTransactionSuccessAsync({
|
||||
from: this._contractOwnerAddress,
|
||||
});
|
||||
}
|
||||
public async burnAsync(tokenAddress: string, tokenId: BigNumber, owner: string): Promise<void> {
|
||||
const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
|
||||
await tokenContract.burn.awaitTransactionSuccessAsync(owner, tokenId, { from: this._contractOwnerAddress });
|
||||
await tokenContract.burn(owner, tokenId).awaitTransactionSuccessAsync({ from: this._contractOwnerAddress });
|
||||
}
|
||||
public async ownerOfAsync(tokenAddress: string, tokenId: BigNumber): Promise<string> {
|
||||
const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
|
||||
const owner = await tokenContract.ownerOf.callAsync(tokenId);
|
||||
const owner = await tokenContract.ownerOf(tokenId).callAsync();
|
||||
return owner;
|
||||
}
|
||||
public async isOwnerAsync(userAddress: string, tokenAddress: string, tokenId: BigNumber): Promise<boolean> {
|
||||
const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
|
||||
const tokenOwner = await tokenContract.ownerOf.callAsync(tokenId);
|
||||
const tokenOwner = await tokenContract.ownerOf(tokenId).callAsync();
|
||||
const isOwner = tokenOwner === userAddress;
|
||||
return isOwner;
|
||||
}
|
||||
@@ -138,13 +140,13 @@ export class ERC721Wrapper {
|
||||
this._validateProxyContractExistsOrThrow();
|
||||
const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
|
||||
const operator = (this._proxyContract as ERC721ProxyContract).address;
|
||||
const didApproveAll = await tokenContract.isApprovedForAll.callAsync(userAddress, operator);
|
||||
const didApproveAll = await tokenContract.isApprovedForAll(userAddress, operator).callAsync();
|
||||
return didApproveAll;
|
||||
}
|
||||
public async isProxyApprovedAsync(tokenAddress: string, tokenId: BigNumber): Promise<boolean> {
|
||||
this._validateProxyContractExistsOrThrow();
|
||||
const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
|
||||
const approvedAddress = await tokenContract.getApproved.callAsync(tokenId);
|
||||
const approvedAddress = await tokenContract.getApproved(tokenId).callAsync();
|
||||
const proxyAddress = (this._proxyContract as ERC721ProxyContract).address;
|
||||
const isProxyAnApprovedOperator = approvedAddress === proxyAddress;
|
||||
return isProxyAnApprovedOperator;
|
||||
@@ -161,7 +163,7 @@ export class ERC721Wrapper {
|
||||
dummyTokenContract.address
|
||||
];
|
||||
for (const tokenId of initialTokenOwnerIds) {
|
||||
tokenOwnerAddresses.push(await dummyTokenContract.ownerOf.callAsync(tokenId));
|
||||
tokenOwnerAddresses.push(await dummyTokenContract.ownerOf(tokenId).callAsync());
|
||||
tokenInfo.push({
|
||||
tokenId,
|
||||
tokenAddress: dummyTokenContract.address,
|
||||
@@ -1,3 +1,93 @@
|
||||
export * from './artifacts';
|
||||
export * from './wrappers';
|
||||
export * from '../test/utils';
|
||||
export { artifacts } from './artifacts';
|
||||
export {
|
||||
BalancerBridgeContract,
|
||||
ChaiBridgeContract,
|
||||
ERC1155ProxyContract,
|
||||
ERC20BridgeProxyContract,
|
||||
ERC20ProxyContract,
|
||||
ERC721ProxyContract,
|
||||
Eth2DaiBridgeContract,
|
||||
DydxBridgeContract,
|
||||
IAssetDataContract,
|
||||
IAssetProxyContract,
|
||||
IChaiContract,
|
||||
IDydxContract,
|
||||
KyberBridgeContract,
|
||||
MultiAssetProxyContract,
|
||||
StaticCallProxyContract,
|
||||
TestDydxBridgeContract,
|
||||
TestStaticCallTargetContract,
|
||||
UniswapBridgeContract,
|
||||
DexForwarderBridgeContract,
|
||||
} from './wrappers';
|
||||
|
||||
export { ERC20Wrapper } from './erc20_wrapper';
|
||||
export { ERC721Wrapper } from './erc721_wrapper';
|
||||
export { ERC1155ProxyWrapper } from './erc1155_proxy_wrapper';
|
||||
export { ERC1155MintableContract, Erc1155Wrapper } from '@0x/contracts-erc1155';
|
||||
export { DummyERC20TokenContract } from '@0x/contracts-erc20';
|
||||
export { DummyERC721TokenContract } from '@0x/contracts-erc721';
|
||||
export { AssetProxyId } from '@0x/types';
|
||||
export {
|
||||
ERC1155HoldingsByOwner,
|
||||
ERC20BalancesByOwner,
|
||||
ERC721TokenIdsByOwner,
|
||||
ERC1155FungibleHoldingsByOwner,
|
||||
ERC1155NonFungibleHoldingsByOwner,
|
||||
} from '@0x/contracts-test-utils';
|
||||
export {
|
||||
TransactionReceiptWithDecodedLogs,
|
||||
Provider,
|
||||
ZeroExProvider,
|
||||
JSONRPCRequestPayload,
|
||||
JSONRPCErrorCallback,
|
||||
TransactionReceiptStatus,
|
||||
JSONRPCResponsePayload,
|
||||
JSONRPCResponseError,
|
||||
ContractArtifact,
|
||||
ContractChains,
|
||||
CompilerOpts,
|
||||
StandardContractOutput,
|
||||
CompilerSettings,
|
||||
ContractChainData,
|
||||
ContractAbi,
|
||||
DevdocOutput,
|
||||
EvmOutput,
|
||||
CompilerSettingsMetadata,
|
||||
OptimizerSettings,
|
||||
OutputField,
|
||||
ParamDescription,
|
||||
EvmBytecodeOutput,
|
||||
EvmBytecodeOutputLinkReferences,
|
||||
AbiDefinition,
|
||||
FunctionAbi,
|
||||
EventAbi,
|
||||
RevertErrorAbi,
|
||||
EventParameter,
|
||||
DataItem,
|
||||
MethodAbi,
|
||||
ConstructorAbi,
|
||||
FallbackAbi,
|
||||
ConstructorStateMutability,
|
||||
TupleDataItem,
|
||||
StateMutability,
|
||||
} from 'ethereum-types';
|
||||
|
||||
export {
|
||||
decodeERC1155AssetData,
|
||||
decodeERC20AssetData,
|
||||
decodeERC20BridgeAssetData,
|
||||
decodeERC721AssetData,
|
||||
decodeMultiAssetData,
|
||||
decodeStaticCallAssetData,
|
||||
encodeERC1155AssetData,
|
||||
encodeERC20AssetData,
|
||||
encodeERC20BridgeAssetData,
|
||||
encodeERC721AssetData,
|
||||
encodeMultiAssetData,
|
||||
encodeStaticCallAssetData,
|
||||
getAssetDataProxyId,
|
||||
} from './asset_data';
|
||||
|
||||
export * from './dydx_bridge_encoder';
|
||||
export * from './dex_forwarder_bridge';
|
||||
|
||||
@@ -3,6 +3,15 @@
|
||||
* Warning: This file is auto-generated by contracts-gen. Don't edit manually.
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
export * from '../generated-wrappers/balancer_bridge';
|
||||
export * from '../generated-wrappers/bancor_bridge';
|
||||
export * from '../generated-wrappers/chai_bridge';
|
||||
export * from '../generated-wrappers/cream_bridge';
|
||||
export * from '../generated-wrappers/crypto_com_bridge';
|
||||
export * from '../generated-wrappers/curve_bridge';
|
||||
export * from '../generated-wrappers/d_o_d_o_bridge';
|
||||
export * from '../generated-wrappers/dex_forwarder_bridge';
|
||||
export * from '../generated-wrappers/dydx_bridge';
|
||||
export * from '../generated-wrappers/erc1155_proxy';
|
||||
export * from '../generated-wrappers/erc20_bridge_proxy';
|
||||
export * from '../generated-wrappers/erc20_proxy';
|
||||
@@ -12,17 +21,44 @@ export * from '../generated-wrappers/i_asset_data';
|
||||
export * from '../generated-wrappers/i_asset_proxy';
|
||||
export * from '../generated-wrappers/i_asset_proxy_dispatcher';
|
||||
export * from '../generated-wrappers/i_authorizable';
|
||||
export * from '../generated-wrappers/i_balancer_pool';
|
||||
export * from '../generated-wrappers/i_bancor_network';
|
||||
export * from '../generated-wrappers/i_chai';
|
||||
export * from '../generated-wrappers/i_curve';
|
||||
export * from '../generated-wrappers/i_dydx';
|
||||
export * from '../generated-wrappers/i_dydx_bridge';
|
||||
export * from '../generated-wrappers/i_erc20_bridge';
|
||||
export * from '../generated-wrappers/i_eth2_dai';
|
||||
export * from '../generated-wrappers/i_gas_token';
|
||||
export * from '../generated-wrappers/i_kyber_network_proxy';
|
||||
export * from '../generated-wrappers/i_m_stable';
|
||||
export * from '../generated-wrappers/i_mooniswap';
|
||||
export * from '../generated-wrappers/i_shell';
|
||||
export * from '../generated-wrappers/i_uniswap_exchange';
|
||||
export * from '../generated-wrappers/i_uniswap_exchange_factory';
|
||||
export * from '../generated-wrappers/i_uniswap_v2_router01';
|
||||
export * from '../generated-wrappers/kyber_bridge';
|
||||
export * from '../generated-wrappers/m_stable_bridge';
|
||||
export * from '../generated-wrappers/mixin_asset_proxy_dispatcher';
|
||||
export * from '../generated-wrappers/mixin_authorizable';
|
||||
export * from '../generated-wrappers/mixin_gas_token';
|
||||
export * from '../generated-wrappers/mooniswap_bridge';
|
||||
export * from '../generated-wrappers/multi_asset_proxy';
|
||||
export * from '../generated-wrappers/ownable';
|
||||
export * from '../generated-wrappers/shell_bridge';
|
||||
export * from '../generated-wrappers/snow_swap_bridge';
|
||||
export * from '../generated-wrappers/static_call_proxy';
|
||||
export * from '../generated-wrappers/sushi_swap_bridge';
|
||||
export * from '../generated-wrappers/swerve_bridge';
|
||||
export * from '../generated-wrappers/test_bancor_bridge';
|
||||
export * from '../generated-wrappers/test_chai_bridge';
|
||||
export * from '../generated-wrappers/test_dex_forwarder_bridge';
|
||||
export * from '../generated-wrappers/test_dydx_bridge';
|
||||
export * from '../generated-wrappers/test_erc20_bridge';
|
||||
export * from '../generated-wrappers/test_eth2_dai_bridge';
|
||||
export * from '../generated-wrappers/test_kyber_bridge';
|
||||
export * from '../generated-wrappers/test_static_call_target';
|
||||
export * from '../generated-wrappers/test_uniswap_bridge';
|
||||
export * from '../generated-wrappers/test_uniswap_v2_bridge';
|
||||
export * from '../generated-wrappers/uniswap_bridge';
|
||||
export * from '../generated-wrappers/uniswap_v2_bridge';
|
||||
|
||||
127
contracts/asset-proxy/test/artifacts.ts
Normal file
127
contracts/asset-proxy/test/artifacts.ts
Normal file
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* -----------------------------------------------------------------------------
|
||||
* Warning: This file is auto-generated by contracts-gen. Don't edit manually.
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
import { ContractArtifact } from 'ethereum-types';
|
||||
|
||||
import * as BalancerBridge from '../test/generated-artifacts/BalancerBridge.json';
|
||||
import * as BancorBridge from '../test/generated-artifacts/BancorBridge.json';
|
||||
import * as ChaiBridge from '../test/generated-artifacts/ChaiBridge.json';
|
||||
import * as CreamBridge from '../test/generated-artifacts/CreamBridge.json';
|
||||
import * as CryptoComBridge from '../test/generated-artifacts/CryptoComBridge.json';
|
||||
import * as CurveBridge from '../test/generated-artifacts/CurveBridge.json';
|
||||
import * as DexForwarderBridge from '../test/generated-artifacts/DexForwarderBridge.json';
|
||||
import * as DODOBridge from '../test/generated-artifacts/DODOBridge.json';
|
||||
import * as DydxBridge from '../test/generated-artifacts/DydxBridge.json';
|
||||
import * as ERC1155Proxy from '../test/generated-artifacts/ERC1155Proxy.json';
|
||||
import * as ERC20BridgeProxy from '../test/generated-artifacts/ERC20BridgeProxy.json';
|
||||
import * as ERC20Proxy from '../test/generated-artifacts/ERC20Proxy.json';
|
||||
import * as ERC721Proxy from '../test/generated-artifacts/ERC721Proxy.json';
|
||||
import * as Eth2DaiBridge from '../test/generated-artifacts/Eth2DaiBridge.json';
|
||||
import * as IAssetData from '../test/generated-artifacts/IAssetData.json';
|
||||
import * as IAssetProxy from '../test/generated-artifacts/IAssetProxy.json';
|
||||
import * as IAssetProxyDispatcher from '../test/generated-artifacts/IAssetProxyDispatcher.json';
|
||||
import * as IAuthorizable from '../test/generated-artifacts/IAuthorizable.json';
|
||||
import * as IBalancerPool from '../test/generated-artifacts/IBalancerPool.json';
|
||||
import * as IBancorNetwork from '../test/generated-artifacts/IBancorNetwork.json';
|
||||
import * as IChai from '../test/generated-artifacts/IChai.json';
|
||||
import * as ICurve from '../test/generated-artifacts/ICurve.json';
|
||||
import * as IDydx from '../test/generated-artifacts/IDydx.json';
|
||||
import * as IDydxBridge from '../test/generated-artifacts/IDydxBridge.json';
|
||||
import * as IERC20Bridge from '../test/generated-artifacts/IERC20Bridge.json';
|
||||
import * as IEth2Dai from '../test/generated-artifacts/IEth2Dai.json';
|
||||
import * as IGasToken from '../test/generated-artifacts/IGasToken.json';
|
||||
import * as IKyberNetworkProxy from '../test/generated-artifacts/IKyberNetworkProxy.json';
|
||||
import * as IMooniswap from '../test/generated-artifacts/IMooniswap.json';
|
||||
import * as IMStable from '../test/generated-artifacts/IMStable.json';
|
||||
import * as IShell from '../test/generated-artifacts/IShell.json';
|
||||
import * as IUniswapExchange from '../test/generated-artifacts/IUniswapExchange.json';
|
||||
import * as IUniswapExchangeFactory from '../test/generated-artifacts/IUniswapExchangeFactory.json';
|
||||
import * as IUniswapV2Router01 from '../test/generated-artifacts/IUniswapV2Router01.json';
|
||||
import * as KyberBridge from '../test/generated-artifacts/KyberBridge.json';
|
||||
import * as MixinAssetProxyDispatcher from '../test/generated-artifacts/MixinAssetProxyDispatcher.json';
|
||||
import * as MixinAuthorizable from '../test/generated-artifacts/MixinAuthorizable.json';
|
||||
import * as MixinGasToken from '../test/generated-artifacts/MixinGasToken.json';
|
||||
import * as MooniswapBridge from '../test/generated-artifacts/MooniswapBridge.json';
|
||||
import * as MStableBridge from '../test/generated-artifacts/MStableBridge.json';
|
||||
import * as MultiAssetProxy from '../test/generated-artifacts/MultiAssetProxy.json';
|
||||
import * as Ownable from '../test/generated-artifacts/Ownable.json';
|
||||
import * as ShellBridge from '../test/generated-artifacts/ShellBridge.json';
|
||||
import * as SnowSwapBridge from '../test/generated-artifacts/SnowSwapBridge.json';
|
||||
import * as StaticCallProxy from '../test/generated-artifacts/StaticCallProxy.json';
|
||||
import * as SushiSwapBridge from '../test/generated-artifacts/SushiSwapBridge.json';
|
||||
import * as SwerveBridge from '../test/generated-artifacts/SwerveBridge.json';
|
||||
import * as TestBancorBridge from '../test/generated-artifacts/TestBancorBridge.json';
|
||||
import * as TestChaiBridge from '../test/generated-artifacts/TestChaiBridge.json';
|
||||
import * as TestDexForwarderBridge from '../test/generated-artifacts/TestDexForwarderBridge.json';
|
||||
import * as TestDydxBridge from '../test/generated-artifacts/TestDydxBridge.json';
|
||||
import * as TestERC20Bridge from '../test/generated-artifacts/TestERC20Bridge.json';
|
||||
import * as TestEth2DaiBridge from '../test/generated-artifacts/TestEth2DaiBridge.json';
|
||||
import * as TestKyberBridge from '../test/generated-artifacts/TestKyberBridge.json';
|
||||
import * as TestStaticCallTarget from '../test/generated-artifacts/TestStaticCallTarget.json';
|
||||
import * as TestUniswapBridge from '../test/generated-artifacts/TestUniswapBridge.json';
|
||||
import * as TestUniswapV2Bridge from '../test/generated-artifacts/TestUniswapV2Bridge.json';
|
||||
import * as UniswapBridge from '../test/generated-artifacts/UniswapBridge.json';
|
||||
import * as UniswapV2Bridge from '../test/generated-artifacts/UniswapV2Bridge.json';
|
||||
export const artifacts = {
|
||||
MixinAssetProxyDispatcher: MixinAssetProxyDispatcher as ContractArtifact,
|
||||
MixinAuthorizable: MixinAuthorizable as ContractArtifact,
|
||||
Ownable: Ownable as ContractArtifact,
|
||||
ERC1155Proxy: ERC1155Proxy as ContractArtifact,
|
||||
ERC20BridgeProxy: ERC20BridgeProxy as ContractArtifact,
|
||||
ERC20Proxy: ERC20Proxy as ContractArtifact,
|
||||
ERC721Proxy: ERC721Proxy as ContractArtifact,
|
||||
MultiAssetProxy: MultiAssetProxy as ContractArtifact,
|
||||
StaticCallProxy: StaticCallProxy as ContractArtifact,
|
||||
BalancerBridge: BalancerBridge as ContractArtifact,
|
||||
BancorBridge: BancorBridge as ContractArtifact,
|
||||
ChaiBridge: ChaiBridge as ContractArtifact,
|
||||
CreamBridge: CreamBridge as ContractArtifact,
|
||||
CryptoComBridge: CryptoComBridge as ContractArtifact,
|
||||
CurveBridge: CurveBridge as ContractArtifact,
|
||||
DODOBridge: DODOBridge as ContractArtifact,
|
||||
DexForwarderBridge: DexForwarderBridge as ContractArtifact,
|
||||
DydxBridge: DydxBridge as ContractArtifact,
|
||||
Eth2DaiBridge: Eth2DaiBridge as ContractArtifact,
|
||||
KyberBridge: KyberBridge as ContractArtifact,
|
||||
MStableBridge: MStableBridge as ContractArtifact,
|
||||
MixinGasToken: MixinGasToken as ContractArtifact,
|
||||
MooniswapBridge: MooniswapBridge as ContractArtifact,
|
||||
ShellBridge: ShellBridge as ContractArtifact,
|
||||
SnowSwapBridge: SnowSwapBridge as ContractArtifact,
|
||||
SushiSwapBridge: SushiSwapBridge as ContractArtifact,
|
||||
SwerveBridge: SwerveBridge as ContractArtifact,
|
||||
UniswapBridge: UniswapBridge as ContractArtifact,
|
||||
UniswapV2Bridge: UniswapV2Bridge as ContractArtifact,
|
||||
IAssetData: IAssetData as ContractArtifact,
|
||||
IAssetProxy: IAssetProxy as ContractArtifact,
|
||||
IAssetProxyDispatcher: IAssetProxyDispatcher as ContractArtifact,
|
||||
IAuthorizable: IAuthorizable as ContractArtifact,
|
||||
IBalancerPool: IBalancerPool as ContractArtifact,
|
||||
IBancorNetwork: IBancorNetwork as ContractArtifact,
|
||||
IChai: IChai as ContractArtifact,
|
||||
ICurve: ICurve as ContractArtifact,
|
||||
IDydx: IDydx as ContractArtifact,
|
||||
IDydxBridge: IDydxBridge as ContractArtifact,
|
||||
IERC20Bridge: IERC20Bridge as ContractArtifact,
|
||||
IEth2Dai: IEth2Dai as ContractArtifact,
|
||||
IGasToken: IGasToken as ContractArtifact,
|
||||
IKyberNetworkProxy: IKyberNetworkProxy as ContractArtifact,
|
||||
IMStable: IMStable as ContractArtifact,
|
||||
IMooniswap: IMooniswap as ContractArtifact,
|
||||
IShell: IShell as ContractArtifact,
|
||||
IUniswapExchange: IUniswapExchange as ContractArtifact,
|
||||
IUniswapExchangeFactory: IUniswapExchangeFactory as ContractArtifact,
|
||||
IUniswapV2Router01: IUniswapV2Router01 as ContractArtifact,
|
||||
TestBancorBridge: TestBancorBridge as ContractArtifact,
|
||||
TestChaiBridge: TestChaiBridge as ContractArtifact,
|
||||
TestDexForwarderBridge: TestDexForwarderBridge as ContractArtifact,
|
||||
TestDydxBridge: TestDydxBridge as ContractArtifact,
|
||||
TestERC20Bridge: TestERC20Bridge as ContractArtifact,
|
||||
TestEth2DaiBridge: TestEth2DaiBridge as ContractArtifact,
|
||||
TestKyberBridge: TestKyberBridge as ContractArtifact,
|
||||
TestStaticCallTarget: TestStaticCallTarget as ContractArtifact,
|
||||
TestUniswapBridge: TestUniswapBridge as ContractArtifact,
|
||||
TestUniswapV2Bridge: TestUniswapV2Bridge as ContractArtifact,
|
||||
};
|
||||
@@ -1,33 +1,20 @@
|
||||
import { chaiSetup, expectTransactionFailedAsync, provider, txDefaults, web3Wrapper } from '@0x/contracts-test-utils';
|
||||
import { BlockchainLifecycle } from '@0x/dev-utils';
|
||||
import { blockchainTests, expect, provider, txDefaults, web3Wrapper } from '@0x/contracts-test-utils';
|
||||
import { RevertReason } from '@0x/types';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import * as chai from 'chai';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { artifacts, MixinAuthorizableContract } from '../src';
|
||||
import { artifacts } from './artifacts';
|
||||
|
||||
chaiSetup.configure();
|
||||
const expect = chai.expect;
|
||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||
import { MixinAuthorizableContract } from './wrappers';
|
||||
|
||||
describe('Authorizable', () => {
|
||||
blockchainTests.resets('Authorizable', () => {
|
||||
let owner: string;
|
||||
let notOwner: string;
|
||||
let address: string;
|
||||
let authorizable: MixinAuthorizableContract;
|
||||
|
||||
before(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await blockchainLifecycle.revertAsync();
|
||||
});
|
||||
|
||||
before(async () => {
|
||||
const accounts = await web3Wrapper.getAvailableAddressesAsync();
|
||||
[owner, address, notOwner] = _.slice(accounts, 0, 3);
|
||||
[owner, address, notOwner] = accounts.slice(0, 3);
|
||||
authorizable = await MixinAuthorizableContract.deployFrom0xArtifactAsync(
|
||||
artifacts.MixinAuthorizable,
|
||||
provider,
|
||||
@@ -36,131 +23,105 @@ describe('Authorizable', () => {
|
||||
);
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await blockchainLifecycle.revertAsync();
|
||||
});
|
||||
|
||||
describe('addAuthorizedAddress', () => {
|
||||
it('should revert if not called by owner', async () => {
|
||||
await expectTransactionFailedAsync(
|
||||
authorizable.addAuthorizedAddress.sendTransactionAsync(notOwner, { from: notOwner }),
|
||||
RevertReason.OnlyContractOwner,
|
||||
);
|
||||
const tx = authorizable.addAuthorizedAddress(notOwner).sendTransactionAsync({ from: notOwner });
|
||||
return expect(tx).to.revertWith(RevertReason.OnlyContractOwner);
|
||||
});
|
||||
|
||||
it('should allow owner to add an authorized address', async () => {
|
||||
await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(address, { from: owner });
|
||||
const isAuthorized = await authorizable.authorized.callAsync(address);
|
||||
await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner });
|
||||
const isAuthorized = await authorizable.authorized(address).callAsync();
|
||||
expect(isAuthorized).to.be.true();
|
||||
});
|
||||
|
||||
it('should revert if owner attempts to authorize a duplicate address', async () => {
|
||||
await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(address, { from: owner });
|
||||
return expectTransactionFailedAsync(
|
||||
authorizable.addAuthorizedAddress.sendTransactionAsync(address, { from: owner }),
|
||||
RevertReason.TargetAlreadyAuthorized,
|
||||
);
|
||||
await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner });
|
||||
const tx = authorizable.addAuthorizedAddress(address).sendTransactionAsync({ from: owner });
|
||||
return expect(tx).to.revertWith(RevertReason.TargetAlreadyAuthorized);
|
||||
});
|
||||
});
|
||||
|
||||
describe('removeAuthorizedAddress', () => {
|
||||
it('should revert if not called by owner', async () => {
|
||||
await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(address, { from: owner });
|
||||
await expectTransactionFailedAsync(
|
||||
authorizable.removeAuthorizedAddress.sendTransactionAsync(address, { from: notOwner }),
|
||||
RevertReason.OnlyContractOwner,
|
||||
);
|
||||
await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner });
|
||||
const tx = authorizable.removeAuthorizedAddress(address).sendTransactionAsync({ from: notOwner });
|
||||
return expect(tx).to.revertWith(RevertReason.OnlyContractOwner);
|
||||
});
|
||||
|
||||
it('should allow owner to remove an authorized address', async () => {
|
||||
await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(address, { from: owner });
|
||||
await authorizable.removeAuthorizedAddress.awaitTransactionSuccessAsync(address, { from: owner });
|
||||
const isAuthorized = await authorizable.authorized.callAsync(address);
|
||||
await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner });
|
||||
await authorizable.removeAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner });
|
||||
const isAuthorized = await authorizable.authorized(address).callAsync();
|
||||
expect(isAuthorized).to.be.false();
|
||||
});
|
||||
|
||||
it('should revert if owner attempts to remove an address that is not authorized', async () => {
|
||||
return expectTransactionFailedAsync(
|
||||
authorizable.removeAuthorizedAddress.sendTransactionAsync(address, {
|
||||
from: owner,
|
||||
}),
|
||||
RevertReason.TargetNotAuthorized,
|
||||
);
|
||||
const tx = authorizable.removeAuthorizedAddress(address).sendTransactionAsync({ from: owner });
|
||||
return expect(tx).to.revertWith(RevertReason.TargetNotAuthorized);
|
||||
});
|
||||
});
|
||||
|
||||
describe('removeAuthorizedAddressAtIndex', () => {
|
||||
it('should revert if not called by owner', async () => {
|
||||
await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(address, { from: owner });
|
||||
await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner });
|
||||
const index = new BigNumber(0);
|
||||
await expectTransactionFailedAsync(
|
||||
authorizable.removeAuthorizedAddressAtIndex.sendTransactionAsync(address, index, {
|
||||
from: notOwner,
|
||||
}),
|
||||
RevertReason.OnlyContractOwner,
|
||||
);
|
||||
const tx = authorizable
|
||||
.removeAuthorizedAddressAtIndex(address, index)
|
||||
.sendTransactionAsync({ from: notOwner });
|
||||
return expect(tx).to.revertWith(RevertReason.OnlyContractOwner);
|
||||
});
|
||||
|
||||
it('should revert if index is >= authorities.length', async () => {
|
||||
await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(address, { from: owner });
|
||||
await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner });
|
||||
const index = new BigNumber(1);
|
||||
return expectTransactionFailedAsync(
|
||||
authorizable.removeAuthorizedAddressAtIndex.sendTransactionAsync(address, index, {
|
||||
from: owner,
|
||||
}),
|
||||
RevertReason.IndexOutOfBounds,
|
||||
);
|
||||
const tx = authorizable
|
||||
.removeAuthorizedAddressAtIndex(address, index)
|
||||
.sendTransactionAsync({ from: owner });
|
||||
return expect(tx).to.revertWith(RevertReason.IndexOutOfBounds);
|
||||
});
|
||||
|
||||
it('should revert if owner attempts to remove an address that is not authorized', async () => {
|
||||
const index = new BigNumber(0);
|
||||
return expectTransactionFailedAsync(
|
||||
authorizable.removeAuthorizedAddressAtIndex.sendTransactionAsync(address, index, {
|
||||
from: owner,
|
||||
}),
|
||||
RevertReason.TargetNotAuthorized,
|
||||
);
|
||||
const tx = authorizable
|
||||
.removeAuthorizedAddressAtIndex(address, index)
|
||||
.sendTransactionAsync({ from: owner });
|
||||
return expect(tx).to.revertWith(RevertReason.TargetNotAuthorized);
|
||||
});
|
||||
|
||||
it('should revert if address at index does not match target', async () => {
|
||||
const address1 = address;
|
||||
const address2 = notOwner;
|
||||
await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(address1, { from: owner });
|
||||
await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(address2, { from: owner });
|
||||
await authorizable.addAuthorizedAddress(address1).awaitTransactionSuccessAsync({ from: owner });
|
||||
await authorizable.addAuthorizedAddress(address2).awaitTransactionSuccessAsync({ from: owner });
|
||||
const address1Index = new BigNumber(0);
|
||||
return expectTransactionFailedAsync(
|
||||
authorizable.removeAuthorizedAddressAtIndex.sendTransactionAsync(address2, address1Index, {
|
||||
from: owner,
|
||||
}),
|
||||
RevertReason.AuthorizedAddressMismatch,
|
||||
);
|
||||
const tx = authorizable
|
||||
.removeAuthorizedAddressAtIndex(address2, address1Index)
|
||||
.sendTransactionAsync({ from: owner });
|
||||
return expect(tx).to.revertWith(RevertReason.AuthorizedAddressMismatch);
|
||||
});
|
||||
|
||||
it('should allow owner to remove an authorized address', async () => {
|
||||
await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(address, { from: owner });
|
||||
await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner });
|
||||
const index = new BigNumber(0);
|
||||
await authorizable.removeAuthorizedAddressAtIndex.awaitTransactionSuccessAsync(address, index, {
|
||||
await authorizable.removeAuthorizedAddressAtIndex(address, index).awaitTransactionSuccessAsync({
|
||||
from: owner,
|
||||
});
|
||||
const isAuthorized = await authorizable.authorized.callAsync(address);
|
||||
const isAuthorized = await authorizable.authorized(address).callAsync();
|
||||
expect(isAuthorized).to.be.false();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getAuthorizedAddresses', () => {
|
||||
it('should return all authorized addresses', async () => {
|
||||
const initial = await authorizable.getAuthorizedAddresses.callAsync();
|
||||
const initial = await authorizable.getAuthorizedAddresses().callAsync();
|
||||
expect(initial).to.have.length(0);
|
||||
await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(address, { from: owner });
|
||||
const afterAdd = await authorizable.getAuthorizedAddresses.callAsync();
|
||||
await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner });
|
||||
const afterAdd = await authorizable.getAuthorizedAddresses().callAsync();
|
||||
expect(afterAdd).to.have.length(1);
|
||||
expect(afterAdd).to.include(address);
|
||||
await authorizable.removeAuthorizedAddress.awaitTransactionSuccessAsync(address, { from: owner });
|
||||
const afterRemove = await authorizable.getAuthorizedAddresses.callAsync();
|
||||
await authorizable.removeAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner });
|
||||
const afterRemove = await authorizable.getAuthorizedAddresses().callAsync();
|
||||
expect(afterRemove).to.have.length(0);
|
||||
});
|
||||
});
|
||||
|
||||
185
contracts/asset-proxy/test/bancor_bridge.ts
Normal file
185
contracts/asset-proxy/test/bancor_bridge.ts
Normal file
@@ -0,0 +1,185 @@
|
||||
import {
|
||||
blockchainTests,
|
||||
constants,
|
||||
expect,
|
||||
filterLogsToArguments,
|
||||
getRandomInteger,
|
||||
randomAddress,
|
||||
} from '@0x/contracts-test-utils';
|
||||
import { AssetProxyId } from '@0x/types';
|
||||
import { AbiEncoder, BigNumber, hexUtils } from '@0x/utils';
|
||||
import { DecodedLogs } from 'ethereum-types';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { artifacts } from './artifacts';
|
||||
import { TestBancorBridgeContract } from './generated-wrappers/test_bancor_bridge';
|
||||
import {
|
||||
TestBancorBridgeConvertByPathInputEventArgs as ConvertByPathArgs,
|
||||
TestBancorBridgeEvents as ContractEvents,
|
||||
TestBancorBridgeTokenApproveEventArgs as TokenApproveArgs,
|
||||
} from './wrappers';
|
||||
|
||||
blockchainTests.resets('Bancor unit tests', env => {
|
||||
const FROM_TOKEN_DECIMALS = 6;
|
||||
const TO_TOKEN_DECIMALS = 18;
|
||||
const FROM_TOKEN_BASE = new BigNumber(10).pow(FROM_TOKEN_DECIMALS);
|
||||
const TO_TOKEN_BASE = new BigNumber(10).pow(TO_TOKEN_DECIMALS);
|
||||
let testContract: TestBancorBridgeContract;
|
||||
|
||||
before(async () => {
|
||||
testContract = await TestBancorBridgeContract.deployFrom0xArtifactAsync(
|
||||
artifacts.TestBancorBridge,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
artifacts,
|
||||
);
|
||||
});
|
||||
|
||||
describe('isValidSignature()', () => {
|
||||
it('returns success bytes', async () => {
|
||||
const LEGACY_WALLET_MAGIC_VALUE = '0xb0671381';
|
||||
const result = await testContract
|
||||
.isValidSignature(hexUtils.random(), hexUtils.random(_.random(0, 32)))
|
||||
.callAsync();
|
||||
expect(result).to.eq(LEGACY_WALLET_MAGIC_VALUE);
|
||||
});
|
||||
});
|
||||
|
||||
describe('bridgeTransferFrom()', () => {
|
||||
interface TransferFromOpts {
|
||||
tokenAddressesPath: string[];
|
||||
toAddress: string;
|
||||
// Amount to pass into `bridgeTransferFrom()`
|
||||
amount: BigNumber;
|
||||
// Token balance of the bridge.
|
||||
fromTokenBalance: BigNumber;
|
||||
// Router reverts with this reason
|
||||
routerRevertReason: string;
|
||||
}
|
||||
|
||||
interface TransferFromResult {
|
||||
opts: TransferFromOpts;
|
||||
result: string;
|
||||
logs: DecodedLogs;
|
||||
blocktime: number;
|
||||
}
|
||||
|
||||
function createTransferFromOpts(opts?: Partial<TransferFromOpts>): TransferFromOpts {
|
||||
const amount = getRandomInteger(1, TO_TOKEN_BASE.times(100));
|
||||
return {
|
||||
tokenAddressesPath: Array(3).fill(constants.NULL_ADDRESS),
|
||||
amount,
|
||||
toAddress: randomAddress(),
|
||||
fromTokenBalance: getRandomInteger(1, FROM_TOKEN_BASE.times(100)),
|
||||
routerRevertReason: '',
|
||||
...opts,
|
||||
};
|
||||
}
|
||||
|
||||
const bridgeDataEncoder = AbiEncoder.create('(address[], address)');
|
||||
|
||||
async function transferFromAsync(opts?: Partial<TransferFromOpts>): Promise<TransferFromResult> {
|
||||
const _opts = createTransferFromOpts(opts);
|
||||
|
||||
for (let i = 0; i < _opts.tokenAddressesPath.length; i++) {
|
||||
const createFromTokenFn = testContract.createToken(_opts.tokenAddressesPath[i]);
|
||||
_opts.tokenAddressesPath[i] = await createFromTokenFn.callAsync();
|
||||
await createFromTokenFn.awaitTransactionSuccessAsync();
|
||||
}
|
||||
|
||||
// Set the token balance for the token we're converting from.
|
||||
await testContract
|
||||
.setTokenBalance(_opts.tokenAddressesPath[0], _opts.fromTokenBalance)
|
||||
.awaitTransactionSuccessAsync();
|
||||
|
||||
// Set revert reason for the router.
|
||||
await testContract.setNetworkRevertReason(_opts.routerRevertReason).awaitTransactionSuccessAsync();
|
||||
|
||||
// Call bridgeTransferFrom().
|
||||
const bridgeTransferFromFn = testContract.bridgeTransferFrom(
|
||||
// Output token
|
||||
_opts.tokenAddressesPath[_opts.tokenAddressesPath.length - 1],
|
||||
// Random maker address.
|
||||
randomAddress(),
|
||||
// Recipient address.
|
||||
_opts.toAddress,
|
||||
// Transfer amount.
|
||||
_opts.amount,
|
||||
// ABI-encode the input token address as the bridge data.
|
||||
bridgeDataEncoder.encode([
|
||||
_opts.tokenAddressesPath,
|
||||
await testContract.getNetworkAddress().callAsync(),
|
||||
]),
|
||||
);
|
||||
const result = await bridgeTransferFromFn.callAsync();
|
||||
const receipt = await bridgeTransferFromFn.awaitTransactionSuccessAsync();
|
||||
return {
|
||||
opts: _opts,
|
||||
result,
|
||||
logs: (receipt.logs as any) as DecodedLogs,
|
||||
blocktime: await env.web3Wrapper.getBlockTimestampAsync(receipt.blockNumber),
|
||||
};
|
||||
}
|
||||
|
||||
it('returns magic bytes on success', async () => {
|
||||
const { result } = await transferFromAsync();
|
||||
expect(result).to.eq(AssetProxyId.ERC20Bridge);
|
||||
});
|
||||
|
||||
describe('token -> token', async () => {
|
||||
it('calls BancorNetwork.convertByPath()', async () => {
|
||||
const { opts, result, logs } = await transferFromAsync();
|
||||
expect(result).to.eq(AssetProxyId.ERC20Bridge, 'asset proxy id');
|
||||
const transfers = filterLogsToArguments<ConvertByPathArgs>(logs, ContractEvents.ConvertByPathInput);
|
||||
|
||||
expect(transfers.length).to.eq(1);
|
||||
expect(transfers[0].toTokenAddress).to.eq(
|
||||
opts.tokenAddressesPath[opts.tokenAddressesPath.length - 1],
|
||||
'output token address',
|
||||
);
|
||||
expect(transfers[0].to).to.eq(opts.toAddress, 'recipient address');
|
||||
expect(transfers[0].amountIn).to.bignumber.eq(opts.fromTokenBalance, 'input token amount');
|
||||
expect(transfers[0].amountOutMin).to.bignumber.eq(opts.amount, 'output token amount');
|
||||
expect(transfers[0].feeRecipient).to.eq(constants.NULL_ADDRESS);
|
||||
expect(transfers[0].feeAmount).to.bignumber.eq(new BigNumber(0));
|
||||
});
|
||||
|
||||
it('sets allowance for "from" token', async () => {
|
||||
const { logs } = await transferFromAsync();
|
||||
const approvals = filterLogsToArguments<TokenApproveArgs>(logs, ContractEvents.TokenApprove);
|
||||
const networkAddress = await testContract.getNetworkAddress().callAsync();
|
||||
expect(approvals.length).to.eq(1);
|
||||
expect(approvals[0].spender).to.eq(networkAddress);
|
||||
expect(approvals[0].allowance).to.bignumber.eq(constants.MAX_UINT256);
|
||||
});
|
||||
|
||||
it('fails if the router fails', async () => {
|
||||
const revertReason = 'FOOBAR';
|
||||
const tx = transferFromAsync({
|
||||
routerRevertReason: revertReason,
|
||||
});
|
||||
return expect(tx).to.eventually.be.rejectedWith(revertReason);
|
||||
});
|
||||
});
|
||||
describe('token -> token -> token', async () => {
|
||||
it('calls BancorNetwork.convertByPath()', async () => {
|
||||
const { opts, result, logs } = await transferFromAsync({
|
||||
tokenAddressesPath: Array(5).fill(constants.NULL_ADDRESS),
|
||||
});
|
||||
expect(result).to.eq(AssetProxyId.ERC20Bridge, 'asset proxy id');
|
||||
const transfers = filterLogsToArguments<ConvertByPathArgs>(logs, ContractEvents.ConvertByPathInput);
|
||||
|
||||
expect(transfers.length).to.eq(1);
|
||||
expect(transfers[0].toTokenAddress).to.eq(
|
||||
opts.tokenAddressesPath[opts.tokenAddressesPath.length - 1],
|
||||
'output token address',
|
||||
);
|
||||
expect(transfers[0].to).to.eq(opts.toAddress, 'recipient address');
|
||||
expect(transfers[0].amountIn).to.bignumber.eq(opts.fromTokenBalance, 'input token amount');
|
||||
expect(transfers[0].amountOutMin).to.bignumber.eq(opts.amount, 'output token amount');
|
||||
expect(transfers[0].feeRecipient).to.eq(constants.NULL_ADDRESS);
|
||||
expect(transfers[0].feeAmount).to.bignumber.eq(new BigNumber(0));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
60
contracts/asset-proxy/test/chai_bridge.ts
Normal file
60
contracts/asset-proxy/test/chai_bridge.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
import { ERC20TokenContract } from '@0x/contracts-erc20';
|
||||
import { blockchainTests, constants, expect, randomAddress } from '@0x/contracts-test-utils';
|
||||
import { AssetProxyId, RevertReason } from '@0x/types';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
|
||||
import { artifacts } from './artifacts';
|
||||
import { TestChaiBridgeContract } from './wrappers';
|
||||
|
||||
blockchainTests.resets('ChaiBridge unit tests', env => {
|
||||
let chaiBridgeContract: TestChaiBridgeContract;
|
||||
let testDaiContract: ERC20TokenContract;
|
||||
let fromAddress: string;
|
||||
let toAddress: string;
|
||||
|
||||
const alwaysRevertAddress = '0x0000000000000000000000000000000000000001';
|
||||
const amount = new BigNumber(1);
|
||||
|
||||
before(async () => {
|
||||
[fromAddress, toAddress] = await env.getAccountAddressesAsync();
|
||||
chaiBridgeContract = await TestChaiBridgeContract.deployFrom0xArtifactAsync(
|
||||
artifacts.TestChaiBridge,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
artifacts,
|
||||
);
|
||||
const testChaiDaiAddress = await chaiBridgeContract.testChaiDai().callAsync();
|
||||
testDaiContract = new ERC20TokenContract(testChaiDaiAddress, env.provider, env.txDefaults);
|
||||
});
|
||||
|
||||
describe('bridgeTransferFrom()', () => {
|
||||
it('fails if not called by ERC20BridgeProxy', async () => {
|
||||
return expect(
|
||||
chaiBridgeContract
|
||||
.bridgeTransferFrom(randomAddress(), fromAddress, toAddress, amount, constants.NULL_BYTES)
|
||||
.awaitTransactionSuccessAsync({ from: alwaysRevertAddress }),
|
||||
).to.revertWith(RevertReason.ChaiBridgeOnlyCallableByErc20BridgeProxy);
|
||||
});
|
||||
it('returns magic bytes upon success', async () => {
|
||||
const magicBytes = await chaiBridgeContract
|
||||
.bridgeTransferFrom(randomAddress(), fromAddress, toAddress, amount, constants.NULL_BYTES)
|
||||
.callAsync();
|
||||
expect(magicBytes).to.eq(AssetProxyId.ERC20Bridge);
|
||||
});
|
||||
it('should increase the Dai balance of `toAddress` by `amount` if successful', async () => {
|
||||
const initialBalance = await testDaiContract.balanceOf(toAddress).callAsync();
|
||||
await chaiBridgeContract
|
||||
.bridgeTransferFrom(randomAddress(), fromAddress, toAddress, amount, constants.NULL_BYTES)
|
||||
.awaitTransactionSuccessAsync();
|
||||
const endBalance = await testDaiContract.balanceOf(toAddress).callAsync();
|
||||
expect(endBalance).to.bignumber.eq(initialBalance.plus(amount));
|
||||
});
|
||||
it('fails if the `chai.draw` call fails', async () => {
|
||||
return expect(
|
||||
chaiBridgeContract
|
||||
.bridgeTransferFrom(randomAddress(), alwaysRevertAddress, toAddress, amount, constants.NULL_BYTES)
|
||||
.awaitTransactionSuccessAsync(),
|
||||
).to.revertWith(RevertReason.ChaiBridgeDrawDaiFailed);
|
||||
});
|
||||
});
|
||||
});
|
||||
399
contracts/asset-proxy/test/dydx_bridge.ts
Normal file
399
contracts/asset-proxy/test/dydx_bridge.ts
Normal file
@@ -0,0 +1,399 @@
|
||||
import { LibMathRevertErrors } from '@0x/contracts-exchange-libs';
|
||||
import { blockchainTests, constants, expect, verifyEventsFromLogs } from '@0x/contracts-test-utils';
|
||||
import { AssetProxyId, RevertReason } from '@0x/types';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { DydxBridgeActionType, DydxBridgeData, dydxBridgeDataEncoder } from '../src/dydx_bridge_encoder';
|
||||
import { ERC20BridgeProxyContract, IAssetDataContract } from '../src/wrappers';
|
||||
|
||||
import { artifacts } from './artifacts';
|
||||
import { TestDydxBridgeContract, TestDydxBridgeEvents } from './wrappers';
|
||||
|
||||
blockchainTests.resets('DydxBridge unit tests', env => {
|
||||
const defaultAccountNumber = new BigNumber(1);
|
||||
const marketId = new BigNumber(2);
|
||||
const defaultAmount = new BigNumber(4);
|
||||
const notAuthorized = '0x0000000000000000000000000000000000000001';
|
||||
const defaultDepositAction = {
|
||||
actionType: DydxBridgeActionType.Deposit,
|
||||
accountIdx: constants.ZERO_AMOUNT,
|
||||
marketId,
|
||||
conversionRateNumerator: constants.ZERO_AMOUNT,
|
||||
conversionRateDenominator: constants.ZERO_AMOUNT,
|
||||
};
|
||||
const defaultWithdrawAction = {
|
||||
actionType: DydxBridgeActionType.Withdraw,
|
||||
accountIdx: constants.ZERO_AMOUNT,
|
||||
marketId,
|
||||
conversionRateNumerator: constants.ZERO_AMOUNT,
|
||||
conversionRateDenominator: constants.ZERO_AMOUNT,
|
||||
};
|
||||
let testContract: TestDydxBridgeContract;
|
||||
let testProxyContract: ERC20BridgeProxyContract;
|
||||
let assetDataEncoder: IAssetDataContract;
|
||||
let owner: string;
|
||||
let authorized: string;
|
||||
let accountOwner: string;
|
||||
let receiver: string;
|
||||
|
||||
before(async () => {
|
||||
// Get accounts
|
||||
const accounts = await env.web3Wrapper.getAvailableAddressesAsync();
|
||||
[owner, authorized, accountOwner, receiver] = accounts;
|
||||
|
||||
// Deploy dydx bridge
|
||||
testContract = await TestDydxBridgeContract.deployFrom0xArtifactAsync(
|
||||
artifacts.TestDydxBridge,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
artifacts,
|
||||
[accountOwner, receiver],
|
||||
);
|
||||
|
||||
// Deploy test erc20 bridge proxy
|
||||
testProxyContract = await ERC20BridgeProxyContract.deployFrom0xArtifactAsync(
|
||||
artifacts.ERC20BridgeProxy,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
artifacts,
|
||||
);
|
||||
await testProxyContract.addAuthorizedAddress(authorized).awaitTransactionSuccessAsync({ from: owner });
|
||||
|
||||
// Setup asset data encoder
|
||||
assetDataEncoder = new IAssetDataContract(constants.NULL_ADDRESS, env.provider);
|
||||
});
|
||||
|
||||
describe('bridgeTransferFrom()', () => {
|
||||
const callBridgeTransferFrom = async (
|
||||
from: string,
|
||||
to: string,
|
||||
amount: BigNumber,
|
||||
bridgeData: DydxBridgeData,
|
||||
sender: string,
|
||||
): Promise<string> => {
|
||||
const returnValue = await testContract
|
||||
.bridgeTransferFrom(
|
||||
constants.NULL_ADDRESS,
|
||||
from,
|
||||
to,
|
||||
amount,
|
||||
dydxBridgeDataEncoder.encode({ bridgeData }),
|
||||
)
|
||||
.callAsync({ from: sender });
|
||||
return returnValue;
|
||||
};
|
||||
const executeBridgeTransferFromAndVerifyEvents = async (
|
||||
from: string,
|
||||
to: string,
|
||||
amount: BigNumber,
|
||||
bridgeData: DydxBridgeData,
|
||||
sender: string,
|
||||
): Promise<void> => {
|
||||
// Execute transaction.
|
||||
const txReceipt = await testContract
|
||||
.bridgeTransferFrom(
|
||||
constants.NULL_ADDRESS,
|
||||
from,
|
||||
to,
|
||||
amount,
|
||||
dydxBridgeDataEncoder.encode({ bridgeData }),
|
||||
)
|
||||
.awaitTransactionSuccessAsync({ from: sender });
|
||||
|
||||
// Verify `OperateAccount` event.
|
||||
const expectedOperateAccountEvents = [];
|
||||
for (const accountNumber of bridgeData.accountNumbers) {
|
||||
expectedOperateAccountEvents.push({
|
||||
owner: accountOwner,
|
||||
number: accountNumber,
|
||||
});
|
||||
}
|
||||
verifyEventsFromLogs(txReceipt.logs, expectedOperateAccountEvents, TestDydxBridgeEvents.OperateAccount);
|
||||
|
||||
// Verify `OperateAction` event.
|
||||
const weiDenomination = 0;
|
||||
const deltaAmountRef = 0;
|
||||
const expectedOperateActionEvents = [];
|
||||
for (const action of bridgeData.actions) {
|
||||
expectedOperateActionEvents.push({
|
||||
actionType: action.actionType as number,
|
||||
accountIdx: action.accountIdx,
|
||||
amountSign: action.actionType === DydxBridgeActionType.Deposit ? true : false,
|
||||
amountDenomination: weiDenomination,
|
||||
amountRef: deltaAmountRef,
|
||||
amountValue: action.conversionRateDenominator.gt(0)
|
||||
? amount
|
||||
.times(action.conversionRateNumerator)
|
||||
.dividedToIntegerBy(action.conversionRateDenominator)
|
||||
: amount,
|
||||
primaryMarketId: marketId,
|
||||
secondaryMarketId: constants.ZERO_AMOUNT,
|
||||
otherAddress: action.actionType === DydxBridgeActionType.Deposit ? from : to,
|
||||
otherAccountId: constants.ZERO_AMOUNT,
|
||||
data: '0x',
|
||||
});
|
||||
}
|
||||
verifyEventsFromLogs(txReceipt.logs, expectedOperateActionEvents, TestDydxBridgeEvents.OperateAction);
|
||||
};
|
||||
it('succeeds when calling with zero amount', async () => {
|
||||
const bridgeData = {
|
||||
accountNumbers: [defaultAccountNumber],
|
||||
actions: [defaultDepositAction],
|
||||
};
|
||||
await executeBridgeTransferFromAndVerifyEvents(
|
||||
accountOwner,
|
||||
receiver,
|
||||
constants.ZERO_AMOUNT,
|
||||
bridgeData,
|
||||
authorized,
|
||||
);
|
||||
});
|
||||
it('succeeds when calling with no accounts', async () => {
|
||||
const bridgeData = {
|
||||
accountNumbers: [],
|
||||
actions: [defaultDepositAction],
|
||||
};
|
||||
await executeBridgeTransferFromAndVerifyEvents(
|
||||
accountOwner,
|
||||
receiver,
|
||||
defaultAmount,
|
||||
bridgeData,
|
||||
authorized,
|
||||
);
|
||||
});
|
||||
it('succeeds when calling with no actions', async () => {
|
||||
const bridgeData = {
|
||||
accountNumbers: [defaultAccountNumber],
|
||||
actions: [],
|
||||
};
|
||||
await executeBridgeTransferFromAndVerifyEvents(
|
||||
accountOwner,
|
||||
receiver,
|
||||
defaultAmount,
|
||||
bridgeData,
|
||||
authorized,
|
||||
);
|
||||
});
|
||||
it('succeeds when calling `operate` with the `deposit` action and a single account', async () => {
|
||||
const bridgeData = {
|
||||
accountNumbers: [defaultAccountNumber],
|
||||
actions: [defaultDepositAction],
|
||||
};
|
||||
await executeBridgeTransferFromAndVerifyEvents(
|
||||
accountOwner,
|
||||
receiver,
|
||||
defaultAmount,
|
||||
bridgeData,
|
||||
authorized,
|
||||
);
|
||||
});
|
||||
it('succeeds when calling `operate` with the `deposit` action and multiple accounts', async () => {
|
||||
const bridgeData = {
|
||||
accountNumbers: [defaultAccountNumber, defaultAccountNumber.plus(1)],
|
||||
actions: [defaultDepositAction],
|
||||
};
|
||||
await executeBridgeTransferFromAndVerifyEvents(
|
||||
accountOwner,
|
||||
receiver,
|
||||
defaultAmount,
|
||||
bridgeData,
|
||||
authorized,
|
||||
);
|
||||
});
|
||||
it('succeeds when calling `operate` with the `withdraw` action and a single account', async () => {
|
||||
const bridgeData = {
|
||||
accountNumbers: [defaultAccountNumber],
|
||||
actions: [defaultWithdrawAction],
|
||||
};
|
||||
await executeBridgeTransferFromAndVerifyEvents(
|
||||
accountOwner,
|
||||
receiver,
|
||||
defaultAmount,
|
||||
bridgeData,
|
||||
authorized,
|
||||
);
|
||||
});
|
||||
it('succeeds when calling `operate` with the `withdraw` action and multiple accounts', async () => {
|
||||
const bridgeData = {
|
||||
accountNumbers: [defaultAccountNumber, defaultAccountNumber.plus(1)],
|
||||
actions: [defaultWithdrawAction],
|
||||
};
|
||||
await executeBridgeTransferFromAndVerifyEvents(
|
||||
accountOwner,
|
||||
receiver,
|
||||
defaultAmount,
|
||||
bridgeData,
|
||||
authorized,
|
||||
);
|
||||
});
|
||||
it('succeeds when calling `operate` with the `deposit` action and multiple accounts', async () => {
|
||||
const bridgeData = {
|
||||
accountNumbers: [defaultAccountNumber, defaultAccountNumber.plus(1)],
|
||||
actions: [defaultWithdrawAction, defaultDepositAction],
|
||||
};
|
||||
await executeBridgeTransferFromAndVerifyEvents(
|
||||
accountOwner,
|
||||
receiver,
|
||||
defaultAmount,
|
||||
bridgeData,
|
||||
authorized,
|
||||
);
|
||||
});
|
||||
it('succeeds when calling `operate` with multiple actions under a single account', async () => {
|
||||
const bridgeData = {
|
||||
accountNumbers: [defaultAccountNumber],
|
||||
actions: [defaultWithdrawAction, defaultDepositAction],
|
||||
};
|
||||
await executeBridgeTransferFromAndVerifyEvents(
|
||||
accountOwner,
|
||||
receiver,
|
||||
defaultAmount,
|
||||
bridgeData,
|
||||
authorized,
|
||||
);
|
||||
});
|
||||
it('succeeds when scaling the `amount` to deposit', async () => {
|
||||
const conversionRateNumerator = new BigNumber(1);
|
||||
const conversionRateDenominator = new BigNumber(2);
|
||||
const bridgeData = {
|
||||
accountNumbers: [defaultAccountNumber],
|
||||
actions: [
|
||||
defaultWithdrawAction,
|
||||
{
|
||||
...defaultDepositAction,
|
||||
conversionRateNumerator,
|
||||
conversionRateDenominator,
|
||||
},
|
||||
],
|
||||
};
|
||||
await executeBridgeTransferFromAndVerifyEvents(
|
||||
accountOwner,
|
||||
receiver,
|
||||
defaultAmount,
|
||||
bridgeData,
|
||||
authorized,
|
||||
);
|
||||
});
|
||||
it('succeeds when scaling the `amount` to withdraw', async () => {
|
||||
const conversionRateNumerator = new BigNumber(1);
|
||||
const conversionRateDenominator = new BigNumber(2);
|
||||
const bridgeData = {
|
||||
accountNumbers: [defaultAccountNumber],
|
||||
actions: [
|
||||
defaultDepositAction,
|
||||
{
|
||||
...defaultWithdrawAction,
|
||||
conversionRateNumerator,
|
||||
conversionRateDenominator,
|
||||
},
|
||||
],
|
||||
};
|
||||
await executeBridgeTransferFromAndVerifyEvents(
|
||||
accountOwner,
|
||||
receiver,
|
||||
defaultAmount,
|
||||
bridgeData,
|
||||
authorized,
|
||||
);
|
||||
});
|
||||
it('reverts if not called by the ERC20 Bridge Proxy', async () => {
|
||||
const bridgeData = {
|
||||
accountNumbers: [defaultAccountNumber],
|
||||
actions: [defaultDepositAction],
|
||||
};
|
||||
const callBridgeTransferFromPromise = callBridgeTransferFrom(
|
||||
accountOwner,
|
||||
receiver,
|
||||
defaultAmount,
|
||||
bridgeData,
|
||||
notAuthorized,
|
||||
);
|
||||
const expectedError = RevertReason.DydxBridgeOnlyCallableByErc20BridgeProxy;
|
||||
return expect(callBridgeTransferFromPromise).to.revertWith(expectedError);
|
||||
});
|
||||
it('should return magic bytes if call succeeds', async () => {
|
||||
const bridgeData = {
|
||||
accountNumbers: [defaultAccountNumber],
|
||||
actions: [defaultDepositAction],
|
||||
};
|
||||
const returnValue = await callBridgeTransferFrom(
|
||||
accountOwner,
|
||||
receiver,
|
||||
defaultAmount,
|
||||
bridgeData,
|
||||
authorized,
|
||||
);
|
||||
expect(returnValue).to.equal(AssetProxyId.ERC20Bridge);
|
||||
});
|
||||
it('should revert when `Operate` reverts', async () => {
|
||||
// Set revert flag.
|
||||
await testContract.setRevertOnOperate(true).awaitTransactionSuccessAsync();
|
||||
|
||||
// Execute transfer.
|
||||
const bridgeData = {
|
||||
accountNumbers: [defaultAccountNumber],
|
||||
actions: [defaultDepositAction],
|
||||
};
|
||||
const tx = callBridgeTransferFrom(accountOwner, receiver, defaultAmount, bridgeData, authorized);
|
||||
const expectedError = 'TestDydxBridge/SHOULD_REVERT_ON_OPERATE';
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
it('should revert when there is a rounding error', async () => {
|
||||
// Setup a rounding error
|
||||
const conversionRateNumerator = new BigNumber(5318);
|
||||
const conversionRateDenominator = new BigNumber(47958);
|
||||
const amount = new BigNumber(9000);
|
||||
const bridgeData = {
|
||||
accountNumbers: [defaultAccountNumber],
|
||||
actions: [
|
||||
defaultDepositAction,
|
||||
{
|
||||
...defaultWithdrawAction,
|
||||
conversionRateNumerator,
|
||||
conversionRateDenominator,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
// Execute transfer and assert error.
|
||||
const tx = callBridgeTransferFrom(accountOwner, receiver, amount, bridgeData, authorized);
|
||||
const expectedError = new LibMathRevertErrors.RoundingError(
|
||||
conversionRateNumerator,
|
||||
conversionRateDenominator,
|
||||
amount,
|
||||
);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
});
|
||||
|
||||
describe('ERC20BridgeProxy.transferFrom()', () => {
|
||||
const bridgeData = {
|
||||
accountNumbers: [defaultAccountNumber],
|
||||
actions: [defaultWithdrawAction],
|
||||
};
|
||||
let assetData: string;
|
||||
|
||||
before(async () => {
|
||||
const testTokenAddress = await testContract.getTestToken().callAsync();
|
||||
assetData = assetDataEncoder
|
||||
.ERC20Bridge(testTokenAddress, testContract.address, dydxBridgeDataEncoder.encode({ bridgeData }))
|
||||
.getABIEncodedTransactionData();
|
||||
});
|
||||
|
||||
it('should succeed if `bridgeTransferFrom` succeeds', async () => {
|
||||
await testProxyContract
|
||||
.transferFrom(assetData, accountOwner, receiver, defaultAmount)
|
||||
.awaitTransactionSuccessAsync({ from: authorized });
|
||||
});
|
||||
it('should revert if `bridgeTransferFrom` reverts', async () => {
|
||||
// Set revert flag.
|
||||
await testContract.setRevertOnOperate(true).awaitTransactionSuccessAsync();
|
||||
const tx = testProxyContract
|
||||
.transferFrom(assetData, accountOwner, receiver, defaultAmount)
|
||||
.awaitTransactionSuccessAsync({ from: authorized });
|
||||
const expectedError = 'TestDydxBridge/SHOULD_REVERT_ON_OPERATE';
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,4 +1,3 @@
|
||||
import { DevUtilsContract } from '@0x/contracts-dev-utils';
|
||||
import {
|
||||
artifacts as erc1155Artifacts,
|
||||
DummyERC1155ReceiverBatchTokenReceivedEventArgs,
|
||||
@@ -15,15 +14,19 @@ import {
|
||||
txDefaults,
|
||||
web3Wrapper,
|
||||
} from '@0x/contracts-test-utils';
|
||||
import { SafeMathRevertErrors } from '@0x/contracts-utils';
|
||||
import { BlockchainLifecycle } from '@0x/dev-utils';
|
||||
import { AssetProxyId, RevertReason } from '@0x/types';
|
||||
import { BigNumber, SafeMathRevertErrors } from '@0x/utils';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import * as chai from 'chai';
|
||||
import { LogWithDecodedArgs } from 'ethereum-types';
|
||||
import * as ethUtil from 'ethereumjs-util';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { artifacts, ERC1155ProxyContract, ERC1155ProxyWrapper, IAssetDataContract } from '../src';
|
||||
import { ERC1155ProxyWrapper } from '../src/erc1155_proxy_wrapper';
|
||||
import { ERC1155ProxyContract, IAssetDataContract } from '../src/wrappers';
|
||||
|
||||
import { artifacts } from './artifacts';
|
||||
|
||||
chaiSetup.configure();
|
||||
const expect = chai.expect;
|
||||
@@ -59,8 +62,8 @@ describe('ERC1155Proxy', () => {
|
||||
// tokens
|
||||
let fungibleTokens: BigNumber[];
|
||||
let nonFungibleTokensOwnedBySpender: BigNumber[];
|
||||
// devUtils for encoding and decoding assetData
|
||||
let devUtils: DevUtilsContract;
|
||||
// IAssetData for encoding and decoding assetData
|
||||
let assetDataContract: IAssetDataContract;
|
||||
// tests
|
||||
before(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
@@ -74,8 +77,8 @@ describe('ERC1155Proxy', () => {
|
||||
const usedAddresses = ([owner, notAuthorized, authorized, spender, receiver] = _.slice(accounts, 0, 5));
|
||||
erc1155ProxyWrapper = new ERC1155ProxyWrapper(provider, usedAddresses, owner);
|
||||
erc1155Proxy = await erc1155ProxyWrapper.deployProxyAsync();
|
||||
await erc1155Proxy.addAuthorizedAddress.awaitTransactionSuccessAsync(authorized, { from: owner });
|
||||
await erc1155Proxy.addAuthorizedAddress.awaitTransactionSuccessAsync(erc1155Proxy.address, { from: owner });
|
||||
await erc1155Proxy.addAuthorizedAddress(authorized).awaitTransactionSuccessAsync({ from: owner });
|
||||
await erc1155Proxy.addAuthorizedAddress(erc1155Proxy.address).awaitTransactionSuccessAsync({ from: owner });
|
||||
// deploy & configure ERC1155 tokens and receiver
|
||||
[erc1155Wrapper] = await erc1155ProxyWrapper.deployDummyContractsAsync();
|
||||
erc1155Contract = erc1155Wrapper.getContract();
|
||||
@@ -97,8 +100,8 @@ describe('ERC1155Proxy', () => {
|
||||
tokenBalances.nonFungible[spender][erc1155Contract.address][nonFungibleTokenAsString][0];
|
||||
nonFungibleTokensOwnedBySpender.push(nonFungibleTokenHeldBySpender);
|
||||
});
|
||||
// set up devUtils
|
||||
devUtils = new DevUtilsContract(constants.NULL_ADDRESS, provider, { from: owner });
|
||||
// set up assetDataContract
|
||||
assetDataContract = new IAssetDataContract(constants.NULL_ADDRESS, provider, { from: owner });
|
||||
});
|
||||
beforeEach(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
@@ -119,7 +122,7 @@ describe('ERC1155Proxy', () => {
|
||||
);
|
||||
});
|
||||
it('should have an id of 0xa7cb5fb7', async () => {
|
||||
const proxyId = await erc1155Proxy.getProxyId.callAsync();
|
||||
const proxyId = await erc1155Proxy.getProxyId().callAsync();
|
||||
const expectedProxyId = AssetProxyId.ERC1155;
|
||||
expect(proxyId).to.equal(expectedProxyId);
|
||||
});
|
||||
@@ -634,12 +637,9 @@ describe('ERC1155Proxy', () => {
|
||||
return value.times(valueMultiplier);
|
||||
});
|
||||
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
|
||||
const assetData = await devUtils.encodeERC1155AssetData.callAsync(
|
||||
erc1155ContractAddress,
|
||||
tokensToTransfer,
|
||||
valuesToTransfer,
|
||||
receiverCallbackData,
|
||||
);
|
||||
const assetData = assetDataContract
|
||||
.ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
|
||||
.getABIEncodedTransactionData();
|
||||
const extraData = '0102030405060708091001020304050607080910010203040506070809100102';
|
||||
const assetDataWithExtraData = `${assetData}${extraData}`;
|
||||
// check balances before transfer
|
||||
@@ -694,14 +694,16 @@ describe('ERC1155Proxy', () => {
|
||||
// create token
|
||||
await erc1155Wrapper
|
||||
.getContract()
|
||||
.createWithType.awaitTransactionSuccessAsync(tokenToCreate, tokenUri, {
|
||||
.createWithType(tokenToCreate, tokenUri)
|
||||
.awaitTransactionSuccessAsync({
|
||||
from: owner,
|
||||
});
|
||||
|
||||
// mint balance for spender
|
||||
await erc1155Wrapper
|
||||
.getContract()
|
||||
.mintFungible.awaitTransactionSuccessAsync(tokenToCreate, [spender], [spenderInitialBalance], {
|
||||
.mintFungible(tokenToCreate, [spender], [spenderInitialBalance])
|
||||
.awaitTransactionSuccessAsync({
|
||||
from: owner,
|
||||
});
|
||||
}
|
||||
@@ -737,9 +739,8 @@ describe('ERC1155Proxy', () => {
|
||||
const valuesToTransfer = tokensToTransfer;
|
||||
const valueMultiplier = new BigNumber(2);
|
||||
|
||||
// hand encode optimized assetData because our tooling (based on LibAssetData.sol/encodeERC1155AssetData) does not use optimized encoding
|
||||
const assetDataContract = new IAssetDataContract(constants.NULL_ADDRESS, provider);
|
||||
const selector = assetDataContract.ERC1155Assets.getSelector();
|
||||
// hand encode optimized assetData because our tooling (based on LibAssetData.sol/ERC1155Assets) does not use optimized encoding
|
||||
const selector = assetDataContract.getSelector('ERC1155Assets');
|
||||
const assetDataWithoutContractAddress =
|
||||
'0000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000040102030400000000000000000000000000000000000000000000000000000000';
|
||||
const assetData = `${selector}000000000000000000000000${erc1155ContractAddress.substr(
|
||||
@@ -794,14 +795,16 @@ describe('ERC1155Proxy', () => {
|
||||
// create token
|
||||
await erc1155Wrapper
|
||||
.getContract()
|
||||
.createWithType.awaitTransactionSuccessAsync(tokenToCreate, tokenUri, {
|
||||
.createWithType(tokenToCreate, tokenUri)
|
||||
.awaitTransactionSuccessAsync({
|
||||
from: owner,
|
||||
});
|
||||
|
||||
// mint balance for spender
|
||||
await erc1155Wrapper
|
||||
.getContract()
|
||||
.mintFungible.awaitTransactionSuccessAsync(tokenToCreate, [spender], [spenderInitialBalance], {
|
||||
.mintFungible(tokenToCreate, [spender], [spenderInitialBalance])
|
||||
.awaitTransactionSuccessAsync({
|
||||
from: owner,
|
||||
});
|
||||
}
|
||||
@@ -847,12 +850,9 @@ describe('ERC1155Proxy', () => {
|
||||
const valuesToTransfer = [new BigNumber(2), new BigNumber(2)];
|
||||
const valueMultiplier = new BigNumber(2);
|
||||
// create callback data that is the encoded version of `valuesToTransfer`
|
||||
const generatedAssetData = await devUtils.encodeERC1155AssetData.callAsync(
|
||||
erc1155ContractAddress,
|
||||
tokensToTransfer,
|
||||
valuesToTransfer,
|
||||
receiverCallbackData,
|
||||
);
|
||||
const generatedAssetData = assetDataContract
|
||||
.ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
|
||||
.getABIEncodedTransactionData();
|
||||
// remove the function selector and contract address from check, as these change on each test
|
||||
const offsetToTokenIds = 74;
|
||||
const assetDataSelectorAndContractAddress = generatedAssetData.substr(0, offsetToTokenIds);
|
||||
@@ -919,14 +919,16 @@ describe('ERC1155Proxy', () => {
|
||||
// create token
|
||||
await erc1155Wrapper
|
||||
.getContract()
|
||||
.createWithType.awaitTransactionSuccessAsync(tokenToCreate, tokenUri, {
|
||||
.createWithType(tokenToCreate, tokenUri)
|
||||
.awaitTransactionSuccessAsync({
|
||||
from: owner,
|
||||
});
|
||||
|
||||
// mint balance for spender
|
||||
await erc1155Wrapper
|
||||
.getContract()
|
||||
.mintFungible.awaitTransactionSuccessAsync(tokenToCreate, [spender], [spenderInitialBalance], {
|
||||
.mintFungible(tokenToCreate, [spender], [spenderInitialBalance])
|
||||
.awaitTransactionSuccessAsync({
|
||||
from: owner,
|
||||
});
|
||||
}
|
||||
@@ -969,12 +971,9 @@ describe('ERC1155Proxy', () => {
|
||||
const valuesToTransfer = [new BigNumber(1), new BigNumber(2)];
|
||||
const valueMultiplier = new BigNumber(2);
|
||||
// create callback data that is the encoded version of `valuesToTransfer`
|
||||
const generatedAssetData = await devUtils.encodeERC1155AssetData.callAsync(
|
||||
erc1155ContractAddress,
|
||||
tokensToTransfer,
|
||||
valuesToTransfer,
|
||||
receiverCallbackData,
|
||||
);
|
||||
const generatedAssetData = assetDataContract
|
||||
.ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
|
||||
.getABIEncodedTransactionData();
|
||||
// remove the function selector and contract address from check, as these change on each test
|
||||
const offsetToTokenIds = 74;
|
||||
const assetDataSelectorAndContractAddress = generatedAssetData.substr(0, offsetToTokenIds);
|
||||
@@ -1032,12 +1031,9 @@ describe('ERC1155Proxy', () => {
|
||||
const valuesToTransfer = [fungibleValueToTransferLarge];
|
||||
const valueMultiplier = valueMultiplierSmall;
|
||||
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
|
||||
const assetData = await devUtils.encodeERC1155AssetData.callAsync(
|
||||
erc1155ContractAddress,
|
||||
tokensToTransfer,
|
||||
valuesToTransfer,
|
||||
receiverCallbackData,
|
||||
);
|
||||
const assetData = assetDataContract
|
||||
.ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
|
||||
.getABIEncodedTransactionData();
|
||||
// The asset data we just generated will look like this:
|
||||
// a7cb5fb7
|
||||
// 0x 0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082
|
||||
@@ -1079,12 +1075,9 @@ describe('ERC1155Proxy', () => {
|
||||
const valuesToTransfer = [fungibleValueToTransferLarge];
|
||||
const valueMultiplier = valueMultiplierSmall;
|
||||
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
|
||||
const assetData = await devUtils.encodeERC1155AssetData.callAsync(
|
||||
erc1155ContractAddress,
|
||||
tokensToTransfer,
|
||||
valuesToTransfer,
|
||||
receiverCallbackData,
|
||||
);
|
||||
const assetData = assetDataContract
|
||||
.ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
|
||||
.getABIEncodedTransactionData();
|
||||
// The asset data we just generated will look like this:
|
||||
// a7cb5fb7
|
||||
// 0x 0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082
|
||||
@@ -1130,12 +1123,9 @@ describe('ERC1155Proxy', () => {
|
||||
const valuesToTransfer = [fungibleValueToTransferLarge];
|
||||
const valueMultiplier = valueMultiplierSmall;
|
||||
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
|
||||
const assetData = await devUtils.encodeERC1155AssetData.callAsync(
|
||||
erc1155ContractAddress,
|
||||
tokensToTransfer,
|
||||
valuesToTransfer,
|
||||
receiverCallbackData,
|
||||
);
|
||||
const assetData = assetDataContract
|
||||
.ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
|
||||
.getABIEncodedTransactionData();
|
||||
// The asset data we just generated will look like this:
|
||||
// a7cb5fb7
|
||||
// 0x 0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082
|
||||
@@ -1181,12 +1171,9 @@ describe('ERC1155Proxy', () => {
|
||||
const valuesToTransfer = [fungibleValueToTransferLarge];
|
||||
const valueMultiplier = valueMultiplierSmall;
|
||||
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
|
||||
const assetData = await devUtils.encodeERC1155AssetData.callAsync(
|
||||
erc1155ContractAddress,
|
||||
tokensToTransfer,
|
||||
valuesToTransfer,
|
||||
receiverCallbackData,
|
||||
);
|
||||
const assetData = assetDataContract
|
||||
.ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
|
||||
.getABIEncodedTransactionData();
|
||||
// The asset data we just generated will look like this:
|
||||
// a7cb5fb7
|
||||
// 0x 0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082
|
||||
@@ -1232,12 +1219,9 @@ describe('ERC1155Proxy', () => {
|
||||
const valuesToTransfer = [fungibleValueToTransferLarge];
|
||||
const valueMultiplier = valueMultiplierSmall;
|
||||
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
|
||||
const assetData = await devUtils.encodeERC1155AssetData.callAsync(
|
||||
erc1155ContractAddress,
|
||||
tokensToTransfer,
|
||||
valuesToTransfer,
|
||||
receiverCallbackData,
|
||||
);
|
||||
const assetData = assetDataContract
|
||||
.ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
|
||||
.getABIEncodedTransactionData();
|
||||
// The asset data we just generated will look like this:
|
||||
// a7cb5fb7
|
||||
// 0x 0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082
|
||||
@@ -1284,12 +1268,9 @@ describe('ERC1155Proxy', () => {
|
||||
const valuesToTransfer = [fungibleValueToTransferLarge];
|
||||
const valueMultiplier = valueMultiplierSmall;
|
||||
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
|
||||
const assetData = await devUtils.encodeERC1155AssetData.callAsync(
|
||||
erc1155ContractAddress,
|
||||
tokensToTransfer,
|
||||
valuesToTransfer,
|
||||
receiverCallbackData,
|
||||
);
|
||||
const assetData = assetDataContract
|
||||
.ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
|
||||
.getABIEncodedTransactionData();
|
||||
// The asset data we just generated will look like this:
|
||||
// a7cb5fb7
|
||||
// 0x 0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082
|
||||
@@ -1331,12 +1312,9 @@ describe('ERC1155Proxy', () => {
|
||||
const valuesToTransfer = [fungibleValueToTransferLarge];
|
||||
const valueMultiplier = valueMultiplierSmall;
|
||||
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
|
||||
const assetData = await devUtils.encodeERC1155AssetData.callAsync(
|
||||
erc1155ContractAddress,
|
||||
tokensToTransfer,
|
||||
valuesToTransfer,
|
||||
receiverCallbackData,
|
||||
);
|
||||
const assetData = assetDataContract
|
||||
.ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
|
||||
.getABIEncodedTransactionData();
|
||||
// The asset data we just generated will look like this:
|
||||
// a7cb5fb7
|
||||
// 0x 0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082
|
||||
@@ -1382,12 +1360,9 @@ describe('ERC1155Proxy', () => {
|
||||
const valuesToTransfer = [fungibleValueToTransferLarge];
|
||||
const valueMultiplier = valueMultiplierSmall;
|
||||
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
|
||||
const assetData = await devUtils.encodeERC1155AssetData.callAsync(
|
||||
erc1155ContractAddress,
|
||||
tokensToTransfer,
|
||||
valuesToTransfer,
|
||||
receiverCallbackData,
|
||||
);
|
||||
const assetData = assetDataContract
|
||||
.ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
|
||||
.getABIEncodedTransactionData();
|
||||
// The asset data we just generated will look like this:
|
||||
// a7cb5fb7
|
||||
// 0x 0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082
|
||||
@@ -1429,12 +1404,9 @@ describe('ERC1155Proxy', () => {
|
||||
const valuesToTransfer = [fungibleValueToTransferLarge];
|
||||
const valueMultiplier = valueMultiplierSmall;
|
||||
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
|
||||
const assetData = await devUtils.encodeERC1155AssetData.callAsync(
|
||||
erc1155ContractAddress,
|
||||
tokensToTransfer,
|
||||
valuesToTransfer,
|
||||
receiverCallbackData,
|
||||
);
|
||||
const assetData = assetDataContract
|
||||
.ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
|
||||
.getABIEncodedTransactionData();
|
||||
// The asset data we just generated will look like this:
|
||||
// a7cb5fb7
|
||||
// 0x 0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082
|
||||
@@ -1480,12 +1452,9 @@ describe('ERC1155Proxy', () => {
|
||||
const valuesToTransfer = [fungibleValueToTransferLarge];
|
||||
const valueMultiplier = valueMultiplierSmall;
|
||||
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
|
||||
const assetData = await devUtils.encodeERC1155AssetData.callAsync(
|
||||
erc1155ContractAddress,
|
||||
tokensToTransfer,
|
||||
valuesToTransfer,
|
||||
receiverCallbackData,
|
||||
);
|
||||
const assetData = assetDataContract
|
||||
.ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
|
||||
.getABIEncodedTransactionData();
|
||||
const txData = await erc1155ProxyWrapper.getTransferFromAbiEncodedTxDataAsync(
|
||||
spender,
|
||||
receiverContract,
|
||||
@@ -1511,12 +1480,9 @@ describe('ERC1155Proxy', () => {
|
||||
const valuesToTransfer = [fungibleValueToTransferLarge];
|
||||
const valueMultiplier = valueMultiplierSmall;
|
||||
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
|
||||
const assetData = await devUtils.encodeERC1155AssetData.callAsync(
|
||||
erc1155ContractAddress,
|
||||
tokensToTransfer,
|
||||
valuesToTransfer,
|
||||
receiverCallbackData,
|
||||
);
|
||||
const assetData = assetDataContract
|
||||
.ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
|
||||
.getABIEncodedTransactionData();
|
||||
const txData = await erc1155ProxyWrapper.getTransferFromAbiEncodedTxDataAsync(
|
||||
spender,
|
||||
receiverContract,
|
||||
@@ -1640,7 +1606,7 @@ describe('ERC1155Proxy', () => {
|
||||
it('should propagate revert reason from erc1155 contract failure', async () => {
|
||||
// disable transfers
|
||||
const shouldRejectTransfer = true;
|
||||
await erc1155Receiver.setRejectTransferFlag.awaitTransactionSuccessAsync(shouldRejectTransfer, {
|
||||
await erc1155Receiver.setRejectTransferFlag(shouldRejectTransfer).awaitTransactionSuccessAsync({
|
||||
from: owner,
|
||||
});
|
||||
// setup test parameters
|
||||
|
||||
@@ -3,27 +3,22 @@ import {
|
||||
constants,
|
||||
expect,
|
||||
getRandomInteger,
|
||||
hexLeftPad,
|
||||
hexRightPad,
|
||||
hexSlice,
|
||||
Numberish,
|
||||
randomAddress,
|
||||
} from '@0x/contracts-test-utils';
|
||||
import { AuthorizableRevertErrors } from '@0x/contracts-utils';
|
||||
import { AssetProxyId } from '@0x/types';
|
||||
import { AbiEncoder, AuthorizableRevertErrors, BigNumber, StringRevertError } from '@0x/utils';
|
||||
import { AbiEncoder, BigNumber, hexUtils, StringRevertError } from '@0x/utils';
|
||||
import { DecodedLogs } from 'ethereum-types';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import {
|
||||
artifacts,
|
||||
ERC20BridgeProxyContract,
|
||||
TestERC20BridgeBridgeWithdrawToEventArgs,
|
||||
TestERC20BridgeContract,
|
||||
} from '../src';
|
||||
import { artifacts } from './artifacts';
|
||||
|
||||
import { ERC20BridgeProxyContract, TestERC20BridgeContract } from './wrappers';
|
||||
|
||||
blockchainTests.resets('ERC20BridgeProxy unit tests', env => {
|
||||
const PROXY_ID = AssetProxyId.ERC20Bridge;
|
||||
const BRIDGE_SUCCESS_RETURN_DATA = hexRightPad(PROXY_ID);
|
||||
const BRIDGE_SUCCESS_RETURN_DATA = hexUtils.rightPad(PROXY_ID);
|
||||
let owner: string;
|
||||
let badCaller: string;
|
||||
let assetProxy: ERC20BridgeProxyContract;
|
||||
@@ -44,8 +39,8 @@ blockchainTests.resets('ERC20BridgeProxy unit tests', env => {
|
||||
env.txDefaults,
|
||||
artifacts,
|
||||
);
|
||||
testTokenAddress = await bridgeContract.testToken.callAsync();
|
||||
await assetProxy.addAuthorizedAddress.awaitTransactionSuccessAsync(owner);
|
||||
testTokenAddress = await bridgeContract.testToken().callAsync();
|
||||
await assetProxy.addAuthorizedAddress(owner).awaitTransactionSuccessAsync();
|
||||
});
|
||||
|
||||
interface AssetDataOpts {
|
||||
@@ -102,7 +97,7 @@ blockchainTests.resets('ERC20BridgeProxy unit tests', env => {
|
||||
}
|
||||
|
||||
async function setTestTokenBalanceAsync(_owner: string, balance: Numberish): Promise<void> {
|
||||
await bridgeContract.setTestTokenBalance.awaitTransactionSuccessAsync(_owner, new BigNumber(balance));
|
||||
await bridgeContract.setTestTokenBalance(_owner, new BigNumber(balance)).awaitTransactionSuccessAsync();
|
||||
}
|
||||
|
||||
describe('transferFrom()', () => {
|
||||
@@ -132,13 +127,9 @@ blockchainTests.resets('ERC20BridgeProxy unit tests', env => {
|
||||
|
||||
async function transferFromAsync(opts?: Partial<TransferFromOpts>, caller?: string): Promise<DecodedLogs> {
|
||||
const _opts = createTransferFromOpts(opts);
|
||||
const { logs } = await assetProxy.transferFrom.awaitTransactionSuccessAsync(
|
||||
encodeAssetData(_opts.assetData),
|
||||
_opts.from,
|
||||
_opts.to,
|
||||
new BigNumber(_opts.amount),
|
||||
{ from: caller },
|
||||
);
|
||||
const { logs } = await assetProxy
|
||||
.transferFrom(encodeAssetData(_opts.assetData), _opts.from, _opts.to, new BigNumber(_opts.amount))
|
||||
.awaitTransactionSuccessAsync({ from: caller });
|
||||
return (logs as any) as DecodedLogs;
|
||||
}
|
||||
|
||||
@@ -164,7 +155,7 @@ blockchainTests.resets('ERC20BridgeProxy unit tests', env => {
|
||||
const opts = createTransferFromOpts();
|
||||
const logs = await transferFromAsync(opts);
|
||||
expect(logs.length).to.eq(1);
|
||||
const args = logs[0].args as TestERC20BridgeBridgeWithdrawToEventArgs;
|
||||
const args = logs[0].args;
|
||||
expect(args.tokenAddress).to.eq(opts.assetData.tokenAddress);
|
||||
expect(args.from).to.eq(opts.from);
|
||||
expect(args.to).to.eq(opts.to);
|
||||
@@ -179,13 +170,10 @@ blockchainTests.resets('ERC20BridgeProxy unit tests', env => {
|
||||
|
||||
it('fails if asset data is truncated', async () => {
|
||||
const opts = createTransferFromOpts();
|
||||
const truncatedAssetData = hexSlice(encodeAssetData(opts.assetData), 0, -1);
|
||||
const tx = assetProxy.transferFrom.awaitTransactionSuccessAsync(
|
||||
truncatedAssetData,
|
||||
opts.from,
|
||||
opts.to,
|
||||
new BigNumber(opts.amount),
|
||||
);
|
||||
const truncatedAssetData = hexUtils.slice(encodeAssetData(opts.assetData), 0, -1);
|
||||
const tx = assetProxy
|
||||
.transferFrom(truncatedAssetData, opts.from, opts.to, new BigNumber(opts.amount))
|
||||
.awaitTransactionSuccessAsync();
|
||||
return expect(tx).to.be.rejected();
|
||||
});
|
||||
|
||||
@@ -206,7 +194,7 @@ blockchainTests.resets('ERC20BridgeProxy unit tests', env => {
|
||||
const tx = transferFromAsync({
|
||||
assetData: createAssetData({
|
||||
bridgeData: createBridgeData({
|
||||
returnData: hexLeftPad('0x1'),
|
||||
returnData: hexUtils.leftPad('0x1'),
|
||||
}),
|
||||
}),
|
||||
});
|
||||
@@ -219,7 +207,7 @@ blockchainTests.resets('ERC20BridgeProxy unit tests', env => {
|
||||
const tx = transferFromAsync({
|
||||
assetData: createAssetData({
|
||||
bridgeData: createBridgeData({
|
||||
returnData: hexRightPad('0x1'),
|
||||
returnData: hexUtils.rightPad('0x1'),
|
||||
}),
|
||||
}),
|
||||
});
|
||||
@@ -281,18 +269,18 @@ blockchainTests.resets('ERC20BridgeProxy unit tests', env => {
|
||||
it('retrieves the balance of the encoded token', async () => {
|
||||
const _owner = randomAddress();
|
||||
const balance = getRandomInteger(1, 100e18);
|
||||
await bridgeContract.setTestTokenBalance.awaitTransactionSuccessAsync(_owner, balance);
|
||||
await bridgeContract.setTestTokenBalance(_owner, balance).awaitTransactionSuccessAsync();
|
||||
const assetData = createAssetData({
|
||||
tokenAddress: testTokenAddress,
|
||||
});
|
||||
const actualBalance = await assetProxy.balanceOf.callAsync(encodeAssetData(assetData), _owner);
|
||||
const actualBalance = await assetProxy.balanceOf(encodeAssetData(assetData), _owner).callAsync();
|
||||
expect(actualBalance).to.bignumber.eq(balance);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getProxyId()', () => {
|
||||
it('returns the correct proxy ID', async () => {
|
||||
const proxyId = await assetProxy.getProxyId.callAsync();
|
||||
const proxyId = await assetProxy.getProxyId().callAsync();
|
||||
expect(proxyId).to.eq(PROXY_ID);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -4,28 +4,25 @@ import {
|
||||
expect,
|
||||
filterLogsToArguments,
|
||||
getRandomInteger,
|
||||
hexLeftPad,
|
||||
hexRandom,
|
||||
Numberish,
|
||||
randomAddress,
|
||||
TransactionHelper,
|
||||
} from '@0x/contracts-test-utils';
|
||||
import { AssetProxyId } from '@0x/types';
|
||||
import { BigNumber, RawRevertError } from '@0x/utils';
|
||||
import { BigNumber, hexUtils, RawRevertError } from '@0x/utils';
|
||||
import { DecodedLogs } from 'ethereum-types';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { artifacts } from './artifacts';
|
||||
|
||||
import {
|
||||
artifacts,
|
||||
TestEth2DaiBridgeContract,
|
||||
TestEth2DaiBridgeEvents,
|
||||
TestEth2DaiBridgeSellAllAmountEventArgs,
|
||||
TestEth2DaiBridgeTokenApproveEventArgs,
|
||||
TestEth2DaiBridgeTokenTransferEventArgs,
|
||||
} from '../src';
|
||||
} from './wrappers';
|
||||
|
||||
blockchainTests.resets('Eth2DaiBridge unit tests', env => {
|
||||
const txHelper = new TransactionHelper(env.web3Wrapper, artifacts);
|
||||
let testContract: TestEth2DaiBridgeContract;
|
||||
|
||||
before(async () => {
|
||||
@@ -40,7 +37,9 @@ blockchainTests.resets('Eth2DaiBridge unit tests', env => {
|
||||
describe('isValidSignature()', () => {
|
||||
it('returns success bytes', async () => {
|
||||
const LEGACY_WALLET_MAGIC_VALUE = '0xb0671381';
|
||||
const result = await testContract.isValidSignature.callAsync(hexRandom(), hexRandom(_.random(0, 32)));
|
||||
const result = await testContract
|
||||
.isValidSignature(hexUtils.random(), hexUtils.random(_.random(0, 32)))
|
||||
.callAsync();
|
||||
expect(result).to.eq(LEGACY_WALLET_MAGIC_VALUE);
|
||||
});
|
||||
});
|
||||
@@ -72,7 +71,7 @@ blockchainTests.resets('Eth2DaiBridge unit tests', env => {
|
||||
fillAmount: getRandomInteger(1, 100e18),
|
||||
fromTokenBalance: getRandomInteger(1, 100e18),
|
||||
toTokentransferRevertReason: '',
|
||||
toTokenTransferReturnData: hexLeftPad(1),
|
||||
toTokenTransferReturnData: hexUtils.leftPad(1),
|
||||
...opts,
|
||||
};
|
||||
}
|
||||
@@ -80,32 +79,30 @@ blockchainTests.resets('Eth2DaiBridge unit tests', env => {
|
||||
async function withdrawToAsync(opts?: Partial<WithdrawToOpts>): Promise<WithdrawToResult> {
|
||||
const _opts = createWithdrawToOpts(opts);
|
||||
// Set the fill behavior.
|
||||
await testContract.setFillBehavior.awaitTransactionSuccessAsync(
|
||||
_opts.revertReason,
|
||||
new BigNumber(_opts.fillAmount),
|
||||
);
|
||||
await testContract
|
||||
.setFillBehavior(_opts.revertReason, new BigNumber(_opts.fillAmount))
|
||||
.awaitTransactionSuccessAsync();
|
||||
// Create tokens and balances.
|
||||
if (_opts.fromTokenAddress === undefined) {
|
||||
[_opts.fromTokenAddress] = await txHelper.getResultAndReceiptAsync(
|
||||
testContract.createToken,
|
||||
new BigNumber(_opts.fromTokenBalance),
|
||||
);
|
||||
const createTokenFn = testContract.createToken(new BigNumber(_opts.fromTokenBalance));
|
||||
_opts.fromTokenAddress = await createTokenFn.callAsync();
|
||||
await createTokenFn.awaitTransactionSuccessAsync();
|
||||
}
|
||||
if (_opts.toTokenAddress === undefined) {
|
||||
[_opts.toTokenAddress] = await txHelper.getResultAndReceiptAsync(
|
||||
testContract.createToken,
|
||||
constants.ZERO_AMOUNT,
|
||||
);
|
||||
const createTokenFn = testContract.createToken(constants.ZERO_AMOUNT);
|
||||
_opts.toTokenAddress = await createTokenFn.callAsync();
|
||||
await createTokenFn.awaitTransactionSuccessAsync();
|
||||
}
|
||||
// Set the transfer behavior of `toTokenAddress`.
|
||||
await testContract.setTransferBehavior.awaitTransactionSuccessAsync(
|
||||
_opts.toTokenAddress,
|
||||
_opts.toTokentransferRevertReason,
|
||||
_opts.toTokenTransferReturnData,
|
||||
);
|
||||
await testContract
|
||||
.setTransferBehavior(
|
||||
_opts.toTokenAddress,
|
||||
_opts.toTokentransferRevertReason,
|
||||
_opts.toTokenTransferReturnData,
|
||||
)
|
||||
.awaitTransactionSuccessAsync();
|
||||
// Call bridgeTransferFrom().
|
||||
const [result, { logs }] = await txHelper.getResultAndReceiptAsync(
|
||||
testContract.bridgeTransferFrom,
|
||||
const bridgeTransferFromFn = testContract.bridgeTransferFrom(
|
||||
// "to" token address
|
||||
_opts.toTokenAddress,
|
||||
// Random from address.
|
||||
@@ -114,8 +111,10 @@ blockchainTests.resets('Eth2DaiBridge unit tests', env => {
|
||||
_opts.toAddress,
|
||||
new BigNumber(_opts.amount),
|
||||
// ABI-encode the "from" token address as the bridge data.
|
||||
hexLeftPad(_opts.fromTokenAddress as string),
|
||||
hexUtils.leftPad(_opts.fromTokenAddress as string),
|
||||
);
|
||||
const result = await bridgeTransferFromFn.callAsync();
|
||||
const { logs } = await bridgeTransferFromFn.awaitTransactionSuccessAsync();
|
||||
return {
|
||||
opts: _opts,
|
||||
result,
|
||||
@@ -180,13 +179,13 @@ blockchainTests.resets('Eth2DaiBridge unit tests', env => {
|
||||
});
|
||||
|
||||
it('fails if `toTokenAddress.transfer()` returns false', async () => {
|
||||
const opts = createWithdrawToOpts({ toTokenTransferReturnData: hexLeftPad(0) });
|
||||
const opts = createWithdrawToOpts({ toTokenTransferReturnData: hexUtils.leftPad(0) });
|
||||
const tx = withdrawToAsync(opts);
|
||||
return expect(tx).to.revertWith(new RawRevertError(hexLeftPad(0)));
|
||||
return expect(tx).to.revertWith(new RawRevertError(hexUtils.leftPad(0)));
|
||||
});
|
||||
|
||||
it('succeeds if `toTokenAddress.transfer()` returns true', async () => {
|
||||
await withdrawToAsync({ toTokenTransferReturnData: hexLeftPad(1) });
|
||||
await withdrawToAsync({ toTokenTransferReturnData: hexUtils.leftPad(1) });
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
284
contracts/asset-proxy/test/kyber_bridge.ts
Normal file
284
contracts/asset-proxy/test/kyber_bridge.ts
Normal file
@@ -0,0 +1,284 @@
|
||||
import {
|
||||
blockchainTests,
|
||||
constants,
|
||||
expect,
|
||||
getRandomInteger,
|
||||
getRandomPortion,
|
||||
randomAddress,
|
||||
verifyEventsFromLogs,
|
||||
} from '@0x/contracts-test-utils';
|
||||
import { AssetProxyId } from '@0x/types';
|
||||
import { BigNumber, hexUtils } from '@0x/utils';
|
||||
import { DecodedLogs } from 'ethereum-types';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { artifacts } from './artifacts';
|
||||
|
||||
import { TestKyberBridgeContract, TestKyberBridgeEvents } from './wrappers';
|
||||
|
||||
// TODO(dorothy-zbornak): Tests need to be updated.
|
||||
blockchainTests.resets.skip('KyberBridge unit tests', env => {
|
||||
const KYBER_ETH_ADDRESS = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee';
|
||||
const FROM_TOKEN_DECIMALS = 6;
|
||||
const TO_TOKEN_DECIMALS = 18;
|
||||
const FROM_TOKEN_BASE = new BigNumber(10).pow(FROM_TOKEN_DECIMALS);
|
||||
const TO_TOKEN_BASE = new BigNumber(10).pow(TO_TOKEN_DECIMALS);
|
||||
const WETH_BASE = new BigNumber(10).pow(18);
|
||||
const KYBER_RATE_BASE = WETH_BASE;
|
||||
let testContract: TestKyberBridgeContract;
|
||||
|
||||
before(async () => {
|
||||
testContract = await TestKyberBridgeContract.deployFrom0xArtifactAsync(
|
||||
artifacts.TestKyberBridge,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
artifacts,
|
||||
);
|
||||
});
|
||||
|
||||
describe('isValidSignature()', () => {
|
||||
it('returns success bytes', async () => {
|
||||
const LEGACY_WALLET_MAGIC_VALUE = '0xb0671381';
|
||||
const result = await testContract
|
||||
.isValidSignature(hexUtils.random(), hexUtils.random(_.random(0, 32)))
|
||||
.callAsync();
|
||||
expect(result).to.eq(LEGACY_WALLET_MAGIC_VALUE);
|
||||
});
|
||||
});
|
||||
|
||||
describe('bridgeTransferFrom()', () => {
|
||||
let fromTokenAddress: string;
|
||||
let toTokenAddress: string;
|
||||
let wethAddress: string;
|
||||
|
||||
before(async () => {
|
||||
wethAddress = await testContract.weth().callAsync();
|
||||
fromTokenAddress = await testContract.createToken(FROM_TOKEN_DECIMALS).callAsync();
|
||||
await testContract.createToken(FROM_TOKEN_DECIMALS).awaitTransactionSuccessAsync();
|
||||
toTokenAddress = await testContract.createToken(TO_TOKEN_DECIMALS).callAsync();
|
||||
await testContract.createToken(TO_TOKEN_DECIMALS).awaitTransactionSuccessAsync();
|
||||
});
|
||||
|
||||
const STATIC_KYBER_TRADE_ARGS = {
|
||||
maxBuyTokenAmount: constants.MAX_UINT256,
|
||||
walletId: constants.NULL_ADDRESS,
|
||||
};
|
||||
|
||||
interface TransferFromOpts {
|
||||
toTokenAddress: string;
|
||||
fromTokenAddress: string;
|
||||
toAddress: string;
|
||||
// Amount to pass into `bridgeTransferFrom()`
|
||||
amount: BigNumber;
|
||||
// Amount to convert in `trade()`.
|
||||
fillAmount: BigNumber;
|
||||
// Token balance of the bridge.
|
||||
fromTokenBalance: BigNumber;
|
||||
}
|
||||
|
||||
interface TransferFromResult {
|
||||
opts: TransferFromOpts;
|
||||
result: string;
|
||||
logs: DecodedLogs;
|
||||
}
|
||||
|
||||
function createTransferFromOpts(opts?: Partial<TransferFromOpts>): TransferFromOpts {
|
||||
const amount = getRandomInteger(1, TO_TOKEN_BASE.times(100));
|
||||
return {
|
||||
fromTokenAddress,
|
||||
toTokenAddress,
|
||||
amount,
|
||||
toAddress: randomAddress(),
|
||||
fillAmount: getRandomPortion(amount),
|
||||
fromTokenBalance: getRandomInteger(1, FROM_TOKEN_BASE.times(100)),
|
||||
...opts,
|
||||
};
|
||||
}
|
||||
|
||||
async function withdrawToAsync(opts?: Partial<TransferFromOpts>): Promise<TransferFromResult> {
|
||||
const _opts = createTransferFromOpts(opts);
|
||||
// Fund the contract with input tokens.
|
||||
await testContract
|
||||
.grantTokensTo(_opts.fromTokenAddress, testContract.address, _opts.fromTokenBalance)
|
||||
.awaitTransactionSuccessAsync({ value: _opts.fromTokenBalance });
|
||||
// Fund the contract with output tokens.
|
||||
await testContract.setNextFillAmount(_opts.fillAmount).awaitTransactionSuccessAsync({
|
||||
value: _opts.toTokenAddress === wethAddress ? _opts.fillAmount : constants.ZERO_AMOUNT,
|
||||
});
|
||||
// Call bridgeTransferFrom().
|
||||
const bridgeTransferFromFn = testContract.bridgeTransferFrom(
|
||||
// Output token
|
||||
_opts.toTokenAddress,
|
||||
// Random maker address.
|
||||
randomAddress(),
|
||||
// Recipient address.
|
||||
_opts.toAddress,
|
||||
// Transfer amount.
|
||||
_opts.amount,
|
||||
// ABI-encode the input token address as the bridge data.
|
||||
hexUtils.concat(hexUtils.leftPad(_opts.fromTokenAddress), hexUtils.leftPad(32), hexUtils.leftPad(0)),
|
||||
);
|
||||
const result = await bridgeTransferFromFn.callAsync();
|
||||
const { logs } = await bridgeTransferFromFn.awaitTransactionSuccessAsync();
|
||||
return {
|
||||
opts: _opts,
|
||||
result,
|
||||
logs: (logs as any) as DecodedLogs,
|
||||
};
|
||||
}
|
||||
|
||||
function getMinimumConversionRate(opts: TransferFromOpts): BigNumber {
|
||||
const fromBase = opts.fromTokenAddress === wethAddress ? WETH_BASE : FROM_TOKEN_BASE;
|
||||
const toBase = opts.toTokenAddress === wethAddress ? WETH_BASE : TO_TOKEN_BASE;
|
||||
return opts.amount
|
||||
.div(toBase)
|
||||
.div(opts.fromTokenBalance.div(fromBase))
|
||||
.times(KYBER_RATE_BASE)
|
||||
.integerValue(BigNumber.ROUND_DOWN);
|
||||
}
|
||||
|
||||
it('returns magic bytes on success', async () => {
|
||||
const BRIDGE_SUCCESS_RETURN_DATA = AssetProxyId.ERC20Bridge;
|
||||
const { result } = await withdrawToAsync();
|
||||
expect(result).to.eq(BRIDGE_SUCCESS_RETURN_DATA);
|
||||
});
|
||||
|
||||
it('can trade token -> token', async () => {
|
||||
const { opts, logs } = await withdrawToAsync();
|
||||
verifyEventsFromLogs(
|
||||
logs,
|
||||
[
|
||||
{
|
||||
sellTokenAddress: opts.fromTokenAddress,
|
||||
buyTokenAddress: opts.toTokenAddress,
|
||||
sellAmount: opts.fromTokenBalance,
|
||||
recipientAddress: opts.toAddress,
|
||||
minConversionRate: getMinimumConversionRate(opts),
|
||||
msgValue: constants.ZERO_AMOUNT,
|
||||
...STATIC_KYBER_TRADE_ARGS,
|
||||
},
|
||||
],
|
||||
TestKyberBridgeEvents.KyberBridgeTrade,
|
||||
);
|
||||
});
|
||||
|
||||
it('can trade token -> ETH', async () => {
|
||||
const { opts, logs } = await withdrawToAsync({
|
||||
toTokenAddress: wethAddress,
|
||||
});
|
||||
verifyEventsFromLogs(
|
||||
logs,
|
||||
[
|
||||
{
|
||||
sellTokenAddress: opts.fromTokenAddress,
|
||||
buyTokenAddress: KYBER_ETH_ADDRESS,
|
||||
sellAmount: opts.fromTokenBalance,
|
||||
recipientAddress: testContract.address,
|
||||
minConversionRate: getMinimumConversionRate(opts),
|
||||
msgValue: constants.ZERO_AMOUNT,
|
||||
...STATIC_KYBER_TRADE_ARGS,
|
||||
},
|
||||
],
|
||||
TestKyberBridgeEvents.KyberBridgeTrade,
|
||||
);
|
||||
});
|
||||
|
||||
it('can trade ETH -> token', async () => {
|
||||
const { opts, logs } = await withdrawToAsync({
|
||||
fromTokenAddress: wethAddress,
|
||||
});
|
||||
verifyEventsFromLogs(
|
||||
logs,
|
||||
[
|
||||
{
|
||||
sellTokenAddress: KYBER_ETH_ADDRESS,
|
||||
buyTokenAddress: opts.toTokenAddress,
|
||||
sellAmount: opts.fromTokenBalance,
|
||||
recipientAddress: opts.toAddress,
|
||||
minConversionRate: getMinimumConversionRate(opts),
|
||||
msgValue: opts.fromTokenBalance,
|
||||
...STATIC_KYBER_TRADE_ARGS,
|
||||
},
|
||||
],
|
||||
TestKyberBridgeEvents.KyberBridgeTrade,
|
||||
);
|
||||
});
|
||||
|
||||
it('does nothing if bridge has no token balance', async () => {
|
||||
const { logs } = await withdrawToAsync({
|
||||
fromTokenBalance: constants.ZERO_AMOUNT,
|
||||
});
|
||||
expect(logs).to.be.length(0);
|
||||
});
|
||||
|
||||
it('only transfers the token if trading the same token', async () => {
|
||||
const { opts, logs } = await withdrawToAsync({
|
||||
toTokenAddress: fromTokenAddress,
|
||||
});
|
||||
verifyEventsFromLogs(
|
||||
logs,
|
||||
[
|
||||
{
|
||||
tokenAddress: fromTokenAddress,
|
||||
ownerAddress: testContract.address,
|
||||
recipientAddress: opts.toAddress,
|
||||
amount: opts.fromTokenBalance,
|
||||
},
|
||||
],
|
||||
TestKyberBridgeEvents.KyberBridgeTokenTransfer,
|
||||
);
|
||||
});
|
||||
|
||||
it('grants Kyber an allowance when selling non-WETH', async () => {
|
||||
const { opts, logs } = await withdrawToAsync();
|
||||
verifyEventsFromLogs(
|
||||
logs,
|
||||
[
|
||||
{
|
||||
tokenAddress: opts.fromTokenAddress,
|
||||
ownerAddress: testContract.address,
|
||||
spenderAddress: testContract.address,
|
||||
allowance: constants.MAX_UINT256,
|
||||
},
|
||||
],
|
||||
TestKyberBridgeEvents.KyberBridgeTokenApprove,
|
||||
);
|
||||
});
|
||||
|
||||
it('does not grant Kyber an allowance when selling WETH', async () => {
|
||||
const { logs } = await withdrawToAsync({
|
||||
fromTokenAddress: wethAddress,
|
||||
});
|
||||
verifyEventsFromLogs(logs, [], TestKyberBridgeEvents.KyberBridgeTokenApprove);
|
||||
});
|
||||
|
||||
it('withdraws WETH and passes it to Kyber when selling WETH', async () => {
|
||||
const { opts, logs } = await withdrawToAsync({
|
||||
fromTokenAddress: wethAddress,
|
||||
});
|
||||
expect(logs[0].event).to.eq(TestKyberBridgeEvents.KyberBridgeWethWithdraw);
|
||||
expect(logs[0].args).to.deep.eq({
|
||||
ownerAddress: testContract.address,
|
||||
amount: opts.fromTokenBalance,
|
||||
});
|
||||
expect(logs[1].event).to.eq(TestKyberBridgeEvents.KyberBridgeTrade);
|
||||
expect(logs[1].args.msgValue).to.bignumber.eq(opts.fromTokenBalance);
|
||||
});
|
||||
|
||||
it('wraps WETH and transfers it to the recipient when buyng WETH', async () => {
|
||||
const { opts, logs } = await withdrawToAsync({
|
||||
toTokenAddress: wethAddress,
|
||||
});
|
||||
expect(logs[0].event).to.eq(TestKyberBridgeEvents.KyberBridgeTokenApprove);
|
||||
expect(logs[0].args.tokenAddress).to.eq(opts.fromTokenAddress);
|
||||
expect(logs[1].event).to.eq(TestKyberBridgeEvents.KyberBridgeTrade);
|
||||
expect(logs[1].args.recipientAddress).to.eq(testContract.address);
|
||||
expect(logs[2].event).to.eq(TestKyberBridgeEvents.KyberBridgeWethDeposit);
|
||||
expect(logs[2].args).to.deep.eq({
|
||||
msgValue: opts.fillAmount,
|
||||
ownerAddress: testContract.address,
|
||||
amount: opts.fillAmount,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,8 +1,6 @@
|
||||
import { DevUtilsContract } from '@0x/contracts-dev-utils';
|
||||
import {
|
||||
chaiSetup,
|
||||
constants,
|
||||
expectTransactionFailedAsync,
|
||||
expectTransactionFailedWithoutReasonAsync,
|
||||
provider,
|
||||
txDefaults,
|
||||
@@ -14,7 +12,14 @@ import { AbiEncoder, BigNumber } from '@0x/utils';
|
||||
import * as chai from 'chai';
|
||||
import * as ethUtil from 'ethereumjs-util';
|
||||
|
||||
import { artifacts, IAssetProxyContract, StaticCallProxyContract, TestStaticCallTargetContract } from '../src';
|
||||
import { artifacts } from './artifacts';
|
||||
|
||||
import {
|
||||
IAssetDataContract,
|
||||
IAssetProxyContract,
|
||||
StaticCallProxyContract,
|
||||
TestStaticCallTargetContract,
|
||||
} from './wrappers';
|
||||
|
||||
chaiSetup.configure();
|
||||
const expect = chai.expect;
|
||||
@@ -25,7 +30,7 @@ describe('StaticCallProxy', () => {
|
||||
let fromAddress: string;
|
||||
let toAddress: string;
|
||||
|
||||
let devUtils: DevUtilsContract;
|
||||
let assetDataInterface: IAssetDataContract;
|
||||
let staticCallProxy: IAssetProxyContract;
|
||||
let staticCallTarget: TestStaticCallTargetContract;
|
||||
|
||||
@@ -44,7 +49,7 @@ describe('StaticCallProxy', () => {
|
||||
txDefaults,
|
||||
artifacts,
|
||||
);
|
||||
devUtils = new DevUtilsContract(constants.NULL_ADDRESS, provider);
|
||||
assetDataInterface = new IAssetDataContract(constants.NULL_ADDRESS, provider);
|
||||
staticCallProxy = new IAssetProxyContract(
|
||||
staticCallProxyWithoutTransferFrom.address,
|
||||
provider,
|
||||
@@ -79,26 +84,21 @@ describe('StaticCallProxy', () => {
|
||||
);
|
||||
});
|
||||
it('should have an id of 0xc339d10a', async () => {
|
||||
const proxyId = await staticCallProxy.getProxyId.callAsync();
|
||||
const proxyId = await staticCallProxy.getProxyId().callAsync();
|
||||
const expectedProxyId = AssetProxyId.StaticCall;
|
||||
expect(proxyId).to.equal(expectedProxyId);
|
||||
});
|
||||
});
|
||||
describe('transferFrom', () => {
|
||||
it('should revert if assetData lies outside the bounds of calldata', async () => {
|
||||
const staticCallData = staticCallTarget.noInputFunction.getABIEncodedTransactionData();
|
||||
const staticCallData = staticCallTarget.noInputFunction().getABIEncodedTransactionData();
|
||||
const expectedResultHash = constants.KECCAK256_NULL;
|
||||
const assetData = await devUtils.encodeStaticCallAssetData.callAsync(
|
||||
staticCallTarget.address,
|
||||
staticCallData,
|
||||
expectedResultHash,
|
||||
);
|
||||
const txData = staticCallProxy.transferFrom.getABIEncodedTransactionData(
|
||||
assetData,
|
||||
fromAddress,
|
||||
toAddress,
|
||||
amount,
|
||||
);
|
||||
const assetData = assetDataInterface
|
||||
.StaticCall(staticCallTarget.address, staticCallData, expectedResultHash)
|
||||
.getABIEncodedTransactionData();
|
||||
const txData = staticCallProxy
|
||||
.transferFrom(assetData, fromAddress, toAddress, amount)
|
||||
.getABIEncodedTransactionData();
|
||||
const offsetToAssetData = '0000000000000000000000000000000000000000000000000000000000000080';
|
||||
const txDataEndBuffer = ethUtil.toBuffer((txData.length - 2) / 2 - 4);
|
||||
const paddedTxDataEndBuffer = ethUtil.setLengthLeft(txDataEndBuffer, 32);
|
||||
@@ -116,25 +116,22 @@ describe('StaticCallProxy', () => {
|
||||
it('should revert if the length of assetData is less than 100 bytes', async () => {
|
||||
const staticCallData = constants.NULL_BYTES;
|
||||
const expectedResultHash = constants.KECCAK256_NULL;
|
||||
const assetData = (await devUtils.encodeStaticCallAssetData.callAsync(
|
||||
staticCallTarget.address,
|
||||
staticCallData,
|
||||
expectedResultHash,
|
||||
)).slice(0, -128);
|
||||
const assetData = assetDataInterface
|
||||
.StaticCall(staticCallTarget.address, staticCallData, expectedResultHash)
|
||||
.getABIEncodedTransactionData()
|
||||
.slice(0, -128);
|
||||
const assetDataByteLen = (assetData.length - 2) / 2;
|
||||
expect((assetDataByteLen - 4) % 32).to.equal(0);
|
||||
await expectTransactionFailedWithoutReasonAsync(
|
||||
staticCallProxy.transferFrom.sendTransactionAsync(assetData, fromAddress, toAddress, amount),
|
||||
staticCallProxy.transferFrom(assetData, fromAddress, toAddress, amount).sendTransactionAsync(),
|
||||
);
|
||||
});
|
||||
it('should revert if the offset to `staticCallData` points to outside of assetData', async () => {
|
||||
const staticCallData = staticCallTarget.noInputFunction.getABIEncodedTransactionData();
|
||||
const staticCallData = staticCallTarget.noInputFunction().getABIEncodedTransactionData();
|
||||
const expectedResultHash = constants.KECCAK256_NULL;
|
||||
const assetData = await devUtils.encodeStaticCallAssetData.callAsync(
|
||||
staticCallTarget.address,
|
||||
staticCallData,
|
||||
expectedResultHash,
|
||||
);
|
||||
const assetData = assetDataInterface
|
||||
.StaticCall(staticCallTarget.address, staticCallData, expectedResultHash)
|
||||
.getABIEncodedTransactionData();
|
||||
const offsetToStaticCallData = '0000000000000000000000000000000000000000000000000000000000000060';
|
||||
const assetDataEndBuffer = ethUtil.toBuffer((assetData.length - 2) / 2 - 4);
|
||||
const paddedAssetDataEndBuffer = ethUtil.setLengthLeft(assetDataEndBuffer, 32);
|
||||
@@ -145,94 +142,86 @@ describe('StaticCallProxy', () => {
|
||||
invalidOffsetToStaticCallData,
|
||||
)}${newStaticCallData}`;
|
||||
await expectTransactionFailedWithoutReasonAsync(
|
||||
staticCallProxy.transferFrom.sendTransactionAsync(badAssetData, fromAddress, toAddress, amount),
|
||||
staticCallProxy.transferFrom(badAssetData, fromAddress, toAddress, amount).sendTransactionAsync(),
|
||||
);
|
||||
});
|
||||
it('should revert if the callTarget attempts to write to state', async () => {
|
||||
const staticCallData = staticCallTarget.updateState.getABIEncodedTransactionData();
|
||||
const staticCallData = staticCallTarget.updateState().getABIEncodedTransactionData();
|
||||
const expectedResultHash = constants.KECCAK256_NULL;
|
||||
const assetData = await devUtils.encodeStaticCallAssetData.callAsync(
|
||||
staticCallTarget.address,
|
||||
staticCallData,
|
||||
expectedResultHash,
|
||||
);
|
||||
const assetData = assetDataInterface
|
||||
.StaticCall(staticCallTarget.address, staticCallData, expectedResultHash)
|
||||
.getABIEncodedTransactionData();
|
||||
await expectTransactionFailedWithoutReasonAsync(
|
||||
staticCallProxy.transferFrom.sendTransactionAsync(assetData, fromAddress, toAddress, amount),
|
||||
staticCallProxy.transferFrom(assetData, fromAddress, toAddress, amount).sendTransactionAsync(),
|
||||
);
|
||||
});
|
||||
it('should revert with data provided by the callTarget if the staticcall reverts', async () => {
|
||||
const staticCallData = staticCallTarget.assertEvenNumber.getABIEncodedTransactionData(new BigNumber(1));
|
||||
const staticCallData = staticCallTarget.assertEvenNumber(new BigNumber(1)).getABIEncodedTransactionData();
|
||||
const expectedResultHash = constants.KECCAK256_NULL;
|
||||
const assetData = await devUtils.encodeStaticCallAssetData.callAsync(
|
||||
staticCallTarget.address,
|
||||
staticCallData,
|
||||
expectedResultHash,
|
||||
);
|
||||
await expectTransactionFailedAsync(
|
||||
staticCallProxy.transferFrom.sendTransactionAsync(assetData, fromAddress, toAddress, amount),
|
||||
RevertReason.TargetNotEven,
|
||||
);
|
||||
const assetData = assetDataInterface
|
||||
.StaticCall(staticCallTarget.address, staticCallData, expectedResultHash)
|
||||
.getABIEncodedTransactionData();
|
||||
return expect(
|
||||
staticCallProxy.transferFrom(assetData, fromAddress, toAddress, amount).awaitTransactionSuccessAsync(),
|
||||
).to.revertWith(RevertReason.TargetNotEven);
|
||||
});
|
||||
it('should revert if the hash of the output is different than expected expected', async () => {
|
||||
const staticCallData = staticCallTarget.isOddNumber.getABIEncodedTransactionData(new BigNumber(0));
|
||||
const staticCallData = staticCallTarget.isOddNumber(new BigNumber(0)).getABIEncodedTransactionData();
|
||||
const trueAsBuffer = ethUtil.toBuffer('0x0000000000000000000000000000000000000000000000000000000000000001');
|
||||
const expectedResultHash = ethUtil.bufferToHex(ethUtil.sha3(trueAsBuffer));
|
||||
const assetData = await devUtils.encodeStaticCallAssetData.callAsync(
|
||||
staticCallTarget.address,
|
||||
staticCallData,
|
||||
expectedResultHash,
|
||||
);
|
||||
await expectTransactionFailedAsync(
|
||||
staticCallProxy.transferFrom.sendTransactionAsync(assetData, fromAddress, toAddress, amount),
|
||||
RevertReason.UnexpectedStaticCallResult,
|
||||
);
|
||||
const expectedResultHash = ethUtil.bufferToHex(ethUtil.keccak256(trueAsBuffer));
|
||||
const assetData = assetDataInterface
|
||||
.StaticCall(staticCallTarget.address, staticCallData, expectedResultHash)
|
||||
.getABIEncodedTransactionData();
|
||||
return expect(
|
||||
staticCallProxy.transferFrom(assetData, fromAddress, toAddress, amount).awaitTransactionSuccessAsync(),
|
||||
).to.revertWith(RevertReason.UnexpectedStaticCallResult);
|
||||
});
|
||||
it('should be successful if a function call with no inputs and no outputs is successful', async () => {
|
||||
const staticCallData = staticCallTarget.noInputFunction.getABIEncodedTransactionData();
|
||||
const staticCallData = staticCallTarget.noInputFunction().getABIEncodedTransactionData();
|
||||
const expectedResultHash = constants.KECCAK256_NULL;
|
||||
const assetData = await devUtils.encodeStaticCallAssetData.callAsync(
|
||||
staticCallTarget.address,
|
||||
staticCallData,
|
||||
expectedResultHash,
|
||||
);
|
||||
await staticCallProxy.transferFrom.awaitTransactionSuccessAsync(assetData, fromAddress, toAddress, amount);
|
||||
const assetData = assetDataInterface
|
||||
.StaticCall(staticCallTarget.address, staticCallData, expectedResultHash)
|
||||
.getABIEncodedTransactionData();
|
||||
await staticCallProxy
|
||||
.transferFrom(assetData, fromAddress, toAddress, amount)
|
||||
.awaitTransactionSuccessAsync();
|
||||
});
|
||||
it('should be successful if the staticCallTarget is not a contract and no return value is expected', async () => {
|
||||
const staticCallData = '0x0102030405060708';
|
||||
const expectedResultHash = constants.KECCAK256_NULL;
|
||||
const assetData = await devUtils.encodeStaticCallAssetData.callAsync(
|
||||
toAddress,
|
||||
staticCallData,
|
||||
expectedResultHash,
|
||||
);
|
||||
await staticCallProxy.transferFrom.awaitTransactionSuccessAsync(assetData, fromAddress, toAddress, amount);
|
||||
const assetData = assetDataInterface
|
||||
.StaticCall(toAddress, staticCallData, expectedResultHash)
|
||||
.getABIEncodedTransactionData();
|
||||
await staticCallProxy
|
||||
.transferFrom(assetData, fromAddress, toAddress, amount)
|
||||
.awaitTransactionSuccessAsync();
|
||||
});
|
||||
it('should be successful if a function call with one static input returns the correct value', async () => {
|
||||
const staticCallData = staticCallTarget.isOddNumber.getABIEncodedTransactionData(new BigNumber(1));
|
||||
const staticCallData = staticCallTarget.isOddNumber(new BigNumber(1)).getABIEncodedTransactionData();
|
||||
const trueAsBuffer = ethUtil.toBuffer('0x0000000000000000000000000000000000000000000000000000000000000001');
|
||||
const expectedResultHash = ethUtil.bufferToHex(ethUtil.sha3(trueAsBuffer));
|
||||
const assetData = await devUtils.encodeStaticCallAssetData.callAsync(
|
||||
staticCallTarget.address,
|
||||
staticCallData,
|
||||
expectedResultHash,
|
||||
);
|
||||
await staticCallProxy.transferFrom.awaitTransactionSuccessAsync(assetData, fromAddress, toAddress, amount);
|
||||
const expectedResultHash = ethUtil.bufferToHex(ethUtil.keccak256(trueAsBuffer));
|
||||
const assetData = assetDataInterface
|
||||
.StaticCall(staticCallTarget.address, staticCallData, expectedResultHash)
|
||||
.getABIEncodedTransactionData();
|
||||
await staticCallProxy
|
||||
.transferFrom(assetData, fromAddress, toAddress, amount)
|
||||
.awaitTransactionSuccessAsync();
|
||||
});
|
||||
it('should be successful if a function with one dynamic input is successful', async () => {
|
||||
const dynamicInput = '0x0102030405060708';
|
||||
const staticCallData = staticCallTarget.dynamicInputFunction.getABIEncodedTransactionData(dynamicInput);
|
||||
const staticCallData = staticCallTarget.dynamicInputFunction(dynamicInput).getABIEncodedTransactionData();
|
||||
const expectedResultHash = constants.KECCAK256_NULL;
|
||||
const assetData = await devUtils.encodeStaticCallAssetData.callAsync(
|
||||
staticCallTarget.address,
|
||||
staticCallData,
|
||||
expectedResultHash,
|
||||
);
|
||||
await staticCallProxy.transferFrom.awaitTransactionSuccessAsync(assetData, fromAddress, toAddress, amount);
|
||||
const assetData = assetDataInterface
|
||||
.StaticCall(staticCallTarget.address, staticCallData, expectedResultHash)
|
||||
.getABIEncodedTransactionData();
|
||||
await staticCallProxy
|
||||
.transferFrom(assetData, fromAddress, toAddress, amount)
|
||||
.awaitTransactionSuccessAsync();
|
||||
});
|
||||
it('should be successful if a function call returns a complex type', async () => {
|
||||
const a = new BigNumber(1);
|
||||
const b = new BigNumber(2);
|
||||
const staticCallData = staticCallTarget.returnComplexType.getABIEncodedTransactionData(a, b);
|
||||
const staticCallData = staticCallTarget.returnComplexType(a, b).getABIEncodedTransactionData();
|
||||
const abiEncoder = new AbiEncoder.DynamicBytes({
|
||||
name: '',
|
||||
type: 'bytes',
|
||||
@@ -243,14 +232,14 @@ describe('StaticCallProxy', () => {
|
||||
const offset = '0000000000000000000000000000000000000000000000000000000000000020';
|
||||
const encodedExpectedResultWithOffset = `0x${offset}${abiEncoder.encode(expectedResults).slice(2)}`;
|
||||
const expectedResultHash = ethUtil.bufferToHex(
|
||||
ethUtil.sha3(ethUtil.toBuffer(encodedExpectedResultWithOffset)),
|
||||
ethUtil.keccak256(ethUtil.toBuffer(encodedExpectedResultWithOffset)),
|
||||
);
|
||||
const assetData = await devUtils.encodeStaticCallAssetData.callAsync(
|
||||
staticCallTarget.address,
|
||||
staticCallData,
|
||||
expectedResultHash,
|
||||
);
|
||||
await staticCallProxy.transferFrom.awaitTransactionSuccessAsync(assetData, fromAddress, toAddress, amount);
|
||||
const assetData = assetDataInterface
|
||||
.StaticCall(staticCallTarget.address, staticCallData, expectedResultHash)
|
||||
.getABIEncodedTransactionData();
|
||||
await staticCallProxy
|
||||
.transferFrom(assetData, fromAddress, toAddress, amount)
|
||||
.awaitTransactionSuccessAsync();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5,19 +5,17 @@ import {
|
||||
filterLogs,
|
||||
filterLogsToArguments,
|
||||
getRandomInteger,
|
||||
hexLeftPad,
|
||||
hexRandom,
|
||||
Numberish,
|
||||
randomAddress,
|
||||
TransactionHelper,
|
||||
} from '@0x/contracts-test-utils';
|
||||
import { AssetProxyId } from '@0x/types';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import { BigNumber, hexUtils } from '@0x/utils';
|
||||
import { DecodedLogs } from 'ethereum-types';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { artifacts } from './artifacts';
|
||||
|
||||
import {
|
||||
artifacts,
|
||||
TestUniswapBridgeContract,
|
||||
TestUniswapBridgeEthToTokenTransferInputEventArgs as EthToTokenTransferInputArgs,
|
||||
TestUniswapBridgeEvents as ContractEvents,
|
||||
@@ -27,10 +25,9 @@ import {
|
||||
TestUniswapBridgeTokenTransferEventArgs as TokenTransferArgs,
|
||||
TestUniswapBridgeWethDepositEventArgs as WethDepositArgs,
|
||||
TestUniswapBridgeWethWithdrawEventArgs as WethWithdrawArgs,
|
||||
} from '../src';
|
||||
} from './wrappers';
|
||||
|
||||
blockchainTests.resets('UniswapBridge unit tests', env => {
|
||||
const txHelper = new TransactionHelper(env.web3Wrapper, artifacts);
|
||||
let testContract: TestUniswapBridgeContract;
|
||||
let wethTokenAddress: string;
|
||||
|
||||
@@ -41,13 +38,15 @@ blockchainTests.resets('UniswapBridge unit tests', env => {
|
||||
env.txDefaults,
|
||||
artifacts,
|
||||
);
|
||||
wethTokenAddress = await testContract.wethToken.callAsync();
|
||||
wethTokenAddress = await testContract.wethToken().callAsync();
|
||||
});
|
||||
|
||||
describe('isValidSignature()', () => {
|
||||
it('returns success bytes', async () => {
|
||||
const LEGACY_WALLET_MAGIC_VALUE = '0xb0671381';
|
||||
const result = await testContract.isValidSignature.callAsync(hexRandom(), hexRandom(_.random(0, 32)));
|
||||
const result = await testContract
|
||||
.isValidSignature(hexUtils.random(), hexUtils.random(_.random(0, 32)))
|
||||
.callAsync();
|
||||
expect(result).to.eq(LEGACY_WALLET_MAGIC_VALUE);
|
||||
});
|
||||
});
|
||||
@@ -89,35 +88,35 @@ blockchainTests.resets('UniswapBridge unit tests', env => {
|
||||
|
||||
async function withdrawToAsync(opts?: Partial<WithdrawToOpts>): Promise<WithdrawToResult> {
|
||||
const _opts = createWithdrawToOpts(opts);
|
||||
const callData = { value: new BigNumber(_opts.exchangeFillAmount) };
|
||||
// Create the "from" token and exchange.
|
||||
[[_opts.fromTokenAddress]] = await txHelper.getResultAndReceiptAsync(
|
||||
testContract.createTokenAndExchange,
|
||||
const createFromTokenFn = testContract.createTokenAndExchange(
|
||||
_opts.fromTokenAddress,
|
||||
_opts.exchangeRevertReason,
|
||||
{ value: new BigNumber(_opts.exchangeFillAmount) },
|
||||
);
|
||||
[_opts.fromTokenAddress] = await createFromTokenFn.callAsync(callData);
|
||||
await createFromTokenFn.awaitTransactionSuccessAsync(callData);
|
||||
|
||||
// Create the "to" token and exchange.
|
||||
[[_opts.toTokenAddress]] = await txHelper.getResultAndReceiptAsync(
|
||||
testContract.createTokenAndExchange,
|
||||
const createToTokenFn = testContract.createTokenAndExchange(
|
||||
_opts.toTokenAddress,
|
||||
_opts.exchangeRevertReason,
|
||||
{ value: new BigNumber(_opts.exchangeFillAmount) },
|
||||
);
|
||||
await testContract.setTokenRevertReason.awaitTransactionSuccessAsync(
|
||||
_opts.toTokenAddress,
|
||||
_opts.toTokenRevertReason,
|
||||
);
|
||||
await testContract.setTokenRevertReason.awaitTransactionSuccessAsync(
|
||||
_opts.fromTokenAddress,
|
||||
_opts.fromTokenRevertReason,
|
||||
);
|
||||
[_opts.toTokenAddress] = await createToTokenFn.callAsync(callData);
|
||||
await createToTokenFn.awaitTransactionSuccessAsync(callData);
|
||||
|
||||
await testContract
|
||||
.setTokenRevertReason(_opts.toTokenAddress, _opts.toTokenRevertReason)
|
||||
.awaitTransactionSuccessAsync();
|
||||
await testContract
|
||||
.setTokenRevertReason(_opts.fromTokenAddress, _opts.fromTokenRevertReason)
|
||||
.awaitTransactionSuccessAsync();
|
||||
// Set the token balance for the token we're converting from.
|
||||
await testContract.setTokenBalance.awaitTransactionSuccessAsync(_opts.fromTokenAddress, {
|
||||
await testContract.setTokenBalance(_opts.fromTokenAddress).awaitTransactionSuccessAsync({
|
||||
value: new BigNumber(_opts.fromTokenBalance),
|
||||
});
|
||||
// Call bridgeTransferFrom().
|
||||
const [result, receipt] = await txHelper.getResultAndReceiptAsync(
|
||||
testContract.bridgeTransferFrom,
|
||||
const bridgeTransferFromFn = testContract.bridgeTransferFrom(
|
||||
// The "to" token address.
|
||||
_opts.toTokenAddress,
|
||||
// The "from" address.
|
||||
@@ -127,8 +126,10 @@ blockchainTests.resets('UniswapBridge unit tests', env => {
|
||||
// The amount to transfer to "to"
|
||||
new BigNumber(_opts.amount),
|
||||
// ABI-encoded "from" token address.
|
||||
hexLeftPad(_opts.fromTokenAddress),
|
||||
hexUtils.leftPad(_opts.fromTokenAddress),
|
||||
);
|
||||
const result = await bridgeTransferFromFn.callAsync();
|
||||
const receipt = await bridgeTransferFromFn.awaitTransactionSuccessAsync();
|
||||
return {
|
||||
opts: _opts,
|
||||
result,
|
||||
@@ -138,7 +139,7 @@ blockchainTests.resets('UniswapBridge unit tests', env => {
|
||||
}
|
||||
|
||||
async function getExchangeForTokenAsync(tokenAddress: string): Promise<string> {
|
||||
return testContract.getExchange.callAsync(tokenAddress);
|
||||
return testContract.getExchange(tokenAddress).callAsync();
|
||||
}
|
||||
|
||||
it('returns magic bytes on success', async () => {
|
||||
@@ -147,11 +148,9 @@ blockchainTests.resets('UniswapBridge unit tests', env => {
|
||||
});
|
||||
|
||||
it('just transfers tokens to `to` if the same tokens are in play', async () => {
|
||||
const [[tokenAddress]] = await txHelper.getResultAndReceiptAsync(
|
||||
testContract.createTokenAndExchange,
|
||||
constants.NULL_ADDRESS,
|
||||
'',
|
||||
);
|
||||
const createTokenFn = await testContract.createTokenAndExchange(constants.NULL_ADDRESS, '');
|
||||
const [tokenAddress] = await createTokenFn.callAsync();
|
||||
await createTokenFn.awaitTransactionSuccessAsync();
|
||||
const { opts, result, logs } = await withdrawToAsync({
|
||||
fromTokenAddress: tokenAddress,
|
||||
toTokenAddress: tokenAddress,
|
||||
@@ -177,7 +176,7 @@ blockchainTests.resets('UniswapBridge unit tests', env => {
|
||||
expect(calls[0].exchange).to.eq(exchangeAddress);
|
||||
expect(calls[0].tokensSold).to.bignumber.eq(opts.fromTokenBalance);
|
||||
expect(calls[0].minTokensBought).to.bignumber.eq(opts.amount);
|
||||
expect(calls[0].minEthBought).to.bignumber.eq(0);
|
||||
expect(calls[0].minEthBought).to.bignumber.eq(1);
|
||||
expect(calls[0].deadline).to.bignumber.eq(blockTime);
|
||||
expect(calls[0].recipient).to.eq(opts.toAddress);
|
||||
expect(calls[0].toTokenAddress).to.eq(opts.toTokenAddress);
|
||||
@@ -203,14 +202,16 @@ blockchainTests.resets('UniswapBridge unit tests', env => {
|
||||
});
|
||||
|
||||
it('fails if "from" token does not exist', async () => {
|
||||
const tx = testContract.bridgeTransferFrom.awaitTransactionSuccessAsync(
|
||||
randomAddress(),
|
||||
randomAddress(),
|
||||
randomAddress(),
|
||||
getRandomInteger(1, 1e18),
|
||||
hexLeftPad(randomAddress()),
|
||||
);
|
||||
return expect(tx).to.revertWith('NO_UNISWAP_EXCHANGE_FOR_TOKEN');
|
||||
const tx = testContract
|
||||
.bridgeTransferFrom(
|
||||
randomAddress(),
|
||||
randomAddress(),
|
||||
randomAddress(),
|
||||
getRandomInteger(1, 1e18),
|
||||
hexUtils.leftPad(randomAddress()),
|
||||
)
|
||||
.awaitTransactionSuccessAsync();
|
||||
return expect(tx).to.eventually.be.rejectedWith('NO_UNISWAP_EXCHANGE_FOR_TOKEN');
|
||||
});
|
||||
|
||||
it('fails if the exchange fails', async () => {
|
||||
@@ -218,7 +219,7 @@ blockchainTests.resets('UniswapBridge unit tests', env => {
|
||||
const tx = withdrawToAsync({
|
||||
exchangeRevertReason: revertReason,
|
||||
});
|
||||
return expect(tx).to.revertWith(revertReason);
|
||||
return expect(tx).to.eventually.be.rejectedWith(revertReason);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -275,14 +276,16 @@ blockchainTests.resets('UniswapBridge unit tests', env => {
|
||||
});
|
||||
|
||||
it('fails if "from" token does not exist', async () => {
|
||||
const tx = testContract.bridgeTransferFrom.awaitTransactionSuccessAsync(
|
||||
randomAddress(),
|
||||
randomAddress(),
|
||||
randomAddress(),
|
||||
getRandomInteger(1, 1e18),
|
||||
hexLeftPad(wethTokenAddress),
|
||||
);
|
||||
return expect(tx).to.revertWith('NO_UNISWAP_EXCHANGE_FOR_TOKEN');
|
||||
const tx = testContract
|
||||
.bridgeTransferFrom(
|
||||
randomAddress(),
|
||||
randomAddress(),
|
||||
randomAddress(),
|
||||
getRandomInteger(1, 1e18),
|
||||
hexUtils.leftPad(wethTokenAddress),
|
||||
)
|
||||
.awaitTransactionSuccessAsync();
|
||||
return expect(tx).to.eventually.be.rejectedWith('NO_UNISWAP_EXCHANGE_FOR_TOKEN');
|
||||
});
|
||||
|
||||
it('fails if `WETH.deposit()` fails', async () => {
|
||||
@@ -291,7 +294,7 @@ blockchainTests.resets('UniswapBridge unit tests', env => {
|
||||
toTokenAddress: wethTokenAddress,
|
||||
toTokenRevertReason: revertReason,
|
||||
});
|
||||
return expect(tx).to.revertWith(revertReason);
|
||||
return expect(tx).to.eventually.be.rejectedWith(revertReason);
|
||||
});
|
||||
|
||||
it('fails if the exchange fails', async () => {
|
||||
@@ -300,7 +303,7 @@ blockchainTests.resets('UniswapBridge unit tests', env => {
|
||||
toTokenAddress: wethTokenAddress,
|
||||
exchangeRevertReason: revertReason,
|
||||
});
|
||||
return expect(tx).to.revertWith(revertReason);
|
||||
return expect(tx).to.eventually.be.rejectedWith(revertReason);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -333,14 +336,16 @@ blockchainTests.resets('UniswapBridge unit tests', env => {
|
||||
});
|
||||
|
||||
it('fails if "to" token does not exist', async () => {
|
||||
const tx = testContract.bridgeTransferFrom.awaitTransactionSuccessAsync(
|
||||
wethTokenAddress,
|
||||
randomAddress(),
|
||||
randomAddress(),
|
||||
getRandomInteger(1, 1e18),
|
||||
hexLeftPad(randomAddress()),
|
||||
);
|
||||
return expect(tx).to.revertWith('NO_UNISWAP_EXCHANGE_FOR_TOKEN');
|
||||
const tx = testContract
|
||||
.bridgeTransferFrom(
|
||||
wethTokenAddress,
|
||||
randomAddress(),
|
||||
randomAddress(),
|
||||
getRandomInteger(1, 1e18),
|
||||
hexUtils.leftPad(randomAddress()),
|
||||
)
|
||||
.awaitTransactionSuccessAsync();
|
||||
return expect(tx).to.eventually.be.rejectedWith('NO_UNISWAP_EXCHANGE_FOR_TOKEN');
|
||||
});
|
||||
|
||||
it('fails if the `WETH.withdraw()` fails', async () => {
|
||||
@@ -349,7 +354,7 @@ blockchainTests.resets('UniswapBridge unit tests', env => {
|
||||
fromTokenAddress: wethTokenAddress,
|
||||
fromTokenRevertReason: revertReason,
|
||||
});
|
||||
return expect(tx).to.revertWith(revertReason);
|
||||
return expect(tx).to.eventually.be.rejectedWith(revertReason);
|
||||
});
|
||||
|
||||
it('fails if the exchange fails', async () => {
|
||||
@@ -358,7 +363,7 @@ blockchainTests.resets('UniswapBridge unit tests', env => {
|
||||
fromTokenAddress: wethTokenAddress,
|
||||
exchangeRevertReason: revertReason,
|
||||
});
|
||||
return expect(tx).to.revertWith(revertReason);
|
||||
return expect(tx).to.eventually.be.rejectedWith(revertReason);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
216
contracts/asset-proxy/test/uniswapv2_bridge.ts
Normal file
216
contracts/asset-proxy/test/uniswapv2_bridge.ts
Normal file
@@ -0,0 +1,216 @@
|
||||
import {
|
||||
blockchainTests,
|
||||
constants,
|
||||
expect,
|
||||
filterLogsToArguments,
|
||||
getRandomInteger,
|
||||
randomAddress,
|
||||
} from '@0x/contracts-test-utils';
|
||||
import { AssetProxyId } from '@0x/types';
|
||||
import { AbiEncoder, BigNumber, hexUtils } from '@0x/utils';
|
||||
import { DecodedLogs } from 'ethereum-types';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { artifacts } from './artifacts';
|
||||
|
||||
import {
|
||||
TestUniswapV2BridgeContract,
|
||||
TestUniswapV2BridgeEvents as ContractEvents,
|
||||
TestUniswapV2BridgeSwapExactTokensForTokensInputEventArgs as SwapExactTokensForTokensArgs,
|
||||
TestUniswapV2BridgeTokenApproveEventArgs as TokenApproveArgs,
|
||||
TestUniswapV2BridgeTokenTransferEventArgs as TokenTransferArgs,
|
||||
} from './wrappers';
|
||||
|
||||
blockchainTests.resets('UniswapV2 unit tests', env => {
|
||||
const FROM_TOKEN_DECIMALS = 6;
|
||||
const TO_TOKEN_DECIMALS = 18;
|
||||
const FROM_TOKEN_BASE = new BigNumber(10).pow(FROM_TOKEN_DECIMALS);
|
||||
const TO_TOKEN_BASE = new BigNumber(10).pow(TO_TOKEN_DECIMALS);
|
||||
let testContract: TestUniswapV2BridgeContract;
|
||||
|
||||
before(async () => {
|
||||
testContract = await TestUniswapV2BridgeContract.deployFrom0xArtifactAsync(
|
||||
artifacts.TestUniswapV2Bridge,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
artifacts,
|
||||
);
|
||||
});
|
||||
|
||||
describe('isValidSignature()', () => {
|
||||
it('returns success bytes', async () => {
|
||||
const LEGACY_WALLET_MAGIC_VALUE = '0xb0671381';
|
||||
const result = await testContract
|
||||
.isValidSignature(hexUtils.random(), hexUtils.random(_.random(0, 32)))
|
||||
.callAsync();
|
||||
expect(result).to.eq(LEGACY_WALLET_MAGIC_VALUE);
|
||||
});
|
||||
});
|
||||
|
||||
describe('bridgeTransferFrom()', () => {
|
||||
interface TransferFromOpts {
|
||||
tokenAddressesPath: string[];
|
||||
toAddress: string;
|
||||
// Amount to pass into `bridgeTransferFrom()`
|
||||
amount: BigNumber;
|
||||
// Token balance of the bridge.
|
||||
fromTokenBalance: BigNumber;
|
||||
// Router reverts with this reason
|
||||
routerRevertReason: string;
|
||||
}
|
||||
|
||||
interface TransferFromResult {
|
||||
opts: TransferFromOpts;
|
||||
result: string;
|
||||
logs: DecodedLogs;
|
||||
blocktime: number;
|
||||
}
|
||||
|
||||
function createTransferFromOpts(opts?: Partial<TransferFromOpts>): TransferFromOpts {
|
||||
const amount = getRandomInteger(1, TO_TOKEN_BASE.times(100));
|
||||
return {
|
||||
tokenAddressesPath: Array(2).fill(constants.NULL_ADDRESS),
|
||||
amount,
|
||||
toAddress: randomAddress(),
|
||||
fromTokenBalance: getRandomInteger(1, FROM_TOKEN_BASE.times(100)),
|
||||
routerRevertReason: '',
|
||||
...opts,
|
||||
};
|
||||
}
|
||||
|
||||
const bridgeDataEncoder = AbiEncoder.create('(address[])');
|
||||
|
||||
async function transferFromAsync(opts?: Partial<TransferFromOpts>): Promise<TransferFromResult> {
|
||||
const _opts = createTransferFromOpts(opts);
|
||||
|
||||
for (let i = 0; i < _opts.tokenAddressesPath.length; i++) {
|
||||
const createFromTokenFn = testContract.createToken(_opts.tokenAddressesPath[i]);
|
||||
_opts.tokenAddressesPath[i] = await createFromTokenFn.callAsync();
|
||||
await createFromTokenFn.awaitTransactionSuccessAsync();
|
||||
}
|
||||
|
||||
// Set the token balance for the token we're converting from.
|
||||
await testContract
|
||||
.setTokenBalance(_opts.tokenAddressesPath[0], _opts.fromTokenBalance)
|
||||
.awaitTransactionSuccessAsync();
|
||||
|
||||
// Set revert reason for the router.
|
||||
await testContract.setRouterRevertReason(_opts.routerRevertReason).awaitTransactionSuccessAsync();
|
||||
|
||||
// Call bridgeTransferFrom().
|
||||
const bridgeTransferFromFn = testContract.bridgeTransferFrom(
|
||||
// Output token
|
||||
_opts.tokenAddressesPath[_opts.tokenAddressesPath.length - 1],
|
||||
// Random maker address.
|
||||
randomAddress(),
|
||||
// Recipient address.
|
||||
_opts.toAddress,
|
||||
// Transfer amount.
|
||||
_opts.amount,
|
||||
// ABI-encode the input token address as the bridge data. // FIXME
|
||||
bridgeDataEncoder.encode([_opts.tokenAddressesPath]),
|
||||
);
|
||||
const result = await bridgeTransferFromFn.callAsync();
|
||||
const receipt = await bridgeTransferFromFn.awaitTransactionSuccessAsync();
|
||||
return {
|
||||
opts: _opts,
|
||||
result,
|
||||
logs: (receipt.logs as any) as DecodedLogs,
|
||||
blocktime: await env.web3Wrapper.getBlockTimestampAsync(receipt.blockNumber),
|
||||
};
|
||||
}
|
||||
|
||||
it('returns magic bytes on success', async () => {
|
||||
const { result } = await transferFromAsync();
|
||||
expect(result).to.eq(AssetProxyId.ERC20Bridge);
|
||||
});
|
||||
|
||||
it('performs transfer when both tokens are the same', async () => {
|
||||
const createTokenFn = testContract.createToken(constants.NULL_ADDRESS);
|
||||
const tokenAddress = await createTokenFn.callAsync();
|
||||
await createTokenFn.awaitTransactionSuccessAsync();
|
||||
|
||||
const { opts, result, logs } = await transferFromAsync({
|
||||
tokenAddressesPath: [tokenAddress, tokenAddress],
|
||||
});
|
||||
expect(result).to.eq(AssetProxyId.ERC20Bridge, 'asset proxy id');
|
||||
const transfers = filterLogsToArguments<TokenTransferArgs>(logs, ContractEvents.TokenTransfer);
|
||||
|
||||
expect(transfers.length).to.eq(1);
|
||||
expect(transfers[0].token).to.eq(tokenAddress, 'input token address');
|
||||
expect(transfers[0].from).to.eq(testContract.address);
|
||||
expect(transfers[0].to).to.eq(opts.toAddress, 'recipient address');
|
||||
expect(transfers[0].amount).to.bignumber.eq(opts.amount, 'amount');
|
||||
});
|
||||
|
||||
describe('token -> token', async () => {
|
||||
it('calls UniswapV2Router01.swapExactTokensForTokens()', async () => {
|
||||
const { opts, result, logs, blocktime } = await transferFromAsync();
|
||||
expect(result).to.eq(AssetProxyId.ERC20Bridge, 'asset proxy id');
|
||||
const transfers = filterLogsToArguments<SwapExactTokensForTokensArgs>(
|
||||
logs,
|
||||
ContractEvents.SwapExactTokensForTokensInput,
|
||||
);
|
||||
|
||||
expect(transfers.length).to.eq(1);
|
||||
expect(transfers[0].toTokenAddress).to.eq(
|
||||
opts.tokenAddressesPath[opts.tokenAddressesPath.length - 1],
|
||||
'output token address',
|
||||
);
|
||||
expect(transfers[0].to).to.eq(opts.toAddress, 'recipient address');
|
||||
expect(transfers[0].amountIn).to.bignumber.eq(opts.fromTokenBalance, 'input token amount');
|
||||
expect(transfers[0].amountOutMin).to.bignumber.eq(opts.amount, 'output token amount');
|
||||
expect(transfers[0].deadline).to.bignumber.eq(blocktime, 'deadline');
|
||||
});
|
||||
|
||||
it('sets allowance for "from" token', async () => {
|
||||
const { logs } = await transferFromAsync();
|
||||
const approvals = filterLogsToArguments<TokenApproveArgs>(logs, ContractEvents.TokenApprove);
|
||||
const routerAddress = await testContract.getRouterAddress().callAsync();
|
||||
expect(approvals.length).to.eq(1);
|
||||
expect(approvals[0].spender).to.eq(routerAddress);
|
||||
expect(approvals[0].allowance).to.bignumber.eq(constants.MAX_UINT256);
|
||||
});
|
||||
|
||||
it('sets allowance for "from" token on subsequent calls', async () => {
|
||||
const { opts } = await transferFromAsync();
|
||||
const { logs } = await transferFromAsync(opts);
|
||||
const approvals = filterLogsToArguments<TokenApproveArgs>(logs, ContractEvents.TokenApprove);
|
||||
const routerAddress = await testContract.getRouterAddress().callAsync();
|
||||
expect(approvals.length).to.eq(1);
|
||||
expect(approvals[0].spender).to.eq(routerAddress);
|
||||
expect(approvals[0].allowance).to.bignumber.eq(constants.MAX_UINT256);
|
||||
});
|
||||
|
||||
it('fails if the router fails', async () => {
|
||||
const revertReason = 'FOOBAR';
|
||||
const tx = transferFromAsync({
|
||||
routerRevertReason: revertReason,
|
||||
});
|
||||
return expect(tx).to.eventually.be.rejectedWith(revertReason);
|
||||
});
|
||||
});
|
||||
describe('token -> token -> token', async () => {
|
||||
it('calls UniswapV2Router01.swapExactTokensForTokens()', async () => {
|
||||
const { opts, result, logs, blocktime } = await transferFromAsync({
|
||||
tokenAddressesPath: Array(3).fill(constants.NULL_ADDRESS),
|
||||
});
|
||||
expect(result).to.eq(AssetProxyId.ERC20Bridge, 'asset proxy id');
|
||||
const transfers = filterLogsToArguments<SwapExactTokensForTokensArgs>(
|
||||
logs,
|
||||
ContractEvents.SwapExactTokensForTokensInput,
|
||||
);
|
||||
|
||||
expect(transfers.length).to.eq(1);
|
||||
expect(transfers[0].toTokenAddress).to.eq(
|
||||
opts.tokenAddressesPath[opts.tokenAddressesPath.length - 1],
|
||||
'output token address',
|
||||
);
|
||||
expect(transfers[0].to).to.eq(opts.toAddress, 'recipient address');
|
||||
expect(transfers[0].amountIn).to.bignumber.eq(opts.fromTokenBalance, 'input token amount');
|
||||
expect(transfers[0].amountOutMin).to.bignumber.eq(opts.amount, 'output token amount');
|
||||
expect(transfers[0].deadline).to.bignumber.eq(blocktime, 'deadline');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,3 +0,0 @@
|
||||
export * from './erc20_wrapper';
|
||||
export * from './erc721_wrapper';
|
||||
export * from './erc1155_proxy_wrapper';
|
||||
64
contracts/asset-proxy/test/wrappers.ts
Normal file
64
contracts/asset-proxy/test/wrappers.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* -----------------------------------------------------------------------------
|
||||
* Warning: This file is auto-generated by contracts-gen. Don't edit manually.
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
export * from '../test/generated-wrappers/balancer_bridge';
|
||||
export * from '../test/generated-wrappers/bancor_bridge';
|
||||
export * from '../test/generated-wrappers/chai_bridge';
|
||||
export * from '../test/generated-wrappers/cream_bridge';
|
||||
export * from '../test/generated-wrappers/crypto_com_bridge';
|
||||
export * from '../test/generated-wrappers/curve_bridge';
|
||||
export * from '../test/generated-wrappers/d_o_d_o_bridge';
|
||||
export * from '../test/generated-wrappers/dex_forwarder_bridge';
|
||||
export * from '../test/generated-wrappers/dydx_bridge';
|
||||
export * from '../test/generated-wrappers/erc1155_proxy';
|
||||
export * from '../test/generated-wrappers/erc20_bridge_proxy';
|
||||
export * from '../test/generated-wrappers/erc20_proxy';
|
||||
export * from '../test/generated-wrappers/erc721_proxy';
|
||||
export * from '../test/generated-wrappers/eth2_dai_bridge';
|
||||
export * from '../test/generated-wrappers/i_asset_data';
|
||||
export * from '../test/generated-wrappers/i_asset_proxy';
|
||||
export * from '../test/generated-wrappers/i_asset_proxy_dispatcher';
|
||||
export * from '../test/generated-wrappers/i_authorizable';
|
||||
export * from '../test/generated-wrappers/i_balancer_pool';
|
||||
export * from '../test/generated-wrappers/i_bancor_network';
|
||||
export * from '../test/generated-wrappers/i_chai';
|
||||
export * from '../test/generated-wrappers/i_curve';
|
||||
export * from '../test/generated-wrappers/i_dydx';
|
||||
export * from '../test/generated-wrappers/i_dydx_bridge';
|
||||
export * from '../test/generated-wrappers/i_erc20_bridge';
|
||||
export * from '../test/generated-wrappers/i_eth2_dai';
|
||||
export * from '../test/generated-wrappers/i_gas_token';
|
||||
export * from '../test/generated-wrappers/i_kyber_network_proxy';
|
||||
export * from '../test/generated-wrappers/i_m_stable';
|
||||
export * from '../test/generated-wrappers/i_mooniswap';
|
||||
export * from '../test/generated-wrappers/i_shell';
|
||||
export * from '../test/generated-wrappers/i_uniswap_exchange';
|
||||
export * from '../test/generated-wrappers/i_uniswap_exchange_factory';
|
||||
export * from '../test/generated-wrappers/i_uniswap_v2_router01';
|
||||
export * from '../test/generated-wrappers/kyber_bridge';
|
||||
export * from '../test/generated-wrappers/m_stable_bridge';
|
||||
export * from '../test/generated-wrappers/mixin_asset_proxy_dispatcher';
|
||||
export * from '../test/generated-wrappers/mixin_authorizable';
|
||||
export * from '../test/generated-wrappers/mixin_gas_token';
|
||||
export * from '../test/generated-wrappers/mooniswap_bridge';
|
||||
export * from '../test/generated-wrappers/multi_asset_proxy';
|
||||
export * from '../test/generated-wrappers/ownable';
|
||||
export * from '../test/generated-wrappers/shell_bridge';
|
||||
export * from '../test/generated-wrappers/snow_swap_bridge';
|
||||
export * from '../test/generated-wrappers/static_call_proxy';
|
||||
export * from '../test/generated-wrappers/sushi_swap_bridge';
|
||||
export * from '../test/generated-wrappers/swerve_bridge';
|
||||
export * from '../test/generated-wrappers/test_bancor_bridge';
|
||||
export * from '../test/generated-wrappers/test_chai_bridge';
|
||||
export * from '../test/generated-wrappers/test_dex_forwarder_bridge';
|
||||
export * from '../test/generated-wrappers/test_dydx_bridge';
|
||||
export * from '../test/generated-wrappers/test_erc20_bridge';
|
||||
export * from '../test/generated-wrappers/test_eth2_dai_bridge';
|
||||
export * from '../test/generated-wrappers/test_kyber_bridge';
|
||||
export * from '../test/generated-wrappers/test_static_call_target';
|
||||
export * from '../test/generated-wrappers/test_uniswap_bridge';
|
||||
export * from '../test/generated-wrappers/test_uniswap_v2_bridge';
|
||||
export * from '../test/generated-wrappers/uniswap_bridge';
|
||||
export * from '../test/generated-wrappers/uniswap_v2_bridge';
|
||||
@@ -84,7 +84,7 @@ module.exports = {
|
||||
solc: {
|
||||
version: '0.5.9',
|
||||
settings: {
|
||||
evmVersion: 'constantinople',
|
||||
evmVersion: 'istanbul',
|
||||
optimizer: {
|
||||
enabled: true,
|
||||
runs: 1000000,
|
||||
|
||||
@@ -3,6 +3,15 @@
|
||||
"compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true },
|
||||
"include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
|
||||
"files": [
|
||||
"generated-artifacts/BalancerBridge.json",
|
||||
"generated-artifacts/BancorBridge.json",
|
||||
"generated-artifacts/ChaiBridge.json",
|
||||
"generated-artifacts/CreamBridge.json",
|
||||
"generated-artifacts/CryptoComBridge.json",
|
||||
"generated-artifacts/CurveBridge.json",
|
||||
"generated-artifacts/DODOBridge.json",
|
||||
"generated-artifacts/DexForwarderBridge.json",
|
||||
"generated-artifacts/DydxBridge.json",
|
||||
"generated-artifacts/ERC1155Proxy.json",
|
||||
"generated-artifacts/ERC20BridgeProxy.json",
|
||||
"generated-artifacts/ERC20Proxy.json",
|
||||
@@ -12,20 +21,106 @@
|
||||
"generated-artifacts/IAssetProxy.json",
|
||||
"generated-artifacts/IAssetProxyDispatcher.json",
|
||||
"generated-artifacts/IAuthorizable.json",
|
||||
"generated-artifacts/IBalancerPool.json",
|
||||
"generated-artifacts/IBancorNetwork.json",
|
||||
"generated-artifacts/IChai.json",
|
||||
"generated-artifacts/ICurve.json",
|
||||
"generated-artifacts/IDydx.json",
|
||||
"generated-artifacts/IDydxBridge.json",
|
||||
"generated-artifacts/IERC20Bridge.json",
|
||||
"generated-artifacts/IEth2Dai.json",
|
||||
"generated-artifacts/IGasToken.json",
|
||||
"generated-artifacts/IKyberNetworkProxy.json",
|
||||
"generated-artifacts/IMStable.json",
|
||||
"generated-artifacts/IMooniswap.json",
|
||||
"generated-artifacts/IShell.json",
|
||||
"generated-artifacts/IUniswapExchange.json",
|
||||
"generated-artifacts/IUniswapExchangeFactory.json",
|
||||
"generated-artifacts/IUniswapV2Router01.json",
|
||||
"generated-artifacts/KyberBridge.json",
|
||||
"generated-artifacts/MStableBridge.json",
|
||||
"generated-artifacts/MixinAssetProxyDispatcher.json",
|
||||
"generated-artifacts/MixinAuthorizable.json",
|
||||
"generated-artifacts/MixinGasToken.json",
|
||||
"generated-artifacts/MooniswapBridge.json",
|
||||
"generated-artifacts/MultiAssetProxy.json",
|
||||
"generated-artifacts/Ownable.json",
|
||||
"generated-artifacts/ShellBridge.json",
|
||||
"generated-artifacts/SnowSwapBridge.json",
|
||||
"generated-artifacts/StaticCallProxy.json",
|
||||
"generated-artifacts/SushiSwapBridge.json",
|
||||
"generated-artifacts/SwerveBridge.json",
|
||||
"generated-artifacts/TestBancorBridge.json",
|
||||
"generated-artifacts/TestChaiBridge.json",
|
||||
"generated-artifacts/TestDexForwarderBridge.json",
|
||||
"generated-artifacts/TestDydxBridge.json",
|
||||
"generated-artifacts/TestERC20Bridge.json",
|
||||
"generated-artifacts/TestEth2DaiBridge.json",
|
||||
"generated-artifacts/TestKyberBridge.json",
|
||||
"generated-artifacts/TestStaticCallTarget.json",
|
||||
"generated-artifacts/TestUniswapBridge.json",
|
||||
"generated-artifacts/UniswapBridge.json"
|
||||
"generated-artifacts/TestUniswapV2Bridge.json",
|
||||
"generated-artifacts/UniswapBridge.json",
|
||||
"generated-artifacts/UniswapV2Bridge.json",
|
||||
"test/generated-artifacts/BalancerBridge.json",
|
||||
"test/generated-artifacts/BancorBridge.json",
|
||||
"test/generated-artifacts/ChaiBridge.json",
|
||||
"test/generated-artifacts/CreamBridge.json",
|
||||
"test/generated-artifacts/CryptoComBridge.json",
|
||||
"test/generated-artifacts/CurveBridge.json",
|
||||
"test/generated-artifacts/DODOBridge.json",
|
||||
"test/generated-artifacts/DexForwarderBridge.json",
|
||||
"test/generated-artifacts/DydxBridge.json",
|
||||
"test/generated-artifacts/ERC1155Proxy.json",
|
||||
"test/generated-artifacts/ERC20BridgeProxy.json",
|
||||
"test/generated-artifacts/ERC20Proxy.json",
|
||||
"test/generated-artifacts/ERC721Proxy.json",
|
||||
"test/generated-artifacts/Eth2DaiBridge.json",
|
||||
"test/generated-artifacts/IAssetData.json",
|
||||
"test/generated-artifacts/IAssetProxy.json",
|
||||
"test/generated-artifacts/IAssetProxyDispatcher.json",
|
||||
"test/generated-artifacts/IAuthorizable.json",
|
||||
"test/generated-artifacts/IBalancerPool.json",
|
||||
"test/generated-artifacts/IBancorNetwork.json",
|
||||
"test/generated-artifacts/IChai.json",
|
||||
"test/generated-artifacts/ICurve.json",
|
||||
"test/generated-artifacts/IDydx.json",
|
||||
"test/generated-artifacts/IDydxBridge.json",
|
||||
"test/generated-artifacts/IERC20Bridge.json",
|
||||
"test/generated-artifacts/IEth2Dai.json",
|
||||
"test/generated-artifacts/IGasToken.json",
|
||||
"test/generated-artifacts/IKyberNetworkProxy.json",
|
||||
"test/generated-artifacts/IMStable.json",
|
||||
"test/generated-artifacts/IMooniswap.json",
|
||||
"test/generated-artifacts/IShell.json",
|
||||
"test/generated-artifacts/IUniswapExchange.json",
|
||||
"test/generated-artifacts/IUniswapExchangeFactory.json",
|
||||
"test/generated-artifacts/IUniswapV2Router01.json",
|
||||
"test/generated-artifacts/KyberBridge.json",
|
||||
"test/generated-artifacts/MStableBridge.json",
|
||||
"test/generated-artifacts/MixinAssetProxyDispatcher.json",
|
||||
"test/generated-artifacts/MixinAuthorizable.json",
|
||||
"test/generated-artifacts/MixinGasToken.json",
|
||||
"test/generated-artifacts/MooniswapBridge.json",
|
||||
"test/generated-artifacts/MultiAssetProxy.json",
|
||||
"test/generated-artifacts/Ownable.json",
|
||||
"test/generated-artifacts/ShellBridge.json",
|
||||
"test/generated-artifacts/SnowSwapBridge.json",
|
||||
"test/generated-artifacts/StaticCallProxy.json",
|
||||
"test/generated-artifacts/SushiSwapBridge.json",
|
||||
"test/generated-artifacts/SwerveBridge.json",
|
||||
"test/generated-artifacts/TestBancorBridge.json",
|
||||
"test/generated-artifacts/TestChaiBridge.json",
|
||||
"test/generated-artifacts/TestDexForwarderBridge.json",
|
||||
"test/generated-artifacts/TestDydxBridge.json",
|
||||
"test/generated-artifacts/TestERC20Bridge.json",
|
||||
"test/generated-artifacts/TestEth2DaiBridge.json",
|
||||
"test/generated-artifacts/TestKyberBridge.json",
|
||||
"test/generated-artifacts/TestStaticCallTarget.json",
|
||||
"test/generated-artifacts/TestUniswapBridge.json",
|
||||
"test/generated-artifacts/TestUniswapV2Bridge.json",
|
||||
"test/generated-artifacts/UniswapBridge.json",
|
||||
"test/generated-artifacts/UniswapV2Bridge.json"
|
||||
],
|
||||
"exclude": ["./deploy/solc/solc_bin"]
|
||||
}
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
*
|
||||
# Whitelist lib
|
||||
!lib/**/*
|
||||
# Blacklist tests and publish scripts
|
||||
# Whitelist Solidity contracts
|
||||
!contracts/src/**/*
|
||||
# Blacklist tests in lib
|
||||
/lib/test/*
|
||||
/lib/monorepo_scripts/
|
||||
# Package specific ignore
|
||||
!bin/**/*
|
||||
@@ -1,323 +1,278 @@
|
||||
[
|
||||
{
|
||||
"version": "2.1.0-beta.1",
|
||||
"timestamp": 1619596077,
|
||||
"version": "1.1.28",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1617311315,
|
||||
"version": "1.1.27",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1616005394,
|
||||
"version": "1.1.26",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1614141718,
|
||||
"version": "1.1.25",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1612950500,
|
||||
"version": "1.1.24",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1611648096,
|
||||
"version": "1.1.23",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1610510890,
|
||||
"version": "1.1.22",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1609802516,
|
||||
"version": "1.1.21",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1608692071,
|
||||
"version": "1.1.20",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1608245516,
|
||||
"version": "1.1.19",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1608105788,
|
||||
"version": "1.1.18",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1607485227,
|
||||
"version": "1.1.17",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1607381756,
|
||||
"version": "1.1.16",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1606961263,
|
||||
"version": "1.1.15",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1605763885,
|
||||
"version": "1.1.14",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1605302002,
|
||||
"version": "1.1.13",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1604385937,
|
||||
"version": "1.1.12",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1604376968,
|
||||
"version": "1.1.11",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1604355662,
|
||||
"version": "1.1.10",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1603851023,
|
||||
"version": "1.1.9",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1603833198,
|
||||
"version": "1.1.8",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1603265572,
|
||||
"version": "1.1.7",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1594788383,
|
||||
"version": "1.1.6",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "1.1.5",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Fix broken tests.",
|
||||
"pr": 2591
|
||||
}
|
||||
],
|
||||
"timestamp": 1573159180
|
||||
"timestamp": 1592969527
|
||||
},
|
||||
{
|
||||
"version": "2.1.0-beta.0",
|
||||
"timestamp": 1583220306,
|
||||
"version": "1.1.4",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1582837861,
|
||||
"version": "1.1.3",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1582677073,
|
||||
"version": "1.1.2",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1582623685,
|
||||
"version": "1.1.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "1.1.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Added decoders for broker data",
|
||||
"pr": 2484
|
||||
}
|
||||
],
|
||||
"timestamp": 1570135330
|
||||
},
|
||||
{
|
||||
"timestamp": 1568744790,
|
||||
"version": "2.0.19",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1567521715,
|
||||
"version": "2.0.18",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1566446343,
|
||||
"version": "2.0.17",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1565296576,
|
||||
"version": "2.0.16",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1564604963,
|
||||
"version": "2.0.15",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1563957393,
|
||||
"version": "2.0.14",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "2.0.13",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Confirm devdoc components exist before using them",
|
||||
"pr": 1878
|
||||
}
|
||||
],
|
||||
"timestamp": 1563006338
|
||||
},
|
||||
{
|
||||
"timestamp": 1558712885,
|
||||
"version": "2.0.12",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1557507213,
|
||||
"version": "2.0.11",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "2.0.10",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
],
|
||||
"timestamp": 1554997931
|
||||
},
|
||||
{
|
||||
"timestamp": 1553183790,
|
||||
"version": "2.0.9",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1553091633,
|
||||
"version": "2.0.8",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1551479279,
|
||||
"version": "2.0.7",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1551299797,
|
||||
"version": "2.0.6",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1551220833,
|
||||
"version": "2.0.5",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1551130135,
|
||||
"version": "2.0.4",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1549733923,
|
||||
"version": "2.0.3",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "2.0.2",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
],
|
||||
"timestamp": 1549547375
|
||||
},
|
||||
{
|
||||
"timestamp": 1549452781,
|
||||
"version": "2.0.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Upgrade the bignumber.js to v8.0.2",
|
||||
"pr": 1517
|
||||
}
|
||||
],
|
||||
"timestamp": 1549373905
|
||||
},
|
||||
{
|
||||
"timestamp": 1547561734,
|
||||
"version": "1.0.14",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1547225310,
|
||||
"version": "1.0.13",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1547040760,
|
||||
"version": "1.0.12",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "1.0.11",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
],
|
||||
"timestamp": 1544739608
|
||||
},
|
||||
{
|
||||
"version": "1.0.10",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
],
|
||||
"timestamp": 1544570656
|
||||
},
|
||||
{
|
||||
"timestamp": 1543401373,
|
||||
"version": "1.0.9",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1542821676,
|
||||
"version": "1.0.8",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1542208198,
|
||||
"version": "1.0.7",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1542134075,
|
||||
"version": "1.0.6",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1542028948,
|
||||
"version": "1.0.5",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "1.0.4",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
],
|
||||
"timestamp": 1541740904
|
||||
},
|
||||
{
|
||||
"timestamp": 1539871071,
|
||||
"version": "1.0.3",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
"timestamp": 1581748629
|
||||
},
|
||||
{
|
||||
"timestamp": 1581204851,
|
||||
"version": "1.0.2",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
],
|
||||
"timestamp": 1538693146
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1538157789,
|
||||
"timestamp": 1580988106,
|
||||
"version": "1.0.1",
|
||||
"changes": [
|
||||
{
|
||||
@@ -329,8 +284,8 @@
|
||||
"version": "1.0.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Utility to generate documentation for Solidity smart contracts, outputting a format compliant with @0xproject/types.DocAgnosticFormat",
|
||||
"pr": 1004
|
||||
"note": "Created package",
|
||||
"pr": "2455"
|
||||
}
|
||||
]
|
||||
}
|
||||
134
contracts/broker/CHANGELOG.md
Normal file
134
contracts/broker/CHANGELOG.md
Normal file
@@ -0,0 +1,134 @@
|
||||
<!--
|
||||
changelogUtils.file is auto-generated using the monorepo-scripts package. Don't edit directly.
|
||||
Edit the package's CHANGELOG.json file only.
|
||||
-->
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v1.1.28 - _April 28, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.1.27 - _April 1, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.1.26 - _March 17, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.1.25 - _February 24, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.1.24 - _February 10, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.1.23 - _January 26, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.1.22 - _January 13, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.1.21 - _January 4, 2021_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.1.20 - _December 23, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.1.19 - _December 17, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.1.18 - _December 16, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.1.17 - _December 9, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.1.16 - _December 7, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.1.15 - _December 3, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.1.14 - _November 19, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.1.13 - _November 13, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.1.12 - _November 3, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.1.11 - _November 3, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.1.10 - _November 2, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.1.9 - _October 28, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.1.8 - _October 27, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.1.7 - _October 21, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.1.6 - _July 15, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.1.5 - _June 24, 2020_
|
||||
|
||||
* Fix broken tests. (#2591)
|
||||
|
||||
## v1.1.4 - _March 3, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.1.3 - _February 27, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.1.2 - _February 26, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.1.1 - _February 25, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.1.0 - _February 15, 2020_
|
||||
|
||||
* Added decoders for broker data (#2484)
|
||||
|
||||
## v1.0.2 - _February 8, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.0.1 - _February 6, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.0.0 - _Invalid date_
|
||||
|
||||
* Created package (#2455)
|
||||
1
contracts/broker/DEPLOYS.json
Normal file
1
contracts/broker/DEPLOYS.json
Normal file
@@ -0,0 +1 @@
|
||||
[]
|
||||
@@ -1,6 +1,18 @@
|
||||
## Tests
|
||||
## Broker
|
||||
|
||||
This package implements unit tests against 0x's smart contracts. Its primary purpose is to help avoid circular dependencies between the contract packages.
|
||||
This package contains the implementation of the [`Broker` contract](https://github.com/0xProject/ZEIPs/issues/75). This contract serves as an entry-point to the 0x Exchange for the filling of property-based orders. Addresses of the deployed contracts can be found in this 0x [guide](https://0x.org/docs/guides/0x-cheat-sheet) or the [DEPLOYS](./DEPLOYS.json) file within this package.
|
||||
|
||||
## Installation
|
||||
|
||||
**Install**
|
||||
|
||||
```bash
|
||||
npm install @0x/contracts-broker --save
|
||||
```
|
||||
|
||||
## Bug bounty
|
||||
|
||||
A bug bounty for the 3.0 contracts is ongoing! Instructions can be found [here](https://0x.org/docs/guides/bug-bounty-program).
|
||||
|
||||
## Contributing
|
||||
|
||||
@@ -29,39 +41,21 @@ yarn install
|
||||
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-tests yarn build
|
||||
PKG=@0x/contracts-broker yarn build
|
||||
```
|
||||
|
||||
Or continuously rebuild on change:
|
||||
|
||||
```bash
|
||||
PKG=@0x/contracts-tests yarn watch
|
||||
PKG=@0x/contracts-broker yarn watch
|
||||
```
|
||||
|
||||
If imports are rebuilt in their source packages, they do not need to be rebuilt here.
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
// contracts/tests/test/some-new/some_new_test.ts
|
||||
import { SomeNewContract } from '@0x/contracts-some-new';
|
||||
|
||||
describe('should do its thing', () => {
|
||||
const contractInstance = new SomeNewContract();
|
||||
expect(contractInstance.someTruthyFunction.callAsync()).to.be.true();
|
||||
})
|
||||
```
|
||||
|
||||
Run `yarn watch` from `contracts/some-new`, and then running `yarn test` from this package should test the new changes.
|
||||
|
||||
### Clean
|
||||
|
||||
```bash
|
||||
yarn clean
|
||||
```
|
||||
|
||||
Since the purpose of this package is to test other packages, make sure you are running `yarn clean` as necessary in the imported packages as well.
|
||||
|
||||
### Lint
|
||||
|
||||
```bash
|
||||
@@ -73,3 +67,7 @@ yarn lint
|
||||
```bash
|
||||
yarn test
|
||||
```
|
||||
|
||||
#### Testing options
|
||||
|
||||
Contracts testing options like coverage, profiling, revert traces or backing node choosing - are described [here](../TESTING.md).
|
||||
@@ -1,10 +1,11 @@
|
||||
{
|
||||
"artifactsDir": "./generated-artifacts",
|
||||
"artifactsDir": "./test/generated-artifacts",
|
||||
"contractsDir": "./contracts",
|
||||
"useDockerisedSolc": false,
|
||||
"isOfflineMode": false,
|
||||
"shouldSaveStandardInput": true,
|
||||
"compilerSettings": {
|
||||
"evmVersion": "constantinople",
|
||||
"evmVersion": "istanbul",
|
||||
"optimizer": {
|
||||
"enabled": true,
|
||||
"runs": 1000000,
|
||||
314
contracts/broker/contracts/src/Broker.sol
Normal file
314
contracts/broker/contracts/src/Broker.sol
Normal file
@@ -0,0 +1,314 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetData.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol";
|
||||
import "@0x/contracts-erc721/contracts/src/interfaces/IERC721Token.sol";
|
||||
import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
|
||||
import "@0x/contracts-extensions/contracts/src/LibAssetDataTransfer.sol";
|
||||
import "@0x/contracts-extensions/contracts/src/MixinWethUtils.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibRichErrors.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
|
||||
import "./interfaces/IBroker.sol";
|
||||
import "./interfaces/IPropertyValidator.sol";
|
||||
import "./libs/LibBrokerRichErrors.sol";
|
||||
|
||||
|
||||
// solhint-disable space-after-comma, var-name-mixedcase
|
||||
contract Broker is
|
||||
IBroker,
|
||||
MixinWethUtils
|
||||
{
|
||||
// Contract addresses
|
||||
|
||||
// Address of the 0x Exchange contract
|
||||
address internal EXCHANGE;
|
||||
// Address of the 0x ERC1155 Asset Proxy contract
|
||||
address internal ERC1155_PROXY;
|
||||
|
||||
// The following storage variables are used to cache data for the duration of the transcation.
|
||||
// They should always cleared at the end of the transaction.
|
||||
|
||||
// Token IDs specified by the taker to be used to fill property-based orders.
|
||||
uint256[] internal _cachedTokenIds;
|
||||
// An index to the above array keeping track of which assets have been transferred.
|
||||
uint256 internal _cacheIndex;
|
||||
// The address that called `brokerTrade` or `batchBrokerTrade`. Assets will be transferred to
|
||||
// and from this address as the effectual taker of the orders.
|
||||
address internal _sender;
|
||||
|
||||
using LibSafeMath for uint256;
|
||||
using LibBytes for bytes;
|
||||
using LibAssetDataTransfer for bytes;
|
||||
|
||||
/// @param exchange Address of the 0x Exchange contract.
|
||||
/// @param exchange Address of the Wrapped Ether contract.
|
||||
/// @param exchange Address of the 0x ERC1155 Asset Proxy contract.
|
||||
constructor (
|
||||
address exchange,
|
||||
address weth
|
||||
)
|
||||
public
|
||||
MixinWethUtils(
|
||||
exchange,
|
||||
weth
|
||||
)
|
||||
{
|
||||
EXCHANGE = exchange;
|
||||
ERC1155_PROXY = IExchange(EXCHANGE).getAssetProxy(IAssetData(address(0)).ERC1155Assets.selector);
|
||||
}
|
||||
|
||||
/// @dev The Broker implements the ERC1155 transfer function to be compatible with the ERC1155 asset proxy
|
||||
/// @param from Since the Broker serves as the taker of the order, this should equal `address(this)`
|
||||
/// @param to This should be the maker of the order.
|
||||
/// @param amounts Should be an array of just one `uint256`, specifying the amount of the brokered assets to transfer.
|
||||
/// @param data Encodes the validator contract address and any auxiliary data it needs for property validation.
|
||||
function safeBatchTransferFrom(
|
||||
address from,
|
||||
address to,
|
||||
uint256[] calldata /* ids */,
|
||||
uint256[] calldata amounts,
|
||||
bytes calldata data
|
||||
)
|
||||
external
|
||||
{
|
||||
// Only the ERC1155 asset proxy contract should be calling this function.
|
||||
if (msg.sender != ERC1155_PROXY) {
|
||||
LibRichErrors.rrevert(LibBrokerRichErrors.OnlyERC1155ProxyError(
|
||||
msg.sender
|
||||
));
|
||||
}
|
||||
// Only `takerAssetData` should be using Broker assets
|
||||
if (from != address(this)) {
|
||||
LibRichErrors.rrevert(
|
||||
LibBrokerRichErrors.InvalidFromAddressError(from)
|
||||
);
|
||||
}
|
||||
// Only one asset amount should be specified.
|
||||
if (amounts.length != 1) {
|
||||
LibRichErrors.rrevert(
|
||||
LibBrokerRichErrors.AmountsLengthMustEqualOneError(amounts.length)
|
||||
);
|
||||
}
|
||||
|
||||
uint256 cacheIndex = _cacheIndex;
|
||||
uint256 remainingAmount = amounts[0];
|
||||
|
||||
// Verify that there are enough broker assets to transfer
|
||||
if (_cachedTokenIds.length.safeSub(cacheIndex) < remainingAmount) {
|
||||
LibRichErrors.rrevert(
|
||||
LibBrokerRichErrors.TooFewBrokerAssetsProvidedError(_cachedTokenIds.length)
|
||||
);
|
||||
}
|
||||
|
||||
// Decode validator and params from `data`
|
||||
(address tokenAddress, address validator, bytes memory propertyData) = abi.decode(
|
||||
data,
|
||||
(address, address, bytes)
|
||||
);
|
||||
|
||||
while (remainingAmount != 0) {
|
||||
uint256 tokenId = _cachedTokenIds[cacheIndex];
|
||||
cacheIndex++;
|
||||
|
||||
// Validate asset properties
|
||||
IPropertyValidator(validator).checkBrokerAsset(
|
||||
tokenId,
|
||||
propertyData
|
||||
);
|
||||
|
||||
// Perform the transfer
|
||||
IERC721Token(tokenAddress).transferFrom(
|
||||
_sender,
|
||||
to,
|
||||
tokenId
|
||||
);
|
||||
|
||||
remainingAmount--;
|
||||
}
|
||||
// Update cache index in storage
|
||||
_cacheIndex = cacheIndex;
|
||||
}
|
||||
|
||||
/// @dev Fills a single property-based order by the given amount using the given assets.
|
||||
/// Pays protocol fees using either the ETH supplied by the taker to the transaction or
|
||||
/// WETH acquired from the maker during settlement. The final WETH balance is sent to the taker.
|
||||
/// @param brokeredTokenIds Token IDs specified by the taker to be used to fill the orders.
|
||||
/// @param order The property-based order to fill. The format of a property-based order is the
|
||||
/// same as that of a normal order, except the takerAssetData. Instaed of specifying a
|
||||
/// specific ERC721 asset, the takerAssetData should be ERC1155 assetData where the
|
||||
/// underlying tokenAddress is this contract's address and the desired properties are
|
||||
/// encoded in the extra data field. Also note that takerFees must be denominated in
|
||||
/// WETH (or zero).
|
||||
/// @param takerAssetFillAmount The amount to fill the order by.
|
||||
/// @param signature The maker's signature of the given order.
|
||||
/// @param fillFunctionSelector The selector for either `fillOrder` or `fillOrKillOrder`.
|
||||
/// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients.
|
||||
/// @param feeRecipients Addresses that will receive ETH when orders are filled.
|
||||
/// @return fillResults Amounts filled and fees paid by the maker and taker.
|
||||
function brokerTrade(
|
||||
uint256[] memory brokeredTokenIds,
|
||||
LibOrder.Order memory order,
|
||||
uint256 takerAssetFillAmount,
|
||||
bytes memory signature,
|
||||
bytes4 fillFunctionSelector,
|
||||
uint256[] memory ethFeeAmounts,
|
||||
address payable[] memory feeRecipients
|
||||
)
|
||||
public
|
||||
payable
|
||||
returns (LibFillResults.FillResults memory fillResults)
|
||||
{
|
||||
// Cache the taker-supplied asset data
|
||||
_cachedTokenIds = brokeredTokenIds;
|
||||
// Cache the sender's address
|
||||
_sender = msg.sender;
|
||||
|
||||
// Sanity-check the provided function selector
|
||||
if (
|
||||
fillFunctionSelector != IExchange(address(0)).fillOrder.selector &&
|
||||
fillFunctionSelector != IExchange(address(0)).fillOrKillOrder.selector
|
||||
) {
|
||||
LibBrokerRichErrors.InvalidFunctionSelectorError(fillFunctionSelector);
|
||||
}
|
||||
|
||||
// Pay ETH affiliate fees to all feeRecipient addresses
|
||||
_transferEthFeesAndWrapRemaining(ethFeeAmounts, feeRecipients);
|
||||
|
||||
// Perform the fill
|
||||
bytes memory fillCalldata = abi.encodeWithSelector(
|
||||
fillFunctionSelector,
|
||||
order,
|
||||
takerAssetFillAmount,
|
||||
signature
|
||||
);
|
||||
// solhint-disable-next-line avoid-call-value
|
||||
(bool didSucceed, bytes memory returnData) = EXCHANGE.call(fillCalldata);
|
||||
if (didSucceed) {
|
||||
fillResults = abi.decode(returnData, (LibFillResults.FillResults));
|
||||
} else {
|
||||
// Re-throw error
|
||||
LibRichErrors.rrevert(returnData);
|
||||
}
|
||||
|
||||
// Transfer maker asset to taker
|
||||
if (!order.makerAssetData.equals(WETH_ASSET_DATA)) {
|
||||
order.makerAssetData.transferOut(fillResults.makerAssetFilledAmount);
|
||||
}
|
||||
|
||||
// Refund remaining ETH to msg.sender.
|
||||
_unwrapAndTransferEth(WETH.balanceOf(address(this)));
|
||||
|
||||
_clearStorage();
|
||||
|
||||
return fillResults;
|
||||
}
|
||||
|
||||
/// @dev Fills multiple property-based orders by the given amounts using the given assets.
|
||||
/// Pays protocol fees using either the ETH supplied by the taker to the transaction or
|
||||
/// WETH acquired from the maker during settlement. The final WETH balance is sent to the taker.
|
||||
/// @param brokeredTokenIds Token IDs specified by the taker to be used to fill the orders.
|
||||
/// @param orders The property-based orders to fill. The format of a property-based order is the
|
||||
/// same as that of a normal order, except the takerAssetData. Instaed of specifying a
|
||||
/// specific ERC721 asset, the takerAssetData should be ERC1155 assetData where the
|
||||
/// underlying tokenAddress is this contract's address and the desired properties are
|
||||
/// encoded in the extra data field. Also note that takerFees must be denominated in
|
||||
/// WETH (or zero).
|
||||
/// @param takerAssetFillAmounts The amounts to fill the orders by.
|
||||
/// @param signatures The makers' signatures for the given orders.
|
||||
/// @param batchFillFunctionSelector The selector for either `batchFillOrders`,
|
||||
/// `batchFillOrKillOrders`, or `batchFillOrdersNoThrow`.
|
||||
/// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients.
|
||||
/// @param feeRecipients Addresses that will receive ETH when orders are filled.
|
||||
/// @return fillResults Amounts filled and fees paid by the makers and taker.
|
||||
function batchBrokerTrade(
|
||||
uint256[] memory brokeredTokenIds,
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256[] memory takerAssetFillAmounts,
|
||||
bytes[] memory signatures,
|
||||
bytes4 batchFillFunctionSelector,
|
||||
uint256[] memory ethFeeAmounts,
|
||||
address payable[] memory feeRecipients
|
||||
)
|
||||
public
|
||||
payable
|
||||
returns (LibFillResults.FillResults[] memory fillResults)
|
||||
{
|
||||
// Cache the taker-supplied asset data
|
||||
_cachedTokenIds = brokeredTokenIds;
|
||||
// Cache the sender's address
|
||||
_sender = msg.sender;
|
||||
|
||||
// Sanity-check the provided function selector
|
||||
if (
|
||||
batchFillFunctionSelector != IExchange(address(0)).batchFillOrders.selector &&
|
||||
batchFillFunctionSelector != IExchange(address(0)).batchFillOrKillOrders.selector &&
|
||||
batchFillFunctionSelector != IExchange(address(0)).batchFillOrdersNoThrow.selector
|
||||
) {
|
||||
LibBrokerRichErrors.InvalidFunctionSelectorError(batchFillFunctionSelector);
|
||||
}
|
||||
|
||||
// Pay ETH affiliate fees to all feeRecipient addresses
|
||||
_transferEthFeesAndWrapRemaining(ethFeeAmounts, feeRecipients);
|
||||
|
||||
// Perform the batch fill
|
||||
bytes memory batchFillCalldata = abi.encodeWithSelector(
|
||||
batchFillFunctionSelector,
|
||||
orders,
|
||||
takerAssetFillAmounts,
|
||||
signatures
|
||||
);
|
||||
// solhint-disable-next-line avoid-call-value
|
||||
(bool didSucceed, bytes memory returnData) = EXCHANGE.call(batchFillCalldata);
|
||||
if (didSucceed) {
|
||||
// solhint-disable-next-line indent
|
||||
fillResults = abi.decode(returnData, (LibFillResults.FillResults[]));
|
||||
} else {
|
||||
// Re-throw error
|
||||
LibRichErrors.rrevert(returnData);
|
||||
}
|
||||
|
||||
// Transfer maker assets to taker
|
||||
for (uint256 i = 0; i < orders.length; i++) {
|
||||
if (!orders[i].makerAssetData.equals(WETH_ASSET_DATA)) {
|
||||
orders[i].makerAssetData.transferOut(fillResults[i].makerAssetFilledAmount);
|
||||
}
|
||||
}
|
||||
|
||||
// Refund remaining ETH to msg.sender.
|
||||
_unwrapAndTransferEth(WETH.balanceOf(address(this)));
|
||||
|
||||
_clearStorage();
|
||||
|
||||
return fillResults;
|
||||
}
|
||||
|
||||
function _clearStorage()
|
||||
private
|
||||
{
|
||||
delete _cachedTokenIds;
|
||||
_cacheIndex = 0;
|
||||
_sender = address(0);
|
||||
}
|
||||
}
|
||||
101
contracts/broker/contracts/src/interfaces/IBroker.sol
Normal file
101
contracts/broker/contracts/src/interfaces/IBroker.sol
Normal file
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
|
||||
|
||||
|
||||
// solhint-disable space-after-comma
|
||||
interface IBroker {
|
||||
|
||||
/// @dev Fills a single property-based order by the given amount using the given assets.
|
||||
/// Pays protocol fees using either the ETH supplied by the taker to the transaction or
|
||||
/// WETH acquired from the maker during settlement. The final WETH balance is sent to the taker.
|
||||
/// @param brokeredTokenIds Token IDs specified by the taker to be used to fill the orders.
|
||||
/// @param order The property-based order to fill. The format of a property-based order is the
|
||||
/// same as that of a normal order, except the takerAssetData. Instaed of specifying a
|
||||
/// specific ERC721 asset, the takerAssetData should be ERC1155 assetData where the
|
||||
/// underlying tokenAddress is this contract's address and the desired properties are
|
||||
/// encoded in the extra data field. Also note that takerFees must be denominated in
|
||||
/// WETH (or zero).
|
||||
/// @param takerAssetFillAmount The amount to fill the order by.
|
||||
/// @param signature The maker's signature of the given order.
|
||||
/// @param fillFunctionSelector The selector for either `fillOrder` or `fillOrKillOrder`.
|
||||
/// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients.
|
||||
/// @param feeRecipients Addresses that will receive ETH when orders are filled.
|
||||
/// @return fillResults Amounts filled and fees paid by the maker and taker.
|
||||
function brokerTrade(
|
||||
uint256[] calldata brokeredTokenIds,
|
||||
LibOrder.Order calldata order,
|
||||
uint256 takerAssetFillAmount,
|
||||
bytes calldata signature,
|
||||
bytes4 fillFunctionSelector,
|
||||
uint256[] calldata ethFeeAmounts,
|
||||
address payable[] calldata feeRecipients
|
||||
)
|
||||
external
|
||||
payable
|
||||
returns (LibFillResults.FillResults memory fillResults);
|
||||
|
||||
/// @dev Fills multiple property-based orders by the given amounts using the given assets.
|
||||
/// Pays protocol fees using either the ETH supplied by the taker to the transaction or
|
||||
/// WETH acquired from the maker during settlement. The final WETH balance is sent to the taker.
|
||||
/// @param brokeredTokenIds Token IDs specified by the taker to be used to fill the orders.
|
||||
/// @param orders The property-based orders to fill. The format of a property-based order is the
|
||||
/// same as that of a normal order, except the takerAssetData. Instaed of specifying a
|
||||
/// specific ERC721 asset, the takerAssetData should be ERC1155 assetData where the
|
||||
/// underlying tokenAddress is this contract's address and the desired properties are
|
||||
/// encoded in the extra data field. Also note that takerFees must be denominated in
|
||||
/// WETH (or zero).
|
||||
/// @param takerAssetFillAmounts The amounts to fill the orders by.
|
||||
/// @param signatures The makers' signatures for the given orders.
|
||||
/// @param batchFillFunctionSelector The selector for either `batchFillOrders`,
|
||||
/// `batchFillOrKillOrders`, or `batchFillOrdersNoThrow`.
|
||||
/// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients.
|
||||
/// @param feeRecipients Addresses that will receive ETH when orders are filled.
|
||||
/// @return fillResults Amounts filled and fees paid by the makers and taker.
|
||||
function batchBrokerTrade(
|
||||
uint256[] calldata brokeredTokenIds,
|
||||
LibOrder.Order[] calldata orders,
|
||||
uint256[] calldata takerAssetFillAmounts,
|
||||
bytes[] calldata signatures,
|
||||
bytes4 batchFillFunctionSelector,
|
||||
uint256[] calldata ethFeeAmounts,
|
||||
address payable[] calldata feeRecipients
|
||||
)
|
||||
external
|
||||
payable
|
||||
returns (LibFillResults.FillResults[] memory fillResults);
|
||||
|
||||
/// @dev The Broker implements the ERC1155 transfer function to be compatible with the ERC1155 asset proxy
|
||||
/// @param from Since the Broker serves as the taker of the order, this should equal `address(this)`
|
||||
/// @param to This should be the maker of the order.
|
||||
/// @param amounts Should be an array of just one `uint256`, specifying the amount of the brokered assets to transfer.
|
||||
/// @param data Encodes the validator contract address and any auxiliary data it needs for property validation.
|
||||
function safeBatchTransferFrom(
|
||||
address from,
|
||||
address to,
|
||||
uint256[] calldata /* ids */,
|
||||
uint256[] calldata amounts,
|
||||
bytes calldata data
|
||||
)
|
||||
external;
|
||||
}
|
||||
@@ -16,22 +16,18 @@
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.5;
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibEIP712ExchangeDomain.sol";
|
||||
import "../src/MixinSignatureValidator.sol";
|
||||
import "../src/MixinTransactions.sol";
|
||||
|
||||
interface IGodsUnchained {
|
||||
|
||||
contract TestSignatureValidator is
|
||||
LibEIP712ExchangeDomain,
|
||||
MixinSignatureValidator
|
||||
{
|
||||
|
||||
// solhint-disable no-empty-blocks
|
||||
constructor (uint256 chainId)
|
||||
public
|
||||
LibEIP712ExchangeDomain(chainId, address(0))
|
||||
{}
|
||||
/// @dev Returns the proto and quality for a particular card given its token id
|
||||
/// @param tokenId The id of the card to query.
|
||||
/// @return proto The proto of the given card.
|
||||
/// @return quality The quality of the given card
|
||||
function getDetails(uint256 tokenId)
|
||||
external
|
||||
view
|
||||
returns (uint16 proto, uint8 quality);
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
|
||||
interface IPropertyValidator {
|
||||
|
||||
/// @dev Checks that the given asset data satisfies the properties encoded in `propertyData`.
|
||||
/// Should revert if the asset does not satisfy the specified properties.
|
||||
/// @param tokenId The ERC721 tokenId of the asset to check.
|
||||
/// @param propertyData Encoded properties or auxiliary data needed to perform the check.
|
||||
function checkBrokerAsset(
|
||||
uint256 tokenId,
|
||||
bytes calldata propertyData
|
||||
)
|
||||
external
|
||||
view;
|
||||
}
|
||||
109
contracts/broker/contracts/src/libs/LibBrokerRichErrors.sol
Normal file
109
contracts/broker/contracts/src/libs/LibBrokerRichErrors.sol
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
|
||||
library LibBrokerRichErrors {
|
||||
|
||||
// bytes4(keccak256("InvalidFromAddressError(address)"))
|
||||
bytes4 internal constant INVALID_FROM_ADDRESS_ERROR_SELECTOR =
|
||||
0x906bfb3c;
|
||||
|
||||
// bytes4(keccak256("AmountsLengthMustEqualOneError(uint256)"))
|
||||
bytes4 internal constant AMOUNTS_LENGTH_MUST_EQUAL_ONE_ERROR_SELECTOR =
|
||||
0xba9be200;
|
||||
|
||||
// bytes4(keccak256("TooFewBrokerAssetsProvidedError(uint256)"))
|
||||
bytes4 internal constant TOO_FEW_BROKER_ASSETS_PROVIDED_ERROR_SELECTOR =
|
||||
0x55272586;
|
||||
|
||||
// bytes4(keccak256("InvalidFunctionSelectorError(bytes4)"))
|
||||
bytes4 internal constant INVALID_FUNCTION_SELECTOR_ERROR_SELECTOR =
|
||||
0x540943f1;
|
||||
|
||||
// bytes4(keccak256("OnlyERC1155ProxyError(address)"))
|
||||
bytes4 internal constant ONLY_ERC_1155_PROXY_ERROR_SELECTOR =
|
||||
0xccc529af;
|
||||
|
||||
// solhint-disable func-name-mixedcase
|
||||
function InvalidFromAddressError(
|
||||
address from
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
INVALID_FROM_ADDRESS_ERROR_SELECTOR,
|
||||
from
|
||||
);
|
||||
}
|
||||
|
||||
function AmountsLengthMustEqualOneError(
|
||||
uint256 amountsLength
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
AMOUNTS_LENGTH_MUST_EQUAL_ONE_ERROR_SELECTOR,
|
||||
amountsLength
|
||||
);
|
||||
}
|
||||
|
||||
function TooFewBrokerAssetsProvidedError(
|
||||
uint256 numBrokeredAssets
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
TOO_FEW_BROKER_ASSETS_PROVIDED_ERROR_SELECTOR,
|
||||
numBrokeredAssets
|
||||
);
|
||||
}
|
||||
|
||||
function InvalidFunctionSelectorError(
|
||||
bytes4 selector
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
INVALID_FUNCTION_SELECTOR_ERROR_SELECTOR,
|
||||
selector
|
||||
);
|
||||
}
|
||||
|
||||
function OnlyERC1155ProxyError(
|
||||
address sender
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
ONLY_ERC_1155_PROXY_ERROR_SELECTOR,
|
||||
sender
|
||||
);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user