Compare commits
740 Commits
@0x/migrat
...
@0x/contra
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ec92cea598 | ||
|
|
0e25f8ba32 | ||
|
|
23602ec6b4 | ||
|
|
f4da2a129d | ||
|
|
ab6938f614 | ||
|
|
09ec6d637b | ||
|
|
703e8e06a3 | ||
|
|
47f30d097a | ||
|
|
5c18b394a4 | ||
|
|
fb5afafbbe | ||
|
|
b3f71af850 | ||
|
|
093fb6e68d | ||
|
|
a8ae2b7355 | ||
|
|
d45f64ab06 | ||
|
|
050343c97a | ||
|
|
64f5aaccd7 | ||
|
|
856472452a | ||
|
|
f06e7a511e | ||
|
|
f6bd8c939c | ||
|
|
d09040d1d3 | ||
|
|
00fcdbd43a | ||
|
|
4dfd91e2df | ||
|
|
50f86dd61b | ||
|
|
9c219159c6 | ||
|
|
e1195a3444 | ||
|
|
7fe4a03683 | ||
|
|
803505cacc | ||
|
|
e05e118bd2 | ||
|
|
c883f5ea41 | ||
|
|
0567b3332b | ||
|
|
cc2833b372 | ||
|
|
0165d67dc1 | ||
|
|
1a4489b96a | ||
|
|
1ecc4a14ca | ||
|
|
9eba6d7146 | ||
|
|
3724ac4b67 | ||
|
|
d912175a7a | ||
|
|
5f23eee6dc | ||
|
|
5fe607557d | ||
|
|
5d6584b0eb | ||
|
|
7bdb77d93f | ||
|
|
2530d47fde | ||
|
|
2b8226a757 | ||
|
|
92d5adaac4 | ||
|
|
0c9daa693e | ||
|
|
89729e828c | ||
|
|
c2113caae1 | ||
|
|
e0adb6624d | ||
|
|
022855add0 | ||
|
|
4dd1c48dc8 | ||
|
|
cdc2393aa6 | ||
|
|
94f94bdda7 | ||
|
|
3264bd223d | ||
|
|
6292c0703c | ||
|
|
9a28079f2a | ||
|
|
c612649f02 | ||
|
|
eda44d1ffb | ||
|
|
4c2f77c014 | ||
|
|
6b8bbd3d5f | ||
|
|
e914e1b7fa | ||
|
|
3d2ce749a8 | ||
|
|
9892d8d6d2 | ||
|
|
218a7ab810 | ||
|
|
6779e52813 | ||
|
|
5d51b40541 | ||
|
|
b12b7069f7 | ||
|
|
10a5d38446 | ||
|
|
e39e7a934e | ||
|
|
b7127d8506 | ||
|
|
a12e07b1a8 | ||
|
|
8ff5c0a603 | ||
|
|
c5c8506cc6 | ||
|
|
dbef531d66 | ||
|
|
4e9c9ca079 | ||
|
|
d7c61fea4c | ||
|
|
08dc5fafa0 | ||
|
|
78493a9d98 | ||
|
|
e274d8994a | ||
|
|
2dee887e6f | ||
|
|
f7eb20a235 | ||
|
|
f3cea0ebd0 | ||
|
|
05e00d278f | ||
|
|
107c7a71f9 | ||
|
|
56698fb09e | ||
|
|
55bb6f89d3 | ||
|
|
47d77cbddd | ||
|
|
2547e0e5b1 | ||
|
|
1a4699ecac | ||
|
|
c825643b67 | ||
|
|
a425d3a234 | ||
|
|
3041e7459e | ||
|
|
1fb9d54174 | ||
|
|
598607f5a3 | ||
|
|
5c5bb20415 | ||
|
|
6199a17791 | ||
|
|
7dd42ad6aa | ||
|
|
c7fd85633d | ||
|
|
b3df71bebf | ||
|
|
88d95ebdbc | ||
|
|
140cf4d378 | ||
|
|
451a19117f | ||
|
|
aa6ab33b93 | ||
|
|
8ec04271f3 | ||
|
|
f583de652f | ||
|
|
96cd9de8a6 | ||
|
|
9a17cb4c92 | ||
|
|
021cba9fad | ||
|
|
47f4321611 | ||
|
|
775a41a789 | ||
|
|
f6c61ed79f | ||
|
|
152e057e08 | ||
|
|
8b84ecc593 | ||
|
|
9c10babefd | ||
|
|
67193d9472 | ||
|
|
7d04dd9520 | ||
|
|
93bda7972c | ||
|
|
92c0e34ed2 | ||
|
|
c0a471b349 | ||
|
|
2543076d16 | ||
|
|
e32bb6fc0f | ||
|
|
7020166473 | ||
|
|
16ae47f2ad | ||
|
|
abf1141ad8 | ||
|
|
3790e0a741 | ||
|
|
9e1966b4fe | ||
|
|
38e06e57a3 | ||
|
|
7f2fc90677 | ||
|
|
1f0ab54fc5 | ||
|
|
7f8c11a74c | ||
|
|
7a4d64d90d | ||
|
|
7217bfa35e | ||
|
|
25077affc8 | ||
|
|
7a80583655 | ||
|
|
c21fe0cb50 | ||
|
|
3d08e79089 | ||
|
|
c43db2d096 | ||
|
|
220856d084 | ||
|
|
a01eafa4e7 | ||
|
|
f9c2d25352 | ||
|
|
d2f77d74e6 | ||
|
|
c3b928c1f5 | ||
|
|
9dfa9c194e | ||
|
|
1a3dc6cefc | ||
|
|
1a73daf82a | ||
|
|
6b20c9a542 | ||
|
|
76c996250d | ||
|
|
52e8de9966 | ||
|
|
81ab84b087 | ||
|
|
e34755a1ef | ||
|
|
6c11b2ad8a | ||
|
|
ede6ecc3aa | ||
|
|
9db69f33e4 | ||
|
|
17d5d4648b | ||
|
|
e203b5593a | ||
|
|
de9aa063c0 | ||
|
|
077d001b42 | ||
|
|
dfd46d68ac | ||
|
|
4dbe137999 | ||
|
|
1ac5cb404f | ||
|
|
43ffa2dd77 | ||
|
|
1efa7935b7 | ||
|
|
b0835b005a | ||
|
|
30946ac110 | ||
|
|
9427858755 | ||
|
|
53864d3817 | ||
|
|
ab283ddd9b | ||
|
|
7efcf9066c | ||
|
|
219e09d157 | ||
|
|
d816551dba | ||
|
|
04c5752b8a | ||
|
|
ed12d8b95f | ||
|
|
f48852742d | ||
|
|
b84d89367a | ||
|
|
d8dab6a070 | ||
|
|
ac2443690c | ||
|
|
5df0f13eb0 | ||
|
|
24d782fb19 | ||
|
|
01a5472318 | ||
|
|
4b7a2e9d49 | ||
|
|
62936e3502 | ||
|
|
d6b3e4fbaa | ||
|
|
a5f011f4a4 | ||
|
|
c6efaab01d | ||
|
|
0f7282d9a9 | ||
|
|
a3b414a986 | ||
|
|
8a6d0b67f1 | ||
|
|
f78ff91975 | ||
|
|
c8e416f3b1 | ||
|
|
d61f67d24a | ||
|
|
258ffdcc94 | ||
|
|
1f93f09864 | ||
|
|
7afddb9309 | ||
|
|
5eb4dbd5d9 | ||
|
|
fc39ddfb71 | ||
|
|
ba04a8bc0c | ||
|
|
02d4a28402 | ||
|
|
ea2bf07ea6 | ||
|
|
b5dc734dc4 | ||
|
|
7dd9b0ba66 | ||
|
|
69a5c8a317 | ||
|
|
b975ac7c31 | ||
|
|
dcede832c8 | ||
|
|
f40bbbc238 | ||
|
|
361f5ca5cc | ||
|
|
a710ebe5b3 | ||
|
|
2becef23ff | ||
|
|
f916d293fa | ||
|
|
f312a260cc | ||
|
|
fd9b51c7db | ||
|
|
1dac6b6157 | ||
|
|
c2ba6b3a0f | ||
|
|
576bd5585f | ||
|
|
ae61a87190 | ||
|
|
2e8f2ae769 | ||
|
|
b507a308e6 | ||
|
|
ad83b17fdf | ||
|
|
e452cfcd59 | ||
|
|
6474a4e08c | ||
|
|
e78288ddfd | ||
|
|
6e2d0ab13d | ||
|
|
bfbc78c95c | ||
|
|
368ae86530 | ||
|
|
d8ccc1694d | ||
|
|
b4e10b1e06 | ||
|
|
05f76958ac | ||
|
|
1183cf5e6b | ||
|
|
bf9eb1413b | ||
|
|
38d48a8f20 | ||
|
|
ca222a470d | ||
|
|
49ca8840ea | ||
|
|
faaeba78bb | ||
|
|
6c37d47f2f | ||
|
|
185e53149f | ||
|
|
4329a252ee | ||
|
|
8d38d69684 | ||
|
|
edb5e50253 | ||
|
|
81ab2e75ca | ||
|
|
e0d8398cf7 | ||
|
|
4fd46d1c95 | ||
|
|
c217764fe0 | ||
|
|
42124274c7 | ||
|
|
562342ac99 | ||
|
|
14b573ebfd | ||
|
|
e3834c2fc0 | ||
|
|
c2f3757de7 | ||
|
|
4b0010be63 | ||
|
|
078af36e0e | ||
|
|
b17d12fe23 | ||
|
|
294c0b449b | ||
|
|
bc3927e973 | ||
|
|
a2cfdd2975 | ||
|
|
53b4f48b2e | ||
|
|
635b80440a | ||
|
|
f2d95477e6 | ||
|
|
1005e4962a | ||
|
|
487bc1a08b | ||
|
|
0cf768185e | ||
|
|
b5558a8cff | ||
|
|
af2b8dfde5 | ||
|
|
2bde5f7034 | ||
|
|
c38f913a84 | ||
|
|
44b4f91208 | ||
|
|
9c4ad6ac32 | ||
|
|
b151c0b701 | ||
|
|
d4b6db773f | ||
|
|
7da71c0955 | ||
|
|
32adb35c2a | ||
|
|
2f197d128a | ||
|
|
5415bc4590 | ||
|
|
f6086b8054 | ||
|
|
c9d77d7fa0 | ||
|
|
ab8c457c51 | ||
|
|
5d91ad3656 | ||
|
|
78ffca06ea | ||
|
|
0d71ec93e7 | ||
|
|
d4c771dc7d | ||
|
|
68004466bb | ||
|
|
4dd2d1afaf | ||
|
|
4947676434 | ||
|
|
ea5e83da03 | ||
|
|
0705276ff9 | ||
|
|
0299abf1b5 | ||
|
|
132394ffbe | ||
|
|
40edcef340 | ||
|
|
bf22eba795 | ||
|
|
e990272db3 | ||
|
|
401a0eadb1 | ||
|
|
5852e0b476 | ||
|
|
401df5f45d | ||
|
|
7da40fd7bc | ||
|
|
89740dc24c | ||
|
|
4d7ba42f8f | ||
|
|
bbd9c4ef67 | ||
|
|
de036ae96a | ||
|
|
e5985d7c3f | ||
|
|
fb54c45d7d | ||
|
|
f1b704a91a | ||
|
|
b99eab6804 | ||
|
|
82acc26f97 | ||
|
|
569a165c87 | ||
|
|
704adcb03d | ||
|
|
197cdee604 | ||
|
|
3dc5de936e | ||
|
|
d88eb6a5c9 | ||
|
|
a168f34538 | ||
|
|
7b150bab73 | ||
|
|
b0e38f79ea | ||
|
|
a68ebc27ed | ||
|
|
25705bd314 | ||
|
|
85c9b7d9c5 | ||
|
|
629c2ecba2 | ||
|
|
be0662a41d | ||
|
|
1985fec892 | ||
|
|
2cbdd76aa3 | ||
|
|
73ae0541d8 | ||
|
|
22621b9f76 | ||
|
|
c9f214504a | ||
|
|
e8a2d1240f | ||
|
|
f2e0fe49f7 | ||
|
|
4ce7bf56e7 | ||
|
|
29be232ae9 | ||
|
|
794c0342ee | ||
|
|
d5a22829ac | ||
|
|
b58d4005d3 | ||
|
|
c16d9d85a2 | ||
|
|
92aeca1f30 | ||
|
|
b81ed67975 | ||
|
|
2bc6582e6b | ||
|
|
b27311da2e | ||
|
|
ab8a0da16a | ||
|
|
800e37ed03 | ||
|
|
950e84fe5c | ||
|
|
fdbc235fd6 | ||
|
|
ffdb5c06f6 | ||
|
|
14f0f89798 | ||
|
|
54b53184b7 | ||
|
|
75b1cdac66 | ||
|
|
d21f394531 | ||
|
|
86d90599ca | ||
|
|
ec24976789 | ||
|
|
00eaa8bd34 | ||
|
|
5c44163d68 | ||
|
|
f73bad5c13 | ||
|
|
a063fa6fe0 | ||
|
|
894ad8af21 | ||
|
|
c01793599f | ||
|
|
63db393b60 | ||
|
|
5846166c85 | ||
|
|
25e941128a | ||
|
|
22964ff913 | ||
|
|
62a58667ba | ||
|
|
c868015989 | ||
|
|
565e5e5770 | ||
|
|
198831d084 | ||
|
|
d3be097436 | ||
|
|
1259de5be4 | ||
|
|
df6be48638 | ||
|
|
4923fdbb73 | ||
|
|
66964a5a2f | ||
|
|
97e24d0e14 | ||
|
|
fe0b75ef26 | ||
|
|
4b76efbc28 | ||
|
|
11cff4d391 | ||
|
|
59211c1c1e | ||
|
|
c0ab2e8127 | ||
|
|
d39e90bfa1 | ||
|
|
16e55457c8 | ||
|
|
ea2a453811 | ||
|
|
7d2a768a0c | ||
|
|
78304c4369 | ||
|
|
85f243e2e0 | ||
|
|
785ca4f5d1 | ||
|
|
730e8ad151 | ||
|
|
b3e6e23508 | ||
|
|
f09d56cdb9 | ||
|
|
b51933c4d9 | ||
|
|
477791a600 | ||
|
|
f0d6476f92 | ||
|
|
fa4accd0c4 | ||
|
|
e64754f554 | ||
|
|
5badb1eb5d | ||
|
|
9c52fd1f2a | ||
|
|
27e01b9249 | ||
|
|
5bf0de5519 | ||
|
|
139a4acb1b | ||
|
|
9d8b2d9e0c | ||
|
|
d16a0f1b56 | ||
|
|
edb63c0f26 | ||
|
|
bd3a80bcde | ||
|
|
9f0da8ec39 | ||
|
|
42ed4e393f | ||
|
|
99ffe6bb2d | ||
|
|
70898be894 | ||
|
|
9f1859575d | ||
|
|
0167689374 | ||
|
|
053c5f0f88 | ||
|
|
fa6516d0be | ||
|
|
7fb0e1b39c | ||
|
|
8ba439c263 | ||
|
|
1a1f24146c | ||
|
|
086fa31d04 | ||
|
|
b5e02d1b74 | ||
|
|
e88aee6ad9 | ||
|
|
fb4ead84f5 | ||
|
|
298967e639 | ||
|
|
903a9947a3 | ||
|
|
72beb59d63 | ||
|
|
75dd1be40e | ||
|
|
6a7c2918bb | ||
|
|
9b9ee2415d | ||
|
|
f1f38fb8b0 | ||
|
|
1e44bcb7c9 | ||
|
|
11e689156e | ||
|
|
6c792e89f9 | ||
|
|
11026fe36a | ||
|
|
3133dde3a3 | ||
|
|
b666ca0271 | ||
|
|
de5c6c1ed0 | ||
|
|
34f4cf133b | ||
|
|
1ba54af4e2 | ||
|
|
42e0d608c8 | ||
|
|
2c35d63976 | ||
|
|
d1ca1e768f | ||
|
|
2255cc2ebc | ||
|
|
6512c12f40 | ||
|
|
fc8d428d1d | ||
|
|
e07613818d | ||
|
|
de59ae11bd | ||
|
|
026690c837 | ||
|
|
c223a72f5b | ||
|
|
c66cf83ef1 | ||
|
|
30cf9ac857 | ||
|
|
b99b9d5435 | ||
|
|
81b9ab2b6e | ||
|
|
78a60a9973 | ||
|
|
fca6f838d5 | ||
|
|
4a39eb7931 | ||
|
|
00ab5f0afb | ||
|
|
34dfd73aab | ||
|
|
9e0e12a468 | ||
|
|
1bdcb4f737 | ||
|
|
5e5ecdcf32 | ||
|
|
b316217394 | ||
|
|
d96e307e2c | ||
|
|
a7944bb3c5 | ||
|
|
2dc3885691 | ||
|
|
027ab98a3e | ||
|
|
1a5736a498 | ||
|
|
73f4c036c6 | ||
|
|
6cbadcf8e9 | ||
|
|
6a38f231b1 | ||
|
|
02d63daba5 | ||
|
|
99074b3c34 | ||
|
|
bb33609164 | ||
|
|
27832741e4 | ||
|
|
0cffdc9868 | ||
|
|
6055d44120 | ||
|
|
984305d483 | ||
|
|
7934624afc | ||
|
|
e7db5aa4f3 | ||
|
|
e922299a55 | ||
|
|
58cbc7a05f | ||
|
|
43648a2382 | ||
|
|
c1abaa3293 | ||
|
|
9f77879198 | ||
|
|
79279e5614 | ||
|
|
d100897b20 | ||
|
|
bfaaefaf0a | ||
|
|
520c6fa426 | ||
|
|
d95b520512 | ||
|
|
10f8637802 | ||
|
|
b327cc0f52 | ||
|
|
88acdaff90 | ||
|
|
d5039809de | ||
|
|
2746b73416 | ||
|
|
fdd1d20c5b | ||
|
|
e2b4670016 | ||
|
|
336adc6974 | ||
|
|
7c72ac52e1 | ||
|
|
d165bb2bb2 | ||
|
|
12dea02fab | ||
|
|
5181ee172b | ||
|
|
def0d9307e | ||
|
|
45e572388b | ||
|
|
4898de8d41 | ||
|
|
1aa2270d97 | ||
|
|
5abc9a8066 | ||
|
|
a8deb6cc74 | ||
|
|
87bcb46f43 | ||
|
|
3d904aac67 | ||
|
|
ace63fe83a | ||
|
|
33320fd758 | ||
|
|
be5b4b7702 | ||
|
|
5c55064c0f | ||
|
|
71ad8dcec0 | ||
|
|
09fd8bc521 | ||
|
|
ace0150fcb | ||
|
|
e627d3ce01 | ||
|
|
a65f981f55 | ||
|
|
dbebb3818d | ||
|
|
2027b74c5f | ||
|
|
5e921fdd08 | ||
|
|
6eda017719 | ||
|
|
9b9960c7b9 | ||
|
|
9df09e2464 | ||
|
|
5dacc58a4e | ||
|
|
fcb18e8d34 | ||
|
|
9af95a9461 | ||
|
|
bef662a6e1 | ||
|
|
04f24f32e2 | ||
|
|
65743882bb | ||
|
|
9e82b51eb5 | ||
|
|
a20c40ca90 | ||
|
|
745bdda1a3 | ||
|
|
3c7e538202 | ||
|
|
786419fee0 | ||
|
|
739651b917 | ||
|
|
e374469818 | ||
|
|
2ecd9672c2 | ||
|
|
68a4ad2e51 | ||
|
|
b2e2c27775 | ||
|
|
8e45d5e137 | ||
|
|
1ded7cd4f1 | ||
|
|
8bd2411a89 | ||
|
|
907fba7d0f | ||
|
|
bb5afc43b9 | ||
|
|
a243c9d685 | ||
|
|
829eeb2374 | ||
|
|
338de4ffa1 | ||
|
|
c7fbd6c64c | ||
|
|
95b7ae3146 | ||
|
|
ded48fd453 | ||
|
|
cbe2cf8a85 | ||
|
|
a12dc5c81b | ||
|
|
db062154d1 | ||
|
|
ac3a6426e8 | ||
|
|
f1f5b57254 | ||
|
|
3403e8af9b | ||
|
|
19286db952 | ||
|
|
40234e5b4a | ||
|
|
a9f046609c | ||
|
|
f2e2672e81 | ||
|
|
784f2674a9 | ||
|
|
93399165e7 | ||
|
|
7422485817 | ||
|
|
2ef19f31db | ||
|
|
8154209eab | ||
|
|
d56fb374a7 | ||
|
|
7bad1d2921 | ||
|
|
37dd494abd | ||
|
|
a9748e1b52 | ||
|
|
cc33101923 | ||
|
|
31fbbb52a8 | ||
|
|
d2c5665a30 | ||
|
|
06744ee7fb | ||
|
|
3e1db453ff | ||
|
|
ec76186c23 | ||
|
|
fcf975a65c | ||
|
|
e6d2c7db88 | ||
|
|
d012268953 | ||
|
|
70b797cb6d | ||
|
|
28d7cf38c8 | ||
|
|
6094fa7b6d | ||
|
|
8f3b7ee522 | ||
|
|
74f6fb7408 | ||
|
|
4ccb735282 | ||
|
|
b94631c84a | ||
|
|
2544e4fd65 | ||
|
|
7454a7a6f3 | ||
|
|
13e262b9cf | ||
|
|
b4db9d8b7d | ||
|
|
14ad5ced78 | ||
|
|
b2e592bb41 | ||
|
|
1a3281a959 | ||
|
|
6701c58a10 | ||
|
|
80fd0db2eb | ||
|
|
7ca8c5c16d | ||
|
|
3ed7cc5cab | ||
|
|
0987ae05a8 | ||
|
|
3154149d37 | ||
|
|
6f46109617 | ||
|
|
b0896408d2 | ||
|
|
243b478b99 | ||
|
|
fabbad2b2c | ||
|
|
1948ffe7bd | ||
|
|
67baee60f8 | ||
|
|
8f4c4715e2 | ||
|
|
3e7cbe6015 | ||
|
|
0053bde668 | ||
|
|
363dd31768 | ||
|
|
f841737adc | ||
|
|
9adaa7972e | ||
|
|
ec387f9bb7 | ||
|
|
aa657776fc | ||
|
|
f12632a1f2 | ||
|
|
4f8164dc43 | ||
|
|
88303d8855 | ||
|
|
4e8ddafa64 | ||
|
|
1ebe9d2bba | ||
|
|
fbae619725 | ||
|
|
8c5f4c3de7 | ||
|
|
154841157f | ||
|
|
6a20d06194 | ||
|
|
245e118016 | ||
|
|
fcc9d6749c | ||
|
|
9e091c5015 | ||
|
|
01247319c3 | ||
|
|
1d3d5f7e32 | ||
|
|
49f2cef5ac | ||
|
|
926d165321 | ||
|
|
86218445cd | ||
|
|
6e0f695699 | ||
|
|
7b9ff7776d | ||
|
|
e0f3f53d42 | ||
|
|
2e911ee709 | ||
|
|
43afed6654 | ||
|
|
0dda8328af | ||
|
|
48052fc3e4 | ||
|
|
5ac5fed513 | ||
|
|
60521e8167 | ||
|
|
510568d4f1 | ||
|
|
3e3ec3134d | ||
|
|
c22374893e | ||
|
|
013eaeeb07 | ||
|
|
b97b6867d8 | ||
|
|
87f31ec532 | ||
|
|
9b12695443 | ||
|
|
cbb40c1c2b | ||
|
|
b0e56fc27b | ||
|
|
d15532227d | ||
|
|
c3f98e95ad | ||
|
|
e92e99d6ea | ||
|
|
f6b67f6c98 | ||
|
|
108861b6ca | ||
|
|
80d93e8d75 | ||
|
|
1634cd53be | ||
|
|
577df3749d | ||
|
|
73c53b3da6 | ||
|
|
9af996a907 | ||
|
|
bd2e4a8076 | ||
|
|
ceaa6a592c | ||
|
|
b503fecccb | ||
|
|
4161055cc7 | ||
|
|
b0c9a3bbe1 | ||
|
|
436bdde461 | ||
|
|
01853064b0 | ||
|
|
c1ccb5af0f | ||
|
|
706f04ee27 | ||
|
|
549e35e972 | ||
|
|
1ed66966a8 | ||
|
|
326539f1f5 | ||
|
|
67322ba39f | ||
|
|
41fcc41bd1 | ||
|
|
7aacff62ca | ||
|
|
4566ddb037 | ||
|
|
957e6b1500 | ||
|
|
5945635d1d | ||
|
|
045fc0914b | ||
|
|
72442871aa | ||
|
|
bbd3c03969 | ||
|
|
a4405c3d39 | ||
|
|
0fe4f587d8 | ||
|
|
d3c714bd17 | ||
|
|
c399b7a7d5 | ||
|
|
b9234e94fb | ||
|
|
417bb87785 | ||
|
|
0233ae3134 | ||
|
|
eed0c5dd59 | ||
|
|
2b3b167095 | ||
|
|
5d91d19808 | ||
|
|
0f374ddee9 | ||
|
|
a65a9913cd | ||
|
|
1ead32c666 | ||
|
|
d1af9fc780 | ||
|
|
0f06737fb6 | ||
|
|
1676231532 | ||
|
|
b1caf697c8 | ||
|
|
51481065fe | ||
|
|
e367da710c | ||
|
|
f493d6524d | ||
|
|
e1b85da2a7 | ||
|
|
22c6548ed1 | ||
|
|
afb32c087d | ||
|
|
bbc1ed1c64 | ||
|
|
3a46f1a27a | ||
|
|
90cd364780 | ||
|
|
6795e6f078 | ||
|
|
cfb3404349 | ||
|
|
0212f3ee78 | ||
|
|
6b2995a4ee | ||
|
|
09e7ac54d4 | ||
|
|
f69009d4a8 | ||
|
|
206802ae33 | ||
|
|
91d4138fb8 | ||
|
|
cb455f951a | ||
|
|
5f25d20cd0 | ||
|
|
1f0e2cd910 | ||
|
|
1749d02701 | ||
|
|
55ace3179c | ||
|
|
7866d9ccb4 | ||
|
|
51f73d07fa | ||
|
|
63d84674ab | ||
|
|
14066997b2 | ||
|
|
28561e765a | ||
|
|
453fbbdc5d | ||
|
|
1e1e5ec10d | ||
|
|
2088b0e459 | ||
|
|
58400d9e01 | ||
|
|
ac9375f1d2 | ||
|
|
db061c9355 | ||
|
|
d5ce6c464b | ||
|
|
b06205bb7f | ||
|
|
f528a3e1de | ||
|
|
bddfdacfad | ||
|
|
d3cdd3f235 | ||
|
|
41ae45ea40 | ||
|
|
657e0895ea | ||
|
|
b2592d1cc2 | ||
|
|
aa3524c3b2 | ||
|
|
39deb1a05f | ||
|
|
302d08e290 | ||
|
|
05489dd7f1 | ||
|
|
55bd076602 | ||
|
|
7a224fe08f | ||
|
|
3bdeb82097 | ||
|
|
f49ab3f919 | ||
|
|
42d5bdd3ab | ||
|
|
7228cbfe92 | ||
|
|
11e2fc5bc4 | ||
|
|
3e88f820b8 | ||
|
|
163750f8c2 | ||
|
|
4aabc5d791 | ||
|
|
c9a7b9dcc1 | ||
|
|
98075b5653 | ||
|
|
57ae5be916 | ||
|
|
8caf62997f | ||
|
|
f8656ad376 | ||
|
|
29c6c2a2ad | ||
|
|
f2db67ef02 | ||
|
|
72b8ef33d9 |
@@ -4,16 +4,26 @@ jobs:
|
|||||||
build:
|
build:
|
||||||
resource_class: medium+
|
resource_class: medium+
|
||||||
docker:
|
docker:
|
||||||
- image: nikolaik/python-nodejs:python3.7-nodejs10
|
- image: nikolaik/python-nodejs:python3.7-nodejs8
|
||||||
environment:
|
environment:
|
||||||
CONTRACTS_COMMIT_HASH: '9ed05f5'
|
CONTRACTS_COMMIT_HASH: '9ed05f5'
|
||||||
working_directory: ~/repo
|
working_directory: ~/repo
|
||||||
steps:
|
steps:
|
||||||
- checkout
|
- checkout
|
||||||
- run: echo 'export PATH=$HOME/CIRCLE_PROJECT_REPONAME/node_modules/.bin:$PATH' >> $BASH_ENV
|
- run: echo 'export PATH=$HOME/CIRCLE_PROJECT_REPONAME/node_modules/.bin:$PATH' >> $BASH_ENV
|
||||||
|
# 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:
|
- run:
|
||||||
name: install-yarn
|
name: install-yarn
|
||||||
command: npm install --force --global yarn@1.17.0
|
command: npm install --global yarn@1.17.0
|
||||||
- run:
|
- run:
|
||||||
name: yarn
|
name: yarn
|
||||||
command: yarn --frozen-lockfile --ignore-engines install || yarn --frozen-lockfile --ignore-engines install
|
command: yarn --frozen-lockfile --ignore-engines install || yarn --frozen-lockfile --ignore-engines install
|
||||||
@@ -27,114 +37,255 @@ jobs:
|
|||||||
- store_artifacts:
|
- store_artifacts:
|
||||||
path: ~/repo/packages/abi-gen/test-cli/output
|
path: ~/repo/packages/abi-gen/test-cli/output
|
||||||
- store_artifacts:
|
- store_artifacts:
|
||||||
path: ~/repo/packages/contract-wrappers/generated_docs
|
path: ~/repo/packages/abi-gen-wrappers/generated_docs
|
||||||
test-exchange-ganache:
|
test-contracts-ganache:
|
||||||
resource_class: medium+
|
resource_class: medium+
|
||||||
docker:
|
docker:
|
||||||
- image: nikolaik/python-nodejs:python3.7-nodejs10
|
- image: nikolaik/python-nodejs:python3.7-nodejs8
|
||||||
working_directory: ~/repo
|
working_directory: ~/repo
|
||||||
steps:
|
steps:
|
||||||
- restore_cache:
|
- restore_cache:
|
||||||
keys:
|
keys:
|
||||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||||
- run: yarn wsrun test:circleci @0x/contracts-exchange
|
- run: yarn wsrun test:circleci @0x/contracts-multisig @0x/contracts-utils @0x/contracts-exchange-libs @0x/contracts-erc20 @0x/contracts-erc721 @0x/contracts-erc1155 @0x/contracts-extensions @0x/contracts-asset-proxy @0x/contracts-exchange @0x/contracts-exchange-forwarder @0x/contracts-coordinator @0x/contracts-dev-utils
|
||||||
test-integrations-ganache:
|
test-contracts-geth:
|
||||||
resource_class: medium+
|
|
||||||
docker:
|
docker:
|
||||||
- image: nikolaik/python-nodejs:python3.7-nodejs10
|
- image: nikolaik/python-nodejs:python3.7-nodejs8
|
||||||
|
- image: 0xorg/devnet
|
||||||
working_directory: ~/repo
|
working_directory: ~/repo
|
||||||
steps:
|
steps:
|
||||||
- restore_cache:
|
- restore_cache:
|
||||||
keys:
|
keys:
|
||||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||||
- run: yarn wsrun test:circleci @0x/contracts-integrations
|
# HACK(albrow): we need to sleep 10 seconds to ensure the devnet is
|
||||||
test-contracts-staking-ganache:
|
# initialized
|
||||||
resource_class: medium+
|
- run: sleep 10 && TEST_PROVIDER=geth yarn wsrun test:circleci @0x/contracts-multisig @0x/contracts-utils @0x/contracts-exchange-libs @0x/contracts-erc20 @0x/contracts-erc721 @0x/contracts-erc1155 @0x/contracts-extensions @0x/contracts-asset-proxy @0x/contracts-exchange @0x/contracts-exchange-forwarder @0x/contracts-coordinator @0x/contracts-dev-utils
|
||||||
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-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:
|
test-publish:
|
||||||
resource_class: medium+
|
resource_class: medium+
|
||||||
docker:
|
docker:
|
||||||
- image: nikolaik/python-nodejs:python3.7-nodejs10
|
- image: nikolaik/python-nodejs:python3.7-nodejs8
|
||||||
- image: 0xorg/verdaccio
|
- image: 0xorg/verdaccio
|
||||||
working_directory: ~/repo
|
working_directory: ~/repo
|
||||||
steps:
|
steps:
|
||||||
- restore_cache:
|
- restore_cache:
|
||||||
keys:
|
keys:
|
||||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||||
- run:
|
- run: yarn test:publish:circleci
|
||||||
command: yarn test:publish:circleci
|
|
||||||
no_output_timeout: 1800
|
|
||||||
- store_artifacts:
|
|
||||||
path: ~/.npm/_logs
|
|
||||||
test-doc-generation:
|
test-doc-generation:
|
||||||
docker:
|
docker:
|
||||||
- image: nikolaik/python-nodejs:python3.7-nodejs10
|
- image: nikolaik/python-nodejs:python3.7-nodejs8
|
||||||
working_directory: ~/repo
|
working_directory: ~/repo
|
||||||
steps:
|
steps:
|
||||||
- restore_cache:
|
- restore_cache:
|
||||||
keys:
|
keys:
|
||||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||||
- run:
|
- run: yarn test:generate_docs:circleci
|
||||||
command: yarn test:generate_docs:circleci
|
|
||||||
no_output_timeout: 1200
|
|
||||||
test-rest:
|
test-rest:
|
||||||
docker:
|
docker:
|
||||||
- image: nikolaik/python-nodejs:python3.7-nodejs10
|
- image: nikolaik/python-nodejs:python3.7-nodejs8
|
||||||
working_directory: ~/repo
|
working_directory: ~/repo
|
||||||
steps:
|
steps:
|
||||||
- restore_cache:
|
- restore_cache:
|
||||||
keys:
|
keys:
|
||||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||||
- run: yarn wsrun test:circleci @0x/contracts-test-utils
|
- run: yarn wsrun test:circleci @0x/contracts-test-utils
|
||||||
|
- run: yarn wsrun test:circleci @0x/abi-gen
|
||||||
|
- run: yarn wsrun test:circleci @0x/asset-buyer
|
||||||
- run: yarn wsrun test:circleci @0x/contract-artifacts
|
- run: yarn wsrun test:circleci @0x/contract-artifacts
|
||||||
- run: yarn wsrun test:circleci @0x/contract-wrappers-test
|
- run: yarn wsrun test:circleci @0x/assert
|
||||||
- run: yarn wsrun test:circleci @0x/migrations
|
- run: yarn wsrun test:circleci @0x/base-contract
|
||||||
|
- 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/order-utils
|
- run: yarn wsrun test:circleci @0x/order-utils
|
||||||
- run: yarn wsrun test:circleci @0x/asset-swapper
|
- 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
|
||||||
- save_cache:
|
- save_cache:
|
||||||
key: coverage-contract-wrappers-test-{{ .Environment.CIRCLE_SHA1 }}
|
key: coverage-abi-gen-{{ .Environment.CIRCLE_SHA1 }}
|
||||||
paths:
|
paths:
|
||||||
- ~/repo/packages/contract-wrappers-test/coverage/lcov.info
|
- ~/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
|
||||||
- save_cache:
|
- save_cache:
|
||||||
key: coverage-order-utils-{{ .Environment.CIRCLE_SHA1 }}
|
key: coverage-order-utils-{{ .Environment.CIRCLE_SHA1 }}
|
||||||
paths:
|
paths:
|
||||||
- ~/repo/packages/order-utils/coverage/lcov.info
|
- ~/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:
|
- save_cache:
|
||||||
key: coverage-web3-wrapper-{{ .Environment.CIRCLE_SHA1 }}
|
key: coverage-web3-wrapper-{{ .Environment.CIRCLE_SHA1 }}
|
||||||
paths:
|
paths:
|
||||||
- ~/repo/packages/web3-wrapper/coverage/lcov.info
|
- ~/repo/packages/web3-wrapper/coverage/lcov.info
|
||||||
|
test-python:
|
||||||
|
working_directory: ~/repo
|
||||||
|
docker:
|
||||||
|
- image: nikolaik/python-nodejs:python3.7-nodejs8
|
||||||
|
- image: 0xorg/ganache-cli:2.2.2
|
||||||
|
- image: 0xorg/launch-kit-backend:74bcc39
|
||||||
|
environment:
|
||||||
|
RPC_URL: http://localhost:8545
|
||||||
|
NETWORK_ID: 50
|
||||||
|
WHITELIST_ALL_TOKENS: True
|
||||||
|
command: |
|
||||||
|
sh -c "until printf 'POST /\r\nContent-Length: 26\r\n\r\n{\"method\":\"net_listening\"}' | nc localhost 8545 | grep true; do continue; done; 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_without_sra_client coverage run setup.py test
|
||||||
|
./build_docs
|
||||||
|
- 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_wrappers/src/zero_ex/contract_wrappers/*/__init__.py
|
||||||
|
- 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:
|
static-tests:
|
||||||
resource_class: large
|
resource_class: large
|
||||||
working_directory: ~/repo
|
working_directory: ~/repo
|
||||||
docker:
|
docker:
|
||||||
- image: nikolaik/python-nodejs:python3.7-nodejs10
|
- image: nikolaik/python-nodejs:python3.7-nodejs8
|
||||||
steps:
|
steps:
|
||||||
- restore_cache:
|
- restore_cache:
|
||||||
keys:
|
keys:
|
||||||
@@ -143,9 +294,11 @@ jobs:
|
|||||||
- run: yarn prettier:ci
|
- run: yarn prettier:ci
|
||||||
- run: yarn deps_versions:ci
|
- run: yarn deps_versions:ci
|
||||||
- run: yarn diff_md_docs:ci
|
- run: yarn diff_md_docs:ci
|
||||||
|
- run: cd packages/0x.js && yarn build:umd:prod
|
||||||
|
- run: yarn bundlewatch
|
||||||
submit-coverage:
|
submit-coverage:
|
||||||
docker:
|
docker:
|
||||||
- image: nikolaik/python-nodejs:python3.7-nodejs10
|
- image: nikolaik/python-nodejs:python3.7-nodejs8
|
||||||
working_directory: ~/repo
|
working_directory: ~/repo
|
||||||
steps:
|
steps:
|
||||||
- restore_cache:
|
- restore_cache:
|
||||||
@@ -153,35 +306,81 @@ jobs:
|
|||||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||||
- restore_cache:
|
- restore_cache:
|
||||||
keys:
|
keys:
|
||||||
- coverage-contract-wrappers-test-{{ .Environment.CIRCLE_SHA1 }}
|
- 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 }}
|
||||||
- restore_cache:
|
- restore_cache:
|
||||||
keys:
|
keys:
|
||||||
- coverage-order-utils-{{ .Environment.CIRCLE_SHA1 }}
|
- 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:
|
- restore_cache:
|
||||||
keys:
|
keys:
|
||||||
- coverage-contracts-{{ .Environment.CIRCLE_SHA1 }}
|
- 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
|
- run: yarn report_coverage
|
||||||
workflows:
|
workflows:
|
||||||
version: 2
|
version: 2
|
||||||
main:
|
main:
|
||||||
jobs:
|
jobs:
|
||||||
- build
|
- build
|
||||||
# Disabled until we begin actively developing on these packages again.
|
- test-contracts-ganache:
|
||||||
# - 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:
|
requires:
|
||||||
- build
|
- build
|
||||||
|
# TODO(albrow): Tests always fail on Geth right now because our fork
|
||||||
|
# is outdated. Uncomment once we have updated our Geth fork.
|
||||||
|
# - test-contracts-geth:
|
||||||
|
# requires:
|
||||||
|
# - build
|
||||||
- test-rest:
|
- test-rest:
|
||||||
requires:
|
requires:
|
||||||
- build
|
- build
|
||||||
@@ -194,14 +393,15 @@ workflows:
|
|||||||
- test-doc-generation:
|
- test-doc-generation:
|
||||||
requires:
|
requires:
|
||||||
- build
|
- build
|
||||||
# Disabled until this repo has a coveralls API key
|
- submit-coverage:
|
||||||
# - submit-coverage:
|
requires:
|
||||||
# requires:
|
- test-rest
|
||||||
# # Disabled until we begin actively developing on these packages again.
|
- test-python
|
||||||
# # - test-exchange-ganache
|
- static-tests-python:
|
||||||
# # - test-integrations-ganache
|
requires:
|
||||||
# # - test-contracts-staking-ganache
|
- test-python
|
||||||
# # - test-contracts-extra-ganache
|
- test-python:
|
||||||
# - test-contracts-rest-ganache
|
requires:
|
||||||
# - test-rest
|
- build
|
||||||
# - static-tests
|
# skip python tox run for now, as we don't yet have multiple test environments to support.
|
||||||
|
#- test-rest-python
|
||||||
|
|||||||
4
.gitattributes
vendored
4
.gitattributes
vendored
@@ -2,3 +2,7 @@
|
|||||||
|
|
||||||
# Automatically collapse generated files in GitHub.
|
# Automatically collapse generated files in GitHub.
|
||||||
*.svg linguist-generated=true
|
*.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
|
||||||
|
|
||||||
|
|||||||
30
.github/autolabeler.yml
vendored
30
.github/autolabeler.yml
vendored
@@ -1,7 +1,37 @@
|
|||||||
python: ['python-packages']
|
python: ['python-packages']
|
||||||
contracts: ['contracts']
|
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/contract-addresses: ['packages/contract-addresses']
|
||||||
@0x/migrations: ['packages/migrations']
|
@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/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/contract-artifacts: ['packages/contract-artifacts']
|
||||||
|
@0x/dev-utils: ['packages/dev-utils']
|
||||||
@0x/contract-wrappers: ['packages/contract-wrappers']
|
@0x/contract-wrappers: ['packages/contract-wrappers']
|
||||||
|
@0x/json-schemas: ['packages/json-schemas']
|
||||||
|
@0x/ethereum-types: ['ethereum-types']
|
||||||
|
@0x/connect: ['packages/connect']
|
||||||
|
@0x/fill-scenarios: ['packages/fill-scenarios']
|
||||||
|
@0x/testnet-faucets: ['packages/testnet-faucets']
|
||||||
|
@0x/monorepo-scripts: ['packages/monorepo-scripts']
|
||||||
|
|||||||
48
.github/workflows/publish.yml
vendored
48
.github/workflows/publish.yml
vendored
@@ -1,48 +0,0 @@
|
|||||||
name: publish
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
ci_status:
|
|
||||||
description: 'required CI status'
|
|
||||||
default: 'success'
|
|
||||||
required: true
|
|
||||||
|
|
||||||
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: 'development'
|
|
||||||
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 }}
|
|
||||||
- name: 'merge into main branch'
|
|
||||||
run: |
|
|
||||||
git checkout main && \
|
|
||||||
git merge ${{ github.ref }} && \
|
|
||||||
git push
|
|
||||||
129
.gitignore
vendored
129
.gitignore
vendored
@@ -78,100 +78,77 @@ TODO.md
|
|||||||
# VSCode file
|
# VSCode file
|
||||||
.vscode
|
.vscode
|
||||||
|
|
||||||
# generated contract artifacts/
|
# server cli
|
||||||
contracts/broker/generated-artifacts/
|
packages/testnet-faucets/server/
|
||||||
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/
|
|
||||||
contracts/dev-utils/test/generated-artifacts/
|
|
||||||
contracts/zero-ex/generated-artifacts/
|
|
||||||
contracts/zero-ex/test/generated-artifacts/
|
|
||||||
|
|
||||||
# generated truffle contract artifacts/
|
# generated contract artifacts/
|
||||||
contracts/broker/build/
|
contracts/coordinator/generated-artifacts/
|
||||||
contracts/erc20-bridge-sampler/build/
|
contracts/exchange/generated-artifacts/
|
||||||
contracts/staking/build/
|
contracts/asset-proxy/generated-artifacts/
|
||||||
contracts/coordinator/build/
|
contracts/multisig/generated-artifacts/
|
||||||
contracts/exchange/build/
|
contracts/utils/generated-artifacts/
|
||||||
contracts/asset-proxy/build/
|
contracts/exchange-libs/generated-artifacts/
|
||||||
contracts/multisig/build/
|
contracts/erc20/generated-artifacts/
|
||||||
contracts/utils/build/
|
contracts/erc721/generated-artifacts/
|
||||||
contracts/exchange-libs/build/
|
contracts/erc1155/generated-artifacts/
|
||||||
contracts/erc20/build/
|
contracts/extensions/generated-artifacts/
|
||||||
contracts/erc721/build/
|
contracts/exchange-forwarder/generated-artifacts/
|
||||||
contracts/erc1155/build/
|
contracts/dev-utils/generated-artifacts/
|
||||||
contracts/extensions/build/
|
packages/sol-tracing-utils/test/fixtures/artifacts/
|
||||||
contracts/exchange-forwarder/build/
|
python-packages/contract_artifacts/src/zero_ex/contract_artifacts/artifacts/
|
||||||
contracts/dev-utils/build/
|
|
||||||
|
|
||||||
# generated contract wrappers
|
# generated contract wrappers
|
||||||
contracts/broker/generated-wrappers/
|
|
||||||
contracts/broker/test/generated-wrappers/
|
|
||||||
packages/python-contract-wrappers/generated/
|
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/generated-wrappers/
|
||||||
contracts/coordinator/test/generated-wrappers/
|
|
||||||
contracts/exchange/generated-wrappers/
|
contracts/exchange/generated-wrappers/
|
||||||
contracts/exchange/test/generated-wrappers/
|
|
||||||
contracts/asset-proxy/generated-wrappers/
|
contracts/asset-proxy/generated-wrappers/
|
||||||
contracts/asset-proxy/test/generated-wrappers/
|
|
||||||
contracts/multisig/generated-wrappers/
|
contracts/multisig/generated-wrappers/
|
||||||
contracts/multisig/test/generated-wrappers/
|
|
||||||
contracts/utils/generated-wrappers/
|
contracts/utils/generated-wrappers/
|
||||||
contracts/utils/test/generated-wrappers/
|
|
||||||
contracts/exchange-libs/generated-wrappers/
|
contracts/exchange-libs/generated-wrappers/
|
||||||
contracts/exchange-libs/test/generated-wrappers/
|
|
||||||
contracts/erc20/generated-wrappers/
|
contracts/erc20/generated-wrappers/
|
||||||
contracts/erc20/test/generated-wrappers/
|
|
||||||
contracts/erc721/generated-wrappers/
|
contracts/erc721/generated-wrappers/
|
||||||
contracts/erc721/test/generated-wrappers/
|
|
||||||
contracts/erc1155/generated-wrappers/
|
contracts/erc1155/generated-wrappers/
|
||||||
contracts/erc1155/test/generated-wrappers/
|
|
||||||
contracts/extensions/generated-wrappers/
|
contracts/extensions/generated-wrappers/
|
||||||
contracts/extensions/test/generated-wrappers/
|
|
||||||
contracts/exchange-forwarder/generated-wrappers/
|
contracts/exchange-forwarder/generated-wrappers/
|
||||||
contracts/exchange-forwarder/test/generated-wrappers/
|
|
||||||
contracts/dev-utils/generated-wrappers/
|
contracts/dev-utils/generated-wrappers/
|
||||||
contracts/dev-utils/test/generated-wrappers/
|
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/erc20_token/__init__.py
|
||||||
contracts/zero-ex/generated-wrappers/
|
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/exchange/__init__.py
|
||||||
contracts/zero-ex/test/generated-wrappers/
|
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/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/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
|
||||||
|
python-packages/json_schemas/src/zero_ex/json_schemas/schemas
|
||||||
|
|
||||||
# Doc README copy
|
# Doc README copy
|
||||||
packages/*/docs/README.md
|
packages/*/docs/README.md
|
||||||
|
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|
||||||
# the snapshot that gets built for migrations sure does have a ton of files
|
|
||||||
packages/migrations/0x_ganache_snapshot*
|
|
||||||
|
|||||||
@@ -1,86 +1,40 @@
|
|||||||
lib
|
lib
|
||||||
.nyc_output
|
.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/generated-wrappers
|
||||||
/contracts/coordinator/test/generated-wrappers
|
|
||||||
/contracts/coordinator/generated-artifacts
|
/contracts/coordinator/generated-artifacts
|
||||||
/contracts/coordinator/test/generated-artifacts
|
|
||||||
/contracts/exchange/generated-wrappers
|
/contracts/exchange/generated-wrappers
|
||||||
/contracts/exchange/test/generated-wrappers
|
|
||||||
/contracts/exchange/generated-artifacts
|
/contracts/exchange/generated-artifacts
|
||||||
/contracts/exchange/test/generated-artifacts
|
|
||||||
/contracts/asset-proxy/generated-wrappers
|
/contracts/asset-proxy/generated-wrappers
|
||||||
/contracts/asset-proxy/test/generated-wrappers
|
|
||||||
/contracts/asset-proxy/generated-artifacts
|
/contracts/asset-proxy/generated-artifacts
|
||||||
/contracts/asset-proxy/test/generated-artifacts
|
|
||||||
/contracts/multisig/generated-wrappers
|
/contracts/multisig/generated-wrappers
|
||||||
/contracts/multisig/test/generated-wrappers
|
|
||||||
/contracts/multisig/generated-artifacts
|
/contracts/multisig/generated-artifacts
|
||||||
/contracts/multisig/test/generated-artifacts
|
|
||||||
/contracts/utils/generated-wrappers
|
/contracts/utils/generated-wrappers
|
||||||
/contracts/utils/test/generated-wrappers
|
|
||||||
/contracts/utils/generated-artifacts
|
/contracts/utils/generated-artifacts
|
||||||
/contracts/utils/test/generated-artifacts
|
|
||||||
/contracts/exchange-libs/generated-wrappers
|
/contracts/exchange-libs/generated-wrappers
|
||||||
/contracts/exchange-libs/test/generated-wrappers
|
|
||||||
/contracts/exchange-libs/generated-artifacts
|
/contracts/exchange-libs/generated-artifacts
|
||||||
/contracts/exchange-libs/test/generated-artifacts
|
|
||||||
/contracts/erc20/generated-wrappers
|
/contracts/erc20/generated-wrappers
|
||||||
/contracts/erc20/test/generated-wrappers
|
|
||||||
/contracts/erc20/generated-artifacts
|
/contracts/erc20/generated-artifacts
|
||||||
/contracts/erc20/test/generated-artifacts
|
|
||||||
/contracts/erc721/generated-wrappers
|
/contracts/erc721/generated-wrappers
|
||||||
/contracts/erc721/test/generated-wrappers
|
|
||||||
/contracts/erc721/generated-artifacts
|
/contracts/erc721/generated-artifacts
|
||||||
/contracts/erc721/test/generated-artifacts
|
|
||||||
/contracts/erc1155/generated-wrappers
|
/contracts/erc1155/generated-wrappers
|
||||||
/contracts/erc1155/test/generated-wrappers
|
|
||||||
/contracts/erc1155/generated-artifacts
|
/contracts/erc1155/generated-artifacts
|
||||||
/contracts/erc1155/test/generated-artifacts
|
|
||||||
/contracts/extensions/generated-wrappers
|
/contracts/extensions/generated-wrappers
|
||||||
/contracts/extensions/test/generated-wrappers
|
|
||||||
/contracts/extensions/generated-artifacts
|
/contracts/extensions/generated-artifacts
|
||||||
/contracts/extensions/test/generated-artifacts
|
|
||||||
/contracts/exchange-forwarder/generated-wrappers
|
/contracts/exchange-forwarder/generated-wrappers
|
||||||
/contracts/exchange-forwarder/test/generated-wrappers
|
|
||||||
/contracts/exchange-forwarder/generated-artifacts
|
/contracts/exchange-forwarder/generated-artifacts
|
||||||
/contracts/exchange-forwarder/test/generated-artifacts
|
|
||||||
/contracts/dev-utils/generated-wrappers
|
/contracts/dev-utils/generated-wrappers
|
||||||
/contracts/dev-utils/test/generated-wrappers
|
|
||||||
/contracts/dev-utils/generated-artifacts
|
/contracts/dev-utils/generated-artifacts
|
||||||
/contracts/dev-utils/test/generated-artifacts
|
/packages/abi-gen/test-cli/output
|
||||||
/contracts/zero-ex/generated-wrappers
|
/packages/json-schemas/schemas
|
||||||
/contracts/zero-ex/test/generated-wrappers
|
/python-packages/json_schemas/src/zero_ex/json_schemas/schemas
|
||||||
/contracts/zero-ex/generated-artifacts
|
/packages/sra-spec/public/
|
||||||
/contracts/zero-ex/test/generated-artifacts
|
|
||||||
/contracts/staking/build/
|
|
||||||
/contracts/coordinator/build/
|
|
||||||
/contracts/exchange/build/
|
|
||||||
/contracts/asset-proxy/build/
|
|
||||||
/contracts/multisig/build/
|
|
||||||
/contracts/utils/build/
|
|
||||||
/contracts/exchange-libs/build/
|
|
||||||
/contracts/erc20/build/
|
|
||||||
/contracts/erc721/build/
|
|
||||||
/contracts/erc1155/build/
|
|
||||||
/contracts/extensions/build/
|
|
||||||
/contracts/exchange-forwarder/build/
|
|
||||||
/packages/asset-swapper/generated-artifacts
|
|
||||||
/packages/asset-swapper/generated-wrappers
|
|
||||||
/packages/asset-swapper/test/generated-artifacts
|
|
||||||
/packages/asset-swapper/test/generated-wrappers
|
|
||||||
package.json
|
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
|
packages/*/docs
|
||||||
docs/
|
|
||||||
*.sol
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
{
|
{
|
||||||
"printWidth": 120,
|
|
||||||
"tabWidth": 4,
|
"tabWidth": 4,
|
||||||
"singleQuote": true,
|
"printWidth": 120,
|
||||||
"trailingComma": "all",
|
"trailingComma": all,
|
||||||
"bracketSpacing": true
|
"singleQuote": true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
# 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,14 +5,34 @@
|
|||||||
# https://git-scm.com/docs/gitignore#_pattern_format
|
# https://git-scm.com/docs/gitignore#_pattern_format
|
||||||
|
|
||||||
# Website
|
# Website
|
||||||
packages/asset-swapper/ @BMillman19 @fragosti @dave4506
|
packages/asset-buyer/ @BMillman19 @fragosti @steveklebanoff
|
||||||
packages/instant/ @BMillman19 @fragosti @dave4506
|
packages/instant/ @BMillman19 @fragosti @steveklebanoff
|
||||||
|
|
||||||
# Dev tools & setup
|
# Dev tools & setup
|
||||||
.circleci/ @dorothy-zbornak
|
.circleci/ @LogvinovLeon
|
||||||
packages/contract-addresses/ @abandeali1
|
packages/abi-gen/ @feuGeneA
|
||||||
packages/contract-artifacts/ @abandeali1
|
packages/base-contract/ @xianny
|
||||||
packages/order-utils/ @dorothy-zbornak
|
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
|
||||||
|
|
||||||
# Protocol/smart contracts
|
# Protocol/smart contracts
|
||||||
contracts/ @abandeali1 @hysz @dorothy-zbornak @mzhu25
|
contracts/ @abandeali1 @hysz
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ We welcome contributions from anyone on the internet and are grateful for even t
|
|||||||
|
|
||||||
### Getting started
|
### Getting started
|
||||||
|
|
||||||
1. Fork `0xproject/0x-tools`
|
1. Fork `0xproject/0x-monorepo`
|
||||||
2. Clone your fork
|
2. Clone your fork
|
||||||
3. Follow the [installation & build steps](https://github.com/0xProject/0x-tools#install-dependencies) in the repo's top-level README.
|
3. Follow the [installation & build steps](https://github.com/0xProject/0x-monorepo#install-dependencies) in the repo's top-level README.
|
||||||
4. Setup the recommended [Development Tooling](#development-tooling).
|
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))
|
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
|
#### Linter
|
||||||
|
|
||||||
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.
|
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.
|
||||||
|
|
||||||
Use `yarn:lint` to lint the entire monorepo, and `PKG={PACKAGE_NAME} yarn lint` to lint a specific package.
|
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-tools/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-monorepo/tree/development/packages/tslint-config) package. All other packages have it as a dependency.
|
||||||
|
|
||||||
Integrate it into your text editor:
|
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
|
### 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-tools`, but when running the check against your fork the token needs to match your repo's name `your-username/0x-tools`.
|
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`.
|
||||||
|
|
||||||
To facilitate this check, after creating your fork, but before creating the branch for your PR, do the following:
|
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.
|
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-tools, 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-monorepo, 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.
|
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.
|
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 2020 ZeroEx Labs
|
Copyright 2017 ZeroEx Intl.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|||||||
81
README.md
81
README.md
@@ -8,7 +8,7 @@ This repository is a monorepo including the 0x protocol smart contracts and nume
|
|||||||
|
|
||||||
[website-url]: https://0x.org
|
[website-url]: https://0x.org
|
||||||
|
|
||||||
[](https://circleci.com/gh/0xProject/protocool)
|
[](https://circleci.com/gh/0xProject/0x-monorepo)
|
||||||
[](https://coveralls.io/github/0xProject/0x-monorepo?branch=development)
|
[](https://coveralls.io/github/0xProject/0x-monorepo?branch=development)
|
||||||
[](https://discordapp.com/invite/d3FTX3M)
|
[](https://discordapp.com/invite/d3FTX3M)
|
||||||
[](https://opensource.org/licenses/Apache-2.0)
|
[](https://opensource.org/licenses/Apache-2.0)
|
||||||
@@ -17,6 +17,17 @@ 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.
|
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
|
### Solidity Packages
|
||||||
|
|
||||||
These packages are all under development. See [/contracts/README.md](/contracts/README.md) for a list of deployed packages.
|
These packages are all under development. See [/contracts/README.md](/contracts/README.md) for a list of deployed packages.
|
||||||
@@ -36,19 +47,59 @@ These packages are all under development. See [/contracts/README.md](/contracts/
|
|||||||
| [`@0x/contracts-utils`](/contracts/utils) | [](https://www.npmjs.com/package/@0x/contracts-utils) | Generic libraries and utilities used throughout all of the contracts |
|
| [`@0x/contracts-utils`](/contracts/utils) | [](https://www.npmjs.com/package/@0x/contracts-utils) | Generic libraries and utilities used throughout all of the contracts |
|
||||||
| [`@0x/contracts-coordinator`](/contracts/coordinator) | [](https://www.npmjs.com/package/@0x/contracts-coordinator) | A contract that allows users to execute 0x transactions with permission from a Coordinator |
|
| [`@0x/contracts-coordinator`](/contracts/coordinator) | [](https://www.npmjs.com/package/@0x/contracts-coordinator) | A contract that allows users to execute 0x transactions with permission from a Coordinator |
|
||||||
| [`@0x/contracts-dev-utils`](/contracts/dev-utils) | [](https://www.npmjs.com/package/@0x/contracts-dev-utils) | A contract contains utility functions for developers (such as validating many orders using a single eth_call) |
|
| [`@0x/contracts-dev-utils`](/contracts/dev-utils) | [](https://www.npmjs.com/package/@0x/contracts-dev-utils) | A contract contains utility functions for developers (such as validating many orders using a single eth_call) |
|
||||||
| [`@0x/contracts-staking`](/contracts/staking) | [](https://www.npmjs.com/package/@0x/contracts-staking) | Implements the stake-based liquidity incentives defined by [`ZEIP-31`](https://github.com/0xProject/ZEIPs/issues/31) |
|
|
||||||
|
|
||||||
### TypeScript/Javascript Packages
|
### TypeScript/Javascript Packages
|
||||||
|
|
||||||
#### 0x-specific packages
|
#### 0x-specific packages
|
||||||
|
|
||||||
| Package | Version | Description |
|
| 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.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-wrappers`](/packages/contract-wrappers) | [](https://www.npmjs.com/package/@0x/contract-wrappers) | JS/TS wrappers for interacting with the 0x smart contracts |
|
| [`@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/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/contract-wrappers`](/packages/contract-wrappers) | [](https://www.npmjs.com/package/@0x/contract-wrappers) | JS/TS wrappers for interacting with the 0x smart contracts |
|
||||||
| [`@0x/migrations`](/packages/migrations) | [](https://www.npmjs.com/package/@0x/migrations) | Migration tool for deploying 0x smart contracts on private testnets |
|
| [`@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/contract-artifacts`](/packages/contract-artifacts) | [](https://www.npmjs.com/package/@0x/contract-artifacts) | 0x smart contract compilation artifacts | |
|
| [`@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 |
|
||||||
|
| [`@0x/fill-scenarios`](/packages/fill-scenarios) | [](https://www.npmjs.com/package/@0x/fill-scenarios) | 0x order fill scenario generator |
|
||||||
|
|
||||||
|
#### 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 |
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
@@ -81,6 +132,8 @@ Then install dependencies
|
|||||||
yarn install
|
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
|
### Build
|
||||||
|
|
||||||
To build all packages:
|
To build all packages:
|
||||||
@@ -92,7 +145,7 @@ yarn build
|
|||||||
To build a specific package:
|
To build a specific package:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
PKG=@0x/contract-wrappers yarn build
|
PKG=@0x/web3-wrapper yarn build
|
||||||
```
|
```
|
||||||
|
|
||||||
To build all contracts packages:
|
To build all contracts packages:
|
||||||
@@ -115,7 +168,7 @@ To watch a specific package and all it's dependent packages:
|
|||||||
PKG=[NPM_PACKAGE_NAME] yarn watch
|
PKG=[NPM_PACKAGE_NAME] yarn watch
|
||||||
|
|
||||||
e.g
|
e.g
|
||||||
PKG=@0x/contract-wrappers yarn watch
|
PKG=@0x/web3-wrapper yarn watch
|
||||||
```
|
```
|
||||||
|
|
||||||
### Clean
|
### Clean
|
||||||
@@ -143,7 +196,7 @@ yarn rebuild
|
|||||||
To re-build (clean & build) a specific package & it's deps:
|
To re-build (clean & build) a specific package & it's deps:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
PKG=@0x/contract-wrappers yarn rebuild
|
PKG=0x.js yarn rebuild
|
||||||
```
|
```
|
||||||
|
|
||||||
### Lint
|
### Lint
|
||||||
@@ -157,7 +210,7 @@ yarn lint
|
|||||||
Lint a specific package:
|
Lint a specific package:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
PKG=@0x/contract-wrappers yarn lint
|
PKG=0x.js yarn lint
|
||||||
```
|
```
|
||||||
|
|
||||||
### Run Tests
|
### Run Tests
|
||||||
@@ -171,7 +224,7 @@ yarn test
|
|||||||
Run a specific package's test:
|
Run a specific package's test:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
PKG=@0x/contract-wrappers yarn test
|
PKG=@0x/web3-wrapper yarn test
|
||||||
```
|
```
|
||||||
|
|
||||||
Run all contracts packages tests:
|
Run all contracts packages tests:
|
||||||
|
|||||||
@@ -13,11 +13,9 @@
|
|||||||
"indent": ["error", 4],
|
"indent": ["error", 4],
|
||||||
"max-line-length": ["warn", 160],
|
"max-line-length": ["warn", 160],
|
||||||
"no-inline-assembly": false,
|
"no-inline-assembly": false,
|
||||||
"no-empty-blocks": false,
|
|
||||||
"quotes": ["error", "double"],
|
"quotes": ["error", "double"],
|
||||||
"separate-by-one-line-in-contract": "error",
|
"separate-by-one-line-in-contract": "error",
|
||||||
"space-after-comma": "error",
|
"space-after-comma": "error",
|
||||||
"statement-indent": "error",
|
"statement-indent": "error"
|
||||||
"no-empty-blocks": false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,4 +13,4 @@
|
|||||||
|
|
||||||
#### Development
|
#### Development
|
||||||
|
|
||||||
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.
|
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.
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
# Blacklist all files
|
|
||||||
.*
|
|
||||||
*
|
|
||||||
# Whitelist lib
|
|
||||||
!lib/**/*
|
|
||||||
# Whitelist Solidity contracts
|
|
||||||
!contracts/src/**/*
|
|
||||||
# Blacklist tests in lib
|
|
||||||
/lib/test/*
|
|
||||||
# Package specific ignore
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
# solhint can't parse `abi.decode` syntax.
|
|
||||||
contracts/src/ERC1155Proxy.sol
|
|
||||||
@@ -1,509 +1,4 @@
|
|||||||
[
|
[
|
||||||
{
|
|
||||||
"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": [
|
|
||||||
{
|
|
||||||
"note": "ERC20Wrapper and ERC1155ProxyWrapper constructors now require an instance of DevUtilsContract",
|
|
||||||
"pr": 2034
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"timestamp": 1573159180
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"version": "2.3.0-beta.0",
|
|
||||||
"changes": [
|
|
||||||
{
|
|
||||||
"note": "Disallow the zero address from being made an authorized address in MixinAuthorizable, and created an archive directory that includes an old version of Ownable",
|
|
||||||
"pr": 2019
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"note": "Remove `LibAssetProxyIds` contract",
|
|
||||||
"pr": 2055
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"note": "Compile and export all contracts, artifacts, and wrappers by default",
|
|
||||||
"pr": 2055
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"note": "Remove unused dependency on IAuthorizable in IAssetProxy",
|
|
||||||
"pr": 1910
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"note": "Add `ERC20BridgeProxy`",
|
|
||||||
"pr": 2220
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"note": "Add `Eth2DaiBridge`",
|
|
||||||
"pr": 2221
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"note": "Add `UniswapBridge`",
|
|
||||||
"pr": 2233
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"note": "Replaced `SafeMath` with `LibSafeMath`",
|
|
||||||
"pr": 2254
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"timestamp": 1570135330
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"timestamp": 1568744790,
|
"timestamp": 1568744790,
|
||||||
"version": "2.2.8",
|
"version": "2.2.8",
|
||||||
@@ -628,18 +123,6 @@
|
|||||||
{
|
{
|
||||||
"note": "Update tests to use contract-built-in `awaitTransactionSuccessAsync`",
|
"note": "Update tests to use contract-built-in `awaitTransactionSuccessAsync`",
|
||||||
"pr": 1797
|
"pr": 1797
|
||||||
},
|
|
||||||
{
|
|
||||||
"note": "Make `ERC721Wrapper.setApprovalForAll()` take an owner address instead of a token ID",
|
|
||||||
"pr": 1819
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"note": "Automatically set unlimited proxy allowances in `ERC721.setBalancesAndAllowancesAsync()`",
|
|
||||||
"pr": 1819
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"note": "Add `setProxyAllowanceForAllAsync()` to `ERC1155ProxyWrapper`.",
|
|
||||||
"pr": 1819
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"timestamp": 1557507213
|
"timestamp": 1557507213
|
||||||
|
|||||||
@@ -5,194 +5,6 @@ Edit the package's CHANGELOG.json file only.
|
|||||||
|
|
||||||
CHANGELOG
|
CHANGELOG
|
||||||
|
|
||||||
## 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)
|
|
||||||
|
|
||||||
## v2.3.0-beta.0 - _October 3, 2019_
|
|
||||||
|
|
||||||
* Disallow the zero address from being made an authorized address in MixinAuthorizable, and created an archive directory that includes an old version of Ownable (#2019)
|
|
||||||
* Remove `LibAssetProxyIds` contract (#2055)
|
|
||||||
* Compile and export all contracts, artifacts, and wrappers by default (#2055)
|
|
||||||
* Remove unused dependency on IAuthorizable in IAssetProxy (#1910)
|
|
||||||
* Add `ERC20BridgeProxy` (#2220)
|
|
||||||
* Add `Eth2DaiBridge` (#2221)
|
|
||||||
* Add `UniswapBridge` (#2233)
|
|
||||||
* Replaced `SafeMath` with `LibSafeMath` (#2254)
|
|
||||||
|
|
||||||
## v2.2.8 - _September 17, 2019_
|
## v2.2.8 - _September 17, 2019_
|
||||||
|
|
||||||
* Dependencies updated
|
* Dependencies updated
|
||||||
@@ -246,9 +58,6 @@ CHANGELOG
|
|||||||
## v2.1.2 - _May 10, 2019_
|
## v2.1.2 - _May 10, 2019_
|
||||||
|
|
||||||
* Update tests to use contract-built-in `awaitTransactionSuccessAsync` (#1797)
|
* Update tests to use contract-built-in `awaitTransactionSuccessAsync` (#1797)
|
||||||
* Make `ERC721Wrapper.setApprovalForAll()` take an owner address instead of a token ID (#1819)
|
|
||||||
* Automatically set unlimited proxy allowances in `ERC721.setBalancesAndAllowancesAsync()` (#1819)
|
|
||||||
* Add `setProxyAllowanceForAllAsync()` to `ERC1155ProxyWrapper`. (#1819)
|
|
||||||
|
|
||||||
## v2.1.1 - _April 11, 2019_
|
## v2.1.1 - _April 11, 2019_
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
{
|
{
|
||||||
"artifactsDir": "./test/generated-artifacts",
|
"artifactsDir": "./generated-artifacts",
|
||||||
"contractsDir": "./contracts",
|
"contractsDir": "./contracts",
|
||||||
"useDockerisedSolc": false,
|
"useDockerisedSolc": false,
|
||||||
"isOfflineMode": false,
|
"isOfflineMode": false,
|
||||||
"shouldSaveStandardInput": true,
|
|
||||||
"compilerSettings": {
|
"compilerSettings": {
|
||||||
"evmVersion": "istanbul",
|
"evmVersion": "constantinople",
|
||||||
"optimizer": {
|
"optimizer": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"runs": 1000000,
|
"runs": 1000000,
|
||||||
@@ -23,5 +22,17 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"contracts": [
|
||||||
|
"src/ERC1155Proxy.sol",
|
||||||
|
"src/ERC20Proxy.sol",
|
||||||
|
"src/ERC721Proxy.sol",
|
||||||
|
"src/MixinAuthorizable.sol",
|
||||||
|
"src/MultiAssetProxy.sol",
|
||||||
|
"src/StaticCallProxy.sol",
|
||||||
|
"src/interfaces/IAssetData.sol",
|
||||||
|
"src/interfaces/IAssetProxy.sol",
|
||||||
|
"src/interfaces/IAuthorizable.sol",
|
||||||
|
"test/TestStaticCallTarget.sol"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,33 +0,0 @@
|
|||||||
pragma solidity ^0.5.9;
|
|
||||||
|
|
||||||
import "@0x/contracts-utils/contracts/src/interfaces/IOwnable.sol";
|
|
||||||
|
|
||||||
|
|
||||||
contract Ownable is
|
|
||||||
IOwnable
|
|
||||||
{
|
|
||||||
address public owner;
|
|
||||||
|
|
||||||
constructor ()
|
|
||||||
public
|
|
||||||
{
|
|
||||||
owner = msg.sender;
|
|
||||||
}
|
|
||||||
|
|
||||||
modifier onlyOwner() {
|
|
||||||
require(
|
|
||||||
msg.sender == owner,
|
|
||||||
"ONLY_CONTRACT_OWNER"
|
|
||||||
);
|
|
||||||
_;
|
|
||||||
}
|
|
||||||
|
|
||||||
function transferOwnership(address newOwner)
|
|
||||||
public
|
|
||||||
onlyOwner
|
|
||||||
{
|
|
||||||
if (newOwner != address(0)) {
|
|
||||||
owner = newOwner;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
|
|
||||||
Copyright 2019 ZeroEx Intl.
|
Copyright 2018 ZeroEx Intl.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -19,18 +19,18 @@
|
|||||||
pragma solidity ^0.5.9;
|
pragma solidity ^0.5.9;
|
||||||
|
|
||||||
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
|
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
|
||||||
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
|
import "@0x/contracts-utils/contracts/src/SafeMath.sol";
|
||||||
import "@0x/contracts-erc1155/contracts/src/interfaces/IERC1155.sol";
|
import "@0x/contracts-erc1155/contracts/src/interfaces/IERC1155.sol";
|
||||||
import "../archive/MixinAuthorizable.sol";
|
import "./MixinAuthorizable.sol";
|
||||||
import "./interfaces/IAssetProxy.sol";
|
import "./interfaces/IAssetProxy.sol";
|
||||||
|
|
||||||
|
|
||||||
contract ERC1155Proxy is
|
contract ERC1155Proxy is
|
||||||
MixinAuthorizable,
|
MixinAuthorizable,
|
||||||
|
SafeMath,
|
||||||
IAssetProxy
|
IAssetProxy
|
||||||
{
|
{
|
||||||
using LibBytes for bytes;
|
using LibBytes for bytes;
|
||||||
using LibSafeMath for uint256;
|
|
||||||
|
|
||||||
// Id of this proxy.
|
// Id of this proxy.
|
||||||
bytes4 constant internal PROXY_ID = bytes4(keccak256("ERC1155Assets(address,uint256[],uint256[],bytes)"));
|
bytes4 constant internal PROXY_ID = bytes4(keccak256("ERC1155Assets(address,uint256[],uint256[],bytes)"));
|
||||||
@@ -69,9 +69,9 @@ contract ERC1155Proxy is
|
|||||||
for (uint256 i = 0; i != length; i++) {
|
for (uint256 i = 0; i != length; i++) {
|
||||||
// We write the scaled values to an unused location in memory in order
|
// We write the scaled values to an unused location in memory in order
|
||||||
// to avoid copying over `ids` or `data`. This is possible if they are
|
// to avoid copying over `ids` or `data`. This is possible if they are
|
||||||
// identical to `values` and the offsets for each are pointing to the
|
// identical to `values` and the offsets for each are pointing to the
|
||||||
// same location in the ABI encoded calldata.
|
// same location in the ABI encoded calldata.
|
||||||
scaledValues[i] = values[i].safeMul(amount);
|
scaledValues[i] = safeMul(values[i], amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute `safeBatchTransferFrom` call
|
// Execute `safeBatchTransferFrom` call
|
||||||
|
|||||||
@@ -1,126 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
Copyright 2019 ZeroEx Intl.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
pragma solidity ^0.5.9;
|
|
||||||
pragma experimental ABIEncoderV2;
|
|
||||||
|
|
||||||
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
|
|
||||||
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
|
|
||||||
import "@0x/contracts-utils/contracts/src/Authorizable.sol";
|
|
||||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
|
||||||
import "./interfaces/IAssetProxy.sol";
|
|
||||||
import "./interfaces/IERC20Bridge.sol";
|
|
||||||
|
|
||||||
|
|
||||||
contract ERC20BridgeProxy is
|
|
||||||
IAssetProxy,
|
|
||||||
Authorizable
|
|
||||||
{
|
|
||||||
using LibBytes for bytes;
|
|
||||||
using LibSafeMath for uint256;
|
|
||||||
|
|
||||||
// @dev Id of this proxy. Also the result of a successful bridge call.
|
|
||||||
// bytes4(keccak256("ERC20Bridge(address,address,bytes)"))
|
|
||||||
bytes4 constant private PROXY_ID = 0xdc1600f3;
|
|
||||||
|
|
||||||
/// @dev Calls a bridge contract to transfer `amount` of ERC20 from `from`
|
|
||||||
/// to `to`. Asserts that the balance of `to` has increased by `amount`.
|
|
||||||
/// @param assetData Abi-encoded data for this asset proxy encoded as:
|
|
||||||
/// abi.encodeWithSelector(
|
|
||||||
/// bytes4 PROXY_ID,
|
|
||||||
/// address tokenAddress,
|
|
||||||
/// address bridgeAddress,
|
|
||||||
/// bytes bridgeData
|
|
||||||
/// )
|
|
||||||
/// @param from Address to transfer asset from.
|
|
||||||
/// @param to Address to transfer asset to.
|
|
||||||
/// @param amount Amount of asset to transfer.
|
|
||||||
function transferFrom(
|
|
||||||
bytes calldata assetData,
|
|
||||||
address from,
|
|
||||||
address to,
|
|
||||||
uint256 amount
|
|
||||||
)
|
|
||||||
external
|
|
||||||
onlyAuthorized
|
|
||||||
{
|
|
||||||
// Extract asset data fields.
|
|
||||||
(
|
|
||||||
address tokenAddress,
|
|
||||||
address bridgeAddress,
|
|
||||||
bytes memory bridgeData
|
|
||||||
) = abi.decode(
|
|
||||||
assetData.sliceDestructive(4, assetData.length),
|
|
||||||
(address, address, bytes)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Remember the balance of `to` before calling the bridge.
|
|
||||||
uint256 balanceBefore = balanceOf(tokenAddress, to);
|
|
||||||
// Call the bridge, who should transfer `amount` of `tokenAddress` to
|
|
||||||
// `to`.
|
|
||||||
bytes4 success = IERC20Bridge(bridgeAddress).bridgeTransferFrom(
|
|
||||||
tokenAddress,
|
|
||||||
from,
|
|
||||||
to,
|
|
||||||
amount,
|
|
||||||
bridgeData
|
|
||||||
);
|
|
||||||
// Bridge must return the proxy ID to indicate success.
|
|
||||||
require(success == PROXY_ID, "BRIDGE_FAILED");
|
|
||||||
// Ensure that the balance of `to` has increased by at least `amount`.
|
|
||||||
require(
|
|
||||||
balanceBefore.safeAdd(amount) <= balanceOf(tokenAddress, to),
|
|
||||||
"BRIDGE_UNDERPAY"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @dev Gets the proxy id associated with this asset proxy.
|
|
||||||
/// @return proxyId The proxy id.
|
|
||||||
function getProxyId()
|
|
||||||
external
|
|
||||||
pure
|
|
||||||
returns (bytes4 proxyId)
|
|
||||||
{
|
|
||||||
return PROXY_ID;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @dev Retrieves the balance of `owner` for this asset.
|
|
||||||
/// @return balance The balance of the ERC20 token being transferred by this
|
|
||||||
/// asset proxy.
|
|
||||||
function balanceOf(bytes calldata assetData, address owner)
|
|
||||||
external
|
|
||||||
view
|
|
||||||
returns (uint256 balance)
|
|
||||||
{
|
|
||||||
(address tokenAddress) = abi.decode(
|
|
||||||
assetData.sliceDestructive(4, assetData.length),
|
|
||||||
(address)
|
|
||||||
);
|
|
||||||
return balanceOf(tokenAddress, owner);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @dev Retrieves the balance of `owner` given an ERC20 address.
|
|
||||||
/// @return balance The balance of the ERC20 token for `owner`.
|
|
||||||
function balanceOf(address tokenAddress, address owner)
|
|
||||||
private
|
|
||||||
view
|
|
||||||
returns (uint256 balance)
|
|
||||||
{
|
|
||||||
return IERC20Token(tokenAddress).balanceOf(owner);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
|
|
||||||
Copyright 2019 ZeroEx Intl.
|
Copyright 2018 ZeroEx Intl.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -16,9 +16,9 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pragma solidity ^0.5.9;
|
pragma solidity ^0.5.5;
|
||||||
|
|
||||||
import "../archive/MixinAuthorizable.sol";
|
import "./MixinAuthorizable.sol";
|
||||||
|
|
||||||
|
|
||||||
contract ERC20Proxy is
|
contract ERC20Proxy is
|
||||||
@@ -26,9 +26,9 @@ contract ERC20Proxy is
|
|||||||
{
|
{
|
||||||
// Id of this proxy.
|
// Id of this proxy.
|
||||||
bytes4 constant internal PROXY_ID = bytes4(keccak256("ERC20Token(address)"));
|
bytes4 constant internal PROXY_ID = bytes4(keccak256("ERC20Token(address)"));
|
||||||
|
|
||||||
// solhint-disable-next-line payable-fallback
|
// solhint-disable-next-line payable-fallback
|
||||||
function ()
|
function ()
|
||||||
external
|
external
|
||||||
{
|
{
|
||||||
assembly {
|
assembly {
|
||||||
@@ -117,13 +117,13 @@ contract ERC20Proxy is
|
|||||||
// * The "token address" is offset 32+4=36 bytes into "assetData" (tables 1 & 2).
|
// * The "token address" is offset 32+4=36 bytes into "assetData" (tables 1 & 2).
|
||||||
// [tokenOffset = assetDataOffsetFromHeader + 36 = calldataload(4) + 4 + 36]
|
// [tokenOffset = assetDataOffsetFromHeader + 36 = calldataload(4) + 4 + 36]
|
||||||
let token := calldataload(add(calldataload(4), 40))
|
let token := calldataload(add(calldataload(4), 40))
|
||||||
|
|
||||||
/////// Setup Header Area ///////
|
/////// Setup Header Area ///////
|
||||||
// This area holds the 4-byte `transferFrom` selector.
|
// This area holds the 4-byte `transferFrom` selector.
|
||||||
// Any trailing data in transferFromSelector will be
|
// Any trailing data in transferFromSelector will be
|
||||||
// overwritten in the next `mstore` call.
|
// overwritten in the next `mstore` call.
|
||||||
mstore(0, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
|
mstore(0, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
|
||||||
|
|
||||||
/////// Setup Params Area ///////
|
/////// Setup Params Area ///////
|
||||||
// We copy the fields `from`, `to` and `amount` in bulk
|
// We copy the fields `from`, `to` and `amount` in bulk
|
||||||
// from our own calldata to the new calldata.
|
// from our own calldata to the new calldata.
|
||||||
@@ -147,7 +147,7 @@ contract ERC20Proxy is
|
|||||||
// If the token does return data, we require that it is a single
|
// If the token does return data, we require that it is a single
|
||||||
// nonzero 32 bytes value.
|
// nonzero 32 bytes value.
|
||||||
// So the transfer succeeded if the call succeeded and either
|
// So the transfer succeeded if the call succeeded and either
|
||||||
// returned nothing, or returned a non-zero 32 byte value.
|
// returned nothing, or returned a non-zero 32 byte value.
|
||||||
success := and(success, or(
|
success := and(success, or(
|
||||||
iszero(returndatasize),
|
iszero(returndatasize),
|
||||||
and(
|
and(
|
||||||
@@ -158,7 +158,7 @@ contract ERC20Proxy is
|
|||||||
if success {
|
if success {
|
||||||
return(0, 0)
|
return(0, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Revert with `Error("TRANSFER_FAILED")`
|
// Revert with `Error("TRANSFER_FAILED")`
|
||||||
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
|
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
|
||||||
mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
|
mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
|
|
||||||
Copyright 2019 ZeroEx Intl.
|
Copyright 2018 ZeroEx Intl.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -16,9 +16,9 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pragma solidity ^0.5.9;
|
pragma solidity ^0.5.5;
|
||||||
|
|
||||||
import "../archive/MixinAuthorizable.sol";
|
import "./MixinAuthorizable.sol";
|
||||||
|
|
||||||
|
|
||||||
contract ERC721Proxy is
|
contract ERC721Proxy is
|
||||||
@@ -28,7 +28,7 @@ contract ERC721Proxy is
|
|||||||
bytes4 constant internal PROXY_ID = bytes4(keccak256("ERC721Token(address,uint256)"));
|
bytes4 constant internal PROXY_ID = bytes4(keccak256("ERC721Token(address,uint256)"));
|
||||||
|
|
||||||
// solhint-disable-next-line payable-fallback
|
// solhint-disable-next-line payable-fallback
|
||||||
function ()
|
function ()
|
||||||
external
|
external
|
||||||
{
|
{
|
||||||
assembly {
|
assembly {
|
||||||
@@ -93,10 +93,10 @@ contract ERC721Proxy is
|
|||||||
// | Params | | 2 * 32 | function parameters: |
|
// | Params | | 2 * 32 | function parameters: |
|
||||||
// | | 4 | 12 + 20 | 1. token address |
|
// | | 4 | 12 + 20 | 1. token address |
|
||||||
// | | 36 | | 2. tokenId |
|
// | | 36 | | 2. tokenId |
|
||||||
|
|
||||||
// We construct calldata for the `token.transferFrom` ABI.
|
// We construct calldata for the `token.transferFrom` ABI.
|
||||||
// The layout of this calldata is in the table below.
|
// The layout of this calldata is in the table below.
|
||||||
//
|
//
|
||||||
// | Area | Offset | Length | Contents |
|
// | Area | Offset | Length | Contents |
|
||||||
// |----------|--------|---------|-------------------------------------|
|
// |----------|--------|---------|-------------------------------------|
|
||||||
// | Header | 0 | 4 | function selector |
|
// | Header | 0 | 4 | function selector |
|
||||||
@@ -121,7 +121,7 @@ contract ERC721Proxy is
|
|||||||
// Any trailing data in transferFromSelector will be
|
// Any trailing data in transferFromSelector will be
|
||||||
// overwritten in the next `mstore` call.
|
// overwritten in the next `mstore` call.
|
||||||
mstore(0, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
|
mstore(0, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
|
||||||
|
|
||||||
/////// Setup Params Area ///////
|
/////// Setup Params Area ///////
|
||||||
// We copy the fields `from` and `to` in bulk
|
// We copy the fields `from` and `to` in bulk
|
||||||
// from our own calldata to the new calldata.
|
// from our own calldata to the new calldata.
|
||||||
@@ -145,7 +145,7 @@ contract ERC721Proxy is
|
|||||||
if success {
|
if success {
|
||||||
return(0, 0)
|
return(0, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Revert with `Error("TRANSFER_FAILED")`
|
// Revert with `Error("TRANSFER_FAILED")`
|
||||||
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
|
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
|
||||||
mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
|
mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
|
|
||||||
Copyright 2019 ZeroEx Intl.
|
Copyright 2018 ZeroEx Intl.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -16,16 +16,16 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pragma solidity ^0.5.9;
|
pragma solidity ^0.5.5;
|
||||||
|
|
||||||
import "../archive/Ownable.sol";
|
import "@0x/contracts-utils/contracts/src/Ownable.sol";
|
||||||
import "../src/interfaces/IAssetProxy.sol";
|
import "./mixins/MAssetProxyDispatcher.sol";
|
||||||
import "../src/interfaces/IAssetProxyDispatcher.sol";
|
import "./interfaces/IAssetProxy.sol";
|
||||||
|
|
||||||
|
|
||||||
contract MixinAssetProxyDispatcher is
|
contract MixinAssetProxyDispatcher is
|
||||||
Ownable,
|
Ownable,
|
||||||
IAssetProxyDispatcher
|
MAssetProxyDispatcher
|
||||||
{
|
{
|
||||||
// Mapping from Asset Proxy Id's to their respective Asset Proxy
|
// Mapping from Asset Proxy Id's to their respective Asset Proxy
|
||||||
mapping (bytes4 => address) public assetProxies;
|
mapping (bytes4 => address) public assetProxies;
|
||||||
@@ -69,7 +69,7 @@ contract MixinAssetProxyDispatcher is
|
|||||||
/// @param from Address to transfer token from.
|
/// @param from Address to transfer token from.
|
||||||
/// @param to Address to transfer token to.
|
/// @param to Address to transfer token to.
|
||||||
/// @param amount Amount of token to transfer.
|
/// @param amount Amount of token to transfer.
|
||||||
function _dispatchTransferFrom(
|
function dispatchTransferFrom(
|
||||||
bytes memory assetData,
|
bytes memory assetData,
|
||||||
address from,
|
address from,
|
||||||
address to,
|
address to,
|
||||||
@@ -84,7 +84,7 @@ contract MixinAssetProxyDispatcher is
|
|||||||
assetData.length > 3,
|
assetData.length > 3,
|
||||||
"LENGTH_GREATER_THAN_3_REQUIRED"
|
"LENGTH_GREATER_THAN_3_REQUIRED"
|
||||||
);
|
);
|
||||||
|
|
||||||
// Lookup assetProxy. We do not use `LibBytes.readBytes4` for gas efficiency reasons.
|
// Lookup assetProxy. We do not use `LibBytes.readBytes4` for gas efficiency reasons.
|
||||||
bytes4 assetProxyId;
|
bytes4 assetProxyId;
|
||||||
assembly {
|
assembly {
|
||||||
@@ -100,10 +100,10 @@ contract MixinAssetProxyDispatcher is
|
|||||||
assetProxy != address(0),
|
assetProxy != address(0),
|
||||||
"ASSET_PROXY_DOES_NOT_EXIST"
|
"ASSET_PROXY_DOES_NOT_EXIST"
|
||||||
);
|
);
|
||||||
|
|
||||||
// We construct calldata for the `assetProxy.transferFrom` ABI.
|
// We construct calldata for the `assetProxy.transferFrom` ABI.
|
||||||
// The layout of this calldata is in the table below.
|
// The layout of this calldata is in the table below.
|
||||||
//
|
//
|
||||||
// | Area | Offset | Length | Contents |
|
// | Area | Offset | Length | Contents |
|
||||||
// | -------- |--------|---------|-------------------------------------------- |
|
// | -------- |--------|---------|-------------------------------------------- |
|
||||||
// | Header | 0 | 4 | function selector |
|
// | Header | 0 | 4 | function selector |
|
||||||
@@ -127,12 +127,12 @@ contract MixinAssetProxyDispatcher is
|
|||||||
// `cdEnd` is the end of the calldata for `assetProxy.transferFrom`.
|
// `cdEnd` is the end of the calldata for `assetProxy.transferFrom`.
|
||||||
let cdEnd := add(cdStart, add(132, dataAreaLength))
|
let cdEnd := add(cdStart, add(132, dataAreaLength))
|
||||||
|
|
||||||
|
|
||||||
/////// Setup Header Area ///////
|
/////// Setup Header Area ///////
|
||||||
// This area holds the 4-byte `transferFromSelector`.
|
// This area holds the 4-byte `transferFromSelector`.
|
||||||
// bytes4(keccak256("transferFrom(bytes,address,address,uint256)")) = 0xa85e59e4
|
// bytes4(keccak256("transferFrom(bytes,address,address,uint256)")) = 0xa85e59e4
|
||||||
mstore(cdStart, 0xa85e59e400000000000000000000000000000000000000000000000000000000)
|
mstore(cdStart, 0xa85e59e400000000000000000000000000000000000000000000000000000000)
|
||||||
|
|
||||||
/////// Setup Params Area ///////
|
/////// Setup Params Area ///////
|
||||||
// Each parameter is padded to 32-bytes. The entire Params Area is 128 bytes.
|
// Each parameter is padded to 32-bytes. The entire Params Area is 128 bytes.
|
||||||
// Notes:
|
// Notes:
|
||||||
@@ -142,7 +142,7 @@ contract MixinAssetProxyDispatcher is
|
|||||||
mstore(add(cdStart, 36), and(from, 0xffffffffffffffffffffffffffffffffffffffff))
|
mstore(add(cdStart, 36), and(from, 0xffffffffffffffffffffffffffffffffffffffff))
|
||||||
mstore(add(cdStart, 68), and(to, 0xffffffffffffffffffffffffffffffffffffffff))
|
mstore(add(cdStart, 68), and(to, 0xffffffffffffffffffffffffffffffffffffffff))
|
||||||
mstore(add(cdStart, 100), amount)
|
mstore(add(cdStart, 100), amount)
|
||||||
|
|
||||||
/////// Setup Data Area ///////
|
/////// Setup Data Area ///////
|
||||||
// This area holds `assetData`.
|
// This area holds `assetData`.
|
||||||
let dataArea := add(cdStart, 132)
|
let dataArea := add(cdStart, 132)
|
||||||
@@ -159,7 +159,7 @@ contract MixinAssetProxyDispatcher is
|
|||||||
assetProxy, // call address of asset proxy
|
assetProxy, // call address of asset proxy
|
||||||
0, // don't send any ETH
|
0, // don't send any ETH
|
||||||
cdStart, // pointer to start of input
|
cdStart, // pointer to start of input
|
||||||
sub(cdEnd, cdStart), // length of input
|
sub(cdEnd, cdStart), // length of input
|
||||||
cdStart, // write output over input
|
cdStart, // write output over input
|
||||||
512 // reserve 512 bytes for output
|
512 // reserve 512 bytes for output
|
||||||
)
|
)
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
|
|
||||||
Copyright 2019 ZeroEx Intl.
|
Copyright 2018 ZeroEx Intl.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -16,15 +16,15 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pragma solidity ^0.5.9;
|
pragma solidity ^0.5.5;
|
||||||
|
|
||||||
import "../archive/Ownable.sol";
|
import "@0x/contracts-utils/contracts/src/Ownable.sol";
|
||||||
import "../src/interfaces/IAuthorizable.sol";
|
import "./mixins/MAuthorizable.sol";
|
||||||
|
|
||||||
|
|
||||||
contract MixinAuthorizable is
|
contract MixinAuthorizable is
|
||||||
Ownable,
|
Ownable,
|
||||||
IAuthorizable
|
MAuthorizable
|
||||||
{
|
{
|
||||||
/// @dev Only authorized addresses can invoke functions with this modifier.
|
/// @dev Only authorized addresses can invoke functions with this modifier.
|
||||||
modifier onlyAuthorized {
|
modifier onlyAuthorized {
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
|
|
||||||
Copyright 2019 ZeroEx Intl.
|
Copyright 2018 ZeroEx Intl.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -16,10 +16,10 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pragma solidity ^0.5.9;
|
pragma solidity ^0.5.5;
|
||||||
|
|
||||||
import "../archive/MixinAssetProxyDispatcher.sol";
|
import "./MixinAssetProxyDispatcher.sol";
|
||||||
import "../archive/MixinAuthorizable.sol";
|
import "./MixinAuthorizable.sol";
|
||||||
|
|
||||||
|
|
||||||
contract MultiAssetProxy is
|
contract MultiAssetProxy is
|
||||||
@@ -105,7 +105,7 @@ contract MultiAssetProxy is
|
|||||||
// | | 36 | | 2. offset to nestedAssetData (*) |
|
// | | 36 | | 2. offset to nestedAssetData (*) |
|
||||||
// | Data | | | amounts: |
|
// | Data | | | amounts: |
|
||||||
// | | 68 | 32 | amounts Length |
|
// | | 68 | 32 | amounts Length |
|
||||||
// | | 100 | a | amounts Contents |
|
// | | 100 | a | amounts Contents |
|
||||||
// | | | | nestedAssetData: |
|
// | | | | nestedAssetData: |
|
||||||
// | | 100 + a | 32 | nestedAssetData Length |
|
// | | 100 + a | 32 | nestedAssetData Length |
|
||||||
// | | 132 + a | b | nestedAssetData Contents (offsets) |
|
// | | 132 + a | b | nestedAssetData Contents (offsets) |
|
||||||
@@ -149,8 +149,8 @@ contract MultiAssetProxy is
|
|||||||
// + 32 (amounts offset)
|
// + 32 (amounts offset)
|
||||||
let nestedAssetDataOffset := calldataload(add(assetDataOffset, 68))
|
let nestedAssetDataOffset := calldataload(add(assetDataOffset, 68))
|
||||||
|
|
||||||
// In order to find the start of the `amounts` contents, we must add:
|
// In order to find the start of the `amounts` contents, we must add:
|
||||||
// assetDataOffset
|
// assetDataOffset
|
||||||
// + 32 (assetData len)
|
// + 32 (assetData len)
|
||||||
// + 4 (assetProxyId)
|
// + 4 (assetProxyId)
|
||||||
// + amountsOffset
|
// + amountsOffset
|
||||||
@@ -160,8 +160,8 @@ contract MultiAssetProxy is
|
|||||||
// Load number of elements in `amounts`
|
// Load number of elements in `amounts`
|
||||||
let amountsLen := calldataload(sub(amountsContentsStart, 32))
|
let amountsLen := calldataload(sub(amountsContentsStart, 32))
|
||||||
|
|
||||||
// In order to find the start of the `nestedAssetData` contents, we must add:
|
// In order to find the start of the `nestedAssetData` contents, we must add:
|
||||||
// assetDataOffset
|
// assetDataOffset
|
||||||
// + 32 (assetData len)
|
// + 32 (assetData len)
|
||||||
// + 4 (assetProxyId)
|
// + 4 (assetProxyId)
|
||||||
// + nestedAssetDataOffset
|
// + nestedAssetDataOffset
|
||||||
@@ -190,10 +190,10 @@ contract MultiAssetProxy is
|
|||||||
|
|
||||||
// Overwrite existing offset to `assetData` with our own
|
// Overwrite existing offset to `assetData` with our own
|
||||||
mstore(4, 128)
|
mstore(4, 128)
|
||||||
|
|
||||||
// Load `amount`
|
// Load `amount`
|
||||||
let amount := calldataload(100)
|
let amount := calldataload(100)
|
||||||
|
|
||||||
// Calculate number of bytes in `amounts` contents
|
// Calculate number of bytes in `amounts` contents
|
||||||
let amountsByteLen := mul(amountsLen, 32)
|
let amountsByteLen := mul(amountsLen, 32)
|
||||||
|
|
||||||
@@ -208,7 +208,7 @@ contract MultiAssetProxy is
|
|||||||
let amountsElement := calldataload(add(amountsContentsStart, i))
|
let amountsElement := calldataload(add(amountsContentsStart, i))
|
||||||
let totalAmount := mul(amountsElement, amount)
|
let totalAmount := mul(amountsElement, amount)
|
||||||
|
|
||||||
// Revert if `amount` != 0 and multiplication resulted in an overflow
|
// Revert if `amount` != 0 and multiplication resulted in an overflow
|
||||||
if iszero(or(
|
if iszero(or(
|
||||||
iszero(amount),
|
iszero(amount),
|
||||||
eq(div(totalAmount, amount), amountsElement)
|
eq(div(totalAmount, amount), amountsElement)
|
||||||
@@ -228,7 +228,7 @@ contract MultiAssetProxy is
|
|||||||
let nestedAssetDataElementOffset := calldataload(add(nestedAssetDataContentsStart, i))
|
let nestedAssetDataElementOffset := calldataload(add(nestedAssetDataContentsStart, i))
|
||||||
|
|
||||||
// In order to find the start of the `nestedAssetData[i]` contents, we must add:
|
// In order to find the start of the `nestedAssetData[i]` contents, we must add:
|
||||||
// assetDataOffset
|
// assetDataOffset
|
||||||
// + 32 (assetData len)
|
// + 32 (assetData len)
|
||||||
// + 4 (assetProxyId)
|
// + 4 (assetProxyId)
|
||||||
// + nestedAssetDataOffset
|
// + nestedAssetDataOffset
|
||||||
@@ -274,7 +274,7 @@ contract MultiAssetProxy is
|
|||||||
mstore(164, assetProxies_slot)
|
mstore(164, assetProxies_slot)
|
||||||
assetProxy := sload(keccak256(132, 64))
|
assetProxy := sload(keccak256(132, 64))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Revert if AssetProxy with given id does not exist
|
// Revert if AssetProxy with given id does not exist
|
||||||
if iszero(assetProxy) {
|
if iszero(assetProxy) {
|
||||||
// Revert with `Error("ASSET_PROXY_DOES_NOT_EXIST")`
|
// Revert with `Error("ASSET_PROXY_DOES_NOT_EXIST")`
|
||||||
@@ -284,7 +284,7 @@ contract MultiAssetProxy is
|
|||||||
mstore(96, 0)
|
mstore(96, 0)
|
||||||
revert(0, 100)
|
revert(0, 100)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy `nestedAssetData[i]` from calldata to memory
|
// Copy `nestedAssetData[i]` from calldata to memory
|
||||||
calldatacopy(
|
calldatacopy(
|
||||||
132, // memory slot after `amounts[i]`
|
132, // memory slot after `amounts[i]`
|
||||||
@@ -298,7 +298,7 @@ contract MultiAssetProxy is
|
|||||||
assetProxy, // call address of asset proxy
|
assetProxy, // call address of asset proxy
|
||||||
0, // don't send any ETH
|
0, // don't send any ETH
|
||||||
0, // pointer to start of input
|
0, // pointer to start of input
|
||||||
add(164, nestedAssetDataElementLen), // length of input
|
add(164, nestedAssetDataElementLen), // length of input
|
||||||
0, // write output over memory that won't be reused
|
0, // write output over memory that won't be reused
|
||||||
0 // don't copy output to memory
|
0 // don't copy output to memory
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
|
|
||||||
Copyright 2019 ZeroEx Intl.
|
Copyright 2018 ZeroEx Intl.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,103 +0,0 @@
|
|||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,144 +0,0 @@
|
|||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
Copyright 2019 ZeroEx Intl.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
pragma solidity ^0.5.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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,103 +0,0 @@
|
|||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,136 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
Copyright 2019 ZeroEx Intl.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
pragma solidity ^0.5.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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,147 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,200 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,242 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
Copyright 2019 ZeroEx Intl.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
pragma solidity ^0.5.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''
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
Copyright 2019 ZeroEx Intl.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
pragma solidity ^0.5.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/IEth2Dai.sol";
|
|
||||||
|
|
||||||
|
|
||||||
// solhint-disable space-after-comma
|
|
||||||
contract Eth2DaiBridge is
|
|
||||||
IERC20Bridge,
|
|
||||||
IWallet,
|
|
||||||
DeploymentConstants
|
|
||||||
{
|
|
||||||
/// @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 to,
|
|
||||||
uint256 amount,
|
|
||||||
bytes calldata bridgeData
|
|
||||||
)
|
|
||||||
external
|
|
||||||
returns (bytes4 success)
|
|
||||||
{
|
|
||||||
// Decode the bridge data to get the `fromTokenAddress`.
|
|
||||||
(address fromTokenAddress) = abi.decode(bridgeData, (address));
|
|
||||||
|
|
||||||
IEth2Dai exchange = IEth2Dai(_getEth2DaiAddress());
|
|
||||||
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.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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,169 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,94 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
Copyright 2019 ZeroEx Intl.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
pragma solidity ^0.5.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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
Copyright 2019 ZeroEx Intl.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
pragma solidity ^0.5.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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,148 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,95 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
Copyright 2019 ZeroEx Intl.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
pragma solidity ^0.5.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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
Copyright 2019 ZeroEx Intl.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
pragma solidity ^0.5.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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,136 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
Copyright 2019 ZeroEx Intl.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
pragma solidity ^0.5.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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,220 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
Copyright 2019 ZeroEx Intl.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
pragma solidity ^0.5.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/IUniswapExchangeFactory.sol";
|
|
||||||
import "../interfaces/IUniswapExchange.sol";
|
|
||||||
import "../interfaces/IERC20Bridge.sol";
|
|
||||||
|
|
||||||
|
|
||||||
// solhint-disable space-after-comma
|
|
||||||
// solhint-disable not-rely-on-time
|
|
||||||
contract UniswapBridge is
|
|
||||||
IERC20Bridge,
|
|
||||||
IWallet,
|
|
||||||
DeploymentConstants
|
|
||||||
{
|
|
||||||
// Struct to hold `bridgeTransferFrom()` local variables in memory and to avoid
|
|
||||||
// stack overflows.
|
|
||||||
struct TransferState {
|
|
||||||
IUniswapExchange exchange;
|
|
||||||
uint256 fromTokenBalance;
|
|
||||||
IEtherToken weth;
|
|
||||||
uint256 boughtAmount;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 "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)
|
|
||||||
{
|
|
||||||
// State memory object to avoid stack overflows.
|
|
||||||
TransferState memory state;
|
|
||||||
// Decode the bridge data to get the `fromTokenAddress`.
|
|
||||||
(address fromTokenAddress) = abi.decode(bridgeData, (address));
|
|
||||||
|
|
||||||
// Just transfer the tokens if they're the same.
|
|
||||||
if (fromTokenAddress == toTokenAddress) {
|
|
||||||
LibERC20Token.transfer(fromTokenAddress, to, amount);
|
|
||||||
return BRIDGE_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the exchange for the token pair.
|
|
||||||
state.exchange = _getUniswapExchangeForTokenPair(
|
|
||||||
fromTokenAddress,
|
|
||||||
toTokenAddress
|
|
||||||
);
|
|
||||||
// Get our balance of `fromTokenAddress` token.
|
|
||||||
state.fromTokenBalance = IERC20Token(fromTokenAddress).balanceOf(address(this));
|
|
||||||
// Get the weth contract.
|
|
||||||
state.weth = IEtherToken(_getWethAddress());
|
|
||||||
|
|
||||||
// Convert from WETH to a token.
|
|
||||||
if (fromTokenAddress == address(state.weth)) {
|
|
||||||
// Unwrap the WETH.
|
|
||||||
state.weth.withdraw(state.fromTokenBalance);
|
|
||||||
// Buy as much of `toTokenAddress` token with ETH as possible and
|
|
||||||
// transfer it to `to`.
|
|
||||||
state.boughtAmount = state.exchange.ethToTokenTransferInput.value(state.fromTokenBalance)(
|
|
||||||
// Minimum buy amount.
|
|
||||||
amount,
|
|
||||||
// Expires after this block.
|
|
||||||
block.timestamp,
|
|
||||||
// Recipient is `to`.
|
|
||||||
to
|
|
||||||
);
|
|
||||||
|
|
||||||
// Convert from a token to WETH.
|
|
||||||
} else if (toTokenAddress == address(state.weth)) {
|
|
||||||
// Grant the exchange an allowance.
|
|
||||||
_grantExchangeAllowance(state.exchange, fromTokenAddress, state.fromTokenBalance);
|
|
||||||
// Buy as much ETH with `fromTokenAddress` token as possible.
|
|
||||||
state.boughtAmount = state.exchange.tokenToEthSwapInput(
|
|
||||||
// Sell all tokens we hold.
|
|
||||||
state.fromTokenBalance,
|
|
||||||
// Minimum buy amount.
|
|
||||||
amount,
|
|
||||||
// Expires after this block.
|
|
||||||
block.timestamp
|
|
||||||
);
|
|
||||||
// Wrap the ETH.
|
|
||||||
state.weth.deposit.value(state.boughtAmount)();
|
|
||||||
// Transfer the WETH to `to`.
|
|
||||||
IEtherToken(toTokenAddress).transfer(to, state.boughtAmount);
|
|
||||||
|
|
||||||
// Convert from one token to another.
|
|
||||||
} else {
|
|
||||||
// Grant the exchange an allowance.
|
|
||||||
_grantExchangeAllowance(state.exchange, fromTokenAddress, state.fromTokenBalance);
|
|
||||||
// Buy as much `toTokenAddress` token with `fromTokenAddress` token
|
|
||||||
// and transfer it to `to`.
|
|
||||||
state.boughtAmount = state.exchange.tokenToTokenTransferInput(
|
|
||||||
// Sell all tokens we hold.
|
|
||||||
state.fromTokenBalance,
|
|
||||||
// Minimum buy amount.
|
|
||||||
amount,
|
|
||||||
// Must buy at least 1 intermediate ETH.
|
|
||||||
1,
|
|
||||||
// Expires after this block.
|
|
||||||
block.timestamp,
|
|
||||||
// Recipient is `to`.
|
|
||||||
to,
|
|
||||||
// Convert to `toTokenAddress`.
|
|
||||||
toTokenAddress
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
emit ERC20BridgeTransfer(
|
|
||||||
fromTokenAddress,
|
|
||||||
toTokenAddress,
|
|
||||||
state.fromTokenBalance,
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @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.
|
|
||||||
/// @param minimumAllowance The minimum necessary allowance.
|
|
||||||
function _grantExchangeAllowance(
|
|
||||||
IUniswapExchange exchange,
|
|
||||||
address tokenAddress,
|
|
||||||
uint256 minimumAllowance
|
|
||||||
)
|
|
||||||
private
|
|
||||||
{
|
|
||||||
LibERC20Token.approveIfBelow(
|
|
||||||
tokenAddress,
|
|
||||||
address(exchange),
|
|
||||||
minimumAllowance
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @dev Retrieves the uniswap exchange for a given token pair.
|
|
||||||
/// In the case of a WETH-token exchange, this will be the non-WETH token.
|
|
||||||
/// In th ecase of a token-token exchange, this will be the first token.
|
|
||||||
/// @param fromTokenAddress The address of the token we are converting from.
|
|
||||||
/// @param toTokenAddress The address of the token we are converting to.
|
|
||||||
/// @return exchange The uniswap exchange.
|
|
||||||
function _getUniswapExchangeForTokenPair(
|
|
||||||
address fromTokenAddress,
|
|
||||||
address toTokenAddress
|
|
||||||
)
|
|
||||||
private
|
|
||||||
view
|
|
||||||
returns (IUniswapExchange exchange)
|
|
||||||
{
|
|
||||||
address exchangeTokenAddress = fromTokenAddress;
|
|
||||||
// Whichever isn't WETH is the exchange token.
|
|
||||||
if (fromTokenAddress == _getWethAddress()) {
|
|
||||||
exchangeTokenAddress = toTokenAddress;
|
|
||||||
}
|
|
||||||
exchange = IUniswapExchange(
|
|
||||||
IUniswapExchangeFactory(_getUniswapExchangeFactoryAddress())
|
|
||||||
.getExchange(exchangeTokenAddress)
|
|
||||||
);
|
|
||||||
require(address(exchange) != address(0), "NO_UNISWAP_EXCHANGE_FOR_TOKEN");
|
|
||||||
return exchange;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,135 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
|
|
||||||
Copyright 2019 ZeroEx Intl.
|
Copyright 2018 ZeroEx Intl.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// solhint-disable
|
// solhint-disable
|
||||||
pragma solidity ^0.5.9;
|
pragma solidity ^0.5.5;
|
||||||
pragma experimental ABIEncoderV2;
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
|
||||||
@@ -26,63 +26,33 @@ pragma experimental ABIEncoderV2;
|
|||||||
// This argument is ABI encoded as one of the methods of this interface.
|
// This argument is ABI encoded as one of the methods of this interface.
|
||||||
interface IAssetData {
|
interface IAssetData {
|
||||||
|
|
||||||
/// @dev Function signature for encoding ERC20 assetData.
|
|
||||||
/// @param tokenAddress Address of ERC20Token contract.
|
|
||||||
function ERC20Token(address tokenAddress)
|
function ERC20Token(address tokenAddress)
|
||||||
external;
|
external;
|
||||||
|
|
||||||
/// @dev Function signature for encoding ERC721 assetData.
|
|
||||||
/// @param tokenAddress Address of ERC721 token contract.
|
|
||||||
/// @param tokenId Id of ERC721 token to be transferred.
|
|
||||||
function ERC721Token(
|
function ERC721Token(
|
||||||
address tokenAddress,
|
address tokenAddress,
|
||||||
uint256 tokenId
|
uint256 tokenId
|
||||||
)
|
)
|
||||||
external;
|
external;
|
||||||
|
|
||||||
/// @dev Function signature for encoding ERC1155 assetData.
|
|
||||||
/// @param tokenAddress Address of ERC1155 token contract.
|
|
||||||
/// @param tokenIds Array of ids of tokens to be transferred.
|
|
||||||
/// @param values Array of values that correspond to each token id to be transferred.
|
|
||||||
/// Note that each value will be multiplied by the amount being filled in the order before transferring.
|
|
||||||
/// @param callbackData Extra data to be passed to receiver's `onERC1155Received` callback function.
|
|
||||||
function ERC1155Assets(
|
function ERC1155Assets(
|
||||||
address tokenAddress,
|
address tokenAddress,
|
||||||
uint256[] calldata tokenIds,
|
uint256[] calldata tokenIds,
|
||||||
uint256[] calldata values,
|
uint256[] calldata tokenValues,
|
||||||
bytes calldata callbackData
|
bytes calldata callbackData
|
||||||
)
|
)
|
||||||
external;
|
external;
|
||||||
|
|
||||||
/// @dev Function signature for encoding MultiAsset assetData.
|
|
||||||
/// @param values Array of amounts that correspond to each asset to be transferred.
|
|
||||||
/// Note that each value will be multiplied by the amount being filled in the order before transferring.
|
|
||||||
/// @param nestedAssetData Array of assetData fields that will be be dispatched to their correspnding AssetProxy contract.
|
|
||||||
function MultiAsset(
|
function MultiAsset(
|
||||||
uint256[] calldata values,
|
uint256[] calldata amounts,
|
||||||
bytes[] calldata nestedAssetData
|
bytes[] calldata nestedAssetData
|
||||||
)
|
)
|
||||||
external;
|
external;
|
||||||
|
|
||||||
/// @dev Function signature for encoding StaticCall assetData.
|
|
||||||
/// @param staticCallTargetAddress Address that will execute the staticcall.
|
|
||||||
/// @param staticCallData Data that will be executed via staticcall on the staticCallTargetAddress.
|
|
||||||
/// @param expectedReturnDataHash Keccak-256 hash of the expected staticcall return data.
|
|
||||||
function StaticCall(
|
function StaticCall(
|
||||||
address staticCallTargetAddress,
|
address callTarget,
|
||||||
bytes calldata staticCallData,
|
bytes calldata staticCallData,
|
||||||
bytes32 expectedReturnDataHash
|
bytes32 callResultHash
|
||||||
)
|
|
||||||
external;
|
|
||||||
|
|
||||||
/// @dev Function signature for encoding ERC20Bridge assetData.
|
|
||||||
/// @param tokenAddress Address of token to transfer.
|
|
||||||
/// @param bridgeAddress Address of the bridge contract.
|
|
||||||
/// @param bridgeData Arbitrary data to be passed to the bridge contract.
|
|
||||||
function ERC20Bridge(
|
|
||||||
address tokenAddress,
|
|
||||||
address bridgeAddress,
|
|
||||||
bytes calldata bridgeData
|
|
||||||
)
|
)
|
||||||
external;
|
external;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
|
|
||||||
Copyright 2019 ZeroEx Intl.
|
Copyright 2018 ZeroEx Intl.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -16,7 +16,9 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pragma solidity ^0.5.9;
|
pragma solidity ^0.5.5;
|
||||||
|
|
||||||
|
import "./IAuthorizable.sol";
|
||||||
|
|
||||||
|
|
||||||
contract IAssetProxy {
|
contract IAssetProxy {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
|
|
||||||
Copyright 2019 ZeroEx Intl.
|
Copyright 2018 ZeroEx Intl.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -16,17 +16,11 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pragma solidity ^0.5.9;
|
pragma solidity ^0.5.5;
|
||||||
|
|
||||||
|
|
||||||
contract IAssetProxyDispatcher {
|
contract IAssetProxyDispatcher {
|
||||||
|
|
||||||
// Logs registration of new asset proxy
|
|
||||||
event AssetProxyRegistered(
|
|
||||||
bytes4 id, // Id of new registered AssetProxy.
|
|
||||||
address assetProxy // Address of new registered AssetProxy.
|
|
||||||
);
|
|
||||||
|
|
||||||
/// @dev Registers an asset proxy to its asset proxy id.
|
/// @dev Registers an asset proxy to its asset proxy id.
|
||||||
/// Once an asset proxy is registered, it cannot be unregistered.
|
/// Once an asset proxy is registered, it cannot be unregistered.
|
||||||
/// @param assetProxy Address of new asset proxy to register.
|
/// @param assetProxy Address of new asset proxy to register.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
|
|
||||||
Copyright 2019 ZeroEx Intl.
|
Copyright 2018 ZeroEx Intl.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pragma solidity ^0.5.9;
|
pragma solidity ^0.5.5;
|
||||||
|
|
||||||
import "@0x/contracts-utils/contracts/src/interfaces/IOwnable.sol";
|
import "@0x/contracts-utils/contracts/src/interfaces/IOwnable.sol";
|
||||||
|
|
||||||
@@ -24,18 +24,6 @@ import "@0x/contracts-utils/contracts/src/interfaces/IOwnable.sol";
|
|||||||
contract IAuthorizable is
|
contract IAuthorizable is
|
||||||
IOwnable
|
IOwnable
|
||||||
{
|
{
|
||||||
// Event logged when a new address is authorized.
|
|
||||||
event AuthorizedAddressAdded(
|
|
||||||
address indexed target,
|
|
||||||
address indexed caller
|
|
||||||
);
|
|
||||||
|
|
||||||
// Event logged when a currently authorized address is unauthorized.
|
|
||||||
event AuthorizedAddressRemoved(
|
|
||||||
address indexed target,
|
|
||||||
address indexed caller
|
|
||||||
);
|
|
||||||
|
|
||||||
/// @dev Authorizes an address.
|
/// @dev Authorizes an address.
|
||||||
/// @param target Address to authorize.
|
/// @param target Address to authorize.
|
||||||
function addAuthorizedAddress(address target)
|
function addAuthorizedAddress(address target)
|
||||||
@@ -54,7 +42,7 @@ contract IAuthorizable is
|
|||||||
uint256 index
|
uint256 index
|
||||||
)
|
)
|
||||||
external;
|
external;
|
||||||
|
|
||||||
/// @dev Gets all authorized addresses.
|
/// @dev Gets all authorized addresses.
|
||||||
/// @return Array of authorized addresses.
|
/// @return Array of authorized addresses.
|
||||||
function getAuthorizedAddresses()
|
function getAuthorizedAddresses()
|
||||||
|
|||||||
@@ -1,39 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
Copyright 2019 ZeroEx Intl.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
pragma solidity ^0.5.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;
|
|
||||||
}
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
Copyright 2019 ZeroEx Intl.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
pragma solidity ^0.5.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);
|
|
||||||
}
|
|
||||||
@@ -1,192 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
Copyright 2019 ZeroEx Intl.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
pragma solidity ^0.5.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);
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
Copyright 2019 ZeroEx Intl.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
pragma solidity ^0.5.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.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
Copyright 2019 ZeroEx Intl.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
pragma solidity ^0.5.9;
|
|
||||||
|
|
||||||
|
|
||||||
contract IERC20Bridge {
|
|
||||||
|
|
||||||
/// @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 `0xdc1600f3` if successful.
|
|
||||||
function bridgeTransferFrom(
|
|
||||||
address tokenAddress,
|
|
||||||
address from,
|
|
||||||
address to,
|
|
||||||
uint256 amount,
|
|
||||||
bytes calldata bridgeData
|
|
||||||
)
|
|
||||||
external
|
|
||||||
returns (bytes4 success);
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
Copyright 2019 ZeroEx Intl.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
pragma solidity ^0.5.9;
|
|
||||||
|
|
||||||
|
|
||||||
interface IEth2Dai {
|
|
||||||
|
|
||||||
/// @dev Sell `sellAmount` of `fromToken` token and receive `toToken` token.
|
|
||||||
/// @param fromToken The token being sold.
|
|
||||||
/// @param sellAmount The amount of `fromToken` token being sold.
|
|
||||||
/// @param toToken The token being bought.
|
|
||||||
/// @param minFillAmount Minimum amount of `toToken` token to buy.
|
|
||||||
/// @return fillAmount Amount of `toToken` bought.
|
|
||||||
function sellAllAmount(
|
|
||||||
address fromToken,
|
|
||||||
uint256 sellAmount,
|
|
||||||
address toToken,
|
|
||||||
uint256 minFillAmount
|
|
||||||
)
|
|
||||||
external
|
|
||||||
returns (uint256 fillAmount);
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
Copyright 2019 ZeroEx Intl.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
pragma solidity ^0.5.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;
|
|
||||||
}
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
Copyright 2019 ZeroEx Intl.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
pragma solidity ^0.5.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);
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
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,34 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
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 IShell {
|
|
||||||
|
|
||||||
function originSwap(
|
|
||||||
address from,
|
|
||||||
address to,
|
|
||||||
uint256 fromAmount,
|
|
||||||
uint256 minTargetAmount,
|
|
||||||
uint256 deadline
|
|
||||||
)
|
|
||||||
external
|
|
||||||
returns (uint256 toAmount);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
Copyright 2019 ZeroEx Intl.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
pragma solidity ^0.5.9;
|
|
||||||
|
|
||||||
|
|
||||||
interface IUniswapExchange {
|
|
||||||
|
|
||||||
/// @dev Buys at least `minTokensBought` tokens with ETH and transfer them
|
|
||||||
/// to `recipient`.
|
|
||||||
/// @param minTokensBought The minimum number of tokens to buy.
|
|
||||||
/// @param deadline Time when this order expires.
|
|
||||||
/// @param recipient Who to transfer the tokens to.
|
|
||||||
/// @return tokensBought Amount of tokens bought.
|
|
||||||
function ethToTokenTransferInput(
|
|
||||||
uint256 minTokensBought,
|
|
||||||
uint256 deadline,
|
|
||||||
address recipient
|
|
||||||
)
|
|
||||||
external
|
|
||||||
payable
|
|
||||||
returns (uint256 tokensBought);
|
|
||||||
|
|
||||||
/// @dev Buys at least `minEthBought` ETH with tokens.
|
|
||||||
/// @param tokensSold Amount of tokens to sell.
|
|
||||||
/// @param minEthBought The minimum amount of ETH to buy.
|
|
||||||
/// @param deadline Time when this order expires.
|
|
||||||
/// @return ethBought Amount of tokens bought.
|
|
||||||
function tokenToEthSwapInput(
|
|
||||||
uint256 tokensSold,
|
|
||||||
uint256 minEthBought,
|
|
||||||
uint256 deadline
|
|
||||||
)
|
|
||||||
external
|
|
||||||
returns (uint256 ethBought);
|
|
||||||
|
|
||||||
/// @dev Buys at least `minTokensBought` tokens with the exchange token
|
|
||||||
/// and transfer them to `recipient`.
|
|
||||||
/// @param minTokensBought The minimum number of tokens to buy.
|
|
||||||
/// @param minEthBought The minimum amount of intermediate ETH to buy.
|
|
||||||
/// @param deadline Time when this order expires.
|
|
||||||
/// @param recipient Who to transfer the tokens to.
|
|
||||||
/// @param toTokenAddress The token being bought.
|
|
||||||
/// @return tokensBought Amount of tokens bought.
|
|
||||||
function tokenToTokenTransferInput(
|
|
||||||
uint256 tokensSold,
|
|
||||||
uint256 minTokensBought,
|
|
||||||
uint256 minEthBought,
|
|
||||||
uint256 deadline,
|
|
||||||
address recipient,
|
|
||||||
address toTokenAddress
|
|
||||||
)
|
|
||||||
external
|
|
||||||
returns (uint256 tokensBought);
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
Copyright 2019 ZeroEx Intl.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
pragma solidity ^0.5.9;
|
|
||||||
|
|
||||||
import "./IUniswapExchange.sol";
|
|
||||||
|
|
||||||
|
|
||||||
interface IUniswapExchangeFactory {
|
|
||||||
|
|
||||||
/// @dev Get the exchange for a token.
|
|
||||||
/// @param tokenAddress The address of the token contract.
|
|
||||||
function getExchange(address tokenAddress)
|
|
||||||
external
|
|
||||||
view
|
|
||||||
returns (address);
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
@@ -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.5;
|
||||||
|
|
||||||
|
|
||||||
|
contract LibAssetProxyIds {
|
||||||
|
|
||||||
|
// AssetProxy Ids are equiavalent the first 4 bytes of the keccak256 hash of the function signature assigned to each AssetProxy.
|
||||||
|
|
||||||
|
// ERC20Token(address)
|
||||||
|
bytes4 constant public ERC20_PROXY_ID = 0xf47261b0;
|
||||||
|
|
||||||
|
// ERC721Token(address,uint256)
|
||||||
|
bytes4 constant public ERC721_PROXY_ID = 0x02571792;
|
||||||
|
|
||||||
|
// ERC1155Assets(address,uint256[],uint256[],bytes)
|
||||||
|
bytes4 constant public ERC1155_PROXY_ID = 0xa7cb5fb7;
|
||||||
|
|
||||||
|
// MultiAsset(uint256[],bytes[])
|
||||||
|
bytes4 constant public MULTI_ASSET_PROXY_ID = 0x94cfcdd7;
|
||||||
|
|
||||||
|
// StaticCall(address,bytes,bytes32)
|
||||||
|
bytes4 constant public STATIC_CALL_PROXY_ID = 0xc339d10a;
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright 2018 ZeroEx Intl.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
pragma solidity ^0.5.5;
|
||||||
|
|
||||||
|
import "../interfaces/IAssetProxyDispatcher.sol";
|
||||||
|
|
||||||
|
|
||||||
|
contract MAssetProxyDispatcher is
|
||||||
|
IAssetProxyDispatcher
|
||||||
|
{
|
||||||
|
// Logs registration of new asset proxy
|
||||||
|
event AssetProxyRegistered(
|
||||||
|
bytes4 id, // Id of new registered AssetProxy.
|
||||||
|
address assetProxy // Address of new registered AssetProxy.
|
||||||
|
);
|
||||||
|
|
||||||
|
/// @dev Forwards arguments to assetProxy and calls `transferFrom`. Either succeeds or throws.
|
||||||
|
/// @param assetData Byte array encoded for the asset.
|
||||||
|
/// @param from Address to transfer token from.
|
||||||
|
/// @param to Address to transfer token to.
|
||||||
|
/// @param amount Amount of token to transfer.
|
||||||
|
function dispatchTransferFrom(
|
||||||
|
bytes memory assetData,
|
||||||
|
address from,
|
||||||
|
address to,
|
||||||
|
uint256 amount
|
||||||
|
)
|
||||||
|
internal;
|
||||||
|
}
|
||||||
41
contracts/asset-proxy/contracts/src/mixins/MAuthorizable.sol
Normal file
41
contracts/asset-proxy/contracts/src/mixins/MAuthorizable.sol
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright 2018 ZeroEx Intl.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
pragma solidity ^0.5.5;
|
||||||
|
|
||||||
|
import "../interfaces/IAuthorizable.sol";
|
||||||
|
|
||||||
|
|
||||||
|
contract MAuthorizable is
|
||||||
|
IAuthorizable
|
||||||
|
{
|
||||||
|
// Event logged when a new address is authorized.
|
||||||
|
event AuthorizedAddressAdded(
|
||||||
|
address indexed target,
|
||||||
|
address indexed caller
|
||||||
|
);
|
||||||
|
|
||||||
|
// Event logged when a currently authorized address is unauthorized.
|
||||||
|
event AuthorizedAddressRemoved(
|
||||||
|
address indexed target,
|
||||||
|
address indexed caller
|
||||||
|
);
|
||||||
|
|
||||||
|
/// @dev Only authorized addresses can invoke functions with this modifier.
|
||||||
|
modifier onlyAuthorized { revert(); _; }
|
||||||
|
}
|
||||||
@@ -1,247 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
Copyright 2019 ZeroEx Intl.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
pragma solidity ^0.5.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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
Copyright 2019 ZeroEx Intl.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
pragma solidity ^0.5.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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,244 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,246 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
Copyright 2019 ZeroEx Intl.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
pragma solidity ^0.5.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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,108 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
Copyright 2019 ZeroEx Intl.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
pragma solidity ^0.5.9;
|
|
||||||
pragma experimental ABIEncoderV2;
|
|
||||||
|
|
||||||
import "../src/interfaces/IERC20Bridge.sol";
|
|
||||||
|
|
||||||
|
|
||||||
/// @dev Test bridge token
|
|
||||||
contract TestERC20BridgeToken {
|
|
||||||
mapping (address => uint256) private _balances;
|
|
||||||
|
|
||||||
function addBalance(address owner, int256 amount)
|
|
||||||
external
|
|
||||||
{
|
|
||||||
setBalance(owner, uint256(int256(balanceOf(owner)) + amount));
|
|
||||||
}
|
|
||||||
|
|
||||||
function setBalance(address owner, uint256 balance)
|
|
||||||
public
|
|
||||||
{
|
|
||||||
_balances[owner] = balance;
|
|
||||||
}
|
|
||||||
|
|
||||||
function balanceOf(address owner)
|
|
||||||
public
|
|
||||||
view
|
|
||||||
returns (uint256)
|
|
||||||
{
|
|
||||||
return _balances[owner];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// @dev Test bridge contract.
|
|
||||||
contract TestERC20Bridge is
|
|
||||||
IERC20Bridge
|
|
||||||
{
|
|
||||||
TestERC20BridgeToken public testToken;
|
|
||||||
|
|
||||||
event BridgeWithdrawTo(
|
|
||||||
address tokenAddress,
|
|
||||||
address from,
|
|
||||||
address to,
|
|
||||||
uint256 amount,
|
|
||||||
bytes bridgeData
|
|
||||||
);
|
|
||||||
|
|
||||||
constructor() public {
|
|
||||||
testToken = new TestERC20BridgeToken();
|
|
||||||
}
|
|
||||||
|
|
||||||
function setTestTokenBalance(address owner, uint256 balance)
|
|
||||||
external
|
|
||||||
{
|
|
||||||
testToken.setBalance(owner, balance);
|
|
||||||
}
|
|
||||||
|
|
||||||
function bridgeTransferFrom(
|
|
||||||
address tokenAddress,
|
|
||||||
address from,
|
|
||||||
address to,
|
|
||||||
uint256 amount,
|
|
||||||
bytes calldata bridgeData
|
|
||||||
)
|
|
||||||
external
|
|
||||||
returns (bytes4)
|
|
||||||
{
|
|
||||||
emit BridgeWithdrawTo(
|
|
||||||
tokenAddress,
|
|
||||||
from,
|
|
||||||
to,
|
|
||||||
amount,
|
|
||||||
bridgeData
|
|
||||||
);
|
|
||||||
// Unpack the bridgeData.
|
|
||||||
(
|
|
||||||
int256 transferAmount,
|
|
||||||
bytes memory revertData,
|
|
||||||
bytes memory returnData
|
|
||||||
) = abi.decode(bridgeData, (int256, bytes, bytes));
|
|
||||||
|
|
||||||
// If `revertData` is set, revert.
|
|
||||||
if (revertData.length != 0) {
|
|
||||||
assembly { revert(add(revertData, 0x20), mload(revertData)) }
|
|
||||||
}
|
|
||||||
// Increase `to`'s balance by `transferAmount`.
|
|
||||||
TestERC20BridgeToken(tokenAddress).addBalance(to, transferAmount);
|
|
||||||
// Return `returnData`.
|
|
||||||
assembly { return(add(returnData, 0x20), mload(returnData)) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,206 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
Copyright 2019 ZeroEx Intl.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
pragma solidity ^0.5.9;
|
|
||||||
pragma experimental ABIEncoderV2;
|
|
||||||
|
|
||||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
|
||||||
import "../src/bridges/Eth2DaiBridge.sol";
|
|
||||||
import "../src/interfaces/IEth2Dai.sol";
|
|
||||||
|
|
||||||
|
|
||||||
// solhint-disable no-simple-event-func-name
|
|
||||||
contract TestEvents {
|
|
||||||
|
|
||||||
event TokenTransfer(
|
|
||||||
address token,
|
|
||||||
address from,
|
|
||||||
address to,
|
|
||||||
uint256 amount
|
|
||||||
);
|
|
||||||
|
|
||||||
event TokenApprove(
|
|
||||||
address token,
|
|
||||||
address spender,
|
|
||||||
uint256 allowance
|
|
||||||
);
|
|
||||||
|
|
||||||
function raiseTokenTransfer(
|
|
||||||
address from,
|
|
||||||
address to,
|
|
||||||
uint256 amount
|
|
||||||
)
|
|
||||||
external
|
|
||||||
{
|
|
||||||
emit TokenTransfer(
|
|
||||||
msg.sender,
|
|
||||||
from,
|
|
||||||
to,
|
|
||||||
amount
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function raiseTokenApprove(address spender, uint256 allowance)
|
|
||||||
external
|
|
||||||
{
|
|
||||||
emit TokenApprove(msg.sender, spender, allowance);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// @dev A minimalist ERC20 token.
|
|
||||||
contract TestToken {
|
|
||||||
|
|
||||||
mapping (address => uint256) public balances;
|
|
||||||
string private _nextTransferRevertReason;
|
|
||||||
bytes private _nextTransferReturnData;
|
|
||||||
|
|
||||||
/// @dev Just calls `raiseTokenTransfer()` on the caller.
|
|
||||||
function transfer(address to, uint256 amount)
|
|
||||||
external
|
|
||||||
returns (bool)
|
|
||||||
{
|
|
||||||
TestEvents(msg.sender).raiseTokenTransfer(msg.sender, to, amount);
|
|
||||||
if (bytes(_nextTransferRevertReason).length != 0) {
|
|
||||||
revert(_nextTransferRevertReason);
|
|
||||||
}
|
|
||||||
bytes memory returnData = _nextTransferReturnData;
|
|
||||||
assembly { return(add(returnData, 0x20), mload(returnData)) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @dev Set the balance for `owner`.
|
|
||||||
function setBalance(address owner, uint256 balance)
|
|
||||||
external
|
|
||||||
{
|
|
||||||
balances[owner] = balance;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @dev Set the behavior of the `transfer()` call.
|
|
||||||
function setTransferBehavior(
|
|
||||||
string calldata revertReason,
|
|
||||||
bytes calldata returnData
|
|
||||||
)
|
|
||||||
external
|
|
||||||
{
|
|
||||||
_nextTransferRevertReason = revertReason;
|
|
||||||
_nextTransferReturnData = returnData;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @dev Just calls `raiseTokenApprove()` on the caller.
|
|
||||||
function approve(address spender, uint256 allowance)
|
|
||||||
external
|
|
||||||
returns (bool)
|
|
||||||
{
|
|
||||||
TestEvents(msg.sender).raiseTokenApprove(spender, allowance);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 Eth2DaiBridge overridden to mock tokens and
|
|
||||||
/// implement IEth2Dai.
|
|
||||||
contract TestEth2DaiBridge is
|
|
||||||
TestEvents,
|
|
||||||
IEth2Dai,
|
|
||||||
Eth2DaiBridge
|
|
||||||
{
|
|
||||||
event SellAllAmount(
|
|
||||||
address sellToken,
|
|
||||||
uint256 sellTokenAmount,
|
|
||||||
address buyToken,
|
|
||||||
uint256 minimumFillAmount
|
|
||||||
);
|
|
||||||
|
|
||||||
mapping (address => TestToken) public testTokens;
|
|
||||||
string private _nextRevertReason;
|
|
||||||
uint256 private _nextFillAmount;
|
|
||||||
|
|
||||||
/// @dev Create a token and set this contract's balance.
|
|
||||||
function createToken(uint256 balance)
|
|
||||||
external
|
|
||||||
returns (address tokenAddress)
|
|
||||||
{
|
|
||||||
TestToken token = new TestToken();
|
|
||||||
testTokens[address(token)] = token;
|
|
||||||
token.setBalance(address(this), balance);
|
|
||||||
return address(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @dev Set the behavior for `IEth2Dai.sellAllAmount()`.
|
|
||||||
function setFillBehavior(string calldata revertReason, uint256 fillAmount)
|
|
||||||
external
|
|
||||||
{
|
|
||||||
_nextRevertReason = revertReason;
|
|
||||||
_nextFillAmount = fillAmount;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @dev Set the behavior of a token's `transfer()`.
|
|
||||||
function setTransferBehavior(
|
|
||||||
address tokenAddress,
|
|
||||||
string calldata revertReason,
|
|
||||||
bytes calldata returnData
|
|
||||||
)
|
|
||||||
external
|
|
||||||
{
|
|
||||||
testTokens[tokenAddress].setTransferBehavior(revertReason, returnData);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @dev Implementation of `IEth2Dai.sellAllAmount()`
|
|
||||||
function sellAllAmount(
|
|
||||||
address sellTokenAddress,
|
|
||||||
uint256 sellTokenAmount,
|
|
||||||
address buyTokenAddress,
|
|
||||||
uint256 minimumFillAmount
|
|
||||||
)
|
|
||||||
external
|
|
||||||
returns (uint256 fillAmount)
|
|
||||||
{
|
|
||||||
emit SellAllAmount(
|
|
||||||
sellTokenAddress,
|
|
||||||
sellTokenAmount,
|
|
||||||
buyTokenAddress,
|
|
||||||
minimumFillAmount
|
|
||||||
);
|
|
||||||
if (bytes(_nextRevertReason).length != 0) {
|
|
||||||
revert(_nextRevertReason);
|
|
||||||
}
|
|
||||||
return _nextFillAmount;
|
|
||||||
}
|
|
||||||
|
|
||||||
// @dev This contract will double as the Eth2Dai contract.
|
|
||||||
function _getEth2DaiAddress()
|
|
||||||
internal
|
|
||||||
view
|
|
||||||
returns (address)
|
|
||||||
{
|
|
||||||
return address(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,355 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
Copyright 2019 ZeroEx Intl.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
pragma solidity ^0.5.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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
|
|
||||||
Copyright 2019 ZeroEx Intl.
|
Copyright 2018 ZeroEx Intl.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,436 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
Copyright 2019 ZeroEx Intl.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
pragma solidity ^0.5.9;
|
|
||||||
pragma experimental ABIEncoderV2;
|
|
||||||
|
|
||||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
|
||||||
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
|
|
||||||
import "../src/bridges/UniswapBridge.sol";
|
|
||||||
import "../src/interfaces/IUniswapExchangeFactory.sol";
|
|
||||||
import "../src/interfaces/IUniswapExchange.sol";
|
|
||||||
|
|
||||||
|
|
||||||
// solhint-disable no-simple-event-func-name
|
|
||||||
contract TestEventsRaiser {
|
|
||||||
|
|
||||||
event TokenTransfer(
|
|
||||||
address token,
|
|
||||||
address from,
|
|
||||||
address to,
|
|
||||||
uint256 amount
|
|
||||||
);
|
|
||||||
|
|
||||||
event TokenApprove(
|
|
||||||
address spender,
|
|
||||||
uint256 allowance
|
|
||||||
);
|
|
||||||
|
|
||||||
event WethDeposit(
|
|
||||||
uint256 amount
|
|
||||||
);
|
|
||||||
|
|
||||||
event WethWithdraw(
|
|
||||||
uint256 amount
|
|
||||||
);
|
|
||||||
|
|
||||||
event EthToTokenTransferInput(
|
|
||||||
address exchange,
|
|
||||||
uint256 minTokensBought,
|
|
||||||
uint256 deadline,
|
|
||||||
address recipient
|
|
||||||
);
|
|
||||||
|
|
||||||
event TokenToEthSwapInput(
|
|
||||||
address exchange,
|
|
||||||
uint256 tokensSold,
|
|
||||||
uint256 minEthBought,
|
|
||||||
uint256 deadline
|
|
||||||
);
|
|
||||||
|
|
||||||
event TokenToTokenTransferInput(
|
|
||||||
address exchange,
|
|
||||||
uint256 tokensSold,
|
|
||||||
uint256 minTokensBought,
|
|
||||||
uint256 minEthBought,
|
|
||||||
uint256 deadline,
|
|
||||||
address recipient,
|
|
||||||
address toTokenAddress
|
|
||||||
);
|
|
||||||
|
|
||||||
function raiseEthToTokenTransferInput(
|
|
||||||
uint256 minTokensBought,
|
|
||||||
uint256 deadline,
|
|
||||||
address recipient
|
|
||||||
)
|
|
||||||
external
|
|
||||||
{
|
|
||||||
emit EthToTokenTransferInput(
|
|
||||||
msg.sender,
|
|
||||||
minTokensBought,
|
|
||||||
deadline,
|
|
||||||
recipient
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function raiseTokenToEthSwapInput(
|
|
||||||
uint256 tokensSold,
|
|
||||||
uint256 minEthBought,
|
|
||||||
uint256 deadline
|
|
||||||
)
|
|
||||||
external
|
|
||||||
{
|
|
||||||
emit TokenToEthSwapInput(
|
|
||||||
msg.sender,
|
|
||||||
tokensSold,
|
|
||||||
minEthBought,
|
|
||||||
deadline
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function raiseTokenToTokenTransferInput(
|
|
||||||
uint256 tokensSold,
|
|
||||||
uint256 minTokensBought,
|
|
||||||
uint256 minEthBought,
|
|
||||||
uint256 deadline,
|
|
||||||
address recipient,
|
|
||||||
address toTokenAddress
|
|
||||||
)
|
|
||||||
external
|
|
||||||
{
|
|
||||||
emit TokenToTokenTransferInput(
|
|
||||||
msg.sender,
|
|
||||||
tokensSold,
|
|
||||||
minTokensBought,
|
|
||||||
minEthBought,
|
|
||||||
deadline,
|
|
||||||
recipient,
|
|
||||||
toTokenAddress
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
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 raiseWethDeposit(uint256 amount)
|
|
||||||
external
|
|
||||||
{
|
|
||||||
emit WethDeposit(amount);
|
|
||||||
}
|
|
||||||
|
|
||||||
function raiseWethWithdraw(uint256 amount)
|
|
||||||
external
|
|
||||||
{
|
|
||||||
emit WethWithdraw(amount);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// @dev A minimalist ERC20/WETH 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)
|
|
||||||
external
|
|
||||||
payable
|
|
||||||
{
|
|
||||||
balances[owner] = msg.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @dev Set the revert reason for `transfer()`,
|
|
||||||
/// `deposit()`, and `withdraw()`.
|
|
||||||
function setRevertReason(string calldata reason)
|
|
||||||
external
|
|
||||||
{
|
|
||||||
_nextRevertReason = reason;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @dev Just calls `raiseTokenTransfer()` on the caller.
|
|
||||||
function transfer(address to, uint256 amount)
|
|
||||||
external
|
|
||||||
returns (bool)
|
|
||||||
{
|
|
||||||
_revertIfReasonExists();
|
|
||||||
TestEventsRaiser(msg.sender).raiseTokenTransfer(msg.sender, to, amount);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @dev Just calls `raiseTokenApprove()` on the caller.
|
|
||||||
function approve(address spender, uint256 allowance)
|
|
||||||
external
|
|
||||||
returns (bool)
|
|
||||||
{
|
|
||||||
TestEventsRaiser(msg.sender).raiseTokenApprove(spender, allowance);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @dev `IWETH.deposit()` that increases balances and calls
|
|
||||||
/// `raiseWethDeposit()` on the caller.
|
|
||||||
function deposit()
|
|
||||||
external
|
|
||||||
payable
|
|
||||||
{
|
|
||||||
_revertIfReasonExists();
|
|
||||||
balances[msg.sender] += balances[msg.sender].safeAdd(msg.value);
|
|
||||||
TestEventsRaiser(msg.sender).raiseWethDeposit(msg.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @dev `IWETH.withdraw()` that just reduces balances and calls
|
|
||||||
/// `raiseWethWithdraw()` on the caller.
|
|
||||||
function withdraw(uint256 amount)
|
|
||||||
external
|
|
||||||
{
|
|
||||||
_revertIfReasonExists();
|
|
||||||
balances[msg.sender] = balances[msg.sender].safeSub(amount);
|
|
||||||
msg.sender.transfer(amount);
|
|
||||||
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
|
|
||||||
view
|
|
||||||
returns (uint256)
|
|
||||||
{
|
|
||||||
return balances[owner];
|
|
||||||
}
|
|
||||||
|
|
||||||
function _revertIfReasonExists()
|
|
||||||
private
|
|
||||||
view
|
|
||||||
{
|
|
||||||
if (bytes(_nextRevertReason).length != 0) {
|
|
||||||
revert(_nextRevertReason);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
contract TestExchange is
|
|
||||||
IUniswapExchange
|
|
||||||
{
|
|
||||||
address public tokenAddress;
|
|
||||||
string private _nextRevertReason;
|
|
||||||
|
|
||||||
constructor(address _tokenAddress) public {
|
|
||||||
tokenAddress = _tokenAddress;
|
|
||||||
}
|
|
||||||
|
|
||||||
function setFillBehavior(
|
|
||||||
string calldata revertReason
|
|
||||||
)
|
|
||||||
external
|
|
||||||
payable
|
|
||||||
{
|
|
||||||
_nextRevertReason = revertReason;
|
|
||||||
}
|
|
||||||
|
|
||||||
function ethToTokenTransferInput(
|
|
||||||
uint256 minTokensBought,
|
|
||||||
uint256 deadline,
|
|
||||||
address recipient
|
|
||||||
)
|
|
||||||
external
|
|
||||||
payable
|
|
||||||
returns (uint256 tokensBought)
|
|
||||||
{
|
|
||||||
TestEventsRaiser(msg.sender).raiseEthToTokenTransferInput(
|
|
||||||
minTokensBought,
|
|
||||||
deadline,
|
|
||||||
recipient
|
|
||||||
);
|
|
||||||
_revertIfReasonExists();
|
|
||||||
return address(this).balance;
|
|
||||||
}
|
|
||||||
|
|
||||||
function tokenToEthSwapInput(
|
|
||||||
uint256 tokensSold,
|
|
||||||
uint256 minEthBought,
|
|
||||||
uint256 deadline
|
|
||||||
)
|
|
||||||
external
|
|
||||||
returns (uint256 ethBought)
|
|
||||||
{
|
|
||||||
TestEventsRaiser(msg.sender).raiseTokenToEthSwapInput(
|
|
||||||
tokensSold,
|
|
||||||
minEthBought,
|
|
||||||
deadline
|
|
||||||
);
|
|
||||||
_revertIfReasonExists();
|
|
||||||
uint256 fillAmount = address(this).balance;
|
|
||||||
msg.sender.transfer(fillAmount);
|
|
||||||
return fillAmount;
|
|
||||||
}
|
|
||||||
|
|
||||||
function tokenToTokenTransferInput(
|
|
||||||
uint256 tokensSold,
|
|
||||||
uint256 minTokensBought,
|
|
||||||
uint256 minEthBought,
|
|
||||||
uint256 deadline,
|
|
||||||
address recipient,
|
|
||||||
address toTokenAddress
|
|
||||||
)
|
|
||||||
external
|
|
||||||
returns (uint256 tokensBought)
|
|
||||||
{
|
|
||||||
TestEventsRaiser(msg.sender).raiseTokenToTokenTransferInput(
|
|
||||||
tokensSold,
|
|
||||||
minTokensBought,
|
|
||||||
minEthBought,
|
|
||||||
deadline,
|
|
||||||
recipient,
|
|
||||||
toTokenAddress
|
|
||||||
);
|
|
||||||
_revertIfReasonExists();
|
|
||||||
return address(this).balance;
|
|
||||||
}
|
|
||||||
|
|
||||||
function toTokenAddress()
|
|
||||||
external
|
|
||||||
view
|
|
||||||
returns (address _tokenAddress)
|
|
||||||
{
|
|
||||||
return tokenAddress;
|
|
||||||
}
|
|
||||||
|
|
||||||
function _revertIfReasonExists()
|
|
||||||
private
|
|
||||||
view
|
|
||||||
{
|
|
||||||
if (bytes(_nextRevertReason).length != 0) {
|
|
||||||
revert(_nextRevertReason);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// @dev UniswapBridge overridden to mock tokens and implement IUniswapExchangeFactory.
|
|
||||||
contract TestUniswapBridge is
|
|
||||||
IUniswapExchangeFactory,
|
|
||||||
TestEventsRaiser,
|
|
||||||
UniswapBridge
|
|
||||||
{
|
|
||||||
TestToken public wethToken;
|
|
||||||
// Token address to TestToken instance.
|
|
||||||
mapping (address => TestToken) private _testTokens;
|
|
||||||
// Token address to TestExchange instance.
|
|
||||||
mapping (address => TestExchange) private _testExchanges;
|
|
||||||
|
|
||||||
constructor() public {
|
|
||||||
wethToken = new TestToken();
|
|
||||||
_testTokens[address(wethToken)] = wethToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @dev Sets the balance of this contract for an existing token.
|
|
||||||
/// The wei attached will be the balance.
|
|
||||||
function setTokenBalance(address tokenAddress)
|
|
||||||
external
|
|
||||||
payable
|
|
||||||
{
|
|
||||||
TestToken token = _testTokens[tokenAddress];
|
|
||||||
token.deposit.value(msg.value)();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @dev Sets the revert reason for an existing token.
|
|
||||||
function setTokenRevertReason(address tokenAddress, string calldata revertReason)
|
|
||||||
external
|
|
||||||
{
|
|
||||||
TestToken token = _testTokens[tokenAddress];
|
|
||||||
token.setRevertReason(revertReason);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @dev Create a token and exchange (if they don't exist) for a new token
|
|
||||||
/// and sets the exchange revert and fill behavior. The wei attached
|
|
||||||
/// will be the fill amount for the exchange.
|
|
||||||
/// @param tokenAddress The token address. If zero, one will be created.
|
|
||||||
/// @param revertReason The revert reason for exchange operations.
|
|
||||||
function createTokenAndExchange(
|
|
||||||
address tokenAddress,
|
|
||||||
string calldata revertReason
|
|
||||||
)
|
|
||||||
external
|
|
||||||
payable
|
|
||||||
returns (TestToken token, TestExchange exchange)
|
|
||||||
{
|
|
||||||
token = TestToken(tokenAddress);
|
|
||||||
if (tokenAddress == address(0)) {
|
|
||||||
token = new TestToken();
|
|
||||||
}
|
|
||||||
_testTokens[address(token)] = token;
|
|
||||||
exchange = _testExchanges[address(token)];
|
|
||||||
if (address(exchange) == address(0)) {
|
|
||||||
_testExchanges[address(token)] = exchange = new TestExchange(address(token));
|
|
||||||
}
|
|
||||||
exchange.setFillBehavior.value(msg.value)(revertReason);
|
|
||||||
return (token, exchange);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @dev `IUniswapExchangeFactory.getExchange`
|
|
||||||
function getExchange(address tokenAddress)
|
|
||||||
external
|
|
||||||
view
|
|
||||||
returns (address)
|
|
||||||
{
|
|
||||||
return address(_testExchanges[tokenAddress]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// @dev Use `wethToken`.
|
|
||||||
function _getWethAddress()
|
|
||||||
internal
|
|
||||||
view
|
|
||||||
returns (address)
|
|
||||||
{
|
|
||||||
return address(wethToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
// @dev This contract will double as the Uniswap contract.
|
|
||||||
function _getUniswapExchangeFactoryAddress()
|
|
||||||
internal
|
|
||||||
view
|
|
||||||
returns (address)
|
|
||||||
{
|
|
||||||
return address(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,253 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
Copyright 2019 ZeroEx Intl.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
pragma solidity ^0.5.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",
|
"name": "@0x/contracts-asset-proxy",
|
||||||
"version": "3.7.5",
|
"version": "2.2.8",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.12"
|
"node": ">=6.12"
|
||||||
},
|
},
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "yarn pre_build && tsc -b",
|
"build": "yarn pre_build && tsc -b",
|
||||||
"build:ci": "yarn build",
|
"build:ci": "yarn build",
|
||||||
"pre_build": "run-s compile contracts:gen generate_contract_wrappers contracts:copy",
|
"pre_build": "run-s compile generate_contract_wrappers",
|
||||||
"test": "yarn run_mocha",
|
"test": "yarn run_mocha",
|
||||||
"rebuild_and_test": "run-s build test",
|
"rebuild_and_test": "run-s build test",
|
||||||
"test:coverage": "SOLIDITY_COVERAGE=true run-s build run_mocha coverage:report:text coverage:report:lcov",
|
"test:coverage": "SOLIDITY_COVERAGE=true run-s build run_mocha coverage:report:text coverage:report:lcov",
|
||||||
@@ -21,79 +21,69 @@
|
|||||||
"run_mocha": "mocha --require source-map-support/register --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit",
|
"run_mocha": "mocha --require source-map-support/register --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit",
|
||||||
"compile": "sol-compiler",
|
"compile": "sol-compiler",
|
||||||
"watch": "sol-compiler -w",
|
"watch": "sol-compiler -w",
|
||||||
"clean": "shx rm -rf lib test/generated-artifacts test/generated-wrappers generated-artifacts generated-wrappers",
|
"clean": "shx rm -rf lib generated-artifacts generated-wrappers",
|
||||||
"generate_contract_wrappers": "abi-gen --debug --abis ${npm_package_config_abis} --output test/generated-wrappers --backend ethers",
|
"generate_contract_wrappers": "abi-gen --abis ${npm_package_config_abis} --output generated-wrappers --backend ethers",
|
||||||
"lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./test/generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
|
"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 ./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 ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
|
||||||
"coverage:report:text": "istanbul report text",
|
"coverage:report:text": "istanbul report text",
|
||||||
"coverage:report:html": "istanbul report html && open coverage/index.html",
|
"coverage:report:html": "istanbul report html && open coverage/index.html",
|
||||||
"profiler: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",
|
"coverage:report:lcov": "istanbul report lcov",
|
||||||
"test:circleci": "yarn test",
|
"test:circleci": "yarn test",
|
||||||
"contracts:gen": "contracts-gen generate",
|
"contracts:gen": "contracts-gen",
|
||||||
"contracts:copy": "contracts-gen copy",
|
"lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol"
|
||||||
"lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol",
|
|
||||||
"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": {
|
"config": {
|
||||||
"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": "./generated-artifacts/@(ERC1155Proxy|ERC20Proxy|ERC721Proxy|IAssetData|IAssetProxy|IAuthorizable|MixinAuthorizable|MultiAssetProxy|StaticCallProxy|TestStaticCallTarget).json",
|
||||||
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually."
|
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually."
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/0xProject/protocol.git"
|
"url": "https://github.com/0xProject/0x-monorepo.git"
|
||||||
},
|
},
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/0xProject/protocol/issues"
|
"url": "https://github.com/0xProject/0x-monorepo/issues"
|
||||||
},
|
},
|
||||||
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/protocol",
|
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/protocol/README.md",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@0x/abi-gen": "^5.4.19",
|
"@0x/abi-gen": "^4.2.1",
|
||||||
"@0x/contract-wrappers": "^13.12.2",
|
"@0x/contracts-gen": "^1.0.15",
|
||||||
"@0x/contracts-gen": "^2.0.30",
|
"@0x/contracts-test-utils": "^3.1.16",
|
||||||
"@0x/contracts-test-utils": "^5.3.20",
|
"@0x/dev-utils": "^2.3.3",
|
||||||
"@0x/contracts-utils": "^4.7.2",
|
"@0x/sol-compiler": "^3.1.15",
|
||||||
"@0x/dev-utils": "^4.2.1",
|
"@0x/tslint-config": "^3.0.1",
|
||||||
"@0x/sol-compiler": "^4.5.2",
|
|
||||||
"@0x/ts-doc-gen": "^0.0.28",
|
|
||||||
"@0x/tslint-config": "^4.1.3",
|
|
||||||
"@types/lodash": "4.14.104",
|
"@types/lodash": "4.14.104",
|
||||||
"@types/mocha": "^5.2.7",
|
"@types/mocha": "^5.2.7",
|
||||||
"@types/node": "12.12.54",
|
"@types/node": "*",
|
||||||
"chai": "^4.0.1",
|
"chai": "^4.0.1",
|
||||||
"chai-as-promised": "^7.1.0",
|
"chai-as-promised": "^7.1.0",
|
||||||
"chai-bignumber": "^3.0.0",
|
"chai-bignumber": "^3.0.0",
|
||||||
"dirty-chai": "^2.0.1",
|
"dirty-chai": "^2.0.1",
|
||||||
"ethereumjs-util": "^5.1.1",
|
|
||||||
"make-promises-safe": "^1.1.0",
|
"make-promises-safe": "^1.1.0",
|
||||||
"mocha": "^6.2.0",
|
"mocha": "^6.2.0",
|
||||||
"npm-run-all": "^4.1.2",
|
"npm-run-all": "^4.1.2",
|
||||||
"shx": "^0.2.2",
|
"shx": "^0.2.2",
|
||||||
"solhint": "^1.4.1",
|
"solhint": "^1.4.1",
|
||||||
"truffle": "^5.0.32",
|
|
||||||
"tslint": "5.11.0",
|
"tslint": "5.11.0",
|
||||||
"typedoc": "~0.16.11",
|
|
||||||
"typescript": "3.0.1"
|
"typescript": "3.0.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@0x/base-contract": "^6.2.18",
|
"@0x/base-contract": "^5.4.0",
|
||||||
"@0x/contracts-erc1155": "^2.1.23",
|
"@0x/contracts-erc1155": "^1.1.15",
|
||||||
"@0x/contracts-erc20": "^3.3.2",
|
"@0x/contracts-erc20": "^2.2.14",
|
||||||
"@0x/contracts-erc721": "^3.1.23",
|
"@0x/contracts-erc721": "^2.1.15",
|
||||||
"@0x/contracts-exchange-libs": "^4.3.23",
|
"@0x/contracts-utils": "^3.2.4",
|
||||||
"@0x/order-utils": "^10.4.15",
|
"@0x/order-utils": "^8.4.0",
|
||||||
"@0x/types": "^3.3.1",
|
"@0x/types": "^2.4.3",
|
||||||
"@0x/typescript-typings": "^5.1.6",
|
"@0x/typescript-typings": "^4.3.0",
|
||||||
"@0x/utils": "^6.2.0",
|
"@0x/utils": "^4.5.2",
|
||||||
"@0x/web3-wrapper": "^7.4.1",
|
"@0x/web3-wrapper": "^6.0.13",
|
||||||
"ethereum-types": "^3.4.0",
|
"ethereum-types": "^2.1.6",
|
||||||
|
"ethereumjs-util": "^5.1.1",
|
||||||
"lodash": "^4.17.11"
|
"lodash": "^4.17.11"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public"
|
||||||
},
|
}
|
||||||
"gitHead": "4f91bfd907996b2f4dd383778b50c479c2602b56"
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,123 +5,25 @@
|
|||||||
*/
|
*/
|
||||||
import { ContractArtifact } from 'ethereum-types';
|
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 ERC1155Proxy from '../generated-artifacts/ERC1155Proxy.json';
|
||||||
import * as ERC20BridgeProxy from '../generated-artifacts/ERC20BridgeProxy.json';
|
|
||||||
import * as ERC20Proxy from '../generated-artifacts/ERC20Proxy.json';
|
import * as ERC20Proxy from '../generated-artifacts/ERC20Proxy.json';
|
||||||
import * as ERC721Proxy from '../generated-artifacts/ERC721Proxy.json';
|
import * as ERC721Proxy from '../generated-artifacts/ERC721Proxy.json';
|
||||||
import * as Eth2DaiBridge from '../generated-artifacts/Eth2DaiBridge.json';
|
|
||||||
import * as IAssetData from '../generated-artifacts/IAssetData.json';
|
import * as IAssetData from '../generated-artifacts/IAssetData.json';
|
||||||
import * as IAssetProxy from '../generated-artifacts/IAssetProxy.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 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 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 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 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 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 = {
|
export const artifacts = {
|
||||||
MixinAssetProxyDispatcher: MixinAssetProxyDispatcher as ContractArtifact,
|
|
||||||
MixinAuthorizable: MixinAuthorizable as ContractArtifact,
|
|
||||||
Ownable: Ownable as ContractArtifact,
|
|
||||||
ERC1155Proxy: ERC1155Proxy as ContractArtifact,
|
ERC1155Proxy: ERC1155Proxy as ContractArtifact,
|
||||||
ERC20BridgeProxy: ERC20BridgeProxy as ContractArtifact,
|
|
||||||
ERC20Proxy: ERC20Proxy as ContractArtifact,
|
ERC20Proxy: ERC20Proxy as ContractArtifact,
|
||||||
ERC721Proxy: ERC721Proxy as ContractArtifact,
|
ERC721Proxy: ERC721Proxy as ContractArtifact,
|
||||||
|
MixinAuthorizable: MixinAuthorizable as ContractArtifact,
|
||||||
MultiAssetProxy: MultiAssetProxy as ContractArtifact,
|
MultiAssetProxy: MultiAssetProxy as ContractArtifact,
|
||||||
StaticCallProxy: StaticCallProxy 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,
|
IAssetData: IAssetData as ContractArtifact,
|
||||||
IAssetProxy: IAssetProxy as ContractArtifact,
|
IAssetProxy: IAssetProxy as ContractArtifact,
|
||||||
IAssetProxyDispatcher: IAssetProxyDispatcher as ContractArtifact,
|
|
||||||
IAuthorizable: IAuthorizable 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,
|
TestStaticCallTarget: TestStaticCallTarget as ContractArtifact,
|
||||||
TestUniswapBridge: TestUniswapBridge as ContractArtifact,
|
|
||||||
TestUniswapV2Bridge: TestUniswapV2Bridge as ContractArtifact,
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,112 +0,0 @@
|
|||||||
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();
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
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' },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
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,93 +1,3 @@
|
|||||||
export { artifacts } from './artifacts';
|
export * from './artifacts';
|
||||||
export {
|
export * from './wrappers';
|
||||||
BalancerBridgeContract,
|
export * from '../test/utils';
|
||||||
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,62 +3,13 @@
|
|||||||
* Warning: This file is auto-generated by contracts-gen. Don't edit manually.
|
* 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/erc1155_proxy';
|
||||||
export * from '../generated-wrappers/erc20_bridge_proxy';
|
|
||||||
export * from '../generated-wrappers/erc20_proxy';
|
export * from '../generated-wrappers/erc20_proxy';
|
||||||
export * from '../generated-wrappers/erc721_proxy';
|
export * from '../generated-wrappers/erc721_proxy';
|
||||||
export * from '../generated-wrappers/eth2_dai_bridge';
|
|
||||||
export * from '../generated-wrappers/i_asset_data';
|
export * from '../generated-wrappers/i_asset_data';
|
||||||
export * from '../generated-wrappers/i_asset_proxy';
|
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_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_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/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/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_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';
|
|
||||||
|
|||||||
@@ -1,127 +0,0 @@
|
|||||||
/*
|
|
||||||
* -----------------------------------------------------------------------------
|
|
||||||
* 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,20 +1,38 @@
|
|||||||
import { blockchainTests, expect, provider, txDefaults, web3Wrapper } from '@0x/contracts-test-utils';
|
import {
|
||||||
|
chaiSetup,
|
||||||
|
constants,
|
||||||
|
expectTransactionFailedAsync,
|
||||||
|
provider,
|
||||||
|
txDefaults,
|
||||||
|
web3Wrapper,
|
||||||
|
} from '@0x/contracts-test-utils';
|
||||||
|
import { BlockchainLifecycle } from '@0x/dev-utils';
|
||||||
import { RevertReason } from '@0x/types';
|
import { RevertReason } from '@0x/types';
|
||||||
import { BigNumber } from '@0x/utils';
|
import { BigNumber } from '@0x/utils';
|
||||||
|
import * as chai from 'chai';
|
||||||
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import { artifacts } from './artifacts';
|
import { artifacts, MixinAuthorizableContract } from '../src';
|
||||||
|
|
||||||
import { MixinAuthorizableContract } from './wrappers';
|
chaiSetup.configure();
|
||||||
|
const expect = chai.expect;
|
||||||
|
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||||
|
|
||||||
blockchainTests.resets('Authorizable', () => {
|
describe('Authorizable', () => {
|
||||||
let owner: string;
|
let owner: string;
|
||||||
let notOwner: string;
|
let notOwner: string;
|
||||||
let address: string;
|
let address: string;
|
||||||
let authorizable: MixinAuthorizableContract;
|
let authorizable: MixinAuthorizableContract;
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
await blockchainLifecycle.startAsync();
|
||||||
|
});
|
||||||
|
after(async () => {
|
||||||
|
await blockchainLifecycle.revertAsync();
|
||||||
|
});
|
||||||
before(async () => {
|
before(async () => {
|
||||||
const accounts = await web3Wrapper.getAvailableAddressesAsync();
|
const accounts = await web3Wrapper.getAvailableAddressesAsync();
|
||||||
[owner, address, notOwner] = accounts.slice(0, 3);
|
[owner, address, notOwner] = _.slice(accounts, 0, 3);
|
||||||
authorizable = await MixinAuthorizableContract.deployFrom0xArtifactAsync(
|
authorizable = await MixinAuthorizableContract.deployFrom0xArtifactAsync(
|
||||||
artifacts.MixinAuthorizable,
|
artifacts.MixinAuthorizable,
|
||||||
provider,
|
provider,
|
||||||
@@ -22,106 +40,176 @@ blockchainTests.resets('Authorizable', () => {
|
|||||||
artifacts,
|
artifacts,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
beforeEach(async () => {
|
||||||
|
await blockchainLifecycle.startAsync();
|
||||||
|
});
|
||||||
|
afterEach(async () => {
|
||||||
|
await blockchainLifecycle.revertAsync();
|
||||||
|
});
|
||||||
describe('addAuthorizedAddress', () => {
|
describe('addAuthorizedAddress', () => {
|
||||||
it('should revert if not called by owner', async () => {
|
it('should throw if not called by owner', async () => {
|
||||||
const tx = authorizable.addAuthorizedAddress(notOwner).sendTransactionAsync({ from: notOwner });
|
return expectTransactionFailedAsync(
|
||||||
return expect(tx).to.revertWith(RevertReason.OnlyContractOwner);
|
authorizable.addAuthorizedAddress.sendTransactionAsync(notOwner, { from: notOwner }),
|
||||||
|
RevertReason.OnlyContractOwner,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should allow owner to add an authorized address', async () => {
|
it('should allow owner to add an authorized address', async () => {
|
||||||
await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner });
|
await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(
|
||||||
const isAuthorized = await authorizable.authorized(address).callAsync();
|
address,
|
||||||
|
{ from: owner },
|
||||||
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
|
);
|
||||||
|
const isAuthorized = await authorizable.authorized.callAsync(address);
|
||||||
expect(isAuthorized).to.be.true();
|
expect(isAuthorized).to.be.true();
|
||||||
});
|
});
|
||||||
|
it('should throw if owner attempts to authorize a duplicate address', async () => {
|
||||||
it('should revert if owner attempts to authorize a duplicate address', async () => {
|
await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(
|
||||||
await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner });
|
address,
|
||||||
const tx = authorizable.addAuthorizedAddress(address).sendTransactionAsync({ from: owner });
|
{ from: owner },
|
||||||
return expect(tx).to.revertWith(RevertReason.TargetAlreadyAuthorized);
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
|
);
|
||||||
|
return expectTransactionFailedAsync(
|
||||||
|
authorizable.addAuthorizedAddress.sendTransactionAsync(address, { from: owner }),
|
||||||
|
RevertReason.TargetAlreadyAuthorized,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('removeAuthorizedAddress', () => {
|
describe('removeAuthorizedAddress', () => {
|
||||||
it('should revert if not called by owner', async () => {
|
it('should throw if not called by owner', async () => {
|
||||||
await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner });
|
await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(
|
||||||
const tx = authorizable.removeAuthorizedAddress(address).sendTransactionAsync({ from: notOwner });
|
address,
|
||||||
return expect(tx).to.revertWith(RevertReason.OnlyContractOwner);
|
{ from: owner },
|
||||||
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
|
);
|
||||||
|
return expectTransactionFailedAsync(
|
||||||
|
authorizable.removeAuthorizedAddress.sendTransactionAsync(address, {
|
||||||
|
from: notOwner,
|
||||||
|
}),
|
||||||
|
RevertReason.OnlyContractOwner,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should allow owner to remove an authorized address', async () => {
|
it('should allow owner to remove an authorized address', async () => {
|
||||||
await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner });
|
await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(
|
||||||
await authorizable.removeAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner });
|
address,
|
||||||
const isAuthorized = await authorizable.authorized(address).callAsync();
|
{ from: owner },
|
||||||
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
|
);
|
||||||
|
await authorizable.removeAuthorizedAddress.awaitTransactionSuccessAsync(
|
||||||
|
address,
|
||||||
|
{ from: owner },
|
||||||
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
|
);
|
||||||
|
const isAuthorized = await authorizable.authorized.callAsync(address);
|
||||||
expect(isAuthorized).to.be.false();
|
expect(isAuthorized).to.be.false();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should revert if owner attempts to remove an address that is not authorized', async () => {
|
it('should throw if owner attempts to remove an address that is not authorized', async () => {
|
||||||
const tx = authorizable.removeAuthorizedAddress(address).sendTransactionAsync({ from: owner });
|
return expectTransactionFailedAsync(
|
||||||
return expect(tx).to.revertWith(RevertReason.TargetNotAuthorized);
|
authorizable.removeAuthorizedAddress.sendTransactionAsync(address, {
|
||||||
|
from: owner,
|
||||||
|
}),
|
||||||
|
RevertReason.TargetNotAuthorized,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('removeAuthorizedAddressAtIndex', () => {
|
describe('removeAuthorizedAddressAtIndex', () => {
|
||||||
it('should revert if not called by owner', async () => {
|
it('should throw if not called by owner', async () => {
|
||||||
await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner });
|
await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(
|
||||||
|
address,
|
||||||
|
{ from: owner },
|
||||||
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
|
);
|
||||||
const index = new BigNumber(0);
|
const index = new BigNumber(0);
|
||||||
const tx = authorizable
|
return expectTransactionFailedAsync(
|
||||||
.removeAuthorizedAddressAtIndex(address, index)
|
authorizable.removeAuthorizedAddressAtIndex.sendTransactionAsync(address, index, {
|
||||||
.sendTransactionAsync({ from: notOwner });
|
from: notOwner,
|
||||||
return expect(tx).to.revertWith(RevertReason.OnlyContractOwner);
|
}),
|
||||||
|
RevertReason.OnlyContractOwner,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
it('should throw if index is >= authorities.length', async () => {
|
||||||
it('should revert if index is >= authorities.length', async () => {
|
await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(
|
||||||
await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner });
|
address,
|
||||||
|
{ from: owner },
|
||||||
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
|
);
|
||||||
const index = new BigNumber(1);
|
const index = new BigNumber(1);
|
||||||
const tx = authorizable
|
return expectTransactionFailedAsync(
|
||||||
.removeAuthorizedAddressAtIndex(address, index)
|
authorizable.removeAuthorizedAddressAtIndex.sendTransactionAsync(address, index, {
|
||||||
.sendTransactionAsync({ from: owner });
|
from: owner,
|
||||||
return expect(tx).to.revertWith(RevertReason.IndexOutOfBounds);
|
}),
|
||||||
|
RevertReason.IndexOutOfBounds,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
it('should throw if owner attempts to remove an address that is not authorized', async () => {
|
||||||
it('should revert if owner attempts to remove an address that is not authorized', async () => {
|
|
||||||
const index = new BigNumber(0);
|
const index = new BigNumber(0);
|
||||||
const tx = authorizable
|
return expectTransactionFailedAsync(
|
||||||
.removeAuthorizedAddressAtIndex(address, index)
|
authorizable.removeAuthorizedAddressAtIndex.sendTransactionAsync(address, index, {
|
||||||
.sendTransactionAsync({ from: owner });
|
from: owner,
|
||||||
return expect(tx).to.revertWith(RevertReason.TargetNotAuthorized);
|
}),
|
||||||
|
RevertReason.TargetNotAuthorized,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
it('should throw if address at index does not match target', async () => {
|
||||||
it('should revert if address at index does not match target', async () => {
|
|
||||||
const address1 = address;
|
const address1 = address;
|
||||||
const address2 = notOwner;
|
const address2 = notOwner;
|
||||||
await authorizable.addAuthorizedAddress(address1).awaitTransactionSuccessAsync({ from: owner });
|
await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(
|
||||||
await authorizable.addAuthorizedAddress(address2).awaitTransactionSuccessAsync({ from: owner });
|
address1,
|
||||||
|
{ from: owner },
|
||||||
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
|
);
|
||||||
|
await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(
|
||||||
|
address2,
|
||||||
|
{ from: owner },
|
||||||
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
|
);
|
||||||
const address1Index = new BigNumber(0);
|
const address1Index = new BigNumber(0);
|
||||||
const tx = authorizable
|
return expectTransactionFailedAsync(
|
||||||
.removeAuthorizedAddressAtIndex(address2, address1Index)
|
authorizable.removeAuthorizedAddressAtIndex.sendTransactionAsync(address2, address1Index, {
|
||||||
.sendTransactionAsync({ from: owner });
|
from: owner,
|
||||||
return expect(tx).to.revertWith(RevertReason.AuthorizedAddressMismatch);
|
}),
|
||||||
|
RevertReason.AuthorizedAddressMismatch,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should allow owner to remove an authorized address', async () => {
|
it('should allow owner to remove an authorized address', async () => {
|
||||||
await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner });
|
await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(
|
||||||
|
address,
|
||||||
|
{ from: owner },
|
||||||
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
|
);
|
||||||
const index = new BigNumber(0);
|
const index = new BigNumber(0);
|
||||||
await authorizable.removeAuthorizedAddressAtIndex(address, index).awaitTransactionSuccessAsync({
|
await authorizable.removeAuthorizedAddressAtIndex.awaitTransactionSuccessAsync(
|
||||||
from: owner,
|
address,
|
||||||
});
|
index,
|
||||||
const isAuthorized = await authorizable.authorized(address).callAsync();
|
{ from: owner },
|
||||||
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
|
);
|
||||||
|
const isAuthorized = await authorizable.authorized.callAsync(address);
|
||||||
expect(isAuthorized).to.be.false();
|
expect(isAuthorized).to.be.false();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('getAuthorizedAddresses', () => {
|
describe('getAuthorizedAddresses', () => {
|
||||||
it('should return all authorized addresses', async () => {
|
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);
|
expect(initial).to.have.length(0);
|
||||||
await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner });
|
await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(
|
||||||
const afterAdd = await authorizable.getAuthorizedAddresses().callAsync();
|
address,
|
||||||
|
{ from: owner },
|
||||||
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
|
);
|
||||||
|
const afterAdd = await authorizable.getAuthorizedAddresses.callAsync();
|
||||||
expect(afterAdd).to.have.length(1);
|
expect(afterAdd).to.have.length(1);
|
||||||
expect(afterAdd).to.include(address);
|
expect(afterAdd).to.include(address);
|
||||||
await authorizable.removeAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner });
|
await authorizable.removeAuthorizedAddress.awaitTransactionSuccessAsync(
|
||||||
const afterRemove = await authorizable.getAuthorizedAddresses().callAsync();
|
address,
|
||||||
|
{ from: owner },
|
||||||
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
|
);
|
||||||
|
const afterRemove = await authorizable.getAuthorizedAddresses.callAsync();
|
||||||
expect(afterRemove).to.have.length(0);
|
expect(afterRemove).to.have.length(0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,185 +0,0 @@
|
|||||||
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));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
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);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,354 +0,0 @@
|
|||||||
import { ContractTxFunctionObj } from '@0x/contract-wrappers';
|
|
||||||
import {
|
|
||||||
blockchainTests,
|
|
||||||
constants,
|
|
||||||
expect,
|
|
||||||
filterLogsToArguments,
|
|
||||||
getRandomInteger,
|
|
||||||
randomAddress,
|
|
||||||
shortZip,
|
|
||||||
} from '@0x/contracts-test-utils';
|
|
||||||
import { BigNumber, hexUtils, NULL_ADDRESS } from '@0x/utils';
|
|
||||||
import { DecodedLogs } from 'ethereum-types';
|
|
||||||
import * as _ from 'lodash';
|
|
||||||
|
|
||||||
import { DexForwarderBridgeCall, dexForwarderBridgeDataEncoder } from '../src/dex_forwarder_bridge';
|
|
||||||
|
|
||||||
import { artifacts } from './artifacts';
|
|
||||||
import {
|
|
||||||
TestDexForwarderBridgeBridgeTransferFromCalledEventArgs as BtfCalledEventArgs,
|
|
||||||
TestDexForwarderBridgeContract,
|
|
||||||
TestDexForwarderBridgeEvents as TestEvents,
|
|
||||||
} from './wrappers';
|
|
||||||
|
|
||||||
const { ZERO_AMOUNT } = constants;
|
|
||||||
|
|
||||||
blockchainTests.resets('DexForwarderBridge unit tests', env => {
|
|
||||||
let testContract: TestDexForwarderBridgeContract;
|
|
||||||
let inputToken: string;
|
|
||||||
let outputToken: string;
|
|
||||||
const BRIDGE_SUCCESS = '0xdc1600f3';
|
|
||||||
const BRIDGE_FAILURE = '0xffffffff';
|
|
||||||
const BRIDGE_REVERT_ERROR = 'oopsie';
|
|
||||||
const NOT_AUTHORIZED_REVERT = 'DexForwarderBridge/SENDER_NOT_AUTHORIZED';
|
|
||||||
const DEFAULTS = {
|
|
||||||
toAddress: randomAddress(),
|
|
||||||
};
|
|
||||||
|
|
||||||
before(async () => {
|
|
||||||
testContract = await TestDexForwarderBridgeContract.deployFrom0xArtifactAsync(
|
|
||||||
artifacts.TestDexForwarderBridge,
|
|
||||||
env.provider,
|
|
||||||
env.txDefaults,
|
|
||||||
artifacts,
|
|
||||||
);
|
|
||||||
// Create test tokens.
|
|
||||||
[inputToken, outputToken] = [
|
|
||||||
await callAndTransactAsync(testContract.createToken()),
|
|
||||||
await callAndTransactAsync(testContract.createToken()),
|
|
||||||
];
|
|
||||||
await callAndTransactAsync(testContract.setAuthorized(env.txDefaults.from as string));
|
|
||||||
});
|
|
||||||
|
|
||||||
async function callAndTransactAsync<TResult>(fnCall: ContractTxFunctionObj<TResult>): Promise<TResult> {
|
|
||||||
const result = await fnCall.callAsync();
|
|
||||||
await fnCall.awaitTransactionSuccessAsync({}, { shouldValidate: false });
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getRandomBridgeCall(
|
|
||||||
bridgeAddress: string,
|
|
||||||
fields: Partial<DexForwarderBridgeCall> = {},
|
|
||||||
): DexForwarderBridgeCall {
|
|
||||||
return {
|
|
||||||
target: bridgeAddress,
|
|
||||||
inputTokenAmount: getRandomInteger(1, '100e18'),
|
|
||||||
outputTokenAmount: getRandomInteger(1, '100e18'),
|
|
||||||
bridgeData: hexUtils.leftPad(inputToken),
|
|
||||||
...fields,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('bridgeTransferFrom()', () => {
|
|
||||||
let goodBridgeCalls: DexForwarderBridgeCall[];
|
|
||||||
let revertingBridgeCall: DexForwarderBridgeCall;
|
|
||||||
let failingBridgeCall: DexForwarderBridgeCall;
|
|
||||||
let allBridgeCalls: DexForwarderBridgeCall[];
|
|
||||||
let totalFillableOutputAmount: BigNumber;
|
|
||||||
let totalFillableInputAmount: BigNumber;
|
|
||||||
let recipientOutputBalance: BigNumber;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
goodBridgeCalls = [];
|
|
||||||
for (let i = 0; i < 4; ++i) {
|
|
||||||
goodBridgeCalls.push(await createBridgeCallAsync({ returnCode: BRIDGE_SUCCESS }));
|
|
||||||
}
|
|
||||||
revertingBridgeCall = await createBridgeCallAsync({ revertError: BRIDGE_REVERT_ERROR });
|
|
||||||
failingBridgeCall = await createBridgeCallAsync({ returnCode: BRIDGE_FAILURE });
|
|
||||||
allBridgeCalls = _.shuffle([failingBridgeCall, revertingBridgeCall, ...goodBridgeCalls]);
|
|
||||||
|
|
||||||
totalFillableInputAmount = BigNumber.sum(...goodBridgeCalls.map(c => c.inputTokenAmount));
|
|
||||||
totalFillableOutputAmount = BigNumber.sum(...goodBridgeCalls.map(c => c.outputTokenAmount));
|
|
||||||
|
|
||||||
// Grant the taker some output tokens.
|
|
||||||
await testContract.setTokenBalance(
|
|
||||||
outputToken,
|
|
||||||
DEFAULTS.toAddress,
|
|
||||||
(recipientOutputBalance = getRandomInteger(1, '100e18')),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
async function setForwarderInputBalanceAsync(amount: BigNumber): Promise<void> {
|
|
||||||
await testContract
|
|
||||||
.setTokenBalance(inputToken, testContract.address, amount)
|
|
||||||
.awaitTransactionSuccessAsync({}, { shouldValidate: false });
|
|
||||||
}
|
|
||||||
|
|
||||||
async function createBridgeCallAsync(
|
|
||||||
opts: Partial<{
|
|
||||||
returnCode: string;
|
|
||||||
revertError: string;
|
|
||||||
callFields: Partial<DexForwarderBridgeCall>;
|
|
||||||
outputFillAmount: BigNumber;
|
|
||||||
}>,
|
|
||||||
): Promise<DexForwarderBridgeCall> {
|
|
||||||
const { returnCode, revertError, callFields, outputFillAmount } = {
|
|
||||||
returnCode: BRIDGE_SUCCESS,
|
|
||||||
revertError: '',
|
|
||||||
...opts,
|
|
||||||
};
|
|
||||||
const bridge = await callAndTransactAsync(testContract.createBridge(returnCode, revertError));
|
|
||||||
const call = getRandomBridgeCall(bridge, callFields);
|
|
||||||
await testContract
|
|
||||||
.setBridgeTransferAmount(call.target, outputFillAmount || call.outputTokenAmount)
|
|
||||||
.awaitTransactionSuccessAsync({}, { shouldValidate: false });
|
|
||||||
return call;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function callBridgeTransferFromAsync(opts: {
|
|
||||||
bridgeData: string;
|
|
||||||
sellAmount?: BigNumber;
|
|
||||||
buyAmount?: BigNumber;
|
|
||||||
}): Promise<DecodedLogs> {
|
|
||||||
// Fund the forwarder with input tokens to sell.
|
|
||||||
await setForwarderInputBalanceAsync(opts.sellAmount || totalFillableInputAmount);
|
|
||||||
const call = testContract.bridgeTransferFrom(
|
|
||||||
outputToken,
|
|
||||||
testContract.address,
|
|
||||||
DEFAULTS.toAddress,
|
|
||||||
opts.buyAmount || totalFillableOutputAmount,
|
|
||||||
opts.bridgeData,
|
|
||||||
);
|
|
||||||
const returnCode = await call.callAsync();
|
|
||||||
if (returnCode !== BRIDGE_SUCCESS) {
|
|
||||||
throw new Error('Expected BRIDGE_SUCCESS');
|
|
||||||
}
|
|
||||||
const receipt = await call.awaitTransactionSuccessAsync({}, { shouldValidate: false });
|
|
||||||
// tslint:disable-next-line: no-unnecessary-type-assertion
|
|
||||||
return receipt.logs as DecodedLogs;
|
|
||||||
}
|
|
||||||
|
|
||||||
it('succeeds with no bridge calls and no input balance', async () => {
|
|
||||||
const bridgeData = dexForwarderBridgeDataEncoder.encode({
|
|
||||||
inputToken,
|
|
||||||
calls: [],
|
|
||||||
});
|
|
||||||
await callBridgeTransferFromAsync({ bridgeData, sellAmount: ZERO_AMOUNT });
|
|
||||||
});
|
|
||||||
|
|
||||||
it('succeeds with bridge calls and no input balance', async () => {
|
|
||||||
const bridgeData = dexForwarderBridgeDataEncoder.encode({
|
|
||||||
inputToken,
|
|
||||||
calls: allBridgeCalls,
|
|
||||||
});
|
|
||||||
await callBridgeTransferFromAsync({ bridgeData, sellAmount: ZERO_AMOUNT });
|
|
||||||
});
|
|
||||||
|
|
||||||
it('succeeds with no bridge calls and an input balance', async () => {
|
|
||||||
const bridgeData = dexForwarderBridgeDataEncoder.encode({
|
|
||||||
inputToken,
|
|
||||||
calls: [],
|
|
||||||
});
|
|
||||||
await callBridgeTransferFromAsync({
|
|
||||||
bridgeData,
|
|
||||||
sellAmount: new BigNumber(1),
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('succeeds if entire input token balance is not consumed', async () => {
|
|
||||||
const bridgeData = dexForwarderBridgeDataEncoder.encode({
|
|
||||||
inputToken,
|
|
||||||
calls: allBridgeCalls,
|
|
||||||
});
|
|
||||||
await callBridgeTransferFromAsync({
|
|
||||||
bridgeData,
|
|
||||||
sellAmount: totalFillableInputAmount.plus(1),
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('fails if not authorized', async () => {
|
|
||||||
const calls = goodBridgeCalls.slice(0, 1);
|
|
||||||
const bridgeData = dexForwarderBridgeDataEncoder.encode({
|
|
||||||
inputToken,
|
|
||||||
calls,
|
|
||||||
});
|
|
||||||
await callAndTransactAsync(testContract.setAuthorized(NULL_ADDRESS));
|
|
||||||
return expect(callBridgeTransferFromAsync({ bridgeData, sellAmount: new BigNumber(1) })).to.revertWith(
|
|
||||||
NOT_AUTHORIZED_REVERT,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('succeeds with one bridge call', async () => {
|
|
||||||
const calls = goodBridgeCalls.slice(0, 1);
|
|
||||||
const bridgeData = dexForwarderBridgeDataEncoder.encode({
|
|
||||||
inputToken,
|
|
||||||
calls,
|
|
||||||
});
|
|
||||||
await callBridgeTransferFromAsync({ bridgeData, sellAmount: calls[0].inputTokenAmount });
|
|
||||||
});
|
|
||||||
|
|
||||||
it('succeeds with many bridge calls', async () => {
|
|
||||||
const calls = goodBridgeCalls;
|
|
||||||
const bridgeData = dexForwarderBridgeDataEncoder.encode({
|
|
||||||
inputToken,
|
|
||||||
calls,
|
|
||||||
});
|
|
||||||
await callBridgeTransferFromAsync({ bridgeData });
|
|
||||||
});
|
|
||||||
|
|
||||||
it('swallows a failing bridge call', async () => {
|
|
||||||
const calls = _.shuffle([...goodBridgeCalls, failingBridgeCall]);
|
|
||||||
const bridgeData = dexForwarderBridgeDataEncoder.encode({
|
|
||||||
inputToken,
|
|
||||||
calls,
|
|
||||||
});
|
|
||||||
await callBridgeTransferFromAsync({ bridgeData });
|
|
||||||
});
|
|
||||||
|
|
||||||
it('consumes input tokens for output tokens', async () => {
|
|
||||||
const calls = allBridgeCalls;
|
|
||||||
const bridgeData = dexForwarderBridgeDataEncoder.encode({
|
|
||||||
inputToken,
|
|
||||||
calls,
|
|
||||||
});
|
|
||||||
await callBridgeTransferFromAsync({ bridgeData });
|
|
||||||
const currentBridgeInputBalance = await testContract
|
|
||||||
.balanceOf(inputToken, testContract.address)
|
|
||||||
.callAsync();
|
|
||||||
expect(currentBridgeInputBalance).to.bignumber.eq(0);
|
|
||||||
const currentRecipientOutputBalance = await testContract
|
|
||||||
.balanceOf(outputToken, DEFAULTS.toAddress)
|
|
||||||
.callAsync();
|
|
||||||
expect(currentRecipientOutputBalance).to.bignumber.eq(totalFillableOutputAmount);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("transfers only up to each call's input amount to each bridge", async () => {
|
|
||||||
const calls = goodBridgeCalls;
|
|
||||||
const bridgeData = dexForwarderBridgeDataEncoder.encode({
|
|
||||||
inputToken,
|
|
||||||
calls,
|
|
||||||
});
|
|
||||||
const logs = await callBridgeTransferFromAsync({ bridgeData });
|
|
||||||
const btfs = filterLogsToArguments<BtfCalledEventArgs>(logs, TestEvents.BridgeTransferFromCalled);
|
|
||||||
for (const [call, btf] of shortZip(goodBridgeCalls, btfs)) {
|
|
||||||
expect(btf.inputTokenBalance).to.bignumber.eq(call.inputTokenAmount);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
it('transfers only up to outstanding sell amount to each bridge', async () => {
|
|
||||||
// Prepend an extra bridge call.
|
|
||||||
const calls = [
|
|
||||||
await createBridgeCallAsync({
|
|
||||||
callFields: {
|
|
||||||
inputTokenAmount: new BigNumber(1),
|
|
||||||
outputTokenAmount: new BigNumber(1),
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
...goodBridgeCalls,
|
|
||||||
];
|
|
||||||
const bridgeData = dexForwarderBridgeDataEncoder.encode({
|
|
||||||
inputToken,
|
|
||||||
calls,
|
|
||||||
});
|
|
||||||
const logs = await callBridgeTransferFromAsync({ bridgeData });
|
|
||||||
const btfs = filterLogsToArguments<BtfCalledEventArgs>(logs, TestEvents.BridgeTransferFromCalled);
|
|
||||||
expect(btfs).to.be.length(goodBridgeCalls.length + 1);
|
|
||||||
// The last call will receive 1 less token.
|
|
||||||
const lastCall = calls.slice(-1)[0];
|
|
||||||
const lastBtf = btfs.slice(-1)[0];
|
|
||||||
expect(lastBtf.inputTokenBalance).to.bignumber.eq(lastCall.inputTokenAmount.minus(1));
|
|
||||||
});
|
|
||||||
|
|
||||||
it('recoups funds from a bridge that fails', async () => {
|
|
||||||
// Prepend a call that will take the whole input amount but will
|
|
||||||
// fail.
|
|
||||||
const badCall = await createBridgeCallAsync({
|
|
||||||
callFields: { inputTokenAmount: totalFillableInputAmount },
|
|
||||||
returnCode: BRIDGE_FAILURE,
|
|
||||||
});
|
|
||||||
const calls = [badCall, ...goodBridgeCalls];
|
|
||||||
const bridgeData = dexForwarderBridgeDataEncoder.encode({
|
|
||||||
inputToken,
|
|
||||||
calls,
|
|
||||||
});
|
|
||||||
const logs = await callBridgeTransferFromAsync({ bridgeData });
|
|
||||||
const btfs = filterLogsToArguments<BtfCalledEventArgs>(logs, TestEvents.BridgeTransferFromCalled);
|
|
||||||
expect(btfs).to.be.length(goodBridgeCalls.length);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('recoups funds from a bridge that reverts', async () => {
|
|
||||||
// Prepend a call that will take the whole input amount but will
|
|
||||||
// revert.
|
|
||||||
const badCall = await createBridgeCallAsync({
|
|
||||||
callFields: { inputTokenAmount: totalFillableInputAmount },
|
|
||||||
revertError: BRIDGE_REVERT_ERROR,
|
|
||||||
});
|
|
||||||
const calls = [badCall, ...goodBridgeCalls];
|
|
||||||
const bridgeData = dexForwarderBridgeDataEncoder.encode({
|
|
||||||
inputToken,
|
|
||||||
calls,
|
|
||||||
});
|
|
||||||
const logs = await callBridgeTransferFromAsync({ bridgeData });
|
|
||||||
const btfs = filterLogsToArguments<BtfCalledEventArgs>(logs, TestEvents.BridgeTransferFromCalled);
|
|
||||||
expect(btfs).to.be.length(goodBridgeCalls.length);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('recoups funds from a bridge that under-pays', async () => {
|
|
||||||
// Prepend a call that will take the whole input amount but will
|
|
||||||
// underpay the output amount..
|
|
||||||
const badCall = await createBridgeCallAsync({
|
|
||||||
callFields: {
|
|
||||||
inputTokenAmount: totalFillableInputAmount,
|
|
||||||
outputTokenAmount: new BigNumber(2),
|
|
||||||
},
|
|
||||||
outputFillAmount: new BigNumber(1),
|
|
||||||
});
|
|
||||||
const calls = [badCall, ...goodBridgeCalls];
|
|
||||||
const bridgeData = dexForwarderBridgeDataEncoder.encode({
|
|
||||||
inputToken,
|
|
||||||
calls,
|
|
||||||
});
|
|
||||||
const logs = await callBridgeTransferFromAsync({ bridgeData });
|
|
||||||
const btfs = filterLogsToArguments<BtfCalledEventArgs>(logs, TestEvents.BridgeTransferFromCalled);
|
|
||||||
expect(btfs).to.be.length(goodBridgeCalls.length);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('executeBridgeCall()', () => {
|
|
||||||
it('cannot be called externally', async () => {
|
|
||||||
return expect(
|
|
||||||
testContract
|
|
||||||
.executeBridgeCall(
|
|
||||||
randomAddress(),
|
|
||||||
randomAddress(),
|
|
||||||
randomAddress(),
|
|
||||||
randomAddress(),
|
|
||||||
new BigNumber(1),
|
|
||||||
new BigNumber(1),
|
|
||||||
constants.NULL_BYTES,
|
|
||||||
)
|
|
||||||
.callAsync(),
|
|
||||||
).to.revertWith('DexForwarderBridge/ONLY_SELF');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,399 +0,0 @@
|
|||||||
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);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -14,8 +14,8 @@ import {
|
|||||||
txDefaults,
|
txDefaults,
|
||||||
web3Wrapper,
|
web3Wrapper,
|
||||||
} from '@0x/contracts-test-utils';
|
} from '@0x/contracts-test-utils';
|
||||||
import { SafeMathRevertErrors } from '@0x/contracts-utils';
|
|
||||||
import { BlockchainLifecycle } from '@0x/dev-utils';
|
import { BlockchainLifecycle } from '@0x/dev-utils';
|
||||||
|
import { assetDataUtils } from '@0x/order-utils';
|
||||||
import { AssetProxyId, RevertReason } from '@0x/types';
|
import { AssetProxyId, RevertReason } from '@0x/types';
|
||||||
import { BigNumber } from '@0x/utils';
|
import { BigNumber } from '@0x/utils';
|
||||||
import * as chai from 'chai';
|
import * as chai from 'chai';
|
||||||
@@ -23,10 +23,7 @@ import { LogWithDecodedArgs } from 'ethereum-types';
|
|||||||
import * as ethUtil from 'ethereumjs-util';
|
import * as ethUtil from 'ethereumjs-util';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import { ERC1155ProxyWrapper } from '../src/erc1155_proxy_wrapper';
|
import { artifacts, ERC1155ProxyContract, ERC1155ProxyWrapper } from '../src';
|
||||||
import { ERC1155ProxyContract, IAssetDataContract } from '../src/wrappers';
|
|
||||||
|
|
||||||
import { artifacts } from './artifacts';
|
|
||||||
|
|
||||||
chaiSetup.configure();
|
chaiSetup.configure();
|
||||||
const expect = chai.expect;
|
const expect = chai.expect;
|
||||||
@@ -62,8 +59,6 @@ describe('ERC1155Proxy', () => {
|
|||||||
// tokens
|
// tokens
|
||||||
let fungibleTokens: BigNumber[];
|
let fungibleTokens: BigNumber[];
|
||||||
let nonFungibleTokensOwnedBySpender: BigNumber[];
|
let nonFungibleTokensOwnedBySpender: BigNumber[];
|
||||||
// IAssetData for encoding and decoding assetData
|
|
||||||
let assetDataContract: IAssetDataContract;
|
|
||||||
// tests
|
// tests
|
||||||
before(async () => {
|
before(async () => {
|
||||||
await blockchainLifecycle.startAsync();
|
await blockchainLifecycle.startAsync();
|
||||||
@@ -77,8 +72,16 @@ describe('ERC1155Proxy', () => {
|
|||||||
const usedAddresses = ([owner, notAuthorized, authorized, spender, receiver] = _.slice(accounts, 0, 5));
|
const usedAddresses = ([owner, notAuthorized, authorized, spender, receiver] = _.slice(accounts, 0, 5));
|
||||||
erc1155ProxyWrapper = new ERC1155ProxyWrapper(provider, usedAddresses, owner);
|
erc1155ProxyWrapper = new ERC1155ProxyWrapper(provider, usedAddresses, owner);
|
||||||
erc1155Proxy = await erc1155ProxyWrapper.deployProxyAsync();
|
erc1155Proxy = await erc1155ProxyWrapper.deployProxyAsync();
|
||||||
await erc1155Proxy.addAuthorizedAddress(authorized).awaitTransactionSuccessAsync({ from: owner });
|
await erc1155Proxy.addAuthorizedAddress.awaitTransactionSuccessAsync(
|
||||||
await erc1155Proxy.addAuthorizedAddress(erc1155Proxy.address).awaitTransactionSuccessAsync({ from: owner });
|
authorized,
|
||||||
|
{ from: owner },
|
||||||
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
|
);
|
||||||
|
await erc1155Proxy.addAuthorizedAddress.awaitTransactionSuccessAsync(
|
||||||
|
erc1155Proxy.address,
|
||||||
|
{ from: owner },
|
||||||
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
|
);
|
||||||
// deploy & configure ERC1155 tokens and receiver
|
// deploy & configure ERC1155 tokens and receiver
|
||||||
[erc1155Wrapper] = await erc1155ProxyWrapper.deployDummyContractsAsync();
|
[erc1155Wrapper] = await erc1155ProxyWrapper.deployDummyContractsAsync();
|
||||||
erc1155Contract = erc1155Wrapper.getContract();
|
erc1155Contract = erc1155Wrapper.getContract();
|
||||||
@@ -100,8 +103,6 @@ describe('ERC1155Proxy', () => {
|
|||||||
tokenBalances.nonFungible[spender][erc1155Contract.address][nonFungibleTokenAsString][0];
|
tokenBalances.nonFungible[spender][erc1155Contract.address][nonFungibleTokenAsString][0];
|
||||||
nonFungibleTokensOwnedBySpender.push(nonFungibleTokenHeldBySpender);
|
nonFungibleTokensOwnedBySpender.push(nonFungibleTokenHeldBySpender);
|
||||||
});
|
});
|
||||||
// set up assetDataContract
|
|
||||||
assetDataContract = new IAssetDataContract(constants.NULL_ADDRESS, provider, { from: owner });
|
|
||||||
});
|
});
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await blockchainLifecycle.startAsync();
|
await blockchainLifecycle.startAsync();
|
||||||
@@ -122,7 +123,7 @@ describe('ERC1155Proxy', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
it('should have an id of 0xa7cb5fb7', async () => {
|
it('should have an id of 0xa7cb5fb7', async () => {
|
||||||
const proxyId = await erc1155Proxy.getProxyId().callAsync();
|
const proxyId = await erc1155Proxy.getProxyId.callAsync();
|
||||||
const expectedProxyId = AssetProxyId.ERC1155;
|
const expectedProxyId = AssetProxyId.ERC1155;
|
||||||
expect(proxyId).to.equal(expectedProxyId);
|
expect(proxyId).to.equal(expectedProxyId);
|
||||||
});
|
});
|
||||||
@@ -637,9 +638,12 @@ describe('ERC1155Proxy', () => {
|
|||||||
return value.times(valueMultiplier);
|
return value.times(valueMultiplier);
|
||||||
});
|
});
|
||||||
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
|
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
|
||||||
const assetData = assetDataContract
|
const assetData = assetDataUtils.encodeERC1155AssetData(
|
||||||
.ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
|
erc1155ContractAddress,
|
||||||
.getABIEncodedTransactionData();
|
tokensToTransfer,
|
||||||
|
valuesToTransfer,
|
||||||
|
receiverCallbackData,
|
||||||
|
);
|
||||||
const extraData = '0102030405060708091001020304050607080910010203040506070809100102';
|
const extraData = '0102030405060708091001020304050607080910010203040506070809100102';
|
||||||
const assetDataWithExtraData = `${assetData}${extraData}`;
|
const assetDataWithExtraData = `${assetData}${extraData}`;
|
||||||
// check balances before transfer
|
// check balances before transfer
|
||||||
@@ -692,20 +696,25 @@ describe('ERC1155Proxy', () => {
|
|||||||
const tokenUri = '';
|
const tokenUri = '';
|
||||||
for (const tokenToCreate of tokensToCreate) {
|
for (const tokenToCreate of tokensToCreate) {
|
||||||
// create token
|
// create token
|
||||||
await erc1155Wrapper
|
await erc1155Wrapper.getContract().createWithType.awaitTransactionSuccessAsync(
|
||||||
.getContract()
|
tokenToCreate,
|
||||||
.createWithType(tokenToCreate, tokenUri)
|
tokenUri,
|
||||||
.awaitTransactionSuccessAsync({
|
{
|
||||||
from: owner,
|
from: owner,
|
||||||
});
|
},
|
||||||
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
|
);
|
||||||
|
|
||||||
// mint balance for spender
|
// mint balance for spender
|
||||||
await erc1155Wrapper
|
await erc1155Wrapper.getContract().mintFungible.awaitTransactionSuccessAsync(
|
||||||
.getContract()
|
tokenToCreate,
|
||||||
.mintFungible(tokenToCreate, [spender], [spenderInitialBalance])
|
[spender],
|
||||||
.awaitTransactionSuccessAsync({
|
[spenderInitialBalance],
|
||||||
|
{
|
||||||
from: owner,
|
from: owner,
|
||||||
});
|
},
|
||||||
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
///// Step 2/5 /////
|
///// Step 2/5 /////
|
||||||
// Check balances before transfer
|
// Check balances before transfer
|
||||||
@@ -738,15 +747,18 @@ describe('ERC1155Proxy', () => {
|
|||||||
const tokensToTransfer = [new BigNumber(1), new BigNumber(2)];
|
const tokensToTransfer = [new BigNumber(1), new BigNumber(2)];
|
||||||
const valuesToTransfer = tokensToTransfer;
|
const valuesToTransfer = tokensToTransfer;
|
||||||
const valueMultiplier = new BigNumber(2);
|
const valueMultiplier = new BigNumber(2);
|
||||||
|
const assetData = assetDataUtils.encodeERC1155AssetData(
|
||||||
// hand encode optimized assetData because our tooling (based on LibAssetData.sol/ERC1155Assets) does not use optimized encoding
|
erc1155ContractAddress,
|
||||||
const selector = assetDataContract.getSelector('ERC1155Assets');
|
tokensToTransfer,
|
||||||
const assetDataWithoutContractAddress =
|
valuesToTransfer,
|
||||||
|
receiverCallbackData,
|
||||||
|
);
|
||||||
|
// remove the function selector and contract address from check, as these change on each test
|
||||||
|
const offsetToTokenIds = 74;
|
||||||
|
const assetDataWithoutContractAddress = assetData.substr(offsetToTokenIds);
|
||||||
|
const expectedAssetDataWithoutContractAddress =
|
||||||
'0000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000040102030400000000000000000000000000000000000000000000000000000000';
|
'0000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000040102030400000000000000000000000000000000000000000000000000000000';
|
||||||
const assetData = `${selector}000000000000000000000000${erc1155ContractAddress.substr(
|
expect(assetDataWithoutContractAddress).to.be.equal(expectedAssetDataWithoutContractAddress);
|
||||||
2,
|
|
||||||
)}${assetDataWithoutContractAddress}`;
|
|
||||||
|
|
||||||
///// Step 4/5 /////
|
///// Step 4/5 /////
|
||||||
// Transfer token IDs [1, 2] and amounts [1, 2] with a multiplier of 2;
|
// Transfer token IDs [1, 2] and amounts [1, 2] with a multiplier of 2;
|
||||||
// the expected trade will be token IDs [1, 2] and amounts [2, 4]
|
// the expected trade will be token IDs [1, 2] and amounts [2, 4]
|
||||||
@@ -793,20 +805,25 @@ describe('ERC1155Proxy', () => {
|
|||||||
const tokenUri = '';
|
const tokenUri = '';
|
||||||
for (const tokenToCreate of tokensToCreate) {
|
for (const tokenToCreate of tokensToCreate) {
|
||||||
// create token
|
// create token
|
||||||
await erc1155Wrapper
|
await erc1155Wrapper.getContract().createWithType.awaitTransactionSuccessAsync(
|
||||||
.getContract()
|
tokenToCreate,
|
||||||
.createWithType(tokenToCreate, tokenUri)
|
tokenUri,
|
||||||
.awaitTransactionSuccessAsync({
|
{
|
||||||
from: owner,
|
from: owner,
|
||||||
});
|
},
|
||||||
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
|
);
|
||||||
|
|
||||||
// mint balance for spender
|
// mint balance for spender
|
||||||
await erc1155Wrapper
|
await erc1155Wrapper.getContract().mintFungible.awaitTransactionSuccessAsync(
|
||||||
.getContract()
|
tokenToCreate,
|
||||||
.mintFungible(tokenToCreate, [spender], [spenderInitialBalance])
|
[spender],
|
||||||
.awaitTransactionSuccessAsync({
|
[spenderInitialBalance],
|
||||||
|
{
|
||||||
from: owner,
|
from: owner,
|
||||||
});
|
},
|
||||||
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
///// Step 2/5 /////
|
///// Step 2/5 /////
|
||||||
// Check balances before transfer
|
// Check balances before transfer
|
||||||
@@ -850,9 +867,12 @@ describe('ERC1155Proxy', () => {
|
|||||||
const valuesToTransfer = [new BigNumber(2), new BigNumber(2)];
|
const valuesToTransfer = [new BigNumber(2), new BigNumber(2)];
|
||||||
const valueMultiplier = new BigNumber(2);
|
const valueMultiplier = new BigNumber(2);
|
||||||
// create callback data that is the encoded version of `valuesToTransfer`
|
// create callback data that is the encoded version of `valuesToTransfer`
|
||||||
const generatedAssetData = assetDataContract
|
const generatedAssetData = assetDataUtils.encodeERC1155AssetData(
|
||||||
.ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
|
erc1155ContractAddress,
|
||||||
.getABIEncodedTransactionData();
|
tokensToTransfer,
|
||||||
|
valuesToTransfer,
|
||||||
|
receiverCallbackData,
|
||||||
|
);
|
||||||
// remove the function selector and contract address from check, as these change on each test
|
// remove the function selector and contract address from check, as these change on each test
|
||||||
const offsetToTokenIds = 74;
|
const offsetToTokenIds = 74;
|
||||||
const assetDataSelectorAndContractAddress = generatedAssetData.substr(0, offsetToTokenIds);
|
const assetDataSelectorAndContractAddress = generatedAssetData.substr(0, offsetToTokenIds);
|
||||||
@@ -917,20 +937,25 @@ describe('ERC1155Proxy', () => {
|
|||||||
const tokenUri = '';
|
const tokenUri = '';
|
||||||
for (const tokenToCreate of tokensToCreate) {
|
for (const tokenToCreate of tokensToCreate) {
|
||||||
// create token
|
// create token
|
||||||
await erc1155Wrapper
|
await erc1155Wrapper.getContract().createWithType.awaitTransactionSuccessAsync(
|
||||||
.getContract()
|
tokenToCreate,
|
||||||
.createWithType(tokenToCreate, tokenUri)
|
tokenUri,
|
||||||
.awaitTransactionSuccessAsync({
|
{
|
||||||
from: owner,
|
from: owner,
|
||||||
});
|
},
|
||||||
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
|
);
|
||||||
|
|
||||||
// mint balance for spender
|
// mint balance for spender
|
||||||
await erc1155Wrapper
|
await erc1155Wrapper.getContract().mintFungible.awaitTransactionSuccessAsync(
|
||||||
.getContract()
|
tokenToCreate,
|
||||||
.mintFungible(tokenToCreate, [spender], [spenderInitialBalance])
|
[spender],
|
||||||
.awaitTransactionSuccessAsync({
|
[spenderInitialBalance],
|
||||||
|
{
|
||||||
from: owner,
|
from: owner,
|
||||||
});
|
},
|
||||||
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
///// Step 2/5 /////
|
///// Step 2/5 /////
|
||||||
// Check balances before transfer
|
// Check balances before transfer
|
||||||
@@ -971,9 +996,12 @@ describe('ERC1155Proxy', () => {
|
|||||||
const valuesToTransfer = [new BigNumber(1), new BigNumber(2)];
|
const valuesToTransfer = [new BigNumber(1), new BigNumber(2)];
|
||||||
const valueMultiplier = new BigNumber(2);
|
const valueMultiplier = new BigNumber(2);
|
||||||
// create callback data that is the encoded version of `valuesToTransfer`
|
// create callback data that is the encoded version of `valuesToTransfer`
|
||||||
const generatedAssetData = assetDataContract
|
const generatedAssetData = assetDataUtils.encodeERC1155AssetData(
|
||||||
.ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
|
erc1155ContractAddress,
|
||||||
.getABIEncodedTransactionData();
|
tokensToTransfer,
|
||||||
|
valuesToTransfer,
|
||||||
|
receiverCallbackData,
|
||||||
|
);
|
||||||
// remove the function selector and contract address from check, as these change on each test
|
// remove the function selector and contract address from check, as these change on each test
|
||||||
const offsetToTokenIds = 74;
|
const offsetToTokenIds = 74;
|
||||||
const assetDataSelectorAndContractAddress = generatedAssetData.substr(0, offsetToTokenIds);
|
const assetDataSelectorAndContractAddress = generatedAssetData.substr(0, offsetToTokenIds);
|
||||||
@@ -1031,9 +1059,12 @@ describe('ERC1155Proxy', () => {
|
|||||||
const valuesToTransfer = [fungibleValueToTransferLarge];
|
const valuesToTransfer = [fungibleValueToTransferLarge];
|
||||||
const valueMultiplier = valueMultiplierSmall;
|
const valueMultiplier = valueMultiplierSmall;
|
||||||
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
|
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
|
||||||
const assetData = assetDataContract
|
const assetData = assetDataUtils.encodeERC1155AssetData(
|
||||||
.ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
|
erc1155ContractAddress,
|
||||||
.getABIEncodedTransactionData();
|
tokensToTransfer,
|
||||||
|
valuesToTransfer,
|
||||||
|
receiverCallbackData,
|
||||||
|
);
|
||||||
// The asset data we just generated will look like this:
|
// The asset data we just generated will look like this:
|
||||||
// a7cb5fb7
|
// a7cb5fb7
|
||||||
// 0x 0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082
|
// 0x 0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082
|
||||||
@@ -1075,9 +1106,12 @@ describe('ERC1155Proxy', () => {
|
|||||||
const valuesToTransfer = [fungibleValueToTransferLarge];
|
const valuesToTransfer = [fungibleValueToTransferLarge];
|
||||||
const valueMultiplier = valueMultiplierSmall;
|
const valueMultiplier = valueMultiplierSmall;
|
||||||
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
|
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
|
||||||
const assetData = assetDataContract
|
const assetData = assetDataUtils.encodeERC1155AssetData(
|
||||||
.ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
|
erc1155ContractAddress,
|
||||||
.getABIEncodedTransactionData();
|
tokensToTransfer,
|
||||||
|
valuesToTransfer,
|
||||||
|
receiverCallbackData,
|
||||||
|
);
|
||||||
// The asset data we just generated will look like this:
|
// The asset data we just generated will look like this:
|
||||||
// a7cb5fb7
|
// a7cb5fb7
|
||||||
// 0x 0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082
|
// 0x 0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082
|
||||||
@@ -1123,9 +1157,12 @@ describe('ERC1155Proxy', () => {
|
|||||||
const valuesToTransfer = [fungibleValueToTransferLarge];
|
const valuesToTransfer = [fungibleValueToTransferLarge];
|
||||||
const valueMultiplier = valueMultiplierSmall;
|
const valueMultiplier = valueMultiplierSmall;
|
||||||
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
|
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
|
||||||
const assetData = assetDataContract
|
const assetData = assetDataUtils.encodeERC1155AssetData(
|
||||||
.ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
|
erc1155ContractAddress,
|
||||||
.getABIEncodedTransactionData();
|
tokensToTransfer,
|
||||||
|
valuesToTransfer,
|
||||||
|
receiverCallbackData,
|
||||||
|
);
|
||||||
// The asset data we just generated will look like this:
|
// The asset data we just generated will look like this:
|
||||||
// a7cb5fb7
|
// a7cb5fb7
|
||||||
// 0x 0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082
|
// 0x 0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082
|
||||||
@@ -1171,9 +1208,12 @@ describe('ERC1155Proxy', () => {
|
|||||||
const valuesToTransfer = [fungibleValueToTransferLarge];
|
const valuesToTransfer = [fungibleValueToTransferLarge];
|
||||||
const valueMultiplier = valueMultiplierSmall;
|
const valueMultiplier = valueMultiplierSmall;
|
||||||
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
|
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
|
||||||
const assetData = assetDataContract
|
const assetData = assetDataUtils.encodeERC1155AssetData(
|
||||||
.ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
|
erc1155ContractAddress,
|
||||||
.getABIEncodedTransactionData();
|
tokensToTransfer,
|
||||||
|
valuesToTransfer,
|
||||||
|
receiverCallbackData,
|
||||||
|
);
|
||||||
// The asset data we just generated will look like this:
|
// The asset data we just generated will look like this:
|
||||||
// a7cb5fb7
|
// a7cb5fb7
|
||||||
// 0x 0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082
|
// 0x 0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082
|
||||||
@@ -1219,9 +1259,12 @@ describe('ERC1155Proxy', () => {
|
|||||||
const valuesToTransfer = [fungibleValueToTransferLarge];
|
const valuesToTransfer = [fungibleValueToTransferLarge];
|
||||||
const valueMultiplier = valueMultiplierSmall;
|
const valueMultiplier = valueMultiplierSmall;
|
||||||
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
|
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
|
||||||
const assetData = assetDataContract
|
const assetData = assetDataUtils.encodeERC1155AssetData(
|
||||||
.ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
|
erc1155ContractAddress,
|
||||||
.getABIEncodedTransactionData();
|
tokensToTransfer,
|
||||||
|
valuesToTransfer,
|
||||||
|
receiverCallbackData,
|
||||||
|
);
|
||||||
// The asset data we just generated will look like this:
|
// The asset data we just generated will look like this:
|
||||||
// a7cb5fb7
|
// a7cb5fb7
|
||||||
// 0x 0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082
|
// 0x 0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082
|
||||||
@@ -1268,9 +1311,12 @@ describe('ERC1155Proxy', () => {
|
|||||||
const valuesToTransfer = [fungibleValueToTransferLarge];
|
const valuesToTransfer = [fungibleValueToTransferLarge];
|
||||||
const valueMultiplier = valueMultiplierSmall;
|
const valueMultiplier = valueMultiplierSmall;
|
||||||
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
|
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
|
||||||
const assetData = assetDataContract
|
const assetData = assetDataUtils.encodeERC1155AssetData(
|
||||||
.ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
|
erc1155ContractAddress,
|
||||||
.getABIEncodedTransactionData();
|
tokensToTransfer,
|
||||||
|
valuesToTransfer,
|
||||||
|
receiverCallbackData,
|
||||||
|
);
|
||||||
// The asset data we just generated will look like this:
|
// The asset data we just generated will look like this:
|
||||||
// a7cb5fb7
|
// a7cb5fb7
|
||||||
// 0x 0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082
|
// 0x 0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082
|
||||||
@@ -1312,9 +1358,12 @@ describe('ERC1155Proxy', () => {
|
|||||||
const valuesToTransfer = [fungibleValueToTransferLarge];
|
const valuesToTransfer = [fungibleValueToTransferLarge];
|
||||||
const valueMultiplier = valueMultiplierSmall;
|
const valueMultiplier = valueMultiplierSmall;
|
||||||
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
|
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
|
||||||
const assetData = assetDataContract
|
const assetData = assetDataUtils.encodeERC1155AssetData(
|
||||||
.ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
|
erc1155ContractAddress,
|
||||||
.getABIEncodedTransactionData();
|
tokensToTransfer,
|
||||||
|
valuesToTransfer,
|
||||||
|
receiverCallbackData,
|
||||||
|
);
|
||||||
// The asset data we just generated will look like this:
|
// The asset data we just generated will look like this:
|
||||||
// a7cb5fb7
|
// a7cb5fb7
|
||||||
// 0x 0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082
|
// 0x 0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082
|
||||||
@@ -1360,9 +1409,12 @@ describe('ERC1155Proxy', () => {
|
|||||||
const valuesToTransfer = [fungibleValueToTransferLarge];
|
const valuesToTransfer = [fungibleValueToTransferLarge];
|
||||||
const valueMultiplier = valueMultiplierSmall;
|
const valueMultiplier = valueMultiplierSmall;
|
||||||
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
|
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
|
||||||
const assetData = assetDataContract
|
const assetData = assetDataUtils.encodeERC1155AssetData(
|
||||||
.ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
|
erc1155ContractAddress,
|
||||||
.getABIEncodedTransactionData();
|
tokensToTransfer,
|
||||||
|
valuesToTransfer,
|
||||||
|
receiverCallbackData,
|
||||||
|
);
|
||||||
// The asset data we just generated will look like this:
|
// The asset data we just generated will look like this:
|
||||||
// a7cb5fb7
|
// a7cb5fb7
|
||||||
// 0x 0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082
|
// 0x 0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082
|
||||||
@@ -1404,9 +1456,12 @@ describe('ERC1155Proxy', () => {
|
|||||||
const valuesToTransfer = [fungibleValueToTransferLarge];
|
const valuesToTransfer = [fungibleValueToTransferLarge];
|
||||||
const valueMultiplier = valueMultiplierSmall;
|
const valueMultiplier = valueMultiplierSmall;
|
||||||
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
|
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
|
||||||
const assetData = assetDataContract
|
const assetData = assetDataUtils.encodeERC1155AssetData(
|
||||||
.ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
|
erc1155ContractAddress,
|
||||||
.getABIEncodedTransactionData();
|
tokensToTransfer,
|
||||||
|
valuesToTransfer,
|
||||||
|
receiverCallbackData,
|
||||||
|
);
|
||||||
// The asset data we just generated will look like this:
|
// The asset data we just generated will look like this:
|
||||||
// a7cb5fb7
|
// a7cb5fb7
|
||||||
// 0x 0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082
|
// 0x 0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082
|
||||||
@@ -1452,10 +1507,13 @@ describe('ERC1155Proxy', () => {
|
|||||||
const valuesToTransfer = [fungibleValueToTransferLarge];
|
const valuesToTransfer = [fungibleValueToTransferLarge];
|
||||||
const valueMultiplier = valueMultiplierSmall;
|
const valueMultiplier = valueMultiplierSmall;
|
||||||
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
|
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
|
||||||
const assetData = assetDataContract
|
const assetData = assetDataUtils.encodeERC1155AssetData(
|
||||||
.ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
|
erc1155ContractAddress,
|
||||||
.getABIEncodedTransactionData();
|
tokensToTransfer,
|
||||||
const txData = await erc1155ProxyWrapper.getTransferFromAbiEncodedTxDataAsync(
|
valuesToTransfer,
|
||||||
|
receiverCallbackData,
|
||||||
|
);
|
||||||
|
const txData = erc1155ProxyWrapper.getTransferFromAbiEncodedTxData(
|
||||||
spender,
|
spender,
|
||||||
receiverContract,
|
receiverContract,
|
||||||
erc1155Contract.address,
|
erc1155Contract.address,
|
||||||
@@ -1480,10 +1538,13 @@ describe('ERC1155Proxy', () => {
|
|||||||
const valuesToTransfer = [fungibleValueToTransferLarge];
|
const valuesToTransfer = [fungibleValueToTransferLarge];
|
||||||
const valueMultiplier = valueMultiplierSmall;
|
const valueMultiplier = valueMultiplierSmall;
|
||||||
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
|
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
|
||||||
const assetData = assetDataContract
|
const assetData = assetDataUtils.encodeERC1155AssetData(
|
||||||
.ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
|
erc1155ContractAddress,
|
||||||
.getABIEncodedTransactionData();
|
tokensToTransfer,
|
||||||
const txData = await erc1155ProxyWrapper.getTransferFromAbiEncodedTxDataAsync(
|
valuesToTransfer,
|
||||||
|
receiverCallbackData,
|
||||||
|
);
|
||||||
|
const txData = erc1155ProxyWrapper.getTransferFromAbiEncodedTxData(
|
||||||
spender,
|
spender,
|
||||||
receiverContract,
|
receiverContract,
|
||||||
erc1155Contract.address,
|
erc1155Contract.address,
|
||||||
@@ -1606,9 +1667,13 @@ describe('ERC1155Proxy', () => {
|
|||||||
it('should propagate revert reason from erc1155 contract failure', async () => {
|
it('should propagate revert reason from erc1155 contract failure', async () => {
|
||||||
// disable transfers
|
// disable transfers
|
||||||
const shouldRejectTransfer = true;
|
const shouldRejectTransfer = true;
|
||||||
await erc1155Receiver.setRejectTransferFlag(shouldRejectTransfer).awaitTransactionSuccessAsync({
|
await erc1155Receiver.setRejectTransferFlag.awaitTransactionSuccessAsync(
|
||||||
from: owner,
|
shouldRejectTransfer,
|
||||||
});
|
{
|
||||||
|
from: owner,
|
||||||
|
},
|
||||||
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
|
);
|
||||||
// setup test parameters
|
// setup test parameters
|
||||||
const tokenHolders = [spender, receiverContract];
|
const tokenHolders = [spender, receiverContract];
|
||||||
const tokensToTransfer = fungibleTokens.slice(0, 1);
|
const tokensToTransfer = fungibleTokens.slice(0, 1);
|
||||||
@@ -1683,14 +1748,9 @@ describe('ERC1155Proxy', () => {
|
|||||||
nftNotOwnerBalance,
|
nftNotOwnerBalance,
|
||||||
];
|
];
|
||||||
await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances);
|
await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances);
|
||||||
const expectedError = new SafeMathRevertErrors.Uint256BinOpError(
|
|
||||||
SafeMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow,
|
|
||||||
maxUintValue,
|
|
||||||
valueMultiplier,
|
|
||||||
);
|
|
||||||
// execute transfer
|
// execute transfer
|
||||||
// note - this will overflow because we are trying to transfer `maxUintValue * 2` of the 2nd token
|
// note - this will overflow because we are trying to transfer `maxUintValue * 2` of the 2nd token
|
||||||
await expect(
|
await expectTransactionFailedAsync(
|
||||||
erc1155ProxyWrapper.transferFromAsync(
|
erc1155ProxyWrapper.transferFromAsync(
|
||||||
spender,
|
spender,
|
||||||
receiver,
|
receiver,
|
||||||
@@ -1701,7 +1761,8 @@ describe('ERC1155Proxy', () => {
|
|||||||
receiverCallbackData,
|
receiverCallbackData,
|
||||||
authorized,
|
authorized,
|
||||||
),
|
),
|
||||||
).to.revertWith(expectedError);
|
RevertReason.Uint256Overflow,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('should revert if transferring > 1 instances of a non-fungible token (valueMultiplier field >1)', async () => {
|
it('should revert if transferring > 1 instances of a non-fungible token (valueMultiplier field >1)', async () => {
|
||||||
// setup test parameters
|
// setup test parameters
|
||||||
@@ -1771,23 +1832,20 @@ describe('ERC1155Proxy', () => {
|
|||||||
// check balances before transfer
|
// check balances before transfer
|
||||||
const expectedInitialBalances = [spenderInitialFungibleBalance, receiverInitialFungibleBalance];
|
const expectedInitialBalances = [spenderInitialFungibleBalance, receiverInitialFungibleBalance];
|
||||||
await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances);
|
await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances);
|
||||||
const expectedError = new SafeMathRevertErrors.Uint256BinOpError(
|
|
||||||
SafeMathRevertErrors.BinOpErrorCodes.SubtractionUnderflow,
|
|
||||||
spenderInitialFungibleBalance,
|
|
||||||
valuesToTransfer[0].times(valueMultiplier),
|
|
||||||
);
|
|
||||||
// execute transfer
|
// execute transfer
|
||||||
const tx = erc1155ProxyWrapper.transferFromAsync(
|
await expectTransactionFailedAsync(
|
||||||
spender,
|
erc1155ProxyWrapper.transferFromAsync(
|
||||||
receiver,
|
spender,
|
||||||
erc1155Contract.address,
|
receiver,
|
||||||
tokensToTransfer,
|
erc1155Contract.address,
|
||||||
valuesToTransfer,
|
tokensToTransfer,
|
||||||
valueMultiplier,
|
valuesToTransfer,
|
||||||
receiverCallbackData,
|
valueMultiplier,
|
||||||
authorized,
|
receiverCallbackData,
|
||||||
|
authorized,
|
||||||
|
),
|
||||||
|
RevertReason.Uint256Underflow,
|
||||||
);
|
);
|
||||||
return expect(tx).to.revertWith(expectedError);
|
|
||||||
});
|
});
|
||||||
it('should revert if sender allowance is insufficient', async () => {
|
it('should revert if sender allowance is insufficient', async () => {
|
||||||
// dremove allowance for ERC1155 proxy
|
// dremove allowance for ERC1155 proxy
|
||||||
|
|||||||
@@ -1,287 +0,0 @@
|
|||||||
import {
|
|
||||||
blockchainTests,
|
|
||||||
constants,
|
|
||||||
expect,
|
|
||||||
getRandomInteger,
|
|
||||||
Numberish,
|
|
||||||
randomAddress,
|
|
||||||
} from '@0x/contracts-test-utils';
|
|
||||||
import { AuthorizableRevertErrors } from '@0x/contracts-utils';
|
|
||||||
import { AssetProxyId } from '@0x/types';
|
|
||||||
import { AbiEncoder, BigNumber, hexUtils, StringRevertError } from '@0x/utils';
|
|
||||||
import { DecodedLogs } from 'ethereum-types';
|
|
||||||
import * as _ from 'lodash';
|
|
||||||
|
|
||||||
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 = hexUtils.rightPad(PROXY_ID);
|
|
||||||
let owner: string;
|
|
||||||
let badCaller: string;
|
|
||||||
let assetProxy: ERC20BridgeProxyContract;
|
|
||||||
let bridgeContract: TestERC20BridgeContract;
|
|
||||||
let testTokenAddress: string;
|
|
||||||
|
|
||||||
before(async () => {
|
|
||||||
[owner, badCaller] = await env.getAccountAddressesAsync();
|
|
||||||
assetProxy = await ERC20BridgeProxyContract.deployFrom0xArtifactAsync(
|
|
||||||
artifacts.ERC20BridgeProxy,
|
|
||||||
env.provider,
|
|
||||||
env.txDefaults,
|
|
||||||
artifacts,
|
|
||||||
);
|
|
||||||
bridgeContract = await TestERC20BridgeContract.deployFrom0xArtifactAsync(
|
|
||||||
artifacts.TestERC20Bridge,
|
|
||||||
env.provider,
|
|
||||||
env.txDefaults,
|
|
||||||
artifacts,
|
|
||||||
);
|
|
||||||
testTokenAddress = await bridgeContract.testToken().callAsync();
|
|
||||||
await assetProxy.addAuthorizedAddress(owner).awaitTransactionSuccessAsync();
|
|
||||||
});
|
|
||||||
|
|
||||||
interface AssetDataOpts {
|
|
||||||
tokenAddress: string;
|
|
||||||
bridgeAddress: string;
|
|
||||||
bridgeData: BridgeDataOpts;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface BridgeDataOpts {
|
|
||||||
transferAmount: Numberish;
|
|
||||||
revertError?: string;
|
|
||||||
returnData: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
function createAssetData(opts?: Partial<AssetDataOpts>): AssetDataOpts {
|
|
||||||
return _.merge(
|
|
||||||
{
|
|
||||||
tokenAddress: testTokenAddress,
|
|
||||||
bridgeAddress: bridgeContract.address,
|
|
||||||
bridgeData: createBridgeData(),
|
|
||||||
},
|
|
||||||
opts,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function createBridgeData(opts?: Partial<BridgeDataOpts>): BridgeDataOpts {
|
|
||||||
return _.merge(
|
|
||||||
{
|
|
||||||
transferAmount: constants.ZERO_AMOUNT,
|
|
||||||
returnData: BRIDGE_SUCCESS_RETURN_DATA,
|
|
||||||
},
|
|
||||||
opts,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function encodeAssetData(opts: AssetDataOpts): string {
|
|
||||||
const encoder = AbiEncoder.createMethod('ERC20BridgeProxy', [
|
|
||||||
{ name: 'tokenAddress', type: 'address' },
|
|
||||||
{ name: 'bridgeAddress', type: 'address' },
|
|
||||||
{ name: 'bridgeData', type: 'bytes' },
|
|
||||||
]);
|
|
||||||
return encoder.encode([opts.tokenAddress, opts.bridgeAddress, encodeBridgeData(opts.bridgeData)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function encodeBridgeData(opts: BridgeDataOpts): string {
|
|
||||||
const encoder = AbiEncoder.create([
|
|
||||||
{ name: 'transferAmount', type: 'int256' },
|
|
||||||
{ name: 'revertData', type: 'bytes' },
|
|
||||||
{ name: 'returnData', type: 'bytes' },
|
|
||||||
]);
|
|
||||||
const revertErrorBytes =
|
|
||||||
opts.revertError !== undefined ? new StringRevertError(opts.revertError).encode() : '0x';
|
|
||||||
return encoder.encode([new BigNumber(opts.transferAmount), revertErrorBytes, opts.returnData]);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function setTestTokenBalanceAsync(_owner: string, balance: Numberish): Promise<void> {
|
|
||||||
await bridgeContract.setTestTokenBalance(_owner, new BigNumber(balance)).awaitTransactionSuccessAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('transferFrom()', () => {
|
|
||||||
interface TransferFromOpts {
|
|
||||||
assetData: AssetDataOpts;
|
|
||||||
from: string;
|
|
||||||
to: string;
|
|
||||||
amount: Numberish;
|
|
||||||
}
|
|
||||||
|
|
||||||
function createTransferFromOpts(opts?: Partial<TransferFromOpts>): TransferFromOpts {
|
|
||||||
const transferAmount = _.get(opts, ['amount'], getRandomInteger(1, 100e18)) as BigNumber;
|
|
||||||
return _.merge(
|
|
||||||
{
|
|
||||||
assetData: createAssetData({
|
|
||||||
bridgeData: createBridgeData({
|
|
||||||
transferAmount,
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
from: randomAddress(),
|
|
||||||
to: randomAddress(),
|
|
||||||
amount: transferAmount,
|
|
||||||
},
|
|
||||||
opts,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function transferFromAsync(opts?: Partial<TransferFromOpts>, caller?: string): Promise<DecodedLogs> {
|
|
||||||
const _opts = createTransferFromOpts(opts);
|
|
||||||
const { logs } = await assetProxy
|
|
||||||
.transferFrom(encodeAssetData(_opts.assetData), _opts.from, _opts.to, new BigNumber(_opts.amount))
|
|
||||||
.awaitTransactionSuccessAsync({ from: caller });
|
|
||||||
return (logs as any) as DecodedLogs;
|
|
||||||
}
|
|
||||||
|
|
||||||
it('succeeds if the bridge succeeds and balance increases by `amount`', async () => {
|
|
||||||
const tx = transferFromAsync();
|
|
||||||
return expect(tx).to.be.fulfilled('');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('succeeds if balance increases more than `amount`', async () => {
|
|
||||||
const amount = getRandomInteger(1, 100e18);
|
|
||||||
const tx = transferFromAsync({
|
|
||||||
amount,
|
|
||||||
assetData: createAssetData({
|
|
||||||
bridgeData: createBridgeData({
|
|
||||||
transferAmount: amount.plus(1),
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
return expect(tx).to.be.fulfilled('');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('passes the correct arguments to the bridge contract', async () => {
|
|
||||||
const opts = createTransferFromOpts();
|
|
||||||
const logs = await transferFromAsync(opts);
|
|
||||||
expect(logs.length).to.eq(1);
|
|
||||||
const args = logs[0].args;
|
|
||||||
expect(args.tokenAddress).to.eq(opts.assetData.tokenAddress);
|
|
||||||
expect(args.from).to.eq(opts.from);
|
|
||||||
expect(args.to).to.eq(opts.to);
|
|
||||||
expect(args.amount).to.bignumber.eq(opts.amount);
|
|
||||||
expect(args.bridgeData).to.eq(encodeBridgeData(opts.assetData.bridgeData));
|
|
||||||
});
|
|
||||||
|
|
||||||
it('fails if not called by an authorized address', async () => {
|
|
||||||
const tx = transferFromAsync({}, badCaller);
|
|
||||||
return expect(tx).to.revertWith(new AuthorizableRevertErrors.SenderNotAuthorizedError(badCaller));
|
|
||||||
});
|
|
||||||
|
|
||||||
it('fails if asset data is truncated', async () => {
|
|
||||||
const opts = createTransferFromOpts();
|
|
||||||
const truncatedAssetData = 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();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('fails if bridge returns nothing', async () => {
|
|
||||||
const tx = transferFromAsync({
|
|
||||||
assetData: createAssetData({
|
|
||||||
bridgeData: createBridgeData({
|
|
||||||
returnData: '0x',
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
// This will actually revert when the AP tries to decode the return
|
|
||||||
// value.
|
|
||||||
return expect(tx).to.be.rejected();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('fails if bridge returns true', async () => {
|
|
||||||
const tx = transferFromAsync({
|
|
||||||
assetData: createAssetData({
|
|
||||||
bridgeData: createBridgeData({
|
|
||||||
returnData: hexUtils.leftPad('0x1'),
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
// This will actually revert when the AP tries to decode the return
|
|
||||||
// value.
|
|
||||||
return expect(tx).to.be.rejected();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('fails if bridge returns 0x1', async () => {
|
|
||||||
const tx = transferFromAsync({
|
|
||||||
assetData: createAssetData({
|
|
||||||
bridgeData: createBridgeData({
|
|
||||||
returnData: hexUtils.rightPad('0x1'),
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
return expect(tx).to.revertWith('BRIDGE_FAILED');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('fails if bridge is an EOA', async () => {
|
|
||||||
const tx = transferFromAsync({
|
|
||||||
assetData: createAssetData({
|
|
||||||
bridgeAddress: randomAddress(),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
// This will actually revert when the AP tries to decode the return
|
|
||||||
// value.
|
|
||||||
return expect(tx).to.be.rejected();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('fails if bridge reverts', async () => {
|
|
||||||
const revertError = 'FOOBAR';
|
|
||||||
const tx = transferFromAsync({
|
|
||||||
assetData: createAssetData({
|
|
||||||
bridgeData: createBridgeData({
|
|
||||||
revertError,
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
return expect(tx).to.revertWith(revertError);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('fails if balance of `to` increases by less than `amount`', async () => {
|
|
||||||
const amount = getRandomInteger(1, 100e18);
|
|
||||||
const tx = transferFromAsync({
|
|
||||||
amount,
|
|
||||||
assetData: createAssetData({
|
|
||||||
bridgeData: createBridgeData({
|
|
||||||
transferAmount: amount.minus(1),
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
return expect(tx).to.revertWith('BRIDGE_UNDERPAY');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('fails if balance of `to` decreases', async () => {
|
|
||||||
const toAddress = randomAddress();
|
|
||||||
await setTestTokenBalanceAsync(toAddress, 1e18);
|
|
||||||
const tx = transferFromAsync({
|
|
||||||
to: toAddress,
|
|
||||||
assetData: createAssetData({
|
|
||||||
bridgeData: createBridgeData({
|
|
||||||
transferAmount: -1,
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
return expect(tx).to.revertWith('BRIDGE_UNDERPAY');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('balanceOf()', () => {
|
|
||||||
it('retrieves the balance of the encoded token', async () => {
|
|
||||||
const _owner = randomAddress();
|
|
||||||
const balance = getRandomInteger(1, 100e18);
|
|
||||||
await bridgeContract.setTestTokenBalance(_owner, balance).awaitTransactionSuccessAsync();
|
|
||||||
const assetData = createAssetData({
|
|
||||||
tokenAddress: testTokenAddress,
|
|
||||||
});
|
|
||||||
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();
|
|
||||||
expect(proxyId).to.eq(PROXY_ID);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,191 +0,0 @@
|
|||||||
import {
|
|
||||||
blockchainTests,
|
|
||||||
constants,
|
|
||||||
expect,
|
|
||||||
filterLogsToArguments,
|
|
||||||
getRandomInteger,
|
|
||||||
Numberish,
|
|
||||||
randomAddress,
|
|
||||||
} from '@0x/contracts-test-utils';
|
|
||||||
import { AssetProxyId } from '@0x/types';
|
|
||||||
import { BigNumber, hexUtils, RawRevertError } from '@0x/utils';
|
|
||||||
import { DecodedLogs } from 'ethereum-types';
|
|
||||||
import * as _ from 'lodash';
|
|
||||||
|
|
||||||
import { artifacts } from './artifacts';
|
|
||||||
|
|
||||||
import {
|
|
||||||
TestEth2DaiBridgeContract,
|
|
||||||
TestEth2DaiBridgeEvents,
|
|
||||||
TestEth2DaiBridgeSellAllAmountEventArgs,
|
|
||||||
TestEth2DaiBridgeTokenApproveEventArgs,
|
|
||||||
TestEth2DaiBridgeTokenTransferEventArgs,
|
|
||||||
} from './wrappers';
|
|
||||||
|
|
||||||
blockchainTests.resets('Eth2DaiBridge unit tests', env => {
|
|
||||||
let testContract: TestEth2DaiBridgeContract;
|
|
||||||
|
|
||||||
before(async () => {
|
|
||||||
testContract = await TestEth2DaiBridgeContract.deployFrom0xArtifactAsync(
|
|
||||||
artifacts.TestEth2DaiBridge,
|
|
||||||
env.provider,
|
|
||||||
env.txDefaults,
|
|
||||||
artifacts,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('isValidSignature()', () => {
|
|
||||||
it('returns success bytes', async () => {
|
|
||||||
const LEGACY_WALLET_MAGIC_VALUE = '0xb0671381';
|
|
||||||
const result = await testContract
|
|
||||||
.isValidSignature(hexUtils.random(), hexUtils.random(_.random(0, 32)))
|
|
||||||
.callAsync();
|
|
||||||
expect(result).to.eq(LEGACY_WALLET_MAGIC_VALUE);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('bridgeTransferFrom()', () => {
|
|
||||||
interface WithdrawToOpts {
|
|
||||||
toTokenAddress?: string;
|
|
||||||
fromTokenAddress?: string;
|
|
||||||
toAddress: string;
|
|
||||||
amount: Numberish;
|
|
||||||
fromTokenBalance: Numberish;
|
|
||||||
revertReason: string;
|
|
||||||
fillAmount: Numberish;
|
|
||||||
toTokentransferRevertReason: string;
|
|
||||||
toTokenTransferReturnData: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface WithdrawToResult {
|
|
||||||
opts: WithdrawToOpts;
|
|
||||||
result: string;
|
|
||||||
logs: DecodedLogs;
|
|
||||||
}
|
|
||||||
|
|
||||||
function createWithdrawToOpts(opts?: Partial<WithdrawToOpts>): WithdrawToOpts {
|
|
||||||
return {
|
|
||||||
toAddress: randomAddress(),
|
|
||||||
amount: getRandomInteger(1, 100e18),
|
|
||||||
revertReason: '',
|
|
||||||
fillAmount: getRandomInteger(1, 100e18),
|
|
||||||
fromTokenBalance: getRandomInteger(1, 100e18),
|
|
||||||
toTokentransferRevertReason: '',
|
|
||||||
toTokenTransferReturnData: hexUtils.leftPad(1),
|
|
||||||
...opts,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
async function withdrawToAsync(opts?: Partial<WithdrawToOpts>): Promise<WithdrawToResult> {
|
|
||||||
const _opts = createWithdrawToOpts(opts);
|
|
||||||
// Set the fill behavior.
|
|
||||||
await testContract
|
|
||||||
.setFillBehavior(_opts.revertReason, new BigNumber(_opts.fillAmount))
|
|
||||||
.awaitTransactionSuccessAsync();
|
|
||||||
// Create tokens and balances.
|
|
||||||
if (_opts.fromTokenAddress === undefined) {
|
|
||||||
const createTokenFn = testContract.createToken(new BigNumber(_opts.fromTokenBalance));
|
|
||||||
_opts.fromTokenAddress = await createTokenFn.callAsync();
|
|
||||||
await createTokenFn.awaitTransactionSuccessAsync();
|
|
||||||
}
|
|
||||||
if (_opts.toTokenAddress === undefined) {
|
|
||||||
const createTokenFn = testContract.createToken(constants.ZERO_AMOUNT);
|
|
||||||
_opts.toTokenAddress = await createTokenFn.callAsync();
|
|
||||||
await createTokenFn.awaitTransactionSuccessAsync();
|
|
||||||
}
|
|
||||||
// Set the transfer behavior of `toTokenAddress`.
|
|
||||||
await testContract
|
|
||||||
.setTransferBehavior(
|
|
||||||
_opts.toTokenAddress,
|
|
||||||
_opts.toTokentransferRevertReason,
|
|
||||||
_opts.toTokenTransferReturnData,
|
|
||||||
)
|
|
||||||
.awaitTransactionSuccessAsync();
|
|
||||||
// Call bridgeTransferFrom().
|
|
||||||
const bridgeTransferFromFn = testContract.bridgeTransferFrom(
|
|
||||||
// "to" token address
|
|
||||||
_opts.toTokenAddress,
|
|
||||||
// Random from address.
|
|
||||||
randomAddress(),
|
|
||||||
// To address.
|
|
||||||
_opts.toAddress,
|
|
||||||
new BigNumber(_opts.amount),
|
|
||||||
// ABI-encode the "from" token address as the bridge data.
|
|
||||||
hexUtils.leftPad(_opts.fromTokenAddress as string),
|
|
||||||
);
|
|
||||||
const result = await bridgeTransferFromFn.callAsync();
|
|
||||||
const { logs } = await bridgeTransferFromFn.awaitTransactionSuccessAsync();
|
|
||||||
return {
|
|
||||||
opts: _opts,
|
|
||||||
result,
|
|
||||||
logs: (logs as any) as DecodedLogs,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
it('returns magic bytes on success', async () => {
|
|
||||||
const BRIDGE_SUCCESS_RETURN_DATA = AssetProxyId.ERC20Bridge;
|
|
||||||
const { result } = await withdrawToAsync();
|
|
||||||
expect(result).to.eq(BRIDGE_SUCCESS_RETURN_DATA);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('calls `Eth2Dai.sellAllAmount()`', async () => {
|
|
||||||
const { opts, logs } = await withdrawToAsync();
|
|
||||||
const transfers = filterLogsToArguments<TestEth2DaiBridgeSellAllAmountEventArgs>(
|
|
||||||
logs,
|
|
||||||
TestEth2DaiBridgeEvents.SellAllAmount,
|
|
||||||
);
|
|
||||||
expect(transfers.length).to.eq(1);
|
|
||||||
expect(transfers[0].sellToken).to.eq(opts.fromTokenAddress);
|
|
||||||
expect(transfers[0].buyToken).to.eq(opts.toTokenAddress);
|
|
||||||
expect(transfers[0].sellTokenAmount).to.bignumber.eq(opts.fromTokenBalance);
|
|
||||||
expect(transfers[0].minimumFillAmount).to.bignumber.eq(opts.amount);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('sets an unlimited allowance on the `fromTokenAddress` token', async () => {
|
|
||||||
const { opts, logs } = await withdrawToAsync();
|
|
||||||
const approvals = filterLogsToArguments<TestEth2DaiBridgeTokenApproveEventArgs>(
|
|
||||||
logs,
|
|
||||||
TestEth2DaiBridgeEvents.TokenApprove,
|
|
||||||
);
|
|
||||||
expect(approvals.length).to.eq(1);
|
|
||||||
expect(approvals[0].token).to.eq(opts.fromTokenAddress);
|
|
||||||
expect(approvals[0].spender).to.eq(testContract.address);
|
|
||||||
expect(approvals[0].allowance).to.bignumber.eq(constants.MAX_UINT256);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('transfers filled amount to `to`', async () => {
|
|
||||||
const { opts, logs } = await withdrawToAsync();
|
|
||||||
const transfers = filterLogsToArguments<TestEth2DaiBridgeTokenTransferEventArgs>(
|
|
||||||
logs,
|
|
||||||
TestEth2DaiBridgeEvents.TokenTransfer,
|
|
||||||
);
|
|
||||||
expect(transfers.length).to.eq(1);
|
|
||||||
expect(transfers[0].token).to.eq(opts.toTokenAddress);
|
|
||||||
expect(transfers[0].from).to.eq(testContract.address);
|
|
||||||
expect(transfers[0].to).to.eq(opts.toAddress);
|
|
||||||
expect(transfers[0].amount).to.bignumber.eq(opts.fillAmount);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('fails if `Eth2Dai.sellAllAmount()` reverts', async () => {
|
|
||||||
const opts = createWithdrawToOpts({ revertReason: 'FOOBAR' });
|
|
||||||
const tx = withdrawToAsync(opts);
|
|
||||||
return expect(tx).to.revertWith(opts.revertReason);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('fails if `toTokenAddress.transfer()` reverts', async () => {
|
|
||||||
const opts = createWithdrawToOpts({ toTokentransferRevertReason: 'FOOBAR' });
|
|
||||||
const tx = withdrawToAsync(opts);
|
|
||||||
return expect(tx).to.revertWith(opts.toTokentransferRevertReason);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('fails if `toTokenAddress.transfer()` returns false', async () => {
|
|
||||||
const opts = createWithdrawToOpts({ toTokenTransferReturnData: hexUtils.leftPad(0) });
|
|
||||||
const tx = withdrawToAsync(opts);
|
|
||||||
return expect(tx).to.revertWith(new RawRevertError(hexUtils.leftPad(0)));
|
|
||||||
});
|
|
||||||
|
|
||||||
it('succeeds if `toTokenAddress.transfer()` returns true', async () => {
|
|
||||||
await withdrawToAsync({ toTokenTransferReturnData: hexUtils.leftPad(1) });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,284 +0,0 @@
|
|||||||
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,25 +1,20 @@
|
|||||||
import {
|
import {
|
||||||
chaiSetup,
|
chaiSetup,
|
||||||
constants,
|
constants,
|
||||||
|
expectTransactionFailedAsync,
|
||||||
expectTransactionFailedWithoutReasonAsync,
|
expectTransactionFailedWithoutReasonAsync,
|
||||||
provider,
|
provider,
|
||||||
txDefaults,
|
txDefaults,
|
||||||
web3Wrapper,
|
web3Wrapper,
|
||||||
} from '@0x/contracts-test-utils';
|
} from '@0x/contracts-test-utils';
|
||||||
import { BlockchainLifecycle } from '@0x/dev-utils';
|
import { BlockchainLifecycle } from '@0x/dev-utils';
|
||||||
|
import { assetDataUtils } from '@0x/order-utils';
|
||||||
import { AssetProxyId, RevertReason } from '@0x/types';
|
import { AssetProxyId, RevertReason } from '@0x/types';
|
||||||
import { AbiEncoder, BigNumber } from '@0x/utils';
|
import { AbiEncoder, BigNumber } from '@0x/utils';
|
||||||
import * as chai from 'chai';
|
import * as chai from 'chai';
|
||||||
import * as ethUtil from 'ethereumjs-util';
|
import * as ethUtil from 'ethereumjs-util';
|
||||||
|
|
||||||
import { artifacts } from './artifacts';
|
import { artifacts, IAssetProxyContract, StaticCallProxyContract, TestStaticCallTargetContract } from '../src';
|
||||||
|
|
||||||
import {
|
|
||||||
IAssetDataContract,
|
|
||||||
IAssetProxyContract,
|
|
||||||
StaticCallProxyContract,
|
|
||||||
TestStaticCallTargetContract,
|
|
||||||
} from './wrappers';
|
|
||||||
|
|
||||||
chaiSetup.configure();
|
chaiSetup.configure();
|
||||||
const expect = chai.expect;
|
const expect = chai.expect;
|
||||||
@@ -30,7 +25,6 @@ describe('StaticCallProxy', () => {
|
|||||||
let fromAddress: string;
|
let fromAddress: string;
|
||||||
let toAddress: string;
|
let toAddress: string;
|
||||||
|
|
||||||
let assetDataInterface: IAssetDataContract;
|
|
||||||
let staticCallProxy: IAssetProxyContract;
|
let staticCallProxy: IAssetProxyContract;
|
||||||
let staticCallTarget: TestStaticCallTargetContract;
|
let staticCallTarget: TestStaticCallTargetContract;
|
||||||
|
|
||||||
@@ -49,14 +43,7 @@ describe('StaticCallProxy', () => {
|
|||||||
txDefaults,
|
txDefaults,
|
||||||
artifacts,
|
artifacts,
|
||||||
);
|
);
|
||||||
assetDataInterface = new IAssetDataContract(constants.NULL_ADDRESS, provider);
|
staticCallProxy = new IAssetProxyContract(staticCallProxyWithoutTransferFrom.address, provider, txDefaults);
|
||||||
staticCallProxy = new IAssetProxyContract(
|
|
||||||
staticCallProxyWithoutTransferFrom.address,
|
|
||||||
provider,
|
|
||||||
txDefaults,
|
|
||||||
{},
|
|
||||||
StaticCallProxyContract.deployedBytecode,
|
|
||||||
);
|
|
||||||
staticCallTarget = await TestStaticCallTargetContract.deployFrom0xArtifactAsync(
|
staticCallTarget = await TestStaticCallTargetContract.deployFrom0xArtifactAsync(
|
||||||
artifacts.TestStaticCallTarget,
|
artifacts.TestStaticCallTarget,
|
||||||
provider,
|
provider,
|
||||||
@@ -84,21 +71,26 @@ describe('StaticCallProxy', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
it('should have an id of 0xc339d10a', async () => {
|
it('should have an id of 0xc339d10a', async () => {
|
||||||
const proxyId = await staticCallProxy.getProxyId().callAsync();
|
const proxyId = await staticCallProxy.getProxyId.callAsync();
|
||||||
const expectedProxyId = AssetProxyId.StaticCall;
|
const expectedProxyId = AssetProxyId.StaticCall;
|
||||||
expect(proxyId).to.equal(expectedProxyId);
|
expect(proxyId).to.equal(expectedProxyId);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('transferFrom', () => {
|
describe('transferFrom', () => {
|
||||||
it('should revert if assetData lies outside the bounds of calldata', async () => {
|
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 expectedResultHash = constants.KECCAK256_NULL;
|
||||||
const assetData = assetDataInterface
|
const assetData = assetDataUtils.encodeStaticCallAssetData(
|
||||||
.StaticCall(staticCallTarget.address, staticCallData, expectedResultHash)
|
staticCallTarget.address,
|
||||||
.getABIEncodedTransactionData();
|
staticCallData,
|
||||||
const txData = staticCallProxy
|
expectedResultHash,
|
||||||
.transferFrom(assetData, fromAddress, toAddress, amount)
|
);
|
||||||
.getABIEncodedTransactionData();
|
const txData = staticCallProxy.transferFrom.getABIEncodedTransactionData(
|
||||||
|
assetData,
|
||||||
|
fromAddress,
|
||||||
|
toAddress,
|
||||||
|
amount,
|
||||||
|
);
|
||||||
const offsetToAssetData = '0000000000000000000000000000000000000000000000000000000000000080';
|
const offsetToAssetData = '0000000000000000000000000000000000000000000000000000000000000080';
|
||||||
const txDataEndBuffer = ethUtil.toBuffer((txData.length - 2) / 2 - 4);
|
const txDataEndBuffer = ethUtil.toBuffer((txData.length - 2) / 2 - 4);
|
||||||
const paddedTxDataEndBuffer = ethUtil.setLengthLeft(txDataEndBuffer, 32);
|
const paddedTxDataEndBuffer = ethUtil.setLengthLeft(txDataEndBuffer, 32);
|
||||||
@@ -116,22 +108,23 @@ describe('StaticCallProxy', () => {
|
|||||||
it('should revert if the length of assetData is less than 100 bytes', async () => {
|
it('should revert if the length of assetData is less than 100 bytes', async () => {
|
||||||
const staticCallData = constants.NULL_BYTES;
|
const staticCallData = constants.NULL_BYTES;
|
||||||
const expectedResultHash = constants.KECCAK256_NULL;
|
const expectedResultHash = constants.KECCAK256_NULL;
|
||||||
const assetData = assetDataInterface
|
const assetData = assetDataUtils
|
||||||
.StaticCall(staticCallTarget.address, staticCallData, expectedResultHash)
|
.encodeStaticCallAssetData(staticCallTarget.address, staticCallData, expectedResultHash)
|
||||||
.getABIEncodedTransactionData()
|
|
||||||
.slice(0, -128);
|
.slice(0, -128);
|
||||||
const assetDataByteLen = (assetData.length - 2) / 2;
|
const assetDataByteLen = (assetData.length - 2) / 2;
|
||||||
expect((assetDataByteLen - 4) % 32).to.equal(0);
|
expect((assetDataByteLen - 4) % 32).to.equal(0);
|
||||||
await expectTransactionFailedWithoutReasonAsync(
|
await expectTransactionFailedWithoutReasonAsync(
|
||||||
staticCallProxy.transferFrom(assetData, fromAddress, toAddress, amount).sendTransactionAsync(),
|
staticCallProxy.transferFrom.sendTransactionAsync(assetData, fromAddress, toAddress, amount),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it('should revert if the offset to `staticCallData` points to outside of assetData', async () => {
|
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 expectedResultHash = constants.KECCAK256_NULL;
|
||||||
const assetData = assetDataInterface
|
const assetData = assetDataUtils.encodeStaticCallAssetData(
|
||||||
.StaticCall(staticCallTarget.address, staticCallData, expectedResultHash)
|
staticCallTarget.address,
|
||||||
.getABIEncodedTransactionData();
|
staticCallData,
|
||||||
|
expectedResultHash,
|
||||||
|
);
|
||||||
const offsetToStaticCallData = '0000000000000000000000000000000000000000000000000000000000000060';
|
const offsetToStaticCallData = '0000000000000000000000000000000000000000000000000000000000000060';
|
||||||
const assetDataEndBuffer = ethUtil.toBuffer((assetData.length - 2) / 2 - 4);
|
const assetDataEndBuffer = ethUtil.toBuffer((assetData.length - 2) / 2 - 4);
|
||||||
const paddedAssetDataEndBuffer = ethUtil.setLengthLeft(assetDataEndBuffer, 32);
|
const paddedAssetDataEndBuffer = ethUtil.setLengthLeft(assetDataEndBuffer, 32);
|
||||||
@@ -142,86 +135,90 @@ describe('StaticCallProxy', () => {
|
|||||||
invalidOffsetToStaticCallData,
|
invalidOffsetToStaticCallData,
|
||||||
)}${newStaticCallData}`;
|
)}${newStaticCallData}`;
|
||||||
await expectTransactionFailedWithoutReasonAsync(
|
await expectTransactionFailedWithoutReasonAsync(
|
||||||
staticCallProxy.transferFrom(badAssetData, fromAddress, toAddress, amount).sendTransactionAsync(),
|
staticCallProxy.transferFrom.sendTransactionAsync(badAssetData, fromAddress, toAddress, amount),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it('should revert if the callTarget attempts to write to state', async () => {
|
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 expectedResultHash = constants.KECCAK256_NULL;
|
||||||
const assetData = assetDataInterface
|
const assetData = assetDataUtils.encodeStaticCallAssetData(
|
||||||
.StaticCall(staticCallTarget.address, staticCallData, expectedResultHash)
|
staticCallTarget.address,
|
||||||
.getABIEncodedTransactionData();
|
staticCallData,
|
||||||
|
expectedResultHash,
|
||||||
|
);
|
||||||
await expectTransactionFailedWithoutReasonAsync(
|
await expectTransactionFailedWithoutReasonAsync(
|
||||||
staticCallProxy.transferFrom(assetData, fromAddress, toAddress, amount).sendTransactionAsync(),
|
staticCallProxy.transferFrom.sendTransactionAsync(assetData, fromAddress, toAddress, amount),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it('should revert with data provided by the callTarget if the staticcall reverts', async () => {
|
it('should revert with data provided by the callTarget if the staticcall reverts', async () => {
|
||||||
const staticCallData = staticCallTarget.assertEvenNumber(new BigNumber(1)).getABIEncodedTransactionData();
|
const staticCallData = staticCallTarget.assertEvenNumber.getABIEncodedTransactionData(new BigNumber(1));
|
||||||
const expectedResultHash = constants.KECCAK256_NULL;
|
const expectedResultHash = constants.KECCAK256_NULL;
|
||||||
const assetData = assetDataInterface
|
const assetData = assetDataUtils.encodeStaticCallAssetData(
|
||||||
.StaticCall(staticCallTarget.address, staticCallData, expectedResultHash)
|
staticCallTarget.address,
|
||||||
.getABIEncodedTransactionData();
|
staticCallData,
|
||||||
return expect(
|
expectedResultHash,
|
||||||
staticCallProxy.transferFrom(assetData, fromAddress, toAddress, amount).awaitTransactionSuccessAsync(),
|
);
|
||||||
).to.revertWith(RevertReason.TargetNotEven);
|
await expectTransactionFailedAsync(
|
||||||
|
staticCallProxy.transferFrom.sendTransactionAsync(assetData, fromAddress, toAddress, amount),
|
||||||
|
RevertReason.TargetNotEven,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('should revert if the hash of the output is different than expected expected', async () => {
|
it('should revert if the hash of the output is different than expected expected', async () => {
|
||||||
const staticCallData = staticCallTarget.isOddNumber(new BigNumber(0)).getABIEncodedTransactionData();
|
const staticCallData = staticCallTarget.isOddNumber.getABIEncodedTransactionData(new BigNumber(0));
|
||||||
const trueAsBuffer = ethUtil.toBuffer('0x0000000000000000000000000000000000000000000000000000000000000001');
|
const trueAsBuffer = ethUtil.toBuffer('0x0000000000000000000000000000000000000000000000000000000000000001');
|
||||||
const expectedResultHash = ethUtil.bufferToHex(ethUtil.sha3(trueAsBuffer));
|
const expectedResultHash = ethUtil.bufferToHex(ethUtil.sha3(trueAsBuffer));
|
||||||
const assetData = assetDataInterface
|
const assetData = assetDataUtils.encodeStaticCallAssetData(
|
||||||
.StaticCall(staticCallTarget.address, staticCallData, expectedResultHash)
|
staticCallTarget.address,
|
||||||
.getABIEncodedTransactionData();
|
staticCallData,
|
||||||
return expect(
|
expectedResultHash,
|
||||||
staticCallProxy.transferFrom(assetData, fromAddress, toAddress, amount).awaitTransactionSuccessAsync(),
|
);
|
||||||
).to.revertWith(RevertReason.UnexpectedStaticCallResult);
|
await expectTransactionFailedAsync(
|
||||||
|
staticCallProxy.transferFrom.sendTransactionAsync(assetData, fromAddress, toAddress, amount),
|
||||||
|
RevertReason.UnexpectedStaticCallResult,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('should be successful if a function call with no inputs and no outputs is successful', async () => {
|
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 expectedResultHash = constants.KECCAK256_NULL;
|
||||||
const assetData = assetDataInterface
|
const assetData = assetDataUtils.encodeStaticCallAssetData(
|
||||||
.StaticCall(staticCallTarget.address, staticCallData, expectedResultHash)
|
staticCallTarget.address,
|
||||||
.getABIEncodedTransactionData();
|
staticCallData,
|
||||||
await staticCallProxy
|
expectedResultHash,
|
||||||
.transferFrom(assetData, fromAddress, toAddress, amount)
|
);
|
||||||
.awaitTransactionSuccessAsync();
|
await staticCallProxy.transferFrom.awaitTransactionSuccessAsync(assetData, fromAddress, toAddress, amount);
|
||||||
});
|
});
|
||||||
it('should be successful if the staticCallTarget is not a contract and no return value is expected', async () => {
|
it('should be successful if the staticCallTarget is not a contract and no return value is expected', async () => {
|
||||||
const staticCallData = '0x0102030405060708';
|
const staticCallData = '0x0102030405060708';
|
||||||
const expectedResultHash = constants.KECCAK256_NULL;
|
const expectedResultHash = constants.KECCAK256_NULL;
|
||||||
const assetData = assetDataInterface
|
const assetData = assetDataUtils.encodeStaticCallAssetData(toAddress, staticCallData, expectedResultHash);
|
||||||
.StaticCall(toAddress, staticCallData, expectedResultHash)
|
await staticCallProxy.transferFrom.awaitTransactionSuccessAsync(assetData, fromAddress, toAddress, amount);
|
||||||
.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 () => {
|
it('should be successful if a function call with one static input returns the correct value', async () => {
|
||||||
const staticCallData = staticCallTarget.isOddNumber(new BigNumber(1)).getABIEncodedTransactionData();
|
const staticCallData = staticCallTarget.isOddNumber.getABIEncodedTransactionData(new BigNumber(1));
|
||||||
const trueAsBuffer = ethUtil.toBuffer('0x0000000000000000000000000000000000000000000000000000000000000001');
|
const trueAsBuffer = ethUtil.toBuffer('0x0000000000000000000000000000000000000000000000000000000000000001');
|
||||||
const expectedResultHash = ethUtil.bufferToHex(ethUtil.sha3(trueAsBuffer));
|
const expectedResultHash = ethUtil.bufferToHex(ethUtil.sha3(trueAsBuffer));
|
||||||
const assetData = assetDataInterface
|
const assetData = assetDataUtils.encodeStaticCallAssetData(
|
||||||
.StaticCall(staticCallTarget.address, staticCallData, expectedResultHash)
|
staticCallTarget.address,
|
||||||
.getABIEncodedTransactionData();
|
staticCallData,
|
||||||
await staticCallProxy
|
expectedResultHash,
|
||||||
.transferFrom(assetData, fromAddress, toAddress, amount)
|
);
|
||||||
.awaitTransactionSuccessAsync();
|
await staticCallProxy.transferFrom.awaitTransactionSuccessAsync(assetData, fromAddress, toAddress, amount);
|
||||||
});
|
});
|
||||||
it('should be successful if a function with one dynamic input is successful', async () => {
|
it('should be successful if a function with one dynamic input is successful', async () => {
|
||||||
const dynamicInput = '0x0102030405060708';
|
const dynamicInput = '0x0102030405060708';
|
||||||
const staticCallData = staticCallTarget.dynamicInputFunction(dynamicInput).getABIEncodedTransactionData();
|
const staticCallData = staticCallTarget.dynamicInputFunction.getABIEncodedTransactionData(dynamicInput);
|
||||||
const expectedResultHash = constants.KECCAK256_NULL;
|
const expectedResultHash = constants.KECCAK256_NULL;
|
||||||
const assetData = assetDataInterface
|
const assetData = assetDataUtils.encodeStaticCallAssetData(
|
||||||
.StaticCall(staticCallTarget.address, staticCallData, expectedResultHash)
|
staticCallTarget.address,
|
||||||
.getABIEncodedTransactionData();
|
staticCallData,
|
||||||
await staticCallProxy
|
expectedResultHash,
|
||||||
.transferFrom(assetData, fromAddress, toAddress, amount)
|
);
|
||||||
.awaitTransactionSuccessAsync();
|
await staticCallProxy.transferFrom.awaitTransactionSuccessAsync(assetData, fromAddress, toAddress, amount);
|
||||||
});
|
});
|
||||||
it('should be successful if a function call returns a complex type', async () => {
|
it('should be successful if a function call returns a complex type', async () => {
|
||||||
const a = new BigNumber(1);
|
const a = new BigNumber(1);
|
||||||
const b = new BigNumber(2);
|
const b = new BigNumber(2);
|
||||||
const staticCallData = staticCallTarget.returnComplexType(a, b).getABIEncodedTransactionData();
|
const staticCallData = staticCallTarget.returnComplexType.getABIEncodedTransactionData(a, b);
|
||||||
const abiEncoder = new AbiEncoder.DynamicBytes({
|
const abiEncoder = new AbiEncoder.DynamicBytes({
|
||||||
name: '',
|
name: '',
|
||||||
type: 'bytes',
|
type: 'bytes',
|
||||||
@@ -234,12 +231,12 @@ describe('StaticCallProxy', () => {
|
|||||||
const expectedResultHash = ethUtil.bufferToHex(
|
const expectedResultHash = ethUtil.bufferToHex(
|
||||||
ethUtil.sha3(ethUtil.toBuffer(encodedExpectedResultWithOffset)),
|
ethUtil.sha3(ethUtil.toBuffer(encodedExpectedResultWithOffset)),
|
||||||
);
|
);
|
||||||
const assetData = assetDataInterface
|
const assetData = assetDataUtils.encodeStaticCallAssetData(
|
||||||
.StaticCall(staticCallTarget.address, staticCallData, expectedResultHash)
|
staticCallTarget.address,
|
||||||
.getABIEncodedTransactionData();
|
staticCallData,
|
||||||
await staticCallProxy
|
expectedResultHash,
|
||||||
.transferFrom(assetData, fromAddress, toAddress, amount)
|
);
|
||||||
.awaitTransactionSuccessAsync();
|
await staticCallProxy.transferFrom.awaitTransactionSuccessAsync(assetData, fromAddress, toAddress, amount);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user