Compare commits
769 Commits
@0x/contra
...
@0x/contra
Author | SHA1 | Date | |
---|---|---|---|
|
7b136a5ad8 | ||
|
0c4a67fa35 | ||
|
668aeb77f7 | ||
|
135ae392d5 | ||
|
88ba04307c | ||
|
e4b8000a48 | ||
|
b9df108314 | ||
|
6106185bf6 | ||
|
3a3e289864 | ||
|
6558632f10 | ||
|
376ee6bdff | ||
|
fc5d759131 | ||
|
7c16bb3df8 | ||
|
5df74d35d0 | ||
|
72fc0c845a | ||
|
b995715a2c | ||
|
857b5c97b0 | ||
|
178d9c280a | ||
|
2416deba25 | ||
|
0ce6243653 | ||
|
40dc10729b | ||
|
0571244e9e | ||
|
3213131cad | ||
|
61bf93aac2 | ||
|
a9d0cec6d1 | ||
|
b5e3f0b90c | ||
|
61f1fe42b0 | ||
|
1cfdc49021 | ||
|
c4d58277cf | ||
|
9ac66c2130 | ||
|
6366163006 | ||
|
85fde8f9a5 | ||
|
a03d0800b0 | ||
|
9cb21006a7 | ||
|
649202f1c4 | ||
|
b798556774 | ||
|
03bc15fbdf | ||
|
b2dfd8740c | ||
|
3182c12b4d | ||
|
f783625d60 | ||
|
891aa8e8bf | ||
|
4b508d255d | ||
|
1cad43bf5d | ||
|
a0cd727832 | ||
|
ab90e15015 | ||
|
52cbddf054 | ||
|
db98ff8cb7 | ||
|
1d8dd2f89c | ||
|
0ae1c926d3 | ||
|
1fcab58e2f | ||
|
a8cbd1a16c | ||
|
3aaa0ad6b2 | ||
|
e34bc77157 | ||
|
088b331f19 | ||
|
56f2dec441 | ||
|
ac8b08d3cf | ||
|
c4ead689a9 | ||
|
07ab10b000 | ||
|
c969a8652a | ||
|
fb21ca5404 | ||
|
bbfa9c34ab | ||
|
7161bbe836 | ||
|
ef65aa5bf6 | ||
|
2cf31f05a1 | ||
|
2b1a1ba0db | ||
|
05b25c6229 | ||
|
2db52c6983 | ||
|
4803e2f68c | ||
|
7030572f1d | ||
|
6e2eb9c5bb | ||
|
eb27e260e0 | ||
|
c72aa653e8 | ||
|
4d04b72674 | ||
|
e3b92d2c8b | ||
|
4aa5a89cd7 | ||
|
c6b9ea5723 | ||
|
2dc0bff1ea | ||
|
408e66e8b4 | ||
|
40fe12a86b | ||
|
1adb56f092 | ||
|
629d48c766 | ||
|
c8886febb9 | ||
|
efe598c8fd | ||
|
32218ce25e | ||
|
f7ae697475 | ||
|
6e954385ce | ||
|
f8df89b506 | ||
|
a3ff406461 | ||
|
221de054f4 | ||
|
98e6aa4bac | ||
|
199808dc44 | ||
|
5d8e35fb68 | ||
|
36546480b1 | ||
|
cd9e408ea3 | ||
|
7698f21517 | ||
|
10724e5745 | ||
|
dde76a4dbb | ||
|
86ff5c53bb | ||
|
efef5f122f | ||
|
83c942ad8c | ||
|
31e90e314c | ||
|
33caae705e | ||
|
961273a2ff | ||
|
46e512a27c | ||
|
290a04a0ad | ||
|
12ff4ec438 | ||
|
1c15ecacb0 | ||
|
c6d738ed0c | ||
|
f089f5d87f | ||
|
78e3cd39d1 | ||
|
1588c1f362 | ||
|
a35d1b8a9d | ||
|
32923ec7e1 | ||
|
5a3bd716ad | ||
|
84862f15c1 | ||
|
9e42dce5c4 | ||
|
a360109013 | ||
|
68d6b3a033 | ||
|
733c3046bc | ||
|
23d4b6bf1c | ||
|
39bd0c5459 | ||
|
c13ffb2072 | ||
|
38bcab1f86 | ||
|
a24f01c90f | ||
|
708e34602b | ||
|
d60c8ddd5a | ||
|
eea63292f0 | ||
|
a97342a594 | ||
|
00f55be83e | ||
|
90ed283b20 | ||
|
61272961a8 | ||
|
507690f9db | ||
|
90ad5eb6c4 | ||
|
7bc9701c81 | ||
|
a7d502a501 | ||
|
fbe99b41f8 | ||
|
66e2d93e9c | ||
|
4672c72fef | ||
|
ac6b03cd4a | ||
|
d7de191947 | ||
|
de7f1fc207 | ||
|
99de5a3814 | ||
|
4cf566cad8 | ||
|
6138955f93 | ||
|
a57cf68ee4 | ||
|
20edcd1ae5 | ||
|
5333befd89 | ||
|
235e406620 | ||
|
5f570b772d | ||
|
f2507cb94a | ||
|
f84b375cde | ||
|
32d11d1ba5 | ||
|
5c9b6eb078 | ||
|
f53a512e70 | ||
|
ec08715090 | ||
|
79e0a9ef37 | ||
|
1ce8a33937 | ||
|
b3053dfb91 | ||
|
3da05f2812 | ||
|
0ba79b060d | ||
|
c4bcc26e29 | ||
|
630108ccb6 | ||
|
1ab33aa132 | ||
|
ee456ea6e7 | ||
|
e7541ac2af | ||
|
d34d46b7fd | ||
|
08ae43aad3 | ||
|
eb141075c7 | ||
|
bd3387a408 | ||
|
e1a48e80e1 | ||
|
bf899d40a0 | ||
|
dc66f1b886 | ||
|
3753b1a7d0 | ||
|
05c5acdb15 | ||
|
ca63bcc9b0 | ||
|
3733d503db | ||
|
ab28e42c22 | ||
|
7e53b4f834 | ||
|
3bb60fee19 | ||
|
9f7840e12b | ||
|
f41e13b574 | ||
|
4049143630 | ||
|
705f46717f | ||
|
a6cf8ae0b6 | ||
|
dba6972281 | ||
|
52d36f5a8b | ||
|
889b58a914 | ||
|
43810835d7 | ||
|
4b9867f167 | ||
|
e9c91e59bd | ||
|
d8844f6970 | ||
|
1cdc6e7184 | ||
|
36ad373f03 | ||
|
78dfb6d525 | ||
|
79254de7bc | ||
|
1d6aef5cd6 | ||
|
f9d02c9e27 | ||
|
228246089e | ||
|
b6319ba3d8 | ||
|
2636384ead | ||
|
0425f76284 | ||
|
d93e72f56a | ||
|
195d543ce3 | ||
|
9cda9f69cd | ||
|
7b0a1c3630 | ||
|
a8f3a47240 | ||
|
db0f3a8780 | ||
|
514db24ceb | ||
|
e738743c89 | ||
|
f471e1a8a3 | ||
|
a2f0d5eedf | ||
|
2f9b894d71 | ||
|
bab34c2d21 | ||
|
a68421b0f8 | ||
|
e9b0ac8820 | ||
|
4f78f55c2a | ||
|
156093127b | ||
|
47d91bb4e0 | ||
|
cc31445189 | ||
|
af78238507 | ||
|
b30f87f50c | ||
|
3cd03ed0f1 | ||
|
e7ad7c3af7 | ||
|
7e8b56eef4 | ||
|
458a014e6d | ||
|
9b6703398e | ||
|
71700e69af | ||
|
14d6330b40 | ||
|
d31d646ecc | ||
|
270d7a3f19 | ||
|
e078f3d479 | ||
|
6aa8f17ed5 | ||
|
8e73ae3614 | ||
|
89117beda2 | ||
|
e27e6baabe | ||
|
15ce90c0ec | ||
|
39e157499d | ||
|
d22c0641fb | ||
|
82806b6fcb | ||
|
fe293d91ee | ||
|
7842bb4cad | ||
|
6f7e156f49 | ||
|
0d19cac487 | ||
|
f30dfcc572 | ||
|
3df39d8cfe | ||
|
ece93fed78 | ||
|
3a2c6ae9d6 | ||
|
2ed71b36b6 | ||
|
ae9c301795 | ||
|
68206ffb6e | ||
|
25a3c18bfe | ||
|
d28476e9f7 | ||
|
7cd30610f9 | ||
|
ceb90989d0 | ||
|
bb39d63d37 | ||
|
213709d020 | ||
|
d0e9081852 | ||
|
71cde281b9 | ||
|
c03f1586e6 | ||
|
10aceb164d | ||
|
34f516a417 | ||
|
5dd686f22f | ||
|
5f47ad3363 | ||
|
e166e9762a | ||
|
341c5782e5 | ||
|
d5180d3ebc | ||
|
2c73bbd689 | ||
|
b10522479c | ||
|
2b39ae4800 | ||
|
788bdba8cd | ||
|
222fd5d822 | ||
|
eedfc64a8c | ||
|
78170b26e9 | ||
|
f966b6f4df | ||
|
053b55fbbf | ||
|
84a55a2d84 | ||
|
498a50b229 | ||
|
766888ec41 | ||
|
466d962c07 | ||
|
ae2a6fb685 | ||
|
5afe2616a4 | ||
|
72c869649a | ||
|
34138fc3b5 | ||
|
f67d2b96ac | ||
|
d877d3686c | ||
|
8260615b4e | ||
|
c3f6d48966 | ||
|
02f979bc74 | ||
|
de1c71aacc | ||
|
ca2aa72e0f | ||
|
9a16f5736e | ||
|
82774df715 | ||
|
314f53c0b3 | ||
|
6553ee0130 | ||
|
d7918ea047 | ||
|
4aa9c85503 | ||
|
f172591059 | ||
|
dfa7e30e42 | ||
|
3fe2013398 | ||
|
391d501ce6 | ||
|
9edaa3a64e | ||
|
6e4e313792 | ||
|
e6dcf92ec8 | ||
|
f359de2cac | ||
|
2d29014091 | ||
|
0450e430f1 | ||
|
b6700af6a8 | ||
|
bcee7546ae | ||
|
4dac620156 | ||
|
74d9df2fb0 | ||
|
9d1615fa23 | ||
|
b1b9949e72 | ||
|
957ef5ab77 | ||
|
07a681c77e | ||
|
145ec8ede1 | ||
|
5f5a158060 | ||
|
3e99c95791 | ||
|
4f83521be8 | ||
|
aae93bb6a7 | ||
|
b5eb1c9ee8 | ||
|
9d3755db36 | ||
|
762e0aec2d | ||
|
ff9c9241d8 | ||
|
5c1ffe7fc8 | ||
|
b1c3c60def | ||
|
8763713596 | ||
|
3e823cc9e3 | ||
|
1c84709db3 | ||
|
9150d6bd2a | ||
|
10f29b66b8 | ||
|
259aec52a9 | ||
|
6554bf9f08 | ||
|
d8558f5956 | ||
|
18bc701e8b | ||
|
a47795fd3f | ||
|
a55e8b268c | ||
|
e8106f04b5 | ||
|
bdc1dbf08a | ||
|
06eeb2088b | ||
|
7da9ec2c75 | ||
|
297ff10c14 | ||
|
1305f4314d | ||
|
55474c0599 | ||
|
687c79ae81 | ||
|
829a353b14 | ||
|
aced474dc5 | ||
|
7c08d5f198 | ||
|
c546787994 | ||
|
31fa530845 | ||
|
120714ecfc | ||
|
615874d2ec | ||
|
67b195c942 | ||
|
75689cee96 | ||
|
8ba77e95a4 | ||
|
7967a8416c | ||
|
934fbca860 | ||
|
e78c8038c7 | ||
|
f64a42ebb5 | ||
|
9164cff234 | ||
|
017f98e87e | ||
|
f33d8670aa | ||
|
e79db7de89 | ||
|
845a42e73a | ||
|
e58c25aa18 | ||
|
8ec44b63b1 | ||
|
41907936a1 | ||
|
406d2cefc5 | ||
|
41cdbc0ec4 | ||
|
c6ec261c5c | ||
|
a2db1a3275 | ||
|
1e8f2f0e83 | ||
|
8491abe142 | ||
|
d4302538bf | ||
|
c34e3765ef | ||
|
1f86bc06ef | ||
|
7e892fac2d | ||
|
23789b0692 | ||
|
89adbe4127 | ||
|
11940fb98e | ||
|
13ae335811 | ||
|
b2dc6ad2fa | ||
|
85ca926fd0 | ||
|
676698a59b | ||
|
22408ecd58 | ||
|
d36acc7ec7 | ||
|
a5a68acfec | ||
|
7431651666 | ||
|
4f91bfd907 | ||
|
8d2086870b | ||
|
1511ef1a98 | ||
|
4e030ce1e8 | ||
|
2507ad274b | ||
|
fb1c149eb9 | ||
|
d4662f428a | ||
|
73c779c13a | ||
|
b8cc164af1 | ||
|
64a391b5f8 | ||
|
21a202dd16 | ||
|
187dd2fdc3 | ||
|
c18f3f0b33 | ||
|
7162935028 | ||
|
9215a73b6c | ||
|
edd840794c | ||
|
c30a6eb1aa | ||
|
233642af29 | ||
|
7dffd0a03e | ||
|
f7bc3ff49d | ||
|
53aabe3cdb | ||
|
09b8d7cfc9 | ||
|
1512afc7e6 | ||
|
dde0c76112 | ||
|
f14b6f2ba2 | ||
|
4fced276c4 | ||
|
7590471d62 | ||
|
0b6bcf6739 | ||
|
3a5ce86ed9 | ||
|
7b298939e2 | ||
|
f1f6aa7d80 | ||
|
7ce7dd7252 | ||
|
01aa556ede | ||
|
48ad39c1c7 | ||
|
9cab034448 | ||
|
0d7a22634c | ||
|
3e3bc5c06d | ||
|
2a81e468c7 | ||
|
0ba67a363e | ||
|
deae846864 | ||
|
3a0d48ad77 | ||
|
81d4803b4d | ||
|
e936c7c507 | ||
|
ad868af96e | ||
|
cd14a45414 | ||
|
f7cd7110ea | ||
|
44262bf747 | ||
|
0fbbabe208 | ||
|
b39189fde3 | ||
|
18fc1d78f4 | ||
|
d44a91d10b | ||
|
5e9829b2d8 | ||
|
2176deae36 | ||
|
7c5035aa39 | ||
|
5707993995 | ||
|
f81697527c | ||
|
967eff4c58 | ||
|
d5d07dd34e | ||
|
b91cc3781d | ||
|
87ed0071c4 | ||
|
0fed48630c | ||
|
7b3e7c98ac | ||
|
09f44b0375 | ||
|
ebfa62637e | ||
|
cb2cc05cac | ||
|
f9c9131d81 | ||
|
1be9a1cbc7 | ||
|
b7fda8ecf0 | ||
|
db16392821 | ||
|
7127f541c3 | ||
|
32793cc008 | ||
|
fbaf55cb25 | ||
|
b8d51fc4e8 | ||
|
0c6e05d220 | ||
|
4066c17a0f | ||
|
429f2bb8dd | ||
|
112f4fc4f0 | ||
|
ecfbd6280f | ||
|
bf84409839 | ||
|
a7ce72cae0 | ||
|
28402ff7d8 | ||
|
e1d213d1a3 | ||
|
c610dd96f5 | ||
|
2ba3818b65 | ||
|
0e1a5a375a | ||
|
cfc3daeb65 | ||
|
6359f1950e | ||
|
d2f581853d | ||
|
030cb285da | ||
|
af45409959 | ||
|
d9a9bc35e3 | ||
|
c911c3352c | ||
|
654abbac25 | ||
|
46d5f42c9d | ||
|
1509da1215 | ||
|
98a99d96aa | ||
|
d62d81af17 | ||
|
dba67eb927 | ||
|
548c30d6a0 | ||
|
1b8b9186a8 | ||
|
a8cfcfb371 | ||
|
f7a414bc29 | ||
|
e05cd1d66b | ||
|
511cd90c44 | ||
|
8fb2d8da88 | ||
|
2fce332ed7 | ||
|
b23f1eb145 | ||
|
f694072b5a | ||
|
10de266e0f | ||
|
71811ed04f | ||
|
e9638ef95e | ||
|
5226bb5596 | ||
|
b9984b6df4 | ||
|
9c11835fee | ||
|
d9e13d6b99 | ||
|
dede076835 | ||
|
c929782e0d | ||
|
a43c7e36f8 | ||
|
b95cec9c32 | ||
|
9a7d9abe3c | ||
|
c77b620453 | ||
|
b348084e2a | ||
|
ff1811ef90 | ||
|
39cf4a7576 | ||
|
21b67625a6 | ||
|
fb0311e675 | ||
|
8a14b4afff | ||
|
e42701599a | ||
|
352b1b43f2 | ||
|
2922ebd095 | ||
|
a9e72085dd | ||
|
ed3d194c90 | ||
|
125c53827b | ||
|
38781807cd | ||
|
c046943269 | ||
|
fe36cd86bb | ||
|
401410089c | ||
|
fa23337519 | ||
|
ae5421f76e | ||
|
a2e2b429d5 | ||
|
ac852b23b3 | ||
|
e12389a002 | ||
|
da18e42d2a | ||
|
93bdaba8ee | ||
|
4cb08a61d5 | ||
|
133692ca92 | ||
|
4bcc4b3cf8 | ||
|
4eb20ca4b6 | ||
|
69f7343be5 | ||
|
19b28a58d6 | ||
|
3c33a93b9c | ||
|
f2e16dfb21 | ||
|
0f689e8051 | ||
|
5b44e6ef64 | ||
|
49e4ade66f | ||
|
3bae27d039 | ||
|
a77f0c606d | ||
|
f1de64dcaf | ||
|
feb672c3cd | ||
|
a90b463a7d | ||
|
5f5f25c978 | ||
|
351ea8bc1c | ||
|
b34edcbf87 | ||
|
160519e1fe | ||
|
44d626e12e | ||
|
efb9dc51c9 | ||
|
deb51434fd | ||
|
501070bfb0 | ||
|
712958d8c8 | ||
|
4d8d944fe5 | ||
|
0042e42160 | ||
|
85509ea251 | ||
|
6063854d06 | ||
|
456f8a90b1 | ||
|
980246d07a | ||
|
141c30b173 | ||
|
22f9b03fce | ||
|
be2db504b9 | ||
|
cac6f5234f | ||
|
eb6b32b6ee | ||
|
07acc9529e | ||
|
f7f0152573 | ||
|
153533f1d5 | ||
|
11622c586a | ||
|
7396bb508a | ||
|
7df6530f3a | ||
|
80787456fa | ||
|
4446ac1ca3 | ||
|
220039ab00 | ||
|
12f2250ab5 | ||
|
0c33aa16a1 | ||
|
72908b02fe | ||
|
223aa04424 | ||
|
e53248cca6 | ||
|
c11d661b39 | ||
|
4212a08337 | ||
|
c0553fa9eb | ||
|
7f26fafed7 | ||
|
3e9309c003 | ||
|
1017707475 | ||
|
e8ff5da209 | ||
|
03ed3ac1b0 | ||
|
2c97208e74 | ||
|
a458e81f8d | ||
|
83289bc801 | ||
|
ba2ac6a7b5 | ||
|
245b6da577 | ||
|
8875f924b0 | ||
|
ad7868ebe1 | ||
|
5effc6ec90 | ||
|
4cc9ceabd2 | ||
|
464c918134 | ||
|
2456adcb68 | ||
|
45bc967f30 | ||
|
d6d4d29257 | ||
|
33fdfdc8c0 | ||
|
80c8712b2a | ||
|
957e3eb93c | ||
|
110e1afa8e | ||
|
1da8f68871 | ||
|
513ddb4cca | ||
|
3bdfcb8542 | ||
|
aee758eca2 | ||
|
47ef7fffce | ||
|
58d6256607 | ||
|
b854fcdb72 | ||
|
27ca75d94f | ||
|
bb15f78af0 | ||
|
ccc9e18132 | ||
|
d55108ab60 | ||
|
84adbcb683 | ||
|
0cb5e4553b | ||
|
264407b707 | ||
|
eb5ec58453 | ||
|
39c2a757be | ||
|
8cdc05f582 | ||
|
5f4778c852 | ||
|
70add44fc1 | ||
|
fa617d2e9d | ||
|
3c795d365d | ||
|
93872ad7a3 | ||
|
227676c150 | ||
|
5f23833b43 | ||
|
121d51b414 | ||
|
0e196a59d9 | ||
|
63bfd23310 | ||
|
aadcf8fed0 | ||
|
37390e03b4 | ||
|
98fc780ade | ||
|
1670b21123 | ||
|
5602aacbd2 | ||
|
6ddbea207f | ||
|
261bced822 | ||
|
a80d1f861c | ||
|
c541340ef5 | ||
|
434af0ae64 | ||
|
c6379ca1d4 | ||
|
cdbcada49b | ||
|
282930cb9b | ||
|
b09c751942 | ||
|
b2047b90b3 | ||
|
0c8aec30bd | ||
|
fafaa3e69b | ||
|
d19bb3de8d | ||
|
481136166c | ||
|
4df81a0b9e | ||
|
da1e9c2d97 | ||
|
4b5a02c246 | ||
|
0e1572cfd7 | ||
|
343caa1ff6 | ||
|
403fb3826d | ||
|
3cdccb7b4e | ||
|
d9be78cdb4 | ||
|
16dc8255e1 | ||
|
2086bfff25 | ||
|
b9a68c0b8e | ||
|
74647f0e88 | ||
|
6e29c8bea9 | ||
|
b36373ab81 | ||
|
dc437aacf1 | ||
|
e19dae9b28 | ||
|
424cbd4831 | ||
|
350feed993 | ||
|
7ca4aa0ff4 | ||
|
bf00e67245 | ||
|
c5a6e49681 | ||
|
a509af2875 | ||
|
1f789bf396 | ||
|
0ccbc7d3d2 | ||
|
f3c6f26f85 | ||
|
338c358df2 | ||
|
4bdaa48303 | ||
|
36267746da | ||
|
7775541eed | ||
|
5029be4c83 | ||
|
277dbacf68 | ||
|
0fdfb03f3c | ||
|
17d81bf014 | ||
|
568e9be07e | ||
|
99b0a95f8a | ||
|
0fdd31892a | ||
|
7a682604f9 | ||
|
ce96e35d7d | ||
|
b7fb5394a7 | ||
|
aaa62beca7 | ||
|
2b58a7242b | ||
|
5ed919df79 | ||
|
baf6372179 | ||
|
1a9063a55b | ||
|
87999f402f | ||
|
109d466260 | ||
|
37597eca75 | ||
|
5fd767b739 | ||
|
0e7a473116 | ||
|
05bf55dca8 | ||
|
cc12ad8d86 | ||
|
847a7f470c | ||
|
95bebd6d1d | ||
|
8179a964ea | ||
|
d0805d4bbb | ||
|
f901c401b7 | ||
|
6ccadcb928 | ||
|
58b6c25d5c | ||
|
9cbab26202 | ||
|
74bcb468ca | ||
|
07a6ba88f4 | ||
|
49dff49993 | ||
|
68207aac80 | ||
|
64652b2ff0 | ||
|
659e8991de | ||
|
9f495b6dc9 | ||
|
d8498134ad | ||
|
17b2320b0d | ||
|
36c457f483 | ||
|
b8ec7f5e26 | ||
|
dbc5c0d5d8 | ||
|
fa886aa849 | ||
|
32e1ae2b18 | ||
|
61f03b0ea2 | ||
|
c47825a820 | ||
|
2d7cb63c7b | ||
|
c3d4c13936 | ||
|
3f51b9322f | ||
|
b604e2bd4e | ||
|
bcd92473d1 | ||
|
6f5bf9d146 | ||
|
490094939f | ||
|
d0d7d2772f | ||
|
59091896b4 | ||
|
3eb1429a25 | ||
|
bc7504c469 | ||
|
99dc4b8e07 | ||
|
807904bb86 | ||
|
7b8c8348f4 | ||
|
9c5ac26170 | ||
|
5db065644c | ||
|
0cc3a99169 | ||
|
2b1545145b | ||
|
49b7c9c8a4 | ||
|
114119f7c8 | ||
|
b4ef866c10 | ||
|
18ce19a84d | ||
|
b0fd78d68d | ||
|
8186d6277e | ||
|
599af2b1a9 | ||
|
82de5adbe9 | ||
|
82b0f85258 | ||
|
d97b30dcee | ||
|
fa8e8ad52d | ||
|
7495ac8111 | ||
|
08619e2c06 | ||
|
5d4bbd5b37 | ||
|
9d2aef5006 | ||
|
bcc3e5ebb0 | ||
|
e5df51a83a | ||
|
7181be8768 | ||
|
9608d8fb46 | ||
|
8be60e2ff5 | ||
|
3c0fd540b1 | ||
|
23a7dc9a8a | ||
|
77d7afe505 | ||
|
90cb86911a |
@@ -4,23 +4,13 @@ jobs:
|
||||
build:
|
||||
resource_class: medium+
|
||||
docker:
|
||||
- image: nikolaik/python-nodejs:python3.7-nodejs8
|
||||
- image: nikolaik/python-nodejs:python3.7-nodejs10
|
||||
environment:
|
||||
CONTRACTS_COMMIT_HASH: '9ed05f5'
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- checkout
|
||||
- run: echo 'export PATH=$HOME/CIRCLE_PROJECT_REPONAME/node_modules/.bin:$PATH' >> $BASH_ENV
|
||||
# HACK(feuGeneA): commented out this hack as we're changing
|
||||
# from a circleci-maintained container to a different
|
||||
# container, and this hack may not apply anymore, as
|
||||
# suggested by the non-existance of `/home/circleci/.bashrc`
|
||||
# when running the command below.
|
||||
# - run:
|
||||
# # HACK(albrow): Without this, yarn commands will sometimes
|
||||
# # fail with a "permission denied" error.
|
||||
# name: Set npm path
|
||||
# command: npm set prefix=/home/circleci/npm && echo 'export PATH=$HOME/circleci/npm/bin:$PATH' >> /home/circleci/.bashrc
|
||||
- run:
|
||||
name: install-yarn
|
||||
command: npm install --force --global yarn@1.17.0
|
||||
@@ -38,54 +28,60 @@ jobs:
|
||||
path: ~/repo/packages/abi-gen/test-cli/output
|
||||
- store_artifacts:
|
||||
path: ~/repo/packages/contract-wrappers/generated_docs
|
||||
test-contracts-ganache:
|
||||
test-exchange-ganache:
|
||||
resource_class: medium+
|
||||
docker:
|
||||
- image: nikolaik/python-nodejs:python3.7-nodejs8
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run: yarn wsrun test:circleci @0x/contracts-multisig @0x/contracts-utils @0x/contracts-exchange-libs @0x/contracts-erc20 @0x/contracts-erc721 @0x/contracts-erc1155 @0x/contracts-extensions @0x/contracts-asset-proxy @0x/contracts-exchange @0x/contracts-exchange-forwarder @0x/contracts-coordinator @0x/contracts-staking
|
||||
test-exchange-ganache-3.0:
|
||||
resource_class: medium+
|
||||
docker:
|
||||
- image: nikolaik/python-nodejs:python3.7-nodejs8
|
||||
- image: nikolaik/python-nodejs:python3.7-nodejs10
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run: yarn wsrun test:circleci @0x/contracts-exchange
|
||||
test-integrations-ganache-3.0:
|
||||
test-integrations-ganache:
|
||||
resource_class: medium+
|
||||
docker:
|
||||
- image: nikolaik/python-nodejs:python3.7-nodejs8
|
||||
- image: nikolaik/python-nodejs:python3.7-nodejs10
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run: yarn wsrun test:circleci @0x/contracts-integrations
|
||||
test-contracts-rest-ganache-3.0:
|
||||
test-contracts-staking-ganache:
|
||||
resource_class: medium+
|
||||
docker:
|
||||
- image: nikolaik/python-nodejs:python3.7-nodejs8
|
||||
- image: nikolaik/python-nodejs:python3.7-nodejs10
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run: yarn wsrun test:circleci @0x/contracts-multisig @0x/contracts-utils @0x/contracts-exchange-libs @0x/contracts-erc20 @0x/contracts-erc721 @0x/contracts-erc1155 @0x/contracts-asset-proxy @0x/contracts-exchange-forwarder @0x/contracts-staking @0x/contracts-coordinator @0x/contracts-erc20-bridge-sampler
|
||||
# TODO(dorothy-zbornak): Re-enable after updating this package for
|
||||
# 3.0. At that time, also remove exclusion from monorepo
|
||||
# package.json's test script.
|
||||
# - run: yarn wsrun test:circleci @0x/contracts-extensions
|
||||
- run: yarn wsrun test:circleci @0x/contracts-staking
|
||||
test-contracts-extra-ganache:
|
||||
resource_class: medium+
|
||||
docker:
|
||||
- image: nikolaik/python-nodejs:python3.7-nodejs10
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run: yarn wsrun test:circleci @0x/contracts-exchange-forwarder @0x/contracts-coordinator
|
||||
test-contracts-rest-ganache:
|
||||
resource_class: medium+
|
||||
docker:
|
||||
- image: nikolaik/python-nodejs:python3.7-nodejs10
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run: yarn wsrun test:circleci @0x/contracts-multisig @0x/contracts-utils @0x/contracts-exchange-libs @0x/contracts-erc20 @0x/contracts-erc721 @0x/contracts-erc1155 @0x/contracts-asset-proxy @0x/contracts-broker @0x/contracts-zero-ex
|
||||
test-publish:
|
||||
resource_class: medium+
|
||||
docker:
|
||||
- image: nikolaik/python-nodejs:python3.7-nodejs8
|
||||
- image: nikolaik/python-nodejs:python3.7-nodejs10
|
||||
- image: 0xorg/verdaccio
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
@@ -95,9 +91,11 @@ jobs:
|
||||
- run:
|
||||
command: yarn test:publish:circleci
|
||||
no_output_timeout: 1800
|
||||
- store_artifacts:
|
||||
path: ~/.npm/_logs
|
||||
test-doc-generation:
|
||||
docker:
|
||||
- image: nikolaik/python-nodejs:python3.7-nodejs8
|
||||
- image: nikolaik/python-nodejs:python3.7-nodejs10
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- restore_cache:
|
||||
@@ -108,228 +106,35 @@ jobs:
|
||||
no_output_timeout: 1200
|
||||
test-rest:
|
||||
docker:
|
||||
- image: nikolaik/python-nodejs:python3.7-nodejs8
|
||||
- image: nikolaik/python-nodejs:python3.7-nodejs10
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run: yarn wsrun test:circleci @0x/contracts-test-utils
|
||||
- run: yarn wsrun test:circleci @0x/abi-gen
|
||||
- run: yarn wsrun test:circleci @0x/asset-swapper
|
||||
- run: yarn wsrun test:circleci @0x/contract-artifacts
|
||||
- run: yarn wsrun test:circleci @0x/assert
|
||||
- run: yarn wsrun test:circleci @0x/base-contract
|
||||
- run: yarn wsrun test:circleci @0x/connect
|
||||
- run: yarn wsrun test:circleci @0x/contract-wrappers-test
|
||||
- run: yarn wsrun test:circleci @0x/dev-utils
|
||||
- run: yarn wsrun test:circleci @0x/json-schemas
|
||||
- run: yarn wsrun test:circleci @0x/migrations
|
||||
- run: yarn wsrun test:circleci @0x/order-utils
|
||||
- run: yarn wsrun test:circleci @0x/orderbook
|
||||
- run: yarn wsrun test:circleci @0x/sol-compiler
|
||||
- run: yarn wsrun test:circleci @0x/sol-tracing-utils
|
||||
- run: yarn wsrun test:circleci @0x/sol-doc
|
||||
- run: yarn wsrun test:circleci @0x/subproviders
|
||||
- run: yarn wsrun test:circleci @0x/web3-wrapper
|
||||
- run: yarn wsrun test:circleci @0x/utils
|
||||
- run: yarn wsrun test:circleci @0x/instant
|
||||
- save_cache:
|
||||
key: coverage-abi-gen-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- ~/repo/packages/abi-gen/coverage/lcov.info
|
||||
- save_cache:
|
||||
key: coverage-assert-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- ~/repo/packages/assert/coverage/lcov.info
|
||||
- save_cache:
|
||||
key: coverage-asset-swapper-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- ~/repo/packages/asset-swapper/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
|
||||
- run: yarn wsrun test:circleci @0x/asset-swapper
|
||||
- save_cache:
|
||||
key: coverage-contract-wrappers-test-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- ~/repo/packages/contract-wrappers-test/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:
|
||||
key: coverage-order-utils-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- ~/repo/packages/order-utils/coverage/lcov.info
|
||||
- save_cache:
|
||||
key: coverage-sol-compiler-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- ~/repo/packages/sol-compiler/coverage/lcov.info
|
||||
- save_cache:
|
||||
key: coverage-sol-tracing-utils-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- ~/repo/packages/sol-tracing-utils/coverage/lcov.info
|
||||
- save_cache:
|
||||
key: coverage-sol-doc-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- ~/repo/packages/sol-doc/coverage/lcov.info
|
||||
- save_cache:
|
||||
key: coverage-subproviders-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- ~/repo/packages/subproviders/coverage/lcov.info
|
||||
- save_cache:
|
||||
key: coverage-web3-wrapper-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- ~/repo/packages/web3-wrapper/coverage/lcov.info
|
||||
test-python:
|
||||
working_directory: ~/repo
|
||||
docker:
|
||||
- image: nikolaik/python-nodejs:python3.7-nodejs8
|
||||
- image: 0xorg/ganache-cli:6.0.0
|
||||
- image: 0xorg/mesh:0xV3
|
||||
environment:
|
||||
ETHEREUM_RPC_URL: 'http://localhost:8545'
|
||||
ETHEREUM_CHAIN_ID: '1337'
|
||||
VERBOSITY: 5
|
||||
BLOCK_POLLING_INTERVAL: '50ms'
|
||||
ETHEREUM_RPC_MAX_REQUESTS_PER_24_HR_UTC: '1778000'
|
||||
command: |
|
||||
sh -c "waitForGanache () { until printf 'POST /\r\nContent-Length: 26\r\n\r\n{\"method\":\"net_listening\"}' | nc localhost 8545 | grep true; do continue; done }; waitForGanache && ./mesh"
|
||||
- image: 0xorg/launch-kit-backend:v3
|
||||
environment:
|
||||
RPC_URL: 'http://localhost:8545'
|
||||
CHAIN_ID: 1337
|
||||
WHITELIST_ALL_TOKENS: True
|
||||
FEE_RECIPIENT: '0x0000000000000000000000000000000000000001'
|
||||
MAKER_FEE_UNIT_AMOUNT: 0
|
||||
TAKER_FEE_UNIT_AMOUNT: 0
|
||||
MESH_ENDPOINT: 'ws://localhost:60557'
|
||||
command: |
|
||||
sh -c "waitForMesh () { sleep 30; }; waitForMesh && node_modules/.bin/forever ts/lib/index.js"
|
||||
steps:
|
||||
- checkout
|
||||
- restore_cache:
|
||||
key: installed-py-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run:
|
||||
command: |
|
||||
cd python-packages
|
||||
python -m ensurepip
|
||||
./pre_install
|
||||
./install
|
||||
- save_cache:
|
||||
key: installed-py-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- '/usr/local/bin'
|
||||
- '/usr/local/lib/python3.7/site-packages'
|
||||
- run:
|
||||
command: |
|
||||
cd python-packages
|
||||
./parallel coverage run setup.py test
|
||||
./build_docs
|
||||
- run:
|
||||
command: |
|
||||
# copy generated wrappers into contract_wrappers/build,
|
||||
# JUST so CircleCI will persist them as build artifacts.
|
||||
cd python-packages/contract_wrappers/src/zero_ex
|
||||
for i in contract_wrappers/[^__]*/; do mkdir -p ../../build/$i; cp $i/__init__.py ../../build/$i; done
|
||||
- save_cache:
|
||||
key: coverage-python-contract-addresses-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- ~/repo/python-packages/contract_addresses/.coverage
|
||||
- save_cache:
|
||||
key: coverage-python-contract-artifacts-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- ~/repo/python-packages/contract_artifacts/.coverage
|
||||
- save_cache:
|
||||
key: coverage-python-contract-demo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- ~/repo/python-packages/contract_demo/.coverage
|
||||
- save_cache:
|
||||
key: coverage-python-json-schemas-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- ~/repo/python-packages/json_schemas/.coverage
|
||||
- save_cache:
|
||||
key: coverage-python-order-utils-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- ~/repo/python-packages/order_utils/.coverage
|
||||
- save_cache:
|
||||
key: coverage-python-sra-client-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- ~/repo/python-packages/sra_client/.coverage
|
||||
- store_artifacts:
|
||||
path: ~/repo/python-packages/contract_addresses/build
|
||||
- store_artifacts:
|
||||
path: ~/repo/python-packages/contract_artifacts/build
|
||||
- store_artifacts:
|
||||
path: ~/repo/python-packages/contract_wrappers/build
|
||||
- store_artifacts:
|
||||
path: ~/repo/python-packages/json_schemas/build
|
||||
- store_artifacts:
|
||||
path: ~/repo/python-packages/middlewares/build
|
||||
- store_artifacts:
|
||||
path: ~/repo/python-packages/order_utils/build
|
||||
- store_artifacts:
|
||||
path: ~/repo/python-packages/sra_client/build
|
||||
test-rest-python:
|
||||
working_directory: ~/repo
|
||||
docker:
|
||||
- image: nikolaik/python-nodejs:python3.7-nodejs8
|
||||
steps:
|
||||
- checkout
|
||||
- restore_cache:
|
||||
key: installed-py-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run:
|
||||
command: |
|
||||
cd python-packages/order_utils
|
||||
python -m ensurepip
|
||||
python -m pip install .
|
||||
- save_cache:
|
||||
key: installed-py-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- '/usr/local/bin'
|
||||
- '/usr/local/lib/python3.7/site-packages'
|
||||
- '.eggs'
|
||||
- '.mypy_cache'
|
||||
- '.pytest_cache'
|
||||
- '.tox'
|
||||
- run:
|
||||
command: |
|
||||
cd python-packages/order_utils
|
||||
tox
|
||||
static-tests-python:
|
||||
working_directory: ~/repo
|
||||
docker:
|
||||
- image: nikolaik/python-nodejs:python3.7-nodejs8
|
||||
steps:
|
||||
- checkout
|
||||
- restore_cache:
|
||||
key: installed-py-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run:
|
||||
command: |
|
||||
python -m ensurepip
|
||||
cd python-packages
|
||||
./pre_install
|
||||
./install
|
||||
./lint
|
||||
static-tests:
|
||||
resource_class: large
|
||||
working_directory: ~/repo
|
||||
docker:
|
||||
- image: nikolaik/python-nodejs:python3.7-nodejs8
|
||||
- image: nikolaik/python-nodejs:python3.7-nodejs10
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
@@ -338,92 +143,43 @@ jobs:
|
||||
- run: yarn prettier:ci
|
||||
- run: yarn deps_versions:ci
|
||||
- run: yarn diff_md_docs:ci
|
||||
- run: cd packages/0x.js && yarn build:umd:prod
|
||||
- run: yarn bundlewatch
|
||||
submit-coverage:
|
||||
docker:
|
||||
- image: nikolaik/python-nodejs:python3.7-nodejs8
|
||||
- image: nikolaik/python-nodejs:python3.7-nodejs10
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- coverage-abi-gen-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- coverage-assert-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- coverage-asset-swapper-{{ .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-test-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- coverage-dev-utils-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- coverage-json-schemas-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- coverage-order-utils-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- coverage-sol-compiler-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- coverage-sol-tracing-utils-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- coverage-sol-doc-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- coverage-subproviders-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- coverage-web3-wrapper-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- coverage-contracts-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- coverage-python-json-schemas-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- coverage-python-contract-addresses-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- coverage-python-contract-artifacts-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- coverage-python-contract-demo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- coverage-python-sra-client-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- coverage-python-order-utils-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run: yarn report_coverage
|
||||
workflows:
|
||||
version: 2
|
||||
main:
|
||||
jobs:
|
||||
- build
|
||||
- test-exchange-ganache-3.0:
|
||||
requires:
|
||||
- build
|
||||
- test-integrations-ganache-3.0:
|
||||
requires:
|
||||
- build
|
||||
- test-contracts-rest-ganache-3.0:
|
||||
# Disabled until we begin actively developing on these packages again.
|
||||
# - test-exchange-ganache:
|
||||
# requires:
|
||||
# - build
|
||||
# - test-integrations-ganache:
|
||||
# requires:
|
||||
# - build
|
||||
# - test-contracts-staking-ganache:
|
||||
# requires:
|
||||
# - build
|
||||
# - test-contracts-extra-ganache:
|
||||
# requires:
|
||||
# - build
|
||||
- test-contracts-rest-ganache:
|
||||
requires:
|
||||
- build
|
||||
- test-rest:
|
||||
@@ -438,17 +194,14 @@ workflows:
|
||||
- test-doc-generation:
|
||||
requires:
|
||||
- build
|
||||
- submit-coverage:
|
||||
requires:
|
||||
- test-contracts-rest-ganache-3.0
|
||||
- test-exchange-ganache-3.0
|
||||
- test-rest
|
||||
- static-tests
|
||||
- test-python:
|
||||
requires:
|
||||
- build
|
||||
- static-tests-python:
|
||||
requires:
|
||||
- build
|
||||
# skip python tox run for now, as we don't yet have multiple test environments to support.
|
||||
# - test-rest-python
|
||||
# Disabled until this repo has a coveralls API key
|
||||
# - submit-coverage:
|
||||
# requires:
|
||||
# # Disabled until we begin actively developing on these packages again.
|
||||
# # - test-exchange-ganache
|
||||
# # - test-integrations-ganache
|
||||
# # - test-contracts-staking-ganache
|
||||
# # - test-contracts-extra-ganache
|
||||
# - test-contracts-rest-ganache
|
||||
# - test-rest
|
||||
# - static-tests
|
||||
|
4
.gitattributes
vendored
4
.gitattributes
vendored
@@ -2,7 +2,3 @@
|
||||
|
||||
# Automatically collapse generated files in GitHub.
|
||||
*.svg linguist-generated=true
|
||||
packages/contract-artifacts/artifacts/*json linguist-generated=true
|
||||
packages/abi-gen-wrappers/src/generated-wrappers/*.ts linguist-generated=true
|
||||
packages/contract-wrappers/src/generated-wrappers/*.ts linguist-generated=true
|
||||
|
||||
|
26
.github/autolabeler.yml
vendored
26
.github/autolabeler.yml
vendored
@@ -1,33 +1,7 @@
|
||||
python: ['python-packages']
|
||||
contracts: ['contracts']
|
||||
@0x/sol-doc: ['packages/sol-doc']
|
||||
@0x/sol-resolver: ['packages/sol-resolver']
|
||||
@0x/contracts-gen: ['packages/contracts-gen']
|
||||
@0x/sra-spec: ['packages/sra-spec']
|
||||
@0x/subproviders: ['packages/subproviders']
|
||||
@0x/contract-addresses: ['packages/contract-addresses']
|
||||
@0x/migrations: ['packages/migrations']
|
||||
@0x/web3-wrapper: ['packages/web3-wrapper']
|
||||
@0x/sol-compiler: ['packages/sol-compiler']
|
||||
@0x/types: ['packages/types']
|
||||
@0x/instant: ['packages/instant']
|
||||
@0x/abi-gen-templates: ['packages/abi-gen-templates']
|
||||
@0x/abi-gen: ['packages/abi-gen']
|
||||
@0x/sol-coverage: ['packages/sol-coverage']
|
||||
@0x/sol-profiler: ['packages/sol-profiler']
|
||||
@0x/sol-trace: ['packages/sol-trace']
|
||||
@0x/sol-tracing-utils: ['packages/sol-tracing-utils']
|
||||
@0x/utils: ['packages/utils']
|
||||
@0x/tslint-config: ['packages/tslint-config']
|
||||
@0x/asset-swapper: ['packages/asset-swapper']
|
||||
@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/contract-artifacts: ['packages/contract-artifacts']
|
||||
@0x/dev-utils: ['packages/dev-utils']
|
||||
@0x/contract-wrappers: ['packages/contract-wrappers']
|
||||
@0x/json-schemas: ['packages/json-schemas']
|
||||
@0x/ethereum-types: ['ethereum-types']
|
||||
@0x/connect: ['packages/connect']
|
||||
|
24
.gitignore
vendored
24
.gitignore
vendored
@@ -111,8 +111,8 @@ contracts/exchange-forwarder/generated-artifacts/
|
||||
contracts/exchange-forwarder/test/generated-artifacts/
|
||||
contracts/dev-utils/generated-artifacts/
|
||||
contracts/dev-utils/test/generated-artifacts/
|
||||
packages/sol-tracing-utils/test/fixtures/artifacts/
|
||||
python-packages/contract_artifacts/src/zero_ex/contract_artifacts/artifacts/
|
||||
contracts/zero-ex/generated-artifacts/
|
||||
contracts/zero-ex/test/generated-artifacts/
|
||||
|
||||
# generated truffle contract artifacts/
|
||||
contracts/broker/build/
|
||||
@@ -165,24 +165,8 @@ contracts/exchange-forwarder/generated-wrappers/
|
||||
contracts/exchange-forwarder/test/generated-wrappers/
|
||||
contracts/dev-utils/generated-wrappers/
|
||||
contracts/dev-utils/test/generated-wrappers/
|
||||
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/*/__init__.py
|
||||
|
||||
# solc-bin in sol-compiler
|
||||
packages/sol-compiler/solc_bin/
|
||||
|
||||
# python stuff
|
||||
.eggs
|
||||
.mypy_cache
|
||||
.tox
|
||||
python-packages/*/build
|
||||
python-packages/*/dist
|
||||
__pycache__
|
||||
python-packages/*/src/*.egg-info
|
||||
python-packages/*/.coverage
|
||||
|
||||
# python keeps package-local copies of json schemas and contract addresses
|
||||
python-packages/json_schemas/src/zero_ex/json_schemas/schemas
|
||||
python-packages/contract_addresses/src/zero_ex/contract_addresses/addresses.json
|
||||
contracts/zero-ex/generated-wrappers/
|
||||
contracts/zero-ex/test/generated-wrappers/
|
||||
|
||||
# Doc README copy
|
||||
packages/*/docs/README.md
|
||||
|
@@ -40,10 +40,6 @@ lib
|
||||
/contracts/erc20/test/generated-wrappers
|
||||
/contracts/erc20/generated-artifacts
|
||||
/contracts/erc20/test/generated-artifacts
|
||||
/contracts/erc20-bridge-sampler/generated-wrappers
|
||||
/contracts/erc20-bridge-sampler/test/generated-wrappers
|
||||
/contracts/erc20-bridge-sampler/generated-artifacts
|
||||
/contracts/erc20-bridge-sampler/test/generated-artifacts
|
||||
/contracts/erc721/generated-wrappers
|
||||
/contracts/erc721/test/generated-wrappers
|
||||
/contracts/erc721/generated-artifacts
|
||||
@@ -64,6 +60,10 @@ lib
|
||||
/contracts/dev-utils/test/generated-wrappers
|
||||
/contracts/dev-utils/generated-artifacts
|
||||
/contracts/dev-utils/test/generated-artifacts
|
||||
/contracts/zero-ex/generated-wrappers
|
||||
/contracts/zero-ex/test/generated-wrappers
|
||||
/contracts/zero-ex/generated-artifacts
|
||||
/contracts/zero-ex/test/generated-artifacts
|
||||
/contracts/staking/build/
|
||||
/contracts/coordinator/build/
|
||||
/contracts/exchange/build/
|
||||
@@ -76,19 +76,10 @@ lib
|
||||
/contracts/erc1155/build/
|
||||
/contracts/extensions/build/
|
||||
/contracts/exchange-forwarder/build/
|
||||
/contracts/dev-utils/build/
|
||||
/packages/abi-gen/test-cli/output
|
||||
/packages/json-schemas/schemas
|
||||
/python-packages/json_schemas/src/zero_ex/json_schemas/schemas
|
||||
/packages/sra-spec/public/
|
||||
/packages/asset-swapper/generated-artifacts
|
||||
/packages/asset-swapper/generated-wrappers
|
||||
/packages/asset-swapper/test/generated-artifacts
|
||||
/packages/asset-swapper/test/generated-wrappers
|
||||
package.json
|
||||
scripts/postpublish_utils.js
|
||||
packages/sol-coverage/test/fixtures/artifacts
|
||||
.pytest_cache
|
||||
.mypy_cache
|
||||
.tox
|
||||
packages/abi-gen/test-cli/fixtures/artifacts/AbiGenDummy.json
|
||||
packages/abi-gen/test-cli/fixtures/artifacts/LibDummy.json
|
||||
packages/abi-gen/test-cli/fixtures/artifacts/TestLibDummy.json
|
||||
packages/*/docs
|
||||
*.sol
|
||||
|
@@ -2,5 +2,6 @@
|
||||
"printWidth": 120,
|
||||
"tabWidth": 4,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "all"
|
||||
"trailingComma": "all",
|
||||
"bracketSpacing": true
|
||||
}
|
||||
|
26
CODEOWNERS
26
CODEOWNERS
@@ -9,30 +9,10 @@ packages/asset-swapper/ @BMillman19 @fragosti @dave4506
|
||||
packages/instant/ @BMillman19 @fragosti @dave4506
|
||||
|
||||
# Dev tools & setup
|
||||
.circleci/ @LogvinovLeon
|
||||
packages/abi-gen/ @feuGeneA
|
||||
packages/base-contract/ @xianny
|
||||
packages/connect/ @fragosti
|
||||
packages/abi-gen-templates/ @feuGeneA @xianny
|
||||
.circleci/ @dorothy-zbornak
|
||||
packages/contract-addresses/ @abandeali1
|
||||
packages/contract-artifacts/ @abandeali1
|
||||
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
|
||||
packages/order-utils/ @dorothy-zbornak
|
||||
|
||||
# Protocol/smart contracts
|
||||
contracts/ @abandeali1 @hysz
|
||||
contracts/ @abandeali1 @hysz @dorothy-zbornak @mzhu25
|
||||
|
@@ -4,9 +4,9 @@ We welcome contributions from anyone on the internet and are grateful for even t
|
||||
|
||||
### Getting started
|
||||
|
||||
1. Fork `0xproject/0x-monorepo`
|
||||
1. Fork `0xproject/0x-tools`
|
||||
2. Clone your fork
|
||||
3. Follow the [installation & build steps](https://github.com/0xProject/0x-monorepo#install-dependencies) in the repo's top-level README.
|
||||
3. Follow the [installation & build steps](https://github.com/0xProject/0x-tools#install-dependencies) in the repo's top-level README.
|
||||
4. Setup the recommended [Development Tooling](#development-tooling).
|
||||
5. Open a PR with the `[WIP]` flag against the `development` branch and describe the change you are intending to undertake in the PR description. (see [our branch naming conventions](#branch-structure))
|
||||
|
||||
@@ -59,11 +59,11 @@ We strongly recommend you use the [VSCode](https://code.visualstudio.com/) text
|
||||
|
||||
#### Linter
|
||||
|
||||
We use [TSLint](https://palantir.github.io/tslint/) with [custom configs](https://github.com/0xProject/0x-monorepo/tree/development/packages/tslint-config) to keep our code-style consistent.
|
||||
We use [TSLint](https://palantir.github.io/tslint/) with [custom configs](https://github.com/0xProject/0x-tools/tree/development/packages/tslint-config) to keep our code-style consistent.
|
||||
|
||||
Use `yarn:lint` to lint the entire monorepo, and `PKG={PACKAGE_NAME} yarn lint` to lint a specific package.
|
||||
|
||||
If you want to change a rule, or add a custom rule, please make these changes to our [tslint-config](https://github.com/0xProject/0x-monorepo/tree/development/packages/tslint-config) package. All other packages have it as a dependency.
|
||||
If you want to change a rule, or add a custom rule, please make these changes to our [tslint-config](https://github.com/0xProject/0x-tools/tree/development/packages/tslint-config) package. All other packages have it as a dependency.
|
||||
|
||||
Integrate it into your text editor:
|
||||
|
||||
@@ -94,12 +94,12 @@ A few of our coding conventions are not yet enforced by the linter/auto-formatte
|
||||
|
||||
### Fix `submit-coverage` CI failure
|
||||
|
||||
If you simply fork the repo and then create a PR from it, your PR will fail the `submit-coverage` check on CI. This is because the 0x CircleCI configuration sets the `COVERALLS_REPO_TOKEN` environment variable to the token for `0xProject/0x-monorepo`, but when running the check against your fork the token needs to match your repo's name `your-username/0x-monorepo`.
|
||||
If you simply fork the repo and then create a PR from it, your PR will fail the `submit-coverage` check on CI. This is because the 0x CircleCI configuration sets the `COVERALLS_REPO_TOKEN` environment variable to the token for `0xProject/0x-tools`, but when running the check against your fork the token needs to match your repo's name `your-username/0x-tools`.
|
||||
|
||||
To facilitate this check, after creating your fork, but before creating the branch for your PR, do the following:
|
||||
|
||||
1. Log in to [coveralls.io](https://coveralls.io/), go to `Add Repos`, and enable your fork. Then go to the settings for that repo, and copy the `Repo Token` identifier.
|
||||
2. Log in to [CircleCI](https://circleci.com/login), go to `Add Projects`, click the `Set Up Project` button corresponding to your fork, and then click `Start Building`. (Aside from step 3 below, no actual set up is needed, since it will use the `.circleci/config.yml` file in 0x-monorepo, so you can ignore all of the instruction/explanation given on the page with the `Start Building` button.)
|
||||
2. Log in to [CircleCI](https://circleci.com/login), go to `Add Projects`, click the `Set Up Project` button corresponding to your fork, and then click `Start Building`. (Aside from step 3 below, no actual set up is needed, since it will use the `.circleci/config.yml` file in 0x-tools, so you can ignore all of the instruction/explanation given on the page with the `Start Building` button.)
|
||||
3. In CircleCI, configure your project to add an environment variable, with name `COVERALLS_REPO_TOKEN`, and for the value paste in the `Repo Token` you copied in step 1.
|
||||
|
||||
Now, when you push to your branch, CircleCI will automatically run all of the checks in your own instance, and the coverage check will work since it has the proper `Repo Token`, and the PR will magically refer to your own checks rather than running them in the 0x CircleCI instance.
|
||||
|
2
LICENSE
2
LICENSE
@@ -1,4 +1,4 @@
|
||||
Copyright 2017 ZeroEx Intl.
|
||||
Copyright 2020 ZeroEx Labs
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
64
README.md
64
README.md
@@ -17,17 +17,6 @@ This repository is a monorepo including the 0x protocol smart contracts and nume
|
||||
|
||||
Visit our [developer portal](https://0x.org/docs/tools/order-utils) for a comprehensive list of core & community maintained packages. All packages maintained with this monorepo are listed below.
|
||||
|
||||
### Python Packages
|
||||
|
||||
| Package | Version | Description |
|
||||
| -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
|
||||
| [`0x-contract-addresses`](/python-packages/contract_addresses) | [](https://pypi.org/project/0x-contract-addresses/) | A tiny utility library for getting known deployed contract addresses for a particular network |
|
||||
| [`0x-contract-artifacts`](/python-packages/contract_artifacts) | [](https://pypi.org/project/0x-contract-artifacts/) | 0x smart contract compilation artifacts |
|
||||
| [`0x-contract-wrappers`](/python-packages/contract_wrappers) | [](https://pypi.org/project/0x-contract-wrappers/) | 0x smart contract wrappers |
|
||||
| [`0x-json-schemas`](/python-packages/json_schemas) | [](https://pypi.org/project/0x-json-schemas/) | 0x-related JSON schemas |
|
||||
| [`0x-order-utils`](/python-packages/order_utils) | [](https://pypi.org/project/0x-order-utils/) | A set of utilities for generating, parsing, signing and validating 0x orders |
|
||||
| [`0x-sra-client`](/python-packages/sra_client) | [](https://pypi.org/project/0x-sra-client/) | A Python client for interacting with servers conforming to the Standard Relayer API specification |
|
||||
|
||||
### Solidity Packages
|
||||
|
||||
These packages are all under development. See [/contracts/README.md](/contracts/README.md) for a list of deployed packages.
|
||||
@@ -53,50 +42,13 @@ These packages are all under development. See [/contracts/README.md](/contracts/
|
||||
|
||||
#### 0x-specific packages
|
||||
|
||||
| Package | Version | Description |
|
||||
| -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
|
||||
| [`0x.js`](/packages/0x.js) | [](https://www.npmjs.com/package/0x.js) | An aggregate package combining many smaller utility packages for interacting with the 0x protocol |
|
||||
| [`@0x/contract-addresses`](/packages/contract-addresses) | [](https://www.npmjs.com/package/@0x/contract-addresses) | A tiny utility library for getting known deployed contract addresses for a particular network. |
|
||||
| [`@0x/contract-wrappers`](/packages/contract-wrappers) | [](https://www.npmjs.com/package/@0x/contract-wrappers) | JS/TS wrappers for interacting with the 0x smart contracts |
|
||||
| [`@0x/order-utils`](/packages/order-utils) | [](https://www.npmjs.com/package/@0x/order-utils) | A set of utilities for generating, parsing, signing and validating 0x orders |
|
||||
| [`@0x/json-schemas`](/packages/json-schemas) | [](https://www.npmjs.com/package/@0x/json-schemas) | 0x-related JSON schemas | |
|
||||
| [`@0x/migrations`](/packages/migrations) | [](https://www.npmjs.com/package/@0x/migrations) | Migration tool for deploying 0x smart contracts on private testnets |
|
||||
| [`@0x/contract-artifacts`](/packages/contract-artifacts) | [](https://www.npmjs.com/package/@0x/contract-artifacts) | 0x smart contract compilation artifacts | |
|
||||
| [`@0x/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-swapper`](/packages/asset-swapper) | [](https://www.npmjs.com/package/@0x/asset-swapper) | Convenience package for discovering and performing swaps for any ERC20 Assets |
|
||||
|
||||
#### Ethereum tooling
|
||||
|
||||
| Package | Version | Description |
|
||||
| -------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| [`@0x/web3-wrapper`](/packages/web3-wrapper) | [](https://www.npmjs.com/package/@0x/web3-wrapper) | An Ethereum JSON RPC client |
|
||||
| [`@0x/sol-compiler`](/packages/sol-compiler) | [](https://www.npmjs.com/package/@0x/sol-compiler) | A wrapper around solc-js that adds smart re-compilation, ability to compile an entire project, Solidity version specific compilation, standard input description support and much more. |
|
||||
| [`@0x/sol-coverage`](/packages/sol-coverage) | [](https://www.npmjs.com/package/@0x/sol-coverage) | A solidity test coverage tool |
|
||||
| [`@0x/sol-profiler`](/packages/sol-profiler) | [](https://www.npmjs.com/package/@0x/sol-profiler) | A solidity gas cost profiler |
|
||||
| [`@0x/sol-trace`](/packages/sol-trace) | [](https://www.npmjs.com/package/@0x/sol-trace) | A solidity stack trace tool |
|
||||
| [`@0x/sol-resolver`](/packages/sol-resolver) | [](https://www.npmjs.com/package/@0x/sol-resolver) | Import resolver for smart contracts dependencies |
|
||||
| [`@0x/subproviders`](/packages/subproviders) | [](https://www.npmjs.com/package/@0x/subproviders) | Web3 provider middlewares (e.g. LedgerSubprovider) |
|
||||
| [`@0x/sol-doc`](/packages/sol-doc) | [](https://www.npmjs.com/package/@0x/sol-doc) | Solidity documentation generator |
|
||||
|
||||
#### Utilities
|
||||
|
||||
| Package | Version | Description |
|
||||
| -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------- |
|
||||
| [`@0x/abi-gen`](/packages/abi-gen) | [](https://www.npmjs.com/package/@0x/abi-gen) | Tool to generate TS wrappers from smart contract ABIs |
|
||||
| [`@0x/tslint-config`](/packages/tslint-config) | [](https://www.npmjs.com/package/@0x/tslint-config) | Custom TSLint rules used by the 0x core team |
|
||||
| [`@0x/types`](/packages/types) | [](https://www.npmjs.com/package/@0x/types) | Shared type declarations |
|
||||
| [`@0x/typescript-typings`](/packages/typescript-typings) | [](https://www.npmjs.com/package/@0x/typescript-typings) | Repository of types for external packages |
|
||||
| [`@0x/utils`](/packages/utils) | [](https://www.npmjs.com/package/@0x/utils) | Shared utilities |
|
||||
| [`@0x/assert`](/packages/assert) | [](https://www.npmjs.com/package/@0x/assert) | Type and schema assertions used by our packages |
|
||||
| [`@0x/base-contract`](/packages/base-contract) | [](https://www.npmjs.com/package/@0x/base-contract) | BaseContract used by auto-generated `abi-gen` wrapper contracts |
|
||||
| [`@0x/dev-utils`](/packages/dev-utils) | [](https://www.npmjs.com/package/@0x/dev-utils) | Dev utils to be shared across 0x packages |
|
||||
|
||||
#### Private Packages
|
||||
|
||||
| Package | Description |
|
||||
| ---------------------------------- | -------------------------------------------------------------------------------- |
|
||||
| [`@0x/instant`](/packages/instant) | A free and flexible way to offer simple crypto purchasing in any app or website. |
|
||||
| Package | Version | Description |
|
||||
| -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
|
||||
| [`@0x/contract-addresses`](/packages/contract-addresses) | [](https://www.npmjs.com/package/@0x/contract-addresses) | A tiny utility library for getting known deployed contract addresses for a particular network. |
|
||||
| [`@0x/contract-wrappers`](/packages/contract-wrappers) | [](https://www.npmjs.com/package/@0x/contract-wrappers) | JS/TS wrappers for interacting with the 0x smart contracts |
|
||||
| [`@0x/order-utils`](/packages/order-utils) | [](https://www.npmjs.com/package/@0x/order-utils) | A set of utilities for generating, parsing, signing and validating 0x orders |
|
||||
| [`@0x/migrations`](/packages/migrations) | [](https://www.npmjs.com/package/@0x/migrations) | Migration tool for deploying 0x smart contracts on private testnets |
|
||||
| [`@0x/contract-artifacts`](/packages/contract-artifacts) | [](https://www.npmjs.com/package/@0x/contract-artifacts) | 0x smart contract compilation artifacts | |
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -129,8 +81,6 @@ Then install dependencies
|
||||
yarn install
|
||||
```
|
||||
|
||||
You will also need to have Python 3 installed, in order to build and run the tests of `abi-gen`'s command-line interface, which is integrated with the yarn build, yarn test, and yarn lint commands described below. More specifically, your local pip should resolve to the Python 3 version of pip, not a Python 2.x version.
|
||||
|
||||
### Build
|
||||
|
||||
To build all packages:
|
||||
|
@@ -1,4 +1,94 @@
|
||||
[
|
||||
{
|
||||
"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",
|
||||
@@ -69,7 +159,7 @@
|
||||
},
|
||||
{
|
||||
"note": "Add `setOperators()` to `IDydx`",
|
||||
"pr": "TODO"
|
||||
"pr": 2462
|
||||
}
|
||||
],
|
||||
"timestamp": 1581204851
|
||||
|
@@ -5,6 +5,33 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## 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
|
||||
@@ -32,7 +59,7 @@ CHANGELOG
|
||||
* Fix broken tests. (#2462)
|
||||
* Remove dependency on `@0x/contracts-dev-utils` (#2462)
|
||||
* Add asset data decoding functions (#2462)
|
||||
* Add `setOperators()` to `IDydx` (#TODO)
|
||||
* Add `setOperators()` to `IDydx` (#2462)
|
||||
|
||||
## v3.1.3 - _February 6, 2020_
|
||||
|
||||
|
103
contracts/asset-proxy/contracts/src/bridges/BalancerBridge.sol
Normal file
103
contracts/asset-proxy/contracts/src/bridges/BalancerBridge.sol
Normal file
@@ -0,0 +1,103 @@
|
||||
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
|
||||
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
|
||||
import "../interfaces/IERC20Bridge.sol";
|
||||
import "../interfaces/IBalancerPool.sol";
|
||||
|
||||
|
||||
contract BalancerBridge is
|
||||
IERC20Bridge,
|
||||
IWallet,
|
||||
DeploymentConstants
|
||||
{
|
||||
/// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of
|
||||
/// `toTokenAddress` tokens by selling the entirety of the `fromTokenAddress`
|
||||
/// token encoded in the bridge data, then transfers the bought
|
||||
/// tokens to `to`.
|
||||
/// @param toTokenAddress The token to buy and transfer to `to`.
|
||||
/// @param from The maker (this contract).
|
||||
/// @param to The recipient of the bought tokens.
|
||||
/// @param amount Minimum amount of `toTokenAddress` tokens to buy.
|
||||
/// @param bridgeData The abi-encoded addresses of the "from" token and Balancer pool.
|
||||
/// @return success The magic bytes if successful.
|
||||
function bridgeTransferFrom(
|
||||
address toTokenAddress,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes calldata bridgeData
|
||||
)
|
||||
external
|
||||
returns (bytes4 success)
|
||||
{
|
||||
// Decode the bridge data.
|
||||
(address fromTokenAddress, address poolAddress) = abi.decode(
|
||||
bridgeData,
|
||||
(address, address)
|
||||
);
|
||||
require(toTokenAddress != fromTokenAddress, "BalancerBridge/INVALID_PAIR");
|
||||
|
||||
uint256 fromTokenBalance = IERC20Token(fromTokenAddress).balanceOf(address(this));
|
||||
// Grant an allowance to the exchange to spend `fromTokenAddress` token.
|
||||
LibERC20Token.approveIfBelow(fromTokenAddress, poolAddress, fromTokenBalance);
|
||||
|
||||
// Sell all of this contract's `fromTokenAddress` token balance.
|
||||
(uint256 boughtAmount,) = IBalancerPool(poolAddress).swapExactAmountIn(
|
||||
fromTokenAddress, // tokenIn
|
||||
fromTokenBalance, // tokenAmountIn
|
||||
toTokenAddress, // tokenOut
|
||||
amount, // minAmountOut
|
||||
uint256(-1) // maxPrice
|
||||
);
|
||||
|
||||
// Transfer the converted `toToken`s to `to`.
|
||||
LibERC20Token.transfer(toTokenAddress, to, boughtAmount);
|
||||
|
||||
emit ERC20BridgeTransfer(
|
||||
fromTokenAddress,
|
||||
toTokenAddress,
|
||||
fromTokenBalance,
|
||||
boughtAmount,
|
||||
from,
|
||||
to
|
||||
);
|
||||
return BRIDGE_SUCCESS;
|
||||
}
|
||||
|
||||
/// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
|
||||
/// and sign for itself in orders. Always succeeds.
|
||||
/// @return magicValue Magic success bytes, always.
|
||||
function isValidSignature(
|
||||
bytes32,
|
||||
bytes calldata
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (bytes4 magicValue)
|
||||
{
|
||||
return LEGACY_WALLET_MAGIC_VALUE;
|
||||
}
|
||||
}
|
122
contracts/asset-proxy/contracts/src/bridges/BancorBridge.sol
Normal file
122
contracts/asset-proxy/contracts/src/bridges/BancorBridge.sol
Normal file
@@ -0,0 +1,122 @@
|
||||
|
||||
/*
|
||||
|
||||
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/IBancorNetwork.sol";
|
||||
|
||||
|
||||
contract BancorBridge is
|
||||
IERC20Bridge,
|
||||
IWallet,
|
||||
DeploymentConstants
|
||||
{
|
||||
struct TransferState {
|
||||
address bancorNetworkAddress;
|
||||
address[] path;
|
||||
}
|
||||
|
||||
/// @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
|
||||
|
||||
require(state.path.length > 0, "BancorBridge/PATH_MUST_EXIST");
|
||||
// Just transfer the tokens if they're the same.
|
||||
if (state.path[0] == toTokenAddress) {
|
||||
LibERC20Token.transfer(state.path[0], to, amount);
|
||||
return BRIDGE_SUCCESS;
|
||||
}
|
||||
|
||||
// Otherwise use Bancor to convert
|
||||
require(state.path.length > 2, "BancorBridge/PATH_LENGTH_MUST_BE_GREATER_THAN_TWO");
|
||||
require(state.path[state.path.length - 1] == toTokenAddress, "BancorBridge/LAST_ELEMENT_OF_PATH_MUST_MATCH_OUTPUT_TOKEN");
|
||||
|
||||
// // Grant an allowance to the Bancor Network to spend `fromTokenAddress` token.
|
||||
uint256 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(
|
||||
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
|
||||
to, // beneficiary
|
||||
address(0), // affiliateAccount; no fee paid
|
||||
0 // affiliateFee; no fee paid
|
||||
);
|
||||
|
||||
emit ERC20BridgeTransfer(
|
||||
state.path[0], // 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;
|
||||
}
|
||||
|
||||
}
|
103
contracts/asset-proxy/contracts/src/bridges/CreamBridge.sol
Normal file
103
contracts/asset-proxy/contracts/src/bridges/CreamBridge.sol
Normal file
@@ -0,0 +1,103 @@
|
||||
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
|
||||
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
|
||||
import "../interfaces/IERC20Bridge.sol";
|
||||
import "../interfaces/IBalancerPool.sol";
|
||||
|
||||
|
||||
contract CreamBridge is
|
||||
IERC20Bridge,
|
||||
IWallet,
|
||||
DeploymentConstants
|
||||
{
|
||||
/// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of
|
||||
/// `toTokenAddress` tokens by selling the entirety of the `fromTokenAddress`
|
||||
/// token encoded in the bridge data, then transfers the bought
|
||||
/// tokens to `to`.
|
||||
/// @param toTokenAddress The token to buy and transfer to `to`.
|
||||
/// @param from The maker (this contract).
|
||||
/// @param to The recipient of the bought tokens.
|
||||
/// @param amount Minimum amount of `toTokenAddress` tokens to buy.
|
||||
/// @param bridgeData The abi-encoded addresses of the "from" token and Balancer pool.
|
||||
/// @return success The magic bytes if successful.
|
||||
function bridgeTransferFrom(
|
||||
address toTokenAddress,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes calldata bridgeData
|
||||
)
|
||||
external
|
||||
returns (bytes4 success)
|
||||
{
|
||||
// Decode the bridge data.
|
||||
(address fromTokenAddress, address poolAddress) = abi.decode(
|
||||
bridgeData,
|
||||
(address, address)
|
||||
);
|
||||
require(toTokenAddress != fromTokenAddress, "CreamBridge/INVALID_PAIR");
|
||||
|
||||
uint256 fromTokenBalance = IERC20Token(fromTokenAddress).balanceOf(address(this));
|
||||
// Grant an allowance to the exchange to spend `fromTokenAddress` token.
|
||||
LibERC20Token.approveIfBelow(fromTokenAddress, poolAddress, fromTokenBalance);
|
||||
|
||||
// Sell all of this contract's `fromTokenAddress` token balance.
|
||||
(uint256 boughtAmount,) = IBalancerPool(poolAddress).swapExactAmountIn(
|
||||
fromTokenAddress, // tokenIn
|
||||
fromTokenBalance, // tokenAmountIn
|
||||
toTokenAddress, // tokenOut
|
||||
amount, // minAmountOut
|
||||
uint256(-1) // maxPrice
|
||||
);
|
||||
|
||||
// Transfer the converted `toToken`s to `to`.
|
||||
LibERC20Token.transfer(toTokenAddress, to, boughtAmount);
|
||||
|
||||
emit ERC20BridgeTransfer(
|
||||
fromTokenAddress,
|
||||
toTokenAddress,
|
||||
fromTokenBalance,
|
||||
boughtAmount,
|
||||
from,
|
||||
to
|
||||
);
|
||||
return BRIDGE_SUCCESS;
|
||||
}
|
||||
|
||||
/// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
|
||||
/// and sign for itself in orders. Always succeeds.
|
||||
/// @return magicValue Magic success bytes, always.
|
||||
function isValidSignature(
|
||||
bytes32,
|
||||
bytes calldata
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (bytes4 magicValue)
|
||||
{
|
||||
return LEGACY_WALLET_MAGIC_VALUE;
|
||||
}
|
||||
}
|
@@ -35,18 +35,27 @@ contract CurveBridge is
|
||||
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 from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes calldata bridgeData
|
||||
@@ -55,40 +64,42 @@ contract CurveBridge is
|
||||
returns (bytes4 success)
|
||||
{
|
||||
// Decode the bridge data to get the Curve metadata.
|
||||
(address curveAddress, int128 fromCoinIdx, int128 toCoinIdx, int128 version) = abi.decode(bridgeData, (address, int128, int128, int128));
|
||||
ICurve exchange = ICurve(curveAddress);
|
||||
CurveBridgeData memory data = abi.decode(bridgeData, (CurveBridgeData));
|
||||
|
||||
address fromTokenAddress = exchange.underlying_coins(fromCoinIdx);
|
||||
require(toTokenAddress != fromTokenAddress, "CurveBridge/INVALID_PAIR");
|
||||
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.approve(fromTokenAddress, address(exchange), uint256(-1));
|
||||
LibERC20Token.approveIfBelow(data.fromTokenAddress, data.curveAddress, fromTokenBalance);
|
||||
|
||||
// Try to sell all of this contract's `fromTokenAddress` token balance.
|
||||
if (version == 0) {
|
||||
exchange.exchange_underlying(
|
||||
fromCoinIdx,
|
||||
toCoinIdx,
|
||||
// dx
|
||||
IERC20Token(fromTokenAddress).balanceOf(address(this)),
|
||||
// min dy
|
||||
amount,
|
||||
// expires
|
||||
block.timestamp + 1
|
||||
);
|
||||
} else {
|
||||
exchange.exchange_underlying(
|
||||
fromCoinIdx,
|
||||
toCoinIdx,
|
||||
// dx
|
||||
IERC20Token(fromTokenAddress).balanceOf(address(this)),
|
||||
// min dy
|
||||
amount
|
||||
);
|
||||
{
|
||||
(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;
|
||||
}
|
||||
|
||||
|
147
contracts/asset-proxy/contracts/src/bridges/DODOBridge.sol
Normal file
147
contracts/asset-proxy/contracts/src/bridges/DODOBridge.sol
Normal file
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
|
||||
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
|
||||
import "../interfaces/IERC20Bridge.sol";
|
||||
|
||||
|
||||
interface IDODOHelper {
|
||||
|
||||
function querySellQuoteToken(address dodo, uint256 amount) external view returns (uint256);
|
||||
}
|
||||
|
||||
|
||||
interface IDODO {
|
||||
|
||||
function sellBaseToken(uint256 amount, uint256 minReceiveQuote, bytes calldata data) external returns (uint256);
|
||||
|
||||
function buyBaseToken(uint256 amount, uint256 maxPayQuote, bytes calldata data) external returns (uint256);
|
||||
|
||||
}
|
||||
|
||||
|
||||
contract DODOBridge is
|
||||
IERC20Bridge,
|
||||
IWallet,
|
||||
DeploymentConstants
|
||||
{
|
||||
|
||||
struct TransferState {
|
||||
address fromTokenAddress;
|
||||
uint256 fromTokenBalance;
|
||||
address pool;
|
||||
bool isSellBase;
|
||||
}
|
||||
|
||||
/// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of
|
||||
/// `toTokenAddress` tokens by selling the entirety of the `fromTokenAddress`
|
||||
/// token encoded in the bridge data.
|
||||
/// @param toTokenAddress The token to buy and transfer to `to`.
|
||||
/// @param from The maker (this contract).
|
||||
/// @param to The recipient of the bought tokens.
|
||||
/// @param amount Minimum amount of `toTokenAddress` tokens to buy.
|
||||
/// @param bridgeData The abi-encoded path of token addresses. Last element must be toTokenAddress
|
||||
/// @return success The magic bytes if successful.
|
||||
function bridgeTransferFrom(
|
||||
address toTokenAddress,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes calldata bridgeData
|
||||
)
|
||||
external
|
||||
returns (bytes4 success)
|
||||
{
|
||||
TransferState memory state;
|
||||
// Decode the bridge data to get the `fromTokenAddress`.
|
||||
(state.fromTokenAddress, state.pool, state.isSellBase) = abi.decode(bridgeData, (address, address, bool));
|
||||
require(state.pool != address(0), "DODOBridge/InvalidPool");
|
||||
IDODO exchange = IDODO(state.pool);
|
||||
// Get our balance of `fromTokenAddress` token.
|
||||
state.fromTokenBalance = IERC20Token(state.fromTokenAddress).balanceOf(address(this));
|
||||
|
||||
// Grant the pool an allowance.
|
||||
LibERC20Token.approveIfBelow(
|
||||
state.fromTokenAddress,
|
||||
address(exchange),
|
||||
state.fromTokenBalance
|
||||
);
|
||||
|
||||
uint256 boughtAmount;
|
||||
if (state.isSellBase) {
|
||||
boughtAmount = exchange.sellBaseToken(
|
||||
// amount to sell
|
||||
state.fromTokenBalance,
|
||||
// min receive amount
|
||||
1,
|
||||
new bytes(0)
|
||||
);
|
||||
} else {
|
||||
// Need to re-calculate the sell quote amount into buyBase
|
||||
boughtAmount = IDODOHelper(_getDODOHelperAddress()).querySellQuoteToken(
|
||||
address(exchange),
|
||||
state.fromTokenBalance
|
||||
);
|
||||
exchange.buyBaseToken(
|
||||
// amount to buy
|
||||
boughtAmount,
|
||||
// max pay amount
|
||||
state.fromTokenBalance,
|
||||
new bytes(0)
|
||||
);
|
||||
}
|
||||
// Transfer funds to `to`
|
||||
IERC20Token(toTokenAddress).transfer(to, boughtAmount);
|
||||
|
||||
|
||||
emit ERC20BridgeTransfer(
|
||||
// input token
|
||||
state.fromTokenAddress,
|
||||
// output token
|
||||
toTokenAddress,
|
||||
// input token amount
|
||||
state.fromTokenBalance,
|
||||
// output token amount
|
||||
boughtAmount,
|
||||
from,
|
||||
to
|
||||
);
|
||||
|
||||
return BRIDGE_SUCCESS;
|
||||
}
|
||||
|
||||
/// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
|
||||
/// and sign for itself in orders. Always succeeds.
|
||||
/// @return magicValue Success bytes, always.
|
||||
function isValidSignature(
|
||||
bytes32,
|
||||
bytes calldata
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (bytes4 magicValue)
|
||||
{
|
||||
return LEGACY_WALLET_MAGIC_VALUE;
|
||||
}
|
||||
}
|
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol";
|
||||
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
|
||||
import "../interfaces/IERC20Bridge.sol";
|
||||
import "./MixinGasToken.sol";
|
||||
|
||||
|
||||
// solhint-disable space-after-comma, indent
|
||||
contract DexForwarderBridge is
|
||||
IERC20Bridge,
|
||||
IWallet,
|
||||
DeploymentConstants,
|
||||
MixinGasToken
|
||||
{
|
||||
using LibSafeMath for uint256;
|
||||
|
||||
/// @dev Data needed to reconstruct a bridge call.
|
||||
struct BridgeCall {
|
||||
address target;
|
||||
uint256 inputTokenAmount;
|
||||
uint256 outputTokenAmount;
|
||||
bytes bridgeData;
|
||||
}
|
||||
|
||||
/// @dev Intermediate state variables used by `bridgeTransferFrom()`, in
|
||||
/// struct form to get around stack limits.
|
||||
struct TransferFromState {
|
||||
address inputToken;
|
||||
uint256 initialInputTokenBalance;
|
||||
uint256 callInputTokenAmount;
|
||||
uint256 callOutputTokenAmount;
|
||||
uint256 totalInputTokenSold;
|
||||
BridgeCall[] calls;
|
||||
}
|
||||
|
||||
/// @dev Spends this contract's entire balance of input tokens by forwarding
|
||||
/// them to other bridges. Reverts if the entire balance is not spent.
|
||||
/// @param outputToken The token being bought.
|
||||
/// @param to The recipient of the bought tokens.
|
||||
/// @param bridgeData The abi-encoded input token address.
|
||||
/// @return success The magic bytes if successful.
|
||||
function bridgeTransferFrom(
|
||||
address outputToken,
|
||||
address /* from */,
|
||||
address to,
|
||||
uint256 /* amount */,
|
||||
bytes calldata bridgeData
|
||||
)
|
||||
external
|
||||
freesGasTokensFromCollector
|
||||
returns (bytes4 success)
|
||||
{
|
||||
require(
|
||||
msg.sender == _getERC20BridgeProxyAddress(),
|
||||
"DexForwarderBridge/SENDER_NOT_AUTHORIZED"
|
||||
);
|
||||
TransferFromState memory state;
|
||||
(
|
||||
state.inputToken,
|
||||
state.calls
|
||||
) = abi.decode(bridgeData, (address, BridgeCall[]));
|
||||
|
||||
state.initialInputTokenBalance =
|
||||
IERC20Token(state.inputToken).balanceOf(address(this));
|
||||
|
||||
for (uint256 i = 0; i < state.calls.length; ++i) {
|
||||
// Stop if the we've sold all our input tokens.
|
||||
if (state.totalInputTokenSold >= state.initialInputTokenBalance) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Compute token amounts.
|
||||
state.callInputTokenAmount = LibSafeMath.min256(
|
||||
state.calls[i].inputTokenAmount,
|
||||
state.initialInputTokenBalance.safeSub(state.totalInputTokenSold)
|
||||
);
|
||||
state.callOutputTokenAmount = LibMath.getPartialAmountFloor(
|
||||
state.callInputTokenAmount,
|
||||
state.calls[i].inputTokenAmount,
|
||||
state.calls[i].outputTokenAmount
|
||||
);
|
||||
|
||||
// Execute the call in a new context so we can recoup transferred
|
||||
// funds by reverting.
|
||||
(bool didSucceed, ) = address(this)
|
||||
.call(abi.encodeWithSelector(
|
||||
this.executeBridgeCall.selector,
|
||||
state.calls[i].target,
|
||||
to,
|
||||
state.inputToken,
|
||||
outputToken,
|
||||
state.callInputTokenAmount,
|
||||
state.callOutputTokenAmount,
|
||||
state.calls[i].bridgeData
|
||||
));
|
||||
|
||||
if (didSucceed) {
|
||||
// Increase the amount of tokens sold.
|
||||
state.totalInputTokenSold = state.totalInputTokenSold.safeAdd(
|
||||
state.callInputTokenAmount
|
||||
);
|
||||
}
|
||||
}
|
||||
// Always succeed.
|
||||
return BRIDGE_SUCCESS;
|
||||
}
|
||||
|
||||
/// @dev Transfers `inputToken` token to a bridge contract then calls
|
||||
/// its `bridgeTransferFrom()`. This is executed in separate context
|
||||
/// so we can revert the transfer on error. This can only be called
|
||||
// by this contract itself.
|
||||
/// @param bridge The bridge contract.
|
||||
/// @param to The recipient of `outputToken` tokens.
|
||||
/// @param inputToken The input token.
|
||||
/// @param outputToken The output token.
|
||||
/// @param inputTokenAmount The amount of input tokens to transfer to `bridge`.
|
||||
/// @param outputTokenAmount The amount of expected output tokens to be sent
|
||||
/// to `to` by `bridge`.
|
||||
function executeBridgeCall(
|
||||
address bridge,
|
||||
address to,
|
||||
address inputToken,
|
||||
address outputToken,
|
||||
uint256 inputTokenAmount,
|
||||
uint256 outputTokenAmount,
|
||||
bytes calldata bridgeData
|
||||
)
|
||||
external
|
||||
{
|
||||
// Must be called through `bridgeTransferFrom()`.
|
||||
require(msg.sender == address(this), "DexForwarderBridge/ONLY_SELF");
|
||||
// `bridge` must not be this contract.
|
||||
require(bridge != address(this));
|
||||
|
||||
// Get the starting balance of output tokens for `to`.
|
||||
uint256 initialRecipientBalance = IERC20Token(outputToken).balanceOf(to);
|
||||
|
||||
// Transfer input tokens to the bridge.
|
||||
LibERC20Token.transfer(inputToken, bridge, inputTokenAmount);
|
||||
|
||||
// Call the bridge.
|
||||
(bool didSucceed, bytes memory resultData) =
|
||||
bridge.call(abi.encodeWithSelector(
|
||||
IERC20Bridge(0).bridgeTransferFrom.selector,
|
||||
outputToken,
|
||||
bridge,
|
||||
to,
|
||||
outputTokenAmount,
|
||||
bridgeData
|
||||
));
|
||||
|
||||
// Revert if the call failed or not enough tokens were bought.
|
||||
// This will also undo the token transfer.
|
||||
require(
|
||||
didSucceed
|
||||
&& resultData.length == 32
|
||||
&& LibBytes.readBytes32(resultData, 0) == bytes32(BRIDGE_SUCCESS)
|
||||
&& IERC20Token(outputToken).balanceOf(to).safeSub(initialRecipientBalance) >= outputTokenAmount
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
|
||||
/// and sign for itself in orders. Always succeeds.
|
||||
/// @return magicValue Magic success bytes, always.
|
||||
function isValidSignature(
|
||||
bytes32,
|
||||
bytes calldata
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (bytes4 magicValue)
|
||||
{
|
||||
return LEGACY_WALLET_MAGIC_VALUE;
|
||||
}
|
||||
}
|
@@ -50,7 +50,7 @@ contract DydxBridge is
|
||||
/// @param encodedBridgeData An abi-encoded `BridgeData` struct.
|
||||
/// @return success The magic bytes if successful.
|
||||
function bridgeTransferFrom(
|
||||
address,
|
||||
address, /* toTokenAddress */
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
@@ -81,6 +81,7 @@ contract DydxBridge is
|
||||
|
||||
// Run operation. This will revert on failure.
|
||||
IDydx(_getDydxAddress()).operate(accounts, actions);
|
||||
|
||||
return BRIDGE_SUCCESS;
|
||||
}
|
||||
|
||||
|
@@ -38,13 +38,14 @@ contract Eth2DaiBridge is
|
||||
/// (DAI or WETH) to the Eth2Dai contract, then transfers the bought
|
||||
/// tokens to `to`.
|
||||
/// @param toTokenAddress The token to give to `to` (either DAI or WETH).
|
||||
/// @param from The maker (this contract).
|
||||
/// @param to The recipient of the bought tokens.
|
||||
/// @param amount Minimum amount of `toTokenAddress` tokens to buy.
|
||||
/// @param bridgeData The abi-encoeded "from" token address.
|
||||
/// @return success The magic bytes if successful.
|
||||
function bridgeTransferFrom(
|
||||
address toTokenAddress,
|
||||
address /* from */,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes calldata bridgeData
|
||||
@@ -56,18 +57,28 @@ contract Eth2DaiBridge is
|
||||
(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.approve(fromTokenAddress, address(exchange), uint256(-1));
|
||||
LibERC20Token.approveIfBelow(fromTokenAddress, address(exchange), fromTokenBalance);
|
||||
|
||||
// Try to sell all of this contract's `fromTokenAddress` token balance.
|
||||
uint256 boughtAmount = exchange.sellAllAmount(
|
||||
fromTokenAddress,
|
||||
IERC20Token(fromTokenAddress).balanceOf(address(this)),
|
||||
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;
|
||||
}
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -45,6 +45,7 @@ contract KyberBridge is
|
||||
uint256 fromTokenBalance;
|
||||
uint256 payableAmount;
|
||||
uint256 conversionRate;
|
||||
bytes hint;
|
||||
}
|
||||
|
||||
/// @dev Kyber ETH pseudo-address.
|
||||
@@ -66,13 +67,14 @@ contract KyberBridge is
|
||||
/// 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 from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes calldata bridgeData
|
||||
@@ -84,43 +86,35 @@ contract KyberBridge is
|
||||
state.kyber = IKyberNetworkProxy(_getKyberNetworkProxyAddress());
|
||||
state.weth = IEtherToken(_getWethAddress());
|
||||
// Decode the bridge data to get the `fromTokenAddress`.
|
||||
(state.fromTokenAddress) = abi.decode(bridgeData, (address));
|
||||
(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;
|
||||
}
|
||||
// Compute the conversion rate, expressed in 18 decimals.
|
||||
// The sequential notation is to get around stack limits.
|
||||
state.conversionRate = KYBER_RATE_BASE;
|
||||
state.conversionRate = state.conversionRate.safeMul(amount);
|
||||
state.conversionRate = state.conversionRate.safeMul(
|
||||
10 ** uint256(LibERC20Token.decimals(state.fromTokenAddress))
|
||||
);
|
||||
state.conversionRate = state.conversionRate.safeDiv(state.fromTokenBalance);
|
||||
state.conversionRate = state.conversionRate.safeDiv(
|
||||
10 ** uint256(LibERC20Token.decimals(toTokenAddress))
|
||||
);
|
||||
if (state.fromTokenAddress == toTokenAddress) {
|
||||
// Just transfer the tokens if they're the same.
|
||||
LibERC20Token.transfer(state.fromTokenAddress, to, state.fromTokenBalance);
|
||||
return BRIDGE_SUCCESS;
|
||||
} else if (state.fromTokenAddress != address(state.weth)) {
|
||||
// If the input token is not WETH, grant an allowance to the exchange
|
||||
// to spend them.
|
||||
LibERC20Token.approve(state.fromTokenAddress, address(state.kyber), uint256(-1));
|
||||
} else {
|
||||
// If the input token is WETH, unwrap it and attach it to the call.
|
||||
}
|
||||
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.trade.value(state.payableAmount)(
|
||||
uint256 boughtAmount = state.kyber.tradeWithHint.value(state.payableAmount)(
|
||||
// Input token.
|
||||
state.fromTokenAddress,
|
||||
// Sell amount.
|
||||
@@ -132,17 +126,26 @@ contract KyberBridge is
|
||||
isToTokenWeth ? address(uint160(address(this))) : address(uint160(to)),
|
||||
// Buy as much as possible.
|
||||
uint256(-1),
|
||||
// Compute the minimum conversion rate, which is expressed in units with
|
||||
// 18 decimal places.
|
||||
state.conversionRate,
|
||||
// The minimum conversion rate
|
||||
1,
|
||||
// No affiliate address.
|
||||
address(0)
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -159,4 +162,5 @@ contract KyberBridge is
|
||||
{
|
||||
return LEGACY_WALLET_MAGIC_VALUE;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
|
||||
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
|
||||
import "../interfaces/IERC20Bridge.sol";
|
||||
import "../interfaces/IMStable.sol";
|
||||
|
||||
|
||||
contract MStableBridge is
|
||||
IERC20Bridge,
|
||||
IWallet,
|
||||
DeploymentConstants
|
||||
{
|
||||
|
||||
/// @dev Swaps specified tokens against the mStable mUSD contract
|
||||
/// @param toTokenAddress The token to give to `to` (i.e DAI, USDC, USDT).
|
||||
/// @param from The maker (this contract).
|
||||
/// @param to The recipient of the bought tokens.
|
||||
/// @param amount Minimum amount of `toTokenAddress` tokens to buy.
|
||||
/// @param bridgeData The abi-encoded "from" token address.
|
||||
/// @return success The magic bytes if successful.
|
||||
// solhint-disable no-unused-vars
|
||||
function bridgeTransferFrom(
|
||||
address toTokenAddress,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes calldata bridgeData
|
||||
)
|
||||
external
|
||||
returns (bytes4 success)
|
||||
{
|
||||
// Decode the bridge data to get the `fromTokenAddress`.
|
||||
(address fromTokenAddress) = abi.decode(bridgeData, (address));
|
||||
|
||||
IMStable exchange = IMStable(_getMUsdAddress());
|
||||
uint256 fromTokenBalance = IERC20Token(fromTokenAddress).balanceOf(address(this));
|
||||
// Grant an allowance to the exchange to spend `fromTokenAddress` token.
|
||||
LibERC20Token.approveIfBelow(fromTokenAddress, address(exchange), fromTokenBalance);
|
||||
|
||||
// Try to sell all of this contract's `fromTokenAddress` token balance.
|
||||
uint256 boughtAmount = exchange.swap(
|
||||
fromTokenAddress,
|
||||
toTokenAddress,
|
||||
fromTokenBalance,
|
||||
to
|
||||
);
|
||||
|
||||
emit ERC20BridgeTransfer(
|
||||
fromTokenAddress,
|
||||
toTokenAddress,
|
||||
fromTokenBalance,
|
||||
boughtAmount,
|
||||
from,
|
||||
to
|
||||
);
|
||||
return BRIDGE_SUCCESS;
|
||||
}
|
||||
|
||||
/// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
|
||||
/// and sign for itself in orders. Always succeeds.
|
||||
/// @return magicValue Magic success bytes, always.
|
||||
function isValidSignature(
|
||||
bytes32,
|
||||
bytes calldata
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (bytes4 magicValue)
|
||||
{
|
||||
return LEGACY_WALLET_MAGIC_VALUE;
|
||||
}
|
||||
}
|
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.16;
|
||||
|
||||
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
|
||||
import "../interfaces/IGasToken.sol";
|
||||
|
||||
|
||||
contract MixinGasToken is
|
||||
DeploymentConstants
|
||||
{
|
||||
|
||||
/// @dev Frees gas tokens based on the amount of gas consumed in the function
|
||||
modifier freesGasTokens {
|
||||
uint256 gasBefore = gasleft();
|
||||
_;
|
||||
IGasToken gst = IGasToken(_getGstAddress());
|
||||
if (address(gst) != address(0)) {
|
||||
// (gasUsed + FREE_BASE) / (2 * REIMBURSE - FREE_TOKEN)
|
||||
// 14154 24000 6870
|
||||
uint256 value = (gasBefore - gasleft() + 14154) / 41130;
|
||||
gst.freeUpTo(value);
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Frees gas tokens using the balance of `from`. Amount freed is based
|
||||
/// on the gas consumed in the function
|
||||
modifier freesGasTokensFromCollector() {
|
||||
uint256 gasBefore = gasleft();
|
||||
_;
|
||||
IGasToken gst = IGasToken(_getGstAddress());
|
||||
if (address(gst) != address(0)) {
|
||||
// (gasUsed + FREE_BASE) / (2 * REIMBURSE - FREE_TOKEN)
|
||||
// 14154 24000 6870
|
||||
uint256 value = (gasBefore - gasleft() + 14154) / 41130;
|
||||
gst.freeFromUpTo(_getGstCollectorAddress(), value);
|
||||
}
|
||||
}
|
||||
}
|
148
contracts/asset-proxy/contracts/src/bridges/MooniswapBridge.sol
Normal file
148
contracts/asset-proxy/contracts/src/bridges/MooniswapBridge.sol
Normal file
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
|
||||
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
|
||||
import "../interfaces/IERC20Bridge.sol";
|
||||
import "../interfaces/IMooniswap.sol";
|
||||
|
||||
|
||||
// solhint-disable space-after-comma
|
||||
// solhint-disable not-rely-on-time
|
||||
contract MooniswapBridge is
|
||||
IERC20Bridge,
|
||||
IWallet,
|
||||
DeploymentConstants
|
||||
{
|
||||
|
||||
struct TransferState {
|
||||
IMooniswap pool;
|
||||
uint256 fromTokenBalance;
|
||||
IEtherToken weth;
|
||||
uint256 boughtAmount;
|
||||
address fromTokenAddress;
|
||||
address toTokenAddress;
|
||||
}
|
||||
|
||||
// solhint-disable no-empty-blocks
|
||||
/// @dev Payable fallback to receive ETH from uniswap.
|
||||
function ()
|
||||
external
|
||||
payable
|
||||
{}
|
||||
|
||||
/// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of
|
||||
/// `toTokenAddress` tokens by selling the entirety of the `fromTokenAddress`
|
||||
/// token encoded in the bridge data.
|
||||
/// @param toTokenAddress The token to buy and transfer to `to`.
|
||||
/// @param from The maker (this contract).
|
||||
/// @param to The recipient of the bought tokens.
|
||||
/// @param amount Minimum amount of `toTokenAddress` tokens to buy.
|
||||
/// @param bridgeData The abi-encoded path of token addresses. Last element must be toTokenAddress
|
||||
/// @return success The magic bytes if successful.
|
||||
function bridgeTransferFrom(
|
||||
address toTokenAddress,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes calldata bridgeData
|
||||
)
|
||||
external
|
||||
returns (bytes4 success)
|
||||
{
|
||||
// State memory object to avoid stack overflows.
|
||||
TransferState memory state;
|
||||
// Decode the bridge data to get the `fromTokenAddress`.
|
||||
address fromTokenAddress = abi.decode(bridgeData, (address));
|
||||
// Get the weth contract.
|
||||
state.weth = IEtherToken(_getWethAddress());
|
||||
// Get our balance of `fromTokenAddress` token.
|
||||
state.fromTokenBalance = IERC20Token(fromTokenAddress).balanceOf(address(this));
|
||||
|
||||
state.fromTokenAddress = fromTokenAddress == address(state.weth) ? address(0) : fromTokenAddress;
|
||||
state.toTokenAddress = toTokenAddress == address(state.weth) ? address(0) : toTokenAddress;
|
||||
state.pool = IMooniswap(
|
||||
IMooniswapRegistry(_getMooniswapAddress()).pools(
|
||||
state.fromTokenAddress,
|
||||
state.toTokenAddress
|
||||
)
|
||||
);
|
||||
|
||||
// withdraw WETH to ETH
|
||||
if (state.fromTokenAddress == address(0)) {
|
||||
state.weth.withdraw(state.fromTokenBalance);
|
||||
} else {
|
||||
// Grant the pool an allowance.
|
||||
LibERC20Token.approveIfBelow(
|
||||
state.fromTokenAddress,
|
||||
address(state.pool),
|
||||
state.fromTokenBalance
|
||||
);
|
||||
}
|
||||
uint256 ethValue = state.fromTokenAddress == address(0) ? state.fromTokenBalance : 0;
|
||||
state.boughtAmount = state.pool.swap.value(ethValue)(
|
||||
state.fromTokenAddress,
|
||||
state.toTokenAddress,
|
||||
state.fromTokenBalance,
|
||||
amount,
|
||||
address(0)
|
||||
);
|
||||
// Deposit to WETH
|
||||
if (state.toTokenAddress == address(0)) {
|
||||
state.weth.deposit.value(state.boughtAmount)();
|
||||
}
|
||||
|
||||
// Transfer funds to `to`
|
||||
LibERC20Token.transfer(toTokenAddress, to, state.boughtAmount);
|
||||
|
||||
emit ERC20BridgeTransfer(
|
||||
// input token
|
||||
fromTokenAddress,
|
||||
// output token
|
||||
toTokenAddress,
|
||||
// input token amount
|
||||
state.fromTokenBalance,
|
||||
// output token amount
|
||||
state.boughtAmount,
|
||||
from,
|
||||
to
|
||||
);
|
||||
|
||||
return BRIDGE_SUCCESS;
|
||||
}
|
||||
|
||||
/// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
|
||||
/// and sign for itself in orders. Always succeeds.
|
||||
/// @return magicValue Success bytes, always.
|
||||
function isValidSignature(
|
||||
bytes32,
|
||||
bytes calldata
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (bytes4 magicValue)
|
||||
{
|
||||
return LEGACY_WALLET_MAGIC_VALUE;
|
||||
}
|
||||
}
|
96
contracts/asset-proxy/contracts/src/bridges/ShellBridge.sol
Normal file
96
contracts/asset-proxy/contracts/src/bridges/ShellBridge.sol
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
|
||||
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`.
|
||||
(address fromTokenAddress) = abi.decode(bridgeData, (address));
|
||||
|
||||
uint256 fromTokenBalance = IERC20Token(fromTokenAddress).balanceOf(address(this));
|
||||
IShell exchange = IShell(_getShellAddress());
|
||||
// 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.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;
|
||||
}
|
||||
}
|
136
contracts/asset-proxy/contracts/src/bridges/SushiSwapBridge.sol
Normal file
136
contracts/asset-proxy/contracts/src/bridges/SushiSwapBridge.sol
Normal file
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibAddressArray.sol";
|
||||
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
|
||||
import "../interfaces/IUniswapV2Router01.sol";
|
||||
import "../interfaces/IERC20Bridge.sol";
|
||||
|
||||
|
||||
// solhint-disable space-after-comma
|
||||
// solhint-disable not-rely-on-time
|
||||
contract SushiSwapBridge is
|
||||
IERC20Bridge,
|
||||
IWallet,
|
||||
DeploymentConstants
|
||||
{
|
||||
struct TransferState {
|
||||
address[] path;
|
||||
address router;
|
||||
uint256 fromTokenBalance;
|
||||
}
|
||||
|
||||
/// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of
|
||||
/// `toTokenAddress` tokens by selling the entirety of the `fromTokenAddress`
|
||||
/// token encoded in the bridge data.
|
||||
/// @param toTokenAddress The token to buy and transfer to `to`.
|
||||
/// @param from The maker (this contract).
|
||||
/// @param to The recipient of the bought tokens.
|
||||
/// @param amount Minimum amount of `toTokenAddress` tokens to buy.
|
||||
/// @param bridgeData The abi-encoded path of token addresses. Last element must be toTokenAddress
|
||||
/// @return success The magic bytes if successful.
|
||||
function bridgeTransferFrom(
|
||||
address toTokenAddress,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes calldata bridgeData
|
||||
)
|
||||
external
|
||||
returns (bytes4 success)
|
||||
{
|
||||
// hold variables to get around stack depth limitations
|
||||
TransferState memory state;
|
||||
|
||||
// Decode the bridge data to get the `fromTokenAddress`.
|
||||
// solhint-disable indent
|
||||
(state.path, state.router) = abi.decode(bridgeData, (address[], address));
|
||||
// solhint-enable indent
|
||||
|
||||
require(state.path.length >= 2, "SushiSwapBridge/PATH_LENGTH_MUST_BE_AT_LEAST_TWO");
|
||||
require(state.path[state.path.length - 1] == toTokenAddress, "SushiSwapBridge/LAST_ELEMENT_OF_PATH_MUST_MATCH_OUTPUT_TOKEN");
|
||||
|
||||
// Just transfer the tokens if they're the same.
|
||||
if (state.path[0] == toTokenAddress) {
|
||||
LibERC20Token.transfer(state.path[0], to, amount);
|
||||
return BRIDGE_SUCCESS;
|
||||
}
|
||||
|
||||
// Get our balance of `fromTokenAddress` token.
|
||||
state.fromTokenBalance = IERC20Token(state.path[0]).balanceOf(address(this));
|
||||
|
||||
// Grant the SushiSwap router an allowance.
|
||||
LibERC20Token.approveIfBelow(
|
||||
state.path[0],
|
||||
state.router,
|
||||
state.fromTokenBalance
|
||||
);
|
||||
|
||||
// Buy as much `toTokenAddress` token with `fromTokenAddress` token
|
||||
// and transfer it to `to`.
|
||||
IUniswapV2Router01 router = IUniswapV2Router01(state.router);
|
||||
uint[] memory amounts = router.swapExactTokensForTokens(
|
||||
// Sell all tokens we hold.
|
||||
state.fromTokenBalance,
|
||||
// Minimum buy amount.
|
||||
amount,
|
||||
// Convert `fromTokenAddress` to `toTokenAddress`.
|
||||
state.path,
|
||||
// Recipient is `to`.
|
||||
to,
|
||||
// Expires after this block.
|
||||
block.timestamp
|
||||
);
|
||||
|
||||
emit ERC20BridgeTransfer(
|
||||
// input token
|
||||
state.path[0],
|
||||
// output token
|
||||
toTokenAddress,
|
||||
// input token amount
|
||||
state.fromTokenBalance,
|
||||
// output token amount
|
||||
amounts[amounts.length - 1],
|
||||
from,
|
||||
to
|
||||
);
|
||||
|
||||
return BRIDGE_SUCCESS;
|
||||
}
|
||||
|
||||
/// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
|
||||
/// and sign for itself in orders. Always succeeds.
|
||||
/// @return magicValue Success bytes, always.
|
||||
function isValidSignature(
|
||||
bytes32,
|
||||
bytes calldata
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (bytes4 magicValue)
|
||||
{
|
||||
return LEGACY_WALLET_MAGIC_VALUE;
|
||||
}
|
||||
}
|
@@ -38,10 +38,11 @@ contract UniswapBridge is
|
||||
{
|
||||
// Struct to hold `bridgeTransferFrom()` local variables in memory and to avoid
|
||||
// stack overflows.
|
||||
struct WithdrawToState {
|
||||
struct TransferState {
|
||||
IUniswapExchange exchange;
|
||||
uint256 fromTokenBalance;
|
||||
IEtherToken weth;
|
||||
uint256 boughtAmount;
|
||||
}
|
||||
|
||||
// solhint-disable no-empty-blocks
|
||||
@@ -55,13 +56,14 @@ contract UniswapBridge is
|
||||
/// `toTokenAddress` tokens by selling the entirety of the `fromTokenAddress`
|
||||
/// token encoded in the bridge data.
|
||||
/// @param toTokenAddress The token to buy and transfer to `to`.
|
||||
/// @param from The maker (this contract).
|
||||
/// @param to The recipient of the bought tokens.
|
||||
/// @param amount Minimum amount of `toTokenAddress` tokens to buy.
|
||||
/// @param bridgeData The abi-encoded "from" token address.
|
||||
/// @return success The magic bytes if successful.
|
||||
function bridgeTransferFrom(
|
||||
address toTokenAddress,
|
||||
address /* from */,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes calldata bridgeData
|
||||
@@ -70,7 +72,7 @@ contract UniswapBridge is
|
||||
returns (bytes4 success)
|
||||
{
|
||||
// State memory object to avoid stack overflows.
|
||||
WithdrawToState memory state;
|
||||
TransferState memory state;
|
||||
// Decode the bridge data to get the `fromTokenAddress`.
|
||||
(address fromTokenAddress) = abi.decode(bridgeData, (address));
|
||||
|
||||
@@ -96,7 +98,7 @@ contract UniswapBridge is
|
||||
state.weth.withdraw(state.fromTokenBalance);
|
||||
// Buy as much of `toTokenAddress` token with ETH as possible and
|
||||
// transfer it to `to`.
|
||||
state.exchange.ethToTokenTransferInput.value(state.fromTokenBalance)(
|
||||
state.boughtAmount = state.exchange.ethToTokenTransferInput.value(state.fromTokenBalance)(
|
||||
// Minimum buy amount.
|
||||
amount,
|
||||
// Expires after this block.
|
||||
@@ -108,9 +110,9 @@ contract UniswapBridge is
|
||||
// Convert from a token to WETH.
|
||||
} else if (toTokenAddress == address(state.weth)) {
|
||||
// Grant the exchange an allowance.
|
||||
_grantExchangeAllowance(state.exchange, fromTokenAddress);
|
||||
_grantExchangeAllowance(state.exchange, fromTokenAddress, state.fromTokenBalance);
|
||||
// Buy as much ETH with `fromTokenAddress` token as possible.
|
||||
uint256 ethBought = state.exchange.tokenToEthSwapInput(
|
||||
state.boughtAmount = state.exchange.tokenToEthSwapInput(
|
||||
// Sell all tokens we hold.
|
||||
state.fromTokenBalance,
|
||||
// Minimum buy amount.
|
||||
@@ -119,17 +121,17 @@ contract UniswapBridge is
|
||||
block.timestamp
|
||||
);
|
||||
// Wrap the ETH.
|
||||
state.weth.deposit.value(ethBought)();
|
||||
state.weth.deposit.value(state.boughtAmount)();
|
||||
// Transfer the WETH to `to`.
|
||||
IEtherToken(toTokenAddress).transfer(to, ethBought);
|
||||
IEtherToken(toTokenAddress).transfer(to, state.boughtAmount);
|
||||
|
||||
// Convert from one token to another.
|
||||
} else {
|
||||
// Grant the exchange an allowance.
|
||||
_grantExchangeAllowance(state.exchange, fromTokenAddress);
|
||||
_grantExchangeAllowance(state.exchange, fromTokenAddress, state.fromTokenBalance);
|
||||
// Buy as much `toTokenAddress` token with `fromTokenAddress` token
|
||||
// and transfer it to `to`.
|
||||
state.exchange.tokenToTokenTransferInput(
|
||||
state.boughtAmount = state.exchange.tokenToTokenTransferInput(
|
||||
// Sell all tokens we hold.
|
||||
state.fromTokenBalance,
|
||||
// Minimum buy amount.
|
||||
@@ -144,6 +146,15 @@ contract UniswapBridge is
|
||||
toTokenAddress
|
||||
);
|
||||
}
|
||||
|
||||
emit ERC20BridgeTransfer(
|
||||
fromTokenAddress,
|
||||
toTokenAddress,
|
||||
state.fromTokenBalance,
|
||||
state.boughtAmount,
|
||||
from,
|
||||
to
|
||||
);
|
||||
return BRIDGE_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -165,10 +176,19 @@ contract UniswapBridge is
|
||||
/// on behalf of this contract.
|
||||
/// @param exchange The Uniswap token exchange.
|
||||
/// @param tokenAddress The token address for the exchange.
|
||||
function _grantExchangeAllowance(IUniswapExchange exchange, address tokenAddress)
|
||||
/// @param minimumAllowance The minimum necessary allowance.
|
||||
function _grantExchangeAllowance(
|
||||
IUniswapExchange exchange,
|
||||
address tokenAddress,
|
||||
uint256 minimumAllowance
|
||||
)
|
||||
private
|
||||
{
|
||||
LibERC20Token.approve(tokenAddress, address(exchange), uint256(-1));
|
||||
LibERC20Token.approveIfBelow(
|
||||
tokenAddress,
|
||||
address(exchange),
|
||||
minimumAllowance
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Retrieves the uniswap exchange for a given token pair.
|
||||
|
135
contracts/asset-proxy/contracts/src/bridges/UniswapV2Bridge.sol
Normal file
135
contracts/asset-proxy/contracts/src/bridges/UniswapV2Bridge.sol
Normal file
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibAddressArray.sol";
|
||||
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
|
||||
import "../interfaces/IUniswapV2Router01.sol";
|
||||
import "../interfaces/IERC20Bridge.sol";
|
||||
|
||||
|
||||
// solhint-disable space-after-comma
|
||||
// solhint-disable not-rely-on-time
|
||||
contract UniswapV2Bridge is
|
||||
IERC20Bridge,
|
||||
IWallet,
|
||||
DeploymentConstants
|
||||
{
|
||||
struct TransferState {
|
||||
address[] path;
|
||||
uint256 fromTokenBalance;
|
||||
}
|
||||
|
||||
/// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of
|
||||
/// `toTokenAddress` tokens by selling the entirety of the `fromTokenAddress`
|
||||
/// token encoded in the bridge data.
|
||||
/// @param toTokenAddress The token to buy and transfer to `to`.
|
||||
/// @param from The maker (this contract).
|
||||
/// @param to The recipient of the bought tokens.
|
||||
/// @param amount Minimum amount of `toTokenAddress` tokens to buy.
|
||||
/// @param bridgeData The abi-encoded path of token addresses. Last element must be toTokenAddress
|
||||
/// @return success The magic bytes if successful.
|
||||
function bridgeTransferFrom(
|
||||
address toTokenAddress,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes calldata bridgeData
|
||||
)
|
||||
external
|
||||
returns (bytes4 success)
|
||||
{
|
||||
// hold variables to get around stack depth limitations
|
||||
TransferState memory state;
|
||||
|
||||
// Decode the bridge data to get the `fromTokenAddress`.
|
||||
// solhint-disable indent
|
||||
state.path = abi.decode(bridgeData, (address[]));
|
||||
// solhint-enable indent
|
||||
|
||||
require(state.path.length >= 2, "UniswapV2Bridge/PATH_LENGTH_MUST_BE_AT_LEAST_TWO");
|
||||
require(state.path[state.path.length - 1] == toTokenAddress, "UniswapV2Bridge/LAST_ELEMENT_OF_PATH_MUST_MATCH_OUTPUT_TOKEN");
|
||||
|
||||
// Just transfer the tokens if they're the same.
|
||||
if (state.path[0] == toTokenAddress) {
|
||||
LibERC20Token.transfer(state.path[0], to, amount);
|
||||
return BRIDGE_SUCCESS;
|
||||
}
|
||||
|
||||
// Get our balance of `fromTokenAddress` token.
|
||||
state.fromTokenBalance = IERC20Token(state.path[0]).balanceOf(address(this));
|
||||
|
||||
// Grant the Uniswap router an allowance.
|
||||
LibERC20Token.approveIfBelow(
|
||||
state.path[0],
|
||||
_getUniswapV2Router01Address(),
|
||||
state.fromTokenBalance
|
||||
);
|
||||
|
||||
// Buy as much `toTokenAddress` token with `fromTokenAddress` token
|
||||
// and transfer it to `to`.
|
||||
IUniswapV2Router01 router = IUniswapV2Router01(_getUniswapV2Router01Address());
|
||||
uint[] memory amounts = router.swapExactTokensForTokens(
|
||||
// Sell all tokens we hold.
|
||||
state.fromTokenBalance,
|
||||
// Minimum buy amount.
|
||||
amount,
|
||||
// Convert `fromTokenAddress` to `toTokenAddress`.
|
||||
state.path,
|
||||
// Recipient is `to`.
|
||||
to,
|
||||
// Expires after this block.
|
||||
block.timestamp
|
||||
);
|
||||
|
||||
emit ERC20BridgeTransfer(
|
||||
// input token
|
||||
state.path[0],
|
||||
// output token
|
||||
toTokenAddress,
|
||||
// input token amount
|
||||
state.fromTokenBalance,
|
||||
// output token amount
|
||||
amounts[amounts.length - 1],
|
||||
from,
|
||||
to
|
||||
);
|
||||
|
||||
return BRIDGE_SUCCESS;
|
||||
}
|
||||
|
||||
/// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
|
||||
/// and sign for itself in orders. Always succeeds.
|
||||
/// @return magicValue Success bytes, always.
|
||||
function isValidSignature(
|
||||
bytes32,
|
||||
bytes calldata
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (bytes4 magicValue)
|
||||
{
|
||||
return LEGACY_WALLET_MAGIC_VALUE;
|
||||
}
|
||||
}
|
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
|
||||
interface IBalancerPool {
|
||||
/// @dev Sell `tokenAmountIn` of `tokenIn` and receive `tokenOut`.
|
||||
/// @param tokenIn The token being sold
|
||||
/// @param tokenAmountIn The amount of `tokenIn` to sell.
|
||||
/// @param tokenOut The token being bought.
|
||||
/// @param minAmountOut The minimum amount of `tokenOut` to buy.
|
||||
/// @param maxPrice The maximum value for `spotPriceAfter`.
|
||||
/// @return tokenAmountOut The amount of `tokenOut` bought.
|
||||
/// @return spotPriceAfter The new marginal spot price of the given
|
||||
/// token pair for this pool.
|
||||
function swapExactAmountIn(
|
||||
address tokenIn,
|
||||
uint tokenAmountIn,
|
||||
address tokenOut,
|
||||
uint minAmountOut,
|
||||
uint maxPrice
|
||||
) external returns (uint tokenAmountOut, uint spotPriceAfter);
|
||||
}
|
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
|
||||
contract IContractRegistry {
|
||||
function addressOf(
|
||||
bytes32 contractName
|
||||
) external returns(address);
|
||||
}
|
||||
|
||||
|
||||
contract IBancorNetwork {
|
||||
function convertByPath(
|
||||
address[] calldata _path,
|
||||
uint256 _amount,
|
||||
uint256 _minReturn,
|
||||
address _beneficiary,
|
||||
address _affiliateAccount,
|
||||
uint256 _affiliateFee
|
||||
) external payable returns (uint256);
|
||||
}
|
@@ -22,22 +22,6 @@ 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 early versions of Curve (USDC/DAI)
|
||||
/// @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.
|
||||
/// @param deadline The time in seconds when this operation should expire.
|
||||
function exchange_underlying(
|
||||
int128 i,
|
||||
int128 j,
|
||||
uint256 sellAmount,
|
||||
uint256 minBuyAmount,
|
||||
uint256 deadline
|
||||
)
|
||||
external;
|
||||
|
||||
/// @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.
|
||||
@@ -65,7 +49,6 @@ interface ICurve {
|
||||
returns (uint256 dy);
|
||||
|
||||
/// @dev Get the amount of `fromToken` by buying `buyAmount` of `toToken`
|
||||
/// 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 buyAmount The amount of token being bought.
|
||||
|
@@ -21,9 +21,25 @@ pragma solidity ^0.5.9;
|
||||
|
||||
contract IERC20Bridge {
|
||||
|
||||
// @dev Result of a successful bridge call.
|
||||
/// @dev Result of a successful bridge call.
|
||||
bytes4 constant internal BRIDGE_SUCCESS = 0xdc1600f3;
|
||||
|
||||
/// @dev Emitted when a trade occurs.
|
||||
/// @param inputToken The token the bridge is converting from.
|
||||
/// @param outputToken The token the bridge is converting to.
|
||||
/// @param inputTokenAmount Amount of input token.
|
||||
/// @param outputTokenAmount Amount of output token.
|
||||
/// @param from The `from` address in `bridgeTransferFrom()`
|
||||
/// @param to The `to` address in `bridgeTransferFrom()`
|
||||
event ERC20BridgeTransfer(
|
||||
address inputToken,
|
||||
address outputToken,
|
||||
uint256 inputTokenAmount,
|
||||
uint256 outputTokenAmount,
|
||||
address from,
|
||||
address to
|
||||
);
|
||||
|
||||
/// @dev Transfers `amount` of the ERC20 `tokenAddress` from `from` to `to`.
|
||||
/// @param tokenAddress The address of the ERC20 token to transfer.
|
||||
/// @param from Address to transfer asset from.
|
||||
|
40
contracts/asset-proxy/contracts/src/interfaces/IGasToken.sol
Normal file
40
contracts/asset-proxy/contracts/src/interfaces/IGasToken.sol
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.15;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||
|
||||
|
||||
contract IGasToken is IERC20Token {
|
||||
|
||||
/// @dev Frees up to `value` sub-tokens
|
||||
/// @param value The amount of tokens to free
|
||||
/// @return How many tokens were freed
|
||||
function freeUpTo(uint256 value) external returns (uint256 freed);
|
||||
|
||||
/// @dev Frees up to `value` sub-tokens owned by `from`
|
||||
/// @param from The owner of tokens to spend
|
||||
/// @param value The amount of tokens to free
|
||||
/// @return How many tokens were freed
|
||||
function freeFromUpTo(address from, uint256 value) external returns (uint256 freed);
|
||||
|
||||
/// @dev Mints `value` amount of tokens
|
||||
/// @param value The amount of tokens to mint
|
||||
function mint(uint256 value) external;
|
||||
}
|
@@ -42,5 +42,31 @@ interface IKyberNetworkProxy {
|
||||
)
|
||||
external
|
||||
payable
|
||||
returns(uint256 boughtAmount);
|
||||
returns (uint256 boughtAmount);
|
||||
|
||||
/// @dev Sells `sellTokenAddress` tokens for `buyTokenAddress` tokens
|
||||
/// using a hint for the reserve.
|
||||
/// @param sellTokenAddress Token to sell.
|
||||
/// @param sellAmount Amount of tokens to sell.
|
||||
/// @param buyTokenAddress Token to buy.
|
||||
/// @param recipientAddress Address to send bought tokens to.
|
||||
/// @param maxBuyTokenAmount A limit on the amount of tokens to buy.
|
||||
/// @param minConversionRate The minimal conversion rate. If actual rate
|
||||
/// is lower, trade is canceled.
|
||||
/// @param walletId The wallet ID to send part of the fees
|
||||
/// @param hint The hint for the selective inclusion (or exclusion) of reserves
|
||||
/// @return boughtAmount Amount of tokens bought.
|
||||
function tradeWithHint(
|
||||
address sellTokenAddress,
|
||||
uint256 sellAmount,
|
||||
address buyTokenAddress,
|
||||
address payable recipientAddress,
|
||||
uint256 maxBuyTokenAmount,
|
||||
uint256 minConversionRate,
|
||||
address payable walletId,
|
||||
bytes calldata hint
|
||||
)
|
||||
external
|
||||
payable
|
||||
returns (uint256 boughtAmount);
|
||||
}
|
||||
|
32
contracts/asset-proxy/contracts/src/interfaces/IMStable.sol
Normal file
32
contracts/asset-proxy/contracts/src/interfaces/IMStable.sol
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
|
||||
interface IMStable {
|
||||
|
||||
function swap(
|
||||
address _input,
|
||||
address _output,
|
||||
uint256 _quantity,
|
||||
address _recipient
|
||||
)
|
||||
external
|
||||
returns (uint256 output);
|
||||
}
|
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
|
||||
interface IMooniswapRegistry {
|
||||
|
||||
function pools(address token1, address token2) external view returns(address);
|
||||
}
|
||||
|
||||
|
||||
interface IMooniswap {
|
||||
|
||||
function swap(
|
||||
address fromToken,
|
||||
address destToken,
|
||||
uint256 amount,
|
||||
uint256 minReturn,
|
||||
address referral
|
||||
)
|
||||
external
|
||||
payable
|
||||
returns(uint256 returnAmount);
|
||||
}
|
34
contracts/asset-proxy/contracts/src/interfaces/IShell.sol
Normal file
34
contracts/asset-proxy/contracts/src/interfaces/IShell.sol
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
|
||||
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);
|
||||
}
|
||||
|
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
|
||||
interface IUniswapV2Router01 {
|
||||
|
||||
/// @dev Swaps an exact amount of input tokens for as many output tokens as possible, along the route determined by the path.
|
||||
/// The first element of path is the input token, the last is the output token, and any intermediate elements represent
|
||||
/// intermediate pairs to trade through (if, for example, a direct pair does not exist).
|
||||
/// @param amountIn The amount of input tokens to send.
|
||||
/// @param amountOutMin The minimum amount of output tokens that must be received for the transaction not to revert.
|
||||
/// @param path An array of token addresses. path.length must be >= 2. Pools for each consecutive pair of addresses must exist and have liquidity.
|
||||
/// @param to Recipient of the output tokens.
|
||||
/// @param deadline Unix timestamp after which the transaction will revert.
|
||||
/// @return amounts The input token amount and all subsequent output token amounts.
|
||||
function swapExactTokensForTokens(
|
||||
uint amountIn,
|
||||
uint amountOutMin,
|
||||
address[] calldata path,
|
||||
address to,
|
||||
uint deadline
|
||||
) external returns (uint[] memory amounts);
|
||||
}
|
247
contracts/asset-proxy/contracts/test/TestBancorBridge.sol
Normal file
247
contracts/asset-proxy/contracts/test/TestBancorBridge.sol
Normal file
@@ -0,0 +1,247 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibAddressArray.sol";
|
||||
import "../src/bridges/BancorBridge.sol";
|
||||
import "../src/interfaces/IBancorNetwork.sol";
|
||||
|
||||
|
||||
contract TestEventsRaiser {
|
||||
|
||||
event TokenTransfer(
|
||||
address token,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
);
|
||||
|
||||
event TokenApprove(
|
||||
address spender,
|
||||
uint256 allowance
|
||||
);
|
||||
|
||||
event ConvertByPathInput(
|
||||
uint amountIn,
|
||||
uint amountOutMin,
|
||||
address toTokenAddress,
|
||||
address to,
|
||||
address feeRecipient,
|
||||
uint256 feeAmount
|
||||
);
|
||||
|
||||
function raiseTokenTransfer(
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
)
|
||||
external
|
||||
{
|
||||
emit TokenTransfer(
|
||||
msg.sender,
|
||||
from,
|
||||
to,
|
||||
amount
|
||||
);
|
||||
}
|
||||
|
||||
function raiseTokenApprove(address spender, uint256 allowance) external {
|
||||
emit TokenApprove(spender, allowance);
|
||||
}
|
||||
|
||||
function raiseConvertByPathInput(
|
||||
uint amountIn,
|
||||
uint amountOutMin,
|
||||
address toTokenAddress,
|
||||
address to,
|
||||
address feeRecipient,
|
||||
uint256 feeAmount
|
||||
) external
|
||||
{
|
||||
emit ConvertByPathInput(
|
||||
amountIn,
|
||||
amountOutMin,
|
||||
toTokenAddress,
|
||||
to,
|
||||
feeRecipient,
|
||||
feeAmount
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// @dev A minimalist ERC20 token.
|
||||
contract TestToken {
|
||||
|
||||
using LibSafeMath for uint256;
|
||||
|
||||
mapping (address => uint256) public balances;
|
||||
string private _nextRevertReason;
|
||||
|
||||
/// @dev Set the balance for `owner`.
|
||||
function setBalance(address owner, uint256 balance)
|
||||
external
|
||||
payable
|
||||
{
|
||||
balances[owner] = balance;
|
||||
}
|
||||
|
||||
/// @dev Just emits a TokenTransfer event on the caller
|
||||
function transfer(address to, uint256 amount)
|
||||
external
|
||||
returns (bool)
|
||||
{
|
||||
TestEventsRaiser(msg.sender).raiseTokenTransfer(msg.sender, to, amount);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// @dev Just emits a TokenApprove event on the caller
|
||||
function approve(address spender, uint256 allowance)
|
||||
external
|
||||
returns (bool)
|
||||
{
|
||||
TestEventsRaiser(msg.sender).raiseTokenApprove(spender, allowance);
|
||||
return true;
|
||||
}
|
||||
|
||||
function allowance(address, address) external view returns (uint256) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// @dev Retrieve the balance for `owner`.
|
||||
function balanceOf(address owner)
|
||||
external
|
||||
view
|
||||
returns (uint256)
|
||||
{
|
||||
return balances[owner];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// @dev Mock the BancorNetwork contract
|
||||
contract TestBancorNetwork is
|
||||
IBancorNetwork
|
||||
{
|
||||
string private _nextRevertReason;
|
||||
|
||||
/// @dev Set the revert reason for `swapExactTokensForTokens`.
|
||||
function setRevertReason(string calldata reason)
|
||||
external
|
||||
{
|
||||
_nextRevertReason = reason;
|
||||
}
|
||||
|
||||
function convertByPath(
|
||||
address[] calldata _path,
|
||||
uint256 _amount,
|
||||
uint256 _minReturn,
|
||||
address _beneficiary,
|
||||
address _affiliateAccount,
|
||||
uint256 _affiliateFee
|
||||
) external payable returns (uint256)
|
||||
{
|
||||
_revertIfReasonExists();
|
||||
|
||||
TestEventsRaiser(msg.sender).raiseConvertByPathInput(
|
||||
// tokens sold
|
||||
_amount,
|
||||
// tokens bought
|
||||
_minReturn,
|
||||
// output token
|
||||
_path[_path.length - 1],
|
||||
// recipient
|
||||
_beneficiary,
|
||||
// fee recipient
|
||||
_affiliateAccount,
|
||||
// fee amount
|
||||
_affiliateFee
|
||||
);
|
||||
}
|
||||
|
||||
function _revertIfReasonExists()
|
||||
private
|
||||
view
|
||||
{
|
||||
if (bytes(_nextRevertReason).length != 0) {
|
||||
revert(_nextRevertReason);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// @dev BancorBridge overridden to mock tokens and BancorNetwork
|
||||
contract TestBancorBridge is
|
||||
BancorBridge,
|
||||
TestEventsRaiser
|
||||
{
|
||||
|
||||
// Token address to TestToken instance.
|
||||
mapping (address => TestToken) private _testTokens;
|
||||
// TestRouter instance.
|
||||
TestBancorNetwork private _testNetwork;
|
||||
|
||||
constructor() public {
|
||||
_testNetwork = new TestBancorNetwork();
|
||||
}
|
||||
|
||||
function setNetworkRevertReason(string calldata revertReason)
|
||||
external
|
||||
{
|
||||
_testNetwork.setRevertReason(revertReason);
|
||||
}
|
||||
|
||||
/// @dev Sets the balance of this contract for an existing token.
|
||||
function setTokenBalance(address tokenAddress, uint256 balance)
|
||||
external
|
||||
{
|
||||
TestToken token = _testTokens[tokenAddress];
|
||||
token.setBalance(address(this), balance);
|
||||
}
|
||||
|
||||
/// @dev Create a new token
|
||||
/// @param tokenAddress The token address. If zero, one will be created.
|
||||
function createToken(
|
||||
address tokenAddress
|
||||
)
|
||||
external
|
||||
returns (TestToken token)
|
||||
{
|
||||
token = TestToken(tokenAddress);
|
||||
if (tokenAddress == address(0)) {
|
||||
token = new TestToken();
|
||||
}
|
||||
_testTokens[address(token)] = token;
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
function getNetworkAddress()
|
||||
external
|
||||
view
|
||||
returns (address)
|
||||
{
|
||||
return address(_testNetwork);
|
||||
}
|
||||
|
||||
}
|
244
contracts/asset-proxy/contracts/test/TestDexForwarderBridge.sol
Normal file
244
contracts/asset-proxy/contracts/test/TestDexForwarderBridge.sol
Normal file
@@ -0,0 +1,244 @@
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "../src/bridges/DexForwarderBridge.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
|
||||
|
||||
|
||||
interface ITestDexForwarderBridge {
|
||||
event BridgeTransferFromCalled(
|
||||
address caller,
|
||||
uint256 inputTokenBalance,
|
||||
address inputToken,
|
||||
address outputToken,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
);
|
||||
|
||||
event TokenTransferCalled(
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
);
|
||||
|
||||
function emitBridgeTransferFromCalled(
|
||||
address caller,
|
||||
uint256 inputTokenBalance,
|
||||
address inputToken,
|
||||
address outputToken,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
) external;
|
||||
|
||||
function emitTokenTransferCalled(
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
) external;
|
||||
}
|
||||
|
||||
|
||||
interface ITestDexForwarderBridgeTestToken {
|
||||
|
||||
function transfer(address to, uint256 amount)
|
||||
external
|
||||
returns (bool);
|
||||
|
||||
function mint(address to, uint256 amount)
|
||||
external;
|
||||
|
||||
function balanceOf(address owner) external view returns (uint256);
|
||||
}
|
||||
|
||||
|
||||
contract TestDexForwarderBridgeTestBridge {
|
||||
|
||||
bytes4 private _returnCode;
|
||||
string private _revertError;
|
||||
uint256 private _transferAmount;
|
||||
ITestDexForwarderBridge private _testContract;
|
||||
|
||||
constructor(bytes4 returnCode, string memory revertError) public {
|
||||
_testContract = ITestDexForwarderBridge(msg.sender);
|
||||
_returnCode = returnCode;
|
||||
_revertError = revertError;
|
||||
}
|
||||
|
||||
function setTransferAmount(uint256 amount) external {
|
||||
_transferAmount = amount;
|
||||
}
|
||||
|
||||
function bridgeTransferFrom(
|
||||
address outputToken,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes memory bridgeData
|
||||
)
|
||||
public
|
||||
returns (bytes4 success)
|
||||
{
|
||||
if (bytes(_revertError).length != 0) {
|
||||
revert(_revertError);
|
||||
}
|
||||
address inputToken = abi.decode(bridgeData, (address));
|
||||
_testContract.emitBridgeTransferFromCalled(
|
||||
msg.sender,
|
||||
ITestDexForwarderBridgeTestToken(inputToken).balanceOf(address(this)),
|
||||
inputToken,
|
||||
outputToken,
|
||||
from,
|
||||
to,
|
||||
amount
|
||||
);
|
||||
ITestDexForwarderBridgeTestToken(outputToken).mint(to, _transferAmount);
|
||||
return _returnCode;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
contract TestDexForwarderBridgeTestToken {
|
||||
|
||||
using LibSafeMath for uint256;
|
||||
|
||||
mapping(address => uint256) public balanceOf;
|
||||
ITestDexForwarderBridge private _testContract;
|
||||
|
||||
constructor() public {
|
||||
_testContract = ITestDexForwarderBridge(msg.sender);
|
||||
}
|
||||
|
||||
function transfer(address to, uint256 amount)
|
||||
external
|
||||
returns (bool)
|
||||
{
|
||||
balanceOf[msg.sender] = balanceOf[msg.sender].safeSub(amount);
|
||||
balanceOf[to] = balanceOf[to].safeAdd(amount);
|
||||
_testContract.emitTokenTransferCalled(msg.sender, to, amount);
|
||||
return true;
|
||||
}
|
||||
|
||||
function mint(address owner, uint256 amount)
|
||||
external
|
||||
{
|
||||
balanceOf[owner] = balanceOf[owner].safeAdd(amount);
|
||||
}
|
||||
|
||||
function setBalance(address owner, uint256 amount)
|
||||
external
|
||||
{
|
||||
balanceOf[owner] = amount;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
contract TestDexForwarderBridge is
|
||||
ITestDexForwarderBridge,
|
||||
DexForwarderBridge
|
||||
{
|
||||
address private AUTHORIZED_ADDRESS; // solhint-disable-line var-name-mixedcase
|
||||
|
||||
function setAuthorized(address authorized)
|
||||
public
|
||||
{
|
||||
AUTHORIZED_ADDRESS = authorized;
|
||||
}
|
||||
|
||||
function createBridge(
|
||||
bytes4 returnCode,
|
||||
string memory revertError
|
||||
)
|
||||
public
|
||||
returns (address bridge)
|
||||
{
|
||||
return address(new TestDexForwarderBridgeTestBridge(returnCode, revertError));
|
||||
}
|
||||
|
||||
function createToken() public returns (address token) {
|
||||
return address(new TestDexForwarderBridgeTestToken());
|
||||
}
|
||||
|
||||
function setTokenBalance(address token, address owner, uint256 amount) public {
|
||||
TestDexForwarderBridgeTestToken(token).setBalance(owner, amount);
|
||||
}
|
||||
|
||||
function setBridgeTransferAmount(address bridge, uint256 amount) public {
|
||||
TestDexForwarderBridgeTestBridge(bridge).setTransferAmount(amount);
|
||||
}
|
||||
|
||||
function emitBridgeTransferFromCalled(
|
||||
address caller,
|
||||
uint256 inputTokenBalance,
|
||||
address inputToken,
|
||||
address outputToken,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
)
|
||||
public
|
||||
{
|
||||
emit BridgeTransferFromCalled(
|
||||
caller,
|
||||
inputTokenBalance,
|
||||
inputToken,
|
||||
outputToken,
|
||||
from,
|
||||
to,
|
||||
amount
|
||||
);
|
||||
}
|
||||
|
||||
function emitTokenTransferCalled(
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
)
|
||||
public
|
||||
{
|
||||
emit TokenTransferCalled(
|
||||
from,
|
||||
to,
|
||||
amount
|
||||
);
|
||||
}
|
||||
|
||||
function balanceOf(address token, address owner) public view returns (uint256) {
|
||||
return TestDexForwarderBridgeTestToken(token).balanceOf(owner);
|
||||
}
|
||||
|
||||
function _getGstAddress()
|
||||
internal
|
||||
view
|
||||
returns (address gst)
|
||||
{
|
||||
return address(0);
|
||||
}
|
||||
|
||||
function _getERC20BridgeProxyAddress()
|
||||
internal
|
||||
view
|
||||
returns (address erc20BridgeProxyAddress)
|
||||
{
|
||||
return AUTHORIZED_ADDRESS;
|
||||
}
|
||||
}
|
@@ -110,6 +110,10 @@ contract TestToken {
|
||||
return true;
|
||||
}
|
||||
|
||||
function allowance(address, address) external view returns (uint256) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// @dev Retrieve the balance for `owner`.
|
||||
function balanceOf(address owner)
|
||||
external
|
||||
|
@@ -110,6 +110,10 @@ contract TestToken {
|
||||
return _testContract.wethDeposit.value(msg.value)(msg.sender);
|
||||
}
|
||||
|
||||
function allowance(address, address) external view returns (uint256) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
function balanceOf(address owner)
|
||||
external
|
||||
view
|
||||
@@ -197,6 +201,33 @@ contract TestKyberBridge is
|
||||
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)
|
||||
|
@@ -224,6 +224,10 @@ contract TestToken {
|
||||
TestEventsRaiser(msg.sender).raiseWethWithdraw(amount);
|
||||
}
|
||||
|
||||
function allowance(address, address) external view returns (uint256) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// @dev Retrieve the balance for `owner`.
|
||||
function balanceOf(address owner)
|
||||
external
|
||||
|
253
contracts/asset-proxy/contracts/test/TestUniswapV2Bridge.sol
Normal file
253
contracts/asset-proxy/contracts/test/TestUniswapV2Bridge.sol
Normal file
@@ -0,0 +1,253 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibAddressArray.sol";
|
||||
import "../src/bridges/UniswapV2Bridge.sol";
|
||||
import "../src/interfaces/IUniswapV2Router01.sol";
|
||||
|
||||
|
||||
contract TestEventsRaiser {
|
||||
|
||||
event TokenTransfer(
|
||||
address token,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
);
|
||||
|
||||
event TokenApprove(
|
||||
address spender,
|
||||
uint256 allowance
|
||||
);
|
||||
|
||||
event SwapExactTokensForTokensInput(
|
||||
uint amountIn,
|
||||
uint amountOutMin,
|
||||
address toTokenAddress,
|
||||
address to,
|
||||
uint deadline
|
||||
);
|
||||
|
||||
function raiseTokenTransfer(
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
)
|
||||
external
|
||||
{
|
||||
emit TokenTransfer(
|
||||
msg.sender,
|
||||
from,
|
||||
to,
|
||||
amount
|
||||
);
|
||||
}
|
||||
|
||||
function raiseTokenApprove(address spender, uint256 allowance) external {
|
||||
emit TokenApprove(spender, allowance);
|
||||
}
|
||||
|
||||
function raiseSwapExactTokensForTokensInput(
|
||||
uint amountIn,
|
||||
uint amountOutMin,
|
||||
address toTokenAddress,
|
||||
address to,
|
||||
uint deadline
|
||||
) external
|
||||
{
|
||||
emit SwapExactTokensForTokensInput(
|
||||
amountIn,
|
||||
amountOutMin,
|
||||
toTokenAddress,
|
||||
to,
|
||||
deadline
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// @dev A minimalist ERC20 token.
|
||||
contract TestToken {
|
||||
|
||||
using LibSafeMath for uint256;
|
||||
|
||||
mapping (address => uint256) public balances;
|
||||
string private _nextRevertReason;
|
||||
|
||||
/// @dev Set the balance for `owner`.
|
||||
function setBalance(address owner, uint256 balance)
|
||||
external
|
||||
payable
|
||||
{
|
||||
balances[owner] = balance;
|
||||
}
|
||||
|
||||
/// @dev Just emits a TokenTransfer event on the caller
|
||||
function transfer(address to, uint256 amount)
|
||||
external
|
||||
returns (bool)
|
||||
{
|
||||
TestEventsRaiser(msg.sender).raiseTokenTransfer(msg.sender, to, amount);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// @dev Just emits a TokenApprove event on the caller
|
||||
function approve(address spender, uint256 allowance)
|
||||
external
|
||||
returns (bool)
|
||||
{
|
||||
TestEventsRaiser(msg.sender).raiseTokenApprove(spender, allowance);
|
||||
return true;
|
||||
}
|
||||
|
||||
function allowance(address, address) external view returns (uint256) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// @dev Retrieve the balance for `owner`.
|
||||
function balanceOf(address owner)
|
||||
external
|
||||
view
|
||||
returns (uint256)
|
||||
{
|
||||
return balances[owner];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// @dev Mock the UniswapV2Router01 contract
|
||||
contract TestRouter is
|
||||
IUniswapV2Router01
|
||||
{
|
||||
string private _nextRevertReason;
|
||||
|
||||
/// @dev Set the revert reason for `swapExactTokensForTokens`.
|
||||
function setRevertReason(string calldata reason)
|
||||
external
|
||||
{
|
||||
_nextRevertReason = reason;
|
||||
}
|
||||
|
||||
function swapExactTokensForTokens(
|
||||
uint amountIn,
|
||||
uint amountOutMin,
|
||||
address[] calldata path,
|
||||
address to,
|
||||
uint deadline
|
||||
) external returns (uint[] memory amounts)
|
||||
{
|
||||
_revertIfReasonExists();
|
||||
|
||||
amounts = new uint[](path.length);
|
||||
amounts[0] = amountIn;
|
||||
amounts[amounts.length - 1] = amountOutMin;
|
||||
|
||||
TestEventsRaiser(msg.sender).raiseSwapExactTokensForTokensInput(
|
||||
// tokens sold
|
||||
amountIn,
|
||||
// tokens bought
|
||||
amountOutMin,
|
||||
// output token (toTokenAddress)
|
||||
path[path.length - 1],
|
||||
// recipient
|
||||
to,
|
||||
// deadline
|
||||
deadline
|
||||
);
|
||||
}
|
||||
|
||||
function _revertIfReasonExists()
|
||||
private
|
||||
view
|
||||
{
|
||||
if (bytes(_nextRevertReason).length != 0) {
|
||||
revert(_nextRevertReason);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// @dev UniswapV2Bridge overridden to mock tokens and Uniswap router
|
||||
contract TestUniswapV2Bridge is
|
||||
UniswapV2Bridge,
|
||||
TestEventsRaiser
|
||||
{
|
||||
|
||||
// Token address to TestToken instance.
|
||||
mapping (address => TestToken) private _testTokens;
|
||||
// TestRouter instance.
|
||||
TestRouter private _testRouter;
|
||||
|
||||
constructor() public {
|
||||
_testRouter = new TestRouter();
|
||||
}
|
||||
|
||||
function setRouterRevertReason(string calldata revertReason)
|
||||
external
|
||||
{
|
||||
_testRouter.setRevertReason(revertReason);
|
||||
}
|
||||
|
||||
/// @dev Sets the balance of this contract for an existing token.
|
||||
/// The wei attached will be the balance.
|
||||
function setTokenBalance(address tokenAddress, uint256 balance)
|
||||
external
|
||||
{
|
||||
TestToken token = _testTokens[tokenAddress];
|
||||
token.setBalance(address(this), balance);
|
||||
}
|
||||
|
||||
/// @dev Create a new token
|
||||
/// @param tokenAddress The token address. If zero, one will be created.
|
||||
function createToken(
|
||||
address tokenAddress
|
||||
)
|
||||
external
|
||||
returns (TestToken token)
|
||||
{
|
||||
token = TestToken(tokenAddress);
|
||||
if (tokenAddress == address(0)) {
|
||||
token = new TestToken();
|
||||
}
|
||||
_testTokens[address(token)] = token;
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
function getRouterAddress()
|
||||
external
|
||||
view
|
||||
returns (address)
|
||||
{
|
||||
return address(_testRouter);
|
||||
}
|
||||
|
||||
function _getUniswapV2Router01Address()
|
||||
internal
|
||||
view
|
||||
returns (address)
|
||||
{
|
||||
return address(_testRouter);
|
||||
}
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-asset-proxy",
|
||||
"version": "3.2.5",
|
||||
"version": "3.5.0",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -38,30 +38,31 @@
|
||||
"docs:json": "typedoc --excludePrivate --excludeExternals --excludeProtected --ignoreCompilerErrors --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES"
|
||||
},
|
||||
"config": {
|
||||
"abis": "./test/generated-artifacts/@(ChaiBridge|CurveBridge|DydxBridge|ERC1155Proxy|ERC20BridgeProxy|ERC20Proxy|ERC721Proxy|Eth2DaiBridge|IAssetData|IAssetProxy|IAssetProxyDispatcher|IAuthorizable|IChai|ICurve|IDydx|IDydxBridge|IERC20Bridge|IEth2Dai|IKyberNetworkProxy|IUniswapExchange|IUniswapExchangeFactory|KyberBridge|MixinAssetProxyDispatcher|MixinAuthorizable|MultiAssetProxy|Ownable|StaticCallProxy|TestChaiBridge|TestDydxBridge|TestERC20Bridge|TestEth2DaiBridge|TestKyberBridge|TestStaticCallTarget|TestUniswapBridge|UniswapBridge).json",
|
||||
"abis": "./test/generated-artifacts/@(BalancerBridge|BancorBridge|ChaiBridge|CreamBridge|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|StaticCallProxy|SushiSwapBridge|TestBancorBridge|TestChaiBridge|TestDexForwarderBridge|TestDydxBridge|TestERC20Bridge|TestEth2DaiBridge|TestKyberBridge|TestStaticCallTarget|TestUniswapBridge|TestUniswapV2Bridge|UniswapBridge|UniswapV2Bridge).json",
|
||||
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually."
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/0xProject/0x-monorepo.git"
|
||||
"url": "https://github.com/0xProject/protocol.git"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/0xProject/0x-monorepo/issues"
|
||||
"url": "https://github.com/0xProject/protocol/issues"
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/protocol/README.md",
|
||||
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/protocol",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.2.2",
|
||||
"@0x/contracts-gen": "^2.0.8",
|
||||
"@0x/contracts-test-utils": "^5.3.2",
|
||||
"@0x/contracts-utils": "^4.4.3",
|
||||
"@0x/dev-utils": "^3.2.1",
|
||||
"@0x/sol-compiler": "^4.0.8",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
"@0x/abi-gen": "^5.4.3",
|
||||
"@0x/contract-wrappers": "^13.9.0",
|
||||
"@0x/contracts-gen": "2.0.13",
|
||||
"@0x/contracts-test-utils": "^5.3.5",
|
||||
"@0x/contracts-utils": "^4.5.2",
|
||||
"@0x/dev-utils": "^3.3.4",
|
||||
"@0x/sol-compiler": "^4.2.3",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
"@0x/tslint-config": "^4.1.3",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "*",
|
||||
"@types/node": "12.12.54",
|
||||
"chai": "^4.0.1",
|
||||
"chai-as-promised": "^7.1.0",
|
||||
"chai-bignumber": "^3.0.0",
|
||||
@@ -74,24 +75,25 @@
|
||||
"solhint": "^1.4.1",
|
||||
"truffle": "^5.0.32",
|
||||
"tslint": "5.11.0",
|
||||
"typedoc": "^0.15.0",
|
||||
"typedoc": "~0.16.11",
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.2.1",
|
||||
"@0x/contracts-erc1155": "^2.1.5",
|
||||
"@0x/contracts-erc20": "^3.1.5",
|
||||
"@0x/contracts-erc721": "^3.1.5",
|
||||
"@0x/contracts-exchange-libs": "^4.3.5",
|
||||
"@0x/order-utils": "^10.2.4",
|
||||
"@0x/types": "^3.1.2",
|
||||
"@0x/typescript-typings": "^5.0.2",
|
||||
"@0x/utils": "^5.4.1",
|
||||
"@0x/web3-wrapper": "^7.0.7",
|
||||
"ethereum-types": "^3.1.0",
|
||||
"@0x/base-contract": "^6.2.7",
|
||||
"@0x/contracts-erc1155": "^2.1.8",
|
||||
"@0x/contracts-erc20": "^3.2.2",
|
||||
"@0x/contracts-erc721": "^3.1.8",
|
||||
"@0x/contracts-exchange-libs": "^4.3.8",
|
||||
"@0x/order-utils": "^10.4.0",
|
||||
"@0x/types": "^3.2.4",
|
||||
"@0x/typescript-typings": "^5.1.5",
|
||||
"@0x/utils": "^5.6.3",
|
||||
"@0x/web3-wrapper": "^7.2.4",
|
||||
"ethereum-types": "^3.3.3",
|
||||
"lodash": "^4.17.11"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
},
|
||||
"gitHead": "4f91bfd907996b2f4dd383778b50c479c2602b56"
|
||||
}
|
||||
|
@@ -5,8 +5,13 @@
|
||||
*/
|
||||
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 CurveBridge from '../generated-artifacts/CurveBridge.json';
|
||||
import * as DexForwarderBridge from '../generated-artifacts/DexForwarderBridge.json';
|
||||
import * as DODOBridge from '../generated-artifacts/DODOBridge.json';
|
||||
import * as DydxBridge from '../generated-artifacts/DydxBridge.json';
|
||||
import * as ERC1155Proxy from '../generated-artifacts/ERC1155Proxy.json';
|
||||
import * as ERC20BridgeProxy from '../generated-artifacts/ERC20BridgeProxy.json';
|
||||
@@ -17,29 +22,45 @@ import * as IAssetData from '../generated-artifacts/IAssetData.json';
|
||||
import * as IAssetProxy from '../generated-artifacts/IAssetProxy.json';
|
||||
import * as IAssetProxyDispatcher from '../generated-artifacts/IAssetProxyDispatcher.json';
|
||||
import * as IAuthorizable from '../generated-artifacts/IAuthorizable.json';
|
||||
import * as IBalancerPool from '../generated-artifacts/IBalancerPool.json';
|
||||
import * as IBancorNetwork from '../generated-artifacts/IBancorNetwork.json';
|
||||
import * as IChai from '../generated-artifacts/IChai.json';
|
||||
import * as ICurve from '../generated-artifacts/ICurve.json';
|
||||
import * as IDydx from '../generated-artifacts/IDydx.json';
|
||||
import * as IDydxBridge from '../generated-artifacts/IDydxBridge.json';
|
||||
import * as IERC20Bridge from '../generated-artifacts/IERC20Bridge.json';
|
||||
import * as IEth2Dai from '../generated-artifacts/IEth2Dai.json';
|
||||
import * as IGasToken from '../generated-artifacts/IGasToken.json';
|
||||
import * as IKyberNetworkProxy from '../generated-artifacts/IKyberNetworkProxy.json';
|
||||
import * as IMooniswap from '../generated-artifacts/IMooniswap.json';
|
||||
import * as IMStable from '../generated-artifacts/IMStable.json';
|
||||
import * as IShell from '../generated-artifacts/IShell.json';
|
||||
import * as IUniswapExchange from '../generated-artifacts/IUniswapExchange.json';
|
||||
import * as IUniswapExchangeFactory from '../generated-artifacts/IUniswapExchangeFactory.json';
|
||||
import * as IUniswapV2Router01 from '../generated-artifacts/IUniswapV2Router01.json';
|
||||
import * as KyberBridge from '../generated-artifacts/KyberBridge.json';
|
||||
import * as MixinAssetProxyDispatcher from '../generated-artifacts/MixinAssetProxyDispatcher.json';
|
||||
import * as MixinAuthorizable from '../generated-artifacts/MixinAuthorizable.json';
|
||||
import * as MixinGasToken from '../generated-artifacts/MixinGasToken.json';
|
||||
import * as MooniswapBridge from '../generated-artifacts/MooniswapBridge.json';
|
||||
import * as MStableBridge from '../generated-artifacts/MStableBridge.json';
|
||||
import * as MultiAssetProxy from '../generated-artifacts/MultiAssetProxy.json';
|
||||
import * as Ownable from '../generated-artifacts/Ownable.json';
|
||||
import * as ShellBridge from '../generated-artifacts/ShellBridge.json';
|
||||
import * as StaticCallProxy from '../generated-artifacts/StaticCallProxy.json';
|
||||
import * as SushiSwapBridge from '../generated-artifacts/SushiSwapBridge.json';
|
||||
import * as TestBancorBridge from '../generated-artifacts/TestBancorBridge.json';
|
||||
import * as TestChaiBridge from '../generated-artifacts/TestChaiBridge.json';
|
||||
import * as TestDexForwarderBridge from '../generated-artifacts/TestDexForwarderBridge.json';
|
||||
import * as TestDydxBridge from '../generated-artifacts/TestDydxBridge.json';
|
||||
import * as TestERC20Bridge from '../generated-artifacts/TestERC20Bridge.json';
|
||||
import * as TestEth2DaiBridge from '../generated-artifacts/TestEth2DaiBridge.json';
|
||||
import * as TestKyberBridge from '../generated-artifacts/TestKyberBridge.json';
|
||||
import * as TestStaticCallTarget from '../generated-artifacts/TestStaticCallTarget.json';
|
||||
import * as TestUniswapBridge from '../generated-artifacts/TestUniswapBridge.json';
|
||||
import * as TestUniswapV2Bridge from '../generated-artifacts/TestUniswapV2Bridge.json';
|
||||
import * as UniswapBridge from '../generated-artifacts/UniswapBridge.json';
|
||||
import * as UniswapV2Bridge from '../generated-artifacts/UniswapV2Bridge.json';
|
||||
export const artifacts = {
|
||||
MixinAssetProxyDispatcher: MixinAssetProxyDispatcher as ContractArtifact,
|
||||
MixinAuthorizable: MixinAuthorizable as ContractArtifact,
|
||||
@@ -50,30 +71,51 @@ export const artifacts = {
|
||||
ERC721Proxy: ERC721Proxy as ContractArtifact,
|
||||
MultiAssetProxy: MultiAssetProxy as ContractArtifact,
|
||||
StaticCallProxy: StaticCallProxy as ContractArtifact,
|
||||
BalancerBridge: BalancerBridge as ContractArtifact,
|
||||
BancorBridge: BancorBridge as ContractArtifact,
|
||||
ChaiBridge: ChaiBridge as ContractArtifact,
|
||||
CreamBridge: CreamBridge as ContractArtifact,
|
||||
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,
|
||||
SushiSwapBridge: SushiSwapBridge 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,
|
||||
};
|
||||
|
27
contracts/asset-proxy/src/dex_forwarder_bridge.ts
Normal file
27
contracts/asset-proxy/src/dex_forwarder_bridge.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { AbiEncoder, BigNumber } from '@0x/utils';
|
||||
|
||||
export interface DexForwarderBridgeCall {
|
||||
target: string;
|
||||
inputTokenAmount: BigNumber;
|
||||
outputTokenAmount: BigNumber;
|
||||
bridgeData: string;
|
||||
}
|
||||
|
||||
export interface DexForwaderBridgeData {
|
||||
inputToken: string;
|
||||
calls: DexForwarderBridgeCall[];
|
||||
}
|
||||
|
||||
export const dexForwarderBridgeDataEncoder = AbiEncoder.create([
|
||||
{ name: 'inputToken', type: 'address' },
|
||||
{
|
||||
name: 'calls',
|
||||
type: 'tuple[]',
|
||||
components: [
|
||||
{ name: 'target', type: 'address' },
|
||||
{ name: 'inputTokenAmount', type: 'uint256' },
|
||||
{ name: 'outputTokenAmount', type: 'uint256' },
|
||||
{ name: 'bridgeData', type: 'bytes' },
|
||||
],
|
||||
},
|
||||
]);
|
@@ -1,5 +1,6 @@
|
||||
export { artifacts } from './artifacts';
|
||||
export {
|
||||
BalancerBridgeContract,
|
||||
ChaiBridgeContract,
|
||||
ERC1155ProxyContract,
|
||||
ERC20BridgeProxyContract,
|
||||
@@ -17,6 +18,7 @@ export {
|
||||
TestDydxBridgeContract,
|
||||
TestStaticCallTargetContract,
|
||||
UniswapBridgeContract,
|
||||
DexForwarderBridgeContract,
|
||||
} from './wrappers';
|
||||
|
||||
export { ERC20Wrapper } from './erc20_wrapper';
|
||||
@@ -88,3 +90,4 @@ export {
|
||||
} from './asset_data';
|
||||
|
||||
export * from './dydx_bridge_encoder';
|
||||
export * from './dex_forwarder_bridge';
|
||||
|
@@ -3,8 +3,13 @@
|
||||
* 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/curve_bridge';
|
||||
export * from '../generated-wrappers/d_o_d_o_bridge';
|
||||
export * from '../generated-wrappers/dex_forwarder_bridge';
|
||||
export * from '../generated-wrappers/dydx_bridge';
|
||||
export * from '../generated-wrappers/erc1155_proxy';
|
||||
export * from '../generated-wrappers/erc20_bridge_proxy';
|
||||
@@ -15,26 +20,42 @@ export * from '../generated-wrappers/i_asset_data';
|
||||
export * from '../generated-wrappers/i_asset_proxy';
|
||||
export * from '../generated-wrappers/i_asset_proxy_dispatcher';
|
||||
export * from '../generated-wrappers/i_authorizable';
|
||||
export * from '../generated-wrappers/i_balancer_pool';
|
||||
export * from '../generated-wrappers/i_bancor_network';
|
||||
export * from '../generated-wrappers/i_chai';
|
||||
export * from '../generated-wrappers/i_curve';
|
||||
export * from '../generated-wrappers/i_dydx';
|
||||
export * from '../generated-wrappers/i_dydx_bridge';
|
||||
export * from '../generated-wrappers/i_erc20_bridge';
|
||||
export * from '../generated-wrappers/i_eth2_dai';
|
||||
export * from '../generated-wrappers/i_gas_token';
|
||||
export * from '../generated-wrappers/i_kyber_network_proxy';
|
||||
export * from '../generated-wrappers/i_m_stable';
|
||||
export * from '../generated-wrappers/i_mooniswap';
|
||||
export * from '../generated-wrappers/i_shell';
|
||||
export * from '../generated-wrappers/i_uniswap_exchange';
|
||||
export * from '../generated-wrappers/i_uniswap_exchange_factory';
|
||||
export * from '../generated-wrappers/i_uniswap_v2_router01';
|
||||
export * from '../generated-wrappers/kyber_bridge';
|
||||
export * from '../generated-wrappers/m_stable_bridge';
|
||||
export * from '../generated-wrappers/mixin_asset_proxy_dispatcher';
|
||||
export * from '../generated-wrappers/mixin_authorizable';
|
||||
export * from '../generated-wrappers/mixin_gas_token';
|
||||
export * from '../generated-wrappers/mooniswap_bridge';
|
||||
export * from '../generated-wrappers/multi_asset_proxy';
|
||||
export * from '../generated-wrappers/ownable';
|
||||
export * from '../generated-wrappers/shell_bridge';
|
||||
export * from '../generated-wrappers/static_call_proxy';
|
||||
export * from '../generated-wrappers/sushi_swap_bridge';
|
||||
export * from '../generated-wrappers/test_bancor_bridge';
|
||||
export * from '../generated-wrappers/test_chai_bridge';
|
||||
export * from '../generated-wrappers/test_dex_forwarder_bridge';
|
||||
export * from '../generated-wrappers/test_dydx_bridge';
|
||||
export * from '../generated-wrappers/test_erc20_bridge';
|
||||
export * from '../generated-wrappers/test_eth2_dai_bridge';
|
||||
export * from '../generated-wrappers/test_kyber_bridge';
|
||||
export * from '../generated-wrappers/test_static_call_target';
|
||||
export * from '../generated-wrappers/test_uniswap_bridge';
|
||||
export * from '../generated-wrappers/test_uniswap_v2_bridge';
|
||||
export * from '../generated-wrappers/uniswap_bridge';
|
||||
export * from '../generated-wrappers/uniswap_v2_bridge';
|
||||
|
@@ -5,8 +5,13 @@
|
||||
*/
|
||||
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 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';
|
||||
@@ -17,29 +22,45 @@ 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 StaticCallProxy from '../test/generated-artifacts/StaticCallProxy.json';
|
||||
import * as SushiSwapBridge from '../test/generated-artifacts/SushiSwapBridge.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,
|
||||
@@ -50,30 +71,51 @@ export const artifacts = {
|
||||
ERC721Proxy: ERC721Proxy as ContractArtifact,
|
||||
MultiAssetProxy: MultiAssetProxy as ContractArtifact,
|
||||
StaticCallProxy: StaticCallProxy as ContractArtifact,
|
||||
BalancerBridge: BalancerBridge as ContractArtifact,
|
||||
BancorBridge: BancorBridge as ContractArtifact,
|
||||
ChaiBridge: ChaiBridge as ContractArtifact,
|
||||
CreamBridge: CreamBridge as ContractArtifact,
|
||||
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,
|
||||
SushiSwapBridge: SushiSwapBridge 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,
|
||||
};
|
||||
|
205
contracts/asset-proxy/test/bancor_bridge.ts
Normal file
205
contracts/asset-proxy/test/bancor_bridge.ts
Normal file
@@ -0,0 +1,205 @@
|
||||
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,
|
||||
TestBancorBridgeTokenTransferEventArgs as TokenTransferArgs,
|
||||
} 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);
|
||||
});
|
||||
|
||||
it('performs transfer when both tokens are the same', async () => {
|
||||
const createTokenFn = testContract.createToken(constants.NULL_ADDRESS);
|
||||
const tokenAddress = await createTokenFn.callAsync();
|
||||
await createTokenFn.awaitTransactionSuccessAsync();
|
||||
|
||||
const { opts, result, logs } = await transferFromAsync({
|
||||
tokenAddressesPath: [tokenAddress, tokenAddress],
|
||||
});
|
||||
expect(result).to.eq(AssetProxyId.ERC20Bridge, 'asset proxy id');
|
||||
const transfers = filterLogsToArguments<TokenTransferArgs>(logs, ContractEvents.TokenTransfer);
|
||||
|
||||
expect(transfers.length).to.eq(1);
|
||||
expect(transfers[0].token).to.eq(tokenAddress, 'input token address');
|
||||
expect(transfers[0].from).to.eq(testContract.address);
|
||||
expect(transfers[0].to).to.eq(opts.toAddress, 'recipient address');
|
||||
expect(transfers[0].amount).to.bignumber.eq(opts.amount, 'amount');
|
||||
});
|
||||
|
||||
describe('token -> token', async () => {
|
||||
it('calls 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));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
354
contracts/asset-proxy/test/dex_forwarder_bridge.ts
Normal file
354
contracts/asset-proxy/test/dex_forwarder_bridge.ts
Normal file
@@ -0,0 +1,354 @@
|
||||
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');
|
||||
});
|
||||
});
|
||||
});
|
@@ -16,7 +16,8 @@ import { artifacts } from './artifacts';
|
||||
|
||||
import { TestKyberBridgeContract, TestKyberBridgeEvents } from './wrappers';
|
||||
|
||||
blockchainTests.resets('KyberBridge unit tests', env => {
|
||||
// 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;
|
||||
@@ -115,7 +116,7 @@ blockchainTests.resets('KyberBridge unit tests', env => {
|
||||
// Transfer amount.
|
||||
_opts.amount,
|
||||
// ABI-encode the input token address as the bridge data.
|
||||
hexUtils.leftPad(_opts.fromTokenAddress),
|
||||
hexUtils.concat(hexUtils.leftPad(_opts.fromTokenAddress), hexUtils.leftPad(32), hexUtils.leftPad(0)),
|
||||
);
|
||||
const result = await bridgeTransferFromFn.callAsync();
|
||||
const { logs } = await bridgeTransferFromFn.awaitTransactionSuccessAsync();
|
||||
|
216
contracts/asset-proxy/test/uniswapv2_bridge.ts
Normal file
216
contracts/asset-proxy/test/uniswapv2_bridge.ts
Normal file
@@ -0,0 +1,216 @@
|
||||
import {
|
||||
blockchainTests,
|
||||
constants,
|
||||
expect,
|
||||
filterLogsToArguments,
|
||||
getRandomInteger,
|
||||
randomAddress,
|
||||
} from '@0x/contracts-test-utils';
|
||||
import { AssetProxyId } from '@0x/types';
|
||||
import { AbiEncoder, BigNumber, hexUtils } from '@0x/utils';
|
||||
import { DecodedLogs } from 'ethereum-types';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { artifacts } from './artifacts';
|
||||
|
||||
import {
|
||||
TestUniswapV2BridgeContract,
|
||||
TestUniswapV2BridgeEvents as ContractEvents,
|
||||
TestUniswapV2BridgeSwapExactTokensForTokensInputEventArgs as SwapExactTokensForTokensArgs,
|
||||
TestUniswapV2BridgeTokenApproveEventArgs as TokenApproveArgs,
|
||||
TestUniswapV2BridgeTokenTransferEventArgs as TokenTransferArgs,
|
||||
} from './wrappers';
|
||||
|
||||
blockchainTests.resets('UniswapV2 unit tests', env => {
|
||||
const FROM_TOKEN_DECIMALS = 6;
|
||||
const TO_TOKEN_DECIMALS = 18;
|
||||
const FROM_TOKEN_BASE = new BigNumber(10).pow(FROM_TOKEN_DECIMALS);
|
||||
const TO_TOKEN_BASE = new BigNumber(10).pow(TO_TOKEN_DECIMALS);
|
||||
let testContract: TestUniswapV2BridgeContract;
|
||||
|
||||
before(async () => {
|
||||
testContract = await TestUniswapV2BridgeContract.deployFrom0xArtifactAsync(
|
||||
artifacts.TestUniswapV2Bridge,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
artifacts,
|
||||
);
|
||||
});
|
||||
|
||||
describe('isValidSignature()', () => {
|
||||
it('returns success bytes', async () => {
|
||||
const LEGACY_WALLET_MAGIC_VALUE = '0xb0671381';
|
||||
const result = await testContract
|
||||
.isValidSignature(hexUtils.random(), hexUtils.random(_.random(0, 32)))
|
||||
.callAsync();
|
||||
expect(result).to.eq(LEGACY_WALLET_MAGIC_VALUE);
|
||||
});
|
||||
});
|
||||
|
||||
describe('bridgeTransferFrom()', () => {
|
||||
interface TransferFromOpts {
|
||||
tokenAddressesPath: string[];
|
||||
toAddress: string;
|
||||
// Amount to pass into `bridgeTransferFrom()`
|
||||
amount: BigNumber;
|
||||
// Token balance of the bridge.
|
||||
fromTokenBalance: BigNumber;
|
||||
// Router reverts with this reason
|
||||
routerRevertReason: string;
|
||||
}
|
||||
|
||||
interface TransferFromResult {
|
||||
opts: TransferFromOpts;
|
||||
result: string;
|
||||
logs: DecodedLogs;
|
||||
blocktime: number;
|
||||
}
|
||||
|
||||
function createTransferFromOpts(opts?: Partial<TransferFromOpts>): TransferFromOpts {
|
||||
const amount = getRandomInteger(1, TO_TOKEN_BASE.times(100));
|
||||
return {
|
||||
tokenAddressesPath: Array(2).fill(constants.NULL_ADDRESS),
|
||||
amount,
|
||||
toAddress: randomAddress(),
|
||||
fromTokenBalance: getRandomInteger(1, FROM_TOKEN_BASE.times(100)),
|
||||
routerRevertReason: '',
|
||||
...opts,
|
||||
};
|
||||
}
|
||||
|
||||
const bridgeDataEncoder = AbiEncoder.create('(address[])');
|
||||
|
||||
async function transferFromAsync(opts?: Partial<TransferFromOpts>): Promise<TransferFromResult> {
|
||||
const _opts = createTransferFromOpts(opts);
|
||||
|
||||
for (let i = 0; i < _opts.tokenAddressesPath.length; i++) {
|
||||
const createFromTokenFn = testContract.createToken(_opts.tokenAddressesPath[i]);
|
||||
_opts.tokenAddressesPath[i] = await createFromTokenFn.callAsync();
|
||||
await createFromTokenFn.awaitTransactionSuccessAsync();
|
||||
}
|
||||
|
||||
// Set the token balance for the token we're converting from.
|
||||
await testContract
|
||||
.setTokenBalance(_opts.tokenAddressesPath[0], _opts.fromTokenBalance)
|
||||
.awaitTransactionSuccessAsync();
|
||||
|
||||
// Set revert reason for the router.
|
||||
await testContract.setRouterRevertReason(_opts.routerRevertReason).awaitTransactionSuccessAsync();
|
||||
|
||||
// Call bridgeTransferFrom().
|
||||
const bridgeTransferFromFn = testContract.bridgeTransferFrom(
|
||||
// Output token
|
||||
_opts.tokenAddressesPath[_opts.tokenAddressesPath.length - 1],
|
||||
// Random maker address.
|
||||
randomAddress(),
|
||||
// Recipient address.
|
||||
_opts.toAddress,
|
||||
// Transfer amount.
|
||||
_opts.amount,
|
||||
// ABI-encode the input token address as the bridge data. // FIXME
|
||||
bridgeDataEncoder.encode([_opts.tokenAddressesPath]),
|
||||
);
|
||||
const result = await bridgeTransferFromFn.callAsync();
|
||||
const receipt = await bridgeTransferFromFn.awaitTransactionSuccessAsync();
|
||||
return {
|
||||
opts: _opts,
|
||||
result,
|
||||
logs: (receipt.logs as any) as DecodedLogs,
|
||||
blocktime: await env.web3Wrapper.getBlockTimestampAsync(receipt.blockNumber),
|
||||
};
|
||||
}
|
||||
|
||||
it('returns magic bytes on success', async () => {
|
||||
const { result } = await transferFromAsync();
|
||||
expect(result).to.eq(AssetProxyId.ERC20Bridge);
|
||||
});
|
||||
|
||||
it('performs transfer when both tokens are the same', async () => {
|
||||
const createTokenFn = testContract.createToken(constants.NULL_ADDRESS);
|
||||
const tokenAddress = await createTokenFn.callAsync();
|
||||
await createTokenFn.awaitTransactionSuccessAsync();
|
||||
|
||||
const { opts, result, logs } = await transferFromAsync({
|
||||
tokenAddressesPath: [tokenAddress, tokenAddress],
|
||||
});
|
||||
expect(result).to.eq(AssetProxyId.ERC20Bridge, 'asset proxy id');
|
||||
const transfers = filterLogsToArguments<TokenTransferArgs>(logs, ContractEvents.TokenTransfer);
|
||||
|
||||
expect(transfers.length).to.eq(1);
|
||||
expect(transfers[0].token).to.eq(tokenAddress, 'input token address');
|
||||
expect(transfers[0].from).to.eq(testContract.address);
|
||||
expect(transfers[0].to).to.eq(opts.toAddress, 'recipient address');
|
||||
expect(transfers[0].amount).to.bignumber.eq(opts.amount, 'amount');
|
||||
});
|
||||
|
||||
describe('token -> token', async () => {
|
||||
it('calls UniswapV2Router01.swapExactTokensForTokens()', async () => {
|
||||
const { opts, result, logs, blocktime } = await transferFromAsync();
|
||||
expect(result).to.eq(AssetProxyId.ERC20Bridge, 'asset proxy id');
|
||||
const transfers = filterLogsToArguments<SwapExactTokensForTokensArgs>(
|
||||
logs,
|
||||
ContractEvents.SwapExactTokensForTokensInput,
|
||||
);
|
||||
|
||||
expect(transfers.length).to.eq(1);
|
||||
expect(transfers[0].toTokenAddress).to.eq(
|
||||
opts.tokenAddressesPath[opts.tokenAddressesPath.length - 1],
|
||||
'output token address',
|
||||
);
|
||||
expect(transfers[0].to).to.eq(opts.toAddress, 'recipient address');
|
||||
expect(transfers[0].amountIn).to.bignumber.eq(opts.fromTokenBalance, 'input token amount');
|
||||
expect(transfers[0].amountOutMin).to.bignumber.eq(opts.amount, 'output token amount');
|
||||
expect(transfers[0].deadline).to.bignumber.eq(blocktime, 'deadline');
|
||||
});
|
||||
|
||||
it('sets allowance for "from" token', async () => {
|
||||
const { logs } = await transferFromAsync();
|
||||
const approvals = filterLogsToArguments<TokenApproveArgs>(logs, ContractEvents.TokenApprove);
|
||||
const routerAddress = await testContract.getRouterAddress().callAsync();
|
||||
expect(approvals.length).to.eq(1);
|
||||
expect(approvals[0].spender).to.eq(routerAddress);
|
||||
expect(approvals[0].allowance).to.bignumber.eq(constants.MAX_UINT256);
|
||||
});
|
||||
|
||||
it('sets allowance for "from" token on subsequent calls', async () => {
|
||||
const { opts } = await transferFromAsync();
|
||||
const { logs } = await transferFromAsync(opts);
|
||||
const approvals = filterLogsToArguments<TokenApproveArgs>(logs, ContractEvents.TokenApprove);
|
||||
const routerAddress = await testContract.getRouterAddress().callAsync();
|
||||
expect(approvals.length).to.eq(1);
|
||||
expect(approvals[0].spender).to.eq(routerAddress);
|
||||
expect(approvals[0].allowance).to.bignumber.eq(constants.MAX_UINT256);
|
||||
});
|
||||
|
||||
it('fails if the router fails', async () => {
|
||||
const revertReason = 'FOOBAR';
|
||||
const tx = transferFromAsync({
|
||||
routerRevertReason: revertReason,
|
||||
});
|
||||
return expect(tx).to.eventually.be.rejectedWith(revertReason);
|
||||
});
|
||||
});
|
||||
describe('token -> token -> token', async () => {
|
||||
it('calls UniswapV2Router01.swapExactTokensForTokens()', async () => {
|
||||
const { opts, result, logs, blocktime } = await transferFromAsync({
|
||||
tokenAddressesPath: Array(3).fill(constants.NULL_ADDRESS),
|
||||
});
|
||||
expect(result).to.eq(AssetProxyId.ERC20Bridge, 'asset proxy id');
|
||||
const transfers = filterLogsToArguments<SwapExactTokensForTokensArgs>(
|
||||
logs,
|
||||
ContractEvents.SwapExactTokensForTokensInput,
|
||||
);
|
||||
|
||||
expect(transfers.length).to.eq(1);
|
||||
expect(transfers[0].toTokenAddress).to.eq(
|
||||
opts.tokenAddressesPath[opts.tokenAddressesPath.length - 1],
|
||||
'output token address',
|
||||
);
|
||||
expect(transfers[0].to).to.eq(opts.toAddress, 'recipient address');
|
||||
expect(transfers[0].amountIn).to.bignumber.eq(opts.fromTokenBalance, 'input token amount');
|
||||
expect(transfers[0].amountOutMin).to.bignumber.eq(opts.amount, 'output token amount');
|
||||
expect(transfers[0].deadline).to.bignumber.eq(blocktime, 'deadline');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
@@ -3,8 +3,13 @@
|
||||
* Warning: This file is auto-generated by contracts-gen. Don't edit manually.
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
export * from '../test/generated-wrappers/balancer_bridge';
|
||||
export * from '../test/generated-wrappers/bancor_bridge';
|
||||
export * from '../test/generated-wrappers/chai_bridge';
|
||||
export * from '../test/generated-wrappers/cream_bridge';
|
||||
export * from '../test/generated-wrappers/curve_bridge';
|
||||
export * from '../test/generated-wrappers/d_o_d_o_bridge';
|
||||
export * from '../test/generated-wrappers/dex_forwarder_bridge';
|
||||
export * from '../test/generated-wrappers/dydx_bridge';
|
||||
export * from '../test/generated-wrappers/erc1155_proxy';
|
||||
export * from '../test/generated-wrappers/erc20_bridge_proxy';
|
||||
@@ -15,26 +20,42 @@ export * from '../test/generated-wrappers/i_asset_data';
|
||||
export * from '../test/generated-wrappers/i_asset_proxy';
|
||||
export * from '../test/generated-wrappers/i_asset_proxy_dispatcher';
|
||||
export * from '../test/generated-wrappers/i_authorizable';
|
||||
export * from '../test/generated-wrappers/i_balancer_pool';
|
||||
export * from '../test/generated-wrappers/i_bancor_network';
|
||||
export * from '../test/generated-wrappers/i_chai';
|
||||
export * from '../test/generated-wrappers/i_curve';
|
||||
export * from '../test/generated-wrappers/i_dydx';
|
||||
export * from '../test/generated-wrappers/i_dydx_bridge';
|
||||
export * from '../test/generated-wrappers/i_erc20_bridge';
|
||||
export * from '../test/generated-wrappers/i_eth2_dai';
|
||||
export * from '../test/generated-wrappers/i_gas_token';
|
||||
export * from '../test/generated-wrappers/i_kyber_network_proxy';
|
||||
export * from '../test/generated-wrappers/i_m_stable';
|
||||
export * from '../test/generated-wrappers/i_mooniswap';
|
||||
export * from '../test/generated-wrappers/i_shell';
|
||||
export * from '../test/generated-wrappers/i_uniswap_exchange';
|
||||
export * from '../test/generated-wrappers/i_uniswap_exchange_factory';
|
||||
export * from '../test/generated-wrappers/i_uniswap_v2_router01';
|
||||
export * from '../test/generated-wrappers/kyber_bridge';
|
||||
export * from '../test/generated-wrappers/m_stable_bridge';
|
||||
export * from '../test/generated-wrappers/mixin_asset_proxy_dispatcher';
|
||||
export * from '../test/generated-wrappers/mixin_authorizable';
|
||||
export * from '../test/generated-wrappers/mixin_gas_token';
|
||||
export * from '../test/generated-wrappers/mooniswap_bridge';
|
||||
export * from '../test/generated-wrappers/multi_asset_proxy';
|
||||
export * from '../test/generated-wrappers/ownable';
|
||||
export * from '../test/generated-wrappers/shell_bridge';
|
||||
export * from '../test/generated-wrappers/static_call_proxy';
|
||||
export * from '../test/generated-wrappers/sushi_swap_bridge';
|
||||
export * from '../test/generated-wrappers/test_bancor_bridge';
|
||||
export * from '../test/generated-wrappers/test_chai_bridge';
|
||||
export * from '../test/generated-wrappers/test_dex_forwarder_bridge';
|
||||
export * from '../test/generated-wrappers/test_dydx_bridge';
|
||||
export * from '../test/generated-wrappers/test_erc20_bridge';
|
||||
export * from '../test/generated-wrappers/test_eth2_dai_bridge';
|
||||
export * from '../test/generated-wrappers/test_kyber_bridge';
|
||||
export * from '../test/generated-wrappers/test_static_call_target';
|
||||
export * from '../test/generated-wrappers/test_uniswap_bridge';
|
||||
export * from '../test/generated-wrappers/test_uniswap_v2_bridge';
|
||||
export * from '../test/generated-wrappers/uniswap_bridge';
|
||||
export * from '../test/generated-wrappers/uniswap_v2_bridge';
|
||||
|
@@ -3,8 +3,13 @@
|
||||
"compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true },
|
||||
"include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
|
||||
"files": [
|
||||
"generated-artifacts/BalancerBridge.json",
|
||||
"generated-artifacts/BancorBridge.json",
|
||||
"generated-artifacts/ChaiBridge.json",
|
||||
"generated-artifacts/CreamBridge.json",
|
||||
"generated-artifacts/CurveBridge.json",
|
||||
"generated-artifacts/DODOBridge.json",
|
||||
"generated-artifacts/DexForwarderBridge.json",
|
||||
"generated-artifacts/DydxBridge.json",
|
||||
"generated-artifacts/ERC1155Proxy.json",
|
||||
"generated-artifacts/ERC20BridgeProxy.json",
|
||||
@@ -15,31 +20,52 @@
|
||||
"generated-artifacts/IAssetProxy.json",
|
||||
"generated-artifacts/IAssetProxyDispatcher.json",
|
||||
"generated-artifacts/IAuthorizable.json",
|
||||
"generated-artifacts/IBalancerPool.json",
|
||||
"generated-artifacts/IBancorNetwork.json",
|
||||
"generated-artifacts/IChai.json",
|
||||
"generated-artifacts/ICurve.json",
|
||||
"generated-artifacts/IDydx.json",
|
||||
"generated-artifacts/IDydxBridge.json",
|
||||
"generated-artifacts/IERC20Bridge.json",
|
||||
"generated-artifacts/IEth2Dai.json",
|
||||
"generated-artifacts/IGasToken.json",
|
||||
"generated-artifacts/IKyberNetworkProxy.json",
|
||||
"generated-artifacts/IMStable.json",
|
||||
"generated-artifacts/IMooniswap.json",
|
||||
"generated-artifacts/IShell.json",
|
||||
"generated-artifacts/IUniswapExchange.json",
|
||||
"generated-artifacts/IUniswapExchangeFactory.json",
|
||||
"generated-artifacts/IUniswapV2Router01.json",
|
||||
"generated-artifacts/KyberBridge.json",
|
||||
"generated-artifacts/MStableBridge.json",
|
||||
"generated-artifacts/MixinAssetProxyDispatcher.json",
|
||||
"generated-artifacts/MixinAuthorizable.json",
|
||||
"generated-artifacts/MixinGasToken.json",
|
||||
"generated-artifacts/MooniswapBridge.json",
|
||||
"generated-artifacts/MultiAssetProxy.json",
|
||||
"generated-artifacts/Ownable.json",
|
||||
"generated-artifacts/ShellBridge.json",
|
||||
"generated-artifacts/StaticCallProxy.json",
|
||||
"generated-artifacts/SushiSwapBridge.json",
|
||||
"generated-artifacts/TestBancorBridge.json",
|
||||
"generated-artifacts/TestChaiBridge.json",
|
||||
"generated-artifacts/TestDexForwarderBridge.json",
|
||||
"generated-artifacts/TestDydxBridge.json",
|
||||
"generated-artifacts/TestERC20Bridge.json",
|
||||
"generated-artifacts/TestEth2DaiBridge.json",
|
||||
"generated-artifacts/TestKyberBridge.json",
|
||||
"generated-artifacts/TestStaticCallTarget.json",
|
||||
"generated-artifacts/TestUniswapBridge.json",
|
||||
"generated-artifacts/TestUniswapV2Bridge.json",
|
||||
"generated-artifacts/UniswapBridge.json",
|
||||
"generated-artifacts/UniswapV2Bridge.json",
|
||||
"test/generated-artifacts/BalancerBridge.json",
|
||||
"test/generated-artifacts/BancorBridge.json",
|
||||
"test/generated-artifacts/ChaiBridge.json",
|
||||
"test/generated-artifacts/CreamBridge.json",
|
||||
"test/generated-artifacts/CurveBridge.json",
|
||||
"test/generated-artifacts/DODOBridge.json",
|
||||
"test/generated-artifacts/DexForwarderBridge.json",
|
||||
"test/generated-artifacts/DydxBridge.json",
|
||||
"test/generated-artifacts/ERC1155Proxy.json",
|
||||
"test/generated-artifacts/ERC20BridgeProxy.json",
|
||||
@@ -50,29 +76,45 @@
|
||||
"test/generated-artifacts/IAssetProxy.json",
|
||||
"test/generated-artifacts/IAssetProxyDispatcher.json",
|
||||
"test/generated-artifacts/IAuthorizable.json",
|
||||
"test/generated-artifacts/IBalancerPool.json",
|
||||
"test/generated-artifacts/IBancorNetwork.json",
|
||||
"test/generated-artifacts/IChai.json",
|
||||
"test/generated-artifacts/ICurve.json",
|
||||
"test/generated-artifacts/IDydx.json",
|
||||
"test/generated-artifacts/IDydxBridge.json",
|
||||
"test/generated-artifacts/IERC20Bridge.json",
|
||||
"test/generated-artifacts/IEth2Dai.json",
|
||||
"test/generated-artifacts/IGasToken.json",
|
||||
"test/generated-artifacts/IKyberNetworkProxy.json",
|
||||
"test/generated-artifacts/IMStable.json",
|
||||
"test/generated-artifacts/IMooniswap.json",
|
||||
"test/generated-artifacts/IShell.json",
|
||||
"test/generated-artifacts/IUniswapExchange.json",
|
||||
"test/generated-artifacts/IUniswapExchangeFactory.json",
|
||||
"test/generated-artifacts/IUniswapV2Router01.json",
|
||||
"test/generated-artifacts/KyberBridge.json",
|
||||
"test/generated-artifacts/MStableBridge.json",
|
||||
"test/generated-artifacts/MixinAssetProxyDispatcher.json",
|
||||
"test/generated-artifacts/MixinAuthorizable.json",
|
||||
"test/generated-artifacts/MixinGasToken.json",
|
||||
"test/generated-artifacts/MooniswapBridge.json",
|
||||
"test/generated-artifacts/MultiAssetProxy.json",
|
||||
"test/generated-artifacts/Ownable.json",
|
||||
"test/generated-artifacts/ShellBridge.json",
|
||||
"test/generated-artifacts/StaticCallProxy.json",
|
||||
"test/generated-artifacts/SushiSwapBridge.json",
|
||||
"test/generated-artifacts/TestBancorBridge.json",
|
||||
"test/generated-artifacts/TestChaiBridge.json",
|
||||
"test/generated-artifacts/TestDexForwarderBridge.json",
|
||||
"test/generated-artifacts/TestDydxBridge.json",
|
||||
"test/generated-artifacts/TestERC20Bridge.json",
|
||||
"test/generated-artifacts/TestEth2DaiBridge.json",
|
||||
"test/generated-artifacts/TestKyberBridge.json",
|
||||
"test/generated-artifacts/TestStaticCallTarget.json",
|
||||
"test/generated-artifacts/TestUniswapBridge.json",
|
||||
"test/generated-artifacts/UniswapBridge.json"
|
||||
"test/generated-artifacts/TestUniswapV2Bridge.json",
|
||||
"test/generated-artifacts/UniswapBridge.json",
|
||||
"test/generated-artifacts/UniswapV2Bridge.json"
|
||||
],
|
||||
"exclude": ["./deploy/solc/solc_bin"]
|
||||
}
|
||||
|
@@ -1,4 +1,32 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1603265572,
|
||||
"version": "1.1.7",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1594788383,
|
||||
"version": "1.1.6",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "1.1.5",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Fix broken tests.",
|
||||
"pr": 2591
|
||||
}
|
||||
],
|
||||
"timestamp": 1592969527
|
||||
},
|
||||
{
|
||||
"timestamp": 1583220306,
|
||||
"version": "1.1.4",
|
||||
|
@@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v1.1.7 - _October 21, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.1.6 - _July 15, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.1.5 - _June 24, 2020_
|
||||
|
||||
* Fix broken tests. (#2591)
|
||||
|
||||
## v1.1.4 - _March 3, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-broker",
|
||||
"version": "1.1.4",
|
||||
"version": "1.1.7",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -43,31 +43,31 @@
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/0xProject/0x-monorepo.git"
|
||||
"url": "https://github.com/0xProject/protocol.git"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/0xProject/0x-monorepo/issues"
|
||||
"url": "https://github.com/0xProject/protocol/issues"
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md",
|
||||
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/extensions",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.2.2",
|
||||
"@0x/contracts-asset-proxy": "^3.2.5",
|
||||
"@0x/contracts-erc20": "^3.1.5",
|
||||
"@0x/contracts-erc721": "^3.1.5",
|
||||
"@0x/contracts-exchange": "^3.2.5",
|
||||
"@0x/contracts-exchange-libs": "^4.3.5",
|
||||
"@0x/contracts-gen": "^2.0.8",
|
||||
"@0x/contracts-test-utils": "^5.3.2",
|
||||
"@0x/contracts-utils": "^4.4.3",
|
||||
"@0x/sol-compiler": "^4.0.8",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
"@0x/types": "^3.1.2",
|
||||
"@0x/web3-wrapper": "^7.0.7",
|
||||
"@0x/abi-gen": "^5.4.3",
|
||||
"@0x/contracts-asset-proxy": "^3.5.0",
|
||||
"@0x/contracts-erc20": "^3.2.2",
|
||||
"@0x/contracts-erc721": "^3.1.8",
|
||||
"@0x/contracts-exchange": "^3.2.8",
|
||||
"@0x/contracts-exchange-libs": "^4.3.8",
|
||||
"@0x/contracts-gen": "2.0.13",
|
||||
"@0x/contracts-test-utils": "^5.3.5",
|
||||
"@0x/contracts-utils": "^4.5.2",
|
||||
"@0x/sol-compiler": "^4.2.3",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
"@0x/tslint-config": "^4.1.3",
|
||||
"@0x/types": "^3.2.4",
|
||||
"@0x/web3-wrapper": "^7.2.4",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "*",
|
||||
"@types/node": "12.12.54",
|
||||
"chai": "^4.0.1",
|
||||
"chai-as-promised": "^7.1.0",
|
||||
"chai-bignumber": "^3.0.0",
|
||||
@@ -80,17 +80,18 @@
|
||||
"solhint": "^1.4.1",
|
||||
"truffle": "^5.0.32",
|
||||
"tslint": "5.11.0",
|
||||
"typedoc": "^0.15.0",
|
||||
"typedoc": "~0.16.11",
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.2.1",
|
||||
"@0x/order-utils": "^10.2.4",
|
||||
"@0x/typescript-typings": "^5.0.2",
|
||||
"@0x/utils": "^5.4.1",
|
||||
"ethereum-types": "^3.1.0"
|
||||
"@0x/base-contract": "^6.2.7",
|
||||
"@0x/order-utils": "^10.4.0",
|
||||
"@0x/typescript-typings": "^5.1.5",
|
||||
"@0x/utils": "^5.6.3",
|
||||
"ethereum-types": "^3.3.3"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
},
|
||||
"gitHead": "4f91bfd907996b2f4dd383778b50c479c2602b56"
|
||||
}
|
||||
|
@@ -44,13 +44,13 @@ blockchainTests.resets('GodsUnchainedValidator unit tests', env => {
|
||||
const tokenId = getRandomInteger(0, constants.MAX_UINT256);
|
||||
await godsUnchained.setTokenProperties(tokenId, proto.plus(1), quality).awaitTransactionSuccessAsync();
|
||||
const tx = validator.checkBrokerAsset(tokenId, propertyData).callAsync();
|
||||
expect(tx).to.revertWith('PROTO_MISMATCH');
|
||||
expect(tx).to.revertWith('GodsUnchainedValidator/PROTO_MISMATCH');
|
||||
});
|
||||
it("reverts if assetData quality doesn't match proeprtyData", async () => {
|
||||
const tokenId = getRandomInteger(0, constants.MAX_UINT256);
|
||||
await godsUnchained.setTokenProperties(tokenId, proto, quality.plus(1)).awaitTransactionSuccessAsync();
|
||||
const tx = validator.checkBrokerAsset(tokenId, propertyData).callAsync();
|
||||
expect(tx).to.revertWith('QUALITY_MISMATCH');
|
||||
expect(tx).to.revertWith('GodsUnchainedValidator/QUALITY_MISMATCH');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -1,4 +1,31 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1603265572,
|
||||
"version": "3.1.8",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1594788383,
|
||||
"version": "3.1.7",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1592969527,
|
||||
"version": "3.1.6",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1583220306,
|
||||
"version": "3.1.5",
|
||||
|
@@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v3.1.8 - _October 21, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.1.7 - _July 15, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.1.6 - _June 24, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.1.5 - _March 3, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-coordinator",
|
||||
"version": "3.1.5",
|
||||
"version": "3.1.8",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -44,30 +44,28 @@
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/0xProject/0x-monorepo.git"
|
||||
"url": "https://github.com/0xProject/protocol.git"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/0xProject/0x-monorepo/issues"
|
||||
"url": "https://github.com/0xProject/protocol/issues"
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md",
|
||||
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/extensions",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.2.2",
|
||||
"@0x/contracts-asset-proxy": "^3.2.5",
|
||||
"@0x/contracts-dev-utils": "^1.3.3",
|
||||
"@0x/contracts-erc20": "^3.1.5",
|
||||
"@0x/contracts-exchange": "^3.2.5",
|
||||
"@0x/contracts-gen": "^2.0.8",
|
||||
"@0x/contracts-test-utils": "^5.3.2",
|
||||
"@0x/dev-utils": "^3.2.1",
|
||||
"@0x/order-utils": "^10.2.4",
|
||||
"@0x/sol-compiler": "^4.0.8",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
"@0x/web3-wrapper": "^7.0.7",
|
||||
"@0x/abi-gen": "^5.4.3",
|
||||
"@0x/contracts-asset-proxy": "^3.5.0",
|
||||
"@0x/contracts-dev-utils": "^1.3.6",
|
||||
"@0x/contracts-erc20": "^3.2.2",
|
||||
"@0x/contracts-gen": "2.0.13",
|
||||
"@0x/dev-utils": "^3.3.4",
|
||||
"@0x/order-utils": "^10.4.0",
|
||||
"@0x/sol-compiler": "^4.2.3",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
"@0x/tslint-config": "^4.1.3",
|
||||
"@0x/web3-wrapper": "^7.2.4",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "*",
|
||||
"@types/node": "12.12.54",
|
||||
"chai": "^4.0.1",
|
||||
"chai-as-promised": "^7.1.0",
|
||||
"chai-bignumber": "^3.0.0",
|
||||
@@ -80,22 +78,25 @@
|
||||
"solhint": "^1.4.1",
|
||||
"truffle": "^5.0.32",
|
||||
"tslint": "5.11.0",
|
||||
"typedoc": "^0.15.0",
|
||||
"typedoc": "~0.16.11",
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/assert": "^3.0.7",
|
||||
"@0x/base-contract": "^6.2.1",
|
||||
"@0x/contract-addresses": "^4.9.0",
|
||||
"@0x/contracts-utils": "^4.4.3",
|
||||
"@0x/json-schemas": "^5.0.7",
|
||||
"@0x/types": "^3.1.2",
|
||||
"@0x/typescript-typings": "^5.0.2",
|
||||
"@0x/utils": "^5.4.1",
|
||||
"ethereum-types": "^3.1.0",
|
||||
"@0x/assert": "^3.0.13",
|
||||
"@0x/base-contract": "^6.2.7",
|
||||
"@0x/contract-addresses": "^4.12.0",
|
||||
"@0x/contracts-exchange": "^3.2.8",
|
||||
"@0x/contracts-test-utils": "^5.3.5",
|
||||
"@0x/contracts-utils": "^4.5.2",
|
||||
"@0x/json-schemas": "^5.2.3",
|
||||
"@0x/types": "^3.2.4",
|
||||
"@0x/typescript-typings": "^5.1.5",
|
||||
"@0x/utils": "^5.6.3",
|
||||
"ethereum-types": "^3.3.3",
|
||||
"http-status-codes": "^1.3.2"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
},
|
||||
"gitHead": "4f91bfd907996b2f4dd383778b50c479c2602b56"
|
||||
}
|
||||
|
@@ -1,4 +1,31 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1603265572,
|
||||
"version": "1.3.6",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1594788383,
|
||||
"version": "1.3.5",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1592969527,
|
||||
"version": "1.3.4",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1583220306,
|
||||
"version": "1.3.3",
|
||||
|
@@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v1.3.6 - _October 21, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.3.5 - _July 15, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.3.4 - _June 24, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.3.3 - _March 3, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-dev-utils",
|
||||
"version": "1.3.3",
|
||||
"version": "1.3.6",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -33,40 +33,41 @@
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/0xProject/0x-monorepo.git"
|
||||
"url": "https://github.com/0xProject/protocol.git"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/0xProject/0x-monorepo/issues"
|
||||
"url": "https://github.com/0xProject/protocol/issues"
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/dev-utils/README.md",
|
||||
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/dev-utils",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.2.2",
|
||||
"@0x/assert": "^3.0.7",
|
||||
"@0x/contracts-asset-proxy": "^3.2.5",
|
||||
"@0x/contracts-erc20": "^3.1.5",
|
||||
"@0x/contracts-gen": "^2.0.8",
|
||||
"@0x/contracts-test-utils": "^5.3.2",
|
||||
"@0x/sol-compiler": "^4.0.8",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
"@0x/types": "^3.1.2",
|
||||
"@0x/utils": "^5.4.1",
|
||||
"@types/node": "*",
|
||||
"ethereum-types": "^3.1.0",
|
||||
"@0x/abi-gen": "^5.4.3",
|
||||
"@0x/assert": "^3.0.13",
|
||||
"@0x/contracts-asset-proxy": "^3.5.0",
|
||||
"@0x/contracts-erc20": "^3.2.2",
|
||||
"@0x/contracts-gen": "2.0.13",
|
||||
"@0x/contracts-test-utils": "^5.3.5",
|
||||
"@0x/sol-compiler": "^4.2.3",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
"@0x/tslint-config": "^4.1.3",
|
||||
"@0x/types": "^3.2.4",
|
||||
"@0x/utils": "^5.6.3",
|
||||
"ethereum-types": "^3.3.3",
|
||||
"ethers": "~4.0.4",
|
||||
"npm-run-all": "^4.1.2",
|
||||
"shx": "^0.2.2",
|
||||
"solhint": "^1.4.1",
|
||||
"truffle": "^5.0.32",
|
||||
"tslint": "5.11.0",
|
||||
"typedoc": "^0.15.0",
|
||||
"typedoc": "~0.16.11",
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.2.1"
|
||||
"@0x/base-contract": "^6.2.7",
|
||||
"@types/node": "12.12.54"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
},
|
||||
"gitHead": "4f91bfd907996b2f4dd383778b50c479c2602b56"
|
||||
}
|
||||
|
@@ -1,4 +1,31 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1603265572,
|
||||
"version": "2.1.8",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1594788383,
|
||||
"version": "2.1.7",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1592969527,
|
||||
"version": "2.1.6",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1583220306,
|
||||
"version": "2.1.5",
|
||||
|
@@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v2.1.8 - _October 21, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v2.1.7 - _July 15, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v2.1.6 - _June 24, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v2.1.5 - _March 3, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-erc1155",
|
||||
"version": "2.1.5",
|
||||
"version": "2.1.8",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -44,31 +44,31 @@
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/0xProject/0x-monorepo.git"
|
||||
"url": "https://github.com/0xProject/protocol.git"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/0xProject/0x-monorepo/issues"
|
||||
"url": "https://github.com/0xProject/protocol/issues"
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/tokens/README.md",
|
||||
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/tokens",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.2.2",
|
||||
"@0x/contracts-gen": "^2.0.8",
|
||||
"@0x/contracts-utils": "^4.4.3",
|
||||
"@0x/dev-utils": "^3.2.1",
|
||||
"@0x/sol-compiler": "^4.0.8",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
"@0x/types": "^3.1.2",
|
||||
"@0x/typescript-typings": "^5.0.2",
|
||||
"@0x/abi-gen": "^5.4.3",
|
||||
"@0x/contracts-gen": "2.0.13",
|
||||
"@0x/contracts-utils": "^4.5.2",
|
||||
"@0x/dev-utils": "^3.3.4",
|
||||
"@0x/sol-compiler": "^4.2.3",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
"@0x/tslint-config": "^4.1.3",
|
||||
"@0x/types": "^3.2.4",
|
||||
"@0x/typescript-typings": "^5.1.5",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "*",
|
||||
"@types/node": "12.12.54",
|
||||
"chai": "^4.0.1",
|
||||
"chai-as-promised": "^7.1.0",
|
||||
"chai-bignumber": "^3.0.0",
|
||||
"dirty-chai": "^2.0.1",
|
||||
"ethereum-types": "^3.1.0",
|
||||
"ethereum-types": "^3.3.3",
|
||||
"make-promises-safe": "^1.1.0",
|
||||
"mocha": "^6.2.0",
|
||||
"npm-run-all": "^4.1.2",
|
||||
@@ -76,17 +76,18 @@
|
||||
"solhint": "^1.4.1",
|
||||
"truffle": "^5.0.32",
|
||||
"tslint": "5.11.0",
|
||||
"typedoc": "^0.15.0",
|
||||
"typedoc": "~0.16.11",
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.2.1",
|
||||
"@0x/contracts-test-utils": "^5.3.2",
|
||||
"@0x/utils": "^5.4.1",
|
||||
"@0x/web3-wrapper": "^7.0.7",
|
||||
"@0x/base-contract": "^6.2.7",
|
||||
"@0x/contracts-test-utils": "^5.3.5",
|
||||
"@0x/utils": "^5.6.3",
|
||||
"@0x/web3-wrapper": "^7.2.4",
|
||||
"lodash": "^4.17.11"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
},
|
||||
"gitHead": "4f91bfd907996b2f4dd383778b50c479c2602b56"
|
||||
}
|
||||
|
@@ -1,157 +0,0 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1583220306,
|
||||
"version": "1.5.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "1.5.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Add generic liquidity provider sampling",
|
||||
"pr": 2487
|
||||
},
|
||||
{
|
||||
"note": "Use liquidity provider registry in sampler",
|
||||
"pr": 2499
|
||||
}
|
||||
],
|
||||
"timestamp": 1582837861
|
||||
},
|
||||
{
|
||||
"timestamp": 1582677073,
|
||||
"version": "1.4.2",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1582623685,
|
||||
"version": "1.4.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "1.4.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Added Curve contract sampling",
|
||||
"pr": 2483
|
||||
}
|
||||
],
|
||||
"timestamp": 1581748629
|
||||
},
|
||||
{
|
||||
"version": "1.3.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Catch reverts to `DevUtils` calls",
|
||||
"pr": 2476
|
||||
},
|
||||
{
|
||||
"note": "Remove wrapper functions and introduce `batchCall()`",
|
||||
"pr": 2477
|
||||
}
|
||||
],
|
||||
"timestamp": 1581204851
|
||||
},
|
||||
{
|
||||
"timestamp": 1580988106,
|
||||
"version": "1.2.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "1.2.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Make source IDs static on all networks, not inherited from `DeploymentConstants`.",
|
||||
"pr": 2459
|
||||
}
|
||||
],
|
||||
"timestamp": 1580811564
|
||||
},
|
||||
{
|
||||
"version": "1.1.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Add batch functions to query quotes",
|
||||
"pr": 2427
|
||||
},
|
||||
{
|
||||
"note": "Early exit if a DEX sample fails",
|
||||
"pr": 2427
|
||||
}
|
||||
],
|
||||
"timestamp": 1579682890
|
||||
},
|
||||
{
|
||||
"version": "1.0.3",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Add gas limits to external quote calls.",
|
||||
"pr": 2405
|
||||
}
|
||||
],
|
||||
"timestamp": 1578272714
|
||||
},
|
||||
{
|
||||
"version": "1.0.2",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Do not query empty/unsigned orders. Swallow revets on DEX quotes.",
|
||||
"pr": 2395
|
||||
}
|
||||
],
|
||||
"timestamp": 1576540892
|
||||
},
|
||||
{
|
||||
"timestamp": 1575931811,
|
||||
"version": "1.0.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "1.0.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Created package.",
|
||||
"pr": 2344
|
||||
}
|
||||
],
|
||||
"timestamp": 1575296764
|
||||
},
|
||||
{
|
||||
"version": "1.0.0-beta.2",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
],
|
||||
"timestamp": 1575290197
|
||||
},
|
||||
{
|
||||
"version": "1.0.0-beta.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Created package.",
|
||||
"pr": 2344
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
@@ -1,69 +0,0 @@
|
||||
<!--
|
||||
changelogUtils.file is auto-generated using the monorepo-scripts package. Don't edit directly.
|
||||
Edit the package's CHANGELOG.json file only.
|
||||
-->
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v1.5.1 - _March 3, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.5.0 - _February 27, 2020_
|
||||
|
||||
* Add generic liquidity provider sampling (#2487)
|
||||
* Use liquidity provider registry in sampler (#2499)
|
||||
|
||||
## v1.4.2 - _February 26, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.4.1 - _February 25, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.4.0 - _February 15, 2020_
|
||||
|
||||
* Added Curve contract sampling (#2483)
|
||||
|
||||
## v1.3.0 - _February 8, 2020_
|
||||
|
||||
* Catch reverts to `DevUtils` calls (#2476)
|
||||
* Remove wrapper functions and introduce `batchCall()` (#2477)
|
||||
|
||||
## v1.2.1 - _February 6, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.2.0 - _February 4, 2020_
|
||||
|
||||
* Make source IDs static on all networks, not inherited from `DeploymentConstants`. (#2459)
|
||||
|
||||
## v1.1.0 - _January 22, 2020_
|
||||
|
||||
* Add batch functions to query quotes (#2427)
|
||||
* Early exit if a DEX sample fails (#2427)
|
||||
|
||||
## v1.0.3 - _January 6, 2020_
|
||||
|
||||
* Add gas limits to external quote calls. (#2405)
|
||||
|
||||
## v1.0.2 - _December 17, 2019_
|
||||
|
||||
* Do not query empty/unsigned orders. Swallow revets on DEX quotes. (#2395)
|
||||
|
||||
## v1.0.1 - _December 9, 2019_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.0.0 - _December 2, 2019_
|
||||
|
||||
* Created package. (#2344)
|
||||
|
||||
## v1.0.0-beta.2 - _December 2, 2019_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.0.0-beta.1 - _Invalid date_
|
||||
|
||||
* Created package. (#2344)
|
@@ -1,635 +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-asset-proxy/contracts/src/interfaces/IUniswapExchangeFactory.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.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 "./IDevUtils.sol";
|
||||
import "./IERC20BridgeSampler.sol";
|
||||
import "./IEth2Dai.sol";
|
||||
import "./IKyberNetwork.sol";
|
||||
import "./IUniswapExchangeQuotes.sol";
|
||||
import "./ICurve.sol";
|
||||
import "./ILiquidityProvider.sol";
|
||||
import "./ILiquidityProviderRegistry.sol";
|
||||
|
||||
|
||||
contract ERC20BridgeSampler is
|
||||
IERC20BridgeSampler,
|
||||
DeploymentConstants
|
||||
{
|
||||
/// @dev Gas limit for DevUtils calls.
|
||||
uint256 constant internal DEV_UTILS_CALL_GAS = 500e3; // 500k
|
||||
/// @dev Gas limit for Kyber calls.
|
||||
uint256 constant internal KYBER_CALL_GAS = 1500e3; // 1.5m
|
||||
/// @dev Gas limit for Uniswap calls.
|
||||
uint256 constant internal UNISWAP_CALL_GAS = 150e3; // 150k
|
||||
/// @dev Base gas limit for Eth2Dai calls.
|
||||
uint256 constant internal ETH2DAI_CALL_GAS = 1000e3; // 1m
|
||||
/// @dev Base gas limit for Curve calls. Some Curves have multiple tokens
|
||||
/// So a reasonable ceil is 150k per token. Biggest Curve has 4 tokens.
|
||||
uint256 constant internal CURVE_CALL_GAS = 600e3; // 600k
|
||||
/// @dev Default gas limit for liquidity provider calls.
|
||||
uint256 constant internal DEFAULT_CALL_GAS = 200e3; // 200k
|
||||
|
||||
/// @dev Call multiple public functions on this contract in a single transaction.
|
||||
/// @param callDatas ABI-encoded call data for each function call.
|
||||
/// @return callResults ABI-encoded results data for each call.
|
||||
function batchCall(bytes[] calldata callDatas)
|
||||
external
|
||||
view
|
||||
returns (bytes[] memory callResults)
|
||||
{
|
||||
callResults = new bytes[](callDatas.length);
|
||||
for (uint256 i = 0; i != callDatas.length; ++i) {
|
||||
(bool didSucceed, bytes memory resultData) = address(this).staticcall(callDatas[i]);
|
||||
if (!didSucceed) {
|
||||
assembly { revert(add(resultData, 0x20), mload(resultData)) }
|
||||
}
|
||||
callResults[i] = resultData;
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Queries the fillable taker asset amounts of native orders.
|
||||
/// Effectively ignores orders that have empty signatures or
|
||||
/// maker/taker asset amounts (returning 0).
|
||||
/// @param orders Native orders to query.
|
||||
/// @param orderSignatures Signatures for each respective order in `orders`.
|
||||
/// @return orderFillableTakerAssetAmounts How much taker asset can be filled
|
||||
/// by each order in `orders`.
|
||||
function getOrderFillableTakerAssetAmounts(
|
||||
LibOrder.Order[] memory orders,
|
||||
bytes[] memory orderSignatures
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (uint256[] memory orderFillableTakerAssetAmounts)
|
||||
{
|
||||
orderFillableTakerAssetAmounts = new uint256[](orders.length);
|
||||
for (uint256 i = 0; i != orders.length; i++) {
|
||||
// Ignore orders with no signature or empty maker/taker amounts.
|
||||
if (orderSignatures[i].length == 0 ||
|
||||
orders[i].makerAssetAmount == 0 ||
|
||||
orders[i].takerAssetAmount == 0) {
|
||||
orderFillableTakerAssetAmounts[i] = 0;
|
||||
continue;
|
||||
}
|
||||
// solhint-disable indent
|
||||
(bool didSucceed, bytes memory resultData) =
|
||||
_getDevUtilsAddress()
|
||||
.staticcall
|
||||
.gas(DEV_UTILS_CALL_GAS)
|
||||
(abi.encodeWithSelector(
|
||||
IDevUtils(_getDevUtilsAddress()).getOrderRelevantState.selector,
|
||||
orders[i],
|
||||
orderSignatures[i]
|
||||
));
|
||||
// solhint-enable indent
|
||||
if (!didSucceed) {
|
||||
orderFillableTakerAssetAmounts[i] = 0;
|
||||
continue;
|
||||
}
|
||||
(
|
||||
LibOrder.OrderInfo memory orderInfo,
|
||||
uint256 fillableTakerAssetAmount,
|
||||
bool isValidSignature
|
||||
) = abi.decode(
|
||||
resultData,
|
||||
(LibOrder.OrderInfo, uint256, bool)
|
||||
);
|
||||
// The fillable amount is zero if the order is not fillable or if the
|
||||
// signature is invalid.
|
||||
if (orderInfo.orderStatus != LibOrder.OrderStatus.FILLABLE ||
|
||||
!isValidSignature) {
|
||||
orderFillableTakerAssetAmounts[i] = 0;
|
||||
} else {
|
||||
orderFillableTakerAssetAmounts[i] = fillableTakerAssetAmount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Queries the fillable taker asset amounts of native orders.
|
||||
/// Effectively ignores orders that have empty signatures or
|
||||
/// @param orders Native orders to query.
|
||||
/// @param orderSignatures Signatures for each respective order in `orders`.
|
||||
/// @return orderFillableMakerAssetAmounts How much maker asset can be filled
|
||||
/// by each order in `orders`.
|
||||
function getOrderFillableMakerAssetAmounts(
|
||||
LibOrder.Order[] memory orders,
|
||||
bytes[] memory orderSignatures
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (uint256[] memory orderFillableMakerAssetAmounts)
|
||||
{
|
||||
orderFillableMakerAssetAmounts = getOrderFillableTakerAssetAmounts(
|
||||
orders,
|
||||
orderSignatures
|
||||
);
|
||||
// `orderFillableMakerAssetAmounts` now holds taker asset amounts, so
|
||||
// convert them to maker asset amounts.
|
||||
for (uint256 i = 0; i < orders.length; ++i) {
|
||||
if (orderFillableMakerAssetAmounts[i] != 0) {
|
||||
orderFillableMakerAssetAmounts[i] = LibMath.getPartialAmountCeil(
|
||||
orderFillableMakerAssetAmounts[i],
|
||||
orders[i].takerAssetAmount,
|
||||
orders[i].makerAssetAmount
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Sample sell quotes from Kyber.
|
||||
/// @param takerToken Address of the taker token (what to sell).
|
||||
/// @param makerToken Address of the maker token (what to buy).
|
||||
/// @param takerTokenAmounts Taker token sell amount for each sample.
|
||||
/// @return makerTokenAmounts Maker amounts bought at each taker token
|
||||
/// amount.
|
||||
function sampleSellsFromKyberNetwork(
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (uint256[] memory makerTokenAmounts)
|
||||
{
|
||||
_assertValidPair(makerToken, takerToken);
|
||||
address _takerToken = takerToken == _getWethAddress() ? KYBER_ETH_ADDRESS : takerToken;
|
||||
address _makerToken = makerToken == _getWethAddress() ? KYBER_ETH_ADDRESS : makerToken;
|
||||
uint256 takerTokenDecimals = _getTokenDecimals(takerToken);
|
||||
uint256 makerTokenDecimals = _getTokenDecimals(makerToken);
|
||||
uint256 numSamples = takerTokenAmounts.length;
|
||||
makerTokenAmounts = new uint256[](numSamples);
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
(bool didSucceed, bytes memory resultData) =
|
||||
_getKyberNetworkProxyAddress().staticcall.gas(KYBER_CALL_GAS)(
|
||||
abi.encodeWithSelector(
|
||||
IKyberNetwork(0).getExpectedRate.selector,
|
||||
_takerToken,
|
||||
_makerToken,
|
||||
takerTokenAmounts[i]
|
||||
));
|
||||
uint256 rate = 0;
|
||||
if (didSucceed) {
|
||||
rate = abi.decode(resultData, (uint256));
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
makerTokenAmounts[i] =
|
||||
rate *
|
||||
takerTokenAmounts[i] *
|
||||
10 ** makerTokenDecimals /
|
||||
10 ** takerTokenDecimals /
|
||||
10 ** 18;
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Sample sell quotes from Eth2Dai/Oasis.
|
||||
/// @param takerToken Address of the taker token (what to sell).
|
||||
/// @param makerToken Address of the maker token (what to buy).
|
||||
/// @param takerTokenAmounts Taker token sell amount for each sample.
|
||||
/// @return makerTokenAmounts Maker amounts bought at each taker token
|
||||
/// amount.
|
||||
function sampleSellsFromEth2Dai(
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (uint256[] memory makerTokenAmounts)
|
||||
{
|
||||
_assertValidPair(makerToken, takerToken);
|
||||
uint256 numSamples = takerTokenAmounts.length;
|
||||
makerTokenAmounts = new uint256[](numSamples);
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
(bool didSucceed, bytes memory resultData) =
|
||||
_getEth2DaiAddress().staticcall.gas(ETH2DAI_CALL_GAS)(
|
||||
abi.encodeWithSelector(
|
||||
IEth2Dai(0).getBuyAmount.selector,
|
||||
makerToken,
|
||||
takerToken,
|
||||
takerTokenAmounts[i]
|
||||
));
|
||||
uint256 buyAmount = 0;
|
||||
if (didSucceed) {
|
||||
buyAmount = abi.decode(resultData, (uint256));
|
||||
} else{
|
||||
break;
|
||||
}
|
||||
makerTokenAmounts[i] = buyAmount;
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Sample buy quotes from Eth2Dai/Oasis.
|
||||
/// @param takerToken Address of the taker token (what to sell).
|
||||
/// @param makerToken Address of the maker token (what to buy).
|
||||
/// @param takerTokenAmounts Maker token sell amount for each sample.
|
||||
/// @return takerTokenAmounts Taker amounts sold at each maker token
|
||||
/// amount.
|
||||
function sampleBuysFromEth2Dai(
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (uint256[] memory takerTokenAmounts)
|
||||
{
|
||||
_assertValidPair(makerToken, takerToken);
|
||||
uint256 numSamples = makerTokenAmounts.length;
|
||||
takerTokenAmounts = new uint256[](numSamples);
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
(bool didSucceed, bytes memory resultData) =
|
||||
_getEth2DaiAddress().staticcall.gas(ETH2DAI_CALL_GAS)(
|
||||
abi.encodeWithSelector(
|
||||
IEth2Dai(0).getPayAmount.selector,
|
||||
takerToken,
|
||||
makerToken,
|
||||
makerTokenAmounts[i]
|
||||
));
|
||||
uint256 sellAmount = 0;
|
||||
if (didSucceed) {
|
||||
sellAmount = abi.decode(resultData, (uint256));
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
takerTokenAmounts[i] = sellAmount;
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Sample sell quotes from Uniswap.
|
||||
/// @param takerToken Address of the taker token (what to sell).
|
||||
/// @param makerToken Address of the maker token (what to buy).
|
||||
/// @param takerTokenAmounts Taker token sell amount for each sample.
|
||||
/// @return makerTokenAmounts Maker amounts bought at each taker token
|
||||
/// amount.
|
||||
function sampleSellsFromUniswap(
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (uint256[] memory makerTokenAmounts)
|
||||
{
|
||||
_assertValidPair(makerToken, takerToken);
|
||||
uint256 numSamples = takerTokenAmounts.length;
|
||||
makerTokenAmounts = new uint256[](numSamples);
|
||||
IUniswapExchangeQuotes takerTokenExchange = takerToken == _getWethAddress() ?
|
||||
IUniswapExchangeQuotes(0) : _getUniswapExchange(takerToken);
|
||||
IUniswapExchangeQuotes makerTokenExchange = makerToken == _getWethAddress() ?
|
||||
IUniswapExchangeQuotes(0) : _getUniswapExchange(makerToken);
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
bool didSucceed = true;
|
||||
if (makerToken == _getWethAddress()) {
|
||||
(makerTokenAmounts[i], didSucceed) = _callUniswapExchangePriceFunction(
|
||||
address(takerTokenExchange),
|
||||
takerTokenExchange.getTokenToEthInputPrice.selector,
|
||||
takerTokenAmounts[i]
|
||||
);
|
||||
} else if (takerToken == _getWethAddress()) {
|
||||
(makerTokenAmounts[i], didSucceed) = _callUniswapExchangePriceFunction(
|
||||
address(makerTokenExchange),
|
||||
makerTokenExchange.getEthToTokenInputPrice.selector,
|
||||
takerTokenAmounts[i]
|
||||
);
|
||||
} else {
|
||||
uint256 ethBought;
|
||||
(ethBought, didSucceed) = _callUniswapExchangePriceFunction(
|
||||
address(takerTokenExchange),
|
||||
takerTokenExchange.getTokenToEthInputPrice.selector,
|
||||
takerTokenAmounts[i]
|
||||
);
|
||||
if (ethBought != 0) {
|
||||
(makerTokenAmounts[i], didSucceed) = _callUniswapExchangePriceFunction(
|
||||
address(makerTokenExchange),
|
||||
makerTokenExchange.getEthToTokenInputPrice.selector,
|
||||
ethBought
|
||||
);
|
||||
} else {
|
||||
makerTokenAmounts[i] = 0;
|
||||
}
|
||||
}
|
||||
if (!didSucceed) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Sample buy quotes from Uniswap.
|
||||
/// @param takerToken Address of the taker token (what to sell).
|
||||
/// @param makerToken Address of the maker token (what to buy).
|
||||
/// @param makerTokenAmounts Maker token sell amount for each sample.
|
||||
/// @return takerTokenAmounts Taker amounts sold at each maker token
|
||||
/// amount.
|
||||
function sampleBuysFromUniswap(
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (uint256[] memory takerTokenAmounts)
|
||||
{
|
||||
_assertValidPair(makerToken, takerToken);
|
||||
uint256 numSamples = makerTokenAmounts.length;
|
||||
takerTokenAmounts = new uint256[](numSamples);
|
||||
IUniswapExchangeQuotes takerTokenExchange = takerToken == _getWethAddress() ?
|
||||
IUniswapExchangeQuotes(0) : _getUniswapExchange(takerToken);
|
||||
IUniswapExchangeQuotes makerTokenExchange = makerToken == _getWethAddress() ?
|
||||
IUniswapExchangeQuotes(0) : _getUniswapExchange(makerToken);
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
bool didSucceed = true;
|
||||
if (makerToken == _getWethAddress()) {
|
||||
(takerTokenAmounts[i], didSucceed) = _callUniswapExchangePriceFunction(
|
||||
address(takerTokenExchange),
|
||||
takerTokenExchange.getTokenToEthOutputPrice.selector,
|
||||
makerTokenAmounts[i]
|
||||
);
|
||||
} else if (takerToken == _getWethAddress()) {
|
||||
(takerTokenAmounts[i], didSucceed) = _callUniswapExchangePriceFunction(
|
||||
address(makerTokenExchange),
|
||||
makerTokenExchange.getEthToTokenOutputPrice.selector,
|
||||
makerTokenAmounts[i]
|
||||
);
|
||||
} else {
|
||||
uint256 ethSold;
|
||||
(ethSold, didSucceed) = _callUniswapExchangePriceFunction(
|
||||
address(makerTokenExchange),
|
||||
makerTokenExchange.getEthToTokenOutputPrice.selector,
|
||||
makerTokenAmounts[i]
|
||||
);
|
||||
if (ethSold != 0) {
|
||||
(takerTokenAmounts[i], didSucceed) = _callUniswapExchangePriceFunction(
|
||||
address(takerTokenExchange),
|
||||
takerTokenExchange.getTokenToEthOutputPrice.selector,
|
||||
ethSold
|
||||
);
|
||||
} else {
|
||||
takerTokenAmounts[i] = 0;
|
||||
}
|
||||
}
|
||||
if (!didSucceed) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Sample sell quotes from Curve.
|
||||
/// @param curveAddress Address of the Curve contract.
|
||||
/// @param fromTokenIdx Index of the taker token (what to sell).
|
||||
/// @param toTokenIdx Index of the maker token (what to buy).
|
||||
/// @param takerTokenAmounts Taker token sell amount for each sample.
|
||||
/// @return makerTokenAmounts Maker amounts bought at each taker token
|
||||
/// amount.
|
||||
function sampleSellsFromCurve(
|
||||
address curveAddress,
|
||||
int128 fromTokenIdx,
|
||||
int128 toTokenIdx,
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (uint256[] memory makerTokenAmounts)
|
||||
{
|
||||
uint256 numSamples = takerTokenAmounts.length;
|
||||
makerTokenAmounts = new uint256[](numSamples);
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
(bool didSucceed, bytes memory resultData) =
|
||||
curveAddress.staticcall.gas(CURVE_CALL_GAS)(
|
||||
abi.encodeWithSelector(
|
||||
ICurve(0).get_dy_underlying.selector,
|
||||
fromTokenIdx,
|
||||
toTokenIdx,
|
||||
takerTokenAmounts[i]
|
||||
));
|
||||
uint256 buyAmount = 0;
|
||||
if (didSucceed) {
|
||||
buyAmount = abi.decode(resultData, (uint256));
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
makerTokenAmounts[i] = buyAmount;
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Sample sell quotes from an arbitrary on-chain liquidity provider.
|
||||
/// @param registryAddress Address of the liquidity provider registry contract.
|
||||
/// @param takerToken Address of the taker token (what to sell).
|
||||
/// @param makerToken Address of the maker token (what to buy).
|
||||
/// @param takerTokenAmounts Taker token sell amount for each sample.
|
||||
/// @return makerTokenAmounts Maker amounts bought at each taker token
|
||||
/// amount.
|
||||
function sampleSellsFromLiquidityProviderRegistry(
|
||||
address registryAddress,
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (uint256[] memory makerTokenAmounts)
|
||||
{
|
||||
// Initialize array of maker token amounts.
|
||||
uint256 numSamples = takerTokenAmounts.length;
|
||||
makerTokenAmounts = new uint256[](numSamples);
|
||||
|
||||
// Query registry for provider address.
|
||||
address providerAddress = getLiquidityProviderFromRegistry(
|
||||
registryAddress,
|
||||
takerToken,
|
||||
makerToken
|
||||
);
|
||||
// If provider doesn't exist, return all zeros.
|
||||
if (providerAddress == address(0)) {
|
||||
return makerTokenAmounts;
|
||||
}
|
||||
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
(bool didSucceed, bytes memory resultData) =
|
||||
providerAddress.staticcall.gas(DEFAULT_CALL_GAS)(
|
||||
abi.encodeWithSelector(
|
||||
ILiquidityProvider(0).getSellQuote.selector,
|
||||
takerToken,
|
||||
makerToken,
|
||||
takerTokenAmounts[i]
|
||||
));
|
||||
uint256 buyAmount = 0;
|
||||
if (didSucceed) {
|
||||
buyAmount = abi.decode(resultData, (uint256));
|
||||
} else {
|
||||
// Exit early if the amount is too high for the liquidity provider to serve
|
||||
break;
|
||||
}
|
||||
makerTokenAmounts[i] = buyAmount;
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Sample buy quotes from an arbitrary on-chain liquidity provider.
|
||||
/// @param registryAddress Address of the liquidity provider registry contract.
|
||||
/// @param takerToken Address of the taker token (what to sell).
|
||||
/// @param makerToken Address of the maker token (what to buy).
|
||||
/// @param makerTokenAmounts Maker token buy amount for each sample.
|
||||
/// @return takerTokenAmounts Taker amounts sold at each maker token
|
||||
/// amount.
|
||||
function sampleBuysFromLiquidityProviderRegistry(
|
||||
address registryAddress,
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (uint256[] memory takerTokenAmounts)
|
||||
{
|
||||
// Initialize array of taker token amounts.
|
||||
uint256 numSamples = makerTokenAmounts.length;
|
||||
takerTokenAmounts = new uint256[](numSamples);
|
||||
|
||||
// Query registry for provider address.
|
||||
address providerAddress = getLiquidityProviderFromRegistry(
|
||||
registryAddress,
|
||||
takerToken,
|
||||
makerToken
|
||||
);
|
||||
// If provider doesn't exist, return all zeros.
|
||||
if (providerAddress == address(0)) {
|
||||
return takerTokenAmounts;
|
||||
}
|
||||
|
||||
// Otherwise, query liquidity provider for quotes.
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
(bool didSucceed, bytes memory resultData) =
|
||||
providerAddress.staticcall.gas(DEFAULT_CALL_GAS)(
|
||||
abi.encodeWithSelector(
|
||||
ILiquidityProvider(0).getBuyQuote.selector,
|
||||
takerToken,
|
||||
makerToken,
|
||||
makerTokenAmounts[i]
|
||||
));
|
||||
uint256 sellAmount = 0;
|
||||
if (didSucceed) {
|
||||
sellAmount = abi.decode(resultData, (uint256));
|
||||
} else {
|
||||
// Exit early if the amount is too high for the liquidity provider to serve
|
||||
break;
|
||||
}
|
||||
takerTokenAmounts[i] = sellAmount;
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Returns the address of a liquidity provider for the given market
|
||||
/// (takerToken, makerToken), from a registry of liquidity providers.
|
||||
/// Returns address(0) if no such provider exists in the registry.
|
||||
/// @param takerToken Taker asset managed by liquidity provider.
|
||||
/// @param makerToken Maker asset managed by liquidity provider.
|
||||
/// @return providerAddress Address of the liquidity provider.
|
||||
function getLiquidityProviderFromRegistry(
|
||||
address registryAddress,
|
||||
address takerToken,
|
||||
address makerToken
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (address providerAddress)
|
||||
{
|
||||
bytes memory callData = abi.encodeWithSelector(
|
||||
ILiquidityProviderRegistry(0).getLiquidityProviderForMarket.selector,
|
||||
takerToken,
|
||||
makerToken
|
||||
);
|
||||
(bool didSucceed, bytes memory returnData) = registryAddress.staticcall(callData);
|
||||
if (didSucceed && returnData.length == 32) {
|
||||
return LibBytes.readAddress(returnData, 12);
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Overridable way to get token decimals.
|
||||
/// @param tokenAddress Address of the token.
|
||||
/// @return decimals The decimal places for the token.
|
||||
function _getTokenDecimals(address tokenAddress)
|
||||
internal
|
||||
view
|
||||
returns (uint8 decimals)
|
||||
{
|
||||
return LibERC20Token.decimals(tokenAddress);
|
||||
}
|
||||
|
||||
/// @dev Gracefully calls a Uniswap pricing function.
|
||||
/// @param uniswapExchangeAddress Address of an `IUniswapExchangeQuotes` exchange.
|
||||
/// @param functionSelector Selector of the target function.
|
||||
/// @param inputAmount Quantity parameter particular to the pricing function.
|
||||
/// @return outputAmount The returned amount from the function call. Will be
|
||||
/// zero if the call fails or if `uniswapExchangeAddress` is zero.
|
||||
function _callUniswapExchangePriceFunction(
|
||||
address uniswapExchangeAddress,
|
||||
bytes4 functionSelector,
|
||||
uint256 inputAmount
|
||||
)
|
||||
private
|
||||
view
|
||||
returns (uint256 outputAmount, bool didSucceed)
|
||||
{
|
||||
if (uniswapExchangeAddress == address(0)) {
|
||||
return (outputAmount, didSucceed);
|
||||
}
|
||||
bytes memory resultData;
|
||||
(didSucceed, resultData) =
|
||||
uniswapExchangeAddress.staticcall.gas(UNISWAP_CALL_GAS)(
|
||||
abi.encodeWithSelector(
|
||||
functionSelector,
|
||||
inputAmount
|
||||
));
|
||||
if (didSucceed) {
|
||||
outputAmount = abi.decode(resultData, (uint256));
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Retrive an existing Uniswap exchange contract.
|
||||
/// Throws if the exchange does not exist.
|
||||
/// @param tokenAddress Address of the token contract.
|
||||
/// @return exchange `IUniswapExchangeQuotes` for the token.
|
||||
function _getUniswapExchange(address tokenAddress)
|
||||
private
|
||||
view
|
||||
returns (IUniswapExchangeQuotes exchange)
|
||||
{
|
||||
exchange = IUniswapExchangeQuotes(
|
||||
address(IUniswapExchangeFactory(_getUniswapExchangeFactoryAddress())
|
||||
.getExchange(tokenAddress))
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Assert that the tokens in a trade pair are valid.
|
||||
/// @param makerToken Address of the maker token.
|
||||
/// @param takerToken Address of the taker token.
|
||||
function _assertValidPair(address makerToken, address takerToken)
|
||||
private
|
||||
pure
|
||||
{
|
||||
require(makerToken != takerToken, "ERC20BridgeSampler/INVALID_TOKEN_PAIR");
|
||||
}
|
||||
}
|
@@ -1,45 +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-exchange-libs/contracts/src/LibOrder.sol";
|
||||
|
||||
|
||||
interface IDevUtils {
|
||||
|
||||
/// @dev Fetches all order-relevant information needed to validate if the supplied order is fillable.
|
||||
/// @param order The order structure.
|
||||
/// @param signature Signature provided by maker that proves the order's authenticity.
|
||||
/// `0x01` can always be provided if the signature does not need to be validated.
|
||||
/// @return The orderInfo (hash, status, and `takerAssetAmount` already filled for the given order),
|
||||
/// fillableTakerAssetAmount (amount of the order's `takerAssetAmount` that is fillable given all on-chain state),
|
||||
/// and isValidSignature (validity of the provided signature).
|
||||
/// NOTE: If the `takerAssetData` encodes data for multiple assets, `fillableTakerAssetAmount` will represent a "scaled"
|
||||
/// amount, meaning it must be multiplied by all the individual asset amounts within the `takerAssetData` to get the final
|
||||
/// amount of each asset that can be filled.
|
||||
function getOrderRelevantState(LibOrder.Order calldata order, bytes calldata signature)
|
||||
external
|
||||
view
|
||||
returns (
|
||||
LibOrder.OrderInfo memory orderInfo,
|
||||
uint256 fillableTakerAssetAmount,
|
||||
bool isValidSignature
|
||||
);
|
||||
}
|
@@ -1,201 +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-exchange-libs/contracts/src/LibOrder.sol";
|
||||
|
||||
|
||||
interface IERC20BridgeSampler {
|
||||
|
||||
/// @dev Call multiple public functions on this contract in a single transaction.
|
||||
/// @param callDatas ABI-encoded call data for each function call.
|
||||
/// @return callResults ABI-encoded results data for each call.
|
||||
function batchCall(bytes[] calldata callDatas)
|
||||
external
|
||||
view
|
||||
returns (bytes[] memory callResults);
|
||||
|
||||
/// @dev Queries the fillable taker asset amounts of native orders.
|
||||
/// @param orders Native orders to query.
|
||||
/// @param orderSignatures Signatures for each respective order in `orders`.
|
||||
/// @return orderFillableTakerAssetAmounts How much taker asset can be filled
|
||||
/// by each order in `orders`.
|
||||
function getOrderFillableTakerAssetAmounts(
|
||||
LibOrder.Order[] calldata orders,
|
||||
bytes[] calldata orderSignatures
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (uint256[] memory orderFillableTakerAssetAmounts);
|
||||
|
||||
/// @dev Queries the fillable maker asset amounts of native orders.
|
||||
/// @param orders Native orders to query.
|
||||
/// @param orderSignatures Signatures for each respective order in `orders`.
|
||||
/// @return orderFillableMakerAssetAmounts How much maker asset can be filled
|
||||
/// by each order in `orders`.
|
||||
function getOrderFillableMakerAssetAmounts(
|
||||
LibOrder.Order[] calldata orders,
|
||||
bytes[] calldata orderSignatures
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (uint256[] memory orderFillableMakerAssetAmounts);
|
||||
|
||||
/// @dev Sample sell quotes from Kyber.
|
||||
/// @param takerToken Address of the taker token (what to sell).
|
||||
/// @param makerToken Address of the maker token (what to buy).
|
||||
/// @param takerTokenAmounts Taker token sell amount for each sample.
|
||||
/// @return makerTokenAmounts Maker amounts bought at each taker token
|
||||
/// amount.
|
||||
function sampleSellsFromKyberNetwork(
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256[] calldata takerTokenAmounts
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (uint256[] memory makerTokenAmounts);
|
||||
|
||||
/// @dev Sample sell quotes from Eth2Dai/Oasis.
|
||||
/// @param takerToken Address of the taker token (what to sell).
|
||||
/// @param makerToken Address of the maker token (what to buy).
|
||||
/// @param takerTokenAmounts Taker token sell amount for each sample.
|
||||
/// @return makerTokenAmounts Maker amounts bought at each taker token
|
||||
/// amount.
|
||||
function sampleSellsFromEth2Dai(
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256[] calldata takerTokenAmounts
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (uint256[] memory makerTokenAmounts);
|
||||
|
||||
/// @dev Sample sell quotes from Uniswap.
|
||||
/// @param takerToken Address of the taker token (what to sell).
|
||||
/// @param makerToken Address of the maker token (what to buy).
|
||||
/// @param takerTokenAmounts Taker token sell amount for each sample.
|
||||
/// @return makerTokenAmounts Maker amounts bought at each taker token
|
||||
/// amount.
|
||||
function sampleSellsFromUniswap(
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256[] calldata takerTokenAmounts
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (uint256[] memory makerTokenAmounts);
|
||||
|
||||
/// @dev Sample buy quotes from Uniswap.
|
||||
/// @param takerToken Address of the taker token (what to sell).
|
||||
/// @param makerToken Address of the maker token (what to buy).
|
||||
/// @param makerTokenAmounts Maker token sell amount for each sample.
|
||||
/// @return takerTokenAmounts Taker amounts sold at each maker token
|
||||
/// amount.
|
||||
function sampleBuysFromUniswap(
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256[] calldata makerTokenAmounts
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (uint256[] memory takerTokenAmounts);
|
||||
|
||||
/// @dev Sample buy quotes from Eth2Dai/Oasis.
|
||||
/// @param takerToken Address of the taker token (what to sell).
|
||||
/// @param makerToken Address of the maker token (what to buy).
|
||||
/// @param takerTokenAmounts Maker token sell amount for each sample.
|
||||
/// @return takerTokenAmounts Taker amounts sold at each maker token
|
||||
/// amount.
|
||||
function sampleBuysFromEth2Dai(
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256[] calldata makerTokenAmounts
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (uint256[] memory takerTokenAmounts);
|
||||
|
||||
/// @dev Sample sell quotes from Curve.
|
||||
/// @param curveAddress Address of the Curve contract.
|
||||
/// @param fromTokenIdx Index of the taker token (what to sell).
|
||||
/// @param toTokenIdx Index of the maker token (what to buy).
|
||||
/// @param takerTokenAmounts Taker token sell amount for each sample.
|
||||
/// @return makerTokenAmounts Maker amounts bought at each taker token
|
||||
/// amount.
|
||||
function sampleSellsFromCurve(
|
||||
address curveAddress,
|
||||
int128 fromTokenIdx,
|
||||
int128 toTokenIdx,
|
||||
uint256[] calldata takerTokenAmounts
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (uint256[] memory makerTokenAmounts);
|
||||
|
||||
/// @dev Sample sell quotes from an arbitrary on-chain liquidity provider.
|
||||
/// @param registryAddress Address of the liquidity provider registry contract.
|
||||
/// @param takerToken Address of the taker token (what to sell).
|
||||
/// @param makerToken Address of the maker token (what to buy).
|
||||
/// @param takerTokenAmounts Taker token sell amount for each sample.
|
||||
/// @return makerTokenAmounts Maker amounts bought at each taker token
|
||||
/// amount.
|
||||
function sampleSellsFromLiquidityProviderRegistry(
|
||||
address registryAddress,
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256[] calldata takerTokenAmounts
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (uint256[] memory makerTokenAmounts);
|
||||
|
||||
/// @dev Sample buy quotes from an arbitrary on-chain liquidity provider.
|
||||
/// @param registryAddress Address of the liquidity provider registry contract.
|
||||
/// @param takerToken Address of the taker token (what to sell).
|
||||
/// @param makerToken Address of the maker token (what to buy).
|
||||
/// @param makerTokenAmounts Maker token buy amount for each sample.
|
||||
/// @return takerTokenAmounts Taker amounts sold at each maker token
|
||||
/// amount.
|
||||
function sampleBuysFromLiquidityProviderRegistry(
|
||||
address registryAddress,
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256[] calldata makerTokenAmounts
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (uint256[] memory takerTokenAmounts);
|
||||
|
||||
/// @dev Returns the address of a liquidity provider for the given market
|
||||
/// (takerToken, makerToken), from a registry of liquidity providers.
|
||||
/// Returns address(0) if no such provider exists in the registry.
|
||||
/// @param takerToken Taker asset managed by liquidity provider.
|
||||
/// @param makerToken Maker asset managed by liquidity provider.
|
||||
/// @return providerAddress Address of the liquidity provider.
|
||||
function getLiquidityProviderFromRegistry(
|
||||
address registryAddress,
|
||||
address takerToken,
|
||||
address makerToken
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (address providerAddress);
|
||||
}
|
@@ -1,92 +0,0 @@
|
||||
{
|
||||
"name": "@0x/contracts-erc20-bridge-sampler",
|
||||
"version": "1.5.1",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
"description": "Sampler contracts for the 0x asset-swapper",
|
||||
"main": "lib/src/index.js",
|
||||
"directories": {
|
||||
"test": "test"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "yarn pre_build && tsc -b",
|
||||
"build:ci": "yarn build",
|
||||
"pre_build": "run-s compile contracts:gen generate_contract_wrappers contracts:copy",
|
||||
"test": "yarn run_mocha",
|
||||
"rebuild_and_test": "run-s build test",
|
||||
"test:coverage": "SOLIDITY_COVERAGE=true run-s build run_mocha coverage:report:text coverage:report:lcov",
|
||||
"test:profiler": "SOLIDITY_PROFILER=true run-s build run_mocha profiler:report:html",
|
||||
"test:trace": "SOLIDITY_REVERT_TRACE=true run-s build run_mocha",
|
||||
"run_mocha": "mocha --require source-map-support/register --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit",
|
||||
"compile": "sol-compiler",
|
||||
"watch": "sol-compiler -w",
|
||||
"clean": "shx rm -rf lib test/generated-artifacts test/generated-wrappers generated-artifacts generated-wrappers",
|
||||
"generate_contract_wrappers": "abi-gen --debug --abis ${npm_package_config_abis} --output test/generated-wrappers --backend ethers",
|
||||
"lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./test/generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
|
||||
"fix": "tslint --fix --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/generated-wrappers/**/* --exclude ./test/generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
|
||||
"coverage:report:text": "istanbul report text",
|
||||
"coverage:report:html": "istanbul report html && open coverage/index.html",
|
||||
"profiler:report:html": "istanbul report html && open coverage/index.html",
|
||||
"coverage:report:lcov": "istanbul report lcov",
|
||||
"test:circleci": "yarn test",
|
||||
"contracts:gen": "contracts-gen generate",
|
||||
"contracts:copy": "contracts-gen copy",
|
||||
"lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol",
|
||||
"compile:truffle": "truffle compile"
|
||||
},
|
||||
"config": {
|
||||
"publicInterfaceContracts": "ERC20BridgeSampler,IERC20BridgeSampler,ILiquidityProvider,ILiquidityProviderRegistry",
|
||||
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
|
||||
"abis": "./test/generated-artifacts/@(ERC20BridgeSampler|ICurve|IDevUtils|IERC20BridgeSampler|IEth2Dai|IKyberNetwork|ILiquidityProvider|ILiquidityProviderRegistry|IUniswapExchangeQuotes|TestERC20BridgeSampler).json"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/0xProject/0x-monorepo.git"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/0xProject/0x-monorepo/issues"
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/protocol/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.2.2",
|
||||
"@0x/contracts-asset-proxy": "^3.2.5",
|
||||
"@0x/contracts-erc20": "^3.1.5",
|
||||
"@0x/contracts-exchange": "^3.2.5",
|
||||
"@0x/contracts-exchange-libs": "^4.3.5",
|
||||
"@0x/contracts-gen": "^2.0.8",
|
||||
"@0x/contracts-test-utils": "^5.3.2",
|
||||
"@0x/contracts-utils": "^4.4.3",
|
||||
"@0x/dev-utils": "^3.2.1",
|
||||
"@0x/sol-compiler": "^4.0.8",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
"@0x/web3-wrapper": "^7.0.7",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "*",
|
||||
"chai": "^4.0.1",
|
||||
"chai-as-promised": "^7.1.0",
|
||||
"chai-bignumber": "^3.0.0",
|
||||
"dirty-chai": "^2.0.1",
|
||||
"make-promises-safe": "^1.1.0",
|
||||
"mocha": "^6.2.0",
|
||||
"npm-run-all": "^4.1.2",
|
||||
"shx": "^0.2.2",
|
||||
"solhint": "^1.4.1",
|
||||
"truffle": "^5.0.32",
|
||||
"tslint": "5.11.0",
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.2.1",
|
||||
"@0x/types": "^3.1.2",
|
||||
"@0x/typescript-typings": "^5.0.2",
|
||||
"@0x/utils": "^5.4.1",
|
||||
"ethereum-types": "^3.1.0",
|
||||
"lodash": "^4.17.11"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
}
|
@@ -1,2 +0,0 @@
|
||||
export * from './wrappers';
|
||||
export * from './artifacts';
|
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
* -----------------------------------------------------------------------------
|
||||
* Warning: This file is auto-generated by contracts-gen. Don't edit manually.
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
import { ContractArtifact } from 'ethereum-types';
|
||||
|
||||
import * as ERC20BridgeSampler from '../test/generated-artifacts/ERC20BridgeSampler.json';
|
||||
import * as ICurve from '../test/generated-artifacts/ICurve.json';
|
||||
import * as IDevUtils from '../test/generated-artifacts/IDevUtils.json';
|
||||
import * as IERC20BridgeSampler from '../test/generated-artifacts/IERC20BridgeSampler.json';
|
||||
import * as IEth2Dai from '../test/generated-artifacts/IEth2Dai.json';
|
||||
import * as IKyberNetwork from '../test/generated-artifacts/IKyberNetwork.json';
|
||||
import * as ILiquidityProvider from '../test/generated-artifacts/ILiquidityProvider.json';
|
||||
import * as ILiquidityProviderRegistry from '../test/generated-artifacts/ILiquidityProviderRegistry.json';
|
||||
import * as IUniswapExchangeQuotes from '../test/generated-artifacts/IUniswapExchangeQuotes.json';
|
||||
import * as TestERC20BridgeSampler from '../test/generated-artifacts/TestERC20BridgeSampler.json';
|
||||
export const artifacts = {
|
||||
ERC20BridgeSampler: ERC20BridgeSampler as ContractArtifact,
|
||||
ICurve: ICurve as ContractArtifact,
|
||||
IDevUtils: IDevUtils as ContractArtifact,
|
||||
IERC20BridgeSampler: IERC20BridgeSampler as ContractArtifact,
|
||||
IEth2Dai: IEth2Dai as ContractArtifact,
|
||||
IKyberNetwork: IKyberNetwork as ContractArtifact,
|
||||
ILiquidityProvider: ILiquidityProvider as ContractArtifact,
|
||||
ILiquidityProviderRegistry: ILiquidityProviderRegistry as ContractArtifact,
|
||||
IUniswapExchangeQuotes: IUniswapExchangeQuotes as ContractArtifact,
|
||||
TestERC20BridgeSampler: TestERC20BridgeSampler as ContractArtifact,
|
||||
};
|
@@ -1,15 +0,0 @@
|
||||
/*
|
||||
* -----------------------------------------------------------------------------
|
||||
* Warning: This file is auto-generated by contracts-gen. Don't edit manually.
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
export * from '../test/generated-wrappers/erc20_bridge_sampler';
|
||||
export * from '../test/generated-wrappers/i_curve';
|
||||
export * from '../test/generated-wrappers/i_dev_utils';
|
||||
export * from '../test/generated-wrappers/i_erc20_bridge_sampler';
|
||||
export * from '../test/generated-wrappers/i_eth2_dai';
|
||||
export * from '../test/generated-wrappers/i_kyber_network';
|
||||
export * from '../test/generated-wrappers/i_liquidity_provider';
|
||||
export * from '../test/generated-wrappers/i_liquidity_provider_registry';
|
||||
export * from '../test/generated-wrappers/i_uniswap_exchange_quotes';
|
||||
export * from '../test/generated-wrappers/test_erc20_bridge_sampler';
|
@@ -1,22 +0,0 @@
|
||||
{
|
||||
"extends": "../../tsconfig",
|
||||
"compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true },
|
||||
"include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
|
||||
"files": [
|
||||
"generated-artifacts/ERC20BridgeSampler.json",
|
||||
"generated-artifacts/IERC20BridgeSampler.json",
|
||||
"generated-artifacts/ILiquidityProvider.json",
|
||||
"generated-artifacts/ILiquidityProviderRegistry.json",
|
||||
"test/generated-artifacts/ERC20BridgeSampler.json",
|
||||
"test/generated-artifacts/ICurve.json",
|
||||
"test/generated-artifacts/IDevUtils.json",
|
||||
"test/generated-artifacts/IERC20BridgeSampler.json",
|
||||
"test/generated-artifacts/IEth2Dai.json",
|
||||
"test/generated-artifacts/IKyberNetwork.json",
|
||||
"test/generated-artifacts/ILiquidityProvider.json",
|
||||
"test/generated-artifacts/ILiquidityProviderRegistry.json",
|
||||
"test/generated-artifacts/IUniswapExchangeQuotes.json",
|
||||
"test/generated-artifacts/TestERC20BridgeSampler.json"
|
||||
],
|
||||
"exclude": ["./deploy/solc/solc_bin"]
|
||||
}
|
@@ -1,4 +1,40 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1603265572,
|
||||
"version": "3.2.2",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1594788383,
|
||||
"version": "3.2.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "3.2.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Add `LibERC20Token.approveIfBelow()`",
|
||||
"pr": 2512
|
||||
},
|
||||
{
|
||||
"note": "Add solidity 0.6 contracts",
|
||||
"pr": 2545
|
||||
},
|
||||
{
|
||||
"note": "Update `LibERC20TokenV06` comments.",
|
||||
"pr": 2597
|
||||
}
|
||||
],
|
||||
"timestamp": 1592969527
|
||||
},
|
||||
{
|
||||
"timestamp": 1583220306,
|
||||
"version": "3.1.5",
|
||||
|
@@ -5,6 +5,20 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v3.2.2 - _October 21, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.2.1 - _July 15, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.2.0 - _June 24, 2020_
|
||||
|
||||
* Add `LibERC20Token.approveIfBelow()` (#2512)
|
||||
* Add solidity 0.6 contracts (#2545)
|
||||
* Update `LibERC20TokenV06` comments. (#2597)
|
||||
|
||||
## v3.1.5 - _March 3, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -47,6 +47,25 @@ library LibERC20Token {
|
||||
_callWithOptionalBooleanResult(token, callData);
|
||||
}
|
||||
|
||||
/// @dev Calls `IERC20Token(token).approve()` and sets the allowance to the
|
||||
/// maximum if the current approval is not already >= an amount.
|
||||
/// Reverts if `false` is returned or if the return
|
||||
/// data length is nonzero and not 32 bytes.
|
||||
/// @param token The address of the token contract.
|
||||
/// @param spender The address that receives an allowance.
|
||||
/// @param amount The minimum allowance needed.
|
||||
function approveIfBelow(
|
||||
address token,
|
||||
address spender,
|
||||
uint256 amount
|
||||
)
|
||||
internal
|
||||
{
|
||||
if (IERC20Token(token).allowance(address(this), spender) < amount) {
|
||||
approve(token, spender, uint256(-1));
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Calls `IERC20Token(token).transfer()`.
|
||||
/// Reverts if `false` is returned or if the return
|
||||
/// data length is nonzero and not 32 bytes.
|
||||
|
95
contracts/erc20/contracts/src/v06/IERC20TokenV06.sol
Normal file
95
contracts/erc20/contracts/src/v06/IERC20TokenV06.sol
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
|
||||
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.6.5;
|
||||
|
||||
|
||||
interface IERC20TokenV06 {
|
||||
|
||||
// solhint-disable no-simple-event-func-name
|
||||
event Transfer(
|
||||
address indexed from,
|
||||
address indexed to,
|
||||
uint256 value
|
||||
);
|
||||
|
||||
event Approval(
|
||||
address indexed owner,
|
||||
address indexed spender,
|
||||
uint256 value
|
||||
);
|
||||
|
||||
/// @dev send `value` token to `to` from `msg.sender`
|
||||
/// @param to The address of the recipient
|
||||
/// @param value The amount of token to be transferred
|
||||
/// @return True if transfer was successful
|
||||
function transfer(address to, uint256 value)
|
||||
external
|
||||
returns (bool);
|
||||
|
||||
/// @dev send `value` token to `to` from `from` on the condition it is approved by `from`
|
||||
/// @param from The address of the sender
|
||||
/// @param to The address of the recipient
|
||||
/// @param value The amount of token to be transferred
|
||||
/// @return True if transfer was successful
|
||||
function transferFrom(
|
||||
address from,
|
||||
address to,
|
||||
uint256 value
|
||||
)
|
||||
external
|
||||
returns (bool);
|
||||
|
||||
/// @dev `msg.sender` approves `spender` to spend `value` tokens
|
||||
/// @param spender The address of the account able to transfer the tokens
|
||||
/// @param value The amount of wei to be approved for transfer
|
||||
/// @return Always true if the call has enough gas to complete execution
|
||||
function approve(address spender, uint256 value)
|
||||
external
|
||||
returns (bool);
|
||||
|
||||
/// @dev Query total supply of token
|
||||
/// @return Total supply of token
|
||||
function totalSupply()
|
||||
external
|
||||
view
|
||||
returns (uint256);
|
||||
|
||||
/// @dev Get the balance of `owner`.
|
||||
/// @param owner The address from which the balance will be retrieved
|
||||
/// @return Balance of owner
|
||||
function balanceOf(address owner)
|
||||
external
|
||||
view
|
||||
returns (uint256);
|
||||
|
||||
/// @dev Get the allowance for `spender` to spend from `owner`.
|
||||
/// @param owner The address of the account owning tokens
|
||||
/// @param spender The address of the account able to transfer the tokens
|
||||
/// @return Amount of remaining tokens allowed to spent
|
||||
function allowance(address owner, address spender)
|
||||
external
|
||||
view
|
||||
returns (uint256);
|
||||
|
||||
/// @dev Get the number of decimals this token has.
|
||||
function decimals()
|
||||
external
|
||||
view
|
||||
returns (uint8);
|
||||
}
|
32
contracts/erc20/contracts/src/v06/IEtherTokenV06.sol
Normal file
32
contracts/erc20/contracts/src/v06/IEtherTokenV06.sol
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.6.5;
|
||||
|
||||
import "./IERC20TokenV06.sol";
|
||||
|
||||
|
||||
interface IEtherTokenV06 is
|
||||
IERC20TokenV06
|
||||
{
|
||||
/// @dev Wrap ether.
|
||||
function deposit() external payable;
|
||||
|
||||
/// @dev Unwrap ether.
|
||||
function withdraw(uint256 amount) external;
|
||||
}
|
208
contracts/erc20/contracts/src/v06/LibERC20TokenV06.sol
Normal file
208
contracts/erc20/contracts/src/v06/LibERC20TokenV06.sol
Normal file
@@ -0,0 +1,208 @@
|
||||
/*
|
||||
|
||||
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.6.5;
|
||||
|
||||
import "@0x/contracts-utils/contracts/src/v06/errors/LibRichErrorsV06.sol";
|
||||
import "@0x/contracts-utils/contracts/src/v06/LibBytesV06.sol";
|
||||
import "./IERC20TokenV06.sol";
|
||||
|
||||
|
||||
library LibERC20TokenV06 {
|
||||
bytes constant private DECIMALS_CALL_DATA = hex"313ce567";
|
||||
|
||||
/// @dev Calls `IERC20TokenV06(token).approve()`.
|
||||
/// Reverts if the result fails `isSuccessfulResult()` or the call reverts.
|
||||
/// @param token The address of the token contract.
|
||||
/// @param spender The address that receives an allowance.
|
||||
/// @param allowance The allowance to set.
|
||||
function compatApprove(
|
||||
IERC20TokenV06 token,
|
||||
address spender,
|
||||
uint256 allowance
|
||||
)
|
||||
internal
|
||||
{
|
||||
bytes memory callData = abi.encodeWithSelector(
|
||||
token.approve.selector,
|
||||
spender,
|
||||
allowance
|
||||
);
|
||||
_callWithOptionalBooleanResult(address(token), callData);
|
||||
}
|
||||
|
||||
/// @dev Calls `IERC20TokenV06(token).approve()` and sets the allowance to the
|
||||
/// maximum if the current approval is not already >= an amount.
|
||||
/// Reverts if the result fails `isSuccessfulResult()` or the call reverts.
|
||||
/// @param token The address of the token contract.
|
||||
/// @param spender The address that receives an allowance.
|
||||
/// @param amount The minimum allowance needed.
|
||||
function approveIfBelow(
|
||||
IERC20TokenV06 token,
|
||||
address spender,
|
||||
uint256 amount
|
||||
)
|
||||
internal
|
||||
{
|
||||
if (token.allowance(address(this), spender) < amount) {
|
||||
compatApprove(token, spender, uint256(-1));
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Calls `IERC20TokenV06(token).transfer()`.
|
||||
/// Reverts if the result fails `isSuccessfulResult()` or the call reverts.
|
||||
/// @param token The address of the token contract.
|
||||
/// @param to The address that receives the tokens
|
||||
/// @param amount Number of tokens to transfer.
|
||||
function compatTransfer(
|
||||
IERC20TokenV06 token,
|
||||
address to,
|
||||
uint256 amount
|
||||
)
|
||||
internal
|
||||
{
|
||||
bytes memory callData = abi.encodeWithSelector(
|
||||
token.transfer.selector,
|
||||
to,
|
||||
amount
|
||||
);
|
||||
_callWithOptionalBooleanResult(address(token), callData);
|
||||
}
|
||||
|
||||
/// @dev Calls `IERC20TokenV06(token).transferFrom()`.
|
||||
/// Reverts if the result fails `isSuccessfulResult()` or the call reverts.
|
||||
/// @param token The address of the token contract.
|
||||
/// @param from The owner of the tokens.
|
||||
/// @param to The address that receives the tokens
|
||||
/// @param amount Number of tokens to transfer.
|
||||
function compatTransferFrom(
|
||||
IERC20TokenV06 token,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
)
|
||||
internal
|
||||
{
|
||||
bytes memory callData = abi.encodeWithSelector(
|
||||
token.transferFrom.selector,
|
||||
from,
|
||||
to,
|
||||
amount
|
||||
);
|
||||
_callWithOptionalBooleanResult(address(token), callData);
|
||||
}
|
||||
|
||||
/// @dev Retrieves the number of decimals for a token.
|
||||
/// Returns `18` if the call reverts.
|
||||
/// @param token The address of the token contract.
|
||||
/// @return tokenDecimals The number of decimals places for the token.
|
||||
function compatDecimals(IERC20TokenV06 token)
|
||||
internal
|
||||
view
|
||||
returns (uint8 tokenDecimals)
|
||||
{
|
||||
tokenDecimals = 18;
|
||||
(bool didSucceed, bytes memory resultData) = address(token).staticcall(DECIMALS_CALL_DATA);
|
||||
if (didSucceed && resultData.length == 32) {
|
||||
tokenDecimals = uint8(LibBytesV06.readUint256(resultData, 0));
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Retrieves the allowance for a token, owner, and spender.
|
||||
/// Returns `0` if the call reverts.
|
||||
/// @param token The address of the token contract.
|
||||
/// @param owner The owner of the tokens.
|
||||
/// @param spender The address the spender.
|
||||
/// @return allowance_ The allowance for a token, owner, and spender.
|
||||
function compatAllowance(IERC20TokenV06 token, address owner, address spender)
|
||||
internal
|
||||
view
|
||||
returns (uint256 allowance_)
|
||||
{
|
||||
(bool didSucceed, bytes memory resultData) = address(token).staticcall(
|
||||
abi.encodeWithSelector(
|
||||
token.allowance.selector,
|
||||
owner,
|
||||
spender
|
||||
)
|
||||
);
|
||||
if (didSucceed && resultData.length == 32) {
|
||||
allowance_ = LibBytesV06.readUint256(resultData, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Retrieves the balance for a token owner.
|
||||
/// Returns `0` if the call reverts.
|
||||
/// @param token The address of the token contract.
|
||||
/// @param owner The owner of the tokens.
|
||||
/// @return balance The token balance of an owner.
|
||||
function compatBalanceOf(IERC20TokenV06 token, address owner)
|
||||
internal
|
||||
view
|
||||
returns (uint256 balance)
|
||||
{
|
||||
(bool didSucceed, bytes memory resultData) = address(token).staticcall(
|
||||
abi.encodeWithSelector(
|
||||
token.balanceOf.selector,
|
||||
owner
|
||||
)
|
||||
);
|
||||
if (didSucceed && resultData.length == 32) {
|
||||
balance = LibBytesV06.readUint256(resultData, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Check if the data returned by a non-static call to an ERC20 token
|
||||
/// is a successful result. Supported functions are `transfer()`,
|
||||
/// `transferFrom()`, and `approve()`.
|
||||
/// @param resultData The raw data returned by a non-static call to the ERC20 token.
|
||||
/// @return isSuccessful Whether the result data indicates success.
|
||||
function isSuccessfulResult(bytes memory resultData)
|
||||
internal
|
||||
pure
|
||||
returns (bool isSuccessful)
|
||||
{
|
||||
if (resultData.length == 0) {
|
||||
return true;
|
||||
}
|
||||
if (resultData.length == 32) {
|
||||
uint256 result = LibBytesV06.readUint256(resultData, 0);
|
||||
if (result == 1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Executes a call on address `target` with calldata `callData`
|
||||
/// and asserts that either nothing was returned or a single boolean
|
||||
/// was returned equal to `true`.
|
||||
/// @param target The call target.
|
||||
/// @param callData The abi-encoded call data.
|
||||
function _callWithOptionalBooleanResult(
|
||||
address target,
|
||||
bytes memory callData
|
||||
)
|
||||
private
|
||||
{
|
||||
(bool didSucceed, bytes memory resultData) = target.call(callData);
|
||||
if (didSucceed && isSuccessfulResult(resultData)) {
|
||||
return;
|
||||
}
|
||||
LibRichErrorsV06.rrevert(resultData);
|
||||
}
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-erc20",
|
||||
"version": "3.1.5",
|
||||
"version": "3.2.2",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -38,39 +38,39 @@
|
||||
},
|
||||
"config": {
|
||||
"publicInterfaceContracts": "DummyERC20Token,ERC20Token,WETH9,ZRXToken,DummyNoReturnERC20Token,DummyMultipleReturnERC20Token",
|
||||
"abis": "./test/generated-artifacts/@(DummyERC20Token|DummyMultipleReturnERC20Token|DummyNoReturnERC20Token|ERC20Token|IERC20Token|IEtherToken|LibERC20Token|MintableERC20Token|TestLibERC20Token|TestLibERC20TokenTarget|UnlimitedAllowanceERC20Token|UntransferrableDummyERC20Token|WETH9|ZRXToken).json",
|
||||
"abis": "./test/generated-artifacts/@(DummyERC20Token|DummyMultipleReturnERC20Token|DummyNoReturnERC20Token|ERC20Token|IERC20Token|IERC20TokenV06|IEtherToken|IEtherTokenV06|LibERC20Token|LibERC20TokenV06|MintableERC20Token|TestLibERC20Token|TestLibERC20TokenTarget|UnlimitedAllowanceERC20Token|UntransferrableDummyERC20Token|WETH9|ZRXToken).json",
|
||||
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually."
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/0xProject/0x-monorepo.git"
|
||||
"url": "https://github.com/0xProject/protocol.git"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/0xProject/0x-monorepo/issues"
|
||||
"url": "https://github.com/0xProject/protocol/issues"
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/tokens/README.md",
|
||||
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/tokens",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.2.2",
|
||||
"@0x/contracts-gen": "^2.0.8",
|
||||
"@0x/contracts-test-utils": "^5.3.2",
|
||||
"@0x/contracts-utils": "^4.4.3",
|
||||
"@0x/dev-utils": "^3.2.1",
|
||||
"@0x/sol-compiler": "^4.0.8",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
"@0x/types": "^3.1.2",
|
||||
"@0x/typescript-typings": "^5.0.2",
|
||||
"@0x/utils": "^5.4.1",
|
||||
"@0x/web3-wrapper": "^7.0.7",
|
||||
"@0x/abi-gen": "^5.4.3",
|
||||
"@0x/contracts-gen": "2.0.13",
|
||||
"@0x/contracts-test-utils": "^5.3.5",
|
||||
"@0x/contracts-utils": "^4.5.2",
|
||||
"@0x/dev-utils": "^3.3.4",
|
||||
"@0x/sol-compiler": "^4.2.3",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
"@0x/tslint-config": "^4.1.3",
|
||||
"@0x/types": "^3.2.4",
|
||||
"@0x/typescript-typings": "^5.1.5",
|
||||
"@0x/utils": "^5.6.3",
|
||||
"@0x/web3-wrapper": "^7.2.4",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "*",
|
||||
"@types/node": "12.12.54",
|
||||
"chai": "^4.0.1",
|
||||
"chai-as-promised": "^7.1.0",
|
||||
"chai-bignumber": "^3.0.0",
|
||||
"dirty-chai": "^2.0.1",
|
||||
"ethereum-types": "^3.1.0",
|
||||
"ethereum-types": "^3.3.3",
|
||||
"lodash": "^4.17.11",
|
||||
"make-promises-safe": "^1.1.0",
|
||||
"mocha": "^6.2.0",
|
||||
@@ -78,13 +78,14 @@
|
||||
"shx": "^0.2.2",
|
||||
"solhint": "^1.4.1",
|
||||
"tslint": "5.11.0",
|
||||
"typedoc": "^0.15.0",
|
||||
"typedoc": "~0.16.11",
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.2.1"
|
||||
"@0x/base-contract": "^6.2.7"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
},
|
||||
"gitHead": "4f91bfd907996b2f4dd383778b50c479c2602b56"
|
||||
}
|
||||
|
@@ -10,8 +10,11 @@ import * as DummyMultipleReturnERC20Token from '../test/generated-artifacts/Dumm
|
||||
import * as DummyNoReturnERC20Token from '../test/generated-artifacts/DummyNoReturnERC20Token.json';
|
||||
import * as ERC20Token from '../test/generated-artifacts/ERC20Token.json';
|
||||
import * as IERC20Token from '../test/generated-artifacts/IERC20Token.json';
|
||||
import * as IERC20TokenV06 from '../test/generated-artifacts/IERC20TokenV06.json';
|
||||
import * as IEtherToken from '../test/generated-artifacts/IEtherToken.json';
|
||||
import * as IEtherTokenV06 from '../test/generated-artifacts/IEtherTokenV06.json';
|
||||
import * as LibERC20Token from '../test/generated-artifacts/LibERC20Token.json';
|
||||
import * as LibERC20TokenV06 from '../test/generated-artifacts/LibERC20TokenV06.json';
|
||||
import * as MintableERC20Token from '../test/generated-artifacts/MintableERC20Token.json';
|
||||
import * as TestLibERC20Token from '../test/generated-artifacts/TestLibERC20Token.json';
|
||||
import * as TestLibERC20TokenTarget from '../test/generated-artifacts/TestLibERC20TokenTarget.json';
|
||||
@@ -28,6 +31,9 @@ export const artifacts = {
|
||||
ZRXToken: (ZRXToken as any) as ContractArtifact,
|
||||
IERC20Token: IERC20Token as ContractArtifact,
|
||||
IEtherToken: IEtherToken as ContractArtifact,
|
||||
IERC20TokenV06: IERC20TokenV06 as ContractArtifact,
|
||||
IEtherTokenV06: IEtherTokenV06 as ContractArtifact,
|
||||
LibERC20TokenV06: LibERC20TokenV06 as ContractArtifact,
|
||||
DummyERC20Token: DummyERC20Token as ContractArtifact,
|
||||
DummyMultipleReturnERC20Token: DummyMultipleReturnERC20Token as ContractArtifact,
|
||||
DummyNoReturnERC20Token: DummyNoReturnERC20Token as ContractArtifact,
|
||||
|
@@ -8,8 +8,11 @@ export * from '../test/generated-wrappers/dummy_multiple_return_erc20_token';
|
||||
export * from '../test/generated-wrappers/dummy_no_return_erc20_token';
|
||||
export * from '../test/generated-wrappers/erc20_token';
|
||||
export * from '../test/generated-wrappers/i_erc20_token';
|
||||
export * from '../test/generated-wrappers/i_erc20_token_v06';
|
||||
export * from '../test/generated-wrappers/i_ether_token';
|
||||
export * from '../test/generated-wrappers/i_ether_token_v06';
|
||||
export * from '../test/generated-wrappers/lib_erc20_token';
|
||||
export * from '../test/generated-wrappers/lib_erc20_token_v06';
|
||||
export * from '../test/generated-wrappers/mintable_erc20_token';
|
||||
export * from '../test/generated-wrappers/test_lib_erc20_token';
|
||||
export * from '../test/generated-wrappers/test_lib_erc20_token_target';
|
||||
|
@@ -14,8 +14,11 @@
|
||||
"test/generated-artifacts/DummyNoReturnERC20Token.json",
|
||||
"test/generated-artifacts/ERC20Token.json",
|
||||
"test/generated-artifacts/IERC20Token.json",
|
||||
"test/generated-artifacts/IERC20TokenV06.json",
|
||||
"test/generated-artifacts/IEtherToken.json",
|
||||
"test/generated-artifacts/IEtherTokenV06.json",
|
||||
"test/generated-artifacts/LibERC20Token.json",
|
||||
"test/generated-artifacts/LibERC20TokenV06.json",
|
||||
"test/generated-artifacts/MintableERC20Token.json",
|
||||
"test/generated-artifacts/TestLibERC20Token.json",
|
||||
"test/generated-artifacts/TestLibERC20TokenTarget.json",
|
||||
|
@@ -1,4 +1,31 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1603265572,
|
||||
"version": "3.1.8",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1594788383,
|
||||
"version": "3.1.7",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1592969527,
|
||||
"version": "3.1.6",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1583220306,
|
||||
"version": "3.1.5",
|
||||
|
@@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v3.1.8 - _October 21, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.1.7 - _July 15, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.1.6 - _June 24, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.1.5 - _March 3, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-erc721",
|
||||
"version": "3.1.5",
|
||||
"version": "3.1.8",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -44,34 +44,34 @@
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/0xProject/0x-monorepo.git"
|
||||
"url": "https://github.com/0xProject/protocol.git"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/0xProject/0x-monorepo/issues"
|
||||
"url": "https://github.com/0xProject/protocol/issues"
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/tokens/README.md",
|
||||
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/tokens",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.2.2",
|
||||
"@0x/contracts-gen": "^2.0.8",
|
||||
"@0x/contracts-test-utils": "^5.3.2",
|
||||
"@0x/contracts-utils": "^4.4.3",
|
||||
"@0x/dev-utils": "^3.2.1",
|
||||
"@0x/sol-compiler": "^4.0.8",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
"@0x/types": "^3.1.2",
|
||||
"@0x/typescript-typings": "^5.0.2",
|
||||
"@0x/utils": "^5.4.1",
|
||||
"@0x/web3-wrapper": "^7.0.7",
|
||||
"@0x/abi-gen": "^5.4.3",
|
||||
"@0x/contracts-gen": "2.0.13",
|
||||
"@0x/contracts-test-utils": "^5.3.5",
|
||||
"@0x/contracts-utils": "^4.5.2",
|
||||
"@0x/dev-utils": "^3.3.4",
|
||||
"@0x/sol-compiler": "^4.2.3",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
"@0x/tslint-config": "^4.1.3",
|
||||
"@0x/types": "^3.2.4",
|
||||
"@0x/typescript-typings": "^5.1.5",
|
||||
"@0x/utils": "^5.6.3",
|
||||
"@0x/web3-wrapper": "^7.2.4",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "*",
|
||||
"@types/node": "12.12.54",
|
||||
"chai": "^4.0.1",
|
||||
"chai-as-promised": "^7.1.0",
|
||||
"chai-bignumber": "^3.0.0",
|
||||
"dirty-chai": "^2.0.1",
|
||||
"ethereum-types": "^3.1.0",
|
||||
"ethereum-types": "^3.3.3",
|
||||
"lodash": "^4.17.11",
|
||||
"make-promises-safe": "^1.1.0",
|
||||
"mocha": "^6.2.0",
|
||||
@@ -80,13 +80,14 @@
|
||||
"solhint": "^1.4.1",
|
||||
"truffle": "^5.0.32",
|
||||
"tslint": "5.11.0",
|
||||
"typedoc": "^0.15.0",
|
||||
"typedoc": "~0.16.11",
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.2.1"
|
||||
"@0x/base-contract": "^6.2.7"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
},
|
||||
"gitHead": "4f91bfd907996b2f4dd383778b50c479c2602b56"
|
||||
}
|
||||
|
@@ -1,4 +1,31 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1603265572,
|
||||
"version": "4.2.8",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1594788383,
|
||||
"version": "4.2.7",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1592969527,
|
||||
"version": "4.2.6",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1583220306,
|
||||
"version": "4.2.5",
|
||||
|
@@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v4.2.8 - _October 21, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.2.7 - _July 15, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.2.6 - _June 24, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.2.5 - _March 3, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -151,6 +151,72 @@ contract Forwarder is
|
||||
_unwrapAndTransferEth(wethRemaining);
|
||||
}
|
||||
|
||||
/// @dev Purchases as much of orders' makerAssets as possible by selling the specified amount of ETH
|
||||
/// accounting for order and forwarder fees. This functions throws if ethSellAmount was not reached.
|
||||
/// @param orders Array of order specifications used containing desired makerAsset and WETH as takerAsset.
|
||||
/// @param ethSellAmount Desired amount of ETH to sell.
|
||||
/// @param signatures Proofs that orders have been created by makers.
|
||||
/// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients.
|
||||
/// @param feeRecipients Addresses that will receive ETH when orders are filled.
|
||||
/// @return wethSpentAmount Amount of WETH spent on the given set of orders.
|
||||
/// @return makerAssetAcquiredAmount Amount of maker asset acquired from the given set of orders.
|
||||
function marketSellAmountWithEth(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256 ethSellAmount,
|
||||
bytes[] memory signatures,
|
||||
uint256[] memory ethFeeAmounts,
|
||||
address payable[] memory feeRecipients
|
||||
)
|
||||
public
|
||||
payable
|
||||
returns (
|
||||
uint256 wethSpentAmount,
|
||||
uint256 makerAssetAcquiredAmount
|
||||
)
|
||||
{
|
||||
if (ethSellAmount > msg.value) {
|
||||
LibRichErrors.rrevert(LibForwarderRichErrors.CompleteSellFailedError(
|
||||
ethSellAmount,
|
||||
msg.value
|
||||
));
|
||||
}
|
||||
// Pay ETH affiliate fees to all feeRecipient addresses
|
||||
uint256 wethRemaining = _transferEthFeesAndWrapRemaining(
|
||||
ethFeeAmounts,
|
||||
feeRecipients
|
||||
);
|
||||
// Need enough remaining to ensure we can sell ethSellAmount
|
||||
if (wethRemaining < ethSellAmount) {
|
||||
LibRichErrors.rrevert(LibForwarderRichErrors.OverspentWethError(
|
||||
wethRemaining,
|
||||
ethSellAmount
|
||||
));
|
||||
}
|
||||
// Spends up to ethSellAmount to fill orders, transfers purchased assets to msg.sender,
|
||||
// and pays WETH order fees.
|
||||
(
|
||||
wethSpentAmount,
|
||||
makerAssetAcquiredAmount
|
||||
) = _marketSellExactAmountNoThrow(
|
||||
orders,
|
||||
ethSellAmount,
|
||||
signatures
|
||||
);
|
||||
// Ensure we sold the specified amount (note: wethSpentAmount includes fees)
|
||||
if (wethSpentAmount < ethSellAmount) {
|
||||
LibRichErrors.rrevert(LibForwarderRichErrors.CompleteSellFailedError(
|
||||
ethSellAmount,
|
||||
wethSpentAmount
|
||||
));
|
||||
}
|
||||
|
||||
// Calculate amount of WETH that hasn't been spent.
|
||||
wethRemaining = wethRemaining.safeSub(wethSpentAmount);
|
||||
|
||||
// Refund remaining ETH to msg.sender.
|
||||
_unwrapAndTransferEth(wethRemaining);
|
||||
}
|
||||
|
||||
/// @dev Attempt to buy makerAssetBuyAmount of makerAsset by selling ETH provided with transaction.
|
||||
/// The Forwarder may *fill* more than makerAssetBuyAmount of the makerAsset so that it can
|
||||
/// pay takerFees where takerFeeAssetData == makerAssetData (i.e. percentage fees).
|
||||
|
@@ -53,6 +53,7 @@ contract MixinExchangeWrapper {
|
||||
// ")"
|
||||
// )));
|
||||
bytes4 constant public EXCHANGE_V2_ORDER_ID = 0x770501f8;
|
||||
bytes4 constant internal ERC20_BRIDGE_PROXY_ID = 0xdc1600f3;
|
||||
|
||||
// solhint-disable var-name-mixedcase
|
||||
IExchange internal EXCHANGE;
|
||||
@@ -73,6 +74,12 @@ contract MixinExchangeWrapper {
|
||||
EXCHANGE_V2 = IExchangeV2(_exchangeV2);
|
||||
}
|
||||
|
||||
struct SellFillResults {
|
||||
uint256 wethSpentAmount;
|
||||
uint256 makerAssetAcquiredAmount;
|
||||
uint256 protocolFeePaid;
|
||||
}
|
||||
|
||||
/// @dev Fills the input order.
|
||||
/// Returns false if the transaction would otherwise revert.
|
||||
/// @param order Order struct containing order specifications.
|
||||
@@ -115,11 +122,16 @@ contract MixinExchangeWrapper {
|
||||
uint256 remainingTakerAssetFillAmount
|
||||
)
|
||||
internal
|
||||
returns (
|
||||
uint256 wethSpentAmount,
|
||||
uint256 makerAssetAcquiredAmount
|
||||
)
|
||||
returns (SellFillResults memory sellFillResults)
|
||||
{
|
||||
// If the maker asset is ERC20Bridge, take a snapshot of the Forwarder contract's balance.
|
||||
bytes4 makerAssetProxyId = order.makerAssetData.readBytes4(0);
|
||||
address tokenAddress;
|
||||
uint256 balanceBefore;
|
||||
if (makerAssetProxyId == ERC20_BRIDGE_PROXY_ID) {
|
||||
tokenAddress = order.makerAssetData.readAddress(16);
|
||||
balanceBefore = IERC20Token(tokenAddress).balanceOf(address(this));
|
||||
}
|
||||
// No taker fee or percentage fee
|
||||
if (
|
||||
order.takerFee == 0 ||
|
||||
@@ -132,11 +144,11 @@ contract MixinExchangeWrapper {
|
||||
signature
|
||||
);
|
||||
|
||||
wethSpentAmount = singleFillResults.takerAssetFilledAmount
|
||||
.safeAdd(singleFillResults.protocolFeePaid);
|
||||
sellFillResults.wethSpentAmount = singleFillResults.takerAssetFilledAmount;
|
||||
sellFillResults.protocolFeePaid = singleFillResults.protocolFeePaid;
|
||||
|
||||
// Subtract fee from makerAssetFilledAmount for the net amount acquired.
|
||||
makerAssetAcquiredAmount = singleFillResults.makerAssetFilledAmount
|
||||
sellFillResults.makerAssetAcquiredAmount = singleFillResults.makerAssetFilledAmount
|
||||
.safeSub(singleFillResults.takerFeePaid);
|
||||
|
||||
// WETH fee
|
||||
@@ -157,18 +169,27 @@ contract MixinExchangeWrapper {
|
||||
);
|
||||
|
||||
// WETH is also spent on the taker fee, so we add it here.
|
||||
wethSpentAmount = singleFillResults.takerAssetFilledAmount
|
||||
.safeAdd(singleFillResults.takerFeePaid)
|
||||
.safeAdd(singleFillResults.protocolFeePaid);
|
||||
|
||||
makerAssetAcquiredAmount = singleFillResults.makerAssetFilledAmount;
|
||||
sellFillResults.wethSpentAmount = singleFillResults.takerAssetFilledAmount
|
||||
.safeAdd(singleFillResults.takerFeePaid);
|
||||
sellFillResults.makerAssetAcquiredAmount = singleFillResults.makerAssetFilledAmount;
|
||||
sellFillResults.protocolFeePaid = singleFillResults.protocolFeePaid;
|
||||
|
||||
// Unsupported fee
|
||||
} else {
|
||||
LibRichErrors.rrevert(LibForwarderRichErrors.UnsupportedFeeError(order.takerFeeAssetData));
|
||||
}
|
||||
|
||||
return (wethSpentAmount, makerAssetAcquiredAmount);
|
||||
// Account for the ERC20Bridge transfering more of the maker asset than expected.
|
||||
if (makerAssetProxyId == ERC20_BRIDGE_PROXY_ID) {
|
||||
uint256 balanceAfter = IERC20Token(tokenAddress).balanceOf(address(this));
|
||||
sellFillResults.makerAssetAcquiredAmount = LibSafeMath.max256(
|
||||
balanceAfter.safeSub(balanceBefore),
|
||||
sellFillResults.makerAssetAcquiredAmount
|
||||
);
|
||||
}
|
||||
|
||||
order.makerAssetData.transferOut(sellFillResults.makerAssetAcquiredAmount);
|
||||
return sellFillResults;
|
||||
}
|
||||
|
||||
/// @dev Synchronously executes multiple calls of fillOrder until total amount of WETH has been sold by taker.
|
||||
@@ -189,7 +210,6 @@ contract MixinExchangeWrapper {
|
||||
)
|
||||
{
|
||||
uint256 protocolFee = tx.gasprice.safeMul(EXCHANGE.protocolFeeMultiplier());
|
||||
bytes4 erc20BridgeProxyId = IAssetData(address(0)).ERC20Bridge.selector;
|
||||
|
||||
for (uint256 i = 0; i != orders.length; i++) {
|
||||
// Preemptively skip to avoid division by zero in _marketSellSingleOrder
|
||||
@@ -199,42 +219,27 @@ contract MixinExchangeWrapper {
|
||||
|
||||
// The remaining amount of WETH to sell
|
||||
uint256 remainingTakerAssetFillAmount = wethSellAmount
|
||||
.safeSub(totalWethSpentAmount)
|
||||
.safeSub(_isV2Order(orders[i]) ? 0 : protocolFee);
|
||||
|
||||
// If the maker asset is ERC20Bridge, take a snapshot of the Forwarder contract's balance.
|
||||
bytes4 makerAssetProxyId = orders[i].makerAssetData.readBytes4(0);
|
||||
address tokenAddress;
|
||||
uint256 balanceBefore;
|
||||
if (makerAssetProxyId == erc20BridgeProxyId) {
|
||||
tokenAddress = orders[i].makerAssetData.readAddress(16);
|
||||
balanceBefore = IERC20Token(tokenAddress).balanceOf(address(this));
|
||||
.safeSub(totalWethSpentAmount);
|
||||
uint256 currentProtocolFee = _isV2Order(orders[i]) ? 0 : protocolFee;
|
||||
if (remainingTakerAssetFillAmount > currentProtocolFee) {
|
||||
// Do not count the protocol fee as part of the fill amount.
|
||||
remainingTakerAssetFillAmount = remainingTakerAssetFillAmount.safeSub(currentProtocolFee);
|
||||
} else {
|
||||
// Stop if we don't have at least enough ETH to pay another protocol fee.
|
||||
break;
|
||||
}
|
||||
|
||||
(
|
||||
uint256 wethSpentAmount,
|
||||
uint256 makerAssetAcquiredAmount
|
||||
) = _marketSellSingleOrder(
|
||||
SellFillResults memory sellFillResults = _marketSellSingleOrder(
|
||||
orders[i],
|
||||
signatures[i],
|
||||
remainingTakerAssetFillAmount
|
||||
);
|
||||
|
||||
// Account for the ERC20Bridge transfering more of the maker asset than expected.
|
||||
if (makerAssetProxyId == erc20BridgeProxyId) {
|
||||
uint256 balanceAfter = IERC20Token(tokenAddress).balanceOf(address(this));
|
||||
makerAssetAcquiredAmount = LibSafeMath.max256(
|
||||
balanceAfter.safeSub(balanceBefore),
|
||||
makerAssetAcquiredAmount
|
||||
);
|
||||
}
|
||||
|
||||
orders[i].makerAssetData.transferOut(makerAssetAcquiredAmount);
|
||||
|
||||
totalWethSpentAmount = totalWethSpentAmount
|
||||
.safeAdd(wethSpentAmount);
|
||||
.safeAdd(sellFillResults.wethSpentAmount)
|
||||
.safeAdd(sellFillResults.protocolFeePaid);
|
||||
totalMakerAssetAcquiredAmount = totalMakerAssetAcquiredAmount
|
||||
.safeAdd(makerAssetAcquiredAmount);
|
||||
.safeAdd(sellFillResults.makerAssetAcquiredAmount);
|
||||
|
||||
// Stop execution if the entire amount of WETH has been sold
|
||||
if (totalWethSpentAmount >= wethSellAmount) {
|
||||
@@ -243,6 +248,56 @@ contract MixinExchangeWrapper {
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Synchronously executes multiple calls of fillOrder until total amount of WETH (exclusive of protocol fee)
|
||||
/// has been sold by taker.
|
||||
/// @param orders Array of order specifications.
|
||||
/// @param wethSellAmount Desired amount of WETH to sell.
|
||||
/// @param signatures Proofs that orders have been signed by makers.
|
||||
/// @return totalWethSpentAmount Total amount of WETH spent on the given orders.
|
||||
/// @return totalMakerAssetAcquiredAmount Total amount of maker asset acquired from the given orders.
|
||||
function _marketSellExactAmountNoThrow(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256 wethSellAmount,
|
||||
bytes[] memory signatures
|
||||
)
|
||||
internal
|
||||
returns (
|
||||
uint256 totalWethSpentAmount,
|
||||
uint256 totalMakerAssetAcquiredAmount
|
||||
)
|
||||
{
|
||||
uint256 totalProtocolFeePaid;
|
||||
|
||||
for (uint256 i = 0; i != orders.length; i++) {
|
||||
// Preemptively skip to avoid division by zero in _marketSellSingleOrder
|
||||
if (orders[i].makerAssetAmount == 0 || orders[i].takerAssetAmount == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// The remaining amount of WETH to sell
|
||||
uint256 remainingTakerAssetFillAmount = wethSellAmount
|
||||
.safeSub(totalWethSpentAmount);
|
||||
|
||||
SellFillResults memory sellFillResults = _marketSellSingleOrder(
|
||||
orders[i],
|
||||
signatures[i],
|
||||
remainingTakerAssetFillAmount
|
||||
);
|
||||
|
||||
totalWethSpentAmount = totalWethSpentAmount
|
||||
.safeAdd(sellFillResults.wethSpentAmount);
|
||||
totalMakerAssetAcquiredAmount = totalMakerAssetAcquiredAmount
|
||||
.safeAdd(sellFillResults.makerAssetAcquiredAmount);
|
||||
totalProtocolFeePaid = totalProtocolFeePaid.safeAdd(sellFillResults.protocolFeePaid);
|
||||
|
||||
// Stop execution if the entire amount of WETH has been sold
|
||||
if (totalWethSpentAmount >= wethSellAmount) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
totalWethSpentAmount = totalWethSpentAmount.safeAdd(totalProtocolFeePaid);
|
||||
}
|
||||
|
||||
/// @dev Executes a single call of fillOrder according to the makerAssetBuyAmount and
|
||||
/// the amount already bought.
|
||||
/// @param order A single order specification.
|
||||
@@ -338,8 +393,6 @@ contract MixinExchangeWrapper {
|
||||
uint256 totalMakerAssetAcquiredAmount
|
||||
)
|
||||
{
|
||||
bytes4 erc20BridgeProxyId = IAssetData(address(0)).ERC20Bridge.selector;
|
||||
|
||||
uint256 ordersLength = orders.length;
|
||||
for (uint256 i = 0; i != ordersLength; i++) {
|
||||
// Preemptively skip to avoid division by zero in _marketBuySingleOrder
|
||||
@@ -354,7 +407,7 @@ contract MixinExchangeWrapper {
|
||||
bytes4 makerAssetProxyId = orders[i].makerAssetData.readBytes4(0);
|
||||
address tokenAddress;
|
||||
uint256 balanceBefore;
|
||||
if (makerAssetProxyId == erc20BridgeProxyId) {
|
||||
if (makerAssetProxyId == ERC20_BRIDGE_PROXY_ID) {
|
||||
tokenAddress = orders[i].makerAssetData.readAddress(16);
|
||||
balanceBefore = IERC20Token(tokenAddress).balanceOf(address(this));
|
||||
}
|
||||
@@ -369,7 +422,7 @@ contract MixinExchangeWrapper {
|
||||
);
|
||||
|
||||
// Account for the ERC20Bridge transfering more of the maker asset than expected.
|
||||
if (makerAssetProxyId == erc20BridgeProxyId) {
|
||||
if (makerAssetProxyId == ERC20_BRIDGE_PROXY_ID) {
|
||||
uint256 balanceAfter = IERC20Token(tokenAddress).balanceOf(address(this));
|
||||
makerAssetAcquiredAmount = LibSafeMath.max256(
|
||||
balanceAfter.safeSub(balanceBefore),
|
||||
|
@@ -29,6 +29,10 @@ library LibForwarderRichErrors {
|
||||
bytes4 internal constant COMPLETE_BUY_FAILED_ERROR_SELECTOR =
|
||||
0x91353a0c;
|
||||
|
||||
// bytes4(keccak256("CompleteSellFailedError(uint256,uint256)"))
|
||||
bytes4 internal constant COMPLETE_SELL_FAILED_ERROR_SELECTOR =
|
||||
0x450a0219;
|
||||
|
||||
// bytes4(keccak256("UnsupportedFeeError(bytes)"))
|
||||
bytes4 internal constant UNSUPPORTED_FEE_ERROR_SELECTOR =
|
||||
0x31360af1;
|
||||
@@ -61,6 +65,21 @@ library LibForwarderRichErrors {
|
||||
);
|
||||
}
|
||||
|
||||
function CompleteSellFailedError(
|
||||
uint256 expectedAssetSellAmount,
|
||||
uint256 actualAssetSellAmount
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
COMPLETE_SELL_FAILED_ERROR_SELECTOR,
|
||||
expectedAssetSellAmount,
|
||||
actualAssetSellAmount
|
||||
);
|
||||
}
|
||||
|
||||
function UnsupportedFeeError(
|
||||
bytes memory takerFeeAssetData
|
||||
)
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-exchange-forwarder",
|
||||
"version": "4.2.5",
|
||||
"version": "4.2.8",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -44,36 +44,36 @@
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/0xProject/0x-monorepo.git"
|
||||
"url": "https://github.com/0xProject/protocol.git"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/0xProject/0x-monorepo/issues"
|
||||
"url": "https://github.com/0xProject/protocol/issues"
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md",
|
||||
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/extensions",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.2.2",
|
||||
"@0x/contracts-asset-proxy": "^3.2.5",
|
||||
"@0x/contracts-dev-utils": "^1.3.3",
|
||||
"@0x/contracts-erc1155": "^2.1.5",
|
||||
"@0x/contracts-erc20": "^3.1.5",
|
||||
"@0x/contracts-erc721": "^3.1.5",
|
||||
"@0x/contracts-exchange": "^3.2.5",
|
||||
"@0x/contracts-exchange-libs": "^4.3.5",
|
||||
"@0x/contracts-gen": "^2.0.8",
|
||||
"@0x/contracts-test-utils": "^5.3.2",
|
||||
"@0x/contracts-utils": "^4.4.3",
|
||||
"@0x/dev-utils": "^3.2.1",
|
||||
"@0x/order-utils": "^10.2.4",
|
||||
"@0x/sol-compiler": "^4.0.8",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
"@0x/types": "^3.1.2",
|
||||
"@0x/utils": "^5.4.1",
|
||||
"@0x/web3-wrapper": "^7.0.7",
|
||||
"@0x/abi-gen": "^5.4.3",
|
||||
"@0x/contracts-asset-proxy": "^3.5.0",
|
||||
"@0x/contracts-dev-utils": "^1.3.6",
|
||||
"@0x/contracts-erc1155": "^2.1.8",
|
||||
"@0x/contracts-erc20": "^3.2.2",
|
||||
"@0x/contracts-erc721": "^3.1.8",
|
||||
"@0x/contracts-exchange": "^3.2.8",
|
||||
"@0x/contracts-exchange-libs": "^4.3.8",
|
||||
"@0x/contracts-gen": "2.0.13",
|
||||
"@0x/contracts-test-utils": "^5.3.5",
|
||||
"@0x/contracts-utils": "^4.5.2",
|
||||
"@0x/dev-utils": "^3.3.4",
|
||||
"@0x/order-utils": "^10.4.0",
|
||||
"@0x/sol-compiler": "^4.2.3",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
"@0x/tslint-config": "^4.1.3",
|
||||
"@0x/types": "^3.2.4",
|
||||
"@0x/utils": "^5.6.3",
|
||||
"@0x/web3-wrapper": "^7.2.4",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "*",
|
||||
"@types/node": "12.12.54",
|
||||
"chai": "^4.0.1",
|
||||
"chai-as-promised": "^7.1.0",
|
||||
"chai-bignumber": "^3.0.0",
|
||||
@@ -86,15 +86,16 @@
|
||||
"solhint": "^1.4.1",
|
||||
"truffle": "^5.0.32",
|
||||
"tslint": "5.11.0",
|
||||
"typedoc": "^0.15.0",
|
||||
"typedoc": "~0.16.11",
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.2.1",
|
||||
"@0x/typescript-typings": "^5.0.2",
|
||||
"ethereum-types": "^3.1.0"
|
||||
"@0x/base-contract": "^6.2.7",
|
||||
"@0x/typescript-typings": "^5.1.5",
|
||||
"ethereum-types": "^3.3.3"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
},
|
||||
"gitHead": "4f91bfd907996b2f4dd383778b50c479c2602b56"
|
||||
}
|
||||
|
@@ -1,4 +1,31 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1603265572,
|
||||
"version": "4.3.8",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1594788383,
|
||||
"version": "4.3.7",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1592969527,
|
||||
"version": "4.3.6",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1583220306,
|
||||
"version": "4.3.5",
|
||||
|
@@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v4.3.8 - _October 21, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.3.7 - _July 15, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.3.6 - _June 24, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.3.5 - _March 3, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user