Compare commits
	
		
			1541 Commits
		
	
	
		
			@0x/dev-ut
			...
			protocol@d
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | dbcb221a59 | ||
|  | 6bbc179f52 | ||
|  | 48e7a391c8 | ||
|  | 2334e64d0c | ||
|  | 14f920ee84 | ||
|  | e10a81023a | ||
|  | f4709ed1cb | ||
|  | e2e14a977a | ||
|  | 866f958a10 | ||
|  | 717db99b38 | ||
|  | 02006118c7 | ||
|  | 9816019bc5 | ||
|  | 9c821dbfc3 | ||
|  | af1b890423 | ||
|  | 673835d2de | ||
|  | 500b57e935 | ||
|  | 3f7d0580c1 | ||
|  | a71c356bba | ||
|  | c3a95b7fb1 | ||
|  | f01540fb35 | ||
|  | 689a8881c2 | ||
|  | 99f5be8378 | ||
|  | 8de0282d92 | ||
|  | f99804d56a | ||
|  | f13d27b749 | ||
|  | 465fd59cbc | ||
|  | 5fdabe6612 | ||
|  | 861871134b | ||
|  | c246d98093 | ||
|  | 02076dba1b | ||
|  | 7b136a5ad8 | ||
|  | 0c4a67fa35 | ||
|  | 668aeb77f7 | ||
|  | 135ae392d5 | ||
|  | 88ba04307c | ||
|  | e4b8000a48 | ||
|  | b9df108314 | ||
|  | 6106185bf6 | ||
|  | 3a3e289864 | ||
|  | 6558632f10 | ||
|  | 376ee6bdff | ||
|  | fc5d759131 | ||
|  | 7c16bb3df8 | ||
|  | 5df74d35d0 | ||
|  | 72fc0c845a | ||
|  | b995715a2c | ||
|  | 857b5c97b0 | ||
|  | 178d9c280a | ||
|  | 2416deba25 | ||
|  | 0ce6243653 | ||
|  | 40dc10729b | ||
|  | 0571244e9e | ||
|  | 3213131cad | ||
|  | 61bf93aac2 | ||
|  | a9d0cec6d1 | ||
|  | b5e3f0b90c | ||
|  | 61f1fe42b0 | ||
|  | 1cfdc49021 | ||
|  | c4d58277cf | ||
|  | 9ac66c2130 | ||
|  | 6366163006 | ||
|  | 85fde8f9a5 | ||
|  | a03d0800b0 | ||
|  | 9cb21006a7 | ||
|  | 649202f1c4 | ||
|  | b798556774 | ||
|  | 03bc15fbdf | ||
|  | b2dfd8740c | ||
|  | 3182c12b4d | ||
|  | f783625d60 | ||
|  | 891aa8e8bf | ||
|  | 4b508d255d | ||
|  | 1cad43bf5d | ||
|  | a0cd727832 | ||
|  | ab90e15015 | ||
|  | 52cbddf054 | ||
|  | db98ff8cb7 | ||
|  | 1d8dd2f89c | ||
|  | 0ae1c926d3 | ||
|  | 1fcab58e2f | ||
|  | a8cbd1a16c | ||
|  | 3aaa0ad6b2 | ||
|  | e34bc77157 | ||
|  | 088b331f19 | ||
|  | 56f2dec441 | ||
|  | ac8b08d3cf | ||
|  | c4ead689a9 | ||
|  | 07ab10b000 | ||
|  | c969a8652a | ||
|  | fb21ca5404 | ||
|  | bbfa9c34ab | ||
|  | 7161bbe836 | ||
|  | ef65aa5bf6 | ||
|  | 2cf31f05a1 | ||
|  | 2b1a1ba0db | ||
|  | 05b25c6229 | ||
|  | 2db52c6983 | ||
|  | 4803e2f68c | ||
|  | 7030572f1d | ||
|  | 6e2eb9c5bb | ||
|  | eb27e260e0 | ||
|  | c72aa653e8 | ||
|  | 4d04b72674 | ||
|  | e3b92d2c8b | ||
|  | 4aa5a89cd7 | ||
|  | c6b9ea5723 | ||
|  | 2dc0bff1ea | ||
|  | 408e66e8b4 | ||
|  | 40fe12a86b | ||
|  | 1adb56f092 | ||
|  | 629d48c766 | ||
|  | c8886febb9 | ||
|  | efe598c8fd | ||
|  | 32218ce25e | ||
|  | f7ae697475 | ||
|  | 6e954385ce | ||
|  | f8df89b506 | ||
|  | a3ff406461 | ||
|  | 221de054f4 | ||
|  | 98e6aa4bac | ||
|  | 199808dc44 | ||
|  | 5d8e35fb68 | ||
|  | 36546480b1 | ||
|  | cd9e408ea3 | ||
|  | 7698f21517 | ||
|  | 10724e5745 | ||
|  | dde76a4dbb | ||
|  | 86ff5c53bb | ||
|  | efef5f122f | ||
|  | 83c942ad8c | ||
|  | 31e90e314c | ||
|  | 33caae705e | ||
|  | 961273a2ff | ||
|  | 46e512a27c | ||
|  | 290a04a0ad | ||
|  | 12ff4ec438 | ||
|  | 1c15ecacb0 | ||
|  | c6d738ed0c | ||
|  | f089f5d87f | ||
|  | 78e3cd39d1 | ||
|  | 1588c1f362 | ||
|  | a35d1b8a9d | ||
|  | 32923ec7e1 | ||
|  | 5a3bd716ad | ||
|  | 84862f15c1 | ||
|  | 9e42dce5c4 | ||
|  | a360109013 | ||
|  | 68d6b3a033 | ||
|  | 733c3046bc | ||
|  | 23d4b6bf1c | ||
|  | 39bd0c5459 | ||
|  | c13ffb2072 | ||
|  | 38bcab1f86 | ||
|  | a24f01c90f | ||
|  | 708e34602b | ||
|  | d60c8ddd5a | ||
|  | eea63292f0 | ||
|  | a97342a594 | ||
|  | 00f55be83e | ||
|  | 90ed283b20 | ||
|  | 61272961a8 | ||
|  | 507690f9db | ||
|  | 90ad5eb6c4 | ||
|  | 7bc9701c81 | ||
|  | a7d502a501 | ||
|  | fbe99b41f8 | ||
|  | 66e2d93e9c | ||
|  | 4672c72fef | ||
|  | ac6b03cd4a | ||
|  | d7de191947 | ||
|  | de7f1fc207 | ||
|  | 99de5a3814 | ||
|  | 4cf566cad8 | ||
|  | 6138955f93 | ||
|  | a57cf68ee4 | ||
|  | 20edcd1ae5 | ||
|  | 5333befd89 | ||
|  | 235e406620 | ||
|  | 5f570b772d | ||
|  | f2507cb94a | ||
|  | f84b375cde | ||
|  | 32d11d1ba5 | ||
|  | 5c9b6eb078 | ||
|  | f53a512e70 | ||
|  | ec08715090 | ||
|  | 79e0a9ef37 | ||
|  | 1ce8a33937 | ||
|  | b3053dfb91 | ||
|  | 3da05f2812 | ||
|  | 0ba79b060d | ||
|  | c4bcc26e29 | ||
|  | 630108ccb6 | ||
|  | 1ab33aa132 | ||
|  | ee456ea6e7 | ||
|  | e7541ac2af | ||
|  | d34d46b7fd | ||
|  | 08ae43aad3 | ||
|  | eb141075c7 | ||
|  | bd3387a408 | ||
|  | e1a48e80e1 | ||
|  | bf899d40a0 | ||
|  | dc66f1b886 | ||
|  | 3753b1a7d0 | ||
|  | 05c5acdb15 | ||
|  | ca63bcc9b0 | ||
|  | 3733d503db | ||
|  | ab28e42c22 | ||
|  | 7e53b4f834 | ||
|  | 3bb60fee19 | ||
|  | 9f7840e12b | ||
|  | f41e13b574 | ||
|  | 4049143630 | ||
|  | 705f46717f | ||
|  | a6cf8ae0b6 | ||
|  | dba6972281 | ||
|  | 52d36f5a8b | ||
|  | 889b58a914 | ||
|  | 43810835d7 | ||
|  | 4b9867f167 | ||
|  | e9c91e59bd | ||
|  | d8844f6970 | ||
|  | 1cdc6e7184 | ||
|  | 36ad373f03 | ||
|  | 78dfb6d525 | ||
|  | 79254de7bc | ||
|  | 1d6aef5cd6 | ||
|  | f9d02c9e27 | ||
|  | 228246089e | ||
|  | b6319ba3d8 | ||
|  | 2636384ead | ||
|  | 0425f76284 | ||
|  | d93e72f56a | ||
|  | 195d543ce3 | ||
|  | 9cda9f69cd | ||
|  | 7b0a1c3630 | ||
|  | a8f3a47240 | ||
|  | db0f3a8780 | ||
|  | 514db24ceb | ||
|  | e738743c89 | ||
|  | f471e1a8a3 | ||
|  | a2f0d5eedf | ||
|  | 2f9b894d71 | ||
|  | bab34c2d21 | ||
|  | a68421b0f8 | ||
|  | e9b0ac8820 | ||
|  | 4f78f55c2a | ||
|  | 156093127b | ||
|  | 47d91bb4e0 | ||
|  | cc31445189 | ||
|  | af78238507 | ||
|  | b30f87f50c | ||
|  | 3cd03ed0f1 | ||
|  | e7ad7c3af7 | ||
|  | 7e8b56eef4 | ||
|  | 458a014e6d | ||
|  | 9b6703398e | ||
|  | 71700e69af | ||
|  | 14d6330b40 | ||
|  | d31d646ecc | ||
|  | 270d7a3f19 | ||
|  | e078f3d479 | ||
|  | 6aa8f17ed5 | ||
|  | 8e73ae3614 | ||
|  | 89117beda2 | ||
|  | e27e6baabe | ||
|  | 15ce90c0ec | ||
|  | 39e157499d | ||
|  | d22c0641fb | ||
|  | 82806b6fcb | ||
|  | fe293d91ee | ||
|  | 7842bb4cad | ||
|  | 6f7e156f49 | ||
|  | 0d19cac487 | ||
|  | f30dfcc572 | ||
|  | 3df39d8cfe | ||
|  | ece93fed78 | ||
|  | 3a2c6ae9d6 | ||
|  | 2ed71b36b6 | ||
|  | ae9c301795 | ||
|  | 68206ffb6e | ||
|  | 25a3c18bfe | ||
|  | d28476e9f7 | ||
|  | 7cd30610f9 | ||
|  | ceb90989d0 | ||
|  | bb39d63d37 | ||
|  | 213709d020 | ||
|  | d0e9081852 | ||
|  | 71cde281b9 | ||
|  | c03f1586e6 | ||
|  | 10aceb164d | ||
|  | 34f516a417 | ||
|  | 5dd686f22f | ||
|  | 5f47ad3363 | ||
|  | e166e9762a | ||
|  | 341c5782e5 | ||
|  | d5180d3ebc | ||
|  | 2c73bbd689 | ||
|  | b10522479c | ||
|  | 2b39ae4800 | ||
|  | 788bdba8cd | ||
|  | 222fd5d822 | ||
|  | eedfc64a8c | ||
|  | 78170b26e9 | ||
|  | f966b6f4df | ||
|  | 053b55fbbf | ||
|  | 84a55a2d84 | ||
|  | 498a50b229 | ||
|  | 766888ec41 | ||
|  | 466d962c07 | ||
|  | ae2a6fb685 | ||
|  | 5afe2616a4 | ||
|  | 72c869649a | ||
|  | 34138fc3b5 | ||
|  | f67d2b96ac | ||
|  | d877d3686c | ||
|  | 8260615b4e | ||
|  | c3f6d48966 | ||
|  | 02f979bc74 | ||
|  | de1c71aacc | ||
|  | ca2aa72e0f | ||
|  | 9a16f5736e | ||
|  | 82774df715 | ||
|  | 314f53c0b3 | ||
|  | 6553ee0130 | ||
|  | d7918ea047 | ||
|  | 4aa9c85503 | ||
|  | f172591059 | ||
|  | dfa7e30e42 | ||
|  | 3fe2013398 | ||
|  | 391d501ce6 | ||
|  | 9edaa3a64e | ||
|  | 6e4e313792 | ||
|  | e6dcf92ec8 | ||
|  | f359de2cac | ||
|  | 2d29014091 | ||
|  | 0450e430f1 | ||
|  | b6700af6a8 | ||
|  | bcee7546ae | ||
|  | 4dac620156 | ||
|  | 74d9df2fb0 | ||
|  | 9d1615fa23 | ||
|  | b1b9949e72 | ||
|  | 957ef5ab77 | ||
|  | 07a681c77e | ||
|  | 145ec8ede1 | ||
|  | 5f5a158060 | ||
|  | 3e99c95791 | ||
|  | 4f83521be8 | ||
|  | aae93bb6a7 | ||
|  | b5eb1c9ee8 | ||
|  | 9d3755db36 | ||
|  | 762e0aec2d | ||
|  | ff9c9241d8 | ||
|  | 5c1ffe7fc8 | ||
|  | b1c3c60def | ||
|  | 8763713596 | ||
|  | 3e823cc9e3 | ||
|  | 1c84709db3 | ||
|  | 9150d6bd2a | ||
|  | 10f29b66b8 | ||
|  | 259aec52a9 | ||
|  | 6554bf9f08 | ||
|  | d8558f5956 | ||
|  | 18bc701e8b | ||
|  | a47795fd3f | ||
|  | a55e8b268c | ||
|  | e8106f04b5 | ||
|  | bdc1dbf08a | ||
|  | 06eeb2088b | ||
|  | 7da9ec2c75 | ||
|  | 297ff10c14 | ||
|  | 1305f4314d | ||
|  | 55474c0599 | ||
|  | 687c79ae81 | ||
|  | 829a353b14 | ||
|  | aced474dc5 | ||
|  | 7c08d5f198 | ||
|  | c546787994 | ||
|  | 31fa530845 | ||
|  | 120714ecfc | ||
|  | 615874d2ec | ||
|  | 67b195c942 | ||
|  | 75689cee96 | ||
|  | 8ba77e95a4 | ||
|  | 7967a8416c | ||
|  | 934fbca860 | ||
|  | e78c8038c7 | ||
|  | f64a42ebb5 | ||
|  | 9164cff234 | ||
|  | 017f98e87e | ||
|  | f33d8670aa | ||
|  | e79db7de89 | ||
|  | 845a42e73a | ||
|  | e58c25aa18 | ||
|  | 8ec44b63b1 | ||
|  | 41907936a1 | ||
|  | 406d2cefc5 | ||
|  | 41cdbc0ec4 | ||
|  | c6ec261c5c | ||
|  | a2db1a3275 | ||
|  | 1e8f2f0e83 | ||
|  | 8491abe142 | ||
|  | d4302538bf | ||
|  | c34e3765ef | ||
|  | 1f86bc06ef | ||
|  | 7e892fac2d | ||
|  | 23789b0692 | ||
|  | 89adbe4127 | ||
|  | 11940fb98e | ||
|  | 13ae335811 | ||
|  | b2dc6ad2fa | ||
|  | 85ca926fd0 | ||
|  | 676698a59b | ||
|  | 22408ecd58 | ||
|  | d36acc7ec7 | ||
|  | a5a68acfec | ||
|  | 7431651666 | ||
|  | 4f91bfd907 | ||
|  | 8d2086870b | ||
|  | 1511ef1a98 | ||
|  | 4e030ce1e8 | ||
|  | 2507ad274b | ||
|  | fb1c149eb9 | ||
|  | d4662f428a | ||
|  | 73c779c13a | ||
|  | b8cc164af1 | ||
|  | 64a391b5f8 | ||
|  | 21a202dd16 | ||
|  | 187dd2fdc3 | ||
|  | c18f3f0b33 | ||
|  | 7162935028 | ||
|  | 9215a73b6c | ||
|  | edd840794c | ||
|  | c30a6eb1aa | ||
|  | 233642af29 | ||
|  | 7dffd0a03e | ||
|  | f7bc3ff49d | ||
|  | 53aabe3cdb | ||
|  | 09b8d7cfc9 | ||
|  | 1512afc7e6 | ||
|  | dde0c76112 | ||
|  | f14b6f2ba2 | ||
|  | 4fced276c4 | ||
|  | 7590471d62 | ||
|  | 0b6bcf6739 | ||
|  | 3a5ce86ed9 | ||
|  | 7b298939e2 | ||
|  | f1f6aa7d80 | ||
|  | 7ce7dd7252 | ||
|  | 01aa556ede | ||
|  | 48ad39c1c7 | ||
|  | 9cab034448 | ||
|  | 0d7a22634c | ||
|  | 3e3bc5c06d | ||
|  | 2a81e468c7 | ||
|  | 0ba67a363e | ||
|  | deae846864 | ||
|  | 3a0d48ad77 | ||
|  | 81d4803b4d | ||
|  | e936c7c507 | ||
|  | ad868af96e | ||
|  | cd14a45414 | ||
|  | f7cd7110ea | ||
|  | 44262bf747 | ||
|  | 0fbbabe208 | ||
|  | b39189fde3 | ||
|  | 18fc1d78f4 | ||
|  | d44a91d10b | ||
|  | 5e9829b2d8 | ||
|  | 2176deae36 | ||
|  | 7c5035aa39 | ||
|  | 5707993995 | ||
|  | f81697527c | ||
|  | 967eff4c58 | ||
|  | d5d07dd34e | ||
|  | b91cc3781d | ||
|  | 87ed0071c4 | ||
|  | 0fed48630c | ||
|  | 7b3e7c98ac | ||
|  | 09f44b0375 | ||
|  | ebfa62637e | ||
|  | cb2cc05cac | ||
|  | f9c9131d81 | ||
|  | 1be9a1cbc7 | ||
|  | b7fda8ecf0 | ||
|  | db16392821 | ||
|  | 7127f541c3 | ||
|  | 32793cc008 | ||
|  | fbaf55cb25 | ||
|  | b8d51fc4e8 | ||
|  | 0c6e05d220 | ||
|  | 4066c17a0f | ||
|  | 429f2bb8dd | ||
|  | 112f4fc4f0 | ||
|  | ecfbd6280f | ||
|  | bf84409839 | ||
|  | a7ce72cae0 | ||
|  | 28402ff7d8 | ||
|  | e1d213d1a3 | ||
|  | c610dd96f5 | ||
|  | 2ba3818b65 | ||
|  | 0e1a5a375a | ||
|  | cfc3daeb65 | ||
|  | 6359f1950e | ||
|  | d2f581853d | ||
|  | 030cb285da | ||
|  | af45409959 | ||
|  | d9a9bc35e3 | ||
|  | c911c3352c | ||
|  | 654abbac25 | ||
|  | 46d5f42c9d | ||
|  | 1509da1215 | ||
|  | 98a99d96aa | ||
|  | d62d81af17 | ||
|  | dba67eb927 | ||
|  | 548c30d6a0 | ||
|  | 1b8b9186a8 | ||
|  | a8cfcfb371 | ||
|  | f7a414bc29 | ||
|  | e05cd1d66b | ||
|  | 511cd90c44 | ||
|  | 8fb2d8da88 | ||
|  | 2fce332ed7 | ||
|  | b23f1eb145 | ||
|  | f694072b5a | ||
|  | 10de266e0f | ||
|  | 71811ed04f | ||
|  | e9638ef95e | ||
|  | 5226bb5596 | ||
|  | b9984b6df4 | ||
|  | 9c11835fee | ||
|  | d9e13d6b99 | ||
|  | dede076835 | ||
|  | c929782e0d | ||
|  | a43c7e36f8 | ||
|  | b95cec9c32 | ||
|  | 9a7d9abe3c | ||
|  | c77b620453 | ||
|  | b348084e2a | ||
|  | ff1811ef90 | ||
|  | 39cf4a7576 | ||
|  | 21b67625a6 | ||
|  | fb0311e675 | ||
|  | 8a14b4afff | ||
|  | e42701599a | ||
|  | 352b1b43f2 | ||
|  | 2922ebd095 | ||
|  | a9e72085dd | ||
|  | ed3d194c90 | ||
|  | 125c53827b | ||
|  | 38781807cd | ||
|  | c046943269 | ||
|  | fe36cd86bb | ||
|  | 401410089c | ||
|  | fa23337519 | ||
|  | ae5421f76e | ||
|  | a2e2b429d5 | ||
|  | ac852b23b3 | ||
|  | e12389a002 | ||
|  | da18e42d2a | ||
|  | 93bdaba8ee | ||
|  | 4cb08a61d5 | ||
|  | 133692ca92 | ||
|  | 4bcc4b3cf8 | ||
|  | 4eb20ca4b6 | ||
|  | 69f7343be5 | ||
|  | 19b28a58d6 | ||
|  | 3c33a93b9c | ||
|  | f2e16dfb21 | ||
|  | 0f689e8051 | ||
|  | 5b44e6ef64 | ||
|  | 49e4ade66f | ||
|  | 3bae27d039 | ||
|  | a77f0c606d | ||
|  | f1de64dcaf | ||
|  | feb672c3cd | ||
|  | a90b463a7d | ||
|  | 5f5f25c978 | ||
|  | 351ea8bc1c | ||
|  | b34edcbf87 | ||
|  | 160519e1fe | ||
|  | 44d626e12e | ||
|  | efb9dc51c9 | ||
|  | deb51434fd | ||
|  | 501070bfb0 | ||
|  | 712958d8c8 | ||
|  | 4d8d944fe5 | ||
|  | 0042e42160 | ||
|  | 85509ea251 | ||
|  | 6063854d06 | ||
|  | 456f8a90b1 | ||
|  | 980246d07a | ||
|  | 141c30b173 | ||
|  | 22f9b03fce | ||
|  | be2db504b9 | ||
|  | cac6f5234f | ||
|  | eb6b32b6ee | ||
|  | 07acc9529e | ||
|  | f7f0152573 | ||
|  | 153533f1d5 | ||
|  | 11622c586a | ||
|  | 7396bb508a | ||
|  | 7df6530f3a | ||
|  | 80787456fa | ||
|  | 4446ac1ca3 | ||
|  | 220039ab00 | ||
|  | 12f2250ab5 | ||
|  | 0c33aa16a1 | ||
|  | 72908b02fe | ||
|  | 223aa04424 | ||
|  | e53248cca6 | ||
|  | c11d661b39 | ||
|  | 4212a08337 | ||
|  | c0553fa9eb | ||
|  | 7f26fafed7 | ||
|  | 3e9309c003 | ||
|  | 1017707475 | ||
|  | e8ff5da209 | ||
|  | 03ed3ac1b0 | ||
|  | 2c97208e74 | ||
|  | a458e81f8d | ||
|  | 83289bc801 | ||
|  | ba2ac6a7b5 | ||
|  | 245b6da577 | ||
|  | 8875f924b0 | ||
|  | ad7868ebe1 | ||
|  | 5effc6ec90 | ||
|  | 4cc9ceabd2 | ||
|  | 464c918134 | ||
|  | 2456adcb68 | ||
|  | 45bc967f30 | ||
|  | d6d4d29257 | ||
|  | 33fdfdc8c0 | ||
|  | 80c8712b2a | ||
|  | 957e3eb93c | ||
|  | 110e1afa8e | ||
|  | 1da8f68871 | ||
|  | 513ddb4cca | ||
|  | 3bdfcb8542 | ||
|  | aee758eca2 | ||
|  | 47ef7fffce | ||
|  | 58d6256607 | ||
|  | b854fcdb72 | ||
|  | 27ca75d94f | ||
|  | bb15f78af0 | ||
|  | ccc9e18132 | ||
|  | d55108ab60 | ||
|  | 84adbcb683 | ||
|  | 0cb5e4553b | ||
|  | 264407b707 | ||
|  | eb5ec58453 | ||
|  | 39c2a757be | ||
|  | 8cdc05f582 | ||
|  | 5f4778c852 | ||
|  | 70add44fc1 | ||
|  | fa617d2e9d | ||
|  | 3c795d365d | ||
|  | 93872ad7a3 | ||
|  | 227676c150 | ||
|  | 5f23833b43 | ||
|  | 121d51b414 | ||
|  | 0e196a59d9 | ||
|  | 63bfd23310 | ||
|  | aadcf8fed0 | ||
|  | 37390e03b4 | ||
|  | 98fc780ade | ||
|  | 1670b21123 | ||
|  | 5602aacbd2 | ||
|  | 6ddbea207f | ||
|  | 261bced822 | ||
|  | a80d1f861c | ||
|  | c541340ef5 | ||
|  | 434af0ae64 | ||
|  | c6379ca1d4 | ||
|  | cdbcada49b | ||
|  | 282930cb9b | ||
|  | b09c751942 | ||
|  | b2047b90b3 | ||
|  | 0c8aec30bd | ||
|  | fafaa3e69b | ||
|  | d19bb3de8d | ||
|  | 481136166c | ||
|  | 4df81a0b9e | ||
|  | da1e9c2d97 | ||
|  | 4b5a02c246 | ||
|  | 0e1572cfd7 | ||
|  | 343caa1ff6 | ||
|  | 403fb3826d | ||
|  | 3cdccb7b4e | ||
|  | d9be78cdb4 | ||
|  | 16dc8255e1 | ||
|  | 2086bfff25 | ||
|  | b9a68c0b8e | ||
|  | 74647f0e88 | ||
|  | 6e29c8bea9 | ||
|  | b36373ab81 | ||
|  | dc437aacf1 | ||
|  | e19dae9b28 | ||
|  | 424cbd4831 | ||
|  | 350feed993 | ||
|  | 7ca4aa0ff4 | ||
|  | bf00e67245 | ||
|  | c5a6e49681 | ||
|  | a509af2875 | ||
|  | 1f789bf396 | ||
|  | 0ccbc7d3d2 | ||
|  | f3c6f26f85 | ||
|  | 338c358df2 | ||
|  | 4bdaa48303 | ||
|  | 36267746da | ||
|  | 7775541eed | ||
|  | 5029be4c83 | ||
|  | 277dbacf68 | ||
|  | 0fdfb03f3c | ||
|  | 17d81bf014 | ||
|  | 568e9be07e | ||
|  | 99b0a95f8a | ||
|  | 0fdd31892a | ||
|  | 7a682604f9 | ||
|  | ce96e35d7d | ||
|  | b7fb5394a7 | ||
|  | aaa62beca7 | ||
|  | 2b58a7242b | ||
|  | 5ed919df79 | ||
|  | baf6372179 | ||
|  | 1a9063a55b | ||
|  | 87999f402f | ||
|  | 109d466260 | ||
|  | 37597eca75 | ||
|  | 5fd767b739 | ||
|  | 0e7a473116 | ||
|  | 05bf55dca8 | ||
|  | cc12ad8d86 | ||
|  | 847a7f470c | ||
|  | 95bebd6d1d | ||
|  | 8179a964ea | ||
|  | d0805d4bbb | ||
|  | f901c401b7 | ||
|  | 6ccadcb928 | ||
|  | 58b6c25d5c | ||
|  | 9cbab26202 | ||
|  | 74bcb468ca | ||
|  | 07a6ba88f4 | ||
|  | 49dff49993 | ||
|  | 68207aac80 | ||
|  | 64652b2ff0 | ||
|  | 659e8991de | ||
|  | 9f495b6dc9 | ||
|  | d8498134ad | ||
|  | 17b2320b0d | ||
|  | 36c457f483 | ||
|  | b8ec7f5e26 | ||
|  | dbc5c0d5d8 | ||
|  | fa886aa849 | ||
|  | 32e1ae2b18 | ||
|  | 61f03b0ea2 | ||
|  | c47825a820 | ||
|  | 2d7cb63c7b | ||
|  | c3d4c13936 | ||
|  | 3f51b9322f | ||
|  | b604e2bd4e | ||
|  | bcd92473d1 | ||
|  | 6f5bf9d146 | ||
|  | 490094939f | ||
|  | d0d7d2772f | ||
|  | 59091896b4 | ||
|  | 3eb1429a25 | ||
|  | bc7504c469 | ||
|  | 99dc4b8e07 | ||
|  | 807904bb86 | ||
|  | 7b8c8348f4 | ||
|  | 9c5ac26170 | ||
|  | 5db065644c | ||
|  | 0cc3a99169 | ||
|  | 2b1545145b | ||
|  | 49b7c9c8a4 | ||
|  | 114119f7c8 | ||
|  | b4ef866c10 | ||
|  | 15f75a08d5 | ||
|  | 29f9c5473d | ||
|  | ea1528aea6 | ||
|  | 18ce19a84d | ||
|  | b0fd78d68d | ||
|  | 8186d6277e | ||
|  | 599af2b1a9 | ||
|  | 82de5adbe9 | ||
|  | 82b0f85258 | ||
|  | cded58c30d | ||
|  | da17b49b81 | ||
|  | 4728cdfa7c | ||
|  | d97b30dcee | ||
|  | fa8e8ad52d | ||
|  | 7495ac8111 | ||
|  | 08619e2c06 | ||
|  | 5d4bbd5b37 | ||
|  | 9d2aef5006 | ||
|  | bcc3e5ebb0 | ||
|  | e5df51a83a | ||
|  | 97fb843f01 | ||
|  | 8afb044877 | ||
|  | 7f869868c9 | ||
|  | 31275228ac | ||
|  | 7181be8768 | ||
|  | 3b446e887a | ||
|  | 431196c391 | ||
|  | 9608d8fb46 | ||
|  | d574ca1628 | ||
|  | 8be60e2ff5 | ||
|  | 3c0fd540b1 | ||
|  | 23a7dc9a8a | ||
|  | f97e6892b6 | ||
|  | 7742901e5c | ||
|  | de68cb25d0 | ||
|  | 77d7afe505 | ||
|  | 68fb6c2c27 | ||
|  | a47c031ad1 | ||
|  | 817049456c | ||
|  | e1a061789f | ||
|  | 28573ba772 | ||
|  | 880b9413f6 | ||
|  | 9a7c4b21a9 | ||
|  | ac56038eca | ||
|  | 4dd2fb6903 | ||
|  | 0baec61f06 | ||
|  | d4751788d1 | ||
|  | ae68c061d1 | ||
|  | b0387245f0 | ||
|  | c2d06a4a23 | ||
|  | 270108abb7 | ||
|  | e76c33232d | ||
|  | 58ff2dc492 | ||
|  | 13c45a0e96 | ||
|  | 90cb86911a | ||
|  | be7b1a1bd4 | ||
|  | 132a3c6705 | ||
|  | 5e73257557 | ||
|  | e83346fbbb | ||
|  | 2dd47a2103 | ||
|  | f31e530b6e | ||
|  | eb50f3fa9c | ||
|  | 8417fe4fdb | ||
|  | 0f1c15a6ca | ||
|  | 9345c4fb7f | ||
|  | 5e0758917b | ||
|  | f56839ec6b | ||
|  | cbb23a42e2 | ||
|  | 5a59c286d0 | ||
|  | 2e8c600d7a | ||
|  | e851cb1cbc | ||
|  | 3da03da32a | ||
|  | 3ec8924e7f | ||
|  | a04722b612 | ||
|  | f9a7857a90 | ||
|  | 58f772c74e | ||
|  | a425c7e260 | ||
|  | 809885afd0 | ||
|  | bf9b4b993f | ||
|  | d94a26f0f4 | ||
|  | bd9c9cedca | ||
|  | 651e94bd94 | ||
|  | 162b6f1a74 | ||
|  | 865a253eb5 | ||
|  | 9b3781abf1 | ||
|  | d89243a0d3 | ||
|  | b4cefc64b4 | ||
|  | 2fd26587e5 | ||
|  | 282a351859 | ||
|  | a84b848ea9 | ||
|  | d329320fc2 | ||
|  | bc096554b5 | ||
|  | 5902d878d8 | ||
|  | 4a133ca36f | ||
|  | f7252f919a | ||
|  | e05a03a842 | ||
|  | dcce8276b8 | ||
|  | fd47947e55 | ||
|  | ae151df2eb | ||
|  | 79de188683 | ||
|  | 6e5c788e13 | ||
|  | f53606007d | ||
|  | a4ac418bc9 | ||
|  | a8c09d0bdb | ||
|  | 871105a48a | ||
|  | 3b61129ade | ||
|  | f471c79b59 | ||
|  | dfd9443f74 | ||
|  | a36ff9e365 | ||
|  | 12e65bbf26 | ||
|  | ab9841e60b | ||
|  | 7a52f12e57 | ||
|  | 11fd4506ac | ||
|  | 0c9c68030e | ||
|  | 55d6eddbb2 | ||
|  | 8341e60edb | ||
|  | 6273a1ca73 | ||
|  | 1b83ebdf89 | ||
|  | fef7f0506f | ||
|  | f44eb4e383 | ||
|  | 05df485c4a | ||
|  | 44857c526b | ||
|  | b8ad5d5d32 | ||
|  | e3e0d00e21 | ||
|  | a9b1ea9690 | ||
|  | 8e5dd0f8d9 | ||
|  | 3b0c8f6d92 | ||
|  | 21058c2227 | ||
|  | f3b8ae0781 | ||
|  | d590b004c1 | ||
|  | 02e21141c6 | ||
|  | f839a3087d | ||
|  | f458815541 | ||
|  | 7ba754d2a4 | ||
|  | 09706e4ae2 | ||
|  | d18de4c541 | ||
|  | 001c7bfdbc | ||
|  | d4e04dc712 | ||
|  | 8650cb5217 | ||
|  | 0eaaddeb95 | ||
|  | 1cf8663f20 | ||
|  | 5130259552 | ||
|  | ba5e19a015 | ||
|  | c0400fa986 | ||
|  | 51179d10ce | ||
|  | 78752f9178 | ||
|  | 762db417d7 | ||
|  | 85bdccbc06 | ||
|  | 9f8cb99340 | ||
|  | 87b90bb04b | ||
|  | e961d88277 | ||
|  | 5754c11e34 | ||
|  | 7bd88c1bb8 | ||
|  | 445b686c6c | ||
|  | 0cb7b75214 | ||
|  | a08399dfee | ||
|  | 4016808fa4 | ||
|  | 8635849977 | ||
|  | 1a9ed4d4fe | ||
|  | e7b3246dd0 | ||
|  | 19589aec57 | ||
|  | 4d33ff0417 | ||
|  | 93a5ab5b33 | ||
|  | 59ada06cdf | ||
|  | ae650849b0 | ||
|  | 3e8f9a6b53 | ||
|  | 79362b0dba | ||
|  | 3e3df06d57 | ||
|  | 6b220eb1c5 | ||
|  | a1c61cae11 | ||
|  | d48a917bf3 | ||
|  | 646b6dafb2 | ||
|  | 8d10f33a3f | ||
|  | 5d603b2f80 | ||
|  | 0e1b08ff54 | ||
|  | befc22d718 | ||
|  | 4a62e80967 | ||
|  | ee9ef9f2c1 | ||
|  | 93dcb68437 | ||
|  | 0691cc7909 | ||
|  | d82f34fe59 | ||
|  | d2313b30af | ||
|  | 329719472a | ||
|  | a2fcab47d4 | ||
|  | 4ab5951c25 | ||
|  | 403cabb201 | ||
|  | 3da7c5d3e2 | ||
|  | c5e0de51aa | ||
|  | c581f1bba4 | ||
|  | b8ac9c2edd | ||
|  | 1027ee2481 | ||
|  | 2f311f7821 | ||
|  | a98c95b514 | ||
|  | 5bbbae5b23 | ||
|  | f9c9b9f924 | ||
|  | 5921208ea6 | ||
|  | f89c78abd1 | ||
|  | 74d3b9334c | ||
|  | 919fc66b9d | ||
|  | 400fb5a5bb | ||
|  | 3bb4f9085c | ||
|  | 714c6cec3c | ||
|  | cb69921202 | ||
|  | 277a0adac9 | ||
|  | 02d14f504f | ||
|  | 1ab7664a60 | ||
|  | 1be46ffb7e | ||
|  | 6ca52aed0d | ||
|  | 74e20970e2 | ||
|  | 93f2b6b4d8 | ||
|  | 00e616b57a | ||
|  | e436673304 | ||
|  | ce04d3ce41 | ||
|  | 4e46bf4697 | ||
|  | 9b95508f99 | ||
|  | c8c24456c1 | ||
|  | 80a6e82e1b | ||
|  | 80cec20d38 | ||
|  | 26cb22020d | ||
|  | 09d05d09c9 | ||
|  | 160c91f908 | ||
|  | 58f41bcd42 | ||
|  | 0235429995 | ||
|  | f79697e117 | ||
|  | 6f0019c71e | ||
|  | 1a04a18245 | ||
|  | 0cf3ff8209 | ||
|  | 7f56091fbd | ||
|  | 391f9b31f6 | ||
|  | 1d7c0f504a | ||
|  | 9cdc62f918 | ||
|  | 6027d0481e | ||
|  | 277fb92f9e | ||
|  | 79b6c3c1af | ||
|  | ad17174119 | ||
|  | 6c2692eec0 | ||
|  | 08640e8575 | ||
|  | 4a2575136f | ||
|  | e792afad17 | ||
|  | 5ecc4b027d | ||
|  | bc540f0cf0 | ||
|  | a24b14c465 | ||
|  | c3f36c3123 | ||
|  | 1d34da7557 | ||
|  | 27d74a4327 | ||
|  | 8a20cc682c | ||
|  | 9b20359e7b | ||
|  | 8866d0ccef | ||
|  | 7fa91a9971 | ||
|  | 28d1f3eef0 | ||
|  | f321cf6655 | ||
|  | 14ade737da | ||
|  | 41b1b1f141 | ||
|  | 25dfd47d32 | ||
|  | 6afa9c8b92 | ||
|  | 2fc449da4c | ||
|  | 5dd3b8cf9d | ||
|  | e834fa0050 | ||
|  | 9a97401606 | ||
|  | 410a3fef18 | ||
|  | 969b9814d5 | ||
|  | 2275e27b87 | ||
|  | 62b06cd204 | ||
|  | 350934ca21 | ||
|  | 6332673434 | ||
|  | f217840998 | ||
|  | 089ec35ceb | ||
|  | fecd0b809e | ||
|  | 4707a46561 | ||
|  | 616533c5a8 | ||
|  | c5b2991821 | ||
|  | c36d0fdc7c | ||
|  | 544e09cf4b | ||
|  | c110dc9e6a | ||
|  | 3bf37d6afd | ||
|  | b80ae5796b | ||
|  | 2083632299 | ||
|  | 3ca2f8ac9e | ||
|  | 7172432084 | ||
|  | 0e6afd147f | ||
|  | 46275a4f43 | ||
|  | 1dca378e03 | ||
|  | 06669594b1 | ||
|  | c09ac58ac0 | ||
|  | e01d32ef1a | ||
|  | 5ea3bcf59e | ||
|  | aa8b14b7ee | ||
|  | e1722cf739 | ||
|  | 7a7f70e15d | ||
|  | b3c3ec16e5 | ||
|  | 149f863951 | ||
|  | 684d09faac | ||
|  | 8a42691c80 | ||
|  | d591b3dd98 | ||
|  | a90fb4d8b6 | ||
|  | ebd08d9c63 | ||
|  | 71731d223b | ||
|  | 726ea5e01e | ||
|  | 16c7d2964b | ||
|  | 5a6e494bda | ||
|  | 88c6d89fbb | ||
|  | de12da18da | ||
|  | 8d10736934 | ||
|  | 2328e02d82 | ||
|  | 87cd5fca90 | ||
|  | b70cb726c5 | ||
|  | 295811ed5a | ||
|  | 4bc55551c6 | ||
|  | 2b8c6dc8f9 | ||
|  | 8b27380feb | ||
|  | 8de3a90851 | ||
|  | f8bb94d721 | ||
|  | 0c6d06e7bb | ||
|  | b0aa5d3af2 | ||
|  | 27d09713fd | ||
|  | ff18852879 | ||
|  | e515c91e5e | ||
|  | 1d5800c4f7 | ||
|  | de8f190945 | ||
|  | f371e3c8d3 | ||
|  | b15a6290a7 | ||
|  | 0f151db355 | ||
|  | fa99b75d1f | ||
|  | 4a299c1f39 | ||
|  | 30a2015a68 | ||
|  | c7c8a4891f | ||
|  | fe9fc6b459 | ||
|  | 2113fb490d | ||
|  | 0afedbd252 | ||
|  | 3dec38450a | ||
|  | d7a00b05e3 | ||
|  | ff2cc8c887 | ||
|  | 0571a96cea | ||
|  | b7b457b076 | ||
|  | d2c12005b2 | ||
|  | 25f26d7e5f | ||
|  | 9d5724e1a0 | ||
|  | 784d23ec87 | ||
|  | 709689a7ee | ||
|  | 35d5d3d995 | ||
|  | 630a8d8a4e | ||
|  | 54eb1d9055 | ||
|  | cb63caea61 | ||
|  | 8e046bb022 | ||
|  | 189b53b8c4 | ||
|  | 9b7277d464 | ||
|  | 551a65c069 | ||
|  | 4c21a697f4 | ||
|  | a8506c07ae | ||
|  | b0feb85b5c | ||
|  | f371eba8ad | ||
|  | 265fa52ace | ||
|  | c1f5322d38 | ||
|  | 4415e00b38 | ||
|  | d4e46c5a9c | ||
|  | bf5b9949fe | ||
|  | 3c11a2b1da | ||
|  | 1248868169 | ||
|  | 930b95a548 | ||
|  | 27c9f68c7c | ||
|  | 358d4d86a7 | ||
|  | d55eea2239 | ||
|  | 4507954ea5 | ||
|  | 8e0a83f8d8 | ||
|  | b6ec09e6cf | ||
|  | ed4e90623d | ||
|  | 38cdb48748 | ||
|  | 71bfe9b745 | ||
|  | 9e7645a167 | ||
|  | 6dccc37143 | ||
|  | 3310310d8c | ||
|  | abb499aad8 | ||
|  | 1afc09b08a | ||
|  | 0e86d72f05 | ||
|  | c9857a2764 | ||
|  | 701ba3902c | ||
|  | bb3ec970a9 | ||
|  | 1d023e6db5 | ||
|  | 1bd906ecb3 | ||
|  | 7cbffdb86b | ||
|  | b979196ffd | ||
|  | 2949db5f49 | ||
|  | 47c3ed9705 | ||
|  | 51ca3109eb | ||
|  | 2bcb79dc44 | ||
|  | ecec985649 | ||
|  | 994908549d | ||
|  | e00f059a4a | ||
|  | 6808e0d531 | ||
|  | 410c95308a | ||
|  | bec1f23616 | ||
|  | 34596b7f83 | ||
|  | 5ca7169ee5 | ||
|  | 3300aaa1b9 | ||
|  | 54afc8a4a1 | ||
|  | f19f4310f4 | ||
|  | 444125a7e1 | ||
|  | 56cbb69401 | ||
|  | 70870ffcd2 | ||
|  | a556d91673 | ||
|  | 8ecbde8e1e | ||
|  | a24b293818 | ||
|  | cab5ebf94b | ||
|  | a54b5baef2 | ||
|  | c324fe204e | ||
|  | 37d972ed9e | ||
|  | e4a3b1cb05 | ||
|  | 49538f272e | ||
|  | 1283232144 | ||
|  | 2f9891f0aa | ||
|  | 865a2b1fb0 | ||
|  | 1fde62eeb6 | ||
|  | 6754cd48e2 | ||
|  | ccb477687a | ||
|  | be0e6c8925 | ||
|  | 1c2cb947c0 | ||
|  | 4663eec950 | ||
|  | fff3c1eb36 | ||
|  | 4b7434d1e8 | ||
|  | 8cc35a60e6 | ||
|  | 130653a1aa | ||
|  | 1dcbebd130 | ||
|  | faf306ad23 | ||
|  | d11cdcd5d2 | ||
|  | 0e59bd0bf3 | ||
|  | c0c6154ec1 | ||
|  | cb5384c2fb | ||
|  | 038c836fe5 | ||
|  | 6b0f3570b9 | ||
|  | 71de0d04f3 | ||
|  | 99debff5d2 | ||
|  | 3bac6fcb27 | ||
|  | 4b842b81a0 | ||
|  | e2e4d048ab | ||
|  | 5574c368cd | ||
|  | 0d34f7b92e | ||
|  | 5be0632e01 | ||
|  | 79ea0bf9f4 | ||
|  | b1929cb688 | ||
|  | 5ad98700e5 | ||
|  | a54624b697 | ||
|  | ca34c865af | ||
|  | dde57b1eca | ||
|  | 264b06938e | ||
|  | 99edb303e2 | ||
|  | 104cc24dfc | ||
|  | fcbcbac889 | ||
|  | b86d19028c | ||
|  | 4f17a251d3 | ||
|  | 731a823cc2 | ||
|  | 3d79fe2bf4 | ||
|  | 474399154f | ||
|  | 19f5153d0e | ||
|  | ce11271866 | ||
|  | 86cf353296 | ||
|  | 36df5dc721 | ||
|  | 1e44a9c942 | ||
|  | 8685cf9036 | ||
|  | 2232870b09 | ||
|  | b68acd101e | ||
|  | 173ba9b2b5 | ||
|  | 64ed1f87d3 | ||
|  | 1ca085ec4a | ||
|  | e332b7535c | ||
|  | 79eb613b3e | ||
|  | 5a79ec28d1 | ||
|  | 97e65a02c0 | ||
|  | e87c786b77 | ||
|  | 251d30d47f | ||
|  | 761d0a0f18 | ||
|  | ae4b1e74f9 | ||
|  | ac44618e58 | ||
|  | d634cbf924 | ||
|  | 21db0e6275 | ||
|  | ce426fd3f4 | ||
|  | b5d4c91207 | ||
|  | b43263be77 | ||
|  | 207cf7ca24 | ||
|  | 00e34758c4 | ||
|  | 7a3f878c11 | ||
|  | b8439598bc | ||
|  | 7fb0818923 | ||
|  | a7c435adc4 | ||
|  | dd90aabad6 | ||
|  | 5bded1946e | ||
|  | 3642e96154 | ||
|  | 9da09ee3a6 | ||
|  | 141c140f53 | ||
|  | 84b660d2ef | ||
|  | 6beedba957 | ||
|  | d73982819b | ||
|  | 6ac5bcc907 | ||
|  | 389d4d10f1 | ||
|  | 89dcbd0229 | ||
|  | ad8caa2b51 | ||
|  | 9c42241269 | ||
|  | 38dd45cce2 | ||
|  | aa90253c62 | ||
|  | 41576652dc | ||
|  | 74830854ca | ||
|  | 2542b1b44d | ||
|  | 51f5e60224 | ||
|  | bb5885e2bb | ||
|  | d51bbb0008 | ||
|  | 49e898b189 | ||
|  | 42c4fe5705 | ||
|  | 4b5f2c36b9 | ||
|  | 935dca67e6 | ||
|  | d431790e19 | ||
|  | 56310b7bd4 | ||
|  | f15e21faad | ||
|  | 44aa6a2b38 | ||
|  | 9f32347c01 | ||
|  | 3d5b229c46 | ||
|  | 5863ccc0a0 | ||
|  | d220a16b99 | ||
|  | 79784fc8ee | ||
|  | a83bc53c6a | ||
|  | 85de0b91b1 | ||
|  | d91c6e5702 | ||
|  | ab7689d188 | ||
|  | c81455c760 | ||
|  | 39bfc97a7a | ||
|  | 88aac78282 | ||
|  | 863e830d24 | ||
|  | 6c705728a4 | ||
|  | 7f00279ffb | ||
|  | c198d0079e | ||
|  | 1135d5a971 | ||
|  | e299fa27a0 | ||
|  | 46e0bc940a | ||
|  | 9a552012f2 | ||
|  | 6498d385ee | ||
|  | dd00f2016f | ||
|  | 64d25e6522 | ||
|  | 1462ab08de | ||
|  | a8e93a594d | ||
|  | dea30b37ef | ||
|  | 39571dda0b | ||
|  | c7d801b6c2 | ||
|  | 57731be689 | ||
|  | f00524e518 | ||
|  | 5567c40bae | ||
|  | 5d1a7613dd | ||
|  | fa768dc112 | ||
|  | 27fb51d37f | ||
|  | d02db3864e | ||
|  | a26c3036a7 | ||
|  | 0af346aad8 | ||
|  | c3c8ee7292 | ||
|  | 5fbdfa66d9 | ||
|  | 15b75715ee | ||
|  | 1fd92b6cbd | ||
|  | 2918b5d74e | ||
|  | 669c5be344 | ||
|  | e1b40ec46e | ||
|  | 15767538eb | ||
|  | de2b16c464 | ||
|  | d5e6b38450 | ||
|  | a636e87a4f | ||
|  | 50d5b4fa37 | ||
|  | f6d26392fb | ||
|  | 2705bcce15 | ||
|  | 379a31ece6 | ||
|  | daa593d225 | ||
|  | ed8340affa | ||
|  | b3c1e72577 | ||
|  | 3da09d140a | ||
|  | 51f254bbb1 | ||
|  | 30ee456d4c | ||
|  | 460d5f2517 | ||
|  | 5da1fc8445 | ||
|  | 1166b43946 | ||
|  | 0a6903c4c3 | ||
|  | 62fae9af93 | ||
|  | 509a1c2eb5 | ||
|  | 8b94bbbc5e | ||
|  | bb923d2b7d | ||
|  | 38adc72954 | ||
|  | 362c7c57fa | ||
|  | 6529b7eebf | ||
|  | 439c98a6e5 | ||
|  | 32258ef666 | ||
|  | 176e088d4e | ||
|  | 4fe57ba025 | ||
|  | 2818e56932 | ||
|  | 5428a19617 | ||
|  | b58cbca61a | ||
|  | 5fc6a03784 | ||
|  | eb4ad0ba1b | ||
|  | 72cdd1ea50 | ||
|  | 18769f0b8f | ||
|  | b7d92c3c12 | ||
|  | b976101dca | ||
|  | 8943b670a4 | ||
|  | c92ff7c622 | ||
|  | 301b5e1721 | ||
|  | 4e50b9b479 | ||
|  | f8b7b8cc28 | ||
|  | 2a6ea74be7 | ||
|  | 6d6a0c12cd | ||
|  | 784a03300a | ||
|  | 392f578567 | ||
|  | a91b1d2dd2 | ||
|  | 400b3d961e | ||
|  | 4f128470bd | ||
|  | fe06f41136 | ||
|  | f81a99565e | ||
|  | 81e146650b | ||
|  | bd4e04d331 | ||
|  | 7663d2c64b | ||
|  | 443c3c2802 | ||
|  | 17a546af5d | ||
|  | 71faf46735 | ||
|  | ac28744df6 | ||
|  | adaf304b4e | ||
|  | 16b13f9768 | ||
|  | d64bf98dc0 | ||
|  | 71f57d13fa | ||
|  | 469c10e45f | ||
|  | 62def596af | ||
|  | aa10844d9e | ||
|  | be52079182 | ||
|  | 255aca8789 | ||
|  | 117f4a282d | ||
|  | e1ea65525f | ||
|  | d0a3495b5f | ||
|  | 9e9e0d6592 | ||
|  | cb5f9ba97d | ||
|  | 34538f2ced | ||
|  | 2575644920 | ||
|  | b4b43a9e9e | ||
|  | df97b20913 | ||
|  | 9e3cc379ed | ||
|  | c1d78a94a2 | ||
|  | 7f4cbba076 | ||
|  | bdca84fe72 | ||
|  | cf8fd7103b | ||
|  | 8e8cdbd413 | ||
|  | 30f01681d4 | ||
|  | ecf1ad8da1 | ||
|  | 42dc112a13 | ||
|  | 58276cefce | ||
|  | 4b6501a739 | ||
|  | 724085e068 | ||
|  | 21fab3ef9f | ||
|  | db8837f4ce | ||
|  | 5781cdf6da | ||
|  | 874eb1602f | ||
|  | 82149917b7 | ||
|  | f11d8a5bd8 | ||
|  | f0d7d10fe7 | ||
|  | 9d4d9ce978 | ||
|  | 96a38602b8 | ||
|  | 90d3558d31 | ||
|  | e491a56dd0 | ||
|  | 4d8eb61924 | ||
|  | 17fab541c6 | ||
|  | 91de35e8e9 | ||
|  | f61964676a | ||
|  | 41a34c19bb | ||
|  | d90810d127 | ||
|  | 7f3d281faa | ||
|  | 812c306805 | ||
|  | fc1c59f374 | ||
|  | 35eac1e3ff | ||
|  | e16041d7fa | ||
|  | b8fc84ecc8 | ||
|  | 572c576e15 | ||
|  | 9df7f80fbb | ||
|  | f003400135 | ||
|  | ca7616c1d2 | ||
|  | a4a2bfdf35 | ||
|  | eb6bbb6e78 | ||
|  | 4d0172f634 | ||
|  | 3b61e0e126 | ||
|  | 1540a91835 | ||
|  | 2bcce9eed0 | ||
|  | 1e53564386 | ||
|  | d1c72706ef | ||
|  | bd9e531257 | ||
|  | 48436424db | ||
|  | 4f10d7f859 | ||
|  | 80e5a29444 | ||
|  | 0ec8a4a160 | ||
|  | 810bf7af0c | ||
|  | e7825206bf | ||
|  | 2b887c336a | ||
|  | 48ecd32d5d | ||
|  | 1f5a0987cb | ||
|  | f33a9d162a | ||
|  | c2919bcdb0 | ||
|  | 120d554a6b | ||
|  | 44f268a7ee | ||
|  | 3c7a0bcd85 | ||
|  | 8e2e9e9331 | ||
|  | 91c26fc046 | ||
|  | afcfe58add | ||
|  | 8d423be223 | ||
|  | 03b7314550 | ||
|  | 1a7e425780 | ||
|  | 8bc5faff3c | ||
|  | 2676278a66 | ||
|  | 6376b3baf3 | ||
|  | e569abe740 | ||
|  | 71be9ef92a | ||
|  | 4990c4903d | ||
|  | 9d468e2383 | ||
|  | 109cac013c | ||
|  | 0d8a9921cd | ||
|  | 2a5f5f7312 | ||
|  | fe54fbefbb | ||
|  | fc824b8d06 | ||
|  | d91a7b6d0e | ||
|  | aa4b3f93fa | ||
|  | efe8225d18 | ||
|  | b2c0f8c158 | ||
|  | 66dce8794d | ||
|  | 30d54407e6 | ||
|  | 6324a92ec5 | ||
|  | 67e7b5c124 | ||
|  | 35099d9b2f | ||
|  | e07f7b54e0 | ||
|  | 5c409929b4 | ||
|  | 1a504fdde9 | ||
|  | 4b06fd511b | ||
|  | def6727286 | ||
|  | bedaa0db16 | ||
|  | 90640a4fcf | ||
|  | 0142d07f10 | ||
|  | c9d85cfc7d | ||
|  | 64304c1991 | ||
|  | 993adc3578 | ||
|  | 8813bd26f6 | ||
|  | 35925de320 | ||
|  | 3b426a3f07 | ||
|  | 5104fd5dcf | ||
|  | a5a9ca9e46 | ||
|  | ba0f07e3b2 | ||
|  | 8614475324 | ||
|  | 744dda144b | ||
|  | 13d47915f4 | ||
|  | 3059b85e41 | ||
|  | 184ea4a67f | ||
|  | 8032f536ed | ||
|  | fba3870ef1 | ||
|  | 2915ee08ea | ||
|  | 86b76a3e75 | ||
|  | bc1dca3f6f | ||
|  | 5db1820123 | ||
|  | 657c35fb86 | ||
|  | 9432a84468 | ||
|  | 15a5bc02ef | ||
|  | f011be9347 | ||
|  | b6094fdb34 | ||
|  | 9e6ab9f585 | ||
|  | 869d2c02fa | ||
|  | 3b1dca0e70 | ||
|  | 595358fa69 | ||
|  | 8a8ec79c6c | ||
|  | 6252446bd3 | ||
|  | 403ceebff9 | ||
|  | 4767882ed3 | 
| @@ -4,26 +4,16 @@ jobs: | |||||||
|     build: |     build: | ||||||
|         resource_class: medium+ |         resource_class: medium+ | ||||||
|         docker: |         docker: | ||||||
|             - image: nikolaik/python-nodejs:python3.7-nodejs8 |             - image: nikolaik/python-nodejs:python3.7-nodejs10 | ||||||
|         environment: |         environment: | ||||||
|             CONTRACTS_COMMIT_HASH: '9ed05f5' |             CONTRACTS_COMMIT_HASH: '9ed05f5' | ||||||
|         working_directory: ~/repo |         working_directory: ~/repo | ||||||
|         steps: |         steps: | ||||||
|             - checkout |             - checkout | ||||||
|             - run: echo 'export PATH=$HOME/CIRCLE_PROJECT_REPONAME/node_modules/.bin:$PATH' >> $BASH_ENV |             - run: echo 'export PATH=$HOME/CIRCLE_PROJECT_REPONAME/node_modules/.bin:$PATH' >> $BASH_ENV | ||||||
|             # HACK(feuGeneA): commented out this hack as we're changing |  | ||||||
|             # from a circleci-maintained container to a different |  | ||||||
|             # container, and this hack may not apply anymore, as |  | ||||||
|             # suggested by the non-existance of `/home/circleci/.bashrc` |  | ||||||
|             # when running the command below. |  | ||||||
|             # - run: |  | ||||||
|             #       # HACK(albrow): Without this, yarn commands will sometimes |  | ||||||
|             #       # fail with a "permission denied" error. |  | ||||||
|             #       name: Set npm path |  | ||||||
|             #       command: npm set prefix=/home/circleci/npm && echo 'export PATH=$HOME/circleci/npm/bin:$PATH' >> /home/circleci/.bashrc |  | ||||||
|             - run: |             - run: | ||||||
|                   name: install-yarn |                   name: install-yarn | ||||||
|                   command: npm install --global yarn@1.17.0 |                   command: npm install --force --global yarn@1.17.0 | ||||||
|             - run: |             - run: | ||||||
|                   name: yarn |                   name: yarn | ||||||
|                   command: yarn --frozen-lockfile --ignore-engines install || yarn --frozen-lockfile --ignore-engines install |                   command: yarn --frozen-lockfile --ignore-engines install || yarn --frozen-lockfile --ignore-engines install | ||||||
| @@ -37,55 +27,61 @@ jobs: | |||||||
|             - store_artifacts: |             - store_artifacts: | ||||||
|                   path: ~/repo/packages/abi-gen/test-cli/output |                   path: ~/repo/packages/abi-gen/test-cli/output | ||||||
|             - store_artifacts: |             - store_artifacts: | ||||||
|                   path: ~/repo/packages/abi-gen-wrappers/generated_docs |                   path: ~/repo/packages/contract-wrappers/generated_docs | ||||||
|     test-contracts-ganache: |     test-exchange-ganache: | ||||||
|         resource_class: medium+ |         resource_class: medium+ | ||||||
|         docker: |         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-extensions @0x/contracts-asset-proxy @0x/contracts-exchange @0x/contracts-exchange-forwarder @0x/contracts-coordinator @0x/contracts-tests @0x/contracts-staking |  | ||||||
|     test-exchange-ganache-3.0: |  | ||||||
|         resource_class: medium+ |  | ||||||
|         docker: |  | ||||||
|             - image: nikolaik/python-nodejs:python3.7-nodejs8 |  | ||||||
|         working_directory: ~/repo |         working_directory: ~/repo | ||||||
|         steps: |         steps: | ||||||
|             - restore_cache: |             - restore_cache: | ||||||
|                   keys: |                   keys: | ||||||
|                       - repo-{{ .Environment.CIRCLE_SHA1 }} |                       - repo-{{ .Environment.CIRCLE_SHA1 }} | ||||||
|             - run: yarn wsrun test:circleci @0x/contracts-exchange |             - run: yarn wsrun test:circleci @0x/contracts-exchange | ||||||
|     test-integrations-ganache-3.0: |     test-integrations-ganache: | ||||||
|         resource_class: medium+ |         resource_class: medium+ | ||||||
|         docker: |         docker: | ||||||
|             - image: nikolaik/python-nodejs:python3.7-nodejs8 |             - image: nikolaik/python-nodejs:python3.7-nodejs10 | ||||||
|         working_directory: ~/repo |         working_directory: ~/repo | ||||||
|         steps: |         steps: | ||||||
|             - restore_cache: |             - restore_cache: | ||||||
|                   keys: |                   keys: | ||||||
|                       - repo-{{ .Environment.CIRCLE_SHA1 }} |                       - repo-{{ .Environment.CIRCLE_SHA1 }} | ||||||
|             - run: yarn wsrun test:circleci @0x/contracts-integrations |             - run: yarn wsrun test:circleci @0x/contracts-integrations | ||||||
|     test-contracts-rest-ganache-3.0: |     test-contracts-staking-ganache: | ||||||
|         resource_class: medium+ |         resource_class: medium+ | ||||||
|         docker: |         docker: | ||||||
|             - image: nikolaik/python-nodejs:python3.7-nodejs8 |             - image: nikolaik/python-nodejs:python3.7-nodejs10 | ||||||
|         working_directory: ~/repo |         working_directory: ~/repo | ||||||
|         steps: |         steps: | ||||||
|             - restore_cache: |             - restore_cache: | ||||||
|                   keys: |                   keys: | ||||||
|                       - repo-{{ .Environment.CIRCLE_SHA1 }} |                       - repo-{{ .Environment.CIRCLE_SHA1 }} | ||||||
|             - run: yarn wsrun test:circleci @0x/contracts-multisig @0x/contracts-utils @0x/contracts-exchange-libs @0x/contracts-erc20 @0x/contracts-erc721 @0x/contracts-erc1155 @0x/contracts-asset-proxy @0x/contracts-exchange-forwarder @0x/contracts-tests @0x/contracts-staking @0x/contracts-coordinator |             - run: yarn wsrun test:circleci @0x/contracts-staking | ||||||
|             # TODO(dorothy-zbornak): Re-enable after updating this package for |     test-contracts-extra-ganache: | ||||||
|             # 3.0. At that time, also remove exclusion from monorepo |         resource_class: medium+ | ||||||
|             # package.json's test script. |         docker: | ||||||
|             # - run: yarn wsrun test:circleci @0x/contracts-extensions |             - image: nikolaik/python-nodejs:python3.7-nodejs10 | ||||||
|  |         working_directory: ~/repo | ||||||
|  |         steps: | ||||||
|  |             - restore_cache: | ||||||
|  |                   keys: | ||||||
|  |                       - repo-{{ .Environment.CIRCLE_SHA1 }} | ||||||
|  |             - run: yarn wsrun test:circleci @0x/contracts-exchange-forwarder @0x/contracts-coordinator | ||||||
|  |     test-contracts-rest-ganache: | ||||||
|  |         resource_class: medium+ | ||||||
|  |         docker: | ||||||
|  |             - image: nikolaik/python-nodejs:python3.7-nodejs10 | ||||||
|  |         working_directory: ~/repo | ||||||
|  |         steps: | ||||||
|  |             - restore_cache: | ||||||
|  |                   keys: | ||||||
|  |                       - repo-{{ .Environment.CIRCLE_SHA1 }} | ||||||
|  |             - run: yarn wsrun test:circleci @0x/contracts-multisig @0x/contracts-utils @0x/contracts-exchange-libs @0x/contracts-erc20 @0x/contracts-erc721 @0x/contracts-erc1155 @0x/contracts-asset-proxy @0x/contracts-broker @0x/contracts-zero-ex | ||||||
|     test-publish: |     test-publish: | ||||||
|         resource_class: medium+ |         resource_class: medium+ | ||||||
|         docker: |         docker: | ||||||
|             - image: nikolaik/python-nodejs:python3.7-nodejs8 |             - image: nikolaik/python-nodejs:python3.7-nodejs10 | ||||||
|             - image: 0xorg/verdaccio |             - image: 0xorg/verdaccio | ||||||
|         working_directory: ~/repo |         working_directory: ~/repo | ||||||
|         steps: |         steps: | ||||||
| @@ -93,256 +89,52 @@ jobs: | |||||||
|                   keys: |                   keys: | ||||||
|                       - repo-{{ .Environment.CIRCLE_SHA1 }} |                       - repo-{{ .Environment.CIRCLE_SHA1 }} | ||||||
|             - run: |             - run: | ||||||
|                 command: yarn test:publish:circleci |                   command: yarn test:publish:circleci | ||||||
|                 no_output_timeout: 1800 |                   no_output_timeout: 1800 | ||||||
|  |             - store_artifacts: | ||||||
|  |                   path: ~/.npm/_logs | ||||||
|     test-doc-generation: |     test-doc-generation: | ||||||
|         docker: |         docker: | ||||||
|             - image: nikolaik/python-nodejs:python3.7-nodejs8 |             - image: nikolaik/python-nodejs:python3.7-nodejs10 | ||||||
|         working_directory: ~/repo |         working_directory: ~/repo | ||||||
|         steps: |         steps: | ||||||
|             - restore_cache: |             - restore_cache: | ||||||
|                   keys: |                   keys: | ||||||
|                       - repo-{{ .Environment.CIRCLE_SHA1 }} |                       - repo-{{ .Environment.CIRCLE_SHA1 }} | ||||||
|             - run: |             - run: | ||||||
|                 command: yarn test:generate_docs:circleci |                   command: yarn test:generate_docs:circleci | ||||||
|                 no_output_timeout: 1200 |                   no_output_timeout: 1200 | ||||||
|     test-rest: |     test-rest: | ||||||
|         docker: |         docker: | ||||||
|             - image: nikolaik/python-nodejs:python3.7-nodejs8 |             - image: nikolaik/python-nodejs:python3.7-nodejs10 | ||||||
|         working_directory: ~/repo |         working_directory: ~/repo | ||||||
|         steps: |         steps: | ||||||
|             - restore_cache: |             - restore_cache: | ||||||
|                   keys: |                   keys: | ||||||
|                       - repo-{{ .Environment.CIRCLE_SHA1 }} |                       - repo-{{ .Environment.CIRCLE_SHA1 }} | ||||||
|             - run: yarn wsrun test:circleci @0x/contracts-test-utils |             - run: yarn wsrun test:circleci @0x/contracts-test-utils | ||||||
|             - run: yarn wsrun test:circleci @0x/abi-gen |  | ||||||
|             # TODO (xianny): Needs to be updated for 3.0 |  | ||||||
|             # - run: yarn wsrun test:circleci @0x/asset-buyer |  | ||||||
|             # TODO: Needs to be updated for 3.0.  At that time, also remove |  | ||||||
|             # exclusion from monorepo package.json's test script. |  | ||||||
|             # - run: yarn wsrun test:circleci @0x/asset-swapper |  | ||||||
|             - run: yarn wsrun test:circleci @0x/contract-artifacts |             - run: yarn wsrun test:circleci @0x/contract-artifacts | ||||||
|             - run: yarn wsrun test:circleci @0x/assert |             - run: yarn wsrun test:circleci @0x/contract-wrappers-test | ||||||
|             - run: yarn wsrun test:circleci @0x/base-contract |             - run: yarn wsrun test:circleci @0x/migrations | ||||||
|             # TODO (xianny): Needs to be updated for 3.0 |  | ||||||
|             # - run: yarn wsrun test:circleci @0x/connect |  | ||||||
|             - run: yarn wsrun test:circleci @0x/contract-wrappers |  | ||||||
|             - run: yarn wsrun test:circleci @0x/dev-utils |  | ||||||
|             - run: yarn wsrun test:circleci @0x/json-schemas |  | ||||||
|             - run: yarn wsrun test:circleci @0x/order-utils |             - run: yarn wsrun test:circleci @0x/order-utils | ||||||
|             # TODO: Needs to be updated for 3.0. At that time, also remove |             - run: yarn wsrun test:circleci @0x/asset-swapper | ||||||
|             # exclusion from monorepo package.json's test script. |  | ||||||
|             # - run: yarn wsrun test:circleci @0x/orderbook |  | ||||||
|             - run: yarn wsrun test:circleci @0x/sol-compiler |  | ||||||
|             - run: yarn wsrun test:circleci @0x/sol-tracing-utils |  | ||||||
|             - run: yarn wsrun test:circleci @0x/sol-doc |  | ||||||
|             - run: yarn wsrun test:circleci @0x/subproviders |  | ||||||
|             - run: yarn wsrun test:circleci @0x/web3-wrapper |  | ||||||
|             - run: yarn wsrun test:circleci @0x/utils |  | ||||||
|             - run: yarn wsrun test:circleci @0x/instant |  | ||||||
|             - save_cache: |             - save_cache: | ||||||
|                   key: coverage-abi-gen-{{ .Environment.CIRCLE_SHA1 }} |                   key: coverage-contract-wrappers-test-{{ .Environment.CIRCLE_SHA1 }} | ||||||
|                   paths: |                   paths: | ||||||
|                       - ~/repo/packages/abi-gen/coverage/lcov.info |                       - ~/repo/packages/contract-wrappers-test/coverage/lcov.info | ||||||
|             - save_cache: |  | ||||||
|                   key: coverage-assert-{{ .Environment.CIRCLE_SHA1 }} |  | ||||||
|                   paths: |  | ||||||
|                       - ~/repo/packages/assert/coverage/lcov.info |  | ||||||
|             - save_cache: |  | ||||||
|                   key: coverage-asset-buyer-{{ .Environment.CIRCLE_SHA1 }} |  | ||||||
|                   paths: |  | ||||||
|                       - ~/repo/packages/asset-buyer/coverage/lcov.info |  | ||||||
|             - save_cache: |  | ||||||
|                   key: coverage-base-contract-{{ .Environment.CIRCLE_SHA1 }} |  | ||||||
|                   paths: |  | ||||||
|                       - ~/repo/packages/base-contract/coverage/lcov.info |  | ||||||
|             - save_cache: |  | ||||||
|                   key: coverage-connect-{{ .Environment.CIRCLE_SHA1 }} |  | ||||||
|                   paths: |  | ||||||
|                       - ~/repo/packages/connect/coverage/lcov.info |  | ||||||
|             - save_cache: |  | ||||||
|                   key: coverage-contract-wrappers-{{ .Environment.CIRCLE_SHA1 }} |  | ||||||
|                   paths: |  | ||||||
|                       - ~/repo/packages/contract-wrappers/coverage/lcov.info |  | ||||||
|             - save_cache: |  | ||||||
|                   key: coverage-dev-utils-{{ .Environment.CIRCLE_SHA1 }} |  | ||||||
|                   paths: |  | ||||||
|                       - ~/repo/packages/dev-utils/coverage/lcov.info |  | ||||||
|             - save_cache: |  | ||||||
|                   key: coverage-json-schemas-{{ .Environment.CIRCLE_SHA1 }} |  | ||||||
|                   paths: |  | ||||||
|                       - ~/repo/packages/json-schemas/coverage/lcov.info |  | ||||||
|             - save_cache: |             - save_cache: | ||||||
|                   key: coverage-order-utils-{{ .Environment.CIRCLE_SHA1 }} |                   key: coverage-order-utils-{{ .Environment.CIRCLE_SHA1 }} | ||||||
|                   paths: |                   paths: | ||||||
|                       - ~/repo/packages/order-utils/coverage/lcov.info |                       - ~/repo/packages/order-utils/coverage/lcov.info | ||||||
|             - save_cache: |  | ||||||
|                   key: coverage-sol-compiler-{{ .Environment.CIRCLE_SHA1 }} |  | ||||||
|                   paths: |  | ||||||
|                       - ~/repo/packages/sol-compiler/coverage/lcov.info |  | ||||||
|             - save_cache: |  | ||||||
|                   key: coverage-sol-tracing-utils-{{ .Environment.CIRCLE_SHA1 }} |  | ||||||
|                   paths: |  | ||||||
|                       - ~/repo/packages/sol-tracing-utils/coverage/lcov.info |  | ||||||
|             - save_cache: |  | ||||||
|                   key: coverage-sol-doc-{{ .Environment.CIRCLE_SHA1 }} |  | ||||||
|                   paths: |  | ||||||
|                       - ~/repo/packages/sol-doc/coverage/lcov.info |  | ||||||
|             - save_cache: |  | ||||||
|                   key: coverage-subproviders-{{ .Environment.CIRCLE_SHA1 }} |  | ||||||
|                   paths: |  | ||||||
|                       - ~/repo/packages/subproviders/coverage/lcov.info |  | ||||||
|             - save_cache: |             - save_cache: | ||||||
|                   key: coverage-web3-wrapper-{{ .Environment.CIRCLE_SHA1 }} |                   key: coverage-web3-wrapper-{{ .Environment.CIRCLE_SHA1 }} | ||||||
|                   paths: |                   paths: | ||||||
|                       - ~/repo/packages/web3-wrapper/coverage/lcov.info |                       - ~/repo/packages/web3-wrapper/coverage/lcov.info | ||||||
|     test-python: |  | ||||||
|         working_directory: ~/repo |  | ||||||
|         docker: |  | ||||||
|             - image: nikolaik/python-nodejs:python3.7-nodejs8 |  | ||||||
|             - image: 0xorg/ganache-cli:4.4.0-beta.1 |  | ||||||
|               environment: |  | ||||||
|                   VERSION: 4.4.0-beta.1 |  | ||||||
|                   SNAPSHOT_NAME: 0x_ganache_snapshot-v3-beta |  | ||||||
|             - image: 0xorg/mesh:6.0.0-beta-0xv3 |  | ||||||
|               environment: |  | ||||||
|                   ETHEREUM_RPC_URL: 'http://localhost:8545' |  | ||||||
|                   ETHEREUM_NETWORK_ID: '50' |  | ||||||
|                   ETHEREUM_CHAIN_ID: '1337' |  | ||||||
|                   USE_BOOTSTRAP_LIST: 'true' |  | ||||||
|                   VERBOSITY: 3 |  | ||||||
|                   PRIVATE_KEY_PATH: '' |  | ||||||
|                   BLOCK_POLLING_INTERVAL: '5s' |  | ||||||
|                   P2P_LISTEN_PORT: '60557' |  | ||||||
|               command: | |  | ||||||
|                   sh -c "waitForGanache () { until printf 'POST /\r\nContent-Length: 26\r\n\r\n{\"method\":\"net_listening\"}' | nc localhost 8545 | grep true; do continue; done }; waitForGanache && ./mesh" |  | ||||||
|             - image: 0xorg/launch-kit-backend:v3 |  | ||||||
|               environment: |  | ||||||
|                   RPC_URL: 'http://localhost:8545' |  | ||||||
|                   NETWORK_ID: 50 |  | ||||||
|                   WHITELIST_ALL_TOKENS: True |  | ||||||
|                   FEE_RECIPIENT: '0x0000000000000000000000000000000000000001' |  | ||||||
|                   MAKER_FEE_UNIT_AMOUNT: 0 |  | ||||||
|                   TAKER_FEE_UNIT_AMOUNT: 0 |  | ||||||
|                   MESH_ENDPOINT: 'ws://localhost:60557' |  | ||||||
|               command: | |  | ||||||
|                   sh -c "waitForMesh () { sleep 5; }; waitForMesh && node_modules/.bin/forever ts/lib/index.js" |  | ||||||
|         steps: |  | ||||||
|             - checkout |  | ||||||
|             - restore_cache: |  | ||||||
|                   key: installed-py-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }} |  | ||||||
|             - restore_cache: |  | ||||||
|                   keys: |  | ||||||
|                       - repo-{{ .Environment.CIRCLE_SHA1 }} |  | ||||||
|             - run: |  | ||||||
|                   command: | |  | ||||||
|                       cd python-packages |  | ||||||
|                       python -m ensurepip |  | ||||||
|                       ./pre_install |  | ||||||
|                       ./install |  | ||||||
|             - save_cache: |  | ||||||
|                   key: installed-py-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }} |  | ||||||
|                   paths: |  | ||||||
|                       - '/usr/local/bin' |  | ||||||
|                       - '/usr/local/lib/python3.7/site-packages' |  | ||||||
|             - run: |  | ||||||
|                   command: | |  | ||||||
|                       cd python-packages |  | ||||||
|                       ./parallel coverage run setup.py test |  | ||||||
|                       ./build_docs |  | ||||||
|             - run: |  | ||||||
|                   command: | |  | ||||||
|                       # copy generated wrappers into contract_wrappers/build, |  | ||||||
|                       # JUST so CircleCI will persist them as build artifacts. |  | ||||||
|                       cd python-packages/contract_wrappers/src/zero_ex |  | ||||||
|                       for i in contract_wrappers/[^__]*/; do mkdir -p ../../build/$i; cp $i/__init__.py ../../build/$i; done |  | ||||||
|             - save_cache: |  | ||||||
|                   key: coverage-python-contract-addresses-{{ .Environment.CIRCLE_SHA1 }} |  | ||||||
|                   paths: |  | ||||||
|                       - ~/repo/python-packages/contract_addresses/.coverage |  | ||||||
|             - save_cache: |  | ||||||
|                   key: coverage-python-contract-artifacts-{{ .Environment.CIRCLE_SHA1 }} |  | ||||||
|                   paths: |  | ||||||
|                       - ~/repo/python-packages/contract_artifacts/.coverage |  | ||||||
|             - save_cache: |  | ||||||
|                   key: coverage-python-contract-demo-{{ .Environment.CIRCLE_SHA1 }} |  | ||||||
|                   paths: |  | ||||||
|                       - ~/repo/python-packages/contract_demo/.coverage |  | ||||||
|             - save_cache: |  | ||||||
|                   key: coverage-python-json-schemas-{{ .Environment.CIRCLE_SHA1 }} |  | ||||||
|                   paths: |  | ||||||
|                       - ~/repo/python-packages/json_schemas/.coverage |  | ||||||
|             - save_cache: |  | ||||||
|                   key: coverage-python-order-utils-{{ .Environment.CIRCLE_SHA1 }} |  | ||||||
|                   paths: |  | ||||||
|                       - ~/repo/python-packages/order_utils/.coverage |  | ||||||
|             - save_cache: |  | ||||||
|                   key: coverage-python-sra-client-{{ .Environment.CIRCLE_SHA1 }} |  | ||||||
|                   paths: |  | ||||||
|                       - ~/repo/python-packages/sra_client/.coverage |  | ||||||
|             - store_artifacts: |  | ||||||
|                   path: ~/repo/python-packages/contract_addresses/build |  | ||||||
|             - store_artifacts: |  | ||||||
|                   path: ~/repo/python-packages/contract_artifacts/build |  | ||||||
|             - store_artifacts: |  | ||||||
|                   path: ~/repo/python-packages/contract_wrappers/build |  | ||||||
|             - store_artifacts: |  | ||||||
|                   path: ~/repo/python-packages/json_schemas/build |  | ||||||
|             - store_artifacts: |  | ||||||
|                   path: ~/repo/python-packages/middlewares/build |  | ||||||
|             - store_artifacts: |  | ||||||
|                   path: ~/repo/python-packages/order_utils/build |  | ||||||
|             - store_artifacts: |  | ||||||
|                   path: ~/repo/python-packages/sra_client/build |  | ||||||
|     test-rest-python: |  | ||||||
|         working_directory: ~/repo |  | ||||||
|         docker: |  | ||||||
|             - image: nikolaik/python-nodejs:python3.7-nodejs8 |  | ||||||
|         steps: |  | ||||||
|             - checkout |  | ||||||
|             - restore_cache: |  | ||||||
|                   key: installed-py-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }} |  | ||||||
|             - run: |  | ||||||
|                   command: | |  | ||||||
|                       cd python-packages/order_utils |  | ||||||
|                       python -m ensurepip |  | ||||||
|                       python -m pip install . |  | ||||||
|             - save_cache: |  | ||||||
|                   key: installed-py-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }} |  | ||||||
|                   paths: |  | ||||||
|                       - '/usr/local/bin' |  | ||||||
|                       - '/usr/local/lib/python3.7/site-packages' |  | ||||||
|                       - '.eggs' |  | ||||||
|                       - '.mypy_cache' |  | ||||||
|                       - '.pytest_cache' |  | ||||||
|                       - '.tox' |  | ||||||
|             - run: |  | ||||||
|                   command: | |  | ||||||
|                       cd python-packages/order_utils |  | ||||||
|                       tox |  | ||||||
|     static-tests-python: |  | ||||||
|         working_directory: ~/repo |  | ||||||
|         docker: |  | ||||||
|             - image: nikolaik/python-nodejs:python3.7-nodejs8 |  | ||||||
|         steps: |  | ||||||
|             - checkout |  | ||||||
|             - restore_cache: |  | ||||||
|                   key: installed-py-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }} |  | ||||||
|             - restore_cache: |  | ||||||
|                   keys: |  | ||||||
|                       - repo-{{ .Environment.CIRCLE_SHA1 }} |  | ||||||
|             - run: |  | ||||||
|                   command: | |  | ||||||
|                       python -m ensurepip |  | ||||||
|                       cd python-packages |  | ||||||
|                       ./pre_install |  | ||||||
|                       ./install |  | ||||||
|                       ./lint |  | ||||||
|     static-tests: |     static-tests: | ||||||
|         resource_class: large |         resource_class: large | ||||||
|         working_directory: ~/repo |         working_directory: ~/repo | ||||||
|         docker: |         docker: | ||||||
|             - image: nikolaik/python-nodejs:python3.7-nodejs8 |             - image: nikolaik/python-nodejs:python3.7-nodejs10 | ||||||
|         steps: |         steps: | ||||||
|             - restore_cache: |             - restore_cache: | ||||||
|                   keys: |                   keys: | ||||||
| @@ -351,11 +143,9 @@ jobs: | |||||||
|             - run: yarn prettier:ci |             - run: yarn prettier:ci | ||||||
|             - run: yarn deps_versions:ci |             - run: yarn deps_versions:ci | ||||||
|             - run: yarn diff_md_docs:ci |             - run: yarn diff_md_docs:ci | ||||||
|             - run: cd packages/0x.js && yarn build:umd:prod |  | ||||||
|             - run: yarn bundlewatch |  | ||||||
|     submit-coverage: |     submit-coverage: | ||||||
|         docker: |         docker: | ||||||
|             - image: nikolaik/python-nodejs:python3.7-nodejs8 |             - image: nikolaik/python-nodejs:python3.7-nodejs10 | ||||||
|         working_directory: ~/repo |         working_directory: ~/repo | ||||||
|         steps: |         steps: | ||||||
|             - restore_cache: |             - restore_cache: | ||||||
| @@ -363,80 +153,33 @@ jobs: | |||||||
|                       - repo-{{ .Environment.CIRCLE_SHA1 }} |                       - repo-{{ .Environment.CIRCLE_SHA1 }} | ||||||
|             - restore_cache: |             - restore_cache: | ||||||
|                   keys: |                   keys: | ||||||
|                       - coverage-abi-gen-{{ .Environment.CIRCLE_SHA1 }} |                       - coverage-contract-wrappers-test-{{ .Environment.CIRCLE_SHA1 }} | ||||||
|             - restore_cache: |  | ||||||
|                   keys: |  | ||||||
|                       - coverage-assert-{{ .Environment.CIRCLE_SHA1 }} |  | ||||||
|             - restore_cache: |  | ||||||
|                   keys: |  | ||||||
|                       - coverage-asset-buyer-{{ .Environment.CIRCLE_SHA1 }} |  | ||||||
|             - restore_cache: |  | ||||||
|                   keys: |  | ||||||
|                       - coverage-base-contract-{{ .Environment.CIRCLE_SHA1 }} |  | ||||||
|             - restore_cache: |  | ||||||
|                   keys: |  | ||||||
|                       - coverage-connect-{{ .Environment.CIRCLE_SHA1 }} |  | ||||||
|             - restore_cache: |  | ||||||
|                   keys: |  | ||||||
|                       - coverage-contract-wrappers-{{ .Environment.CIRCLE_SHA1 }} |  | ||||||
|             - restore_cache: |  | ||||||
|                   keys: |  | ||||||
|                       - coverage-dev-utils-{{ .Environment.CIRCLE_SHA1 }} |  | ||||||
|             - restore_cache: |  | ||||||
|                   keys: |  | ||||||
|                       - coverage-json-schemas-{{ .Environment.CIRCLE_SHA1 }} |  | ||||||
|             - restore_cache: |             - restore_cache: | ||||||
|                   keys: |                   keys: | ||||||
|                       - coverage-order-utils-{{ .Environment.CIRCLE_SHA1 }} |                       - coverage-order-utils-{{ .Environment.CIRCLE_SHA1 }} | ||||||
|             - restore_cache: |  | ||||||
|                   keys: |  | ||||||
|                       - coverage-sol-compiler-{{ .Environment.CIRCLE_SHA1 }} |  | ||||||
|             - restore_cache: |  | ||||||
|                   keys: |  | ||||||
|                       - coverage-sol-tracing-utils-{{ .Environment.CIRCLE_SHA1 }} |  | ||||||
|             - restore_cache: |  | ||||||
|                   keys: |  | ||||||
|                       - coverage-sol-doc-{{ .Environment.CIRCLE_SHA1 }} |  | ||||||
|             - restore_cache: |  | ||||||
|                   keys: |  | ||||||
|                       - coverage-subproviders-{{ .Environment.CIRCLE_SHA1 }} |  | ||||||
|             - restore_cache: |  | ||||||
|                   keys: |  | ||||||
|                       - coverage-web3-wrapper-{{ .Environment.CIRCLE_SHA1 }} |  | ||||||
|             - restore_cache: |             - restore_cache: | ||||||
|                   keys: |                   keys: | ||||||
|                       - coverage-contracts-{{ .Environment.CIRCLE_SHA1 }} |                       - coverage-contracts-{{ .Environment.CIRCLE_SHA1 }} | ||||||
|             - restore_cache: |  | ||||||
|                   keys: |  | ||||||
|                       - coverage-python-json-schemas-{{ .Environment.CIRCLE_SHA1 }} |  | ||||||
|             - restore_cache: |  | ||||||
|                   keys: |  | ||||||
|                       - coverage-python-contract-addresses-{{ .Environment.CIRCLE_SHA1 }} |  | ||||||
|             - restore_cache: |  | ||||||
|                   keys: |  | ||||||
|                       - coverage-python-contract-artifacts-{{ .Environment.CIRCLE_SHA1 }} |  | ||||||
|             - restore_cache: |  | ||||||
|                   keys: |  | ||||||
|                       - coverage-python-contract-demo-{{ .Environment.CIRCLE_SHA1 }} |  | ||||||
|             - restore_cache: |  | ||||||
|                   keys: |  | ||||||
|                       - coverage-python-sra-client-{{ .Environment.CIRCLE_SHA1 }} |  | ||||||
|             - restore_cache: |  | ||||||
|                   keys: |  | ||||||
|                       - coverage-python-order-utils-{{ .Environment.CIRCLE_SHA1 }} |  | ||||||
|             - run: yarn report_coverage |             - run: yarn report_coverage | ||||||
| workflows: | workflows: | ||||||
|     version: 2 |     version: 2 | ||||||
|     main: |     main: | ||||||
|         jobs: |         jobs: | ||||||
|             - build |             - build | ||||||
|             - test-exchange-ganache-3.0: |             # Disabled until we begin actively developing on these packages again. | ||||||
|                   requires: |             # - test-exchange-ganache: | ||||||
|                       - build |             #       requires: | ||||||
|             - test-integrations-ganache-3.0: |             #           - build | ||||||
|                   requires: |             # - test-integrations-ganache: | ||||||
|                       - build |             #       requires: | ||||||
|             - test-contracts-rest-ganache-3.0: |             #           - build | ||||||
|  |             # - test-contracts-staking-ganache: | ||||||
|  |             #       requires: | ||||||
|  |             #           - build | ||||||
|  |             # - test-contracts-extra-ganache: | ||||||
|  |             #       requires: | ||||||
|  |             #           - build | ||||||
|  |             - test-contracts-rest-ganache: | ||||||
|                   requires: |                   requires: | ||||||
|                       - build |                       - build | ||||||
|             - test-rest: |             - test-rest: | ||||||
| @@ -451,17 +194,14 @@ workflows: | |||||||
|             - test-doc-generation: |             - test-doc-generation: | ||||||
|                   requires: |                   requires: | ||||||
|                       - build |                       - build | ||||||
|             - submit-coverage: |             # Disabled until this repo has a coveralls API key | ||||||
|                   requires: |             # - submit-coverage: | ||||||
|                       - test-contracts-rest-ganache-3.0 |             #       requires: | ||||||
|                       - test-exchange-ganache-3.0 |             #           # Disabled until we begin actively developing on these packages again. | ||||||
|                       - test-rest |             #           # - test-exchange-ganache | ||||||
|                       - static-tests |             #           # - test-integrations-ganache | ||||||
|             - test-python: |             #           # - test-contracts-staking-ganache | ||||||
|                   requires: |             #           # - test-contracts-extra-ganache | ||||||
|                       - build |             #           - test-contracts-rest-ganache | ||||||
|             - static-tests-python: |             #           - test-rest | ||||||
|                   requires: |             #           - static-tests | ||||||
|                       - build |  | ||||||
|             # skip python tox run for now, as we don't yet have multiple test environments to support. |  | ||||||
|             # - test-rest-python |  | ||||||
|   | |||||||
							
								
								
									
										4
									
								
								.gitattributes
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.gitattributes
									
									
									
									
										vendored
									
									
								
							| @@ -2,7 +2,3 @@ | |||||||
|  |  | ||||||
| # Automatically collapse generated files in GitHub. | # Automatically collapse generated files in GitHub. | ||||||
| *.svg linguist-generated=true | *.svg linguist-generated=true | ||||||
| packages/contract-artifacts/artifacts/*json linguist-generated=true |  | ||||||
| packages/abi-gen-wrappers/src/generated-wrappers/*.ts linguist-generated=true |  | ||||||
| packages/contract-wrappers/src/generated-wrappers/*.ts linguist-generated=true |  | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										29
									
								
								.github/autolabeler.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										29
									
								
								.github/autolabeler.yml
									
									
									
									
										vendored
									
									
								
							| @@ -1,36 +1,7 @@ | |||||||
| python: ['python-packages'] | python: ['python-packages'] | ||||||
| contracts: ['contracts'] | contracts: ['contracts'] | ||||||
| @0x/sol-doc: ['packages/sol-doc'] |  | ||||||
| @0x/sol-resolver: ['packages/sol-resolver'] |  | ||||||
| @0x/contracts-gen: ['packages/contracts-gen'] |  | ||||||
| @0x/sra-spec: ['packages/sra-spec'] |  | ||||||
| @0x/subproviders: ['packages/subproviders'] |  | ||||||
| @0x/contract-addresses: ['packages/contract-addresses'] | @0x/contract-addresses: ['packages/contract-addresses'] | ||||||
| @0x/migrations: ['packages/migrations'] | @0x/migrations: ['packages/migrations'] | ||||||
| @0x/web3-wrapper: ['packages/web3-wrapper'] |  | ||||||
| @0x/sol-compiler: ['packages/sol-compiler'] |  | ||||||
| @0x/types: ['packages/types'] |  | ||||||
| @0x/instant: ['packages/instant'] |  | ||||||
| @0x/abi-gen-templates: ['packages/abi-gen-templates'] |  | ||||||
| @0x/abi-gen: ['packages/abi-gen'] |  | ||||||
| @0x/sol-coverage: ['packages/sol-coverage'] |  | ||||||
| @0x/sol-profiler: ['packages/sol-profiler'] |  | ||||||
| @0x/sol-trace: ['packages/sol-trace'] |  | ||||||
| @0x/sol-tracing-utils: ['packages/sol-tracing-utils'] |  | ||||||
| @0x/utils: ['packages/utils'] |  | ||||||
| @0x/tslint-config: ['packages/tslint-config'] |  | ||||||
| @0x/asset-buyer: ['packages/asset-buyer'] |  | ||||||
| @0x/order-utils: ['packages/order-utils'] | @0x/order-utils: ['packages/order-utils'] | ||||||
| @0x/assert: ['packages/assert'] |  | ||||||
| @0x/base-contract: ['packages/base-contract'] |  | ||||||
| @0x/typescript-typings: ['packages/typescript-typings'] |  | ||||||
| 0x.js: ['packages/0x.js'] |  | ||||||
| @0x/abi-gen-wrappers: ['packages/abi-gen-wrappers'] |  | ||||||
| @0x/contract-artifacts: ['packages/contract-artifacts'] | @0x/contract-artifacts: ['packages/contract-artifacts'] | ||||||
| @0x/dev-utils: ['packages/dev-utils'] |  | ||||||
| @0x/contract-wrappers: ['packages/contract-wrappers'] | @0x/contract-wrappers: ['packages/contract-wrappers'] | ||||||
| @0x/json-schemas: ['packages/json-schemas'] |  | ||||||
| @0x/ethereum-types: ['ethereum-types'] |  | ||||||
| @0x/connect: ['packages/connect'] |  | ||||||
| @0x/testnet-faucets: ['packages/testnet-faucets'] |  | ||||||
| @0x/monorepo-scripts: ['packages/monorepo-scripts'] |  | ||||||
|   | |||||||
							
								
								
									
										48
									
								
								.github/workflows/publish.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								.github/workflows/publish.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,48 @@ | |||||||
|  | name: publish | ||||||
|  |  | ||||||
|  | on: | ||||||
|  |   workflow_dispatch: | ||||||
|  |       inputs: | ||||||
|  |           ci_status: | ||||||
|  |               description: 'required CI status' | ||||||
|  |               default: 'success' | ||||||
|  |               required: true | ||||||
|  |  | ||||||
|  | jobs: | ||||||
|  |     publish: | ||||||
|  |         runs-on: ubuntu-latest | ||||||
|  |         steps: | ||||||
|  |             - name: 'check successful status' | ||||||
|  |               run: | | ||||||
|  |                   REF_STATUS=$(curl -s \ | ||||||
|  |                   'https://api.github.com/repos/${{ github.repository }}/commits/${{ github.ref }}/status' \ | ||||||
|  |                   | jq .state) | ||||||
|  |                   [[ "${REF_STATUS}" == '"${{ github.event.inputs.ci_status }}"' ]] || \ | ||||||
|  |                   (echo "::error ::${{ github.ref }} does not have a successful CI status" && false) | ||||||
|  |             - uses: actions/checkout@v2 | ||||||
|  |               with: | ||||||
|  |                 ref: 'development' | ||||||
|  |                 fetch-depth: 0 | ||||||
|  |             - uses: actions/setup-node@v1 | ||||||
|  |               with: | ||||||
|  |                 node-version: 10 | ||||||
|  |             - uses: actions/setup-python@v2 | ||||||
|  |             - name: 'configure git' | ||||||
|  |               run: | | ||||||
|  |                   git config --global user.email "github-actions@github.com" | ||||||
|  |                   git config --global user.name "Github Actions" | ||||||
|  |             - name: 'install dependencies' | ||||||
|  |               run: | | ||||||
|  |                   yarn -D | ||||||
|  |             - name: 'build and publish' | ||||||
|  |               run: | | ||||||
|  |                   echo '//registry.npmjs.org/:_authToken=${NPM_TOKEN}' > .npmrc | ||||||
|  |                   npm run run:publish:gha | ||||||
|  |               env: | ||||||
|  |                   NPM_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }} | ||||||
|  |                   GITHUB_TOKEN: ${{ github.token }} | ||||||
|  |             - name: 'merge into main branch' | ||||||
|  |               run: | | ||||||
|  |                   git checkout main && \ | ||||||
|  |                   git merge ${{ github.ref }} && \ | ||||||
|  |                   git push | ||||||
							
								
								
									
										88
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										88
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -78,28 +78,45 @@ TODO.md | |||||||
| # VSCode file | # VSCode file | ||||||
| .vscode | .vscode | ||||||
|  |  | ||||||
| # server cli |  | ||||||
| packages/testnet-faucets/server/ |  | ||||||
|  |  | ||||||
| # generated contract artifacts/ | # generated contract artifacts/ | ||||||
|  | contracts/broker/generated-artifacts/ | ||||||
|  | contracts/broker/test/generated-artifacts/ | ||||||
|  | contracts/erc20-bridge-sampler/generated-artifacts/ | ||||||
|  | contracts/erc20-bridge-sampler/test/generated-artifacts/ | ||||||
| contracts/integrations/generated-artifacts/ | contracts/integrations/generated-artifacts/ | ||||||
|  | contracts/integrations/test/generated-artifacts/ | ||||||
| contracts/staking/generated-artifacts/ | contracts/staking/generated-artifacts/ | ||||||
|  | contracts/staking/test/generated-artifacts/ | ||||||
| contracts/coordinator/generated-artifacts/ | contracts/coordinator/generated-artifacts/ | ||||||
|  | contracts/coordinator/test/generated-artifacts/ | ||||||
| contracts/exchange/generated-artifacts/ | contracts/exchange/generated-artifacts/ | ||||||
|  | contracts/exchange/test/generated-artifacts/ | ||||||
| contracts/asset-proxy/generated-artifacts/ | contracts/asset-proxy/generated-artifacts/ | ||||||
|  | contracts/asset-proxy/test/generated-artifacts/ | ||||||
| contracts/multisig/generated-artifacts/ | contracts/multisig/generated-artifacts/ | ||||||
|  | contracts/multisig/test/generated-artifacts/ | ||||||
| contracts/utils/generated-artifacts/ | contracts/utils/generated-artifacts/ | ||||||
|  | contracts/utils/test/generated-artifacts/ | ||||||
| contracts/exchange-libs/generated-artifacts/ | contracts/exchange-libs/generated-artifacts/ | ||||||
|  | contracts/exchange-libs/test/generated-artifacts/ | ||||||
| contracts/erc20/generated-artifacts/ | contracts/erc20/generated-artifacts/ | ||||||
|  | contracts/erc20/test/generated-artifacts/ | ||||||
| contracts/erc721/generated-artifacts/ | contracts/erc721/generated-artifacts/ | ||||||
|  | contracts/erc721/test/generated-artifacts/ | ||||||
| contracts/erc1155/generated-artifacts/ | contracts/erc1155/generated-artifacts/ | ||||||
|  | contracts/erc1155/test/generated-artifacts/ | ||||||
| contracts/extensions/generated-artifacts/ | contracts/extensions/generated-artifacts/ | ||||||
|  | contracts/extensions/test/generated-artifacts/ | ||||||
| contracts/exchange-forwarder/generated-artifacts/ | contracts/exchange-forwarder/generated-artifacts/ | ||||||
|  | contracts/exchange-forwarder/test/generated-artifacts/ | ||||||
| contracts/dev-utils/generated-artifacts/ | contracts/dev-utils/generated-artifacts/ | ||||||
| packages/sol-tracing-utils/test/fixtures/artifacts/ | contracts/dev-utils/test/generated-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/ | # generated truffle contract artifacts/ | ||||||
|  | contracts/broker/build/ | ||||||
|  | contracts/erc20-bridge-sampler/build/ | ||||||
| contracts/staking/build/ | contracts/staking/build/ | ||||||
| contracts/coordinator/build/ | contracts/coordinator/build/ | ||||||
| contracts/exchange/build/ | contracts/exchange/build/ | ||||||
| @@ -115,62 +132,41 @@ contracts/exchange-forwarder/build/ | |||||||
| contracts/dev-utils/build/ | contracts/dev-utils/build/ | ||||||
|  |  | ||||||
| # generated contract wrappers | # generated contract wrappers | ||||||
|  | contracts/broker/generated-wrappers/ | ||||||
|  | contracts/broker/test/generated-wrappers/ | ||||||
| packages/python-contract-wrappers/generated/ | packages/python-contract-wrappers/generated/ | ||||||
|  | contracts/erc20-bridge-sampler/generated-wrappers/ | ||||||
|  | contracts/erc20-bridge-sampler/test/generated-wrappers/ | ||||||
| contracts/integrations/generated-wrappers/ | contracts/integrations/generated-wrappers/ | ||||||
|  | contracts/integrations/test/generated-wrappers/ | ||||||
| contracts/staking/generated-wrappers/ | contracts/staking/generated-wrappers/ | ||||||
|  | contracts/staking/test/generated-wrappers/ | ||||||
| contracts/coordinator/generated-wrappers/ | contracts/coordinator/generated-wrappers/ | ||||||
|  | contracts/coordinator/test/generated-wrappers/ | ||||||
| contracts/exchange/generated-wrappers/ | contracts/exchange/generated-wrappers/ | ||||||
|  | contracts/exchange/test/generated-wrappers/ | ||||||
| contracts/asset-proxy/generated-wrappers/ | contracts/asset-proxy/generated-wrappers/ | ||||||
|  | contracts/asset-proxy/test/generated-wrappers/ | ||||||
| contracts/multisig/generated-wrappers/ | contracts/multisig/generated-wrappers/ | ||||||
|  | contracts/multisig/test/generated-wrappers/ | ||||||
| contracts/utils/generated-wrappers/ | contracts/utils/generated-wrappers/ | ||||||
|  | contracts/utils/test/generated-wrappers/ | ||||||
| contracts/exchange-libs/generated-wrappers/ | contracts/exchange-libs/generated-wrappers/ | ||||||
|  | contracts/exchange-libs/test/generated-wrappers/ | ||||||
| contracts/erc20/generated-wrappers/ | contracts/erc20/generated-wrappers/ | ||||||
|  | contracts/erc20/test/generated-wrappers/ | ||||||
| contracts/erc721/generated-wrappers/ | contracts/erc721/generated-wrappers/ | ||||||
|  | contracts/erc721/test/generated-wrappers/ | ||||||
| contracts/erc1155/generated-wrappers/ | contracts/erc1155/generated-wrappers/ | ||||||
|  | contracts/erc1155/test/generated-wrappers/ | ||||||
| contracts/extensions/generated-wrappers/ | contracts/extensions/generated-wrappers/ | ||||||
|  | contracts/extensions/test/generated-wrappers/ | ||||||
| contracts/exchange-forwarder/generated-wrappers/ | contracts/exchange-forwarder/generated-wrappers/ | ||||||
|  | contracts/exchange-forwarder/test/generated-wrappers/ | ||||||
| contracts/dev-utils/generated-wrappers/ | contracts/dev-utils/generated-wrappers/ | ||||||
| python-packages/contract_wrappers/src/zero_ex/contract_wrappers/dev_utils/__init__.py | contracts/dev-utils/test/generated-wrappers/ | ||||||
| python-packages/contract_wrappers/src/zero_ex/contract_wrappers/erc20_token/__init__.py | contracts/zero-ex/generated-wrappers/ | ||||||
| python-packages/contract_wrappers/src/zero_ex/contract_wrappers/exchange/__init__.py | contracts/zero-ex/test/generated-wrappers/ | ||||||
| python-packages/contract_wrappers/src/zero_ex/contract_wrappers/asset_proxy_owner/__init__.py |  | ||||||
| python-packages/contract_wrappers/src/zero_ex/contract_wrappers/coordinator/__init__.py |  | ||||||
| python-packages/contract_wrappers/src/zero_ex/contract_wrappers/coordinator_registry/__init__.py |  | ||||||
| python-packages/contract_wrappers/src/zero_ex/contract_wrappers/dummy_erc20_token/__init__.py |  | ||||||
| python-packages/contract_wrappers/src/zero_ex/contract_wrappers/dummy_erc721_token/__init__.py |  | ||||||
| python-packages/contract_wrappers/src/zero_ex/contract_wrappers/dutch_auction/__init__.py |  | ||||||
| python-packages/contract_wrappers/src/zero_ex/contract_wrappers/erc1155_mintable/__init__.py |  | ||||||
| python-packages/contract_wrappers/src/zero_ex/contract_wrappers/erc1155_proxy/__init__.py |  | ||||||
| python-packages/contract_wrappers/src/zero_ex/contract_wrappers/erc20_proxy/__init__.py |  | ||||||
| python-packages/contract_wrappers/src/zero_ex/contract_wrappers/erc721_proxy/__init__.py |  | ||||||
| python-packages/contract_wrappers/src/zero_ex/contract_wrappers/erc721_token/__init__.py |  | ||||||
| python-packages/contract_wrappers/src/zero_ex/contract_wrappers/eth_balance_checker/__init__.py |  | ||||||
| python-packages/contract_wrappers/src/zero_ex/contract_wrappers/forwarder/__init__.py |  | ||||||
| python-packages/contract_wrappers/src/zero_ex/contract_wrappers/i_asset_proxy/__init__.py |  | ||||||
| python-packages/contract_wrappers/src/zero_ex/contract_wrappers/i_validator/__init__.py |  | ||||||
| python-packages/contract_wrappers/src/zero_ex/contract_wrappers/i_wallet/__init__.py |  | ||||||
| python-packages/contract_wrappers/src/zero_ex/contract_wrappers/multi_asset_proxy/__init__.py |  | ||||||
| python-packages/contract_wrappers/src/zero_ex/contract_wrappers/order_validator/__init__.py |  | ||||||
| python-packages/contract_wrappers/src/zero_ex/contract_wrappers/static_call_proxy/__init__.py |  | ||||||
| python-packages/contract_wrappers/src/zero_ex/contract_wrappers/weth9/__init__.py |  | ||||||
| python-packages/contract_wrappers/src/zero_ex/contract_wrappers/zrx_token/__init__.py |  | ||||||
|  |  | ||||||
| # solc-bin in sol-compiler |  | ||||||
| packages/sol-compiler/solc_bin/ |  | ||||||
|  |  | ||||||
| # python stuff |  | ||||||
| .eggs |  | ||||||
| .mypy_cache |  | ||||||
| .tox |  | ||||||
| python-packages/*/build |  | ||||||
| python-packages/*/dist |  | ||||||
| __pycache__ |  | ||||||
| python-packages/*/src/*.egg-info |  | ||||||
| python-packages/*/.coverage |  | ||||||
|  |  | ||||||
| # python keeps package-local copies of json schemas and contract addresses |  | ||||||
| python-packages/json_schemas/src/zero_ex/json_schemas/schemas |  | ||||||
| python-packages/contract_addresses/src/zero_ex/contract_addresses/addresses.json |  | ||||||
|  |  | ||||||
| # Doc README copy | # Doc README copy | ||||||
| packages/*/docs/README.md | packages/*/docs/README.md | ||||||
|   | |||||||
| @@ -1,33 +1,69 @@ | |||||||
| lib | lib | ||||||
| .nyc_output | .nyc_output | ||||||
|  | /contracts/broker/generated-wrappers | ||||||
|  | /contracts/broker/test/generated-wrappers | ||||||
|  | /contracts/broker/generated-artifacts | ||||||
|  | /contracts/broker/test/generated-artifacts | ||||||
| /contracts/integrations/generated-wrappers | /contracts/integrations/generated-wrappers | ||||||
|  | /contracts/integrations/test/generated-wrappers | ||||||
| /contracts/integrations/generated-artifacts | /contracts/integrations/generated-artifacts | ||||||
|  | /contracts/integrations/test/generated-artifacts | ||||||
| /contracts/staking/generated-wrappers | /contracts/staking/generated-wrappers | ||||||
|  | /contracts/staking/test/generated-wrappers | ||||||
| /contracts/staking/generated-artifacts | /contracts/staking/generated-artifacts | ||||||
|  | /contracts/staking/test/generated-artifacts | ||||||
| /contracts/coordinator/generated-wrappers | /contracts/coordinator/generated-wrappers | ||||||
|  | /contracts/coordinator/test/generated-wrappers | ||||||
| /contracts/coordinator/generated-artifacts | /contracts/coordinator/generated-artifacts | ||||||
|  | /contracts/coordinator/test/generated-artifacts | ||||||
| /contracts/exchange/generated-wrappers | /contracts/exchange/generated-wrappers | ||||||
|  | /contracts/exchange/test/generated-wrappers | ||||||
| /contracts/exchange/generated-artifacts | /contracts/exchange/generated-artifacts | ||||||
|  | /contracts/exchange/test/generated-artifacts | ||||||
| /contracts/asset-proxy/generated-wrappers | /contracts/asset-proxy/generated-wrappers | ||||||
|  | /contracts/asset-proxy/test/generated-wrappers | ||||||
| /contracts/asset-proxy/generated-artifacts | /contracts/asset-proxy/generated-artifacts | ||||||
|  | /contracts/asset-proxy/test/generated-artifacts | ||||||
| /contracts/multisig/generated-wrappers | /contracts/multisig/generated-wrappers | ||||||
|  | /contracts/multisig/test/generated-wrappers | ||||||
| /contracts/multisig/generated-artifacts | /contracts/multisig/generated-artifacts | ||||||
|  | /contracts/multisig/test/generated-artifacts | ||||||
| /contracts/utils/generated-wrappers | /contracts/utils/generated-wrappers | ||||||
|  | /contracts/utils/test/generated-wrappers | ||||||
| /contracts/utils/generated-artifacts | /contracts/utils/generated-artifacts | ||||||
|  | /contracts/utils/test/generated-artifacts | ||||||
| /contracts/exchange-libs/generated-wrappers | /contracts/exchange-libs/generated-wrappers | ||||||
|  | /contracts/exchange-libs/test/generated-wrappers | ||||||
| /contracts/exchange-libs/generated-artifacts | /contracts/exchange-libs/generated-artifacts | ||||||
|  | /contracts/exchange-libs/test/generated-artifacts | ||||||
| /contracts/erc20/generated-wrappers | /contracts/erc20/generated-wrappers | ||||||
|  | /contracts/erc20/test/generated-wrappers | ||||||
| /contracts/erc20/generated-artifacts | /contracts/erc20/generated-artifacts | ||||||
|  | /contracts/erc20/test/generated-artifacts | ||||||
| /contracts/erc721/generated-wrappers | /contracts/erc721/generated-wrappers | ||||||
|  | /contracts/erc721/test/generated-wrappers | ||||||
| /contracts/erc721/generated-artifacts | /contracts/erc721/generated-artifacts | ||||||
|  | /contracts/erc721/test/generated-artifacts | ||||||
| /contracts/erc1155/generated-wrappers | /contracts/erc1155/generated-wrappers | ||||||
|  | /contracts/erc1155/test/generated-wrappers | ||||||
| /contracts/erc1155/generated-artifacts | /contracts/erc1155/generated-artifacts | ||||||
|  | /contracts/erc1155/test/generated-artifacts | ||||||
| /contracts/extensions/generated-wrappers | /contracts/extensions/generated-wrappers | ||||||
|  | /contracts/extensions/test/generated-wrappers | ||||||
| /contracts/extensions/generated-artifacts | /contracts/extensions/generated-artifacts | ||||||
|  | /contracts/extensions/test/generated-artifacts | ||||||
| /contracts/exchange-forwarder/generated-wrappers | /contracts/exchange-forwarder/generated-wrappers | ||||||
|  | /contracts/exchange-forwarder/test/generated-wrappers | ||||||
| /contracts/exchange-forwarder/generated-artifacts | /contracts/exchange-forwarder/generated-artifacts | ||||||
|  | /contracts/exchange-forwarder/test/generated-artifacts | ||||||
| /contracts/dev-utils/generated-wrappers | /contracts/dev-utils/generated-wrappers | ||||||
|  | /contracts/dev-utils/test/generated-wrappers | ||||||
| /contracts/dev-utils/generated-artifacts | /contracts/dev-utils/generated-artifacts | ||||||
|  | /contracts/dev-utils/test/generated-artifacts | ||||||
|  | /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/staking/build/ | ||||||
| /contracts/coordinator/build/ | /contracts/coordinator/build/ | ||||||
| /contracts/exchange/build/ | /contracts/exchange/build/ | ||||||
| @@ -40,18 +76,11 @@ lib | |||||||
| /contracts/erc1155/build/ | /contracts/erc1155/build/ | ||||||
| /contracts/extensions/build/ | /contracts/extensions/build/ | ||||||
| /contracts/exchange-forwarder/build/ | /contracts/exchange-forwarder/build/ | ||||||
| /contracts/dev-utils/build/ | /packages/asset-swapper/generated-artifacts | ||||||
| /packages/abi-gen/test-cli/output | /packages/asset-swapper/generated-wrappers | ||||||
| /packages/json-schemas/schemas | /packages/asset-swapper/test/generated-artifacts | ||||||
| /python-packages/json_schemas/src/zero_ex/json_schemas/schemas | /packages/asset-swapper/test/generated-wrappers | ||||||
| /packages/sra-spec/public/ |  | ||||||
| package.json | package.json | ||||||
| scripts/postpublish_utils.js |  | ||||||
| packages/sol-coverage/test/fixtures/artifacts |  | ||||||
| .pytest_cache |  | ||||||
| .mypy_cache |  | ||||||
| .tox |  | ||||||
| packages/abi-gen/test-cli/fixtures/artifacts/AbiGenDummy.json |  | ||||||
| packages/abi-gen/test-cli/fixtures/artifacts/LibDummy.json |  | ||||||
| packages/abi-gen/test-cli/fixtures/artifacts/TestLibDummy.json |  | ||||||
| packages/*/docs | packages/*/docs | ||||||
|  | docs/ | ||||||
|  | *.sol | ||||||
|   | |||||||
| @@ -1,6 +1,7 @@ | |||||||
| { | { | ||||||
|     "tabWidth": 4, |  | ||||||
|     "printWidth": 120, |     "printWidth": 120, | ||||||
|     "trailingComma": all, |     "tabWidth": 4, | ||||||
|     "singleQuote": true |     "singleQuote": true, | ||||||
|  |     "trailingComma": "all", | ||||||
|  |     "bracketSpacing": true | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										34
									
								
								CODEOWNERS
									
									
									
									
									
								
							
							
						
						
									
										34
									
								
								CODEOWNERS
									
									
									
									
									
								
							| @@ -5,34 +5,14 @@ | |||||||
| # https://git-scm.com/docs/gitignore#_pattern_format | # https://git-scm.com/docs/gitignore#_pattern_format | ||||||
|  |  | ||||||
| # Website | # Website | ||||||
| packages/asset-buyer/  @BMillman19 @fragosti @steveklebanoff | packages/asset-swapper/  @BMillman19 @fragosti @dave4506 | ||||||
| packages/instant/  @BMillman19 @fragosti @steveklebanoff | packages/instant/  @BMillman19 @fragosti @dave4506 | ||||||
|  |  | ||||||
| # Dev tools & setup | # Dev tools & setup | ||||||
| .circleci/ @LogvinovLeon | .circleci/ @dorothy-zbornak | ||||||
| packages/abi-gen/ @feuGeneA | packages/contract-addresses/ @abandeali1 | ||||||
| packages/base-contract/ @xianny | packages/contract-artifacts/ @abandeali1 | ||||||
| packages/connect/ @fragosti  | packages/order-utils/ @dorothy-zbornak  | ||||||
| packages/abi-gen-templates/ @feuGeneA @xianny |  | ||||||
| packages/contract-addresses/ @albrow |  | ||||||
| packages/contract-artifacts/ @albrow |  | ||||||
| packages/dev-utils/ @LogvinovLeon @fabioberger |  | ||||||
| packages/devnet/ @albrow |  | ||||||
| packages/ethereum-types/ @LogvinovLeon |  | ||||||
| packages/monorepo-scripts/ @fabioberger |  | ||||||
| packages/order-utils/ @fabioberger @LogvinovLeon  |  | ||||||
| packages/python-contract-wrappers/ @feuGeneA |  | ||||||
| packages/sol-compiler/ @LogvinovLeon |  | ||||||
| packages/sol-coverage/ @LogvinovLeon |  | ||||||
| packages/sol-profiler/ @LogvinovLeon |  | ||||||
| packages/sol-trace/ @LogvinovLeon |  | ||||||
| packages/sol-tracing-utils/ @LogvinovLeon |  | ||||||
| packages/sol-resolver/ @LogvinovLeon |  | ||||||
| packages/subproviders/ @fabioberger @dekz |  | ||||||
| packages/verdaccio/ @albrow |  | ||||||
| packages/web3-wrapper/ @LogvinovLeon @fabioberger |  | ||||||
| python-packages/ @feuGeneA |  | ||||||
| packages/utils/ @hysz |  | ||||||
|  |  | ||||||
| # Protocol/smart contracts | # Protocol/smart contracts | ||||||
| contracts/ @abandeali1 @hysz | 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 | ### Getting started | ||||||
|  |  | ||||||
| 1.  Fork `0xproject/0x-monorepo` | 1.  Fork `0xproject/0x-tools` | ||||||
| 2.  Clone your fork | 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). | 4.  Setup the recommended [Development Tooling](#development-tooling). | ||||||
| 5.  Open a PR with the `[WIP]` flag against the `development` branch and describe the change you are intending to undertake in the PR description. (see [our branch naming conventions](#branch-structure)) | 5.  Open a PR with the `[WIP]` flag against the `development` branch and describe the change you are intending to undertake in the PR description. (see [our branch naming conventions](#branch-structure)) | ||||||
|  |  | ||||||
| @@ -59,11 +59,11 @@ We strongly recommend you use the [VSCode](https://code.visualstudio.com/) text | |||||||
|  |  | ||||||
| #### Linter | #### Linter | ||||||
|  |  | ||||||
| We use [TSLint](https://palantir.github.io/tslint/) with [custom configs](https://github.com/0xProject/0x-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. | 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: | Integrate it into your text editor: | ||||||
|  |  | ||||||
| @@ -94,12 +94,12 @@ A few of our coding conventions are not yet enforced by the linter/auto-formatte | |||||||
|  |  | ||||||
| ### Fix `submit-coverage` CI failure | ### Fix `submit-coverage` CI failure | ||||||
|  |  | ||||||
| If you simply fork the repo and then create a PR from it, your PR will fail the `submit-coverage` check on CI. This is because the 0x CircleCI configuration sets the `COVERALLS_REPO_TOKEN` environment variable to the token for `0xProject/0x-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: | To facilitate this check, after creating your fork, but before creating the branch for your PR, do the following: | ||||||
|  |  | ||||||
| 1.  Log in to [coveralls.io](https://coveralls.io/), go to `Add Repos`, and enable your fork. Then go to the settings for that repo, and copy the `Repo Token` identifier. | 1.  Log in to [coveralls.io](https://coveralls.io/), go to `Add Repos`, and enable your fork. Then go to the settings for that repo, and copy the `Repo Token` identifier. | ||||||
| 2.  Log in to [CircleCI](https://circleci.com/login), go to `Add Projects`, click the `Set Up Project` button corresponding to your fork, and then click `Start Building`. (Aside from step 3 below, no actual set up is needed, since it will use the `.circleci/config.yml` file in 0x-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. | 3.  In CircleCI, configure your project to add an environment variable, with name `COVERALLS_REPO_TOKEN`, and for the value paste in the `Repo Token` you copied in step 1. | ||||||
|  |  | ||||||
| Now, when you push to your branch, CircleCI will automatically run all of the checks in your own instance, and the coverage check will work since it has the proper `Repo Token`, and the PR will magically refer to your own checks rather than running them in the 0x CircleCI instance. | Now, when you push to your branch, CircleCI will automatically run all of the checks in your own instance, and the coverage check will work since it has the proper `Repo Token`, and the PR will magically refer to your own checks rather than running them in the 0x CircleCI instance. | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								LICENSE
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								LICENSE
									
									
									
									
									
								
							| @@ -1,4 +1,4 @@ | |||||||
| Copyright 2017 ZeroEx Intl. | Copyright 2020 ZeroEx Labs | ||||||
|  |  | ||||||
| Licensed under the Apache License, Version 2.0 (the "License"); | Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
| you may not use this file except in compliance with the License. | you may not use this file except in compliance with the License. | ||||||
|   | |||||||
							
								
								
									
										79
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										79
									
								
								README.md
									
									
									
									
									
								
							| @@ -8,7 +8,7 @@ This repository is a monorepo including the 0x protocol smart contracts and nume | |||||||
|  |  | ||||||
| [website-url]: https://0x.org | [website-url]: https://0x.org | ||||||
|  |  | ||||||
| [](https://circleci.com/gh/0xProject/0x-monorepo) | [](https://circleci.com/gh/0xProject/protocool) | ||||||
| [](https://coveralls.io/github/0xProject/0x-monorepo?branch=development) | [](https://coveralls.io/github/0xProject/0x-monorepo?branch=development) | ||||||
| [](https://discordapp.com/invite/d3FTX3M) | [](https://discordapp.com/invite/d3FTX3M) | ||||||
| [](https://opensource.org/licenses/Apache-2.0) | [](https://opensource.org/licenses/Apache-2.0) | ||||||
| @@ -17,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. | Visit our [developer portal](https://0x.org/docs/tools/order-utils) for a comprehensive list of core & community maintained packages. All packages maintained with this monorepo are listed below. | ||||||
|  |  | ||||||
| ### Python Packages |  | ||||||
|  |  | ||||||
| | Package                                                        | Version                                                                                                             | Description                                                                                       | |  | ||||||
| | -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | |  | ||||||
| | [`0x-contract-addresses`](/python-packages/contract_addresses) | [](https://pypi.org/project/0x-contract-addresses/) | A tiny utility library for getting known deployed contract addresses for a particular network     | |  | ||||||
| | [`0x-contract-artifacts`](/python-packages/contract_artifacts) | [](https://pypi.org/project/0x-contract-artifacts/) | 0x smart contract compilation artifacts                                                           | |  | ||||||
| | [`0x-contract-wrappers`](/python-packages/contract_wrappers)   | [](https://pypi.org/project/0x-contract-wrappers/)   | 0x smart contract wrappers                                                                        | |  | ||||||
| | [`0x-json-schemas`](/python-packages/json_schemas)             | [](https://pypi.org/project/0x-json-schemas/)             | 0x-related JSON schemas                                                                           | |  | ||||||
| | [`0x-order-utils`](/python-packages/order_utils)               | [](https://pypi.org/project/0x-order-utils/)               | A set of utilities for generating, parsing, signing and validating 0x orders                      | |  | ||||||
| | [`0x-sra-client`](/python-packages/sra_client)                 | [](https://pypi.org/project/0x-sra-client/)                 | A Python client for interacting with servers conforming to the Standard Relayer API specification | |  | ||||||
|  |  | ||||||
| ### Solidity Packages | ### Solidity Packages | ||||||
|  |  | ||||||
| These packages are all under development. See [/contracts/README.md](/contracts/README.md) for a list of deployed packages. | These packages are all under development. See [/contracts/README.md](/contracts/README.md) for a list of deployed packages. | ||||||
| @@ -53,53 +42,13 @@ These packages are all under development. See [/contracts/README.md](/contracts/ | |||||||
|  |  | ||||||
| #### 0x-specific packages | #### 0x-specific packages | ||||||
|  |  | ||||||
| | Package                                                  | Version                                                                                                                 | Description                                                                                       | | | 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-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/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/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/json-schemas`](/packages/json-schemas)             | [](https://www.npmjs.com/package/@0x/json-schemas)             | 0x-related JSON schemas                                                                           |  | | | [`@0x/contract-artifacts`](/packages/contract-artifacts) | [](https://www.npmjs.com/package/@0x/contract-artifacts) | 0x smart contract compilation artifacts                                                        |  | | ||||||
| | [`@0x/migrations`](/packages/migrations)                 | [](https://www.npmjs.com/package/@0x/migrations)                 | Migration tool for deploying 0x smart contracts on private testnets                               | |  | ||||||
| | [`@0x/contract-artifacts`](/packages/contract-artifacts) | [](https://www.npmjs.com/package/@0x/contract-artifacts) | 0x smart contract compilation artifacts                                                           | |  | ||||||
| | [`@0x/abi-gen-wrappers`](/packages/abi-gen-wrappers)     | [](https://www.npmjs.com/package/@0x/abi-gen-wrappers)     | Low-level 0x smart contract wrappers generated using `@0x/abi-gen`                                | |  | ||||||
| | [`@0x/sra-spec`](/packages/sra-spec)                     | [](https://www.npmjs.com/package/@0x/sra-spec)                     | OpenAPI specification for the Standard Relayer API                                                | |  | ||||||
| | [`@0x/connect`](/packages/connect)                       | [](https://www.npmjs.com/package/@0x/connect)                       | An HTTP/WS client for interacting with the Standard Relayer API                                   | |  | ||||||
| | [`@0x/asset-buyer`](/packages/asset-buyer)               | [](https://www.npmjs.com/package/@0x/asset-buyer)               | Convenience package for discovering and buying assets with Ether                                  | |  | ||||||
| | [`@0x/asset-swapper`](/packages/asset-swapper)           | [](https://www.npmjs.com/package/@0x/asset-swapper)           | Convenience package for discovering and performing swaps for any ERC20 Assets                     | |  | ||||||
|  |  | ||||||
| #### Ethereum tooling |  | ||||||
|  |  | ||||||
| | Package                                      | Version                                                                                                     | Description                                                                                                                                                                             | |  | ||||||
| | -------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | |  | ||||||
| | [`@0x/web3-wrapper`](/packages/web3-wrapper) | [](https://www.npmjs.com/package/@0x/web3-wrapper) | An Ethereum JSON RPC client                                                                                                                                                             | |  | ||||||
| | [`@0x/sol-compiler`](/packages/sol-compiler) | [](https://www.npmjs.com/package/@0x/sol-compiler) | A wrapper around solc-js that adds smart re-compilation, ability to compile an entire project, Solidity version specific compilation, standard input description support and much more. | |  | ||||||
| | [`@0x/sol-coverage`](/packages/sol-coverage) | [](https://www.npmjs.com/package/@0x/sol-coverage) | A solidity test coverage tool                                                                                                                                                           | |  | ||||||
| | [`@0x/sol-profiler`](/packages/sol-profiler) | [](https://www.npmjs.com/package/@0x/sol-profiler) | A solidity gas cost profiler                                                                                                                                                            | |  | ||||||
| | [`@0x/sol-trace`](/packages/sol-trace)       | [](https://www.npmjs.com/package/@0x/sol-trace)       | A solidity stack trace tool                                                                                                                                                             | |  | ||||||
| | [`@0x/sol-resolver`](/packages/sol-resolver) | [](https://www.npmjs.com/package/@0x/sol-resolver) | Import resolver for smart contracts dependencies                                                                                                                                        | |  | ||||||
| | [`@0x/subproviders`](/packages/subproviders) | [](https://www.npmjs.com/package/@0x/subproviders) | Web3 provider middlewares (e.g. LedgerSubprovider)                                                                                                                                      | |  | ||||||
| | [`@0x/sol-doc`](/packages/sol-doc)           | [](https://www.npmjs.com/package/@0x/sol-doc)           | Solidity documentation generator                                                                                                                                                        | |  | ||||||
|  |  | ||||||
| #### Utilities |  | ||||||
|  |  | ||||||
| | Package                                                  | Version                                                                                                                 | Description                                                     | |  | ||||||
| | -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------- | |  | ||||||
| | [`@0x/abi-gen`](/packages/abi-gen)                       | [](https://www.npmjs.com/package/@0x/abi-gen)                       | Tool to generate TS wrappers from smart contract ABIs           | |  | ||||||
| | [`@0x/tslint-config`](/packages/tslint-config)           | [](https://www.npmjs.com/package/@0x/tslint-config)           | Custom TSLint rules used by the 0x core team                    | |  | ||||||
| | [`@0x/types`](/packages/types)                           | [](https://www.npmjs.com/package/@0x/types)                           | Shared type declarations                                        | |  | ||||||
| | [`@0x/typescript-typings`](/packages/typescript-typings) | [](https://www.npmjs.com/package/@0x/typescript-typings) | Repository of types for external packages                       | |  | ||||||
| | [`@0x/utils`](/packages/utils)                           | [](https://www.npmjs.com/package/@0x/utils)                           | Shared utilities                                                | |  | ||||||
| | [`@0x/assert`](/packages/assert)                         | [](https://www.npmjs.com/package/@0x/assert)                         | Type and schema assertions used by our packages                 | |  | ||||||
| | [`@0x/base-contract`](/packages/base-contract)           | [](https://www.npmjs.com/package/@0x/base-contract)           | BaseContract used by auto-generated `abi-gen` wrapper contracts | |  | ||||||
| | [`@0x/dev-utils`](/packages/dev-utils)                   | [](https://www.npmjs.com/package/@0x/dev-utils)                   | Dev utils to be shared across 0x packages                       | |  | ||||||
|  |  | ||||||
| #### Private Packages |  | ||||||
|  |  | ||||||
| | Package                                            | Description                                                                      | |  | ||||||
| | -------------------------------------------------- | -------------------------------------------------------------------------------- | |  | ||||||
| | [`@0x/instant`](/packages/instant)                 | A free and flexible way to offer simple crypto purchasing in any app or website. | |  | ||||||
| | [`@0x/testnet-faucets`](/packages/testnet-faucets) | A faucet micro-service that dispenses test ERC20 tokens or Ether                 | |  | ||||||
|  |  | ||||||
| ## Usage | ## Usage | ||||||
|  |  | ||||||
| @@ -132,8 +81,6 @@ Then install dependencies | |||||||
| yarn install | yarn install | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| You will also need to have Python 3 installed, in order to build and run the tests of `abi-gen`'s command-line interface, which is integrated with the yarn build, yarn test, and yarn lint commands described below. More specifically, your local pip should resolve to the Python 3 version of pip, not a Python 2.x version. |  | ||||||
|  |  | ||||||
| ### Build | ### Build | ||||||
|  |  | ||||||
| To build all packages: | To build all packages: | ||||||
| @@ -145,7 +92,7 @@ yarn build | |||||||
| To build a specific package: | To build a specific package: | ||||||
|  |  | ||||||
| ```bash | ```bash | ||||||
| PKG=@0x/web3-wrapper yarn build | PKG=@0x/contract-wrappers yarn build | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| To build all contracts packages: | To build all contracts packages: | ||||||
| @@ -168,7 +115,7 @@ To watch a specific package and all it's dependent packages: | |||||||
| PKG=[NPM_PACKAGE_NAME] yarn watch | PKG=[NPM_PACKAGE_NAME] yarn watch | ||||||
|  |  | ||||||
| e.g | e.g | ||||||
| PKG=@0x/web3-wrapper yarn watch | PKG=@0x/contract-wrappers yarn watch | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| ### Clean | ### Clean | ||||||
| @@ -196,7 +143,7 @@ yarn rebuild | |||||||
| To re-build (clean & build) a specific package & it's deps: | To re-build (clean & build) a specific package & it's deps: | ||||||
|  |  | ||||||
| ```bash | ```bash | ||||||
| PKG=0x.js yarn rebuild | PKG=@0x/contract-wrappers yarn rebuild | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| ### Lint | ### Lint | ||||||
| @@ -210,7 +157,7 @@ yarn lint | |||||||
| Lint a specific package: | Lint a specific package: | ||||||
|  |  | ||||||
| ```bash | ```bash | ||||||
| PKG=0x.js yarn lint | PKG=@0x/contract-wrappers yarn lint | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| ### Run Tests | ### Run Tests | ||||||
| @@ -224,7 +171,7 @@ yarn test | |||||||
| Run a specific package's test: | Run a specific package's test: | ||||||
|  |  | ||||||
| ```bash | ```bash | ||||||
| PKG=@0x/web3-wrapper yarn test | PKG=@0x/contract-wrappers yarn test | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| Run all contracts packages tests: | Run all contracts packages tests: | ||||||
|   | |||||||
| @@ -13,4 +13,4 @@ | |||||||
|  |  | ||||||
| #### Development | #### Development | ||||||
|  |  | ||||||
| Building solidity files will update the contract artifact in `{package-name}/generated-artifacts/{contract}.json`, but does not automatically update the `abi-gen-wrappers` package, which are generated from the artifact JSON. To ensure consistency, clean and rebuild `abi-gen-wrappers` after any changes to the artifact JSON. | Building solidity files will update the contract artifact in `{package-name}/generated-artifacts/{contract}.json`, but does not automatically update the `contract-artifacts` or `contract-wrappers` packages, which are generated from the artifact JSON. See `contract-artifacts/README.md` for instructions on updating these packages. | ||||||
|   | |||||||
| @@ -3,8 +3,8 @@ | |||||||
| * | * | ||||||
| # Whitelist lib | # Whitelist lib | ||||||
| !lib/**/* | !lib/**/* | ||||||
| # Blacklist tests and publish scripts | # Whitelist Solidity contracts | ||||||
|  | !contracts/src/**/* | ||||||
|  | # Blacklist tests in lib | ||||||
| /lib/test/* | /lib/test/* | ||||||
| /lib/monorepo_scripts/ |  | ||||||
| # Package specific ignore | # Package specific ignore | ||||||
| !_bundles/**/* |  | ||||||
| @@ -1,4 +1,352 @@ | |||||||
| [ | [ | ||||||
|  |     { | ||||||
|  |         "timestamp": 1604376968, | ||||||
|  |         "version": "3.6.3", | ||||||
|  |         "changes": [ | ||||||
|  |             { | ||||||
|  |                 "note": "Dependencies updated" | ||||||
|  |             } | ||||||
|  |         ] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |         "timestamp": 1604355662, | ||||||
|  |         "version": "3.6.2", | ||||||
|  |         "changes": [ | ||||||
|  |             { | ||||||
|  |                 "note": "Dependencies updated" | ||||||
|  |             } | ||||||
|  |         ] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |         "timestamp": 1603851023, | ||||||
|  |         "version": "3.6.1", | ||||||
|  |         "changes": [ | ||||||
|  |             { | ||||||
|  |                 "note": "Dependencies updated" | ||||||
|  |             } | ||||||
|  |         ] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |         "version": "3.6.0", | ||||||
|  |         "changes": [ | ||||||
|  |             { | ||||||
|  |                 "note": "Add `SwerveBridge` and `SnowSwapBridge` (duplicate of `CurveBridge`)", | ||||||
|  |                 "pr": 2707 | ||||||
|  |             } | ||||||
|  |         ], | ||||||
|  |         "timestamp": 1603833198 | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |         "version": "3.5.0", | ||||||
|  |         "changes": [ | ||||||
|  |             { | ||||||
|  |                 "note": "Update `CurveBridge` to support more varied curves", | ||||||
|  |                 "pr": 2633 | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |                 "note": "Export DexForwarderBridgeContract", | ||||||
|  |                 "pr": 2656 | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |                 "note": "Add BancorBridge and IBancorNetwork, ", | ||||||
|  |                 "pr": 2650 | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |                 "note": "Added `MStableBridge`", | ||||||
|  |                 "pr": 2662 | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |                 "note": "Added `MooniswapBridge`", | ||||||
|  |                 "pr": 2675 | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |                 "note": "Reworked `KyberBridge`", | ||||||
|  |                 "pr": 2683 | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |                 "note": "Added `CreamBridge`", | ||||||
|  |                 "pr": 2715 | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |                 "note": "Added `ShellBridge`", | ||||||
|  |                 "pr": 2722 | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |                 "note": "Added `DODOBridge`", | ||||||
|  |                 "pr": 2701 | ||||||
|  |             } | ||||||
|  |         ], | ||||||
|  |         "timestamp": 1603265572 | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |         "version": "3.4.0", | ||||||
|  |         "changes": [ | ||||||
|  |             { | ||||||
|  |                 "note": "Fix instability with DFB.", | ||||||
|  |                 "pr": 2616 | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |                 "note": "Add `BalancerBridge`", | ||||||
|  |                 "pr": 2613 | ||||||
|  |             } | ||||||
|  |         ], | ||||||
|  |         "timestamp": 1594788383 | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |         "version": "3.3.0", | ||||||
|  |         "changes": [ | ||||||
|  |             { | ||||||
|  |                 "note": "Use `LibERC20Token.approveIfBelow()` in DEX bridges for for approvals.", | ||||||
|  |                 "pr": 2512 | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |                 "note": "Emit `ERC20BridgeTransfer` events in bridges.", | ||||||
|  |                 "pr": 2512 | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |                 "note": "Change names of `ERC20BridgeTransfer` args to be less ambiguous.", | ||||||
|  |                 "pr": 2524 | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |                 "note": "Added `MixinGasToken` allowing Gas Tokens to be freed", | ||||||
|  |                 "pr": 2523 | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |                 "note": "Add `DexForwaderBridge` bridge contract.", | ||||||
|  |                 "pr": 2525 | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |                 "note": "Add `UniswapV2Bridge` bridge contract.", | ||||||
|  |                 "pr": 2590 | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |                 "note": "Add Gas Token freeing to `DexForwarderBridge` contract.", | ||||||
|  |                 "pr": 2536 | ||||||
|  |             } | ||||||
|  |         ], | ||||||
|  |         "timestamp": 1592969527 | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |         "timestamp": 1583220306, | ||||||
|  |         "version": "3.2.5", | ||||||
|  |         "changes": [ | ||||||
|  |             { | ||||||
|  |                 "note": "Dependencies updated" | ||||||
|  |             } | ||||||
|  |         ] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |         "timestamp": 1582837861, | ||||||
|  |         "version": "3.2.4", | ||||||
|  |         "changes": [ | ||||||
|  |             { | ||||||
|  |                 "note": "Dependencies updated" | ||||||
|  |             } | ||||||
|  |         ] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |         "timestamp": 1582677073, | ||||||
|  |         "version": "3.2.3", | ||||||
|  |         "changes": [ | ||||||
|  |             { | ||||||
|  |                 "note": "Dependencies updated" | ||||||
|  |             } | ||||||
|  |         ] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |         "timestamp": 1582623685, | ||||||
|  |         "version": "3.2.2", | ||||||
|  |         "changes": [ | ||||||
|  |             { | ||||||
|  |                 "note": "Dependencies updated" | ||||||
|  |             } | ||||||
|  |         ] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |         "timestamp": 1581748629, | ||||||
|  |         "version": "3.2.1", | ||||||
|  |         "changes": [ | ||||||
|  |             { | ||||||
|  |                 "note": "Dependencies updated" | ||||||
|  |             } | ||||||
|  |         ] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |         "version": "3.2.0", | ||||||
|  |         "changes": [ | ||||||
|  |             { | ||||||
|  |                 "note": "Add more types and functions to `IDydx`", | ||||||
|  |                 "pr": 2466 | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |                 "note": "Rename `DydxBrigeAction.accountId` to `DydxBridgeAction.accountIdx`", | ||||||
|  |                 "pr": 2466 | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |                 "note": "Fix broken tests.", | ||||||
|  |                 "pr": 2462 | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |                 "note": "Remove dependency on `@0x/contracts-dev-utils`", | ||||||
|  |                 "pr": 2462 | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |                 "note": "Add asset data decoding functions", | ||||||
|  |                 "pr": 2462 | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |                 "note": "Add `setOperators()` to `IDydx`", | ||||||
|  |                 "pr": 2462 | ||||||
|  |             } | ||||||
|  |         ], | ||||||
|  |         "timestamp": 1581204851 | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |         "timestamp": 1580988106, | ||||||
|  |         "version": "3.1.3", | ||||||
|  |         "changes": [ | ||||||
|  |             { | ||||||
|  |                 "note": "Dependencies updated" | ||||||
|  |             } | ||||||
|  |         ] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |         "timestamp": 1580811564, | ||||||
|  |         "version": "3.1.2", | ||||||
|  |         "changes": [ | ||||||
|  |             { | ||||||
|  |                 "note": "Dependencies updated" | ||||||
|  |             } | ||||||
|  |         ] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |         "timestamp": 1579682890, | ||||||
|  |         "version": "3.1.1", | ||||||
|  |         "changes": [ | ||||||
|  |             { | ||||||
|  |                 "note": "Dependencies updated" | ||||||
|  |             } | ||||||
|  |         ] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |         "version": "3.1.0", | ||||||
|  |         "changes": [ | ||||||
|  |             { | ||||||
|  |                 "note": "Integration tests for DydxBridge with ERC20BridgeProxy.", | ||||||
|  |                 "pr": 2401 | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |                 "note": "Fix `UniswapBridge` token -> token transfer call.", | ||||||
|  |                 "pr": 2412 | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |                 "note": "Fix `KyberBridge` incorrect `minConversionRate` calculation.", | ||||||
|  |                 "pr": 2412 | ||||||
|  |             } | ||||||
|  |         ], | ||||||
|  |         "timestamp": 1578272714 | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |         "timestamp": 1576540892, | ||||||
|  |         "version": "3.0.2", | ||||||
|  |         "changes": [ | ||||||
|  |             { | ||||||
|  |                 "note": "Dependencies updated" | ||||||
|  |             } | ||||||
|  |         ] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |         "timestamp": 1575931811, | ||||||
|  |         "version": "3.0.1", | ||||||
|  |         "changes": [ | ||||||
|  |             { | ||||||
|  |                 "note": "Dependencies updated" | ||||||
|  |             } | ||||||
|  |         ] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |         "version": "3.0.0", | ||||||
|  |         "changes": [ | ||||||
|  |             { | ||||||
|  |                 "note": "Implement `KyberBridge`.", | ||||||
|  |                 "pr": 2352 | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |                 "note": "Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils", | ||||||
|  |                 "pr": 2330 | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |                 "note": "ERC20Wrapper and ERC1155ProxyWrapper constructors now require an instance of DevUtilsContract", | ||||||
|  |                 "pr": 2034 | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |                 "note": "Disallow the zero address from being made an authorized address in MixinAuthorizable, and created an archive directory that includes an old version of Ownable", | ||||||
|  |                 "pr": 2019 | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |                 "note": "Remove `LibAssetProxyIds` contract", | ||||||
|  |                 "pr": 2055 | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |                 "note": "Compile and export all contracts, artifacts, and wrappers by default", | ||||||
|  |                 "pr": 2055 | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |                 "note": "Remove unused dependency on IAuthorizable in IAssetProxy", | ||||||
|  |                 "pr": 1910 | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |                 "note": "Add `ERC20BridgeProxy`", | ||||||
|  |                 "pr": 2220 | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |                 "note": "Add `Eth2DaiBridge`", | ||||||
|  |                 "pr": 2221 | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |                 "note": "Add `UniswapBridge`", | ||||||
|  |                 "pr": 2233 | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |                 "note": "Replaced `SafeMath` with `LibSafeMath`", | ||||||
|  |                 "pr": 2254 | ||||||
|  |             } | ||||||
|  |         ], | ||||||
|  |         "timestamp": 1575296764 | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |         "version": "2.3.0-beta.4", | ||||||
|  |         "changes": [ | ||||||
|  |             { | ||||||
|  |                 "note": "Implement `KyberBridge`.", | ||||||
|  |                 "pr": 2352 | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |                 "note": "Implement `DydxBridge`.", | ||||||
|  |                 "pr": 2365 | ||||||
|  |             } | ||||||
|  |         ], | ||||||
|  |         "timestamp": 1575290197 | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |         "version": "2.3.0-beta.3", | ||||||
|  |         "changes": [ | ||||||
|  |             { | ||||||
|  |                 "note": "Dependencies updated" | ||||||
|  |             } | ||||||
|  |         ], | ||||||
|  |         "timestamp": 1574238768 | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |         "version": "2.3.0-beta.2", | ||||||
|  |         "changes": [ | ||||||
|  |             { | ||||||
|  |                 "note": "Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils", | ||||||
|  |                 "pr": 2330 | ||||||
|  |             } | ||||||
|  |         ], | ||||||
|  |         "timestamp": 1574030254 | ||||||
|  |     }, | ||||||
|     { |     { | ||||||
|         "version": "2.3.0-beta.1", |         "version": "2.3.0-beta.1", | ||||||
|         "changes": [ |         "changes": [ | ||||||
|   | |||||||
| @@ -5,6 +5,131 @@ Edit the package's CHANGELOG.json file only. | |||||||
|  |  | ||||||
| CHANGELOG | CHANGELOG | ||||||
|  |  | ||||||
|  | ## v3.6.3 - _November 3, 2020_ | ||||||
|  |  | ||||||
|  |     * Dependencies updated | ||||||
|  |  | ||||||
|  | ## v3.6.2 - _November 2, 2020_ | ||||||
|  |  | ||||||
|  |     * Dependencies updated | ||||||
|  |  | ||||||
|  | ## v3.6.1 - _October 28, 2020_ | ||||||
|  |  | ||||||
|  |     * Dependencies updated | ||||||
|  |  | ||||||
|  | ## v3.6.0 - _October 27, 2020_ | ||||||
|  |  | ||||||
|  |     * Add `SwerveBridge` and `SnowSwapBridge` (duplicate of `CurveBridge`) (#2707) | ||||||
|  |  | ||||||
|  | ## v3.5.0 - _October 21, 2020_ | ||||||
|  |  | ||||||
|  |     * Update `CurveBridge` to support more varied curves (#2633) | ||||||
|  |     * Export DexForwarderBridgeContract (#2656) | ||||||
|  |     * Add BancorBridge and IBancorNetwork,  (#2650) | ||||||
|  |     * Added `MStableBridge` (#2662) | ||||||
|  |     * Added `MooniswapBridge` (#2675) | ||||||
|  |     * Reworked `KyberBridge` (#2683) | ||||||
|  |     * Added `CreamBridge` (#2715) | ||||||
|  |     * Added `ShellBridge` (#2722) | ||||||
|  |     * Added `DODOBridge` (#2701) | ||||||
|  |  | ||||||
|  | ## v3.4.0 - _July 15, 2020_ | ||||||
|  |  | ||||||
|  |     * Fix instability with DFB. (#2616) | ||||||
|  |     * Add `BalancerBridge` (#2613) | ||||||
|  |  | ||||||
|  | ## v3.3.0 - _June 24, 2020_ | ||||||
|  |  | ||||||
|  |     * Use `LibERC20Token.approveIfBelow()` in DEX bridges for for approvals. (#2512) | ||||||
|  |     * Emit `ERC20BridgeTransfer` events in bridges. (#2512) | ||||||
|  |     * Change names of `ERC20BridgeTransfer` args to be less ambiguous. (#2524) | ||||||
|  |     * Added `MixinGasToken` allowing Gas Tokens to be freed (#2523) | ||||||
|  |     * Add `DexForwaderBridge` bridge contract. (#2525) | ||||||
|  |     * Add `UniswapV2Bridge` bridge contract. (#2590) | ||||||
|  |     * Add Gas Token freeing to `DexForwarderBridge` contract. (#2536) | ||||||
|  |  | ||||||
|  | ## v3.2.5 - _March 3, 2020_ | ||||||
|  |  | ||||||
|  |     * Dependencies updated | ||||||
|  |  | ||||||
|  | ## v3.2.4 - _February 27, 2020_ | ||||||
|  |  | ||||||
|  |     * Dependencies updated | ||||||
|  |  | ||||||
|  | ## v3.2.3 - _February 26, 2020_ | ||||||
|  |  | ||||||
|  |     * Dependencies updated | ||||||
|  |  | ||||||
|  | ## v3.2.2 - _February 25, 2020_ | ||||||
|  |  | ||||||
|  |     * Dependencies updated | ||||||
|  |  | ||||||
|  | ## v3.2.1 - _February 15, 2020_ | ||||||
|  |  | ||||||
|  |     * Dependencies updated | ||||||
|  |  | ||||||
|  | ## v3.2.0 - _February 8, 2020_ | ||||||
|  |  | ||||||
|  |     * Add more types and functions to `IDydx` (#2466) | ||||||
|  |     * Rename `DydxBrigeAction.accountId` to `DydxBridgeAction.accountIdx` (#2466) | ||||||
|  |     * Fix broken tests. (#2462) | ||||||
|  |     * Remove dependency on `@0x/contracts-dev-utils` (#2462) | ||||||
|  |     * Add asset data decoding functions (#2462) | ||||||
|  |     * Add `setOperators()` to `IDydx` (#2462) | ||||||
|  |  | ||||||
|  | ## v3.1.3 - _February 6, 2020_ | ||||||
|  |  | ||||||
|  |     * Dependencies updated | ||||||
|  |  | ||||||
|  | ## v3.1.2 - _February 4, 2020_ | ||||||
|  |  | ||||||
|  |     * Dependencies updated | ||||||
|  |  | ||||||
|  | ## v3.1.1 - _January 22, 2020_ | ||||||
|  |  | ||||||
|  |     * Dependencies updated | ||||||
|  |  | ||||||
|  | ## v3.1.0 - _January 6, 2020_ | ||||||
|  |  | ||||||
|  |     * Integration tests for DydxBridge with ERC20BridgeProxy. (#2401) | ||||||
|  |     * Fix `UniswapBridge` token -> token transfer call. (#2412) | ||||||
|  |     * Fix `KyberBridge` incorrect `minConversionRate` calculation. (#2412) | ||||||
|  |  | ||||||
|  | ## v3.0.2 - _December 17, 2019_ | ||||||
|  |  | ||||||
|  |     * Dependencies updated | ||||||
|  |  | ||||||
|  | ## v3.0.1 - _December 9, 2019_ | ||||||
|  |  | ||||||
|  |     * Dependencies updated | ||||||
|  |  | ||||||
|  | ## v3.0.0 - _December 2, 2019_ | ||||||
|  |  | ||||||
|  |     * Implement `KyberBridge`. (#2352) | ||||||
|  |     * Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils (#2330) | ||||||
|  |     * ERC20Wrapper and ERC1155ProxyWrapper constructors now require an instance of DevUtilsContract (#2034) | ||||||
|  |     * Disallow the zero address from being made an authorized address in MixinAuthorizable, and created an archive directory that includes an old version of Ownable (#2019) | ||||||
|  |     * Remove `LibAssetProxyIds` contract (#2055) | ||||||
|  |     * Compile and export all contracts, artifacts, and wrappers by default (#2055) | ||||||
|  |     * Remove unused dependency on IAuthorizable in IAssetProxy (#1910) | ||||||
|  |     * Add `ERC20BridgeProxy` (#2220) | ||||||
|  |     * Add `Eth2DaiBridge` (#2221) | ||||||
|  |     * Add `UniswapBridge` (#2233) | ||||||
|  |     * Replaced `SafeMath` with `LibSafeMath` (#2254) | ||||||
|  |  | ||||||
|  | ## v2.3.0-beta.4 - _December 2, 2019_ | ||||||
|  |  | ||||||
|  |     * Implement `KyberBridge`. (#2352) | ||||||
|  |     * Implement `DydxBridge`. (#2365) | ||||||
|  |  | ||||||
|  | ## v2.3.0-beta.3 - _November 20, 2019_ | ||||||
|  |  | ||||||
|  |     * Dependencies updated | ||||||
|  |  | ||||||
|  | ## v2.3.0-beta.2 - _November 17, 2019_ | ||||||
|  |  | ||||||
|  |     * Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils (#2330) | ||||||
|  |  | ||||||
| ## v2.3.0-beta.1 - _November 7, 2019_ | ## v2.3.0-beta.1 - _November 7, 2019_ | ||||||
|  |  | ||||||
|     * ERC20Wrapper and ERC1155ProxyWrapper constructors now require an instance of DevUtilsContract (#2034) |     * ERC20Wrapper and ERC1155ProxyWrapper constructors now require an instance of DevUtilsContract (#2034) | ||||||
|   | |||||||
| @@ -1,10 +1,11 @@ | |||||||
| { | { | ||||||
|     "artifactsDir": "./generated-artifacts", |     "artifactsDir": "./test/generated-artifacts", | ||||||
|     "contractsDir": "./contracts", |     "contractsDir": "./contracts", | ||||||
|     "useDockerisedSolc": false, |     "useDockerisedSolc": false, | ||||||
|     "isOfflineMode": false, |     "isOfflineMode": false, | ||||||
|  |     "shouldSaveStandardInput": true, | ||||||
|     "compilerSettings": { |     "compilerSettings": { | ||||||
|         "evmVersion": "constantinople", |         "evmVersion": "istanbul", | ||||||
|         "optimizer": { |         "optimizer": { | ||||||
|             "enabled": true, |             "enabled": true, | ||||||
|             "runs": 1000000, |             "runs": 1000000, | ||||||
|   | |||||||
							
								
								
									
										103
									
								
								contracts/asset-proxy/contracts/src/bridges/BalancerBridge.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								contracts/asset-proxy/contracts/src/bridges/BalancerBridge.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,103 @@ | |||||||
|  |  | ||||||
|  | /* | ||||||
|  |  | ||||||
|  |   Copyright 2020 ZeroEx Intl. | ||||||
|  |  | ||||||
|  |   Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |   you may not use this file except in compliance with the License. | ||||||
|  |   You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |     http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |   Unless required by applicable law or agreed to in writing, software | ||||||
|  |   distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |   See the License for the specific language governing permissions and | ||||||
|  |   limitations under the License. | ||||||
|  |  | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | pragma solidity ^0.5.9; | ||||||
|  | pragma experimental ABIEncoderV2; | ||||||
|  |  | ||||||
|  | import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; | ||||||
|  | import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol"; | ||||||
|  | import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol"; | ||||||
|  | import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; | ||||||
|  | import "../interfaces/IERC20Bridge.sol"; | ||||||
|  | import "../interfaces/IBalancerPool.sol"; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | contract BalancerBridge is | ||||||
|  |     IERC20Bridge, | ||||||
|  |     IWallet, | ||||||
|  |     DeploymentConstants | ||||||
|  | { | ||||||
|  |     /// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of | ||||||
|  |     ///      `toTokenAddress` tokens by selling the entirety of the `fromTokenAddress` | ||||||
|  |     ///      token encoded in the bridge data, then transfers the bought | ||||||
|  |     ///      tokens to `to`. | ||||||
|  |     /// @param toTokenAddress The token to buy and transfer to `to`. | ||||||
|  |     /// @param from The maker (this contract). | ||||||
|  |     /// @param to The recipient of the bought tokens. | ||||||
|  |     /// @param amount Minimum amount of `toTokenAddress` tokens to buy. | ||||||
|  |     /// @param bridgeData The abi-encoded addresses of the "from" token and Balancer pool. | ||||||
|  |     /// @return success The magic bytes if successful. | ||||||
|  |     function bridgeTransferFrom( | ||||||
|  |         address toTokenAddress, | ||||||
|  |         address from, | ||||||
|  |         address to, | ||||||
|  |         uint256 amount, | ||||||
|  |         bytes calldata bridgeData | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         returns (bytes4 success) | ||||||
|  |     { | ||||||
|  |         // Decode the bridge data. | ||||||
|  |         (address fromTokenAddress, address poolAddress) = abi.decode( | ||||||
|  |             bridgeData, | ||||||
|  |             (address, address) | ||||||
|  |         ); | ||||||
|  |         require(toTokenAddress != fromTokenAddress, "BalancerBridge/INVALID_PAIR"); | ||||||
|  |  | ||||||
|  |         uint256 fromTokenBalance = IERC20Token(fromTokenAddress).balanceOf(address(this)); | ||||||
|  |         // Grant an allowance to the exchange to spend `fromTokenAddress` token. | ||||||
|  |         LibERC20Token.approveIfBelow(fromTokenAddress, poolAddress, fromTokenBalance); | ||||||
|  |  | ||||||
|  |         // Sell all of this contract's `fromTokenAddress` token balance. | ||||||
|  |         (uint256 boughtAmount,) = IBalancerPool(poolAddress).swapExactAmountIn( | ||||||
|  |             fromTokenAddress, // tokenIn | ||||||
|  |             fromTokenBalance, // tokenAmountIn | ||||||
|  |             toTokenAddress,   // tokenOut | ||||||
|  |             amount,           // minAmountOut | ||||||
|  |             uint256(-1)       // maxPrice | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         // Transfer the converted `toToken`s to `to`. | ||||||
|  |         LibERC20Token.transfer(toTokenAddress, to, boughtAmount); | ||||||
|  |  | ||||||
|  |         emit ERC20BridgeTransfer( | ||||||
|  |             fromTokenAddress, | ||||||
|  |             toTokenAddress, | ||||||
|  |             fromTokenBalance, | ||||||
|  |             boughtAmount, | ||||||
|  |             from, | ||||||
|  |             to | ||||||
|  |         ); | ||||||
|  |         return BRIDGE_SUCCESS; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker | ||||||
|  |     ///      and sign for itself in orders. Always succeeds. | ||||||
|  |     /// @return magicValue Magic success bytes, always. | ||||||
|  |     function isValidSignature( | ||||||
|  |         bytes32, | ||||||
|  |         bytes calldata | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         view | ||||||
|  |         returns (bytes4 magicValue) | ||||||
|  |     { | ||||||
|  |         return LEGACY_WALLET_MAGIC_VALUE; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										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; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  | } | ||||||
							
								
								
									
										75
									
								
								contracts/asset-proxy/contracts/src/bridges/ChaiBridge.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								contracts/asset-proxy/contracts/src/bridges/ChaiBridge.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,75 @@ | |||||||
|  | /* | ||||||
|  |  | ||||||
|  |   Copyright 2019 ZeroEx Intl. | ||||||
|  |  | ||||||
|  |   Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |   you may not use this file except in compliance with the License. | ||||||
|  |   You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |     http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |   Unless required by applicable law or agreed to in writing, software | ||||||
|  |   distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |   See the License for the specific language governing permissions and | ||||||
|  |   limitations under the License. | ||||||
|  |  | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | pragma solidity ^0.5.9; | ||||||
|  | pragma experimental ABIEncoderV2; | ||||||
|  |  | ||||||
|  | import "../interfaces/IERC20Bridge.sol"; | ||||||
|  | import "../interfaces/IChai.sol"; | ||||||
|  | import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; | ||||||
|  | import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // solhint-disable space-after-comma | ||||||
|  | contract ChaiBridge is | ||||||
|  |     IERC20Bridge, | ||||||
|  |     DeploymentConstants | ||||||
|  | { | ||||||
|  |     /// @dev Withdraws `amount` of `from` address's Dai from the Chai contract. | ||||||
|  |     ///      Transfers `amount` of Dai to `to` address. | ||||||
|  |     /// @param from Address to transfer asset from. | ||||||
|  |     /// @param to Address to transfer asset to. | ||||||
|  |     /// @param amount Amount of asset to transfer. | ||||||
|  |     /// @return success The magic bytes `0xdc1600f3` if successful. | ||||||
|  |     function bridgeTransferFrom( | ||||||
|  |         address /* tokenAddress */, | ||||||
|  |         address from, | ||||||
|  |         address to, | ||||||
|  |         uint256 amount, | ||||||
|  |         bytes calldata /* bridgeData */ | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         returns (bytes4 success) | ||||||
|  |     { | ||||||
|  |         // Ensure that only the `ERC20BridgeProxy` can call this function. | ||||||
|  |         require( | ||||||
|  |             msg.sender == _getERC20BridgeProxyAddress(), | ||||||
|  |             "ChaiBridge/ONLY_CALLABLE_BY_ERC20_BRIDGE_PROXY" | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         // Withdraw `from` address's Dai. | ||||||
|  |         // NOTE: This contract must be approved to spend Chai on behalf of `from`. | ||||||
|  |         bytes memory drawCalldata = abi.encodeWithSelector( | ||||||
|  |             IChai(address(0)).draw.selector, | ||||||
|  |             from, | ||||||
|  |             amount | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         (bool success,) = _getChaiAddress().call(drawCalldata); | ||||||
|  |         require( | ||||||
|  |             success, | ||||||
|  |             "ChaiBridge/DRAW_DAI_FAILED" | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         // Transfer Dai to `to` | ||||||
|  |         // This will never fail if the `draw` call was successful | ||||||
|  |         IERC20Token(_getDaiAddress()).transfer(to, amount); | ||||||
|  |  | ||||||
|  |         return BRIDGE_SUCCESS; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										103
									
								
								contracts/asset-proxy/contracts/src/bridges/CreamBridge.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								contracts/asset-proxy/contracts/src/bridges/CreamBridge.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,103 @@ | |||||||
|  |  | ||||||
|  | /* | ||||||
|  |  | ||||||
|  |   Copyright 2020 ZeroEx Intl. | ||||||
|  |  | ||||||
|  |   Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |   you may not use this file except in compliance with the License. | ||||||
|  |   You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |     http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |   Unless required by applicable law or agreed to in writing, software | ||||||
|  |   distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |   See the License for the specific language governing permissions and | ||||||
|  |   limitations under the License. | ||||||
|  |  | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | pragma solidity ^0.5.9; | ||||||
|  | pragma experimental ABIEncoderV2; | ||||||
|  |  | ||||||
|  | import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; | ||||||
|  | import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol"; | ||||||
|  | import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol"; | ||||||
|  | import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; | ||||||
|  | import "../interfaces/IERC20Bridge.sol"; | ||||||
|  | import "../interfaces/IBalancerPool.sol"; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | contract CreamBridge is | ||||||
|  |     IERC20Bridge, | ||||||
|  |     IWallet, | ||||||
|  |     DeploymentConstants | ||||||
|  | { | ||||||
|  |     /// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of | ||||||
|  |     ///      `toTokenAddress` tokens by selling the entirety of the `fromTokenAddress` | ||||||
|  |     ///      token encoded in the bridge data, then transfers the bought | ||||||
|  |     ///      tokens to `to`. | ||||||
|  |     /// @param toTokenAddress The token to buy and transfer to `to`. | ||||||
|  |     /// @param from The maker (this contract). | ||||||
|  |     /// @param to The recipient of the bought tokens. | ||||||
|  |     /// @param amount Minimum amount of `toTokenAddress` tokens to buy. | ||||||
|  |     /// @param bridgeData The abi-encoded addresses of the "from" token and Balancer pool. | ||||||
|  |     /// @return success The magic bytes if successful. | ||||||
|  |     function bridgeTransferFrom( | ||||||
|  |         address toTokenAddress, | ||||||
|  |         address from, | ||||||
|  |         address to, | ||||||
|  |         uint256 amount, | ||||||
|  |         bytes calldata bridgeData | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         returns (bytes4 success) | ||||||
|  |     { | ||||||
|  |         // Decode the bridge data. | ||||||
|  |         (address fromTokenAddress, address poolAddress) = abi.decode( | ||||||
|  |             bridgeData, | ||||||
|  |             (address, address) | ||||||
|  |         ); | ||||||
|  |         require(toTokenAddress != fromTokenAddress, "CreamBridge/INVALID_PAIR"); | ||||||
|  |  | ||||||
|  |         uint256 fromTokenBalance = IERC20Token(fromTokenAddress).balanceOf(address(this)); | ||||||
|  |         // Grant an allowance to the exchange to spend `fromTokenAddress` token. | ||||||
|  |         LibERC20Token.approveIfBelow(fromTokenAddress, poolAddress, fromTokenBalance); | ||||||
|  |  | ||||||
|  |         // Sell all of this contract's `fromTokenAddress` token balance. | ||||||
|  |         (uint256 boughtAmount,) = IBalancerPool(poolAddress).swapExactAmountIn( | ||||||
|  |             fromTokenAddress, // tokenIn | ||||||
|  |             fromTokenBalance, // tokenAmountIn | ||||||
|  |             toTokenAddress,   // tokenOut | ||||||
|  |             amount,           // minAmountOut | ||||||
|  |             uint256(-1)       // maxPrice | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         // Transfer the converted `toToken`s to `to`. | ||||||
|  |         LibERC20Token.transfer(toTokenAddress, to, boughtAmount); | ||||||
|  |  | ||||||
|  |         emit ERC20BridgeTransfer( | ||||||
|  |             fromTokenAddress, | ||||||
|  |             toTokenAddress, | ||||||
|  |             fromTokenBalance, | ||||||
|  |             boughtAmount, | ||||||
|  |             from, | ||||||
|  |             to | ||||||
|  |         ); | ||||||
|  |         return BRIDGE_SUCCESS; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker | ||||||
|  |     ///      and sign for itself in orders. Always succeeds. | ||||||
|  |     /// @return magicValue Magic success bytes, always. | ||||||
|  |     function isValidSignature( | ||||||
|  |         bytes32, | ||||||
|  |         bytes calldata | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         view | ||||||
|  |         returns (bytes4 magicValue) | ||||||
|  |     { | ||||||
|  |         return LEGACY_WALLET_MAGIC_VALUE; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										119
									
								
								contracts/asset-proxy/contracts/src/bridges/CurveBridge.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								contracts/asset-proxy/contracts/src/bridges/CurveBridge.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,119 @@ | |||||||
|  |  | ||||||
|  | /* | ||||||
|  |  | ||||||
|  |   Copyright 2019 ZeroEx Intl. | ||||||
|  |  | ||||||
|  |   Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |   you may not use this file except in compliance with the License. | ||||||
|  |   You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |     http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |   Unless required by applicable law or agreed to in writing, software | ||||||
|  |   distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |   See the License for the specific language governing permissions and | ||||||
|  |   limitations under the License. | ||||||
|  |  | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | pragma solidity ^0.5.9; | ||||||
|  | pragma experimental ABIEncoderV2; | ||||||
|  |  | ||||||
|  | import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; | ||||||
|  | import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol"; | ||||||
|  | import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol"; | ||||||
|  | import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; | ||||||
|  | import "../interfaces/IERC20Bridge.sol"; | ||||||
|  | import "../interfaces/ICurve.sol"; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // solhint-disable not-rely-on-time | ||||||
|  | // solhint-disable space-after-comma | ||||||
|  | contract CurveBridge is | ||||||
|  |     IERC20Bridge, | ||||||
|  |     IWallet, | ||||||
|  |     DeploymentConstants | ||||||
|  | { | ||||||
|  |     struct CurveBridgeData { | ||||||
|  |         address curveAddress; | ||||||
|  |         bytes4 exchangeFunctionSelector; | ||||||
|  |         address fromTokenAddress; | ||||||
|  |         int128 fromCoinIdx; | ||||||
|  |         int128 toCoinIdx; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// @dev Callback for `ICurve`. Tries to buy `amount` of | ||||||
|  |     ///      `toTokenAddress` tokens by selling the entirety of the opposing asset | ||||||
|  |     ///      (DAI, USDC) to the Curve contract, then transfers the bought | ||||||
|  |     ///      tokens to `to`. | ||||||
|  |     /// @param toTokenAddress The token to give to `to` (i.e DAI, USDC, USDT). | ||||||
|  |     /// @param from The maker (this contract). | ||||||
|  |     /// @param to The recipient of the bought tokens. | ||||||
|  |     /// @param amount Minimum amount of `toTokenAddress` tokens to buy. | ||||||
|  |     /// @param bridgeData The abi-encoeded "from" token address. | ||||||
|  |     /// @return success The magic bytes if successful. | ||||||
|  |     function bridgeTransferFrom( | ||||||
|  |         address toTokenAddress, | ||||||
|  |         address from, | ||||||
|  |         address to, | ||||||
|  |         uint256 amount, | ||||||
|  |         bytes calldata bridgeData | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         returns (bytes4 success) | ||||||
|  |     { | ||||||
|  |         // Decode the bridge data to get the Curve metadata. | ||||||
|  |         CurveBridgeData memory data = abi.decode(bridgeData, (CurveBridgeData)); | ||||||
|  |  | ||||||
|  |         require(toTokenAddress != data.fromTokenAddress, "CurveBridge/INVALID_PAIR"); | ||||||
|  |         uint256 fromTokenBalance = IERC20Token(data.fromTokenAddress).balanceOf(address(this)); | ||||||
|  |         // Grant an allowance to the exchange to spend `fromTokenAddress` token. | ||||||
|  |         LibERC20Token.approveIfBelow(data.fromTokenAddress, data.curveAddress, fromTokenBalance); | ||||||
|  |  | ||||||
|  |         // Try to sell all of this contract's `fromTokenAddress` token balance. | ||||||
|  |         { | ||||||
|  |             (bool didSucceed, bytes memory resultData) = | ||||||
|  |                 data.curveAddress.call(abi.encodeWithSelector( | ||||||
|  |                     data.exchangeFunctionSelector, | ||||||
|  |                     data.fromCoinIdx, | ||||||
|  |                     data.toCoinIdx, | ||||||
|  |                     // dx | ||||||
|  |                     fromTokenBalance, | ||||||
|  |                     // min dy | ||||||
|  |                     amount | ||||||
|  |                 )); | ||||||
|  |             if (!didSucceed) { | ||||||
|  |                 assembly { revert(add(resultData, 32), mload(resultData)) } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         uint256 toTokenBalance = IERC20Token(toTokenAddress).balanceOf(address(this)); | ||||||
|  |         // Transfer the converted `toToken`s to `to`. | ||||||
|  |         LibERC20Token.transfer(toTokenAddress, to, toTokenBalance); | ||||||
|  |  | ||||||
|  |         emit ERC20BridgeTransfer( | ||||||
|  |             data.fromTokenAddress, | ||||||
|  |             toTokenAddress, | ||||||
|  |             fromTokenBalance, | ||||||
|  |             toTokenBalance, | ||||||
|  |             from, | ||||||
|  |             to | ||||||
|  |         ); | ||||||
|  |         return BRIDGE_SUCCESS; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker | ||||||
|  |     ///      and sign for itself in orders. Always succeeds. | ||||||
|  |     /// @return magicValue Magic success bytes, always. | ||||||
|  |     function isValidSignature( | ||||||
|  |         bytes32, | ||||||
|  |         bytes calldata | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         view | ||||||
|  |         returns (bytes4 magicValue) | ||||||
|  |     { | ||||||
|  |         return LEGACY_WALLET_MAGIC_VALUE; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										147
									
								
								contracts/asset-proxy/contracts/src/bridges/DODOBridge.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										147
									
								
								contracts/asset-proxy/contracts/src/bridges/DODOBridge.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,147 @@ | |||||||
|  | /* | ||||||
|  |  | ||||||
|  |   Copyright 2020 ZeroEx Intl. | ||||||
|  |  | ||||||
|  |   Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |   you may not use this file except in compliance with the License. | ||||||
|  |   You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |     http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |   Unless required by applicable law or agreed to in writing, software | ||||||
|  |   distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |   See the License for the specific language governing permissions and | ||||||
|  |   limitations under the License. | ||||||
|  |  | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | pragma solidity ^0.5.9; | ||||||
|  | pragma experimental ABIEncoderV2; | ||||||
|  |  | ||||||
|  | import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; | ||||||
|  | import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol"; | ||||||
|  | import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol"; | ||||||
|  | import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; | ||||||
|  | import "../interfaces/IERC20Bridge.sol"; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | interface IDODOHelper { | ||||||
|  |  | ||||||
|  |     function querySellQuoteToken(address dodo, uint256 amount) external view returns (uint256); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | interface IDODO { | ||||||
|  |  | ||||||
|  |     function sellBaseToken(uint256 amount, uint256 minReceiveQuote, bytes calldata data) external returns (uint256); | ||||||
|  |  | ||||||
|  |     function buyBaseToken(uint256 amount, uint256 maxPayQuote, bytes calldata data) external returns (uint256); | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | contract DODOBridge is | ||||||
|  |     IERC20Bridge, | ||||||
|  |     IWallet, | ||||||
|  |     DeploymentConstants | ||||||
|  | { | ||||||
|  |  | ||||||
|  |     struct TransferState { | ||||||
|  |         address fromTokenAddress; | ||||||
|  |         uint256 fromTokenBalance; | ||||||
|  |         address pool; | ||||||
|  |         bool isSellBase; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of | ||||||
|  |     ///      `toTokenAddress` tokens by selling the entirety of the `fromTokenAddress` | ||||||
|  |     ///      token encoded in the bridge data. | ||||||
|  |     /// @param toTokenAddress The token to buy and transfer to `to`. | ||||||
|  |     /// @param from The maker (this contract). | ||||||
|  |     /// @param to The recipient of the bought tokens. | ||||||
|  |     /// @param amount Minimum amount of `toTokenAddress` tokens to buy. | ||||||
|  |     /// @param bridgeData The abi-encoded path of token addresses. Last element must be toTokenAddress | ||||||
|  |     /// @return success The magic bytes if successful. | ||||||
|  |     function bridgeTransferFrom( | ||||||
|  |         address toTokenAddress, | ||||||
|  |         address from, | ||||||
|  |         address to, | ||||||
|  |         uint256 amount, | ||||||
|  |         bytes calldata bridgeData | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         returns (bytes4 success) | ||||||
|  |     { | ||||||
|  |         TransferState memory state; | ||||||
|  |         // Decode the bridge data to get the `fromTokenAddress`. | ||||||
|  |         (state.fromTokenAddress, state.pool, state.isSellBase) = abi.decode(bridgeData, (address, address, bool)); | ||||||
|  |         require(state.pool != address(0), "DODOBridge/InvalidPool"); | ||||||
|  |         IDODO exchange = IDODO(state.pool); | ||||||
|  |         // Get our balance of `fromTokenAddress` token. | ||||||
|  |         state.fromTokenBalance = IERC20Token(state.fromTokenAddress).balanceOf(address(this)); | ||||||
|  |  | ||||||
|  |         // Grant the pool an allowance. | ||||||
|  |         LibERC20Token.approveIfBelow( | ||||||
|  |             state.fromTokenAddress, | ||||||
|  |             address(exchange), | ||||||
|  |             state.fromTokenBalance | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         uint256 boughtAmount; | ||||||
|  |         if (state.isSellBase) { | ||||||
|  |             boughtAmount = exchange.sellBaseToken( | ||||||
|  |                 // amount to sell | ||||||
|  |                 state.fromTokenBalance, | ||||||
|  |                 // min receive amount | ||||||
|  |                 1, | ||||||
|  |                 new bytes(0) | ||||||
|  |             ); | ||||||
|  |         } else { | ||||||
|  |             // Need to re-calculate the sell quote amount into buyBase | ||||||
|  |             boughtAmount = IDODOHelper(_getDODOHelperAddress()).querySellQuoteToken( | ||||||
|  |                 address(exchange), | ||||||
|  |                 state.fromTokenBalance | ||||||
|  |             ); | ||||||
|  |             exchange.buyBaseToken( | ||||||
|  |                 // amount to buy | ||||||
|  |                 boughtAmount, | ||||||
|  |                 // max pay amount | ||||||
|  |                 state.fromTokenBalance, | ||||||
|  |                 new bytes(0) | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|  |         // Transfer funds to `to` | ||||||
|  |         IERC20Token(toTokenAddress).transfer(to, boughtAmount); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |         emit ERC20BridgeTransfer( | ||||||
|  |             // input token | ||||||
|  |             state.fromTokenAddress, | ||||||
|  |             // output token | ||||||
|  |             toTokenAddress, | ||||||
|  |             // input token amount | ||||||
|  |             state.fromTokenBalance, | ||||||
|  |             // output token amount | ||||||
|  |             boughtAmount, | ||||||
|  |             from, | ||||||
|  |             to | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         return BRIDGE_SUCCESS; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker | ||||||
|  |     ///      and sign for itself in orders. Always succeeds. | ||||||
|  |     /// @return magicValue Success bytes, always. | ||||||
|  |     function isValidSignature( | ||||||
|  |         bytes32, | ||||||
|  |         bytes calldata | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         view | ||||||
|  |         returns (bytes4 magicValue) | ||||||
|  |     { | ||||||
|  |         return LEGACY_WALLET_MAGIC_VALUE; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,200 @@ | |||||||
|  | /* | ||||||
|  |  | ||||||
|  |   Copyright 2020 ZeroEx Intl. | ||||||
|  |  | ||||||
|  |   Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |   you may not use this file except in compliance with the License. | ||||||
|  |   You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |     http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |   Unless required by applicable law or agreed to in writing, software | ||||||
|  |   distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |   See the License for the specific language governing permissions and | ||||||
|  |   limitations under the License. | ||||||
|  |  | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | pragma solidity ^0.5.9; | ||||||
|  | pragma experimental ABIEncoderV2; | ||||||
|  |  | ||||||
|  | import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; | ||||||
|  | import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol"; | ||||||
|  | import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol"; | ||||||
|  | import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol"; | ||||||
|  | import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; | ||||||
|  | import "@0x/contracts-utils/contracts/src/LibBytes.sol"; | ||||||
|  | import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; | ||||||
|  | import "../interfaces/IERC20Bridge.sol"; | ||||||
|  | import "./MixinGasToken.sol"; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // solhint-disable space-after-comma, indent | ||||||
|  | contract DexForwarderBridge is | ||||||
|  |     IERC20Bridge, | ||||||
|  |     IWallet, | ||||||
|  |     DeploymentConstants, | ||||||
|  |     MixinGasToken | ||||||
|  | { | ||||||
|  |     using LibSafeMath for uint256; | ||||||
|  |  | ||||||
|  |     /// @dev Data needed to reconstruct a bridge call. | ||||||
|  |     struct BridgeCall { | ||||||
|  |         address target; | ||||||
|  |         uint256 inputTokenAmount; | ||||||
|  |         uint256 outputTokenAmount; | ||||||
|  |         bytes bridgeData; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// @dev Intermediate state variables used by `bridgeTransferFrom()`, in | ||||||
|  |     ///      struct form to get around stack limits. | ||||||
|  |     struct TransferFromState { | ||||||
|  |         address inputToken; | ||||||
|  |         uint256 initialInputTokenBalance; | ||||||
|  |         uint256 callInputTokenAmount; | ||||||
|  |         uint256 callOutputTokenAmount; | ||||||
|  |         uint256 totalInputTokenSold; | ||||||
|  |         BridgeCall[] calls; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// @dev Spends this contract's entire balance of input tokens by forwarding | ||||||
|  |     /// them to other bridges. Reverts if the entire balance is not spent. | ||||||
|  |     /// @param outputToken The token being bought. | ||||||
|  |     /// @param to The recipient of the bought tokens. | ||||||
|  |     /// @param bridgeData The abi-encoded input token address. | ||||||
|  |     /// @return success The magic bytes if successful. | ||||||
|  |     function bridgeTransferFrom( | ||||||
|  |         address outputToken, | ||||||
|  |         address /* from */, | ||||||
|  |         address to, | ||||||
|  |         uint256 /* amount */, | ||||||
|  |         bytes calldata bridgeData | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         freesGasTokensFromCollector | ||||||
|  |         returns (bytes4 success) | ||||||
|  |     { | ||||||
|  |         require( | ||||||
|  |             msg.sender == _getERC20BridgeProxyAddress(), | ||||||
|  |             "DexForwarderBridge/SENDER_NOT_AUTHORIZED" | ||||||
|  |         ); | ||||||
|  |         TransferFromState memory state; | ||||||
|  |         ( | ||||||
|  |             state.inputToken, | ||||||
|  |             state.calls | ||||||
|  |         ) = abi.decode(bridgeData, (address, BridgeCall[])); | ||||||
|  |  | ||||||
|  |         state.initialInputTokenBalance = | ||||||
|  |             IERC20Token(state.inputToken).balanceOf(address(this)); | ||||||
|  |  | ||||||
|  |         for (uint256 i = 0; i < state.calls.length; ++i) { | ||||||
|  |             // Stop if the we've sold all our input tokens. | ||||||
|  |             if (state.totalInputTokenSold >= state.initialInputTokenBalance) { | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             // Compute token amounts. | ||||||
|  |             state.callInputTokenAmount = LibSafeMath.min256( | ||||||
|  |                 state.calls[i].inputTokenAmount, | ||||||
|  |                 state.initialInputTokenBalance.safeSub(state.totalInputTokenSold) | ||||||
|  |             ); | ||||||
|  |             state.callOutputTokenAmount = LibMath.getPartialAmountFloor( | ||||||
|  |                 state.callInputTokenAmount, | ||||||
|  |                 state.calls[i].inputTokenAmount, | ||||||
|  |                 state.calls[i].outputTokenAmount | ||||||
|  |             ); | ||||||
|  |  | ||||||
|  |             // Execute the call in a new context so we can recoup transferred | ||||||
|  |             // funds by reverting. | ||||||
|  |             (bool didSucceed, ) = address(this) | ||||||
|  |                 .call(abi.encodeWithSelector( | ||||||
|  |                     this.executeBridgeCall.selector, | ||||||
|  |                     state.calls[i].target, | ||||||
|  |                     to, | ||||||
|  |                     state.inputToken, | ||||||
|  |                     outputToken, | ||||||
|  |                     state.callInputTokenAmount, | ||||||
|  |                     state.callOutputTokenAmount, | ||||||
|  |                     state.calls[i].bridgeData | ||||||
|  |                 )); | ||||||
|  |  | ||||||
|  |             if (didSucceed) { | ||||||
|  |                 // Increase the amount of tokens sold. | ||||||
|  |                 state.totalInputTokenSold = state.totalInputTokenSold.safeAdd( | ||||||
|  |                     state.callInputTokenAmount | ||||||
|  |                 ); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         // Always succeed. | ||||||
|  |         return BRIDGE_SUCCESS; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// @dev Transfers `inputToken` token to a bridge contract then calls | ||||||
|  |     ///      its `bridgeTransferFrom()`. This is executed in separate context | ||||||
|  |     ///      so we can revert the transfer on error. This can only be called | ||||||
|  |     //       by this contract itself. | ||||||
|  |     /// @param bridge The bridge contract. | ||||||
|  |     /// @param to The recipient of `outputToken` tokens. | ||||||
|  |     /// @param inputToken The input token. | ||||||
|  |     /// @param outputToken The output token. | ||||||
|  |     /// @param inputTokenAmount The amount of input tokens to transfer to `bridge`. | ||||||
|  |     /// @param outputTokenAmount The amount of expected output tokens to be sent | ||||||
|  |     ///        to `to` by `bridge`. | ||||||
|  |     function executeBridgeCall( | ||||||
|  |         address bridge, | ||||||
|  |         address to, | ||||||
|  |         address inputToken, | ||||||
|  |         address outputToken, | ||||||
|  |         uint256 inputTokenAmount, | ||||||
|  |         uint256 outputTokenAmount, | ||||||
|  |         bytes calldata bridgeData | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |     { | ||||||
|  |         // Must be called through `bridgeTransferFrom()`. | ||||||
|  |         require(msg.sender == address(this), "DexForwarderBridge/ONLY_SELF"); | ||||||
|  |         // `bridge` must not be this contract. | ||||||
|  |         require(bridge != address(this)); | ||||||
|  |  | ||||||
|  |         // Get the starting balance of output tokens for `to`. | ||||||
|  |         uint256 initialRecipientBalance = IERC20Token(outputToken).balanceOf(to); | ||||||
|  |  | ||||||
|  |         // Transfer input tokens to the bridge. | ||||||
|  |         LibERC20Token.transfer(inputToken, bridge, inputTokenAmount); | ||||||
|  |  | ||||||
|  |         // Call the bridge. | ||||||
|  |         (bool didSucceed, bytes memory resultData) = | ||||||
|  |             bridge.call(abi.encodeWithSelector( | ||||||
|  |                 IERC20Bridge(0).bridgeTransferFrom.selector, | ||||||
|  |                 outputToken, | ||||||
|  |                 bridge, | ||||||
|  |                 to, | ||||||
|  |                 outputTokenAmount, | ||||||
|  |                 bridgeData | ||||||
|  |             )); | ||||||
|  |  | ||||||
|  |         // Revert if the call failed or not enough tokens were bought. | ||||||
|  |         // This will also undo the token transfer. | ||||||
|  |         require( | ||||||
|  |             didSucceed | ||||||
|  |             && resultData.length == 32 | ||||||
|  |             && LibBytes.readBytes32(resultData, 0) == bytes32(BRIDGE_SUCCESS) | ||||||
|  |             && IERC20Token(outputToken).balanceOf(to).safeSub(initialRecipientBalance) >= outputTokenAmount | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker | ||||||
|  |     ///      and sign for itself in orders. Always succeeds. | ||||||
|  |     /// @return magicValue Magic success bytes, always. | ||||||
|  |     function isValidSignature( | ||||||
|  |         bytes32, | ||||||
|  |         bytes calldata | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         view | ||||||
|  |         returns (bytes4 magicValue) | ||||||
|  |     { | ||||||
|  |         return LEGACY_WALLET_MAGIC_VALUE; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										242
									
								
								contracts/asset-proxy/contracts/src/bridges/DydxBridge.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										242
									
								
								contracts/asset-proxy/contracts/src/bridges/DydxBridge.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,242 @@ | |||||||
|  | /* | ||||||
|  |  | ||||||
|  |   Copyright 2019 ZeroEx Intl. | ||||||
|  |  | ||||||
|  |   Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |   you may not use this file except in compliance with the License. | ||||||
|  |   You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |     http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |   Unless required by applicable law or agreed to in writing, software | ||||||
|  |   distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |   See the License for the specific language governing permissions and | ||||||
|  |   limitations under the License. | ||||||
|  |  | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | pragma solidity ^0.5.9; | ||||||
|  | pragma experimental ABIEncoderV2; | ||||||
|  |  | ||||||
|  | import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; | ||||||
|  | import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; | ||||||
|  | import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol"; | ||||||
|  | import "../interfaces/IERC20Bridge.sol"; | ||||||
|  | import "../interfaces/IDydxBridge.sol"; | ||||||
|  | import "../interfaces/IDydx.sol"; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | contract DydxBridge is | ||||||
|  |     IERC20Bridge, | ||||||
|  |     IDydxBridge, | ||||||
|  |     DeploymentConstants | ||||||
|  | { | ||||||
|  |  | ||||||
|  |     using LibSafeMath for uint256; | ||||||
|  |  | ||||||
|  |     /// @dev Callback for `IERC20Bridge`. Deposits or withdraws tokens from a dydx account. | ||||||
|  |     ///      Notes: | ||||||
|  |     ///         1. This bridge must be set as an operator of the input dydx account. | ||||||
|  |     ///         2. This function may only be called in the context of the 0x Exchange. | ||||||
|  |     ///         3. The maker or taker of the 0x order must be the dydx account owner. | ||||||
|  |     ///         4. Deposits into dydx are made from the `from` address. | ||||||
|  |     ///         5. Withdrawals from dydx are made to the `to` address. | ||||||
|  |     ///         6. Calling this function must always withdraw at least `amount`, | ||||||
|  |     ///            otherwise the `ERC20Bridge` will revert. | ||||||
|  |     /// @param from The sender of the tokens and owner of the dydx account. | ||||||
|  |     /// @param to The recipient of the tokens. | ||||||
|  |     /// @param amount Minimum amount of `toTokenAddress` tokens to deposit or withdraw. | ||||||
|  |     /// @param encodedBridgeData An abi-encoded `BridgeData` struct. | ||||||
|  |     /// @return success The magic bytes if successful. | ||||||
|  |     function bridgeTransferFrom( | ||||||
|  |         address, /* toTokenAddress */ | ||||||
|  |         address from, | ||||||
|  |         address to, | ||||||
|  |         uint256 amount, | ||||||
|  |         bytes calldata encodedBridgeData | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         returns (bytes4 success) | ||||||
|  |     { | ||||||
|  |         // Ensure that only the `ERC20BridgeProxy` can call this function. | ||||||
|  |         require( | ||||||
|  |             msg.sender == _getERC20BridgeProxyAddress(), | ||||||
|  |             "DydxBridge/ONLY_CALLABLE_BY_ERC20_BRIDGE_PROXY" | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         // Decode bridge data. | ||||||
|  |         (BridgeData memory bridgeData) = abi.decode(encodedBridgeData, (BridgeData)); | ||||||
|  |  | ||||||
|  |         // The dydx accounts are owned by the `from` address. | ||||||
|  |         IDydx.AccountInfo[] memory accounts = _createAccounts(from, bridgeData); | ||||||
|  |  | ||||||
|  |         // Create dydx actions to run on the dydx accounts. | ||||||
|  |         IDydx.ActionArgs[] memory actions = _createActions( | ||||||
|  |             from, | ||||||
|  |             to, | ||||||
|  |             amount, | ||||||
|  |             bridgeData | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         // Run operation. This will revert on failure. | ||||||
|  |         IDydx(_getDydxAddress()).operate(accounts, actions); | ||||||
|  |  | ||||||
|  |         return BRIDGE_SUCCESS; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// @dev Creates an array of accounts for dydx to operate on. | ||||||
|  |     ///      All accounts must belong to the same owner. | ||||||
|  |     /// @param accountOwner Owner of the dydx account. | ||||||
|  |     /// @param bridgeData A `BridgeData` struct. | ||||||
|  |     function _createAccounts( | ||||||
|  |         address accountOwner, | ||||||
|  |         BridgeData memory bridgeData | ||||||
|  |     ) | ||||||
|  |         internal | ||||||
|  |         returns (IDydx.AccountInfo[] memory accounts) | ||||||
|  |     { | ||||||
|  |         uint256[] memory accountNumbers = bridgeData.accountNumbers; | ||||||
|  |         uint256 nAccounts = accountNumbers.length; | ||||||
|  |         accounts = new IDydx.AccountInfo[](nAccounts); | ||||||
|  |         for (uint256 i = 0; i < nAccounts; ++i) { | ||||||
|  |             accounts[i] = IDydx.AccountInfo({ | ||||||
|  |                 owner: accountOwner, | ||||||
|  |                 number: accountNumbers[i] | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// @dev Creates an array of actions to carry out on dydx. | ||||||
|  |     /// @param depositFrom Deposit value from this address (owner of the dydx account). | ||||||
|  |     /// @param withdrawTo Withdraw value to this address. | ||||||
|  |     /// @param amount The amount of value available to operate on. | ||||||
|  |     /// @param bridgeData A `BridgeData` struct. | ||||||
|  |     function _createActions( | ||||||
|  |         address depositFrom, | ||||||
|  |         address withdrawTo, | ||||||
|  |         uint256 amount, | ||||||
|  |         BridgeData memory bridgeData | ||||||
|  |     ) | ||||||
|  |         internal | ||||||
|  |         returns (IDydx.ActionArgs[] memory actions) | ||||||
|  |     { | ||||||
|  |         BridgeAction[] memory bridgeActions = bridgeData.actions; | ||||||
|  |         uint256 nBridgeActions = bridgeActions.length; | ||||||
|  |         actions = new IDydx.ActionArgs[](nBridgeActions); | ||||||
|  |         for (uint256 i = 0; i < nBridgeActions; ++i) { | ||||||
|  |             // Cache current bridge action. | ||||||
|  |             BridgeAction memory bridgeAction = bridgeActions[i]; | ||||||
|  |  | ||||||
|  |             // Scale amount, if conversion rate is set. | ||||||
|  |             uint256 scaledAmount; | ||||||
|  |             if (bridgeAction.conversionRateDenominator > 0) { | ||||||
|  |                 scaledAmount = LibMath.safeGetPartialAmountFloor( | ||||||
|  |                     bridgeAction.conversionRateNumerator, | ||||||
|  |                     bridgeAction.conversionRateDenominator, | ||||||
|  |                     amount | ||||||
|  |                 ); | ||||||
|  |             } else { | ||||||
|  |                 scaledAmount = amount; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             // Construct dydx action. | ||||||
|  |             if (bridgeAction.actionType == BridgeActionType.Deposit) { | ||||||
|  |                 // Deposit tokens from the account owner into their dydx account. | ||||||
|  |                 actions[i] = _createDepositAction( | ||||||
|  |                     depositFrom, | ||||||
|  |                     scaledAmount, | ||||||
|  |                     bridgeAction | ||||||
|  |                 ); | ||||||
|  |             } else if (bridgeAction.actionType == BridgeActionType.Withdraw) { | ||||||
|  |                 // Withdraw tokens from dydx to the `otherAccount`. | ||||||
|  |                 actions[i] = _createWithdrawAction( | ||||||
|  |                     withdrawTo, | ||||||
|  |                     scaledAmount, | ||||||
|  |                     bridgeAction | ||||||
|  |                 ); | ||||||
|  |             } else { | ||||||
|  |                 // If all values in the `Action` enum are handled then this | ||||||
|  |                 // revert is unreachable: Solidity will revert when casting | ||||||
|  |                 // from `uint8` to `Action`. | ||||||
|  |                 revert("DydxBridge/UNRECOGNIZED_BRIDGE_ACTION"); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// @dev Returns a dydx `DepositAction`. | ||||||
|  |     /// @param depositFrom Deposit tokens from this address who is also the account owner. | ||||||
|  |     /// @param amount of tokens to deposit. | ||||||
|  |     /// @param bridgeAction A `BridgeAction` struct. | ||||||
|  |     /// @return depositAction The encoded dydx action. | ||||||
|  |     function _createDepositAction( | ||||||
|  |         address depositFrom, | ||||||
|  |         uint256 amount, | ||||||
|  |         BridgeAction memory bridgeAction | ||||||
|  |     ) | ||||||
|  |         internal | ||||||
|  |         pure | ||||||
|  |         returns ( | ||||||
|  |             IDydx.ActionArgs memory depositAction | ||||||
|  |         ) | ||||||
|  |     { | ||||||
|  |         // Create dydx amount. | ||||||
|  |         IDydx.AssetAmount memory dydxAmount = IDydx.AssetAmount({ | ||||||
|  |             sign: true,                                 // true if positive. | ||||||
|  |             denomination: IDydx.AssetDenomination.Wei,  // Wei => actual token amount held in account. | ||||||
|  |             ref: IDydx.AssetReference.Delta,                // Delta => a relative amount. | ||||||
|  |             value: amount                               // amount to deposit. | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         // Create dydx deposit action. | ||||||
|  |         depositAction = IDydx.ActionArgs({ | ||||||
|  |             actionType: IDydx.ActionType.Deposit,           // deposit tokens. | ||||||
|  |             amount: dydxAmount,                             // amount to deposit. | ||||||
|  |             accountIdx: bridgeAction.accountIdx,             // index in the `accounts` when calling `operate`. | ||||||
|  |             primaryMarketId: bridgeAction.marketId,         // indicates which token to deposit. | ||||||
|  |             otherAddress: depositFrom,                      // deposit from the account owner. | ||||||
|  |             // unused parameters | ||||||
|  |             secondaryMarketId: 0, | ||||||
|  |             otherAccountIdx: 0, | ||||||
|  |             data: hex'' | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// @dev Returns a dydx `WithdrawAction`. | ||||||
|  |     /// @param withdrawTo Withdraw tokens to this address. | ||||||
|  |     /// @param amount of tokens to withdraw. | ||||||
|  |     /// @param bridgeAction A `BridgeAction` struct. | ||||||
|  |     /// @return withdrawAction The encoded dydx action. | ||||||
|  |     function _createWithdrawAction( | ||||||
|  |         address withdrawTo, | ||||||
|  |         uint256 amount, | ||||||
|  |         BridgeAction memory bridgeAction | ||||||
|  |     ) | ||||||
|  |         internal | ||||||
|  |         pure | ||||||
|  |         returns ( | ||||||
|  |             IDydx.ActionArgs memory withdrawAction | ||||||
|  |         ) | ||||||
|  |     { | ||||||
|  |         // Create dydx amount. | ||||||
|  |         IDydx.AssetAmount memory amountToWithdraw = IDydx.AssetAmount({ | ||||||
|  |             sign: false,                                    // false if negative. | ||||||
|  |             denomination: IDydx.AssetDenomination.Wei,      // Wei => actual token amount held in account. | ||||||
|  |             ref: IDydx.AssetReference.Delta,                // Delta => a relative amount. | ||||||
|  |             value: amount                                   // amount to withdraw. | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         // Create withdraw action. | ||||||
|  |         withdrawAction = IDydx.ActionArgs({ | ||||||
|  |             actionType: IDydx.ActionType.Withdraw,          // withdraw tokens. | ||||||
|  |             amount: amountToWithdraw,                       // amount to withdraw. | ||||||
|  |             accountIdx: bridgeAction.accountIdx,            // index in the `accounts` when calling `operate`. | ||||||
|  |             primaryMarketId: bridgeAction.marketId,         // indicates which token to withdraw. | ||||||
|  |             otherAddress: withdrawTo,                       // withdraw tokens to this address. | ||||||
|  |             // unused parameters | ||||||
|  |             secondaryMarketId: 0, | ||||||
|  |             otherAccountIdx: 0, | ||||||
|  |             data: hex'' | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -22,6 +22,7 @@ pragma experimental ABIEncoderV2; | |||||||
| import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; | import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; | ||||||
| import "@0x/contracts-erc20/contracts/src/LibERC20Token.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/IWallet.sol"; | ||||||
|  | import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; | ||||||
| import "../interfaces/IERC20Bridge.sol"; | import "../interfaces/IERC20Bridge.sol"; | ||||||
| import "../interfaces/IEth2Dai.sol"; | import "../interfaces/IEth2Dai.sol"; | ||||||
|  |  | ||||||
| @@ -29,23 +30,22 @@ import "../interfaces/IEth2Dai.sol"; | |||||||
| // solhint-disable space-after-comma | // solhint-disable space-after-comma | ||||||
| contract Eth2DaiBridge is | contract Eth2DaiBridge is | ||||||
|     IERC20Bridge, |     IERC20Bridge, | ||||||
|     IWallet |     IWallet, | ||||||
|  |     DeploymentConstants | ||||||
| { | { | ||||||
|     /* Mainnet addresses */ |  | ||||||
|     address constant public ETH2DAI_ADDRESS = 0x39755357759cE0d7f32dC8dC45414CCa409AE24e; |  | ||||||
|  |  | ||||||
|     /// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of |     /// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of | ||||||
|     ///      `toTokenAddress` tokens by selling the entirety of the opposing asset |     ///      `toTokenAddress` tokens by selling the entirety of the opposing asset | ||||||
|     ///      (DAI or WETH) to the Eth2Dai contract, then transfers the bought |     ///      (DAI or WETH) to the Eth2Dai contract, then transfers the bought | ||||||
|     ///      tokens to `to`. |     ///      tokens to `to`. | ||||||
|     /// @param toTokenAddress The token to give to `to` (either DAI or WETH). |     /// @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 to The recipient of the bought tokens. | ||||||
|     /// @param amount Minimum amount of `toTokenAddress` tokens to buy. |     /// @param amount Minimum amount of `toTokenAddress` tokens to buy. | ||||||
|     /// @param bridgeData The abi-encoeded "from" token address. |     /// @param bridgeData The abi-encoeded "from" token address. | ||||||
|     /// @return success The magic bytes if successful. |     /// @return success The magic bytes if successful. | ||||||
|     function bridgeTransferFrom( |     function bridgeTransferFrom( | ||||||
|         address toTokenAddress, |         address toTokenAddress, | ||||||
|         address /* from */, |         address from, | ||||||
|         address to, |         address to, | ||||||
|         uint256 amount, |         uint256 amount, | ||||||
|         bytes calldata bridgeData |         bytes calldata bridgeData | ||||||
| @@ -56,19 +56,29 @@ contract Eth2DaiBridge is | |||||||
|         // Decode the bridge data to get the `fromTokenAddress`. |         // Decode the bridge data to get the `fromTokenAddress`. | ||||||
|         (address fromTokenAddress) = abi.decode(bridgeData, (address)); |         (address fromTokenAddress) = abi.decode(bridgeData, (address)); | ||||||
|  |  | ||||||
|         IEth2Dai exchange = _getEth2DaiContract(); |         IEth2Dai exchange = IEth2Dai(_getEth2DaiAddress()); | ||||||
|  |         uint256 fromTokenBalance = IERC20Token(fromTokenAddress).balanceOf(address(this)); | ||||||
|         // Grant an allowance to the exchange to spend `fromTokenAddress` token. |         // 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. |         // Try to sell all of this contract's `fromTokenAddress` token balance. | ||||||
|         uint256 boughtAmount = _getEth2DaiContract().sellAllAmount( |         uint256 boughtAmount = exchange.sellAllAmount( | ||||||
|             address(fromTokenAddress), |             fromTokenAddress, | ||||||
|             IERC20Token(fromTokenAddress).balanceOf(address(this)), |             fromTokenBalance, | ||||||
|             toTokenAddress, |             toTokenAddress, | ||||||
|             amount |             amount | ||||||
|         ); |         ); | ||||||
|         // Transfer the converted `toToken`s to `to`. |         // Transfer the converted `toToken`s to `to`. | ||||||
|         LibERC20Token.transfer(toTokenAddress, to, boughtAmount); |         LibERC20Token.transfer(toTokenAddress, to, boughtAmount); | ||||||
|  |  | ||||||
|  |         emit ERC20BridgeTransfer( | ||||||
|  |             fromTokenAddress, | ||||||
|  |             toTokenAddress, | ||||||
|  |             fromTokenBalance, | ||||||
|  |             boughtAmount, | ||||||
|  |             from, | ||||||
|  |             to | ||||||
|  |         ); | ||||||
|         return BRIDGE_SUCCESS; |         return BRIDGE_SUCCESS; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -85,14 +95,4 @@ contract Eth2DaiBridge is | |||||||
|     { |     { | ||||||
|         return LEGACY_WALLET_MAGIC_VALUE; |         return LEGACY_WALLET_MAGIC_VALUE; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// @dev Overridable way to get the eth2dai contract. |  | ||||||
|     /// @return exchange The Eth2Dai exchange contract. |  | ||||||
|     function _getEth2DaiContract() |  | ||||||
|         internal |  | ||||||
|         view |  | ||||||
|         returns (IEth2Dai exchange) |  | ||||||
|     { |  | ||||||
|         return IEth2Dai(ETH2DAI_ADDRESS); |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										166
									
								
								contracts/asset-proxy/contracts/src/bridges/KyberBridge.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										166
									
								
								contracts/asset-proxy/contracts/src/bridges/KyberBridge.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,166 @@ | |||||||
|  | /* | ||||||
|  |  | ||||||
|  |   Copyright 2020 ZeroEx Intl. | ||||||
|  |  | ||||||
|  |   Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |   you may not use this file except in compliance with the License. | ||||||
|  |   You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |     http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |   Unless required by applicable law or agreed to in writing, software | ||||||
|  |   distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |   See the License for the specific language governing permissions and | ||||||
|  |   limitations under the License. | ||||||
|  |  | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | pragma solidity ^0.5.9; | ||||||
|  | pragma experimental ABIEncoderV2; | ||||||
|  |  | ||||||
|  | import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; | ||||||
|  | import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol"; | ||||||
|  | import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol"; | ||||||
|  | import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol"; | ||||||
|  | import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; | ||||||
|  | import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; | ||||||
|  | import "../interfaces/IERC20Bridge.sol"; | ||||||
|  | import "../interfaces/IKyberNetworkProxy.sol"; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // solhint-disable space-after-comma | ||||||
|  | contract KyberBridge is | ||||||
|  |     IERC20Bridge, | ||||||
|  |     IWallet, | ||||||
|  |     DeploymentConstants | ||||||
|  | { | ||||||
|  |     using LibSafeMath for uint256; | ||||||
|  |  | ||||||
|  |     // @dev Structure used internally to get around stack limits. | ||||||
|  |     struct TradeState { | ||||||
|  |         IKyberNetworkProxy kyber; | ||||||
|  |         IEtherToken weth; | ||||||
|  |         address fromTokenAddress; | ||||||
|  |         uint256 fromTokenBalance; | ||||||
|  |         uint256 payableAmount; | ||||||
|  |         uint256 conversionRate; | ||||||
|  |         bytes hint; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// @dev Kyber ETH pseudo-address. | ||||||
|  |     address constant public KYBER_ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; | ||||||
|  |     /// @dev `bridgeTransferFrom()` failure result. | ||||||
|  |     bytes4 constant private BRIDGE_FAILED = 0x0; | ||||||
|  |     /// @dev Precision of Kyber rates. | ||||||
|  |     uint256 constant private KYBER_RATE_BASE = 10 ** 18; | ||||||
|  |  | ||||||
|  |     // solhint-disable no-empty-blocks | ||||||
|  |     /// @dev Payable fallback to receive ETH from Kyber. | ||||||
|  |     function () | ||||||
|  |         external | ||||||
|  |         payable | ||||||
|  |     {} | ||||||
|  |  | ||||||
|  |     /// @dev Callback for `IKyberBridge`. Tries to buy `amount` of | ||||||
|  |     ///      `toTokenAddress` tokens by selling the entirety of the opposing asset | ||||||
|  |     ///      to the `KyberNetworkProxy` contract, then transfers the bought | ||||||
|  |     ///      tokens to `to`. | ||||||
|  |     /// @param toTokenAddress The token to give to `to`. | ||||||
|  |     /// @param from The maker (this contract). | ||||||
|  |     /// @param to The recipient of the bought tokens. | ||||||
|  |     /// @param amount Minimum amount of `toTokenAddress` tokens to buy. | ||||||
|  |     /// @param bridgeData The abi-encoeded "from" token address. | ||||||
|  |     /// @return success The magic bytes if successful. | ||||||
|  |     function bridgeTransferFrom( | ||||||
|  |         address toTokenAddress, | ||||||
|  |         address from, | ||||||
|  |         address to, | ||||||
|  |         uint256 amount, | ||||||
|  |         bytes calldata bridgeData | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         returns (bytes4 success) | ||||||
|  |     { | ||||||
|  |         TradeState memory state; | ||||||
|  |         state.kyber = IKyberNetworkProxy(_getKyberNetworkProxyAddress()); | ||||||
|  |         state.weth = IEtherToken(_getWethAddress()); | ||||||
|  |         // Decode the bridge data to get the `fromTokenAddress`. | ||||||
|  |         (state.fromTokenAddress, state.hint) = abi.decode(bridgeData, (address, bytes)); | ||||||
|  |         // Query the balance of "from" tokens. | ||||||
|  |         state.fromTokenBalance = IERC20Token(state.fromTokenAddress).balanceOf(address(this)); | ||||||
|  |         if (state.fromTokenBalance == 0) { | ||||||
|  |             // Return failure if no input tokens. | ||||||
|  |             return BRIDGE_FAILED; | ||||||
|  |         } | ||||||
|  |         if (state.fromTokenAddress == toTokenAddress) { | ||||||
|  |             // Just transfer the tokens if they're the same. | ||||||
|  |             LibERC20Token.transfer(state.fromTokenAddress, to, state.fromTokenBalance); | ||||||
|  |             return BRIDGE_SUCCESS; | ||||||
|  |         } | ||||||
|  |         if (state.fromTokenAddress == address(state.weth)) { | ||||||
|  |             // From WETH | ||||||
|  |             state.fromTokenAddress = KYBER_ETH_ADDRESS; | ||||||
|  |             state.payableAmount = state.fromTokenBalance; | ||||||
|  |             state.weth.withdraw(state.fromTokenBalance); | ||||||
|  |         } else { | ||||||
|  |             LibERC20Token.approveIfBelow( | ||||||
|  |                 state.fromTokenAddress, | ||||||
|  |                 address(state.kyber), | ||||||
|  |                 state.fromTokenBalance | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|  |         bool isToTokenWeth = toTokenAddress == address(state.weth); | ||||||
|  |  | ||||||
|  |         // Try to sell all of this contract's input token balance through | ||||||
|  |         // `KyberNetworkProxy.trade()`. | ||||||
|  |         uint256 boughtAmount = state.kyber.tradeWithHint.value(state.payableAmount)( | ||||||
|  |             // Input token. | ||||||
|  |             state.fromTokenAddress, | ||||||
|  |             // Sell amount. | ||||||
|  |             state.fromTokenBalance, | ||||||
|  |             // Output token. | ||||||
|  |             isToTokenWeth ? KYBER_ETH_ADDRESS : toTokenAddress, | ||||||
|  |             // Transfer to this contract if converting to ETH, otherwise | ||||||
|  |             // transfer directly to the recipient. | ||||||
|  |             isToTokenWeth ? address(uint160(address(this))) : address(uint160(to)), | ||||||
|  |             // Buy as much as possible. | ||||||
|  |             uint256(-1), | ||||||
|  |             // The minimum conversion rate | ||||||
|  |             1, | ||||||
|  |             // No affiliate address. | ||||||
|  |             address(0), | ||||||
|  |             state.hint | ||||||
|  |         ); | ||||||
|  |         // Wrap ETH output and transfer to recipient. | ||||||
|  |         if (isToTokenWeth) { | ||||||
|  |             state.weth.deposit.value(boughtAmount)(); | ||||||
|  |             state.weth.transfer(to, boughtAmount); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         emit ERC20BridgeTransfer( | ||||||
|  |             state.fromTokenAddress == KYBER_ETH_ADDRESS ? address(state.weth) : state.fromTokenAddress, | ||||||
|  |             toTokenAddress, | ||||||
|  |             state.fromTokenBalance, | ||||||
|  |             boughtAmount, | ||||||
|  |             from, | ||||||
|  |             to | ||||||
|  |         ); | ||||||
|  |         return BRIDGE_SUCCESS; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker | ||||||
|  |     ///      and sign for itself in orders. Always succeeds. | ||||||
|  |     /// @return magicValue Magic success bytes, always. | ||||||
|  |     function isValidSignature( | ||||||
|  |         bytes32, | ||||||
|  |         bytes calldata | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         view | ||||||
|  |         returns (bytes4 magicValue) | ||||||
|  |     { | ||||||
|  |         return LEGACY_WALLET_MAGIC_VALUE; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -0,0 +1,94 @@ | |||||||
|  | /* | ||||||
|  |  | ||||||
|  |   Copyright 2019 ZeroEx Intl. | ||||||
|  |  | ||||||
|  |   Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |   you may not use this file except in compliance with the License. | ||||||
|  |   You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |     http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |   Unless required by applicable law or agreed to in writing, software | ||||||
|  |   distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |   See the License for the specific language governing permissions and | ||||||
|  |   limitations under the License. | ||||||
|  |  | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | pragma solidity ^0.5.9; | ||||||
|  | pragma experimental ABIEncoderV2; | ||||||
|  |  | ||||||
|  | import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; | ||||||
|  | import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol"; | ||||||
|  | import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol"; | ||||||
|  | import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; | ||||||
|  | import "../interfaces/IERC20Bridge.sol"; | ||||||
|  | import "../interfaces/IMStable.sol"; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | contract MStableBridge is | ||||||
|  |     IERC20Bridge, | ||||||
|  |     IWallet, | ||||||
|  |     DeploymentConstants | ||||||
|  | { | ||||||
|  |  | ||||||
|  |     /// @dev Swaps specified tokens against the mStable mUSD contract | ||||||
|  |     /// @param toTokenAddress The token to give to `to` (i.e DAI, USDC, USDT). | ||||||
|  |     /// @param from The maker (this contract). | ||||||
|  |     /// @param to The recipient of the bought tokens. | ||||||
|  |     /// @param amount Minimum amount of `toTokenAddress` tokens to buy. | ||||||
|  |     /// @param bridgeData The abi-encoded "from" token address. | ||||||
|  |     /// @return success The magic bytes if successful. | ||||||
|  |     // solhint-disable no-unused-vars | ||||||
|  |     function bridgeTransferFrom( | ||||||
|  |         address toTokenAddress, | ||||||
|  |         address from, | ||||||
|  |         address to, | ||||||
|  |         uint256 amount, | ||||||
|  |         bytes calldata bridgeData | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         returns (bytes4 success) | ||||||
|  |     { | ||||||
|  |         // Decode the bridge data to get the `fromTokenAddress`. | ||||||
|  |         (address fromTokenAddress) = abi.decode(bridgeData, (address)); | ||||||
|  |  | ||||||
|  |         IMStable exchange = IMStable(_getMUsdAddress()); | ||||||
|  |         uint256 fromTokenBalance = IERC20Token(fromTokenAddress).balanceOf(address(this)); | ||||||
|  |         // Grant an allowance to the exchange to spend `fromTokenAddress` token. | ||||||
|  |         LibERC20Token.approveIfBelow(fromTokenAddress, address(exchange), fromTokenBalance); | ||||||
|  |  | ||||||
|  |         // Try to sell all of this contract's `fromTokenAddress` token balance. | ||||||
|  |         uint256 boughtAmount = exchange.swap( | ||||||
|  |             fromTokenAddress, | ||||||
|  |             toTokenAddress, | ||||||
|  |             fromTokenBalance, | ||||||
|  |             to | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         emit ERC20BridgeTransfer( | ||||||
|  |             fromTokenAddress, | ||||||
|  |             toTokenAddress, | ||||||
|  |             fromTokenBalance, | ||||||
|  |             boughtAmount, | ||||||
|  |             from, | ||||||
|  |             to | ||||||
|  |         ); | ||||||
|  |         return BRIDGE_SUCCESS; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker | ||||||
|  |     ///      and sign for itself in orders. Always succeeds. | ||||||
|  |     /// @return magicValue Magic success bytes, always. | ||||||
|  |     function isValidSignature( | ||||||
|  |         bytes32, | ||||||
|  |         bytes calldata | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         view | ||||||
|  |         returns (bytes4 magicValue) | ||||||
|  |     { | ||||||
|  |         return LEGACY_WALLET_MAGIC_VALUE; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,55 @@ | |||||||
|  | /* | ||||||
|  |  | ||||||
|  |   Copyright 2019 ZeroEx Intl. | ||||||
|  |  | ||||||
|  |   Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |   you may not use this file except in compliance with the License. | ||||||
|  |   You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |     http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |   Unless required by applicable law or agreed to in writing, software | ||||||
|  |   distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |   See the License for the specific language governing permissions and | ||||||
|  |   limitations under the License. | ||||||
|  |  | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | pragma solidity ^0.5.16; | ||||||
|  |  | ||||||
|  | import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; | ||||||
|  | import "../interfaces/IGasToken.sol"; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | contract MixinGasToken is | ||||||
|  |     DeploymentConstants | ||||||
|  | { | ||||||
|  |  | ||||||
|  |     /// @dev Frees gas tokens based on the amount of gas consumed in the function | ||||||
|  |     modifier freesGasTokens { | ||||||
|  |         uint256 gasBefore = gasleft(); | ||||||
|  |         _; | ||||||
|  |         IGasToken gst = IGasToken(_getGstAddress()); | ||||||
|  |         if (address(gst) != address(0)) { | ||||||
|  |             // (gasUsed + FREE_BASE) / (2 * REIMBURSE - FREE_TOKEN) | ||||||
|  |             //            14154             24000        6870 | ||||||
|  |             uint256 value = (gasBefore - gasleft() + 14154) / 41130; | ||||||
|  |             gst.freeUpTo(value); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// @dev Frees gas tokens using the balance of `from`. Amount freed is based | ||||||
|  |     ///     on the gas consumed in the function | ||||||
|  |     modifier freesGasTokensFromCollector() { | ||||||
|  |         uint256 gasBefore = gasleft(); | ||||||
|  |         _; | ||||||
|  |         IGasToken gst = IGasToken(_getGstAddress()); | ||||||
|  |         if (address(gst) != address(0)) { | ||||||
|  |             // (gasUsed + FREE_BASE) / (2 * REIMBURSE - FREE_TOKEN) | ||||||
|  |             //            14154             24000        6870 | ||||||
|  |             uint256 value = (gasBefore - gasleft() + 14154) / 41130; | ||||||
|  |             gst.freeFromUpTo(_getGstCollectorAddress(), value); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										148
									
								
								contracts/asset-proxy/contracts/src/bridges/MooniswapBridge.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										148
									
								
								contracts/asset-proxy/contracts/src/bridges/MooniswapBridge.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,148 @@ | |||||||
|  | /* | ||||||
|  |  | ||||||
|  |   Copyright 2020 ZeroEx Intl. | ||||||
|  |  | ||||||
|  |   Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |   you may not use this file except in compliance with the License. | ||||||
|  |   You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |     http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |   Unless required by applicable law or agreed to in writing, software | ||||||
|  |   distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |   See the License for the specific language governing permissions and | ||||||
|  |   limitations under the License. | ||||||
|  |  | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | pragma solidity ^0.5.9; | ||||||
|  | pragma experimental ABIEncoderV2; | ||||||
|  |  | ||||||
|  | import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; | ||||||
|  | import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol"; | ||||||
|  | import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol"; | ||||||
|  | import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol"; | ||||||
|  | import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; | ||||||
|  | import "../interfaces/IERC20Bridge.sol"; | ||||||
|  | import "../interfaces/IMooniswap.sol"; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // solhint-disable space-after-comma | ||||||
|  | // solhint-disable not-rely-on-time | ||||||
|  | contract MooniswapBridge is | ||||||
|  |     IERC20Bridge, | ||||||
|  |     IWallet, | ||||||
|  |     DeploymentConstants | ||||||
|  | { | ||||||
|  |  | ||||||
|  |     struct TransferState { | ||||||
|  |         IMooniswap pool; | ||||||
|  |         uint256 fromTokenBalance; | ||||||
|  |         IEtherToken weth; | ||||||
|  |         uint256 boughtAmount; | ||||||
|  |         address fromTokenAddress; | ||||||
|  |         address toTokenAddress; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // solhint-disable no-empty-blocks | ||||||
|  |     /// @dev Payable fallback to receive ETH from uniswap. | ||||||
|  |     function () | ||||||
|  |         external | ||||||
|  |         payable | ||||||
|  |     {} | ||||||
|  |  | ||||||
|  |     /// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of | ||||||
|  |     ///      `toTokenAddress` tokens by selling the entirety of the `fromTokenAddress` | ||||||
|  |     ///      token encoded in the bridge data. | ||||||
|  |     /// @param toTokenAddress The token to buy and transfer to `to`. | ||||||
|  |     /// @param from The maker (this contract). | ||||||
|  |     /// @param to The recipient of the bought tokens. | ||||||
|  |     /// @param amount Minimum amount of `toTokenAddress` tokens to buy. | ||||||
|  |     /// @param bridgeData The abi-encoded path of token addresses. Last element must be toTokenAddress | ||||||
|  |     /// @return success The magic bytes if successful. | ||||||
|  |     function bridgeTransferFrom( | ||||||
|  |         address toTokenAddress, | ||||||
|  |         address from, | ||||||
|  |         address to, | ||||||
|  |         uint256 amount, | ||||||
|  |         bytes calldata bridgeData | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         returns (bytes4 success) | ||||||
|  |     { | ||||||
|  |         // State memory object to avoid stack overflows. | ||||||
|  |         TransferState memory state; | ||||||
|  |         // Decode the bridge data to get the `fromTokenAddress`. | ||||||
|  |         address fromTokenAddress = abi.decode(bridgeData, (address)); | ||||||
|  |         // Get the weth contract. | ||||||
|  |         state.weth = IEtherToken(_getWethAddress()); | ||||||
|  |         // Get our balance of `fromTokenAddress` token. | ||||||
|  |         state.fromTokenBalance = IERC20Token(fromTokenAddress).balanceOf(address(this)); | ||||||
|  |  | ||||||
|  |         state.fromTokenAddress = fromTokenAddress == address(state.weth) ? address(0) : fromTokenAddress; | ||||||
|  |         state.toTokenAddress = toTokenAddress == address(state.weth) ? address(0) : toTokenAddress; | ||||||
|  |         state.pool = IMooniswap( | ||||||
|  |             IMooniswapRegistry(_getMooniswapAddress()).pools( | ||||||
|  |                 state.fromTokenAddress, | ||||||
|  |                 state.toTokenAddress | ||||||
|  |             ) | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         // withdraw WETH to ETH | ||||||
|  |         if (state.fromTokenAddress == address(0)) { | ||||||
|  |             state.weth.withdraw(state.fromTokenBalance); | ||||||
|  |         } else { | ||||||
|  |             // Grant the pool an allowance. | ||||||
|  |             LibERC20Token.approveIfBelow( | ||||||
|  |                 state.fromTokenAddress, | ||||||
|  |                 address(state.pool), | ||||||
|  |                 state.fromTokenBalance | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|  |         uint256 ethValue = state.fromTokenAddress == address(0) ? state.fromTokenBalance : 0; | ||||||
|  |         state.boughtAmount = state.pool.swap.value(ethValue)( | ||||||
|  |             state.fromTokenAddress, | ||||||
|  |             state.toTokenAddress, | ||||||
|  |             state.fromTokenBalance, | ||||||
|  |             amount, | ||||||
|  |             address(0) | ||||||
|  |         ); | ||||||
|  |         // Deposit to WETH | ||||||
|  |         if (state.toTokenAddress == address(0)) { | ||||||
|  |             state.weth.deposit.value(state.boughtAmount)(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Transfer funds to `to` | ||||||
|  |         LibERC20Token.transfer(toTokenAddress, to, state.boughtAmount); | ||||||
|  |  | ||||||
|  |         emit ERC20BridgeTransfer( | ||||||
|  |             // input token | ||||||
|  |             fromTokenAddress, | ||||||
|  |             // output token | ||||||
|  |             toTokenAddress, | ||||||
|  |             // input token amount | ||||||
|  |             state.fromTokenBalance, | ||||||
|  |             // output token amount | ||||||
|  |             state.boughtAmount, | ||||||
|  |             from, | ||||||
|  |             to | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         return BRIDGE_SUCCESS; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker | ||||||
|  |     ///      and sign for itself in orders. Always succeeds. | ||||||
|  |     /// @return magicValue Success bytes, always. | ||||||
|  |     function isValidSignature( | ||||||
|  |         bytes32, | ||||||
|  |         bytes calldata | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         view | ||||||
|  |         returns (bytes4 magicValue) | ||||||
|  |     { | ||||||
|  |         return LEGACY_WALLET_MAGIC_VALUE; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										95
									
								
								contracts/asset-proxy/contracts/src/bridges/ShellBridge.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								contracts/asset-proxy/contracts/src/bridges/ShellBridge.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,95 @@ | |||||||
|  | /* | ||||||
|  |  | ||||||
|  |   Copyright 2019 ZeroEx Intl. | ||||||
|  |  | ||||||
|  |   Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |   you may not use this file except in compliance with the License. | ||||||
|  |   You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |     http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |   Unless required by applicable law or agreed to in writing, software | ||||||
|  |   distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |   See the License for the specific language governing permissions and | ||||||
|  |   limitations under the License. | ||||||
|  |  | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | pragma solidity ^0.5.9; | ||||||
|  | pragma experimental ABIEncoderV2; | ||||||
|  |  | ||||||
|  | import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; | ||||||
|  | import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol"; | ||||||
|  | import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol"; | ||||||
|  | import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; | ||||||
|  | import "../interfaces/IERC20Bridge.sol"; | ||||||
|  | import "../interfaces/IShell.sol"; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | contract ShellBridge is | ||||||
|  |     IERC20Bridge, | ||||||
|  |     IWallet, | ||||||
|  |     DeploymentConstants | ||||||
|  | { | ||||||
|  |  | ||||||
|  |     /// @dev Swaps specified tokens against the Shell contract | ||||||
|  |     /// @param toTokenAddress The token to give to `to`. | ||||||
|  |     /// @param from The maker (this contract). | ||||||
|  |     /// @param to The recipient of the bought tokens. | ||||||
|  |     /// @param amount Minimum amount of `toTokenAddress` tokens to buy. | ||||||
|  |     /// @param bridgeData The abi-encoded "from" token address. | ||||||
|  |     /// @return success The magic bytes if successful. | ||||||
|  |     // solhint-disable no-unused-vars | ||||||
|  |     function bridgeTransferFrom( | ||||||
|  |         address toTokenAddress, | ||||||
|  |         address from, | ||||||
|  |         address to, | ||||||
|  |         uint256 amount, | ||||||
|  |         bytes calldata bridgeData | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         returns (bytes4 success) | ||||||
|  |     { | ||||||
|  |         // Decode the bridge data to get the `fromTokenAddress` and `pool`. | ||||||
|  |         (address fromTokenAddress, address pool) = abi.decode(bridgeData, (address, address)); | ||||||
|  |  | ||||||
|  |         uint256 fromTokenBalance = IERC20Token(fromTokenAddress).balanceOf(address(this)); | ||||||
|  |         // Grant an allowance to the exchange to spend `fromTokenAddress` token. | ||||||
|  |         LibERC20Token.approveIfBelow(fromTokenAddress, pool, fromTokenBalance); | ||||||
|  |  | ||||||
|  |         // Try to sell all of this contract's `fromTokenAddress` token balance. | ||||||
|  |         uint256 boughtAmount = IShell(pool).originSwap( | ||||||
|  |             fromTokenAddress, | ||||||
|  |             toTokenAddress, | ||||||
|  |             fromTokenBalance, | ||||||
|  |             amount, // min amount | ||||||
|  |             block.timestamp + 1 | ||||||
|  |         ); | ||||||
|  |         LibERC20Token.transfer(toTokenAddress, to, boughtAmount); | ||||||
|  |  | ||||||
|  |         emit ERC20BridgeTransfer( | ||||||
|  |             fromTokenAddress, | ||||||
|  |             toTokenAddress, | ||||||
|  |             fromTokenBalance, | ||||||
|  |             boughtAmount, | ||||||
|  |             from, | ||||||
|  |             to | ||||||
|  |         ); | ||||||
|  |         return BRIDGE_SUCCESS; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker | ||||||
|  |     ///      and sign for itself in orders. Always succeeds. | ||||||
|  |     /// @return magicValue Magic success bytes, always. | ||||||
|  |     function isValidSignature( | ||||||
|  |         bytes32, | ||||||
|  |         bytes calldata | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         view | ||||||
|  |         returns (bytes4 magicValue) | ||||||
|  |     { | ||||||
|  |         return LEGACY_WALLET_MAGIC_VALUE; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										119
									
								
								contracts/asset-proxy/contracts/src/bridges/SnowSwapBridge.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								contracts/asset-proxy/contracts/src/bridges/SnowSwapBridge.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,119 @@ | |||||||
|  |  | ||||||
|  | /* | ||||||
|  |  | ||||||
|  |   Copyright 2019 ZeroEx Intl. | ||||||
|  |  | ||||||
|  |   Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |   you may not use this file except in compliance with the License. | ||||||
|  |   You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |     http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |   Unless required by applicable law or agreed to in writing, software | ||||||
|  |   distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |   See the License for the specific language governing permissions and | ||||||
|  |   limitations under the License. | ||||||
|  |  | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | pragma solidity ^0.5.9; | ||||||
|  | pragma experimental ABIEncoderV2; | ||||||
|  |  | ||||||
|  | import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; | ||||||
|  | import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol"; | ||||||
|  | import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol"; | ||||||
|  | import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; | ||||||
|  | import "../interfaces/IERC20Bridge.sol"; | ||||||
|  | import "../interfaces/ICurve.sol"; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // solhint-disable not-rely-on-time | ||||||
|  | // solhint-disable space-after-comma | ||||||
|  | contract SnowSwapBridge is | ||||||
|  |     IERC20Bridge, | ||||||
|  |     IWallet, | ||||||
|  |     DeploymentConstants | ||||||
|  | { | ||||||
|  |     struct SnowSwapBridgeData { | ||||||
|  |         address curveAddress; | ||||||
|  |         bytes4 exchangeFunctionSelector; | ||||||
|  |         address fromTokenAddress; | ||||||
|  |         int128 fromCoinIdx; | ||||||
|  |         int128 toCoinIdx; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// @dev Callback for `ICurve`. Tries to buy `amount` of | ||||||
|  |     ///      `toTokenAddress` tokens by selling the entirety of the opposing asset | ||||||
|  |     ///      (DAI, USDC) to the Curve contract, then transfers the bought | ||||||
|  |     ///      tokens to `to`. | ||||||
|  |     /// @param toTokenAddress The token to give to `to` (i.e DAI, USDC, USDT). | ||||||
|  |     /// @param from The maker (this contract). | ||||||
|  |     /// @param to The recipient of the bought tokens. | ||||||
|  |     /// @param amount Minimum amount of `toTokenAddress` tokens to buy. | ||||||
|  |     /// @param bridgeData The abi-encoeded "from" token address. | ||||||
|  |     /// @return success The magic bytes if successful. | ||||||
|  |     function bridgeTransferFrom( | ||||||
|  |         address toTokenAddress, | ||||||
|  |         address from, | ||||||
|  |         address to, | ||||||
|  |         uint256 amount, | ||||||
|  |         bytes calldata bridgeData | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         returns (bytes4 success) | ||||||
|  |     { | ||||||
|  |         // Decode the bridge data to get the SnowSwap metadata. | ||||||
|  |         SnowSwapBridgeData memory data = abi.decode(bridgeData, (SnowSwapBridgeData)); | ||||||
|  |  | ||||||
|  |         require(toTokenAddress != data.fromTokenAddress, "SnowSwapBridge/INVALID_PAIR"); | ||||||
|  |         uint256 fromTokenBalance = IERC20Token(data.fromTokenAddress).balanceOf(address(this)); | ||||||
|  |         // Grant an allowance to the exchange to spend `fromTokenAddress` token. | ||||||
|  |         LibERC20Token.approveIfBelow(data.fromTokenAddress, data.curveAddress, fromTokenBalance); | ||||||
|  |  | ||||||
|  |         // Try to sell all of this contract's `fromTokenAddress` token balance. | ||||||
|  |         { | ||||||
|  |             (bool didSucceed, bytes memory resultData) = | ||||||
|  |                 data.curveAddress.call(abi.encodeWithSelector( | ||||||
|  |                     data.exchangeFunctionSelector, | ||||||
|  |                     data.fromCoinIdx, | ||||||
|  |                     data.toCoinIdx, | ||||||
|  |                     // dx | ||||||
|  |                     fromTokenBalance, | ||||||
|  |                     // min dy | ||||||
|  |                     amount | ||||||
|  |                 )); | ||||||
|  |             if (!didSucceed) { | ||||||
|  |                 assembly { revert(add(resultData, 32), mload(resultData)) } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         uint256 toTokenBalance = IERC20Token(toTokenAddress).balanceOf(address(this)); | ||||||
|  |         // Transfer the converted `toToken`s to `to`. | ||||||
|  |         LibERC20Token.transfer(toTokenAddress, to, toTokenBalance); | ||||||
|  |  | ||||||
|  |         emit ERC20BridgeTransfer( | ||||||
|  |             data.fromTokenAddress, | ||||||
|  |             toTokenAddress, | ||||||
|  |             fromTokenBalance, | ||||||
|  |             toTokenBalance, | ||||||
|  |             from, | ||||||
|  |             to | ||||||
|  |         ); | ||||||
|  |         return BRIDGE_SUCCESS; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker | ||||||
|  |     ///      and sign for itself in orders. Always succeeds. | ||||||
|  |     /// @return magicValue Magic success bytes, always. | ||||||
|  |     function isValidSignature( | ||||||
|  |         bytes32, | ||||||
|  |         bytes calldata | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         view | ||||||
|  |         returns (bytes4 magicValue) | ||||||
|  |     { | ||||||
|  |         return LEGACY_WALLET_MAGIC_VALUE; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										136
									
								
								contracts/asset-proxy/contracts/src/bridges/SushiSwapBridge.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										136
									
								
								contracts/asset-proxy/contracts/src/bridges/SushiSwapBridge.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,136 @@ | |||||||
|  | /* | ||||||
|  |  | ||||||
|  |   Copyright 2020 ZeroEx Intl. | ||||||
|  |  | ||||||
|  |   Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |   you may not use this file except in compliance with the License. | ||||||
|  |   You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |     http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |   Unless required by applicable law or agreed to in writing, software | ||||||
|  |   distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |   See the License for the specific language governing permissions and | ||||||
|  |   limitations under the License. | ||||||
|  |  | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | pragma solidity ^0.5.9; | ||||||
|  | pragma experimental ABIEncoderV2; | ||||||
|  |  | ||||||
|  | import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; | ||||||
|  | import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol"; | ||||||
|  | import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol"; | ||||||
|  | import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol"; | ||||||
|  | import "@0x/contracts-utils/contracts/src/LibAddressArray.sol"; | ||||||
|  | import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; | ||||||
|  | import "../interfaces/IUniswapV2Router01.sol"; | ||||||
|  | import "../interfaces/IERC20Bridge.sol"; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // solhint-disable space-after-comma | ||||||
|  | // solhint-disable not-rely-on-time | ||||||
|  | contract SushiSwapBridge is | ||||||
|  |     IERC20Bridge, | ||||||
|  |     IWallet, | ||||||
|  |     DeploymentConstants | ||||||
|  | { | ||||||
|  |     struct TransferState { | ||||||
|  |         address[] path; | ||||||
|  |         address router; | ||||||
|  |         uint256 fromTokenBalance; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of | ||||||
|  |     ///      `toTokenAddress` tokens by selling the entirety of the `fromTokenAddress` | ||||||
|  |     ///      token encoded in the bridge data. | ||||||
|  |     /// @param toTokenAddress The token to buy and transfer to `to`. | ||||||
|  |     /// @param from The maker (this contract). | ||||||
|  |     /// @param to The recipient of the bought tokens. | ||||||
|  |     /// @param amount Minimum amount of `toTokenAddress` tokens to buy. | ||||||
|  |     /// @param bridgeData The abi-encoded path of token addresses. Last element must be toTokenAddress | ||||||
|  |     /// @return success The magic bytes if successful. | ||||||
|  |     function bridgeTransferFrom( | ||||||
|  |         address toTokenAddress, | ||||||
|  |         address from, | ||||||
|  |         address to, | ||||||
|  |         uint256 amount, | ||||||
|  |         bytes calldata bridgeData | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         returns (bytes4 success) | ||||||
|  |     { | ||||||
|  |         // hold variables to get around stack depth limitations | ||||||
|  |         TransferState memory state; | ||||||
|  |  | ||||||
|  |         // Decode the bridge data to get the `fromTokenAddress`. | ||||||
|  |         // solhint-disable indent | ||||||
|  |         (state.path, state.router) = abi.decode(bridgeData, (address[], address)); | ||||||
|  |         // solhint-enable indent | ||||||
|  |  | ||||||
|  |         require(state.path.length >= 2, "SushiSwapBridge/PATH_LENGTH_MUST_BE_AT_LEAST_TWO"); | ||||||
|  |         require(state.path[state.path.length - 1] == toTokenAddress, "SushiSwapBridge/LAST_ELEMENT_OF_PATH_MUST_MATCH_OUTPUT_TOKEN"); | ||||||
|  |  | ||||||
|  |         // Just transfer the tokens if they're the same. | ||||||
|  |         if (state.path[0] == toTokenAddress) { | ||||||
|  |             LibERC20Token.transfer(state.path[0], to, amount); | ||||||
|  |             return BRIDGE_SUCCESS; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Get our balance of `fromTokenAddress` token. | ||||||
|  |         state.fromTokenBalance = IERC20Token(state.path[0]).balanceOf(address(this)); | ||||||
|  |  | ||||||
|  |         // Grant the SushiSwap router an allowance. | ||||||
|  |         LibERC20Token.approveIfBelow( | ||||||
|  |             state.path[0], | ||||||
|  |             state.router, | ||||||
|  |             state.fromTokenBalance | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         // Buy as much `toTokenAddress` token with `fromTokenAddress` token | ||||||
|  |         // and transfer it to `to`. | ||||||
|  |         IUniswapV2Router01 router = IUniswapV2Router01(state.router); | ||||||
|  |         uint[] memory amounts = router.swapExactTokensForTokens( | ||||||
|  |              // Sell all tokens we hold. | ||||||
|  |             state.fromTokenBalance, | ||||||
|  |              // Minimum buy amount. | ||||||
|  |             amount, | ||||||
|  |             // Convert `fromTokenAddress` to `toTokenAddress`. | ||||||
|  |             state.path, | ||||||
|  |             // Recipient is `to`. | ||||||
|  |             to, | ||||||
|  |             // Expires after this block. | ||||||
|  |             block.timestamp | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         emit ERC20BridgeTransfer( | ||||||
|  |             // input token | ||||||
|  |             state.path[0], | ||||||
|  |             // output token | ||||||
|  |             toTokenAddress, | ||||||
|  |             // input token amount | ||||||
|  |             state.fromTokenBalance, | ||||||
|  |             // output token amount | ||||||
|  |             amounts[amounts.length - 1], | ||||||
|  |             from, | ||||||
|  |             to | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         return BRIDGE_SUCCESS; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker | ||||||
|  |     ///      and sign for itself in orders. Always succeeds. | ||||||
|  |     /// @return magicValue Success bytes, always. | ||||||
|  |     function isValidSignature( | ||||||
|  |         bytes32, | ||||||
|  |         bytes calldata | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         view | ||||||
|  |         returns (bytes4 magicValue) | ||||||
|  |     { | ||||||
|  |         return LEGACY_WALLET_MAGIC_VALUE; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										119
									
								
								contracts/asset-proxy/contracts/src/bridges/SwerveBridge.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								contracts/asset-proxy/contracts/src/bridges/SwerveBridge.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,119 @@ | |||||||
|  |  | ||||||
|  | /* | ||||||
|  |  | ||||||
|  |   Copyright 2019 ZeroEx Intl. | ||||||
|  |  | ||||||
|  |   Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |   you may not use this file except in compliance with the License. | ||||||
|  |   You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |     http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |   Unless required by applicable law or agreed to in writing, software | ||||||
|  |   distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |   See the License for the specific language governing permissions and | ||||||
|  |   limitations under the License. | ||||||
|  |  | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | pragma solidity ^0.5.9; | ||||||
|  | pragma experimental ABIEncoderV2; | ||||||
|  |  | ||||||
|  | import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; | ||||||
|  | import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol"; | ||||||
|  | import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol"; | ||||||
|  | import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; | ||||||
|  | import "../interfaces/IERC20Bridge.sol"; | ||||||
|  | import "../interfaces/ICurve.sol"; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // solhint-disable not-rely-on-time | ||||||
|  | // solhint-disable space-after-comma | ||||||
|  | contract SwerveBridge is | ||||||
|  |     IERC20Bridge, | ||||||
|  |     IWallet, | ||||||
|  |     DeploymentConstants | ||||||
|  | { | ||||||
|  |     struct SwerveBridgeData { | ||||||
|  |         address curveAddress; | ||||||
|  |         bytes4 exchangeFunctionSelector; | ||||||
|  |         address fromTokenAddress; | ||||||
|  |         int128 fromCoinIdx; | ||||||
|  |         int128 toCoinIdx; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// @dev Callback for `ICurve`. Tries to buy `amount` of | ||||||
|  |     ///      `toTokenAddress` tokens by selling the entirety of the opposing asset | ||||||
|  |     ///      (DAI, USDC) to the Curve contract, then transfers the bought | ||||||
|  |     ///      tokens to `to`. | ||||||
|  |     /// @param toTokenAddress The token to give to `to` (i.e DAI, USDC, USDT). | ||||||
|  |     /// @param from The maker (this contract). | ||||||
|  |     /// @param to The recipient of the bought tokens. | ||||||
|  |     /// @param amount Minimum amount of `toTokenAddress` tokens to buy. | ||||||
|  |     /// @param bridgeData The abi-encoeded "from" token address. | ||||||
|  |     /// @return success The magic bytes if successful. | ||||||
|  |     function bridgeTransferFrom( | ||||||
|  |         address toTokenAddress, | ||||||
|  |         address from, | ||||||
|  |         address to, | ||||||
|  |         uint256 amount, | ||||||
|  |         bytes calldata bridgeData | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         returns (bytes4 success) | ||||||
|  |     { | ||||||
|  |         // Decode the bridge data to get the SwerveBridgeData metadata. | ||||||
|  |         SwerveBridgeData memory data = abi.decode(bridgeData, (SwerveBridgeData)); | ||||||
|  |  | ||||||
|  |         require(toTokenAddress != data.fromTokenAddress, "SwerveBridge/INVALID_PAIR"); | ||||||
|  |         uint256 fromTokenBalance = IERC20Token(data.fromTokenAddress).balanceOf(address(this)); | ||||||
|  |         // Grant an allowance to the exchange to spend `fromTokenAddress` token. | ||||||
|  |         LibERC20Token.approveIfBelow(data.fromTokenAddress, data.curveAddress, fromTokenBalance); | ||||||
|  |  | ||||||
|  |         // Try to sell all of this contract's `fromTokenAddress` token balance. | ||||||
|  |         { | ||||||
|  |             (bool didSucceed, bytes memory resultData) = | ||||||
|  |                 data.curveAddress.call(abi.encodeWithSelector( | ||||||
|  |                     data.exchangeFunctionSelector, | ||||||
|  |                     data.fromCoinIdx, | ||||||
|  |                     data.toCoinIdx, | ||||||
|  |                     // dx | ||||||
|  |                     fromTokenBalance, | ||||||
|  |                     // min dy | ||||||
|  |                     amount | ||||||
|  |                 )); | ||||||
|  |             if (!didSucceed) { | ||||||
|  |                 assembly { revert(add(resultData, 32), mload(resultData)) } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         uint256 toTokenBalance = IERC20Token(toTokenAddress).balanceOf(address(this)); | ||||||
|  |         // Transfer the converted `toToken`s to `to`. | ||||||
|  |         LibERC20Token.transfer(toTokenAddress, to, toTokenBalance); | ||||||
|  |  | ||||||
|  |         emit ERC20BridgeTransfer( | ||||||
|  |             data.fromTokenAddress, | ||||||
|  |             toTokenAddress, | ||||||
|  |             fromTokenBalance, | ||||||
|  |             toTokenBalance, | ||||||
|  |             from, | ||||||
|  |             to | ||||||
|  |         ); | ||||||
|  |         return BRIDGE_SUCCESS; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker | ||||||
|  |     ///      and sign for itself in orders. Always succeeds. | ||||||
|  |     /// @return magicValue Magic success bytes, always. | ||||||
|  |     function isValidSignature( | ||||||
|  |         bytes32, | ||||||
|  |         bytes calldata | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         view | ||||||
|  |         returns (bytes4 magicValue) | ||||||
|  |     { | ||||||
|  |         return LEGACY_WALLET_MAGIC_VALUE; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -23,6 +23,7 @@ import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; | |||||||
| import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol"; | import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol"; | ||||||
| import "@0x/contracts-erc20/contracts/src/LibERC20Token.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/IWallet.sol"; | ||||||
|  | import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; | ||||||
| import "../interfaces/IUniswapExchangeFactory.sol"; | import "../interfaces/IUniswapExchangeFactory.sol"; | ||||||
| import "../interfaces/IUniswapExchange.sol"; | import "../interfaces/IUniswapExchange.sol"; | ||||||
| import "../interfaces/IERC20Bridge.sol"; | import "../interfaces/IERC20Bridge.sol"; | ||||||
| @@ -32,18 +33,16 @@ import "../interfaces/IERC20Bridge.sol"; | |||||||
| // solhint-disable not-rely-on-time | // solhint-disable not-rely-on-time | ||||||
| contract UniswapBridge is | contract UniswapBridge is | ||||||
|     IERC20Bridge, |     IERC20Bridge, | ||||||
|     IWallet |     IWallet, | ||||||
|  |     DeploymentConstants | ||||||
| { | { | ||||||
|     /* Mainnet addresses */ |  | ||||||
|     address constant private UNISWAP_EXCHANGE_FACTORY_ADDRESS = 0xc0a47dFe034B400B47bDaD5FecDa2621de6c4d95; |  | ||||||
|     address constant private WETH_ADDRESS = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; |  | ||||||
|  |  | ||||||
|     // Struct to hold `bridgeTransferFrom()` local variables in memory and to avoid |     // Struct to hold `bridgeTransferFrom()` local variables in memory and to avoid | ||||||
|     // stack overflows. |     // stack overflows. | ||||||
|     struct WithdrawToState { |     struct TransferState { | ||||||
|         IUniswapExchange exchange; |         IUniswapExchange exchange; | ||||||
|         uint256 fromTokenBalance; |         uint256 fromTokenBalance; | ||||||
|         IEtherToken weth; |         IEtherToken weth; | ||||||
|  |         uint256 boughtAmount; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // solhint-disable no-empty-blocks |     // solhint-disable no-empty-blocks | ||||||
| @@ -57,13 +56,14 @@ contract UniswapBridge is | |||||||
|     ///      `toTokenAddress` tokens by selling the entirety of the `fromTokenAddress` |     ///      `toTokenAddress` tokens by selling the entirety of the `fromTokenAddress` | ||||||
|     ///      token encoded in the bridge data. |     ///      token encoded in the bridge data. | ||||||
|     /// @param toTokenAddress The token to buy and transfer 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 to The recipient of the bought tokens. | ||||||
|     /// @param amount Minimum amount of `toTokenAddress` tokens to buy. |     /// @param amount Minimum amount of `toTokenAddress` tokens to buy. | ||||||
|     /// @param bridgeData The abi-encoded "from" token address. |     /// @param bridgeData The abi-encoded "from" token address. | ||||||
|     /// @return success The magic bytes if successful. |     /// @return success The magic bytes if successful. | ||||||
|     function bridgeTransferFrom( |     function bridgeTransferFrom( | ||||||
|         address toTokenAddress, |         address toTokenAddress, | ||||||
|         address /* from */, |         address from, | ||||||
|         address to, |         address to, | ||||||
|         uint256 amount, |         uint256 amount, | ||||||
|         bytes calldata bridgeData |         bytes calldata bridgeData | ||||||
| @@ -72,7 +72,7 @@ contract UniswapBridge is | |||||||
|         returns (bytes4 success) |         returns (bytes4 success) | ||||||
|     { |     { | ||||||
|         // State memory object to avoid stack overflows. |         // State memory object to avoid stack overflows. | ||||||
|         WithdrawToState memory state; |         TransferState memory state; | ||||||
|         // Decode the bridge data to get the `fromTokenAddress`. |         // Decode the bridge data to get the `fromTokenAddress`. | ||||||
|         (address fromTokenAddress) = abi.decode(bridgeData, (address)); |         (address fromTokenAddress) = abi.decode(bridgeData, (address)); | ||||||
|  |  | ||||||
| @@ -90,7 +90,7 @@ contract UniswapBridge is | |||||||
|         // Get our balance of `fromTokenAddress` token. |         // Get our balance of `fromTokenAddress` token. | ||||||
|         state.fromTokenBalance = IERC20Token(fromTokenAddress).balanceOf(address(this)); |         state.fromTokenBalance = IERC20Token(fromTokenAddress).balanceOf(address(this)); | ||||||
|         // Get the weth contract. |         // Get the weth contract. | ||||||
|         state.weth = getWethContract(); |         state.weth = IEtherToken(_getWethAddress()); | ||||||
|  |  | ||||||
|         // Convert from WETH to a token. |         // Convert from WETH to a token. | ||||||
|         if (fromTokenAddress == address(state.weth)) { |         if (fromTokenAddress == address(state.weth)) { | ||||||
| @@ -98,7 +98,7 @@ contract UniswapBridge is | |||||||
|             state.weth.withdraw(state.fromTokenBalance); |             state.weth.withdraw(state.fromTokenBalance); | ||||||
|             // Buy as much of `toTokenAddress` token with ETH as possible and |             // Buy as much of `toTokenAddress` token with ETH as possible and | ||||||
|             // transfer it to `to`. |             // transfer it to `to`. | ||||||
|             state.exchange.ethToTokenTransferInput.value(state.fromTokenBalance)( |             state.boughtAmount = state.exchange.ethToTokenTransferInput.value(state.fromTokenBalance)( | ||||||
|                 // Minimum buy amount. |                 // Minimum buy amount. | ||||||
|                 amount, |                 amount, | ||||||
|                 // Expires after this block. |                 // Expires after this block. | ||||||
| @@ -110,9 +110,9 @@ contract UniswapBridge is | |||||||
|         // Convert from a token to WETH. |         // Convert from a token to WETH. | ||||||
|         } else if (toTokenAddress == address(state.weth)) { |         } else if (toTokenAddress == address(state.weth)) { | ||||||
|             // Grant the exchange an allowance. |             // Grant the exchange an allowance. | ||||||
|             _grantExchangeAllowance(state.exchange, fromTokenAddress); |             _grantExchangeAllowance(state.exchange, fromTokenAddress, state.fromTokenBalance); | ||||||
|             // Buy as much ETH with `fromTokenAddress` token as possible. |             // Buy as much ETH with `fromTokenAddress` token as possible. | ||||||
|             uint256 ethBought = state.exchange.tokenToEthSwapInput( |             state.boughtAmount = state.exchange.tokenToEthSwapInput( | ||||||
|                 // Sell all tokens we hold. |                 // Sell all tokens we hold. | ||||||
|                 state.fromTokenBalance, |                 state.fromTokenBalance, | ||||||
|                 // Minimum buy amount. |                 // Minimum buy amount. | ||||||
| @@ -121,23 +121,23 @@ contract UniswapBridge is | |||||||
|                 block.timestamp |                 block.timestamp | ||||||
|             ); |             ); | ||||||
|             // Wrap the ETH. |             // Wrap the ETH. | ||||||
|             state.weth.deposit.value(ethBought)(); |             state.weth.deposit.value(state.boughtAmount)(); | ||||||
|             // Transfer the WETH to `to`. |             // Transfer the WETH to `to`. | ||||||
|             IEtherToken(toTokenAddress).transfer(to, ethBought); |             IEtherToken(toTokenAddress).transfer(to, state.boughtAmount); | ||||||
|  |  | ||||||
|         // Convert from one token to another. |         // Convert from one token to another. | ||||||
|         } else { |         } else { | ||||||
|             // Grant the exchange an allowance. |             // Grant the exchange an allowance. | ||||||
|             _grantExchangeAllowance(state.exchange, fromTokenAddress); |             _grantExchangeAllowance(state.exchange, fromTokenAddress, state.fromTokenBalance); | ||||||
|             // Buy as much `toTokenAddress` token with `fromTokenAddress` token |             // Buy as much `toTokenAddress` token with `fromTokenAddress` token | ||||||
|             // and transfer it to `to`. |             // and transfer it to `to`. | ||||||
|             state.exchange.tokenToTokenTransferInput( |             state.boughtAmount = state.exchange.tokenToTokenTransferInput( | ||||||
|                 // Sell all tokens we hold. |                 // Sell all tokens we hold. | ||||||
|                 state.fromTokenBalance, |                 state.fromTokenBalance, | ||||||
|                 // Minimum buy amount. |                 // Minimum buy amount. | ||||||
|                 amount, |                 amount, | ||||||
|                 // No minimum intermediate ETH buy amount. |                 // Must buy at least 1 intermediate ETH. | ||||||
|                 0, |                 1, | ||||||
|                 // Expires after this block. |                 // Expires after this block. | ||||||
|                 block.timestamp, |                 block.timestamp, | ||||||
|                 // Recipient is `to`. |                 // Recipient is `to`. | ||||||
| @@ -146,6 +146,15 @@ contract UniswapBridge is | |||||||
|                 toTokenAddress |                 toTokenAddress | ||||||
|             ); |             ); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         emit ERC20BridgeTransfer( | ||||||
|  |             fromTokenAddress, | ||||||
|  |             toTokenAddress, | ||||||
|  |             state.fromTokenBalance, | ||||||
|  |             state.boughtAmount, | ||||||
|  |             from, | ||||||
|  |             to | ||||||
|  |         ); | ||||||
|         return BRIDGE_SUCCESS; |         return BRIDGE_SUCCESS; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -163,34 +172,23 @@ contract UniswapBridge is | |||||||
|         return LEGACY_WALLET_MAGIC_VALUE; |         return LEGACY_WALLET_MAGIC_VALUE; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// @dev Overridable way to get the weth contract. |  | ||||||
|     /// @return token The WETH contract. |  | ||||||
|     function getWethContract() |  | ||||||
|         public |  | ||||||
|         view |  | ||||||
|         returns (IEtherToken token) |  | ||||||
|     { |  | ||||||
|         return IEtherToken(WETH_ADDRESS); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// @dev Overridable way to get the uniswap exchange factory contract. |  | ||||||
|     /// @return factory The exchange factory contract. |  | ||||||
|     function getUniswapExchangeFactoryContract() |  | ||||||
|         public |  | ||||||
|         view |  | ||||||
|         returns (IUniswapExchangeFactory factory) |  | ||||||
|     { |  | ||||||
|         return IUniswapExchangeFactory(UNISWAP_EXCHANGE_FACTORY_ADDRESS); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// @dev Grants an unlimited allowance to the exchange for its token |     /// @dev Grants an unlimited allowance to the exchange for its token | ||||||
|     ///      on behalf of this contract. |     ///      on behalf of this contract. | ||||||
|     /// @param exchange The Uniswap token exchange. |     /// @param exchange The Uniswap token exchange. | ||||||
|     /// @param tokenAddress The token address for the 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 |         private | ||||||
|     { |     { | ||||||
|         LibERC20Token.approve(tokenAddress, address(exchange), uint256(-1)); |         LibERC20Token.approveIfBelow( | ||||||
|  |             tokenAddress, | ||||||
|  |             address(exchange), | ||||||
|  |             minimumAllowance | ||||||
|  |         ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// @dev Retrieves the uniswap exchange for a given token pair. |     /// @dev Retrieves the uniswap exchange for a given token pair. | ||||||
| @@ -209,10 +207,13 @@ contract UniswapBridge is | |||||||
|     { |     { | ||||||
|         address exchangeTokenAddress = fromTokenAddress; |         address exchangeTokenAddress = fromTokenAddress; | ||||||
|         // Whichever isn't WETH is the exchange token. |         // Whichever isn't WETH is the exchange token. | ||||||
|         if (fromTokenAddress == address(getWethContract())) { |         if (fromTokenAddress == _getWethAddress()) { | ||||||
|             exchangeTokenAddress = toTokenAddress; |             exchangeTokenAddress = toTokenAddress; | ||||||
|         } |         } | ||||||
|         exchange = getUniswapExchangeFactoryContract().getExchange(exchangeTokenAddress); |         exchange = IUniswapExchange( | ||||||
|  |             IUniswapExchangeFactory(_getUniswapExchangeFactoryAddress()) | ||||||
|  |             .getExchange(exchangeTokenAddress) | ||||||
|  |         ); | ||||||
|         require(address(exchange) != address(0), "NO_UNISWAP_EXCHANGE_FOR_TOKEN"); |         require(address(exchange) != address(0), "NO_UNISWAP_EXCHANGE_FOR_TOKEN"); | ||||||
|         return exchange; |         return exchange; | ||||||
|     } |     } | ||||||
|   | |||||||
							
								
								
									
										135
									
								
								contracts/asset-proxy/contracts/src/bridges/UniswapV2Bridge.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								contracts/asset-proxy/contracts/src/bridges/UniswapV2Bridge.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,135 @@ | |||||||
|  | /* | ||||||
|  |  | ||||||
|  |   Copyright 2020 ZeroEx Intl. | ||||||
|  |  | ||||||
|  |   Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |   you may not use this file except in compliance with the License. | ||||||
|  |   You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |     http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |   Unless required by applicable law or agreed to in writing, software | ||||||
|  |   distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |   See the License for the specific language governing permissions and | ||||||
|  |   limitations under the License. | ||||||
|  |  | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | pragma solidity ^0.5.9; | ||||||
|  | pragma experimental ABIEncoderV2; | ||||||
|  |  | ||||||
|  | import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; | ||||||
|  | import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol"; | ||||||
|  | import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol"; | ||||||
|  | import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol"; | ||||||
|  | import "@0x/contracts-utils/contracts/src/LibAddressArray.sol"; | ||||||
|  | import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; | ||||||
|  | import "../interfaces/IUniswapV2Router01.sol"; | ||||||
|  | import "../interfaces/IERC20Bridge.sol"; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // solhint-disable space-after-comma | ||||||
|  | // solhint-disable not-rely-on-time | ||||||
|  | contract UniswapV2Bridge is | ||||||
|  |     IERC20Bridge, | ||||||
|  |     IWallet, | ||||||
|  |     DeploymentConstants | ||||||
|  | { | ||||||
|  |     struct TransferState { | ||||||
|  |         address[] path; | ||||||
|  |         uint256 fromTokenBalance; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of | ||||||
|  |     ///      `toTokenAddress` tokens by selling the entirety of the `fromTokenAddress` | ||||||
|  |     ///      token encoded in the bridge data. | ||||||
|  |     /// @param toTokenAddress The token to buy and transfer to `to`. | ||||||
|  |     /// @param from The maker (this contract). | ||||||
|  |     /// @param to The recipient of the bought tokens. | ||||||
|  |     /// @param amount Minimum amount of `toTokenAddress` tokens to buy. | ||||||
|  |     /// @param bridgeData The abi-encoded path of token addresses. Last element must be toTokenAddress | ||||||
|  |     /// @return success The magic bytes if successful. | ||||||
|  |     function bridgeTransferFrom( | ||||||
|  |         address toTokenAddress, | ||||||
|  |         address from, | ||||||
|  |         address to, | ||||||
|  |         uint256 amount, | ||||||
|  |         bytes calldata bridgeData | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         returns (bytes4 success) | ||||||
|  |     { | ||||||
|  |         // hold variables to get around stack depth limitations | ||||||
|  |         TransferState memory state; | ||||||
|  |  | ||||||
|  |         // Decode the bridge data to get the `fromTokenAddress`. | ||||||
|  |         // solhint-disable indent | ||||||
|  |         state.path = abi.decode(bridgeData, (address[])); | ||||||
|  |         // solhint-enable indent | ||||||
|  |  | ||||||
|  |         require(state.path.length >= 2, "UniswapV2Bridge/PATH_LENGTH_MUST_BE_AT_LEAST_TWO"); | ||||||
|  |         require(state.path[state.path.length - 1] == toTokenAddress, "UniswapV2Bridge/LAST_ELEMENT_OF_PATH_MUST_MATCH_OUTPUT_TOKEN"); | ||||||
|  |  | ||||||
|  |         // Just transfer the tokens if they're the same. | ||||||
|  |         if (state.path[0] == toTokenAddress) { | ||||||
|  |             LibERC20Token.transfer(state.path[0], to, amount); | ||||||
|  |             return BRIDGE_SUCCESS; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Get our balance of `fromTokenAddress` token. | ||||||
|  |         state.fromTokenBalance = IERC20Token(state.path[0]).balanceOf(address(this)); | ||||||
|  |  | ||||||
|  |         // Grant the Uniswap router an allowance. | ||||||
|  |         LibERC20Token.approveIfBelow( | ||||||
|  |             state.path[0], | ||||||
|  |             _getUniswapV2Router01Address(), | ||||||
|  |             state.fromTokenBalance | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         // Buy as much `toTokenAddress` token with `fromTokenAddress` token | ||||||
|  |         // and transfer it to `to`. | ||||||
|  |         IUniswapV2Router01 router = IUniswapV2Router01(_getUniswapV2Router01Address()); | ||||||
|  |         uint[] memory amounts = router.swapExactTokensForTokens( | ||||||
|  |              // Sell all tokens we hold. | ||||||
|  |             state.fromTokenBalance, | ||||||
|  |              // Minimum buy amount. | ||||||
|  |             amount, | ||||||
|  |             // Convert `fromTokenAddress` to `toTokenAddress`. | ||||||
|  |             state.path, | ||||||
|  |             // Recipient is `to`. | ||||||
|  |             to, | ||||||
|  |             // Expires after this block. | ||||||
|  |             block.timestamp | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         emit ERC20BridgeTransfer( | ||||||
|  |             // input token | ||||||
|  |             state.path[0], | ||||||
|  |             // output token | ||||||
|  |             toTokenAddress, | ||||||
|  |             // input token amount | ||||||
|  |             state.fromTokenBalance, | ||||||
|  |             // output token amount | ||||||
|  |             amounts[amounts.length - 1], | ||||||
|  |             from, | ||||||
|  |             to | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         return BRIDGE_SUCCESS; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker | ||||||
|  |     ///      and sign for itself in orders. Always succeeds. | ||||||
|  |     /// @return magicValue Success bytes, always. | ||||||
|  |     function isValidSignature( | ||||||
|  |         bytes32, | ||||||
|  |         bytes calldata | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         view | ||||||
|  |         returns (bytes4 magicValue) | ||||||
|  |     { | ||||||
|  |         return LEGACY_WALLET_MAGIC_VALUE; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,39 @@ | |||||||
|  | /* | ||||||
|  |  | ||||||
|  |   Copyright 2020 ZeroEx Intl. | ||||||
|  |  | ||||||
|  |   Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |   you may not use this file except in compliance with the License. | ||||||
|  |   You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |     http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |   Unless required by applicable law or agreed to in writing, software | ||||||
|  |   distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |   See the License for the specific language governing permissions and | ||||||
|  |   limitations under the License. | ||||||
|  |  | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | pragma solidity ^0.5.9; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | interface IBalancerPool { | ||||||
|  |     /// @dev Sell `tokenAmountIn` of `tokenIn` and receive `tokenOut`. | ||||||
|  |     /// @param tokenIn The token being sold | ||||||
|  |     /// @param tokenAmountIn The amount of `tokenIn` to sell. | ||||||
|  |     /// @param tokenOut The token being bought. | ||||||
|  |     /// @param minAmountOut The minimum amount of `tokenOut` to buy. | ||||||
|  |     /// @param maxPrice The maximum value for `spotPriceAfter`. | ||||||
|  |     /// @return tokenAmountOut The amount of `tokenOut` bought. | ||||||
|  |     /// @return spotPriceAfter The new marginal spot price of the given | ||||||
|  |     ///         token pair for this pool. | ||||||
|  |     function swapExactAmountIn( | ||||||
|  |         address tokenIn, | ||||||
|  |         uint tokenAmountIn, | ||||||
|  |         address tokenOut, | ||||||
|  |         uint minAmountOut, | ||||||
|  |         uint maxPrice | ||||||
|  |     ) external returns (uint tokenAmountOut, uint spotPriceAfter); | ||||||
|  | } | ||||||
| @@ -0,0 +1,38 @@ | |||||||
|  | /* | ||||||
|  |  | ||||||
|  |   Copyright 2020 ZeroEx Intl. | ||||||
|  |  | ||||||
|  |   Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |   you may not use this file except in compliance with the License. | ||||||
|  |   You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |     http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |   Unless required by applicable law or agreed to in writing, software | ||||||
|  |   distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |   See the License for the specific language governing permissions and | ||||||
|  |   limitations under the License. | ||||||
|  |  | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | pragma solidity ^0.5.9; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | contract IContractRegistry { | ||||||
|  |     function addressOf( | ||||||
|  |         bytes32 contractName | ||||||
|  |     ) external returns(address); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | contract IBancorNetwork { | ||||||
|  |     function convertByPath( | ||||||
|  |         address[] calldata _path, | ||||||
|  |         uint256 _amount, | ||||||
|  |         uint256 _minReturn, | ||||||
|  |         address _beneficiary, | ||||||
|  |         address _affiliateAccount, | ||||||
|  |         uint256 _affiliateFee | ||||||
|  |     ) external payable returns (uint256); | ||||||
|  | } | ||||||
							
								
								
									
										66
									
								
								contracts/asset-proxy/contracts/src/interfaces/IChai.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								contracts/asset-proxy/contracts/src/interfaces/IChai.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,66 @@ | |||||||
|  | /* | ||||||
|  |  | ||||||
|  |   Copyright 2019 ZeroEx Intl. | ||||||
|  |  | ||||||
|  |   Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |   you may not use this file except in compliance with the License. | ||||||
|  |   You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |     http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |   Unless required by applicable law or agreed to in writing, software | ||||||
|  |   distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |   See the License for the specific language governing permissions and | ||||||
|  |   limitations under the License. | ||||||
|  |  | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | pragma solidity ^0.5.9; | ||||||
|  |  | ||||||
|  | import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | contract PotLike { | ||||||
|  |     function chi() external returns (uint256); | ||||||
|  |     function rho() external returns (uint256); | ||||||
|  |     function drip() external returns (uint256); | ||||||
|  |     function join(uint256) external; | ||||||
|  |     function exit(uint256) external; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // The actual Chai contract can be found here: https://github.com/dapphub/chai | ||||||
|  | contract IChai is | ||||||
|  |     IERC20Token | ||||||
|  | { | ||||||
|  |     /// @dev Withdraws Dai owned by `src` | ||||||
|  |     /// @param src Address that owns Dai. | ||||||
|  |     /// @param wad Amount of Dai to withdraw. | ||||||
|  |     function draw( | ||||||
|  |         address src, | ||||||
|  |         uint256 wad | ||||||
|  |     ) | ||||||
|  |         external; | ||||||
|  |  | ||||||
|  |     /// @dev Queries Dai balance of Chai holder. | ||||||
|  |     /// @param usr Address of Chai holder. | ||||||
|  |     /// @return Dai balance. | ||||||
|  |     function dai(address usr) | ||||||
|  |         external | ||||||
|  |         returns (uint256); | ||||||
|  |  | ||||||
|  |     /// @dev Queries the Pot contract used by the Chai contract. | ||||||
|  |     function pot() | ||||||
|  |         external | ||||||
|  |         returns (PotLike); | ||||||
|  |  | ||||||
|  |     /// @dev Deposits Dai in exchange for Chai | ||||||
|  |     /// @param dst Address to receive Chai. | ||||||
|  |     /// @param wad Amount of Dai to deposit. | ||||||
|  |     function join( | ||||||
|  |         address dst, | ||||||
|  |         uint256 wad | ||||||
|  |     ) | ||||||
|  |         external; | ||||||
|  | } | ||||||
							
								
								
									
										70
									
								
								contracts/asset-proxy/contracts/src/interfaces/ICurve.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								contracts/asset-proxy/contracts/src/interfaces/ICurve.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,70 @@ | |||||||
|  | /* | ||||||
|  |  | ||||||
|  |   Copyright 2019 ZeroEx Intl. | ||||||
|  |  | ||||||
|  |   Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |   you may not use this file except in compliance with the License. | ||||||
|  |   You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |     http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |   Unless required by applicable law or agreed to in writing, software | ||||||
|  |   distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |   See the License for the specific language governing permissions and | ||||||
|  |   limitations under the License. | ||||||
|  |  | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | pragma solidity ^0.5.9; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // solhint-disable func-name-mixedcase | ||||||
|  | interface ICurve { | ||||||
|  |  | ||||||
|  |     /// @dev Sell `sellAmount` of `fromToken` token and receive `toToken` token. | ||||||
|  |     ///      This function exists on later versions of Curve (USDC/DAI/USDT) | ||||||
|  |     /// @param i The token index being sold. | ||||||
|  |     /// @param j The token index being bought. | ||||||
|  |     /// @param sellAmount The amount of token being bought. | ||||||
|  |     /// @param minBuyAmount The minimum buy amount of the token being bought. | ||||||
|  |     function exchange_underlying( | ||||||
|  |         int128 i, | ||||||
|  |         int128 j, | ||||||
|  |         uint256 sellAmount, | ||||||
|  |         uint256 minBuyAmount | ||||||
|  |     ) | ||||||
|  |         external; | ||||||
|  |  | ||||||
|  |     /// @dev Get the amount of `toToken` by selling `sellAmount` of `fromToken` | ||||||
|  |     /// @param i The token index being sold. | ||||||
|  |     /// @param j The token index being bought. | ||||||
|  |     /// @param sellAmount The amount of token being bought. | ||||||
|  |     function get_dy_underlying( | ||||||
|  |         int128 i, | ||||||
|  |         int128 j, | ||||||
|  |         uint256 sellAmount | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         returns (uint256 dy); | ||||||
|  |  | ||||||
|  |     /// @dev Get the amount of `fromToken` by buying `buyAmount` of `toToken` | ||||||
|  |     /// @param i The token index being sold. | ||||||
|  |     /// @param j The token index being bought. | ||||||
|  |     /// @param buyAmount The amount of token being bought. | ||||||
|  |     function get_dx_underlying( | ||||||
|  |         int128 i, | ||||||
|  |         int128 j, | ||||||
|  |         uint256 buyAmount | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         returns (uint256 dx); | ||||||
|  |  | ||||||
|  |     /// @dev Get the underlying token address from the token index | ||||||
|  |     /// @param i The token index. | ||||||
|  |     function underlying_coins( | ||||||
|  |         int128 i | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         returns (address tokenAddress); | ||||||
|  | } | ||||||
							
								
								
									
										192
									
								
								contracts/asset-proxy/contracts/src/interfaces/IDydx.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										192
									
								
								contracts/asset-proxy/contracts/src/interfaces/IDydx.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,192 @@ | |||||||
|  | /* | ||||||
|  |  | ||||||
|  |   Copyright 2019 ZeroEx Intl. | ||||||
|  |  | ||||||
|  |   Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |   you may not use this file except in compliance with the License. | ||||||
|  |   You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |     http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |   Unless required by applicable law or agreed to in writing, software | ||||||
|  |   distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |   See the License for the specific language governing permissions and | ||||||
|  |   limitations under the License. | ||||||
|  |  | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | pragma solidity ^0.5.9; | ||||||
|  | pragma experimental ABIEncoderV2; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | interface IDydx { | ||||||
|  |  | ||||||
|  |     /// @dev Represents the unique key that specifies an account | ||||||
|  |     struct AccountInfo { | ||||||
|  |         address owner;  // The address that owns the account | ||||||
|  |         uint256 number; // A nonce that allows a single address to control many accounts | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     enum ActionType { | ||||||
|  |         Deposit,   // supply tokens | ||||||
|  |         Withdraw,  // borrow tokens | ||||||
|  |         Transfer,  // transfer balance between accounts | ||||||
|  |         Buy,       // buy an amount of some token (externally) | ||||||
|  |         Sell,      // sell an amount of some token (externally) | ||||||
|  |         Trade,     // trade tokens against another account | ||||||
|  |         Liquidate, // liquidate an undercollateralized or expiring account | ||||||
|  |         Vaporize,  // use excess tokens to zero-out a completely negative account | ||||||
|  |         Call       // send arbitrary data to an address | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// @dev Arguments that are passed to Solo in an ordered list as part of a single operation. | ||||||
|  |     /// Each ActionArgs has an actionType which specifies which action struct that this data will be | ||||||
|  |     /// parsed into before being processed. | ||||||
|  |     struct ActionArgs { | ||||||
|  |         ActionType actionType; | ||||||
|  |         uint256 accountIdx; | ||||||
|  |         AssetAmount amount; | ||||||
|  |         uint256 primaryMarketId; | ||||||
|  |         uint256 secondaryMarketId; | ||||||
|  |         address otherAddress; | ||||||
|  |         uint256 otherAccountIdx; | ||||||
|  |         bytes data; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     enum AssetDenomination { | ||||||
|  |         Wei, // the amount is denominated in wei | ||||||
|  |         Par  // the amount is denominated in par | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     enum AssetReference { | ||||||
|  |         Delta, // the amount is given as a delta from the current value | ||||||
|  |         Target // the amount is given as an exact number to end up at | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     struct AssetAmount { | ||||||
|  |         bool sign; // true if positive | ||||||
|  |         AssetDenomination denomination; | ||||||
|  |         AssetReference ref; | ||||||
|  |         uint256 value; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     struct D256 { | ||||||
|  |         uint256 value; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     struct Value { | ||||||
|  |         uint256 value; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     struct Price { | ||||||
|  |         uint256 value; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     struct OperatorArg { | ||||||
|  |         address operator; | ||||||
|  |         bool trusted; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// @dev The global risk parameters that govern the health and security of the system | ||||||
|  |     struct RiskParams { | ||||||
|  |         // Required ratio of over-collateralization | ||||||
|  |         D256 marginRatio; | ||||||
|  |         // Percentage penalty incurred by liquidated accounts | ||||||
|  |         D256 liquidationSpread; | ||||||
|  |         // Percentage of the borrower's interest fee that gets passed to the suppliers | ||||||
|  |         D256 earningsRate; | ||||||
|  |         // The minimum absolute borrow value of an account | ||||||
|  |         // There must be sufficient incentivize to liquidate undercollateralized accounts | ||||||
|  |         Value minBorrowedValue; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// @dev The main entry-point to Solo that allows users and contracts to manage accounts. | ||||||
|  |     ///      Take one or more actions on one or more accounts. The msg.sender must be the owner or | ||||||
|  |     ///      operator of all accounts except for those being liquidated, vaporized, or traded with. | ||||||
|  |     ///      One call to operate() is considered a singular "operation". Account collateralization is | ||||||
|  |     ///      ensured only after the completion of the entire operation. | ||||||
|  |     /// @param  accounts  A list of all accounts that will be used in this operation. Cannot contain | ||||||
|  |     ///                   duplicates. In each action, the relevant account will be referred-to by its | ||||||
|  |     ///                   index in the list. | ||||||
|  |     /// @param  actions   An ordered list of all actions that will be taken in this operation. The | ||||||
|  |     ///                   actions will be processed in order. | ||||||
|  |     function operate( | ||||||
|  |         AccountInfo[] calldata accounts, | ||||||
|  |         ActionArgs[] calldata actions | ||||||
|  |     ) | ||||||
|  |         external; | ||||||
|  |  | ||||||
|  |     // @dev Approves/disapproves any number of operators. An operator is an external address that has the | ||||||
|  |     //      same permissions to manipulate an account as the owner of the account. Operators are simply | ||||||
|  |     //      addresses and therefore may either be externally-owned Ethereum accounts OR smart contracts. | ||||||
|  |     //      Operators are also able to act as AutoTrader contracts on behalf of the account owner if the | ||||||
|  |     //      operator is a smart contract and implements the IAutoTrader interface. | ||||||
|  |     // @param args A list of OperatorArgs which have an address and a boolean. The boolean value | ||||||
|  |     //        denotes whether to approve (true) or revoke approval (false) for that address. | ||||||
|  |     function setOperators(OperatorArg[] calldata args) external; | ||||||
|  |  | ||||||
|  |     /// @dev Return true if a particular address is approved as an operator for an owner's accounts. | ||||||
|  |     ///      Approved operators can act on the accounts of the owner as if it were the operator's own. | ||||||
|  |     /// @param owner The owner of the accounts | ||||||
|  |     /// @param operator The possible operator | ||||||
|  |     /// @return isLocalOperator True if operator is approved for owner's accounts | ||||||
|  |     function getIsLocalOperator( | ||||||
|  |         address owner, | ||||||
|  |         address operator | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         view | ||||||
|  |         returns (bool isLocalOperator); | ||||||
|  |  | ||||||
|  |     /// @dev Get the ERC20 token address for a market. | ||||||
|  |     /// @param marketId The market to query | ||||||
|  |     /// @return tokenAddress The token address | ||||||
|  |     function getMarketTokenAddress( | ||||||
|  |         uint256 marketId | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         view | ||||||
|  |         returns (address tokenAddress); | ||||||
|  |  | ||||||
|  |     /// @dev Get all risk parameters in a single struct. | ||||||
|  |     /// @return riskParams All global risk parameters | ||||||
|  |     function getRiskParams() | ||||||
|  |         external | ||||||
|  |         view | ||||||
|  |         returns (RiskParams memory riskParams); | ||||||
|  |  | ||||||
|  |     /// @dev Get the price of the token for a market. | ||||||
|  |     /// @param marketId The market to query | ||||||
|  |     /// @return price The price of each atomic unit of the token | ||||||
|  |     function getMarketPrice( | ||||||
|  |         uint256 marketId | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         view | ||||||
|  |         returns (Price memory price); | ||||||
|  |  | ||||||
|  |     /// @dev Get the margin premium for a market. A margin premium makes it so that any positions that | ||||||
|  |     ///      include the market require a higher collateralization to avoid being liquidated. | ||||||
|  |     /// @param  marketId  The market to query | ||||||
|  |     /// @return premium The market's margin premium | ||||||
|  |     function getMarketMarginPremium(uint256 marketId) | ||||||
|  |         external | ||||||
|  |         view | ||||||
|  |         returns (D256 memory premium); | ||||||
|  |  | ||||||
|  |     /// @dev Get the total supplied and total borrowed values of an account adjusted by the marginPremium | ||||||
|  |     ///      of each market. Supplied values are divided by (1 + marginPremium) for each market and | ||||||
|  |     ///      borrowed values are multiplied by (1 + marginPremium) for each market. Comparing these | ||||||
|  |     ///      adjusted values gives the margin-ratio of the account which will be compared to the global | ||||||
|  |     ///      margin-ratio when determining if the account can be liquidated. | ||||||
|  |     /// @param account The account to query | ||||||
|  |     /// @return supplyValue The supplied value of the account (adjusted for marginPremium) | ||||||
|  |     /// @return borrowValue The borrowed value of the account (adjusted for marginPremium) | ||||||
|  |     function getAdjustedAccountValues( | ||||||
|  |         AccountInfo calldata account | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         view | ||||||
|  |         returns (Value memory supplyValue, Value memory borrowValue); | ||||||
|  | } | ||||||
| @@ -0,0 +1,42 @@ | |||||||
|  | /* | ||||||
|  |  | ||||||
|  |   Copyright 2019 ZeroEx Intl. | ||||||
|  |  | ||||||
|  |   Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |   you may not use this file except in compliance with the License. | ||||||
|  |   You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |     http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |   Unless required by applicable law or agreed to in writing, software | ||||||
|  |   distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |   See the License for the specific language governing permissions and | ||||||
|  |   limitations under the License. | ||||||
|  |  | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | pragma solidity ^0.5.9; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | interface IDydxBridge { | ||||||
|  |  | ||||||
|  |     /// @dev This is the subset of `IDydx.ActionType` that are supported by the bridge. | ||||||
|  |     enum BridgeActionType { | ||||||
|  |         Deposit,                    // Deposit tokens into dydx account. | ||||||
|  |         Withdraw                    // Withdraw tokens from dydx account. | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     struct BridgeAction { | ||||||
|  |         BridgeActionType actionType;            // Action to run on dydx account. | ||||||
|  |         uint256 accountIdx;                     // Index in `BridgeData.accountNumbers` for this action. | ||||||
|  |         uint256 marketId;                       // Market to operate on. | ||||||
|  |         uint256 conversionRateNumerator;        // Optional. If set, transfer amount is scaled by (conversionRateNumerator/conversionRateDenominator). | ||||||
|  |         uint256 conversionRateDenominator;      // Optional. If set, transfer amount is scaled by (conversionRateNumerator/conversionRateDenominator). | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     struct BridgeData { | ||||||
|  |         uint256[] accountNumbers;               // Account number used to identify the owner's specific account. | ||||||
|  |         BridgeAction[] actions;                 // Actions to carry out on the owner's accounts. | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -21,16 +21,32 @@ pragma solidity ^0.5.9; | |||||||
|  |  | ||||||
| contract IERC20Bridge { | contract IERC20Bridge { | ||||||
|  |  | ||||||
|     // @dev Result of a successful bridge call. |     /// @dev Result of a successful bridge call. | ||||||
|     bytes4 constant internal BRIDGE_SUCCESS = 0xdc1600f3; |     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`. |     /// @dev Transfers `amount` of the ERC20 `tokenAddress` from `from` to `to`. | ||||||
|     /// @param tokenAddress The address of the ERC20 token to transfer. |     /// @param tokenAddress The address of the ERC20 token to transfer. | ||||||
|     /// @param from Address to transfer asset from. |     /// @param from Address to transfer asset from. | ||||||
|     /// @param to Address to transfer asset to. |     /// @param to Address to transfer asset to. | ||||||
|     /// @param amount Amount of asset to transfer. |     /// @param amount Amount of asset to transfer. | ||||||
|     /// @param bridgeData Arbitrary asset data needed by the bridge contract. |     /// @param bridgeData Arbitrary asset data needed by the bridge contract. | ||||||
|     /// @return success The magic bytes `0x37708e9b` if successful. |     /// @return success The magic bytes `0xdc1600f3` if successful. | ||||||
|     function bridgeTransferFrom( |     function bridgeTransferFrom( | ||||||
|         address tokenAddress, |         address tokenAddress, | ||||||
|         address from, |         address from, | ||||||
|   | |||||||
							
								
								
									
										40
									
								
								contracts/asset-proxy/contracts/src/interfaces/IGasToken.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								contracts/asset-proxy/contracts/src/interfaces/IGasToken.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | |||||||
|  | /* | ||||||
|  |  | ||||||
|  |   Copyright 2019 ZeroEx Intl. | ||||||
|  |  | ||||||
|  |   Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |   you may not use this file except in compliance with the License. | ||||||
|  |   You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |     http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |   Unless required by applicable law or agreed to in writing, software | ||||||
|  |   distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |   See the License for the specific language governing permissions and | ||||||
|  |   limitations under the License. | ||||||
|  |  | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | pragma solidity ^0.5.15; | ||||||
|  |  | ||||||
|  | import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | contract IGasToken is IERC20Token { | ||||||
|  |  | ||||||
|  |     /// @dev Frees up to `value` sub-tokens | ||||||
|  |     /// @param value The amount of tokens to free | ||||||
|  |     /// @return How many tokens were freed | ||||||
|  |     function freeUpTo(uint256 value) external returns (uint256 freed); | ||||||
|  |  | ||||||
|  |     /// @dev Frees up to `value` sub-tokens owned by `from` | ||||||
|  |     /// @param from The owner of tokens to spend | ||||||
|  |     /// @param value The amount of tokens to free | ||||||
|  |     /// @return How many tokens were freed | ||||||
|  |     function freeFromUpTo(address from, uint256 value) external returns (uint256 freed); | ||||||
|  |  | ||||||
|  |     /// @dev Mints `value` amount of tokens | ||||||
|  |     /// @param value The amount of tokens to mint | ||||||
|  |     function mint(uint256 value) external; | ||||||
|  | } | ||||||
| @@ -0,0 +1,72 @@ | |||||||
|  | /* | ||||||
|  |  | ||||||
|  |   Copyright 2019 ZeroEx Intl. | ||||||
|  |  | ||||||
|  |   Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |   you may not use this file except in compliance with the License. | ||||||
|  |   You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |     http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |   Unless required by applicable law or agreed to in writing, software | ||||||
|  |   distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |   See the License for the specific language governing permissions and | ||||||
|  |   limitations under the License. | ||||||
|  |  | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | pragma solidity ^0.5.9; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | interface IKyberNetworkProxy { | ||||||
|  |  | ||||||
|  |     /// @dev Sells `sellTokenAddress` tokens for `buyTokenAddress` tokens. | ||||||
|  |     /// @param sellTokenAddress Token to sell. | ||||||
|  |     /// @param sellAmount Amount of tokens to sell. | ||||||
|  |     /// @param buyTokenAddress Token to buy. | ||||||
|  |     /// @param recipientAddress Address to send bought tokens to. | ||||||
|  |     /// @param maxBuyTokenAmount A limit on the amount of tokens to buy. | ||||||
|  |     /// @param minConversionRate The minimal conversion rate. If actual rate | ||||||
|  |     ///        is lower, trade is canceled. | ||||||
|  |     /// @param walletId The wallet ID to send part of the fees | ||||||
|  |     /// @return boughtAmount Amount of tokens bought. | ||||||
|  |     function trade( | ||||||
|  |         address sellTokenAddress, | ||||||
|  |         uint256 sellAmount, | ||||||
|  |         address buyTokenAddress, | ||||||
|  |         address payable recipientAddress, | ||||||
|  |         uint256 maxBuyTokenAmount, | ||||||
|  |         uint256 minConversionRate, | ||||||
|  |         address walletId | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         payable | ||||||
|  |         returns (uint256 boughtAmount); | ||||||
|  |  | ||||||
|  |     /// @dev Sells `sellTokenAddress` tokens for `buyTokenAddress` tokens | ||||||
|  |     /// using a hint for the reserve. | ||||||
|  |     /// @param sellTokenAddress Token to sell. | ||||||
|  |     /// @param sellAmount Amount of tokens to sell. | ||||||
|  |     /// @param buyTokenAddress Token to buy. | ||||||
|  |     /// @param recipientAddress Address to send bought tokens to. | ||||||
|  |     /// @param maxBuyTokenAmount A limit on the amount of tokens to buy. | ||||||
|  |     /// @param minConversionRate The minimal conversion rate. If actual rate | ||||||
|  |     ///        is lower, trade is canceled. | ||||||
|  |     /// @param walletId The wallet ID to send part of the fees | ||||||
|  |     /// @param hint The hint for the selective inclusion (or exclusion) of reserves | ||||||
|  |     /// @return boughtAmount Amount of tokens bought. | ||||||
|  |     function tradeWithHint( | ||||||
|  |         address sellTokenAddress, | ||||||
|  |         uint256 sellAmount, | ||||||
|  |         address buyTokenAddress, | ||||||
|  |         address payable recipientAddress, | ||||||
|  |         uint256 maxBuyTokenAmount, | ||||||
|  |         uint256 minConversionRate, | ||||||
|  |         address payable walletId, | ||||||
|  |         bytes calldata hint | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         payable | ||||||
|  |         returns (uint256 boughtAmount); | ||||||
|  | } | ||||||
							
								
								
									
										32
									
								
								contracts/asset-proxy/contracts/src/interfaces/IMStable.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								contracts/asset-proxy/contracts/src/interfaces/IMStable.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | |||||||
|  | /* | ||||||
|  |  | ||||||
|  |   Copyright 2020 ZeroEx Intl. | ||||||
|  |  | ||||||
|  |   Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |   you may not use this file except in compliance with the License. | ||||||
|  |   You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |     http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |   Unless required by applicable law or agreed to in writing, software | ||||||
|  |   distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |   See the License for the specific language governing permissions and | ||||||
|  |   limitations under the License. | ||||||
|  |  | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | pragma solidity ^0.5.9; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | interface IMStable { | ||||||
|  |  | ||||||
|  |     function swap( | ||||||
|  |         address _input, | ||||||
|  |         address _output, | ||||||
|  |         uint256 _quantity, | ||||||
|  |         address _recipient | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         returns (uint256 output); | ||||||
|  | } | ||||||
| @@ -0,0 +1,40 @@ | |||||||
|  | /* | ||||||
|  |  | ||||||
|  |   Copyright 2020 ZeroEx Intl. | ||||||
|  |  | ||||||
|  |   Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |   you may not use this file except in compliance with the License. | ||||||
|  |   You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |     http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |   Unless required by applicable law or agreed to in writing, software | ||||||
|  |   distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |   See the License for the specific language governing permissions and | ||||||
|  |   limitations under the License. | ||||||
|  |  | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | pragma solidity ^0.5.9; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | interface IMooniswapRegistry { | ||||||
|  |  | ||||||
|  |     function pools(address token1, address token2) external view returns(address); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | interface IMooniswap { | ||||||
|  |  | ||||||
|  |     function swap( | ||||||
|  |         address fromToken, | ||||||
|  |         address destToken, | ||||||
|  |         uint256 amount, | ||||||
|  |         uint256 minReturn, | ||||||
|  |         address referral | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         payable | ||||||
|  |         returns(uint256 returnAmount); | ||||||
|  | } | ||||||
| @@ -1,6 +1,6 @@ | |||||||
| /* | /* | ||||||
| 
 | 
 | ||||||
|   Copyright 2019 ZeroEx Intl. |   Copyright 2020 ZeroEx Intl. | ||||||
| 
 | 
 | ||||||
|   Licensed under the Apache License, Version 2.0 (the "License"); |   Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|   you may not use this file except in compliance with the License. |   you may not use this file except in compliance with the License. | ||||||
| @@ -19,13 +19,16 @@ | |||||||
| pragma solidity ^0.5.9; | pragma solidity ^0.5.9; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| contract IThresholdAsset { | interface IShell { | ||||||
| 
 | 
 | ||||||
|     /// @param _owner The address from which the balance will be retrieved |     function originSwap( | ||||||
|     /// @return Balance of owner |         address from, | ||||||
|     function balanceOf(address _owner) |         address to, | ||||||
|  |         uint256 fromAmount, | ||||||
|  |         uint256 minTargetAmount, | ||||||
|  |         uint256 deadline | ||||||
|  |     ) | ||||||
|         external |         external | ||||||
|         view |         returns (uint256 toAmount); | ||||||
|         returns (uint256); |  | ||||||
| 
 |  | ||||||
| } | } | ||||||
|  | 
 | ||||||
| @@ -67,11 +67,4 @@ interface IUniswapExchange { | |||||||
|     ) |     ) | ||||||
|         external |         external | ||||||
|         returns (uint256 tokensBought); |         returns (uint256 tokensBought); | ||||||
|  |  | ||||||
|     /// @dev Retrieves the token that is associated with this exchange. |  | ||||||
|     /// @return tokenAddress The token address. |  | ||||||
|     function toTokenAddress() |  | ||||||
|         external |  | ||||||
|         view |  | ||||||
|         returns (address tokenAddress); |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -28,5 +28,5 @@ interface IUniswapExchangeFactory { | |||||||
|     function getExchange(address tokenAddress) |     function getExchange(address tokenAddress) | ||||||
|         external |         external | ||||||
|         view |         view | ||||||
|         returns (IUniswapExchange); |         returns (address); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -0,0 +1,40 @@ | |||||||
|  | /* | ||||||
|  |  | ||||||
|  |   Copyright 2020 ZeroEx Intl. | ||||||
|  |  | ||||||
|  |   Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |   you may not use this file except in compliance with the License. | ||||||
|  |   You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |     http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |   Unless required by applicable law or agreed to in writing, software | ||||||
|  |   distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |   See the License for the specific language governing permissions and | ||||||
|  |   limitations under the License. | ||||||
|  |  | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | pragma solidity ^0.5.9; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | interface IUniswapV2Router01 { | ||||||
|  |  | ||||||
|  |     /// @dev Swaps an exact amount of input tokens for as many output tokens as possible, along the route determined by the path. | ||||||
|  |     ///      The first element of path is the input token, the last is the output token, and any intermediate elements represent | ||||||
|  |     ///      intermediate pairs to trade through (if, for example, a direct pair does not exist). | ||||||
|  |     /// @param amountIn The amount of input tokens to send. | ||||||
|  |     /// @param amountOutMin The minimum amount of output tokens that must be received for the transaction not to revert. | ||||||
|  |     /// @param path An array of token addresses. path.length must be >= 2. Pools for each consecutive pair of addresses must exist and have liquidity. | ||||||
|  |     /// @param to Recipient of the output tokens. | ||||||
|  |     /// @param deadline Unix timestamp after which the transaction will revert. | ||||||
|  |     /// @return amounts The input token amount and all subsequent output token amounts. | ||||||
|  |     function swapExactTokensForTokens( | ||||||
|  |         uint amountIn, | ||||||
|  |         uint amountOutMin, | ||||||
|  |         address[] calldata path, | ||||||
|  |         address to, | ||||||
|  |         uint deadline | ||||||
|  |     ) external returns (uint[] memory amounts); | ||||||
|  | } | ||||||
							
								
								
									
										247
									
								
								contracts/asset-proxy/contracts/test/TestBancorBridge.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										247
									
								
								contracts/asset-proxy/contracts/test/TestBancorBridge.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,247 @@ | |||||||
|  | /* | ||||||
|  |  | ||||||
|  |   Copyright 2019 ZeroEx Intl. | ||||||
|  |  | ||||||
|  |   Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |   you may not use this file except in compliance with the License. | ||||||
|  |   You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |     http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |   Unless required by applicable law or agreed to in writing, software | ||||||
|  |   distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |   See the License for the specific language governing permissions and | ||||||
|  |   limitations under the License. | ||||||
|  |  | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | pragma solidity ^0.5.9; | ||||||
|  | pragma experimental ABIEncoderV2; | ||||||
|  |  | ||||||
|  | import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; | ||||||
|  | import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; | ||||||
|  | import "@0x/contracts-utils/contracts/src/LibAddressArray.sol"; | ||||||
|  | import "../src/bridges/BancorBridge.sol"; | ||||||
|  | import "../src/interfaces/IBancorNetwork.sol"; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | contract TestEventsRaiser { | ||||||
|  |  | ||||||
|  |     event TokenTransfer( | ||||||
|  |         address token, | ||||||
|  |         address from, | ||||||
|  |         address to, | ||||||
|  |         uint256 amount | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     event TokenApprove( | ||||||
|  |         address spender, | ||||||
|  |         uint256 allowance | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     event ConvertByPathInput( | ||||||
|  |         uint amountIn, | ||||||
|  |         uint amountOutMin, | ||||||
|  |         address toTokenAddress, | ||||||
|  |         address to, | ||||||
|  |         address feeRecipient, | ||||||
|  |         uint256 feeAmount | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     function raiseTokenTransfer( | ||||||
|  |         address from, | ||||||
|  |         address to, | ||||||
|  |         uint256 amount | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |     { | ||||||
|  |         emit TokenTransfer( | ||||||
|  |             msg.sender, | ||||||
|  |             from, | ||||||
|  |             to, | ||||||
|  |             amount | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function raiseTokenApprove(address spender, uint256 allowance) external { | ||||||
|  |         emit TokenApprove(spender, allowance); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function raiseConvertByPathInput( | ||||||
|  |         uint amountIn, | ||||||
|  |         uint amountOutMin, | ||||||
|  |         address toTokenAddress, | ||||||
|  |         address to, | ||||||
|  |         address feeRecipient, | ||||||
|  |         uint256 feeAmount | ||||||
|  |     ) external | ||||||
|  |     { | ||||||
|  |         emit ConvertByPathInput( | ||||||
|  |             amountIn, | ||||||
|  |             amountOutMin, | ||||||
|  |             toTokenAddress, | ||||||
|  |             to, | ||||||
|  |             feeRecipient, | ||||||
|  |             feeAmount | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /// @dev A minimalist ERC20 token. | ||||||
|  | contract TestToken { | ||||||
|  |  | ||||||
|  |     using LibSafeMath for uint256; | ||||||
|  |  | ||||||
|  |     mapping (address => uint256) public balances; | ||||||
|  |     string private _nextRevertReason; | ||||||
|  |  | ||||||
|  |     /// @dev Set the balance for `owner`. | ||||||
|  |     function setBalance(address owner, uint256 balance) | ||||||
|  |         external | ||||||
|  |         payable | ||||||
|  |     { | ||||||
|  |         balances[owner] = balance; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// @dev Just emits a TokenTransfer event on the caller | ||||||
|  |     function transfer(address to, uint256 amount) | ||||||
|  |         external | ||||||
|  |         returns (bool) | ||||||
|  |     { | ||||||
|  |         TestEventsRaiser(msg.sender).raiseTokenTransfer(msg.sender, to, amount); | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// @dev Just emits a TokenApprove event on the caller | ||||||
|  |     function approve(address spender, uint256 allowance) | ||||||
|  |         external | ||||||
|  |         returns (bool) | ||||||
|  |     { | ||||||
|  |         TestEventsRaiser(msg.sender).raiseTokenApprove(spender, allowance); | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function allowance(address, address) external view returns (uint256) { | ||||||
|  |         return 0; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// @dev Retrieve the balance for `owner`. | ||||||
|  |     function balanceOf(address owner) | ||||||
|  |         external | ||||||
|  |         view | ||||||
|  |         returns (uint256) | ||||||
|  |     { | ||||||
|  |         return balances[owner]; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /// @dev Mock the BancorNetwork contract | ||||||
|  | contract TestBancorNetwork is | ||||||
|  |     IBancorNetwork | ||||||
|  | { | ||||||
|  |     string private _nextRevertReason; | ||||||
|  |  | ||||||
|  |     /// @dev Set the revert reason for `swapExactTokensForTokens`. | ||||||
|  |     function setRevertReason(string calldata reason) | ||||||
|  |         external | ||||||
|  |     { | ||||||
|  |         _nextRevertReason = reason; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function convertByPath( | ||||||
|  |         address[] calldata _path, | ||||||
|  |         uint256 _amount, | ||||||
|  |         uint256 _minReturn, | ||||||
|  |         address _beneficiary, | ||||||
|  |         address _affiliateAccount, | ||||||
|  |         uint256 _affiliateFee | ||||||
|  |     ) external payable returns (uint256) | ||||||
|  |     { | ||||||
|  |         _revertIfReasonExists(); | ||||||
|  |  | ||||||
|  |         TestEventsRaiser(msg.sender).raiseConvertByPathInput( | ||||||
|  |             // tokens sold | ||||||
|  |             _amount, | ||||||
|  |             // tokens bought | ||||||
|  |             _minReturn, | ||||||
|  |             // output token | ||||||
|  |             _path[_path.length - 1], | ||||||
|  |             // recipient | ||||||
|  |             _beneficiary, | ||||||
|  |             // fee recipient | ||||||
|  |             _affiliateAccount, | ||||||
|  |             // fee amount | ||||||
|  |             _affiliateFee | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function _revertIfReasonExists() | ||||||
|  |         private | ||||||
|  |         view | ||||||
|  |     { | ||||||
|  |         if (bytes(_nextRevertReason).length != 0) { | ||||||
|  |             revert(_nextRevertReason); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /// @dev BancorBridge overridden to mock tokens and BancorNetwork | ||||||
|  | contract TestBancorBridge is | ||||||
|  |     BancorBridge, | ||||||
|  |     TestEventsRaiser | ||||||
|  | { | ||||||
|  |  | ||||||
|  |     // Token address to TestToken instance. | ||||||
|  |     mapping (address => TestToken) private _testTokens; | ||||||
|  |     // TestRouter instance. | ||||||
|  |     TestBancorNetwork private _testNetwork; | ||||||
|  |  | ||||||
|  |     constructor() public { | ||||||
|  |         _testNetwork = new TestBancorNetwork(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function setNetworkRevertReason(string calldata revertReason) | ||||||
|  |         external | ||||||
|  |     { | ||||||
|  |         _testNetwork.setRevertReason(revertReason); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// @dev Sets the balance of this contract for an existing token. | ||||||
|  |     function setTokenBalance(address tokenAddress, uint256 balance) | ||||||
|  |         external | ||||||
|  |     { | ||||||
|  |         TestToken token = _testTokens[tokenAddress]; | ||||||
|  |         token.setBalance(address(this), balance); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// @dev Create a new token | ||||||
|  |     /// @param tokenAddress The token address. If zero, one will be created. | ||||||
|  |     function createToken( | ||||||
|  |         address tokenAddress | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         returns (TestToken token) | ||||||
|  |     { | ||||||
|  |         token = TestToken(tokenAddress); | ||||||
|  |         if (tokenAddress == address(0)) { | ||||||
|  |             token = new TestToken(); | ||||||
|  |         } | ||||||
|  |         _testTokens[address(token)] = token; | ||||||
|  |  | ||||||
|  |         return token; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function getNetworkAddress() | ||||||
|  |         external | ||||||
|  |         view | ||||||
|  |         returns (address) | ||||||
|  |     { | ||||||
|  |         return address(_testNetwork); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										80
									
								
								contracts/asset-proxy/contracts/test/TestChaiBridge.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								contracts/asset-proxy/contracts/test/TestChaiBridge.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,80 @@ | |||||||
|  | /* | ||||||
|  |  | ||||||
|  |   Copyright 2019 ZeroEx Intl. | ||||||
|  |  | ||||||
|  |   Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |   you may not use this file except in compliance with the License. | ||||||
|  |   You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |     http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |   Unless required by applicable law or agreed to in writing, software | ||||||
|  |   distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |   See the License for the specific language governing permissions and | ||||||
|  |   limitations under the License. | ||||||
|  |  | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | pragma solidity ^0.5.9; | ||||||
|  | pragma experimental ABIEncoderV2; | ||||||
|  |  | ||||||
|  | import "../src/bridges/ChaiBridge.sol"; | ||||||
|  | import "@0x/contracts-erc20/contracts/src/ERC20Token.sol"; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | contract TestChaiDai is | ||||||
|  |     ERC20Token | ||||||
|  | { | ||||||
|  |     address private constant ALWAYS_REVERT_ADDRESS = address(1); | ||||||
|  |  | ||||||
|  |     function draw( | ||||||
|  |         address from, | ||||||
|  |         uint256 amount | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |     { | ||||||
|  |         if (from == ALWAYS_REVERT_ADDRESS) { | ||||||
|  |             revert(); | ||||||
|  |         } | ||||||
|  |         balances[msg.sender] += amount; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | contract TestChaiBridge is | ||||||
|  |     ChaiBridge | ||||||
|  | { | ||||||
|  |     address public testChaiDai; | ||||||
|  |     address private constant ALWAYS_REVERT_ADDRESS = address(1); | ||||||
|  |  | ||||||
|  |     constructor() | ||||||
|  |         public | ||||||
|  |     { | ||||||
|  |         testChaiDai = address(new TestChaiDai()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function _getDaiAddress() | ||||||
|  |         internal | ||||||
|  |         view | ||||||
|  |         returns (address) | ||||||
|  |     { | ||||||
|  |         return testChaiDai; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function _getChaiAddress() | ||||||
|  |         internal | ||||||
|  |         view | ||||||
|  |         returns (address) | ||||||
|  |     { | ||||||
|  |         return testChaiDai; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function _getERC20BridgeProxyAddress() | ||||||
|  |         internal | ||||||
|  |         view | ||||||
|  |         returns (address) | ||||||
|  |     { | ||||||
|  |         return msg.sender == ALWAYS_REVERT_ADDRESS ? address(0) : msg.sender; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										244
									
								
								contracts/asset-proxy/contracts/test/TestDexForwarderBridge.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										244
									
								
								contracts/asset-proxy/contracts/test/TestDexForwarderBridge.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,244 @@ | |||||||
|  | /* | ||||||
|  |  | ||||||
|  |   Copyright 2020 ZeroEx Intl. | ||||||
|  |  | ||||||
|  |   Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |   you may not use this file except in compliance with the License. | ||||||
|  |   You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |     http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |   Unless required by applicable law or agreed to in writing, software | ||||||
|  |   distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |   See the License for the specific language governing permissions and | ||||||
|  |   limitations under the License. | ||||||
|  |  | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | pragma solidity ^0.5.9; | ||||||
|  | pragma experimental ABIEncoderV2; | ||||||
|  |  | ||||||
|  | import "../src/bridges/DexForwarderBridge.sol"; | ||||||
|  | import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | interface ITestDexForwarderBridge { | ||||||
|  |     event BridgeTransferFromCalled( | ||||||
|  |         address caller, | ||||||
|  |         uint256 inputTokenBalance, | ||||||
|  |         address inputToken, | ||||||
|  |         address outputToken, | ||||||
|  |         address from, | ||||||
|  |         address to, | ||||||
|  |         uint256 amount | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     event TokenTransferCalled( | ||||||
|  |         address from, | ||||||
|  |         address to, | ||||||
|  |         uint256 amount | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     function emitBridgeTransferFromCalled( | ||||||
|  |         address caller, | ||||||
|  |         uint256 inputTokenBalance, | ||||||
|  |         address inputToken, | ||||||
|  |         address outputToken, | ||||||
|  |         address from, | ||||||
|  |         address to, | ||||||
|  |         uint256 amount | ||||||
|  |     ) external; | ||||||
|  |  | ||||||
|  |     function emitTokenTransferCalled( | ||||||
|  |         address from, | ||||||
|  |         address to, | ||||||
|  |         uint256 amount | ||||||
|  |     ) external; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | interface ITestDexForwarderBridgeTestToken { | ||||||
|  |  | ||||||
|  |     function transfer(address to, uint256 amount) | ||||||
|  |         external | ||||||
|  |         returns (bool); | ||||||
|  |  | ||||||
|  |     function mint(address to, uint256 amount) | ||||||
|  |         external; | ||||||
|  |  | ||||||
|  |     function balanceOf(address owner) external view returns (uint256); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | contract TestDexForwarderBridgeTestBridge { | ||||||
|  |  | ||||||
|  |     bytes4 private _returnCode; | ||||||
|  |     string private _revertError; | ||||||
|  |     uint256 private _transferAmount; | ||||||
|  |     ITestDexForwarderBridge private _testContract; | ||||||
|  |  | ||||||
|  |     constructor(bytes4 returnCode, string memory revertError) public { | ||||||
|  |         _testContract = ITestDexForwarderBridge(msg.sender); | ||||||
|  |         _returnCode = returnCode; | ||||||
|  |         _revertError = revertError; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function setTransferAmount(uint256 amount) external { | ||||||
|  |         _transferAmount = amount; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function bridgeTransferFrom( | ||||||
|  |         address outputToken, | ||||||
|  |         address from, | ||||||
|  |         address to, | ||||||
|  |         uint256 amount, | ||||||
|  |         bytes memory bridgeData | ||||||
|  |     ) | ||||||
|  |         public | ||||||
|  |         returns (bytes4 success) | ||||||
|  |     { | ||||||
|  |         if (bytes(_revertError).length != 0) { | ||||||
|  |             revert(_revertError); | ||||||
|  |         } | ||||||
|  |         address inputToken = abi.decode(bridgeData, (address)); | ||||||
|  |         _testContract.emitBridgeTransferFromCalled( | ||||||
|  |             msg.sender, | ||||||
|  |             ITestDexForwarderBridgeTestToken(inputToken).balanceOf(address(this)), | ||||||
|  |             inputToken, | ||||||
|  |             outputToken, | ||||||
|  |             from, | ||||||
|  |             to, | ||||||
|  |             amount | ||||||
|  |         ); | ||||||
|  |         ITestDexForwarderBridgeTestToken(outputToken).mint(to, _transferAmount); | ||||||
|  |         return _returnCode; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | contract TestDexForwarderBridgeTestToken { | ||||||
|  |  | ||||||
|  |     using LibSafeMath for uint256; | ||||||
|  |  | ||||||
|  |     mapping(address => uint256) public balanceOf; | ||||||
|  |     ITestDexForwarderBridge private _testContract; | ||||||
|  |  | ||||||
|  |     constructor() public { | ||||||
|  |         _testContract = ITestDexForwarderBridge(msg.sender); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function transfer(address to, uint256 amount) | ||||||
|  |         external | ||||||
|  |         returns (bool) | ||||||
|  |     { | ||||||
|  |         balanceOf[msg.sender] = balanceOf[msg.sender].safeSub(amount); | ||||||
|  |         balanceOf[to] = balanceOf[to].safeAdd(amount); | ||||||
|  |         _testContract.emitTokenTransferCalled(msg.sender, to, amount); | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function mint(address owner, uint256 amount) | ||||||
|  |         external | ||||||
|  |     { | ||||||
|  |         balanceOf[owner] = balanceOf[owner].safeAdd(amount); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function setBalance(address owner, uint256 amount) | ||||||
|  |         external | ||||||
|  |     { | ||||||
|  |         balanceOf[owner] = amount; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | contract TestDexForwarderBridge is | ||||||
|  |     ITestDexForwarderBridge, | ||||||
|  |     DexForwarderBridge | ||||||
|  | { | ||||||
|  |     address private AUTHORIZED_ADDRESS; // solhint-disable-line var-name-mixedcase | ||||||
|  |  | ||||||
|  |     function setAuthorized(address authorized) | ||||||
|  |         public | ||||||
|  |     { | ||||||
|  |         AUTHORIZED_ADDRESS = authorized; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function createBridge( | ||||||
|  |         bytes4 returnCode, | ||||||
|  |         string memory revertError | ||||||
|  |     ) | ||||||
|  |         public | ||||||
|  |         returns (address bridge) | ||||||
|  |     { | ||||||
|  |         return address(new TestDexForwarderBridgeTestBridge(returnCode, revertError)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function createToken() public returns (address token) { | ||||||
|  |         return address(new TestDexForwarderBridgeTestToken()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function setTokenBalance(address token, address owner, uint256 amount) public { | ||||||
|  |         TestDexForwarderBridgeTestToken(token).setBalance(owner, amount); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function setBridgeTransferAmount(address bridge, uint256 amount) public { | ||||||
|  |         TestDexForwarderBridgeTestBridge(bridge).setTransferAmount(amount); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function emitBridgeTransferFromCalled( | ||||||
|  |         address caller, | ||||||
|  |         uint256 inputTokenBalance, | ||||||
|  |         address inputToken, | ||||||
|  |         address outputToken, | ||||||
|  |         address from, | ||||||
|  |         address to, | ||||||
|  |         uint256 amount | ||||||
|  |     ) | ||||||
|  |         public | ||||||
|  |     { | ||||||
|  |         emit BridgeTransferFromCalled( | ||||||
|  |             caller, | ||||||
|  |             inputTokenBalance, | ||||||
|  |             inputToken, | ||||||
|  |             outputToken, | ||||||
|  |             from, | ||||||
|  |             to, | ||||||
|  |             amount | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function emitTokenTransferCalled( | ||||||
|  |         address from, | ||||||
|  |         address to, | ||||||
|  |         uint256 amount | ||||||
|  |     ) | ||||||
|  |         public | ||||||
|  |     { | ||||||
|  |         emit TokenTransferCalled( | ||||||
|  |             from, | ||||||
|  |             to, | ||||||
|  |             amount | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function balanceOf(address token, address owner) public view returns (uint256) { | ||||||
|  |         return TestDexForwarderBridgeTestToken(token).balanceOf(owner); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function _getGstAddress() | ||||||
|  |         internal | ||||||
|  |         view | ||||||
|  |         returns (address gst) | ||||||
|  |     { | ||||||
|  |         return address(0); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function _getERC20BridgeProxyAddress() | ||||||
|  |         internal | ||||||
|  |         view | ||||||
|  |         returns (address erc20BridgeProxyAddress) | ||||||
|  |     { | ||||||
|  |         return AUTHORIZED_ADDRESS; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										246
									
								
								contracts/asset-proxy/contracts/test/TestDydxBridge.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										246
									
								
								contracts/asset-proxy/contracts/test/TestDydxBridge.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,246 @@ | |||||||
|  | /* | ||||||
|  |  | ||||||
|  |   Copyright 2019 ZeroEx Intl. | ||||||
|  |  | ||||||
|  |   Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |   you may not use this file except in compliance with the License. | ||||||
|  |   You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |     http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |   Unless required by applicable law or agreed to in writing, software | ||||||
|  |   distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |   See the License for the specific language governing permissions and | ||||||
|  |   limitations under the License. | ||||||
|  |  | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | pragma solidity ^0.5.9; | ||||||
|  | pragma experimental ABIEncoderV2; | ||||||
|  |  | ||||||
|  | import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; | ||||||
|  | import "../src/bridges/DydxBridge.sol"; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // solhint-disable no-empty-blocks | ||||||
|  | contract TestDydxBridgeToken { | ||||||
|  |  | ||||||
|  |     uint256 private constant INIT_HOLDER_BALANCE = 10 * 10**18; // 10 tokens | ||||||
|  |     mapping (address => uint256) private _balances; | ||||||
|  |  | ||||||
|  |     /// @dev Sets initial balance of token holders. | ||||||
|  |     constructor(address[] memory holders) | ||||||
|  |         public | ||||||
|  |     { | ||||||
|  |         for (uint256 i = 0; i != holders.length; ++i) { | ||||||
|  |             _balances[holders[i]] = INIT_HOLDER_BALANCE; | ||||||
|  |         } | ||||||
|  |         _balances[msg.sender] = INIT_HOLDER_BALANCE; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// @dev Basic transferFrom implementation. | ||||||
|  |     function transferFrom(address from, address to, uint256 amount) | ||||||
|  |         external | ||||||
|  |         returns (bool) | ||||||
|  |     { | ||||||
|  |         if (_balances[from] < amount || _balances[to] + amount < _balances[to]) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |         _balances[from] -= amount; | ||||||
|  |         _balances[to] += amount; | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// @dev Returns balance of `holder`. | ||||||
|  |     function balanceOf(address holder) | ||||||
|  |         external | ||||||
|  |         view | ||||||
|  |         returns (uint256) | ||||||
|  |     { | ||||||
|  |         return _balances[holder]; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // solhint-disable space-after-comma | ||||||
|  | contract TestDydxBridge is | ||||||
|  |     IDydx, | ||||||
|  |     DydxBridge | ||||||
|  | { | ||||||
|  |  | ||||||
|  |     address private constant ALWAYS_REVERT_ADDRESS = address(1); | ||||||
|  |     address private _testTokenAddress; | ||||||
|  |     bool private _shouldRevertOnOperate; | ||||||
|  |  | ||||||
|  |     event OperateAccount( | ||||||
|  |         address owner, | ||||||
|  |         uint256 number | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     event OperateAction( | ||||||
|  |         ActionType actionType, | ||||||
|  |         uint256 accountIdx, | ||||||
|  |         bool amountSign, | ||||||
|  |         AssetDenomination amountDenomination, | ||||||
|  |         AssetReference amountRef, | ||||||
|  |         uint256 amountValue, | ||||||
|  |         uint256 primaryMarketId, | ||||||
|  |         uint256 secondaryMarketId, | ||||||
|  |         address otherAddress, | ||||||
|  |         uint256 otherAccountId, | ||||||
|  |         bytes data | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     constructor(address[] memory holders) | ||||||
|  |         public | ||||||
|  |     { | ||||||
|  |         // Deploy a test token. This represents the asset being deposited/withdrawn from dydx. | ||||||
|  |         _testTokenAddress = address(new TestDydxBridgeToken(holders)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// @dev Simulates `operate` in dydx contract. | ||||||
|  |     ///      Emits events so that arguments can be validated client-side. | ||||||
|  |     function operate( | ||||||
|  |         AccountInfo[] calldata accounts, | ||||||
|  |         ActionArgs[] calldata actions | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |     { | ||||||
|  |         if (_shouldRevertOnOperate) { | ||||||
|  |             revert("TestDydxBridge/SHOULD_REVERT_ON_OPERATE"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         for (uint i = 0; i < accounts.length; ++i) { | ||||||
|  |             emit OperateAccount( | ||||||
|  |                 accounts[i].owner, | ||||||
|  |                 accounts[i].number | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         for (uint i = 0; i < actions.length; ++i) { | ||||||
|  |             emit OperateAction( | ||||||
|  |                 actions[i].actionType, | ||||||
|  |                 actions[i].accountIdx, | ||||||
|  |                 actions[i].amount.sign, | ||||||
|  |                 actions[i].amount.denomination, | ||||||
|  |                 actions[i].amount.ref, | ||||||
|  |                 actions[i].amount.value, | ||||||
|  |                 actions[i].primaryMarketId, | ||||||
|  |                 actions[i].secondaryMarketId, | ||||||
|  |                 actions[i].otherAddress, | ||||||
|  |                 actions[i].otherAccountIdx, | ||||||
|  |                 actions[i].data | ||||||
|  |             ); | ||||||
|  |  | ||||||
|  |             if (actions[i].actionType == IDydx.ActionType.Withdraw) { | ||||||
|  |                 require( | ||||||
|  |                     IERC20Token(_testTokenAddress).transferFrom( | ||||||
|  |                         address(this), | ||||||
|  |                         actions[i].otherAddress, | ||||||
|  |                         actions[i].amount.value | ||||||
|  |                     ), | ||||||
|  |                     "TestDydxBridge/WITHDRAW_FAILED" | ||||||
|  |                 ); | ||||||
|  |             } else if (actions[i].actionType == IDydx.ActionType.Deposit) { | ||||||
|  |                 require( | ||||||
|  |                     IERC20Token(_testTokenAddress).transferFrom( | ||||||
|  |                         actions[i].otherAddress, | ||||||
|  |                         address(this), | ||||||
|  |                         actions[i].amount.value | ||||||
|  |                     ), | ||||||
|  |                     "TestDydxBridge/DEPOSIT_FAILED" | ||||||
|  |                 ); | ||||||
|  |             } else { | ||||||
|  |                 revert("TestDydxBridge/UNSUPPORTED_ACTION"); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// @dev If `true` then subsequent calls to `operate` will revert. | ||||||
|  |     function setRevertOnOperate(bool shouldRevert) | ||||||
|  |         external | ||||||
|  |     { | ||||||
|  |         _shouldRevertOnOperate = shouldRevert; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// @dev Returns test token. | ||||||
|  |     function getTestToken() | ||||||
|  |         external | ||||||
|  |         returns (address) | ||||||
|  |     { | ||||||
|  |         return _testTokenAddress; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// @dev Unused. | ||||||
|  |     function setOperators(OperatorArg[] calldata args) external {} | ||||||
|  |  | ||||||
|  |     /// @dev Unused. | ||||||
|  |     function getIsLocalOperator( | ||||||
|  |         address owner, | ||||||
|  |         address operator | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         view | ||||||
|  |         returns (bool isLocalOperator) | ||||||
|  |     {} | ||||||
|  |  | ||||||
|  |     /// @dev Unused. | ||||||
|  |     function getMarketTokenAddress( | ||||||
|  |         uint256 marketId | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         view | ||||||
|  |         returns (address tokenAddress) | ||||||
|  |     {} | ||||||
|  |  | ||||||
|  |     /// @dev Unused. | ||||||
|  |     function getRiskParams() | ||||||
|  |         external | ||||||
|  |         view | ||||||
|  |         returns (RiskParams memory riskParams) | ||||||
|  |     {} | ||||||
|  |  | ||||||
|  |     /// @dev Unsused. | ||||||
|  |     function getMarketPrice( | ||||||
|  |         uint256 marketId | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         view | ||||||
|  |         returns (Price memory price) | ||||||
|  |     {} | ||||||
|  |  | ||||||
|  |     /// @dev Unsused | ||||||
|  |     function getMarketMarginPremium(uint256 marketId) | ||||||
|  |         external | ||||||
|  |         view | ||||||
|  |         returns (IDydx.D256 memory premium) | ||||||
|  |     {} | ||||||
|  |  | ||||||
|  |     /// @dev Unused. | ||||||
|  |     function getAdjustedAccountValues( | ||||||
|  |         AccountInfo calldata account | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         view | ||||||
|  |         returns (Value memory supplyValue, Value memory borrowValue) | ||||||
|  |     {} | ||||||
|  |  | ||||||
|  |     /// @dev overrides `_getDydxAddress()` from `DeploymentConstants` to return this address. | ||||||
|  |     function _getDydxAddress() | ||||||
|  |         internal | ||||||
|  |         view | ||||||
|  |         returns (address) | ||||||
|  |     { | ||||||
|  |         return address(this); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// @dev overrides `_getERC20BridgeProxyAddress()` from `DeploymentConstants` for testing. | ||||||
|  |     function _getERC20BridgeProxyAddress() | ||||||
|  |         internal | ||||||
|  |         view | ||||||
|  |         returns (address) | ||||||
|  |     { | ||||||
|  |         return msg.sender == ALWAYS_REVERT_ADDRESS ? address(0) : msg.sender; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -110,6 +110,10 @@ contract TestToken { | |||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     function allowance(address, address) external view returns (uint256) { | ||||||
|  |         return 0; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /// @dev Retrieve the balance for `owner`. |     /// @dev Retrieve the balance for `owner`. | ||||||
|     function balanceOf(address owner) |     function balanceOf(address owner) | ||||||
|         external |         external | ||||||
| @@ -192,11 +196,11 @@ contract TestEth2DaiBridge is | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     // @dev This contract will double as the Eth2Dai contract. |     // @dev This contract will double as the Eth2Dai contract. | ||||||
|     function _getEth2DaiContract() |     function _getEth2DaiAddress() | ||||||
|         internal |         internal | ||||||
|         view |         view | ||||||
|         returns (IEth2Dai) |         returns (address) | ||||||
|     { |     { | ||||||
|         return IEth2Dai(address(this)); |         return address(this); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										355
									
								
								contracts/asset-proxy/contracts/test/TestKyberBridge.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										355
									
								
								contracts/asset-proxy/contracts/test/TestKyberBridge.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,355 @@ | |||||||
|  | /* | ||||||
|  |  | ||||||
|  |   Copyright 2019 ZeroEx Intl. | ||||||
|  |  | ||||||
|  |   Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |   you may not use this file except in compliance with the License. | ||||||
|  |   You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |     http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |   Unless required by applicable law or agreed to in writing, software | ||||||
|  |   distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |   See the License for the specific language governing permissions and | ||||||
|  |   limitations under the License. | ||||||
|  |  | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | pragma solidity ^0.5.9; | ||||||
|  | pragma experimental ABIEncoderV2; | ||||||
|  |  | ||||||
|  | import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; | ||||||
|  | import "../src/bridges/KyberBridge.sol"; | ||||||
|  | import "../src/interfaces/IKyberNetworkProxy.sol"; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // solhint-disable no-simple-event-func-name | ||||||
|  | interface ITestContract { | ||||||
|  |  | ||||||
|  |     function wethWithdraw( | ||||||
|  |         address payable ownerAddress, | ||||||
|  |         uint256 amount | ||||||
|  |     ) | ||||||
|  |         external; | ||||||
|  |  | ||||||
|  |     function wethDeposit( | ||||||
|  |         address ownerAddress | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         payable; | ||||||
|  |  | ||||||
|  |     function tokenTransfer( | ||||||
|  |         address ownerAddress, | ||||||
|  |         address recipientAddress, | ||||||
|  |         uint256 amount | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         returns (bool success); | ||||||
|  |  | ||||||
|  |     function tokenApprove( | ||||||
|  |         address ownerAddress, | ||||||
|  |         address spenderAddress, | ||||||
|  |         uint256 allowance | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         returns (bool success); | ||||||
|  |  | ||||||
|  |     function tokenBalanceOf( | ||||||
|  |         address ownerAddress | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         view | ||||||
|  |         returns (uint256 balance); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /// @dev A minimalist ERC20/WETH token. | ||||||
|  | contract TestToken { | ||||||
|  |  | ||||||
|  |     uint8 public decimals; | ||||||
|  |     ITestContract private _testContract; | ||||||
|  |  | ||||||
|  |     constructor(uint8 decimals_) public { | ||||||
|  |         decimals = decimals_; | ||||||
|  |         _testContract = ITestContract(msg.sender); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function approve(address spender, uint256 allowance) | ||||||
|  |         external | ||||||
|  |         returns (bool) | ||||||
|  |     { | ||||||
|  |         return _testContract.tokenApprove( | ||||||
|  |             msg.sender, | ||||||
|  |             spender, | ||||||
|  |             allowance | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function transfer(address recipient, uint256 amount) | ||||||
|  |         external | ||||||
|  |         returns (bool) | ||||||
|  |     { | ||||||
|  |         return _testContract.tokenTransfer( | ||||||
|  |             msg.sender, | ||||||
|  |             recipient, | ||||||
|  |             amount | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function withdraw(uint256 amount) | ||||||
|  |         external | ||||||
|  |     { | ||||||
|  |         return _testContract.wethWithdraw(msg.sender, amount); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function deposit() | ||||||
|  |         external | ||||||
|  |         payable | ||||||
|  |     { | ||||||
|  |         return _testContract.wethDeposit.value(msg.value)(msg.sender); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function allowance(address, address) external view returns (uint256) { | ||||||
|  |         return 0; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function balanceOf(address owner) | ||||||
|  |         external | ||||||
|  |         view | ||||||
|  |         returns (uint256) | ||||||
|  |     { | ||||||
|  |         return _testContract.tokenBalanceOf(owner); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /// @dev KyberBridge overridden to mock tokens and implement IKyberBridge. | ||||||
|  | contract TestKyberBridge is | ||||||
|  |     KyberBridge, | ||||||
|  |     ITestContract, | ||||||
|  |     IKyberNetworkProxy | ||||||
|  | { | ||||||
|  |     event KyberBridgeTrade( | ||||||
|  |         uint256 msgValue, | ||||||
|  |         address sellTokenAddress, | ||||||
|  |         uint256 sellAmount, | ||||||
|  |         address buyTokenAddress, | ||||||
|  |         address payable recipientAddress, | ||||||
|  |         uint256 maxBuyTokenAmount, | ||||||
|  |         uint256 minConversionRate, | ||||||
|  |         address walletId | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     event KyberBridgeWethWithdraw( | ||||||
|  |         address ownerAddress, | ||||||
|  |         uint256 amount | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     event KyberBridgeWethDeposit( | ||||||
|  |         uint256 msgValue, | ||||||
|  |         address ownerAddress, | ||||||
|  |         uint256 amount | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     event KyberBridgeTokenApprove( | ||||||
|  |         address tokenAddress, | ||||||
|  |         address ownerAddress, | ||||||
|  |         address spenderAddress, | ||||||
|  |         uint256 allowance | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     event KyberBridgeTokenTransfer( | ||||||
|  |         address tokenAddress, | ||||||
|  |         address ownerAddress, | ||||||
|  |         address recipientAddress, | ||||||
|  |         uint256 amount | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     IEtherToken public weth; | ||||||
|  |     mapping (address => mapping (address => uint256)) private _tokenBalances; | ||||||
|  |     uint256 private _nextFillAmount; | ||||||
|  |  | ||||||
|  |     constructor() public { | ||||||
|  |         weth = IEtherToken(address(new TestToken(18))); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// @dev Implementation of `IKyberNetworkProxy.trade()` | ||||||
|  |     function trade( | ||||||
|  |         address sellTokenAddress, | ||||||
|  |         uint256 sellAmount, | ||||||
|  |         address buyTokenAddress, | ||||||
|  |         address payable recipientAddress, | ||||||
|  |         uint256 maxBuyTokenAmount, | ||||||
|  |         uint256 minConversionRate, | ||||||
|  |         address walletId | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         payable | ||||||
|  |         returns(uint256 boughtAmount) | ||||||
|  |     { | ||||||
|  |         emit KyberBridgeTrade( | ||||||
|  |             msg.value, | ||||||
|  |             sellTokenAddress, | ||||||
|  |             sellAmount, | ||||||
|  |             buyTokenAddress, | ||||||
|  |             recipientAddress, | ||||||
|  |             maxBuyTokenAmount, | ||||||
|  |             minConversionRate, | ||||||
|  |             walletId | ||||||
|  |         ); | ||||||
|  |         return _nextFillAmount; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function tradeWithHint( | ||||||
|  |         address sellTokenAddress, | ||||||
|  |         uint256 sellAmount, | ||||||
|  |         address buyTokenAddress, | ||||||
|  |         address payable recipientAddress, | ||||||
|  |         uint256 maxBuyTokenAmount, | ||||||
|  |         uint256 minConversionRate, | ||||||
|  |         address payable walletId, | ||||||
|  |         bytes calldata hint | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         payable | ||||||
|  |         returns (uint256 boughtAmount) | ||||||
|  |     { | ||||||
|  |         emit KyberBridgeTrade( | ||||||
|  |             msg.value, | ||||||
|  |             sellTokenAddress, | ||||||
|  |             sellAmount, | ||||||
|  |             buyTokenAddress, | ||||||
|  |             recipientAddress, | ||||||
|  |             maxBuyTokenAmount, | ||||||
|  |             minConversionRate, | ||||||
|  |             walletId | ||||||
|  |         ); | ||||||
|  |         return _nextFillAmount; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function createToken(uint8 decimals) | ||||||
|  |         external | ||||||
|  |         returns (address tokenAddress) | ||||||
|  |     { | ||||||
|  |         return address(new TestToken(decimals)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function setNextFillAmount(uint256 amount) | ||||||
|  |         external | ||||||
|  |         payable | ||||||
|  |     { | ||||||
|  |         if (msg.value != 0) { | ||||||
|  |             require(amount == msg.value, "VALUE_AMOUNT_MISMATCH"); | ||||||
|  |             grantTokensTo(address(weth), address(this), msg.value); | ||||||
|  |         } | ||||||
|  |         _nextFillAmount = amount; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function wethDeposit( | ||||||
|  |         address ownerAddress | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         payable | ||||||
|  |     { | ||||||
|  |         require(msg.sender == address(weth), "ONLY_WETH"); | ||||||
|  |         grantTokensTo(address(weth), ownerAddress, msg.value); | ||||||
|  |         emit KyberBridgeWethDeposit( | ||||||
|  |             msg.value, | ||||||
|  |             ownerAddress, | ||||||
|  |             msg.value | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function wethWithdraw( | ||||||
|  |         address payable ownerAddress, | ||||||
|  |         uint256 amount | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |     { | ||||||
|  |         require(msg.sender == address(weth), "ONLY_WETH"); | ||||||
|  |         _tokenBalances[address(weth)][ownerAddress] -= amount; | ||||||
|  |         ownerAddress.transfer(amount); | ||||||
|  |         emit KyberBridgeWethWithdraw( | ||||||
|  |             ownerAddress, | ||||||
|  |             amount | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function tokenApprove( | ||||||
|  |         address ownerAddress, | ||||||
|  |         address spenderAddress, | ||||||
|  |         uint256 allowance | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         returns (bool success) | ||||||
|  |     { | ||||||
|  |         emit KyberBridgeTokenApprove( | ||||||
|  |             msg.sender, | ||||||
|  |             ownerAddress, | ||||||
|  |             spenderAddress, | ||||||
|  |             allowance | ||||||
|  |         ); | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function tokenTransfer( | ||||||
|  |         address ownerAddress, | ||||||
|  |         address recipientAddress, | ||||||
|  |         uint256 amount | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         returns (bool success) | ||||||
|  |     { | ||||||
|  |         _tokenBalances[msg.sender][ownerAddress] -= amount; | ||||||
|  |         _tokenBalances[msg.sender][recipientAddress] += amount; | ||||||
|  |         emit KyberBridgeTokenTransfer( | ||||||
|  |             msg.sender, | ||||||
|  |             ownerAddress, | ||||||
|  |             recipientAddress, | ||||||
|  |             amount | ||||||
|  |         ); | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function tokenBalanceOf( | ||||||
|  |         address ownerAddress | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         view | ||||||
|  |         returns (uint256 balance) | ||||||
|  |     { | ||||||
|  |         return _tokenBalances[msg.sender][ownerAddress]; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function grantTokensTo(address tokenAddress, address ownerAddress, uint256 amount) | ||||||
|  |         public | ||||||
|  |         payable | ||||||
|  |     { | ||||||
|  |         _tokenBalances[tokenAddress][ownerAddress] += amount; | ||||||
|  |         if (tokenAddress != address(weth)) { | ||||||
|  |             // Send back ether if not WETH. | ||||||
|  |             msg.sender.transfer(msg.value); | ||||||
|  |         } else { | ||||||
|  |             require(msg.value == amount, "VALUE_AMOUNT_MISMATCH"); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // @dev overridden to point to this contract. | ||||||
|  |     function _getKyberNetworkProxyAddress() | ||||||
|  |         internal | ||||||
|  |         view | ||||||
|  |         returns (address) | ||||||
|  |     { | ||||||
|  |         return address(this); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // @dev overridden to point to test WETH. | ||||||
|  |     function _getWethAddress() | ||||||
|  |         internal | ||||||
|  |         view | ||||||
|  |         returns (address) | ||||||
|  |     { | ||||||
|  |         return address(weth); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -224,6 +224,10 @@ contract TestToken { | |||||||
|         TestEventsRaiser(msg.sender).raiseWethWithdraw(amount); |         TestEventsRaiser(msg.sender).raiseWethWithdraw(amount); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     function allowance(address, address) external view returns (uint256) { | ||||||
|  |         return 0; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /// @dev Retrieve the balance for `owner`. |     /// @dev Retrieve the balance for `owner`. | ||||||
|     function balanceOf(address owner) |     function balanceOf(address owner) | ||||||
|         external |         external | ||||||
| @@ -407,26 +411,26 @@ contract TestUniswapBridge is | |||||||
|     function getExchange(address tokenAddress) |     function getExchange(address tokenAddress) | ||||||
|         external |         external | ||||||
|         view |         view | ||||||
|         returns (IUniswapExchange) |         returns (address) | ||||||
|     { |     { | ||||||
|         return IUniswapExchange(_testExchanges[tokenAddress]); |         return address(_testExchanges[tokenAddress]); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // @dev Use `wethToken`. |     // @dev Use `wethToken`. | ||||||
|     function getWethContract() |     function _getWethAddress() | ||||||
|         public |         internal | ||||||
|         view |         view | ||||||
|         returns (IEtherToken) |         returns (address) | ||||||
|     { |     { | ||||||
|         return IEtherToken(address(wethToken)); |         return address(wethToken); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // @dev This contract will double as the Uniswap contract. |     // @dev This contract will double as the Uniswap contract. | ||||||
|     function getUniswapExchangeFactoryContract() |     function _getUniswapExchangeFactoryAddress() | ||||||
|         public |         internal | ||||||
|         view |         view | ||||||
|         returns (IUniswapExchangeFactory) |         returns (address) | ||||||
|     { |     { | ||||||
|         return IUniswapExchangeFactory(address(this)); |         return address(this); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										253
									
								
								contracts/asset-proxy/contracts/test/TestUniswapV2Bridge.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										253
									
								
								contracts/asset-proxy/contracts/test/TestUniswapV2Bridge.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,253 @@ | |||||||
|  | /* | ||||||
|  |  | ||||||
|  |   Copyright 2019 ZeroEx Intl. | ||||||
|  |  | ||||||
|  |   Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |   you may not use this file except in compliance with the License. | ||||||
|  |   You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |     http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |   Unless required by applicable law or agreed to in writing, software | ||||||
|  |   distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |   See the License for the specific language governing permissions and | ||||||
|  |   limitations under the License. | ||||||
|  |  | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | pragma solidity ^0.5.9; | ||||||
|  | pragma experimental ABIEncoderV2; | ||||||
|  |  | ||||||
|  | import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; | ||||||
|  | import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; | ||||||
|  | import "@0x/contracts-utils/contracts/src/LibAddressArray.sol"; | ||||||
|  | import "../src/bridges/UniswapV2Bridge.sol"; | ||||||
|  | import "../src/interfaces/IUniswapV2Router01.sol"; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | contract TestEventsRaiser { | ||||||
|  |  | ||||||
|  |     event TokenTransfer( | ||||||
|  |         address token, | ||||||
|  |         address from, | ||||||
|  |         address to, | ||||||
|  |         uint256 amount | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     event TokenApprove( | ||||||
|  |         address spender, | ||||||
|  |         uint256 allowance | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     event SwapExactTokensForTokensInput( | ||||||
|  |         uint amountIn, | ||||||
|  |         uint amountOutMin, | ||||||
|  |         address toTokenAddress, | ||||||
|  |         address to, | ||||||
|  |         uint deadline | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     function raiseTokenTransfer( | ||||||
|  |         address from, | ||||||
|  |         address to, | ||||||
|  |         uint256 amount | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |     { | ||||||
|  |         emit TokenTransfer( | ||||||
|  |             msg.sender, | ||||||
|  |             from, | ||||||
|  |             to, | ||||||
|  |             amount | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function raiseTokenApprove(address spender, uint256 allowance) external { | ||||||
|  |         emit TokenApprove(spender, allowance); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function raiseSwapExactTokensForTokensInput( | ||||||
|  |         uint amountIn, | ||||||
|  |         uint amountOutMin, | ||||||
|  |         address toTokenAddress, | ||||||
|  |         address to, | ||||||
|  |         uint deadline | ||||||
|  |     ) external | ||||||
|  |     { | ||||||
|  |         emit SwapExactTokensForTokensInput( | ||||||
|  |             amountIn, | ||||||
|  |             amountOutMin, | ||||||
|  |             toTokenAddress, | ||||||
|  |             to, | ||||||
|  |             deadline | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /// @dev A minimalist ERC20 token. | ||||||
|  | contract TestToken { | ||||||
|  |  | ||||||
|  |     using LibSafeMath for uint256; | ||||||
|  |  | ||||||
|  |     mapping (address => uint256) public balances; | ||||||
|  |     string private _nextRevertReason; | ||||||
|  |  | ||||||
|  |     /// @dev Set the balance for `owner`. | ||||||
|  |     function setBalance(address owner, uint256 balance) | ||||||
|  |         external | ||||||
|  |         payable | ||||||
|  |     { | ||||||
|  |         balances[owner] = balance; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// @dev Just emits a TokenTransfer event on the caller | ||||||
|  |     function transfer(address to, uint256 amount) | ||||||
|  |         external | ||||||
|  |         returns (bool) | ||||||
|  |     { | ||||||
|  |         TestEventsRaiser(msg.sender).raiseTokenTransfer(msg.sender, to, amount); | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// @dev Just emits a TokenApprove event on the caller | ||||||
|  |     function approve(address spender, uint256 allowance) | ||||||
|  |         external | ||||||
|  |         returns (bool) | ||||||
|  |     { | ||||||
|  |         TestEventsRaiser(msg.sender).raiseTokenApprove(spender, allowance); | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function allowance(address, address) external view returns (uint256) { | ||||||
|  |         return 0; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// @dev Retrieve the balance for `owner`. | ||||||
|  |     function balanceOf(address owner) | ||||||
|  |         external | ||||||
|  |         view | ||||||
|  |         returns (uint256) | ||||||
|  |     { | ||||||
|  |         return balances[owner]; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /// @dev Mock the UniswapV2Router01 contract | ||||||
|  | contract TestRouter is | ||||||
|  |     IUniswapV2Router01 | ||||||
|  | { | ||||||
|  |     string private _nextRevertReason; | ||||||
|  |  | ||||||
|  |     /// @dev Set the revert reason for `swapExactTokensForTokens`. | ||||||
|  |     function setRevertReason(string calldata reason) | ||||||
|  |         external | ||||||
|  |     { | ||||||
|  |         _nextRevertReason = reason; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function swapExactTokensForTokens( | ||||||
|  |         uint amountIn, | ||||||
|  |         uint amountOutMin, | ||||||
|  |         address[] calldata path, | ||||||
|  |         address to, | ||||||
|  |         uint deadline | ||||||
|  |     ) external returns (uint[] memory amounts) | ||||||
|  |     { | ||||||
|  |         _revertIfReasonExists(); | ||||||
|  |  | ||||||
|  |         amounts = new uint[](path.length); | ||||||
|  |         amounts[0] = amountIn; | ||||||
|  |         amounts[amounts.length - 1] = amountOutMin; | ||||||
|  |  | ||||||
|  |         TestEventsRaiser(msg.sender).raiseSwapExactTokensForTokensInput( | ||||||
|  |             // tokens sold | ||||||
|  |             amountIn, | ||||||
|  |             // tokens bought | ||||||
|  |             amountOutMin, | ||||||
|  |             // output token (toTokenAddress) | ||||||
|  |             path[path.length - 1], | ||||||
|  |             // recipient | ||||||
|  |             to, | ||||||
|  |             // deadline | ||||||
|  |             deadline | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function _revertIfReasonExists() | ||||||
|  |         private | ||||||
|  |         view | ||||||
|  |     { | ||||||
|  |         if (bytes(_nextRevertReason).length != 0) { | ||||||
|  |             revert(_nextRevertReason); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /// @dev UniswapV2Bridge overridden to mock tokens and Uniswap router | ||||||
|  | contract TestUniswapV2Bridge is | ||||||
|  |     UniswapV2Bridge, | ||||||
|  |     TestEventsRaiser | ||||||
|  | { | ||||||
|  |  | ||||||
|  |     // Token address to TestToken instance. | ||||||
|  |     mapping (address => TestToken) private _testTokens; | ||||||
|  |     // TestRouter instance. | ||||||
|  |     TestRouter private _testRouter; | ||||||
|  |  | ||||||
|  |     constructor() public { | ||||||
|  |         _testRouter = new TestRouter(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function setRouterRevertReason(string calldata revertReason) | ||||||
|  |         external | ||||||
|  |     { | ||||||
|  |         _testRouter.setRevertReason(revertReason); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// @dev Sets the balance of this contract for an existing token. | ||||||
|  |     ///      The wei attached will be the balance. | ||||||
|  |     function setTokenBalance(address tokenAddress, uint256 balance) | ||||||
|  |         external | ||||||
|  |     { | ||||||
|  |         TestToken token = _testTokens[tokenAddress]; | ||||||
|  |         token.setBalance(address(this), balance); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// @dev Create a new token | ||||||
|  |     /// @param tokenAddress The token address. If zero, one will be created. | ||||||
|  |     function createToken( | ||||||
|  |         address tokenAddress | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         returns (TestToken token) | ||||||
|  |     { | ||||||
|  |         token = TestToken(tokenAddress); | ||||||
|  |         if (tokenAddress == address(0)) { | ||||||
|  |             token = new TestToken(); | ||||||
|  |         } | ||||||
|  |         _testTokens[address(token)] = token; | ||||||
|  |  | ||||||
|  |         return token; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function getRouterAddress() | ||||||
|  |         external | ||||||
|  |         view | ||||||
|  |         returns (address) | ||||||
|  |     { | ||||||
|  |         return address(_testRouter); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function _getUniswapV2Router01Address() | ||||||
|  |         internal | ||||||
|  |         view | ||||||
|  |         returns (address) | ||||||
|  |     { | ||||||
|  |         return address(_testRouter); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -1,6 +1,6 @@ | |||||||
| { | { | ||||||
|     "name": "@0x/contracts-asset-proxy", |     "name": "@0x/contracts-asset-proxy", | ||||||
|     "version": "2.3.0-beta.1", |     "version": "3.6.3", | ||||||
|     "engines": { |     "engines": { | ||||||
|         "node": ">=6.12" |         "node": ">=6.12" | ||||||
|     }, |     }, | ||||||
| @@ -12,7 +12,7 @@ | |||||||
|     "scripts": { |     "scripts": { | ||||||
|         "build": "yarn pre_build && tsc -b", |         "build": "yarn pre_build && tsc -b", | ||||||
|         "build:ci": "yarn build", |         "build:ci": "yarn build", | ||||||
|         "pre_build": "run-s compile contracts:gen generate_contract_wrappers", |         "pre_build": "run-s compile contracts:gen generate_contract_wrappers contracts:copy", | ||||||
|         "test": "yarn run_mocha", |         "test": "yarn run_mocha", | ||||||
|         "rebuild_and_test": "run-s build test", |         "rebuild_and_test": "run-s build test", | ||||||
|         "test:coverage": "SOLIDITY_COVERAGE=true run-s build run_mocha coverage:report:text coverage:report:lcov", |         "test:coverage": "SOLIDITY_COVERAGE=true run-s build run_mocha coverage:report:text coverage:report:lcov", | ||||||
| @@ -21,46 +21,53 @@ | |||||||
|         "run_mocha": "mocha --require source-map-support/register --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit", |         "run_mocha": "mocha --require source-map-support/register --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit", | ||||||
|         "compile": "sol-compiler", |         "compile": "sol-compiler", | ||||||
|         "watch": "sol-compiler -w", |         "watch": "sol-compiler -w", | ||||||
|         "clean": "shx rm -rf lib generated-artifacts generated-wrappers", |         "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 generated-wrappers --backend ethers", |         "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 ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts", |         "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 **/lib/**/* && yarn lint-contracts", |         "fix": "tslint --fix --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./test/generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts", | ||||||
|         "coverage:report:text": "istanbul report text", |         "coverage:report:text": "istanbul report text", | ||||||
|         "coverage:report:html": "istanbul report html && open coverage/index.html", |         "coverage:report:html": "istanbul report html && open coverage/index.html", | ||||||
|         "profiler:report:html": "istanbul report html && open coverage/index.html", |         "profiler:report:html": "istanbul report html && open coverage/index.html", | ||||||
|         "coverage:report:lcov": "istanbul report lcov", |         "coverage:report:lcov": "istanbul report lcov", | ||||||
|         "test:circleci": "yarn test", |         "test:circleci": "yarn test", | ||||||
|         "contracts:gen": "contracts-gen", |         "contracts:gen": "contracts-gen generate", | ||||||
|  |         "contracts:copy": "contracts-gen copy", | ||||||
|         "lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol", |         "lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol", | ||||||
|         "compile:truffle": "truffle compile" |         "compile:truffle": "truffle compile", | ||||||
|  |         "docs:md": "ts-doc-gen --sourceDir='$PROJECT_FILES' --output=$MD_FILE_DIR --fileExtension=mdx --tsconfig=./typedoc-tsconfig.json", | ||||||
|  |         "docs:json": "typedoc --excludePrivate --excludeExternals --excludeProtected --ignoreCompilerErrors --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES" | ||||||
|     }, |     }, | ||||||
|     "config": { |     "config": { | ||||||
|         "abis": "./generated-artifacts/@(ERC1155Proxy|ERC20BridgeProxy|ERC20Proxy|ERC721Proxy|Eth2DaiBridge|IAssetData|IAssetProxy|IAssetProxyDispatcher|IAuthorizable|IERC20Bridge|IEth2Dai|IUniswapExchange|IUniswapExchangeFactory|MixinAssetProxyDispatcher|MixinAuthorizable|MultiAssetProxy|Ownable|StaticCallProxy|TestERC20Bridge|TestEth2DaiBridge|TestStaticCallTarget|TestUniswapBridge|UniswapBridge).json", |         "abis": "./test/generated-artifacts/@(BalancerBridge|BancorBridge|ChaiBridge|CreamBridge|CurveBridge|DODOBridge|DexForwarderBridge|DydxBridge|ERC1155Proxy|ERC20BridgeProxy|ERC20Proxy|ERC721Proxy|Eth2DaiBridge|IAssetData|IAssetProxy|IAssetProxyDispatcher|IAuthorizable|IBalancerPool|IBancorNetwork|IChai|ICurve|IDydx|IDydxBridge|IERC20Bridge|IEth2Dai|IGasToken|IKyberNetworkProxy|IMStable|IMooniswap|IShell|IUniswapExchange|IUniswapExchangeFactory|IUniswapV2Router01|KyberBridge|MStableBridge|MixinAssetProxyDispatcher|MixinAuthorizable|MixinGasToken|MooniswapBridge|MultiAssetProxy|Ownable|ShellBridge|SnowSwapBridge|StaticCallProxy|SushiSwapBridge|SwerveBridge|TestBancorBridge|TestChaiBridge|TestDexForwarderBridge|TestDydxBridge|TestERC20Bridge|TestEth2DaiBridge|TestKyberBridge|TestStaticCallTarget|TestUniswapBridge|TestUniswapV2Bridge|UniswapBridge|UniswapV2Bridge).json", | ||||||
|         "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually." |         "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually." | ||||||
|     }, |     }, | ||||||
|     "repository": { |     "repository": { | ||||||
|         "type": "git", |         "type": "git", | ||||||
|         "url": "https://github.com/0xProject/0x-monorepo.git" |         "url": "https://github.com/0xProject/protocol.git" | ||||||
|     }, |     }, | ||||||
|     "license": "Apache-2.0", |     "license": "Apache-2.0", | ||||||
|     "bugs": { |     "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": { |     "devDependencies": { | ||||||
|         "@0x/abi-gen": "^4.4.0-beta.1", |         "@0x/abi-gen": "^5.4.7", | ||||||
|         "@0x/contracts-gen": "^1.1.0-beta.1", |         "@0x/contract-wrappers": "^13.9.4", | ||||||
|         "@0x/contracts-test-utils": "^3.2.0-beta.1", |         "@0x/contracts-gen": "2.0.18", | ||||||
|         "@0x/dev-utils": "^2.4.0-beta.1", |         "@0x/contracts-test-utils": "^5.3.9", | ||||||
|         "@0x/sol-compiler": "^3.2.0-beta.1", |         "@0x/contracts-utils": "^4.5.6", | ||||||
|         "@0x/tslint-config": "^3.1.0-beta.1", |         "@0x/dev-utils": "^4.0.1", | ||||||
|  |         "@0x/sol-compiler": "^4.2.7", | ||||||
|  |         "@0x/ts-doc-gen": "^0.0.28", | ||||||
|  |         "@0x/tslint-config": "^4.1.3", | ||||||
|         "@types/lodash": "4.14.104", |         "@types/lodash": "4.14.104", | ||||||
|         "@types/mocha": "^5.2.7", |         "@types/mocha": "^5.2.7", | ||||||
|         "@types/node": "*", |         "@types/node": "12.12.54", | ||||||
|         "chai": "^4.0.1", |         "chai": "^4.0.1", | ||||||
|         "chai-as-promised": "^7.1.0", |         "chai-as-promised": "^7.1.0", | ||||||
|         "chai-bignumber": "^3.0.0", |         "chai-bignumber": "^3.0.0", | ||||||
|         "dirty-chai": "^2.0.1", |         "dirty-chai": "^2.0.1", | ||||||
|  |         "ethereumjs-util": "^5.1.1", | ||||||
|         "make-promises-safe": "^1.1.0", |         "make-promises-safe": "^1.1.0", | ||||||
|         "mocha": "^6.2.0", |         "mocha": "^6.2.0", | ||||||
|         "npm-run-all": "^4.1.2", |         "npm-run-all": "^4.1.2", | ||||||
| @@ -68,25 +75,25 @@ | |||||||
|         "solhint": "^1.4.1", |         "solhint": "^1.4.1", | ||||||
|         "truffle": "^5.0.32", |         "truffle": "^5.0.32", | ||||||
|         "tslint": "5.11.0", |         "tslint": "5.11.0", | ||||||
|  |         "typedoc": "~0.16.11", | ||||||
|         "typescript": "3.0.1" |         "typescript": "3.0.1" | ||||||
|     }, |     }, | ||||||
|     "dependencies": { |     "dependencies": { | ||||||
|         "@0x/base-contract": "^5.5.0-beta.1", |         "@0x/base-contract": "^6.2.11", | ||||||
|         "@0x/contracts-dev-utils": "^0.1.0-beta.1", |         "@0x/contracts-erc1155": "^2.1.12", | ||||||
|         "@0x/contracts-erc1155": "^1.2.0-beta.1", |         "@0x/contracts-erc20": "^3.2.6", | ||||||
|         "@0x/contracts-erc20": "^2.3.0-beta.1", |         "@0x/contracts-erc721": "^3.1.12", | ||||||
|         "@0x/contracts-erc721": "^2.2.0-beta.1", |         "@0x/contracts-exchange-libs": "^4.3.12", | ||||||
|         "@0x/contracts-utils": "^3.3.0-beta.1", |         "@0x/order-utils": "^10.4.4", | ||||||
|         "@0x/order-utils": "^8.5.0-beta.1", |         "@0x/types": "^3.3.0", | ||||||
|         "@0x/types": "^2.5.0-beta.1", |         "@0x/typescript-typings": "^5.1.5", | ||||||
|         "@0x/typescript-typings": "^4.4.0-beta.1", |         "@0x/utils": "^6.1.0", | ||||||
|         "@0x/utils": "^4.6.0-beta.1", |         "@0x/web3-wrapper": "^7.2.8", | ||||||
|         "@0x/web3-wrapper": "^6.1.0-beta.1", |         "ethereum-types": "^3.3.3", | ||||||
|         "ethereum-types": "^2.2.0-beta.1", |  | ||||||
|         "ethereumjs-util": "^5.1.1", |  | ||||||
|         "lodash": "^4.17.11" |         "lodash": "^4.17.11" | ||||||
|     }, |     }, | ||||||
|     "publishConfig": { |     "publishConfig": { | ||||||
|         "access": "public" |         "access": "public" | ||||||
|     } |     }, | ||||||
|  |     "gitHead": "4f91bfd907996b2f4dd383778b50c479c2602b56" | ||||||
| } | } | ||||||
|   | |||||||
| @@ -5,6 +5,14 @@ | |||||||
|  */ |  */ | ||||||
| import { ContractArtifact } from 'ethereum-types'; | import { ContractArtifact } from 'ethereum-types'; | ||||||
|  |  | ||||||
|  | import * as BalancerBridge from '../generated-artifacts/BalancerBridge.json'; | ||||||
|  | import * as BancorBridge from '../generated-artifacts/BancorBridge.json'; | ||||||
|  | import * as ChaiBridge from '../generated-artifacts/ChaiBridge.json'; | ||||||
|  | import * as CreamBridge from '../generated-artifacts/CreamBridge.json'; | ||||||
|  | import * as CurveBridge from '../generated-artifacts/CurveBridge.json'; | ||||||
|  | import * as DexForwarderBridge from '../generated-artifacts/DexForwarderBridge.json'; | ||||||
|  | import * as DODOBridge from '../generated-artifacts/DODOBridge.json'; | ||||||
|  | import * as DydxBridge from '../generated-artifacts/DydxBridge.json'; | ||||||
| import * as ERC1155Proxy from '../generated-artifacts/ERC1155Proxy.json'; | import * as ERC1155Proxy from '../generated-artifacts/ERC1155Proxy.json'; | ||||||
| import * as ERC20BridgeProxy from '../generated-artifacts/ERC20BridgeProxy.json'; | import * as ERC20BridgeProxy from '../generated-artifacts/ERC20BridgeProxy.json'; | ||||||
| import * as ERC20Proxy from '../generated-artifacts/ERC20Proxy.json'; | import * as ERC20Proxy from '../generated-artifacts/ERC20Proxy.json'; | ||||||
| @@ -14,20 +22,47 @@ import * as IAssetData from '../generated-artifacts/IAssetData.json'; | |||||||
| import * as IAssetProxy from '../generated-artifacts/IAssetProxy.json'; | import * as IAssetProxy from '../generated-artifacts/IAssetProxy.json'; | ||||||
| import * as IAssetProxyDispatcher from '../generated-artifacts/IAssetProxyDispatcher.json'; | import * as IAssetProxyDispatcher from '../generated-artifacts/IAssetProxyDispatcher.json'; | ||||||
| import * as IAuthorizable from '../generated-artifacts/IAuthorizable.json'; | import * as IAuthorizable from '../generated-artifacts/IAuthorizable.json'; | ||||||
|  | import * as IBalancerPool from '../generated-artifacts/IBalancerPool.json'; | ||||||
|  | import * as IBancorNetwork from '../generated-artifacts/IBancorNetwork.json'; | ||||||
|  | import * as IChai from '../generated-artifacts/IChai.json'; | ||||||
|  | import * as ICurve from '../generated-artifacts/ICurve.json'; | ||||||
|  | import * as IDydx from '../generated-artifacts/IDydx.json'; | ||||||
|  | import * as IDydxBridge from '../generated-artifacts/IDydxBridge.json'; | ||||||
| import * as IERC20Bridge from '../generated-artifacts/IERC20Bridge.json'; | import * as IERC20Bridge from '../generated-artifacts/IERC20Bridge.json'; | ||||||
| import * as IEth2Dai from '../generated-artifacts/IEth2Dai.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 IUniswapExchange from '../generated-artifacts/IUniswapExchange.json'; | ||||||
| import * as IUniswapExchangeFactory from '../generated-artifacts/IUniswapExchangeFactory.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 MixinAssetProxyDispatcher from '../generated-artifacts/MixinAssetProxyDispatcher.json'; | ||||||
| import * as MixinAuthorizable from '../generated-artifacts/MixinAuthorizable.json'; | import * as MixinAuthorizable from '../generated-artifacts/MixinAuthorizable.json'; | ||||||
|  | import * as MixinGasToken from '../generated-artifacts/MixinGasToken.json'; | ||||||
|  | import * as MooniswapBridge from '../generated-artifacts/MooniswapBridge.json'; | ||||||
|  | import * as MStableBridge from '../generated-artifacts/MStableBridge.json'; | ||||||
| import * as MultiAssetProxy from '../generated-artifacts/MultiAssetProxy.json'; | import * as MultiAssetProxy from '../generated-artifacts/MultiAssetProxy.json'; | ||||||
| import * as Ownable from '../generated-artifacts/Ownable.json'; | import * as Ownable from '../generated-artifacts/Ownable.json'; | ||||||
|  | import * as ShellBridge from '../generated-artifacts/ShellBridge.json'; | ||||||
|  | import * as SnowSwapBridge from '../generated-artifacts/SnowSwapBridge.json'; | ||||||
| import * as StaticCallProxy from '../generated-artifacts/StaticCallProxy.json'; | import * as StaticCallProxy from '../generated-artifacts/StaticCallProxy.json'; | ||||||
|  | import * as SushiSwapBridge from '../generated-artifacts/SushiSwapBridge.json'; | ||||||
|  | import * as SwerveBridge from '../generated-artifacts/SwerveBridge.json'; | ||||||
|  | import * as TestBancorBridge from '../generated-artifacts/TestBancorBridge.json'; | ||||||
|  | import * as TestChaiBridge from '../generated-artifacts/TestChaiBridge.json'; | ||||||
|  | import * as TestDexForwarderBridge from '../generated-artifacts/TestDexForwarderBridge.json'; | ||||||
|  | import * as TestDydxBridge from '../generated-artifacts/TestDydxBridge.json'; | ||||||
| import * as TestERC20Bridge from '../generated-artifacts/TestERC20Bridge.json'; | import * as TestERC20Bridge from '../generated-artifacts/TestERC20Bridge.json'; | ||||||
| import * as TestEth2DaiBridge from '../generated-artifacts/TestEth2DaiBridge.json'; | import * as TestEth2DaiBridge from '../generated-artifacts/TestEth2DaiBridge.json'; | ||||||
|  | import * as TestKyberBridge from '../generated-artifacts/TestKyberBridge.json'; | ||||||
| import * as TestStaticCallTarget from '../generated-artifacts/TestStaticCallTarget.json'; | import * as TestStaticCallTarget from '../generated-artifacts/TestStaticCallTarget.json'; | ||||||
| import * as TestUniswapBridge from '../generated-artifacts/TestUniswapBridge.json'; | import * as TestUniswapBridge from '../generated-artifacts/TestUniswapBridge.json'; | ||||||
|  | import * as TestUniswapV2Bridge from '../generated-artifacts/TestUniswapV2Bridge.json'; | ||||||
| import * as UniswapBridge from '../generated-artifacts/UniswapBridge.json'; | import * as UniswapBridge from '../generated-artifacts/UniswapBridge.json'; | ||||||
|  | import * as UniswapV2Bridge from '../generated-artifacts/UniswapV2Bridge.json'; | ||||||
| export const artifacts = { | export const artifacts = { | ||||||
|     MixinAssetProxyDispatcher: MixinAssetProxyDispatcher as ContractArtifact, |     MixinAssetProxyDispatcher: MixinAssetProxyDispatcher as ContractArtifact, | ||||||
|     MixinAuthorizable: MixinAuthorizable as ContractArtifact, |     MixinAuthorizable: MixinAuthorizable as ContractArtifact, | ||||||
| @@ -38,18 +73,53 @@ export const artifacts = { | |||||||
|     ERC721Proxy: ERC721Proxy as ContractArtifact, |     ERC721Proxy: ERC721Proxy as ContractArtifact, | ||||||
|     MultiAssetProxy: MultiAssetProxy as ContractArtifact, |     MultiAssetProxy: MultiAssetProxy as ContractArtifact, | ||||||
|     StaticCallProxy: StaticCallProxy as ContractArtifact, |     StaticCallProxy: StaticCallProxy as ContractArtifact, | ||||||
|  |     BalancerBridge: BalancerBridge as ContractArtifact, | ||||||
|  |     BancorBridge: BancorBridge as ContractArtifact, | ||||||
|  |     ChaiBridge: ChaiBridge as ContractArtifact, | ||||||
|  |     CreamBridge: CreamBridge as ContractArtifact, | ||||||
|  |     CurveBridge: CurveBridge as ContractArtifact, | ||||||
|  |     DODOBridge: DODOBridge as ContractArtifact, | ||||||
|  |     DexForwarderBridge: DexForwarderBridge as ContractArtifact, | ||||||
|  |     DydxBridge: DydxBridge as ContractArtifact, | ||||||
|     Eth2DaiBridge: Eth2DaiBridge as ContractArtifact, |     Eth2DaiBridge: Eth2DaiBridge as ContractArtifact, | ||||||
|  |     KyberBridge: KyberBridge as ContractArtifact, | ||||||
|  |     MStableBridge: MStableBridge as ContractArtifact, | ||||||
|  |     MixinGasToken: MixinGasToken as ContractArtifact, | ||||||
|  |     MooniswapBridge: MooniswapBridge as ContractArtifact, | ||||||
|  |     ShellBridge: ShellBridge as ContractArtifact, | ||||||
|  |     SnowSwapBridge: SnowSwapBridge as ContractArtifact, | ||||||
|  |     SushiSwapBridge: SushiSwapBridge as ContractArtifact, | ||||||
|  |     SwerveBridge: SwerveBridge as ContractArtifact, | ||||||
|     UniswapBridge: UniswapBridge as ContractArtifact, |     UniswapBridge: UniswapBridge as ContractArtifact, | ||||||
|  |     UniswapV2Bridge: UniswapV2Bridge as ContractArtifact, | ||||||
|     IAssetData: IAssetData as ContractArtifact, |     IAssetData: IAssetData as ContractArtifact, | ||||||
|     IAssetProxy: IAssetProxy as ContractArtifact, |     IAssetProxy: IAssetProxy as ContractArtifact, | ||||||
|     IAssetProxyDispatcher: IAssetProxyDispatcher as ContractArtifact, |     IAssetProxyDispatcher: IAssetProxyDispatcher as ContractArtifact, | ||||||
|     IAuthorizable: IAuthorizable as ContractArtifact, |     IAuthorizable: IAuthorizable as ContractArtifact, | ||||||
|  |     IBalancerPool: IBalancerPool as ContractArtifact, | ||||||
|  |     IBancorNetwork: IBancorNetwork as ContractArtifact, | ||||||
|  |     IChai: IChai as ContractArtifact, | ||||||
|  |     ICurve: ICurve as ContractArtifact, | ||||||
|  |     IDydx: IDydx as ContractArtifact, | ||||||
|  |     IDydxBridge: IDydxBridge as ContractArtifact, | ||||||
|     IERC20Bridge: IERC20Bridge as ContractArtifact, |     IERC20Bridge: IERC20Bridge as ContractArtifact, | ||||||
|     IEth2Dai: IEth2Dai 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, |     IUniswapExchange: IUniswapExchange as ContractArtifact, | ||||||
|     IUniswapExchangeFactory: IUniswapExchangeFactory 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, |     TestERC20Bridge: TestERC20Bridge as ContractArtifact, | ||||||
|     TestEth2DaiBridge: TestEth2DaiBridge as ContractArtifact, |     TestEth2DaiBridge: TestEth2DaiBridge as ContractArtifact, | ||||||
|  |     TestKyberBridge: TestKyberBridge as ContractArtifact, | ||||||
|     TestStaticCallTarget: TestStaticCallTarget as ContractArtifact, |     TestStaticCallTarget: TestStaticCallTarget as ContractArtifact, | ||||||
|     TestUniswapBridge: TestUniswapBridge as ContractArtifact, |     TestUniswapBridge: TestUniswapBridge as ContractArtifact, | ||||||
|  |     TestUniswapV2Bridge: TestUniswapV2Bridge as ContractArtifact, | ||||||
| }; | }; | ||||||
|   | |||||||
							
								
								
									
										112
									
								
								contracts/asset-proxy/src/asset_data.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								contracts/asset-proxy/src/asset_data.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,112 @@ | |||||||
|  | import { AssetProxyId } from '@0x/types'; | ||||||
|  | import { BigNumber, hexUtils } from '@0x/utils'; | ||||||
|  |  | ||||||
|  | import { IAssetDataContract } from './wrappers'; | ||||||
|  |  | ||||||
|  | const assetDataIface = new IAssetDataContract('0x0000000000000000000000000000000000000000', { isEIP1193: true } as any); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Get the proxy ID from encoded asset data. | ||||||
|  |  */ | ||||||
|  | export function getAssetDataProxyId(encoded: string): AssetProxyId { | ||||||
|  |     // tslint:disable-next-line: no-unnecessary-type-assertion | ||||||
|  |     return hexUtils.slice(encoded, 0, 4) as AssetProxyId; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Decode ERC20 asset data. | ||||||
|  |  */ | ||||||
|  | export function decodeERC20AssetData(encoded: string): string { | ||||||
|  |     return assetDataIface.getABIDecodedTransactionData<string>('ERC20Token', encoded); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Decode ERC721 asset data. | ||||||
|  |  */ | ||||||
|  | export function decodeERC721AssetData(encoded: string): [string, BigNumber] { | ||||||
|  |     return assetDataIface.getABIDecodedTransactionData<[string, BigNumber]>('ERC721Token', encoded); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Decode ERC1155 asset data. | ||||||
|  |  */ | ||||||
|  | export function decodeERC1155AssetData(encoded: string): [string, BigNumber[], BigNumber[], string] { | ||||||
|  |     return assetDataIface.getABIDecodedTransactionData<[string, BigNumber[], BigNumber[], string]>( | ||||||
|  |         'ERC1155Assets', | ||||||
|  |         encoded, | ||||||
|  |     ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Decode MultiAsset asset data. | ||||||
|  |  */ | ||||||
|  | export function decodeMultiAssetData(encoded: string): [BigNumber[], string[]] { | ||||||
|  |     return assetDataIface.getABIDecodedTransactionData<[BigNumber[], string[]]>('MultiAsset', encoded); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Decode StaticCall asset data. | ||||||
|  |  */ | ||||||
|  | export function decodeStaticCallAssetData(encoded: string): [string, string, string] { | ||||||
|  |     return assetDataIface.getABIDecodedTransactionData<[string, string, string]>('StaticCall', encoded); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Decode ERC20Bridge asset data. | ||||||
|  |  */ | ||||||
|  | export function decodeERC20BridgeAssetData(encoded: string): [string, string, string] { | ||||||
|  |     return assetDataIface.getABIDecodedTransactionData<[string, string, string]>('ERC20Bridge', encoded); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Encode ERC20 asset data. | ||||||
|  |  */ | ||||||
|  | export function encodeERC20AssetData(tokenAddress: string): string { | ||||||
|  |     return assetDataIface.ERC20Token(tokenAddress).getABIEncodedTransactionData(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Encode ERC721 asset data. | ||||||
|  |  */ | ||||||
|  | export function encodeERC721AssetData(tokenAddress: string, tokenId: BigNumber): string { | ||||||
|  |     return assetDataIface.ERC721Token(tokenAddress, tokenId).getABIEncodedTransactionData(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Encode ERC1155 asset data. | ||||||
|  |  */ | ||||||
|  | export function encodeERC1155AssetData( | ||||||
|  |     tokenAddress: string, | ||||||
|  |     tokenIds: BigNumber[], | ||||||
|  |     values: BigNumber[], | ||||||
|  |     callbackData: string, | ||||||
|  | ): string { | ||||||
|  |     return assetDataIface.ERC1155Assets(tokenAddress, tokenIds, values, callbackData).getABIEncodedTransactionData(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Encode MultiAsset asset data. | ||||||
|  |  */ | ||||||
|  | export function encodeMultiAssetData(values: BigNumber[], nestedAssetData: string[]): string { | ||||||
|  |     return assetDataIface.MultiAsset(values, nestedAssetData).getABIEncodedTransactionData(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Encode StaticCall asset data. | ||||||
|  |  */ | ||||||
|  | export function encodeStaticCallAssetData( | ||||||
|  |     staticCallTargetAddress: string, | ||||||
|  |     staticCallData: string, | ||||||
|  |     expectedReturnDataHash: string, | ||||||
|  | ): string { | ||||||
|  |     return assetDataIface | ||||||
|  |         .StaticCall(staticCallTargetAddress, staticCallData, expectedReturnDataHash) | ||||||
|  |         .getABIEncodedTransactionData(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Encode ERC20Bridge asset data. | ||||||
|  |  */ | ||||||
|  | export function encodeERC20BridgeAssetData(tokenAddress: string, bridgeAddress: string, bridgeData: string): string { | ||||||
|  |     return assetDataIface.ERC20Bridge(tokenAddress, bridgeAddress, bridgeData).getABIEncodedTransactionData(); | ||||||
|  | } | ||||||
							
								
								
									
										27
									
								
								contracts/asset-proxy/src/dex_forwarder_bridge.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								contracts/asset-proxy/src/dex_forwarder_bridge.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | |||||||
|  | import { AbiEncoder, BigNumber } from '@0x/utils'; | ||||||
|  |  | ||||||
|  | export interface DexForwarderBridgeCall { | ||||||
|  |     target: string; | ||||||
|  |     inputTokenAmount: BigNumber; | ||||||
|  |     outputTokenAmount: BigNumber; | ||||||
|  |     bridgeData: string; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export interface DexForwaderBridgeData { | ||||||
|  |     inputToken: string; | ||||||
|  |     calls: DexForwarderBridgeCall[]; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const dexForwarderBridgeDataEncoder = AbiEncoder.create([ | ||||||
|  |     { name: 'inputToken', type: 'address' }, | ||||||
|  |     { | ||||||
|  |         name: 'calls', | ||||||
|  |         type: 'tuple[]', | ||||||
|  |         components: [ | ||||||
|  |             { name: 'target', type: 'address' }, | ||||||
|  |             { name: 'inputTokenAmount', type: 'uint256' }, | ||||||
|  |             { name: 'outputTokenAmount', type: 'uint256' }, | ||||||
|  |             { name: 'bridgeData', type: 'bytes' }, | ||||||
|  |         ], | ||||||
|  |     }, | ||||||
|  | ]); | ||||||
							
								
								
									
										40
									
								
								contracts/asset-proxy/src/dydx_bridge_encoder.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								contracts/asset-proxy/src/dydx_bridge_encoder.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | |||||||
|  | import { AbiEncoder, BigNumber } from '@0x/utils'; | ||||||
|  |  | ||||||
|  | export enum DydxBridgeActionType { | ||||||
|  |     Deposit, | ||||||
|  |     Withdraw, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export interface DydxBridgeAction { | ||||||
|  |     actionType: DydxBridgeActionType; | ||||||
|  |     accountIdx: BigNumber; | ||||||
|  |     marketId: BigNumber; | ||||||
|  |     conversionRateNumerator: BigNumber; | ||||||
|  |     conversionRateDenominator: BigNumber; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export interface DydxBridgeData { | ||||||
|  |     accountNumbers: BigNumber[]; | ||||||
|  |     actions: DydxBridgeAction[]; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const dydxBridgeDataEncoder = AbiEncoder.create([ | ||||||
|  |     { | ||||||
|  |         name: 'bridgeData', | ||||||
|  |         type: 'tuple', | ||||||
|  |         components: [ | ||||||
|  |             { name: 'accountNumbers', type: 'uint256[]' }, | ||||||
|  |             { | ||||||
|  |                 name: 'actions', | ||||||
|  |                 type: 'tuple[]', | ||||||
|  |                 components: [ | ||||||
|  |                     { name: 'actionType', type: 'uint8' }, | ||||||
|  |                     { name: 'accountIdx', type: 'uint256' }, | ||||||
|  |                     { name: 'marketId', type: 'uint256' }, | ||||||
|  |                     { name: 'conversionRateNumerator', type: 'uint256' }, | ||||||
|  |                     { name: 'conversionRateDenominator', type: 'uint256' }, | ||||||
|  |                 ], | ||||||
|  |             }, | ||||||
|  |         ], | ||||||
|  |     }, | ||||||
|  | ]); | ||||||
| @@ -1,4 +1,3 @@ | |||||||
| import { DevUtilsContract } from '@0x/contracts-dev-utils'; |  | ||||||
| import { artifacts as erc1155Artifacts, ERC1155MintableContract, Erc1155Wrapper } from '@0x/contracts-erc1155'; | import { artifacts as erc1155Artifacts, ERC1155MintableContract, Erc1155Wrapper } from '@0x/contracts-erc1155'; | ||||||
| import { | import { | ||||||
|     constants, |     constants, | ||||||
| @@ -13,7 +12,9 @@ import { Web3Wrapper } from '@0x/web3-wrapper'; | |||||||
| import { Provider, TransactionReceiptWithDecodedLogs } from 'ethereum-types'; | import { Provider, TransactionReceiptWithDecodedLogs } from 'ethereum-types'; | ||||||
| import * as _ from 'lodash'; | import * as _ from 'lodash'; | ||||||
| 
 | 
 | ||||||
| import { artifacts, ERC1155ProxyContract, IAssetProxyContract } from '../../src'; | import { artifacts } from './artifacts'; | ||||||
|  | 
 | ||||||
|  | import { ERC1155ProxyContract, IAssetDataContract, IAssetProxyContract } from './wrappers'; | ||||||
| 
 | 
 | ||||||
| export class ERC1155ProxyWrapper { | export class ERC1155ProxyWrapper { | ||||||
|     private readonly _tokenOwnerAddresses: string[]; |     private readonly _tokenOwnerAddresses: string[]; | ||||||
| @@ -26,7 +27,7 @@ export class ERC1155ProxyWrapper { | |||||||
|     private readonly _logDecoder: LogDecoder; |     private readonly _logDecoder: LogDecoder; | ||||||
|     private readonly _dummyTokenWrappers: Erc1155Wrapper[]; |     private readonly _dummyTokenWrappers: Erc1155Wrapper[]; | ||||||
|     private readonly _assetProxyInterface: IAssetProxyContract; |     private readonly _assetProxyInterface: IAssetProxyContract; | ||||||
|     private readonly _devUtils: DevUtilsContract; |     private readonly _assetDataInterface: IAssetDataContract; | ||||||
|     private _proxyContract?: ERC1155ProxyContract; |     private _proxyContract?: ERC1155ProxyContract; | ||||||
|     private _proxyIdIfExists?: string; |     private _proxyIdIfExists?: string; | ||||||
|     private _initialTokenIdsByOwner: ERC1155HoldingsByOwner = { fungible: {}, nonFungible: {} }; |     private _initialTokenIdsByOwner: ERC1155HoldingsByOwner = { fungible: {}, nonFungible: {} }; | ||||||
| @@ -38,7 +39,7 @@ export class ERC1155ProxyWrapper { | |||||||
|         this._logDecoder = new LogDecoder(this._web3Wrapper, allArtifacts); |         this._logDecoder = new LogDecoder(this._web3Wrapper, allArtifacts); | ||||||
|         this._dummyTokenWrappers = []; |         this._dummyTokenWrappers = []; | ||||||
|         this._assetProxyInterface = new IAssetProxyContract(constants.NULL_ADDRESS, provider); |         this._assetProxyInterface = new IAssetProxyContract(constants.NULL_ADDRESS, provider); | ||||||
|         this._devUtils = new DevUtilsContract(constants.NULL_ADDRESS, provider); |         this._assetDataInterface = new IAssetDataContract(constants.NULL_ADDRESS, provider); | ||||||
|         this._tokenOwnerAddresses = tokenOwnerAddresses; |         this._tokenOwnerAddresses = tokenOwnerAddresses; | ||||||
|         this._contractOwnerAddress = contractOwnerAddress; |         this._contractOwnerAddress = contractOwnerAddress; | ||||||
|         this._fungibleTokenIds = []; |         this._fungibleTokenIds = []; | ||||||
| @@ -58,7 +59,7 @@ export class ERC1155ProxyWrapper { | |||||||
|                 txDefaults, |                 txDefaults, | ||||||
|                 artifacts, |                 artifacts, | ||||||
|             ); |             ); | ||||||
|             const erc1155Wrapper = new Erc1155Wrapper(erc1155Contract, this._provider, this._contractOwnerAddress); |             const erc1155Wrapper = new Erc1155Wrapper(erc1155Contract, this._contractOwnerAddress); | ||||||
|             this._dummyTokenWrappers.push(erc1155Wrapper); |             this._dummyTokenWrappers.push(erc1155Wrapper); | ||||||
|         } |         } | ||||||
|         return this._dummyTokenWrappers; |         return this._dummyTokenWrappers; | ||||||
| @@ -74,7 +75,7 @@ export class ERC1155ProxyWrapper { | |||||||
|             txDefaults, |             txDefaults, | ||||||
|             artifacts, |             artifacts, | ||||||
|         ); |         ); | ||||||
|         this._proxyIdIfExists = await this._proxyContract.getProxyId.callAsync(); |         this._proxyIdIfExists = await this._proxyContract.getProxyId().callAsync(); | ||||||
|         return this._proxyContract; |         return this._proxyContract; | ||||||
|     } |     } | ||||||
|     /** |     /** | ||||||
| @@ -111,19 +112,13 @@ export class ERC1155ProxyWrapper { | |||||||
|         this._validateProxyContractExistsOrThrow(); |         this._validateProxyContractExistsOrThrow(); | ||||||
|         const assetData = |         const assetData = | ||||||
|             assetData_ === undefined |             assetData_ === undefined | ||||||
|                 ? await this._devUtils.encodeERC1155AssetData.callAsync( |                 ? this._assetDataInterface | ||||||
|                       contractAddress, |                       .ERC1155Assets(contractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData) | ||||||
|                       tokensToTransfer, |                       .getABIEncodedTransactionData() | ||||||
|                       valuesToTransfer, |  | ||||||
|                       receiverCallbackData, |  | ||||||
|                   ) |  | ||||||
|                 : assetData_; |                 : assetData_; | ||||||
|         const data = this._assetProxyInterface.transferFrom.getABIEncodedTransactionData( |         const data = this._assetProxyInterface | ||||||
|             assetData, |             .transferFrom(assetData, from, to, valueMultiplier) | ||||||
|             from, |             .getABIEncodedTransactionData(); | ||||||
|             to, |  | ||||||
|             valueMultiplier, |  | ||||||
|         ); |  | ||||||
|         return data; |         return data; | ||||||
|     } |     } | ||||||
|     /** |     /** | ||||||
| @@ -171,19 +166,13 @@ export class ERC1155ProxyWrapper { | |||||||
|         this._validateProxyContractExistsOrThrow(); |         this._validateProxyContractExistsOrThrow(); | ||||||
|         const assetData = |         const assetData = | ||||||
|             assetData_ === undefined |             assetData_ === undefined | ||||||
|                 ? await this._devUtils.encodeERC1155AssetData.callAsync( |                 ? this._assetDataInterface | ||||||
|                       contractAddress, |                       .ERC1155Assets(contractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData) | ||||||
|                       tokensToTransfer, |                       .getABIEncodedTransactionData() | ||||||
|                       valuesToTransfer, |  | ||||||
|                       receiverCallbackData, |  | ||||||
|                   ) |  | ||||||
|                 : assetData_; |                 : assetData_; | ||||||
|         const data = this._assetProxyInterface.transferFrom.getABIEncodedTransactionData( |         const data = this._assetProxyInterface | ||||||
|             assetData, |             .transferFrom(assetData, from, to, valueMultiplier) | ||||||
|             from, |             .getABIEncodedTransactionData(); | ||||||
|             to, |  | ||||||
|             valueMultiplier, |  | ||||||
|         ); |  | ||||||
|         const txHash = await this._web3Wrapper.sendTransactionAsync({ |         const txHash = await this._web3Wrapper.sendTransactionAsync({ | ||||||
|             to: (this._proxyContract as ERC1155ProxyContract).address, |             to: (this._proxyContract as ERC1155ProxyContract).address, | ||||||
|             data, |             data, | ||||||
| @@ -364,7 +353,7 @@ export class ERC1155ProxyWrapper { | |||||||
|         this._validateProxyContractExistsOrThrow(); |         this._validateProxyContractExistsOrThrow(); | ||||||
|         const tokenContract = this._getContractFromAddress(contractAddress); |         const tokenContract = this._getContractFromAddress(contractAddress); | ||||||
|         const operator = (this._proxyContract as ERC1155ProxyContract).address; |         const operator = (this._proxyContract as ERC1155ProxyContract).address; | ||||||
|         const didApproveAll = await tokenContract.isApprovedForAll.callAsync(userAddress, operator); |         const didApproveAll = await tokenContract.isApprovedForAll(userAddress, operator).callAsync(); | ||||||
|         return didApproveAll; |         return didApproveAll; | ||||||
|     } |     } | ||||||
|     public getFungibleTokenIds(): BigNumber[] { |     public getFungibleTokenIds(): BigNumber[] { | ||||||
| @@ -1,18 +1,19 @@ | |||||||
| import { DevUtilsContract } from '@0x/contracts-dev-utils'; |  | ||||||
| import { artifacts as erc20Artifacts, DummyERC20TokenContract } from '@0x/contracts-erc20'; | import { artifacts as erc20Artifacts, DummyERC20TokenContract } from '@0x/contracts-erc20'; | ||||||
| import { constants, ERC20BalancesByOwner, txDefaults } from '@0x/contracts-test-utils'; | import { constants, ERC20BalancesByOwner, txDefaults } from '@0x/contracts-test-utils'; | ||||||
| import { BigNumber } from '@0x/utils'; | import { BigNumber } from '@0x/utils'; | ||||||
| import { ZeroExProvider } from 'ethereum-types'; | import { ZeroExProvider } from 'ethereum-types'; | ||||||
| import * as _ from 'lodash'; | import * as _ from 'lodash'; | ||||||
| 
 | 
 | ||||||
| import { artifacts, ERC20ProxyContract } from '../../src'; | import { artifacts } from './artifacts'; | ||||||
|  | 
 | ||||||
|  | import { ERC20ProxyContract, IAssetDataContract } from './wrappers'; | ||||||
| 
 | 
 | ||||||
| export class ERC20Wrapper { | export class ERC20Wrapper { | ||||||
|     private readonly _tokenOwnerAddresses: string[]; |     private readonly _tokenOwnerAddresses: string[]; | ||||||
|     private readonly _contractOwnerAddress: string; |     private readonly _contractOwnerAddress: string; | ||||||
|     private readonly _provider: ZeroExProvider; |     private readonly _provider: ZeroExProvider; | ||||||
|     private readonly _dummyTokenContracts: DummyERC20TokenContract[]; |     private readonly _dummyTokenContracts: DummyERC20TokenContract[]; | ||||||
|     private readonly _devUtils: DevUtilsContract; |     private readonly _assetDataInterface: IAssetDataContract; | ||||||
|     private _proxyContract?: ERC20ProxyContract; |     private _proxyContract?: ERC20ProxyContract; | ||||||
|     private _proxyIdIfExists?: string; |     private _proxyIdIfExists?: string; | ||||||
|     /** |     /** | ||||||
| @@ -27,7 +28,7 @@ export class ERC20Wrapper { | |||||||
|         this._provider = provider; |         this._provider = provider; | ||||||
|         this._tokenOwnerAddresses = tokenOwnerAddresses; |         this._tokenOwnerAddresses = tokenOwnerAddresses; | ||||||
|         this._contractOwnerAddress = contractOwnerAddress; |         this._contractOwnerAddress = contractOwnerAddress; | ||||||
|         this._devUtils = new DevUtilsContract(constants.NULL_ADDRESS, provider); |         this._assetDataInterface = new IAssetDataContract(constants.NULL_ADDRESS, provider); | ||||||
|     } |     } | ||||||
|     public async deployDummyTokensAsync( |     public async deployDummyTokensAsync( | ||||||
|         numberToDeploy: number, |         numberToDeploy: number, | ||||||
| @@ -56,7 +57,7 @@ export class ERC20Wrapper { | |||||||
|             txDefaults, |             txDefaults, | ||||||
|             artifacts, |             artifacts, | ||||||
|         ); |         ); | ||||||
|         this._proxyIdIfExists = await this._proxyContract.getProxyId.callAsync(); |         this._proxyIdIfExists = await this._proxyContract.getProxyId().callAsync(); | ||||||
|         return this._proxyContract; |         return this._proxyContract; | ||||||
|     } |     } | ||||||
|     public getProxyId(): string { |     public getProxyId(): string { | ||||||
| @@ -68,43 +69,39 @@ export class ERC20Wrapper { | |||||||
|         this._validateProxyContractExistsOrThrow(); |         this._validateProxyContractExistsOrThrow(); | ||||||
|         for (const dummyTokenContract of this._dummyTokenContracts) { |         for (const dummyTokenContract of this._dummyTokenContracts) { | ||||||
|             for (const tokenOwnerAddress of this._tokenOwnerAddresses) { |             for (const tokenOwnerAddress of this._tokenOwnerAddresses) { | ||||||
|                 await dummyTokenContract.setBalance.awaitTransactionSuccessAsync( |                 await dummyTokenContract | ||||||
|                     tokenOwnerAddress, |                     .setBalance(tokenOwnerAddress, constants.INITIAL_ERC20_BALANCE) | ||||||
|                     constants.INITIAL_ERC20_BALANCE, |                     .awaitTransactionSuccessAsync({ from: this._contractOwnerAddress }); | ||||||
|                     { from: this._contractOwnerAddress }, |                 await dummyTokenContract | ||||||
|                 ); |                     .approve((this._proxyContract as ERC20ProxyContract).address, constants.INITIAL_ERC20_ALLOWANCE) | ||||||
|                 await dummyTokenContract.approve.awaitTransactionSuccessAsync( |                     .awaitTransactionSuccessAsync({ from: tokenOwnerAddress }); | ||||||
|                     (this._proxyContract as ERC20ProxyContract).address, |  | ||||||
|                     constants.INITIAL_ERC20_ALLOWANCE, |  | ||||||
|                     { from: tokenOwnerAddress }, |  | ||||||
|                 ); |  | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     public async getBalanceAsync(userAddress: string, assetData: string): Promise<BigNumber> { |     public async getBalanceAsync(userAddress: string, assetData: string): Promise<BigNumber> { | ||||||
|         const tokenContract = await this._getTokenContractFromAssetDataAsync(assetData); |         const tokenContract = await this._getTokenContractFromAssetDataAsync(assetData); | ||||||
|         const balance = new BigNumber(await tokenContract.balanceOf.callAsync(userAddress)); |         const balance = new BigNumber(await tokenContract.balanceOf(userAddress).callAsync()); | ||||||
|         return balance; |         return balance; | ||||||
|     } |     } | ||||||
|     public async setBalanceAsync(userAddress: string, assetData: string, amount: BigNumber): Promise<void> { |     public async setBalanceAsync(userAddress: string, assetData: string, amount: BigNumber): Promise<void> { | ||||||
|         const tokenContract = await this._getTokenContractFromAssetDataAsync(assetData); |         const tokenContract = await this._getTokenContractFromAssetDataAsync(assetData); | ||||||
|         await tokenContract.setBalance.awaitTransactionSuccessAsync( |         await tokenContract | ||||||
|             userAddress, |             .setBalance(userAddress, amount) | ||||||
|             amount, |             .awaitTransactionSuccessAsync( | ||||||
|             { from: this._contractOwnerAddress }, |                 { from: this._contractOwnerAddress }, | ||||||
|             { pollingIntervalMs: constants.AWAIT_TRANSACTION_MINED_MS }, |                 { pollingIntervalMs: constants.AWAIT_TRANSACTION_MINED_MS }, | ||||||
|         ); |             ); | ||||||
|     } |     } | ||||||
|     public async getProxyAllowanceAsync(userAddress: string, assetData: string): Promise<BigNumber> { |     public async getProxyAllowanceAsync(userAddress: string, assetData: string): Promise<BigNumber> { | ||||||
|         const tokenContract = await this._getTokenContractFromAssetDataAsync(assetData); |         const tokenContract = await this._getTokenContractFromAssetDataAsync(assetData); | ||||||
|         const proxyAddress = (this._proxyContract as ERC20ProxyContract).address; |         const proxyAddress = (this._proxyContract as ERC20ProxyContract).address; | ||||||
|         const allowance = new BigNumber(await tokenContract.allowance.callAsync(userAddress, proxyAddress)); |         const allowance = new BigNumber(await tokenContract.allowance(userAddress, proxyAddress).callAsync()); | ||||||
|         return allowance; |         return allowance; | ||||||
|     } |     } | ||||||
|     public async setAllowanceAsync(userAddress: string, assetData: string, amount: BigNumber): Promise<void> { |     public async setAllowanceAsync(userAddress: string, assetData: string, amount: BigNumber): Promise<void> { | ||||||
|         const tokenContract = await this._getTokenContractFromAssetDataAsync(assetData); |         const tokenContract = await this._getTokenContractFromAssetDataAsync(assetData); | ||||||
|         const proxyAddress = (this._proxyContract as ERC20ProxyContract).address; |         const proxyAddress = (this._proxyContract as ERC20ProxyContract).address; | ||||||
|         await tokenContract.approve.awaitTransactionSuccessAsync(proxyAddress, amount, { from: userAddress }); |         await tokenContract.approve(proxyAddress, amount).awaitTransactionSuccessAsync({ from: userAddress }); | ||||||
|     } |     } | ||||||
|     public async getBalancesAsync(): Promise<ERC20BalancesByOwner> { |     public async getBalancesAsync(): Promise<ERC20BalancesByOwner> { | ||||||
|         this._validateDummyTokenContractsExistOrThrow(); |         this._validateDummyTokenContractsExistOrThrow(); | ||||||
| @@ -113,7 +110,7 @@ export class ERC20Wrapper { | |||||||
|         const balanceInfo: Array<{ tokenOwnerAddress: string; tokenAddress: string }> = []; |         const balanceInfo: Array<{ tokenOwnerAddress: string; tokenAddress: string }> = []; | ||||||
|         for (const dummyTokenContract of this._dummyTokenContracts) { |         for (const dummyTokenContract of this._dummyTokenContracts) { | ||||||
|             for (const tokenOwnerAddress of this._tokenOwnerAddresses) { |             for (const tokenOwnerAddress of this._tokenOwnerAddresses) { | ||||||
|                 balances.push(await dummyTokenContract.balanceOf.callAsync(tokenOwnerAddress)); |                 balances.push(await dummyTokenContract.balanceOf(tokenOwnerAddress).callAsync()); | ||||||
|                 balanceInfo.push({ |                 balanceInfo.push({ | ||||||
|                     tokenOwnerAddress, |                     tokenOwnerAddress, | ||||||
|                     tokenAddress: dummyTokenContract.address, |                     tokenAddress: dummyTokenContract.address, | ||||||
| @@ -147,7 +144,7 @@ export class ERC20Wrapper { | |||||||
|         return tokenAddresses; |         return tokenAddresses; | ||||||
|     } |     } | ||||||
|     private async _getTokenContractFromAssetDataAsync(assetData: string): Promise<DummyERC20TokenContract> { |     private async _getTokenContractFromAssetDataAsync(assetData: string): Promise<DummyERC20TokenContract> { | ||||||
|         const [proxyId, tokenAddress] = await this._devUtils.decodeERC20AssetData.callAsync(assetData); // tslint:disable-line:no-unused-variable
 |         const tokenAddress = this._assetDataInterface.getABIDecodedTransactionData<string>('ERC20Token', assetData); // tslint:disable-line:no-unused-variable
 | ||||||
|         const tokenContractIfExists = _.find(this._dummyTokenContracts, c => c.address === tokenAddress); |         const tokenContractIfExists = _.find(this._dummyTokenContracts, c => c.address === tokenAddress); | ||||||
|         if (tokenContractIfExists === undefined) { |         if (tokenContractIfExists === undefined) { | ||||||
|             throw new Error(`Token: ${tokenAddress} was not deployed through ERC20Wrapper`); |             throw new Error(`Token: ${tokenAddress} was not deployed through ERC20Wrapper`); | ||||||
| @@ -5,7 +5,9 @@ import { BigNumber } from '@0x/utils'; | |||||||
| import { ZeroExProvider } from 'ethereum-types'; | import { ZeroExProvider } from 'ethereum-types'; | ||||||
| import * as _ from 'lodash'; | import * as _ from 'lodash'; | ||||||
| 
 | 
 | ||||||
| import { artifacts, ERC721ProxyContract } from '../../src'; | import { artifacts } from './artifacts'; | ||||||
|  | 
 | ||||||
|  | import { ERC721ProxyContract } from './wrappers'; | ||||||
| 
 | 
 | ||||||
| export class ERC721Wrapper { | export class ERC721Wrapper { | ||||||
|     private readonly _tokenOwnerAddresses: string[]; |     private readonly _tokenOwnerAddresses: string[]; | ||||||
| @@ -44,7 +46,7 @@ export class ERC721Wrapper { | |||||||
|             txDefaults, |             txDefaults, | ||||||
|             artifacts, |             artifacts, | ||||||
|         ); |         ); | ||||||
|         this._proxyIdIfExists = await this._proxyContract.getProxyId.callAsync(); |         this._proxyIdIfExists = await this._proxyContract.getProxyId().callAsync(); | ||||||
|         return this._proxyContract; |         return this._proxyContract; | ||||||
|     } |     } | ||||||
|     public getProxyId(): string { |     public getProxyId(): string { | ||||||
| @@ -78,7 +80,7 @@ export class ERC721Wrapper { | |||||||
|     } |     } | ||||||
|     public async doesTokenExistAsync(tokenAddress: string, tokenId: BigNumber): Promise<boolean> { |     public async doesTokenExistAsync(tokenAddress: string, tokenId: BigNumber): Promise<boolean> { | ||||||
|         const tokenContract = this._getTokenContractFromAssetData(tokenAddress); |         const tokenContract = this._getTokenContractFromAssetData(tokenAddress); | ||||||
|         const owner = await tokenContract.ownerOf.callAsync(tokenId); |         const owner = await tokenContract.ownerOf(tokenId).callAsync(); | ||||||
|         const doesExist = owner !== constants.NULL_ADDRESS; |         const doesExist = owner !== constants.NULL_ADDRESS; | ||||||
|         return doesExist; |         return doesExist; | ||||||
|     } |     } | ||||||
| @@ -93,14 +95,14 @@ export class ERC721Wrapper { | |||||||
|     ): Promise<void> { |     ): Promise<void> { | ||||||
|         const tokenContract = this._getTokenContractFromAssetData(tokenAddress); |         const tokenContract = this._getTokenContractFromAssetData(tokenAddress); | ||||||
|         const proxyAddress = (this._proxyContract as ERC721ProxyContract).address; |         const proxyAddress = (this._proxyContract as ERC721ProxyContract).address; | ||||||
|         await tokenContract.setApprovalForAll.awaitTransactionSuccessAsync(proxyAddress, isApproved, { |         await tokenContract.setApprovalForAll(proxyAddress, isApproved).awaitTransactionSuccessAsync({ | ||||||
|             from: ownerAddress, |             from: ownerAddress, | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
|     public async approveAsync(to: string, tokenAddress: string, tokenId: BigNumber): Promise<void> { |     public async approveAsync(to: string, tokenAddress: string, tokenId: BigNumber): Promise<void> { | ||||||
|         const tokenContract = this._getTokenContractFromAssetData(tokenAddress); |         const tokenContract = this._getTokenContractFromAssetData(tokenAddress); | ||||||
|         const tokenOwner = await this.ownerOfAsync(tokenAddress, tokenId); |         const tokenOwner = await this.ownerOfAsync(tokenAddress, tokenId); | ||||||
|         await tokenContract.approve.awaitTransactionSuccessAsync(to, tokenId, { from: tokenOwner }); |         await tokenContract.approve(to, tokenId).awaitTransactionSuccessAsync({ from: tokenOwner }); | ||||||
|     } |     } | ||||||
|     public async transferFromAsync( |     public async transferFromAsync( | ||||||
|         tokenAddress: string, |         tokenAddress: string, | ||||||
| @@ -109,28 +111,28 @@ export class ERC721Wrapper { | |||||||
|         userAddress: string, |         userAddress: string, | ||||||
|     ): Promise<void> { |     ): Promise<void> { | ||||||
|         const tokenContract = this._getTokenContractFromAssetData(tokenAddress); |         const tokenContract = this._getTokenContractFromAssetData(tokenAddress); | ||||||
|         await tokenContract.transferFrom.awaitTransactionSuccessAsync(currentOwner, userAddress, tokenId, { |         await tokenContract.transferFrom(currentOwner, userAddress, tokenId).awaitTransactionSuccessAsync({ | ||||||
|             from: currentOwner, |             from: currentOwner, | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
|     public async mintAsync(tokenAddress: string, tokenId: BigNumber, userAddress: string): Promise<void> { |     public async mintAsync(tokenAddress: string, tokenId: BigNumber, userAddress: string): Promise<void> { | ||||||
|         const tokenContract = this._getTokenContractFromAssetData(tokenAddress); |         const tokenContract = this._getTokenContractFromAssetData(tokenAddress); | ||||||
|         await tokenContract.mint.awaitTransactionSuccessAsync(userAddress, tokenId, { |         await tokenContract.mint(userAddress, tokenId).awaitTransactionSuccessAsync({ | ||||||
|             from: this._contractOwnerAddress, |             from: this._contractOwnerAddress, | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
|     public async burnAsync(tokenAddress: string, tokenId: BigNumber, owner: string): Promise<void> { |     public async burnAsync(tokenAddress: string, tokenId: BigNumber, owner: string): Promise<void> { | ||||||
|         const tokenContract = this._getTokenContractFromAssetData(tokenAddress); |         const tokenContract = this._getTokenContractFromAssetData(tokenAddress); | ||||||
|         await tokenContract.burn.awaitTransactionSuccessAsync(owner, tokenId, { from: this._contractOwnerAddress }); |         await tokenContract.burn(owner, tokenId).awaitTransactionSuccessAsync({ from: this._contractOwnerAddress }); | ||||||
|     } |     } | ||||||
|     public async ownerOfAsync(tokenAddress: string, tokenId: BigNumber): Promise<string> { |     public async ownerOfAsync(tokenAddress: string, tokenId: BigNumber): Promise<string> { | ||||||
|         const tokenContract = this._getTokenContractFromAssetData(tokenAddress); |         const tokenContract = this._getTokenContractFromAssetData(tokenAddress); | ||||||
|         const owner = await tokenContract.ownerOf.callAsync(tokenId); |         const owner = await tokenContract.ownerOf(tokenId).callAsync(); | ||||||
|         return owner; |         return owner; | ||||||
|     } |     } | ||||||
|     public async isOwnerAsync(userAddress: string, tokenAddress: string, tokenId: BigNumber): Promise<boolean> { |     public async isOwnerAsync(userAddress: string, tokenAddress: string, tokenId: BigNumber): Promise<boolean> { | ||||||
|         const tokenContract = this._getTokenContractFromAssetData(tokenAddress); |         const tokenContract = this._getTokenContractFromAssetData(tokenAddress); | ||||||
|         const tokenOwner = await tokenContract.ownerOf.callAsync(tokenId); |         const tokenOwner = await tokenContract.ownerOf(tokenId).callAsync(); | ||||||
|         const isOwner = tokenOwner === userAddress; |         const isOwner = tokenOwner === userAddress; | ||||||
|         return isOwner; |         return isOwner; | ||||||
|     } |     } | ||||||
| @@ -138,13 +140,13 @@ export class ERC721Wrapper { | |||||||
|         this._validateProxyContractExistsOrThrow(); |         this._validateProxyContractExistsOrThrow(); | ||||||
|         const tokenContract = this._getTokenContractFromAssetData(tokenAddress); |         const tokenContract = this._getTokenContractFromAssetData(tokenAddress); | ||||||
|         const operator = (this._proxyContract as ERC721ProxyContract).address; |         const operator = (this._proxyContract as ERC721ProxyContract).address; | ||||||
|         const didApproveAll = await tokenContract.isApprovedForAll.callAsync(userAddress, operator); |         const didApproveAll = await tokenContract.isApprovedForAll(userAddress, operator).callAsync(); | ||||||
|         return didApproveAll; |         return didApproveAll; | ||||||
|     } |     } | ||||||
|     public async isProxyApprovedAsync(tokenAddress: string, tokenId: BigNumber): Promise<boolean> { |     public async isProxyApprovedAsync(tokenAddress: string, tokenId: BigNumber): Promise<boolean> { | ||||||
|         this._validateProxyContractExistsOrThrow(); |         this._validateProxyContractExistsOrThrow(); | ||||||
|         const tokenContract = this._getTokenContractFromAssetData(tokenAddress); |         const tokenContract = this._getTokenContractFromAssetData(tokenAddress); | ||||||
|         const approvedAddress = await tokenContract.getApproved.callAsync(tokenId); |         const approvedAddress = await tokenContract.getApproved(tokenId).callAsync(); | ||||||
|         const proxyAddress = (this._proxyContract as ERC721ProxyContract).address; |         const proxyAddress = (this._proxyContract as ERC721ProxyContract).address; | ||||||
|         const isProxyAnApprovedOperator = approvedAddress === proxyAddress; |         const isProxyAnApprovedOperator = approvedAddress === proxyAddress; | ||||||
|         return isProxyAnApprovedOperator; |         return isProxyAnApprovedOperator; | ||||||
| @@ -161,7 +163,7 @@ export class ERC721Wrapper { | |||||||
|                     dummyTokenContract.address |                     dummyTokenContract.address | ||||||
|                 ]; |                 ]; | ||||||
|                 for (const tokenId of initialTokenOwnerIds) { |                 for (const tokenId of initialTokenOwnerIds) { | ||||||
|                     tokenOwnerAddresses.push(await dummyTokenContract.ownerOf.callAsync(tokenId)); |                     tokenOwnerAddresses.push(await dummyTokenContract.ownerOf(tokenId).callAsync()); | ||||||
|                     tokenInfo.push({ |                     tokenInfo.push({ | ||||||
|                         tokenId, |                         tokenId, | ||||||
|                         tokenAddress: dummyTokenContract.address, |                         tokenAddress: dummyTokenContract.address, | ||||||
| @@ -1,3 +1,93 @@ | |||||||
| export * from './artifacts'; | export { artifacts } from './artifacts'; | ||||||
| export * from './wrappers'; | export { | ||||||
| export * from '../test/utils'; |     BalancerBridgeContract, | ||||||
|  |     ChaiBridgeContract, | ||||||
|  |     ERC1155ProxyContract, | ||||||
|  |     ERC20BridgeProxyContract, | ||||||
|  |     ERC20ProxyContract, | ||||||
|  |     ERC721ProxyContract, | ||||||
|  |     Eth2DaiBridgeContract, | ||||||
|  |     DydxBridgeContract, | ||||||
|  |     IAssetDataContract, | ||||||
|  |     IAssetProxyContract, | ||||||
|  |     IChaiContract, | ||||||
|  |     IDydxContract, | ||||||
|  |     KyberBridgeContract, | ||||||
|  |     MultiAssetProxyContract, | ||||||
|  |     StaticCallProxyContract, | ||||||
|  |     TestDydxBridgeContract, | ||||||
|  |     TestStaticCallTargetContract, | ||||||
|  |     UniswapBridgeContract, | ||||||
|  |     DexForwarderBridgeContract, | ||||||
|  | } from './wrappers'; | ||||||
|  |  | ||||||
|  | export { ERC20Wrapper } from './erc20_wrapper'; | ||||||
|  | export { ERC721Wrapper } from './erc721_wrapper'; | ||||||
|  | export { ERC1155ProxyWrapper } from './erc1155_proxy_wrapper'; | ||||||
|  | export { ERC1155MintableContract, Erc1155Wrapper } from '@0x/contracts-erc1155'; | ||||||
|  | export { DummyERC20TokenContract } from '@0x/contracts-erc20'; | ||||||
|  | export { DummyERC721TokenContract } from '@0x/contracts-erc721'; | ||||||
|  | export { AssetProxyId } from '@0x/types'; | ||||||
|  | export { | ||||||
|  |     ERC1155HoldingsByOwner, | ||||||
|  |     ERC20BalancesByOwner, | ||||||
|  |     ERC721TokenIdsByOwner, | ||||||
|  |     ERC1155FungibleHoldingsByOwner, | ||||||
|  |     ERC1155NonFungibleHoldingsByOwner, | ||||||
|  | } from '@0x/contracts-test-utils'; | ||||||
|  | export { | ||||||
|  |     TransactionReceiptWithDecodedLogs, | ||||||
|  |     Provider, | ||||||
|  |     ZeroExProvider, | ||||||
|  |     JSONRPCRequestPayload, | ||||||
|  |     JSONRPCErrorCallback, | ||||||
|  |     TransactionReceiptStatus, | ||||||
|  |     JSONRPCResponsePayload, | ||||||
|  |     JSONRPCResponseError, | ||||||
|  |     ContractArtifact, | ||||||
|  |     ContractChains, | ||||||
|  |     CompilerOpts, | ||||||
|  |     StandardContractOutput, | ||||||
|  |     CompilerSettings, | ||||||
|  |     ContractChainData, | ||||||
|  |     ContractAbi, | ||||||
|  |     DevdocOutput, | ||||||
|  |     EvmOutput, | ||||||
|  |     CompilerSettingsMetadata, | ||||||
|  |     OptimizerSettings, | ||||||
|  |     OutputField, | ||||||
|  |     ParamDescription, | ||||||
|  |     EvmBytecodeOutput, | ||||||
|  |     EvmBytecodeOutputLinkReferences, | ||||||
|  |     AbiDefinition, | ||||||
|  |     FunctionAbi, | ||||||
|  |     EventAbi, | ||||||
|  |     RevertErrorAbi, | ||||||
|  |     EventParameter, | ||||||
|  |     DataItem, | ||||||
|  |     MethodAbi, | ||||||
|  |     ConstructorAbi, | ||||||
|  |     FallbackAbi, | ||||||
|  |     ConstructorStateMutability, | ||||||
|  |     TupleDataItem, | ||||||
|  |     StateMutability, | ||||||
|  | } from 'ethereum-types'; | ||||||
|  |  | ||||||
|  | export { | ||||||
|  |     decodeERC1155AssetData, | ||||||
|  |     decodeERC20AssetData, | ||||||
|  |     decodeERC20BridgeAssetData, | ||||||
|  |     decodeERC721AssetData, | ||||||
|  |     decodeMultiAssetData, | ||||||
|  |     decodeStaticCallAssetData, | ||||||
|  |     encodeERC1155AssetData, | ||||||
|  |     encodeERC20AssetData, | ||||||
|  |     encodeERC20BridgeAssetData, | ||||||
|  |     encodeERC721AssetData, | ||||||
|  |     encodeMultiAssetData, | ||||||
|  |     encodeStaticCallAssetData, | ||||||
|  |     getAssetDataProxyId, | ||||||
|  | } from './asset_data'; | ||||||
|  |  | ||||||
|  | export * from './dydx_bridge_encoder'; | ||||||
|  | export * from './dex_forwarder_bridge'; | ||||||
|   | |||||||
| @@ -3,6 +3,14 @@ | |||||||
|  * Warning: This file is auto-generated by contracts-gen. Don't edit manually. |  * Warning: This file is auto-generated by contracts-gen. Don't edit manually. | ||||||
|  * ----------------------------------------------------------------------------- |  * ----------------------------------------------------------------------------- | ||||||
|  */ |  */ | ||||||
|  | export * from '../generated-wrappers/balancer_bridge'; | ||||||
|  | export * from '../generated-wrappers/bancor_bridge'; | ||||||
|  | export * from '../generated-wrappers/chai_bridge'; | ||||||
|  | export * from '../generated-wrappers/cream_bridge'; | ||||||
|  | export * from '../generated-wrappers/curve_bridge'; | ||||||
|  | export * from '../generated-wrappers/d_o_d_o_bridge'; | ||||||
|  | export * from '../generated-wrappers/dex_forwarder_bridge'; | ||||||
|  | export * from '../generated-wrappers/dydx_bridge'; | ||||||
| export * from '../generated-wrappers/erc1155_proxy'; | export * from '../generated-wrappers/erc1155_proxy'; | ||||||
| export * from '../generated-wrappers/erc20_bridge_proxy'; | export * from '../generated-wrappers/erc20_bridge_proxy'; | ||||||
| export * from '../generated-wrappers/erc20_proxy'; | export * from '../generated-wrappers/erc20_proxy'; | ||||||
| @@ -12,17 +20,44 @@ export * from '../generated-wrappers/i_asset_data'; | |||||||
| export * from '../generated-wrappers/i_asset_proxy'; | export * from '../generated-wrappers/i_asset_proxy'; | ||||||
| export * from '../generated-wrappers/i_asset_proxy_dispatcher'; | export * from '../generated-wrappers/i_asset_proxy_dispatcher'; | ||||||
| export * from '../generated-wrappers/i_authorizable'; | export * from '../generated-wrappers/i_authorizable'; | ||||||
|  | export * from '../generated-wrappers/i_balancer_pool'; | ||||||
|  | export * from '../generated-wrappers/i_bancor_network'; | ||||||
|  | export * from '../generated-wrappers/i_chai'; | ||||||
|  | export * from '../generated-wrappers/i_curve'; | ||||||
|  | export * from '../generated-wrappers/i_dydx'; | ||||||
|  | export * from '../generated-wrappers/i_dydx_bridge'; | ||||||
| export * from '../generated-wrappers/i_erc20_bridge'; | export * from '../generated-wrappers/i_erc20_bridge'; | ||||||
| export * from '../generated-wrappers/i_eth2_dai'; | 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'; | ||||||
| export * from '../generated-wrappers/i_uniswap_exchange_factory'; | 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_asset_proxy_dispatcher'; | ||||||
| export * from '../generated-wrappers/mixin_authorizable'; | export * from '../generated-wrappers/mixin_authorizable'; | ||||||
|  | export * from '../generated-wrappers/mixin_gas_token'; | ||||||
|  | export * from '../generated-wrappers/mooniswap_bridge'; | ||||||
| export * from '../generated-wrappers/multi_asset_proxy'; | export * from '../generated-wrappers/multi_asset_proxy'; | ||||||
| export * from '../generated-wrappers/ownable'; | export * from '../generated-wrappers/ownable'; | ||||||
|  | export * from '../generated-wrappers/shell_bridge'; | ||||||
|  | export * from '../generated-wrappers/snow_swap_bridge'; | ||||||
| export * from '../generated-wrappers/static_call_proxy'; | export * from '../generated-wrappers/static_call_proxy'; | ||||||
|  | export * from '../generated-wrappers/sushi_swap_bridge'; | ||||||
|  | export * from '../generated-wrappers/swerve_bridge'; | ||||||
|  | export * from '../generated-wrappers/test_bancor_bridge'; | ||||||
|  | export * from '../generated-wrappers/test_chai_bridge'; | ||||||
|  | export * from '../generated-wrappers/test_dex_forwarder_bridge'; | ||||||
|  | export * from '../generated-wrappers/test_dydx_bridge'; | ||||||
| export * from '../generated-wrappers/test_erc20_bridge'; | export * from '../generated-wrappers/test_erc20_bridge'; | ||||||
| export * from '../generated-wrappers/test_eth2_dai_bridge'; | export * from '../generated-wrappers/test_eth2_dai_bridge'; | ||||||
|  | export * from '../generated-wrappers/test_kyber_bridge'; | ||||||
| export * from '../generated-wrappers/test_static_call_target'; | export * from '../generated-wrappers/test_static_call_target'; | ||||||
| export * from '../generated-wrappers/test_uniswap_bridge'; | export * from '../generated-wrappers/test_uniswap_bridge'; | ||||||
|  | export * from '../generated-wrappers/test_uniswap_v2_bridge'; | ||||||
| export * from '../generated-wrappers/uniswap_bridge'; | export * from '../generated-wrappers/uniswap_bridge'; | ||||||
|  | export * from '../generated-wrappers/uniswap_v2_bridge'; | ||||||
|   | |||||||
							
								
								
									
										125
									
								
								contracts/asset-proxy/test/artifacts.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								contracts/asset-proxy/test/artifacts.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,125 @@ | |||||||
|  | /* | ||||||
|  |  * ----------------------------------------------------------------------------- | ||||||
|  |  * Warning: This file is auto-generated by contracts-gen. Don't edit manually. | ||||||
|  |  * ----------------------------------------------------------------------------- | ||||||
|  |  */ | ||||||
|  | import { ContractArtifact } from 'ethereum-types'; | ||||||
|  |  | ||||||
|  | import * as BalancerBridge from '../test/generated-artifacts/BalancerBridge.json'; | ||||||
|  | import * as BancorBridge from '../test/generated-artifacts/BancorBridge.json'; | ||||||
|  | import * as ChaiBridge from '../test/generated-artifacts/ChaiBridge.json'; | ||||||
|  | import * as CreamBridge from '../test/generated-artifacts/CreamBridge.json'; | ||||||
|  | import * as CurveBridge from '../test/generated-artifacts/CurveBridge.json'; | ||||||
|  | import * as DexForwarderBridge from '../test/generated-artifacts/DexForwarderBridge.json'; | ||||||
|  | import * as DODOBridge from '../test/generated-artifacts/DODOBridge.json'; | ||||||
|  | import * as DydxBridge from '../test/generated-artifacts/DydxBridge.json'; | ||||||
|  | import * as ERC1155Proxy from '../test/generated-artifacts/ERC1155Proxy.json'; | ||||||
|  | import * as ERC20BridgeProxy from '../test/generated-artifacts/ERC20BridgeProxy.json'; | ||||||
|  | import * as ERC20Proxy from '../test/generated-artifacts/ERC20Proxy.json'; | ||||||
|  | import * as ERC721Proxy from '../test/generated-artifacts/ERC721Proxy.json'; | ||||||
|  | import * as Eth2DaiBridge from '../test/generated-artifacts/Eth2DaiBridge.json'; | ||||||
|  | import * as IAssetData from '../test/generated-artifacts/IAssetData.json'; | ||||||
|  | import * as IAssetProxy from '../test/generated-artifacts/IAssetProxy.json'; | ||||||
|  | import * as IAssetProxyDispatcher from '../test/generated-artifacts/IAssetProxyDispatcher.json'; | ||||||
|  | import * as IAuthorizable from '../test/generated-artifacts/IAuthorizable.json'; | ||||||
|  | import * as IBalancerPool from '../test/generated-artifacts/IBalancerPool.json'; | ||||||
|  | import * as IBancorNetwork from '../test/generated-artifacts/IBancorNetwork.json'; | ||||||
|  | import * as IChai from '../test/generated-artifacts/IChai.json'; | ||||||
|  | import * as ICurve from '../test/generated-artifacts/ICurve.json'; | ||||||
|  | import * as IDydx from '../test/generated-artifacts/IDydx.json'; | ||||||
|  | import * as IDydxBridge from '../test/generated-artifacts/IDydxBridge.json'; | ||||||
|  | import * as IERC20Bridge from '../test/generated-artifacts/IERC20Bridge.json'; | ||||||
|  | import * as IEth2Dai from '../test/generated-artifacts/IEth2Dai.json'; | ||||||
|  | import * as IGasToken from '../test/generated-artifacts/IGasToken.json'; | ||||||
|  | import * as IKyberNetworkProxy from '../test/generated-artifacts/IKyberNetworkProxy.json'; | ||||||
|  | import * as IMooniswap from '../test/generated-artifacts/IMooniswap.json'; | ||||||
|  | import * as IMStable from '../test/generated-artifacts/IMStable.json'; | ||||||
|  | import * as IShell from '../test/generated-artifacts/IShell.json'; | ||||||
|  | import * as IUniswapExchange from '../test/generated-artifacts/IUniswapExchange.json'; | ||||||
|  | import * as IUniswapExchangeFactory from '../test/generated-artifacts/IUniswapExchangeFactory.json'; | ||||||
|  | import * as IUniswapV2Router01 from '../test/generated-artifacts/IUniswapV2Router01.json'; | ||||||
|  | import * as KyberBridge from '../test/generated-artifacts/KyberBridge.json'; | ||||||
|  | import * as MixinAssetProxyDispatcher from '../test/generated-artifacts/MixinAssetProxyDispatcher.json'; | ||||||
|  | import * as MixinAuthorizable from '../test/generated-artifacts/MixinAuthorizable.json'; | ||||||
|  | import * as MixinGasToken from '../test/generated-artifacts/MixinGasToken.json'; | ||||||
|  | import * as MooniswapBridge from '../test/generated-artifacts/MooniswapBridge.json'; | ||||||
|  | import * as MStableBridge from '../test/generated-artifacts/MStableBridge.json'; | ||||||
|  | import * as MultiAssetProxy from '../test/generated-artifacts/MultiAssetProxy.json'; | ||||||
|  | import * as Ownable from '../test/generated-artifacts/Ownable.json'; | ||||||
|  | import * as ShellBridge from '../test/generated-artifacts/ShellBridge.json'; | ||||||
|  | import * as SnowSwapBridge from '../test/generated-artifacts/SnowSwapBridge.json'; | ||||||
|  | import * as StaticCallProxy from '../test/generated-artifacts/StaticCallProxy.json'; | ||||||
|  | import * as SushiSwapBridge from '../test/generated-artifacts/SushiSwapBridge.json'; | ||||||
|  | import * as SwerveBridge from '../test/generated-artifacts/SwerveBridge.json'; | ||||||
|  | import * as TestBancorBridge from '../test/generated-artifacts/TestBancorBridge.json'; | ||||||
|  | import * as TestChaiBridge from '../test/generated-artifacts/TestChaiBridge.json'; | ||||||
|  | import * as TestDexForwarderBridge from '../test/generated-artifacts/TestDexForwarderBridge.json'; | ||||||
|  | import * as TestDydxBridge from '../test/generated-artifacts/TestDydxBridge.json'; | ||||||
|  | import * as TestERC20Bridge from '../test/generated-artifacts/TestERC20Bridge.json'; | ||||||
|  | import * as TestEth2DaiBridge from '../test/generated-artifacts/TestEth2DaiBridge.json'; | ||||||
|  | import * as TestKyberBridge from '../test/generated-artifacts/TestKyberBridge.json'; | ||||||
|  | import * as TestStaticCallTarget from '../test/generated-artifacts/TestStaticCallTarget.json'; | ||||||
|  | import * as TestUniswapBridge from '../test/generated-artifacts/TestUniswapBridge.json'; | ||||||
|  | import * as TestUniswapV2Bridge from '../test/generated-artifacts/TestUniswapV2Bridge.json'; | ||||||
|  | import * as UniswapBridge from '../test/generated-artifacts/UniswapBridge.json'; | ||||||
|  | import * as UniswapV2Bridge from '../test/generated-artifacts/UniswapV2Bridge.json'; | ||||||
|  | export const artifacts = { | ||||||
|  |     MixinAssetProxyDispatcher: MixinAssetProxyDispatcher as ContractArtifact, | ||||||
|  |     MixinAuthorizable: MixinAuthorizable as ContractArtifact, | ||||||
|  |     Ownable: Ownable as ContractArtifact, | ||||||
|  |     ERC1155Proxy: ERC1155Proxy as ContractArtifact, | ||||||
|  |     ERC20BridgeProxy: ERC20BridgeProxy as ContractArtifact, | ||||||
|  |     ERC20Proxy: ERC20Proxy as ContractArtifact, | ||||||
|  |     ERC721Proxy: ERC721Proxy as ContractArtifact, | ||||||
|  |     MultiAssetProxy: MultiAssetProxy as ContractArtifact, | ||||||
|  |     StaticCallProxy: StaticCallProxy as ContractArtifact, | ||||||
|  |     BalancerBridge: BalancerBridge as ContractArtifact, | ||||||
|  |     BancorBridge: BancorBridge as ContractArtifact, | ||||||
|  |     ChaiBridge: ChaiBridge as ContractArtifact, | ||||||
|  |     CreamBridge: CreamBridge as ContractArtifact, | ||||||
|  |     CurveBridge: CurveBridge as ContractArtifact, | ||||||
|  |     DODOBridge: DODOBridge as ContractArtifact, | ||||||
|  |     DexForwarderBridge: DexForwarderBridge as ContractArtifact, | ||||||
|  |     DydxBridge: DydxBridge as ContractArtifact, | ||||||
|  |     Eth2DaiBridge: Eth2DaiBridge as ContractArtifact, | ||||||
|  |     KyberBridge: KyberBridge as ContractArtifact, | ||||||
|  |     MStableBridge: MStableBridge as ContractArtifact, | ||||||
|  |     MixinGasToken: MixinGasToken as ContractArtifact, | ||||||
|  |     MooniswapBridge: MooniswapBridge as ContractArtifact, | ||||||
|  |     ShellBridge: ShellBridge as ContractArtifact, | ||||||
|  |     SnowSwapBridge: SnowSwapBridge as ContractArtifact, | ||||||
|  |     SushiSwapBridge: SushiSwapBridge as ContractArtifact, | ||||||
|  |     SwerveBridge: SwerveBridge as ContractArtifact, | ||||||
|  |     UniswapBridge: UniswapBridge as ContractArtifact, | ||||||
|  |     UniswapV2Bridge: UniswapV2Bridge as ContractArtifact, | ||||||
|  |     IAssetData: IAssetData as ContractArtifact, | ||||||
|  |     IAssetProxy: IAssetProxy as ContractArtifact, | ||||||
|  |     IAssetProxyDispatcher: IAssetProxyDispatcher as ContractArtifact, | ||||||
|  |     IAuthorizable: IAuthorizable as ContractArtifact, | ||||||
|  |     IBalancerPool: IBalancerPool as ContractArtifact, | ||||||
|  |     IBancorNetwork: IBancorNetwork as ContractArtifact, | ||||||
|  |     IChai: IChai as ContractArtifact, | ||||||
|  |     ICurve: ICurve as ContractArtifact, | ||||||
|  |     IDydx: IDydx as ContractArtifact, | ||||||
|  |     IDydxBridge: IDydxBridge as ContractArtifact, | ||||||
|  |     IERC20Bridge: IERC20Bridge as ContractArtifact, | ||||||
|  |     IEth2Dai: IEth2Dai as ContractArtifact, | ||||||
|  |     IGasToken: IGasToken as ContractArtifact, | ||||||
|  |     IKyberNetworkProxy: IKyberNetworkProxy as ContractArtifact, | ||||||
|  |     IMStable: IMStable as ContractArtifact, | ||||||
|  |     IMooniswap: IMooniswap as ContractArtifact, | ||||||
|  |     IShell: IShell as ContractArtifact, | ||||||
|  |     IUniswapExchange: IUniswapExchange as ContractArtifact, | ||||||
|  |     IUniswapExchangeFactory: IUniswapExchangeFactory as ContractArtifact, | ||||||
|  |     IUniswapV2Router01: IUniswapV2Router01 as ContractArtifact, | ||||||
|  |     TestBancorBridge: TestBancorBridge as ContractArtifact, | ||||||
|  |     TestChaiBridge: TestChaiBridge as ContractArtifact, | ||||||
|  |     TestDexForwarderBridge: TestDexForwarderBridge as ContractArtifact, | ||||||
|  |     TestDydxBridge: TestDydxBridge as ContractArtifact, | ||||||
|  |     TestERC20Bridge: TestERC20Bridge as ContractArtifact, | ||||||
|  |     TestEth2DaiBridge: TestEth2DaiBridge as ContractArtifact, | ||||||
|  |     TestKyberBridge: TestKyberBridge as ContractArtifact, | ||||||
|  |     TestStaticCallTarget: TestStaticCallTarget as ContractArtifact, | ||||||
|  |     TestUniswapBridge: TestUniswapBridge as ContractArtifact, | ||||||
|  |     TestUniswapV2Bridge: TestUniswapV2Bridge as ContractArtifact, | ||||||
|  | }; | ||||||
| @@ -1,33 +1,20 @@ | |||||||
| import { chaiSetup, expectTransactionFailedAsync, provider, txDefaults, web3Wrapper } from '@0x/contracts-test-utils'; | import { blockchainTests, expect, provider, txDefaults, web3Wrapper } from '@0x/contracts-test-utils'; | ||||||
| import { BlockchainLifecycle } from '@0x/dev-utils'; |  | ||||||
| import { RevertReason } from '@0x/types'; | import { RevertReason } from '@0x/types'; | ||||||
| import { BigNumber } from '@0x/utils'; | import { BigNumber } from '@0x/utils'; | ||||||
| import * as chai from 'chai'; |  | ||||||
| import * as _ from 'lodash'; |  | ||||||
|  |  | ||||||
| import { artifacts, MixinAuthorizableContract } from '../src'; | import { artifacts } from './artifacts'; | ||||||
|  |  | ||||||
| chaiSetup.configure(); | import { MixinAuthorizableContract } from './wrappers'; | ||||||
| const expect = chai.expect; |  | ||||||
| const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); |  | ||||||
|  |  | ||||||
| describe('Authorizable', () => { | blockchainTests.resets('Authorizable', () => { | ||||||
|     let owner: string; |     let owner: string; | ||||||
|     let notOwner: string; |     let notOwner: string; | ||||||
|     let address: string; |     let address: string; | ||||||
|     let authorizable: MixinAuthorizableContract; |     let authorizable: MixinAuthorizableContract; | ||||||
|  |  | ||||||
|     before(async () => { |  | ||||||
|         await blockchainLifecycle.startAsync(); |  | ||||||
|     }); |  | ||||||
|  |  | ||||||
|     after(async () => { |  | ||||||
|         await blockchainLifecycle.revertAsync(); |  | ||||||
|     }); |  | ||||||
|  |  | ||||||
|     before(async () => { |     before(async () => { | ||||||
|         const accounts = await web3Wrapper.getAvailableAddressesAsync(); |         const accounts = await web3Wrapper.getAvailableAddressesAsync(); | ||||||
|         [owner, address, notOwner] = _.slice(accounts, 0, 3); |         [owner, address, notOwner] = accounts.slice(0, 3); | ||||||
|         authorizable = await MixinAuthorizableContract.deployFrom0xArtifactAsync( |         authorizable = await MixinAuthorizableContract.deployFrom0xArtifactAsync( | ||||||
|             artifacts.MixinAuthorizable, |             artifacts.MixinAuthorizable, | ||||||
|             provider, |             provider, | ||||||
| @@ -36,131 +23,105 @@ describe('Authorizable', () => { | |||||||
|         ); |         ); | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|     beforeEach(async () => { |  | ||||||
|         await blockchainLifecycle.startAsync(); |  | ||||||
|     }); |  | ||||||
|  |  | ||||||
|     afterEach(async () => { |  | ||||||
|         await blockchainLifecycle.revertAsync(); |  | ||||||
|     }); |  | ||||||
|  |  | ||||||
|     describe('addAuthorizedAddress', () => { |     describe('addAuthorizedAddress', () => { | ||||||
|         it('should revert if not called by owner', async () => { |         it('should revert if not called by owner', async () => { | ||||||
|             await expectTransactionFailedAsync( |             const tx = authorizable.addAuthorizedAddress(notOwner).sendTransactionAsync({ from: notOwner }); | ||||||
|                 authorizable.addAuthorizedAddress.sendTransactionAsync(notOwner, { from: notOwner }), |             return expect(tx).to.revertWith(RevertReason.OnlyContractOwner); | ||||||
|                 RevertReason.OnlyContractOwner, |  | ||||||
|             ); |  | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
|         it('should allow owner to add an authorized address', async () => { |         it('should allow owner to add an authorized address', async () => { | ||||||
|             await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(address, { from: owner }); |             await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner }); | ||||||
|             const isAuthorized = await authorizable.authorized.callAsync(address); |             const isAuthorized = await authorizable.authorized(address).callAsync(); | ||||||
|             expect(isAuthorized).to.be.true(); |             expect(isAuthorized).to.be.true(); | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
|         it('should revert if owner attempts to authorize a duplicate address', async () => { |         it('should revert if owner attempts to authorize a duplicate address', async () => { | ||||||
|             await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(address, { from: owner }); |             await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner }); | ||||||
|             return expectTransactionFailedAsync( |             const tx = authorizable.addAuthorizedAddress(address).sendTransactionAsync({ from: owner }); | ||||||
|                 authorizable.addAuthorizedAddress.sendTransactionAsync(address, { from: owner }), |             return expect(tx).to.revertWith(RevertReason.TargetAlreadyAuthorized); | ||||||
|                 RevertReason.TargetAlreadyAuthorized, |  | ||||||
|             ); |  | ||||||
|         }); |         }); | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|     describe('removeAuthorizedAddress', () => { |     describe('removeAuthorizedAddress', () => { | ||||||
|         it('should revert if not called by owner', async () => { |         it('should revert if not called by owner', async () => { | ||||||
|             await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(address, { from: owner }); |             await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner }); | ||||||
|             await expectTransactionFailedAsync( |             const tx = authorizable.removeAuthorizedAddress(address).sendTransactionAsync({ from: notOwner }); | ||||||
|                 authorizable.removeAuthorizedAddress.sendTransactionAsync(address, { from: notOwner }), |             return expect(tx).to.revertWith(RevertReason.OnlyContractOwner); | ||||||
|                 RevertReason.OnlyContractOwner, |  | ||||||
|             ); |  | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
|         it('should allow owner to remove an authorized address', async () => { |         it('should allow owner to remove an authorized address', async () => { | ||||||
|             await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(address, { from: owner }); |             await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner }); | ||||||
|             await authorizable.removeAuthorizedAddress.awaitTransactionSuccessAsync(address, { from: owner }); |             await authorizable.removeAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner }); | ||||||
|             const isAuthorized = await authorizable.authorized.callAsync(address); |             const isAuthorized = await authorizable.authorized(address).callAsync(); | ||||||
|             expect(isAuthorized).to.be.false(); |             expect(isAuthorized).to.be.false(); | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
|         it('should revert if owner attempts to remove an address that is not authorized', async () => { |         it('should revert if owner attempts to remove an address that is not authorized', async () => { | ||||||
|             return expectTransactionFailedAsync( |             const tx = authorizable.removeAuthorizedAddress(address).sendTransactionAsync({ from: owner }); | ||||||
|                 authorizable.removeAuthorizedAddress.sendTransactionAsync(address, { |             return expect(tx).to.revertWith(RevertReason.TargetNotAuthorized); | ||||||
|                     from: owner, |  | ||||||
|                 }), |  | ||||||
|                 RevertReason.TargetNotAuthorized, |  | ||||||
|             ); |  | ||||||
|         }); |         }); | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|     describe('removeAuthorizedAddressAtIndex', () => { |     describe('removeAuthorizedAddressAtIndex', () => { | ||||||
|         it('should revert if not called by owner', async () => { |         it('should revert if not called by owner', async () => { | ||||||
|             await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(address, { from: owner }); |             await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner }); | ||||||
|             const index = new BigNumber(0); |             const index = new BigNumber(0); | ||||||
|             await expectTransactionFailedAsync( |             const tx = authorizable | ||||||
|                 authorizable.removeAuthorizedAddressAtIndex.sendTransactionAsync(address, index, { |                 .removeAuthorizedAddressAtIndex(address, index) | ||||||
|                     from: notOwner, |                 .sendTransactionAsync({ from: notOwner }); | ||||||
|                 }), |             return expect(tx).to.revertWith(RevertReason.OnlyContractOwner); | ||||||
|                 RevertReason.OnlyContractOwner, |  | ||||||
|             ); |  | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
|         it('should revert if index is >= authorities.length', async () => { |         it('should revert if index is >= authorities.length', async () => { | ||||||
|             await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(address, { from: owner }); |             await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner }); | ||||||
|             const index = new BigNumber(1); |             const index = new BigNumber(1); | ||||||
|             return expectTransactionFailedAsync( |             const tx = authorizable | ||||||
|                 authorizable.removeAuthorizedAddressAtIndex.sendTransactionAsync(address, index, { |                 .removeAuthorizedAddressAtIndex(address, index) | ||||||
|                     from: owner, |                 .sendTransactionAsync({ from: owner }); | ||||||
|                 }), |             return expect(tx).to.revertWith(RevertReason.IndexOutOfBounds); | ||||||
|                 RevertReason.IndexOutOfBounds, |  | ||||||
|             ); |  | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
|         it('should revert if owner attempts to remove an address that is not authorized', async () => { |         it('should revert if owner attempts to remove an address that is not authorized', async () => { | ||||||
|             const index = new BigNumber(0); |             const index = new BigNumber(0); | ||||||
|             return expectTransactionFailedAsync( |             const tx = authorizable | ||||||
|                 authorizable.removeAuthorizedAddressAtIndex.sendTransactionAsync(address, index, { |                 .removeAuthorizedAddressAtIndex(address, index) | ||||||
|                     from: owner, |                 .sendTransactionAsync({ from: owner }); | ||||||
|                 }), |             return expect(tx).to.revertWith(RevertReason.TargetNotAuthorized); | ||||||
|                 RevertReason.TargetNotAuthorized, |  | ||||||
|             ); |  | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
|         it('should revert if address at index does not match target', async () => { |         it('should revert if address at index does not match target', async () => { | ||||||
|             const address1 = address; |             const address1 = address; | ||||||
|             const address2 = notOwner; |             const address2 = notOwner; | ||||||
|             await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(address1, { from: owner }); |             await authorizable.addAuthorizedAddress(address1).awaitTransactionSuccessAsync({ from: owner }); | ||||||
|             await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(address2, { from: owner }); |             await authorizable.addAuthorizedAddress(address2).awaitTransactionSuccessAsync({ from: owner }); | ||||||
|             const address1Index = new BigNumber(0); |             const address1Index = new BigNumber(0); | ||||||
|             return expectTransactionFailedAsync( |             const tx = authorizable | ||||||
|                 authorizable.removeAuthorizedAddressAtIndex.sendTransactionAsync(address2, address1Index, { |                 .removeAuthorizedAddressAtIndex(address2, address1Index) | ||||||
|                     from: owner, |                 .sendTransactionAsync({ from: owner }); | ||||||
|                 }), |             return expect(tx).to.revertWith(RevertReason.AuthorizedAddressMismatch); | ||||||
|                 RevertReason.AuthorizedAddressMismatch, |  | ||||||
|             ); |  | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
|         it('should allow owner to remove an authorized address', async () => { |         it('should allow owner to remove an authorized address', async () => { | ||||||
|             await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(address, { from: owner }); |             await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner }); | ||||||
|             const index = new BigNumber(0); |             const index = new BigNumber(0); | ||||||
|             await authorizable.removeAuthorizedAddressAtIndex.awaitTransactionSuccessAsync(address, index, { |             await authorizable.removeAuthorizedAddressAtIndex(address, index).awaitTransactionSuccessAsync({ | ||||||
|                 from: owner, |                 from: owner, | ||||||
|             }); |             }); | ||||||
|             const isAuthorized = await authorizable.authorized.callAsync(address); |             const isAuthorized = await authorizable.authorized(address).callAsync(); | ||||||
|             expect(isAuthorized).to.be.false(); |             expect(isAuthorized).to.be.false(); | ||||||
|         }); |         }); | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|     describe('getAuthorizedAddresses', () => { |     describe('getAuthorizedAddresses', () => { | ||||||
|         it('should return all authorized addresses', async () => { |         it('should return all authorized addresses', async () => { | ||||||
|             const initial = await authorizable.getAuthorizedAddresses.callAsync(); |             const initial = await authorizable.getAuthorizedAddresses().callAsync(); | ||||||
|             expect(initial).to.have.length(0); |             expect(initial).to.have.length(0); | ||||||
|             await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(address, { from: owner }); |             await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner }); | ||||||
|             const afterAdd = await authorizable.getAuthorizedAddresses.callAsync(); |             const afterAdd = await authorizable.getAuthorizedAddresses().callAsync(); | ||||||
|             expect(afterAdd).to.have.length(1); |             expect(afterAdd).to.have.length(1); | ||||||
|             expect(afterAdd).to.include(address); |             expect(afterAdd).to.include(address); | ||||||
|             await authorizable.removeAuthorizedAddress.awaitTransactionSuccessAsync(address, { from: owner }); |             await authorizable.removeAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner }); | ||||||
|             const afterRemove = await authorizable.getAuthorizedAddresses.callAsync(); |             const afterRemove = await authorizable.getAuthorizedAddresses().callAsync(); | ||||||
|             expect(afterRemove).to.have.length(0); |             expect(afterRemove).to.have.length(0); | ||||||
|         }); |         }); | ||||||
|     }); |     }); | ||||||
|   | |||||||
							
								
								
									
										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)); | ||||||
|  |             }); | ||||||
|  |         }); | ||||||
|  |     }); | ||||||
|  | }); | ||||||
							
								
								
									
										60
									
								
								contracts/asset-proxy/test/chai_bridge.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								contracts/asset-proxy/test/chai_bridge.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,60 @@ | |||||||
|  | import { ERC20TokenContract } from '@0x/contracts-erc20'; | ||||||
|  | import { blockchainTests, constants, expect, randomAddress } from '@0x/contracts-test-utils'; | ||||||
|  | import { AssetProxyId, RevertReason } from '@0x/types'; | ||||||
|  | import { BigNumber } from '@0x/utils'; | ||||||
|  |  | ||||||
|  | import { artifacts } from './artifacts'; | ||||||
|  | import { TestChaiBridgeContract } from './wrappers'; | ||||||
|  |  | ||||||
|  | blockchainTests.resets('ChaiBridge unit tests', env => { | ||||||
|  |     let chaiBridgeContract: TestChaiBridgeContract; | ||||||
|  |     let testDaiContract: ERC20TokenContract; | ||||||
|  |     let fromAddress: string; | ||||||
|  |     let toAddress: string; | ||||||
|  |  | ||||||
|  |     const alwaysRevertAddress = '0x0000000000000000000000000000000000000001'; | ||||||
|  |     const amount = new BigNumber(1); | ||||||
|  |  | ||||||
|  |     before(async () => { | ||||||
|  |         [fromAddress, toAddress] = await env.getAccountAddressesAsync(); | ||||||
|  |         chaiBridgeContract = await TestChaiBridgeContract.deployFrom0xArtifactAsync( | ||||||
|  |             artifacts.TestChaiBridge, | ||||||
|  |             env.provider, | ||||||
|  |             env.txDefaults, | ||||||
|  |             artifacts, | ||||||
|  |         ); | ||||||
|  |         const testChaiDaiAddress = await chaiBridgeContract.testChaiDai().callAsync(); | ||||||
|  |         testDaiContract = new ERC20TokenContract(testChaiDaiAddress, env.provider, env.txDefaults); | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     describe('bridgeTransferFrom()', () => { | ||||||
|  |         it('fails if not called by ERC20BridgeProxy', async () => { | ||||||
|  |             return expect( | ||||||
|  |                 chaiBridgeContract | ||||||
|  |                     .bridgeTransferFrom(randomAddress(), fromAddress, toAddress, amount, constants.NULL_BYTES) | ||||||
|  |                     .awaitTransactionSuccessAsync({ from: alwaysRevertAddress }), | ||||||
|  |             ).to.revertWith(RevertReason.ChaiBridgeOnlyCallableByErc20BridgeProxy); | ||||||
|  |         }); | ||||||
|  |         it('returns magic bytes upon success', async () => { | ||||||
|  |             const magicBytes = await chaiBridgeContract | ||||||
|  |                 .bridgeTransferFrom(randomAddress(), fromAddress, toAddress, amount, constants.NULL_BYTES) | ||||||
|  |                 .callAsync(); | ||||||
|  |             expect(magicBytes).to.eq(AssetProxyId.ERC20Bridge); | ||||||
|  |         }); | ||||||
|  |         it('should increase the Dai balance of `toAddress` by `amount` if successful', async () => { | ||||||
|  |             const initialBalance = await testDaiContract.balanceOf(toAddress).callAsync(); | ||||||
|  |             await chaiBridgeContract | ||||||
|  |                 .bridgeTransferFrom(randomAddress(), fromAddress, toAddress, amount, constants.NULL_BYTES) | ||||||
|  |                 .awaitTransactionSuccessAsync(); | ||||||
|  |             const endBalance = await testDaiContract.balanceOf(toAddress).callAsync(); | ||||||
|  |             expect(endBalance).to.bignumber.eq(initialBalance.plus(amount)); | ||||||
|  |         }); | ||||||
|  |         it('fails if the `chai.draw` call fails', async () => { | ||||||
|  |             return expect( | ||||||
|  |                 chaiBridgeContract | ||||||
|  |                     .bridgeTransferFrom(randomAddress(), alwaysRevertAddress, toAddress, amount, constants.NULL_BYTES) | ||||||
|  |                     .awaitTransactionSuccessAsync(), | ||||||
|  |             ).to.revertWith(RevertReason.ChaiBridgeDrawDaiFailed); | ||||||
|  |         }); | ||||||
|  |     }); | ||||||
|  | }); | ||||||
							
								
								
									
										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'); | ||||||
|  |         }); | ||||||
|  |     }); | ||||||
|  | }); | ||||||
							
								
								
									
										399
									
								
								contracts/asset-proxy/test/dydx_bridge.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										399
									
								
								contracts/asset-proxy/test/dydx_bridge.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,399 @@ | |||||||
|  | import { LibMathRevertErrors } from '@0x/contracts-exchange-libs'; | ||||||
|  | import { blockchainTests, constants, expect, verifyEventsFromLogs } from '@0x/contracts-test-utils'; | ||||||
|  | import { AssetProxyId, RevertReason } from '@0x/types'; | ||||||
|  | import { BigNumber } from '@0x/utils'; | ||||||
|  | import * as _ from 'lodash'; | ||||||
|  |  | ||||||
|  | import { DydxBridgeActionType, DydxBridgeData, dydxBridgeDataEncoder } from '../src/dydx_bridge_encoder'; | ||||||
|  | import { ERC20BridgeProxyContract, IAssetDataContract } from '../src/wrappers'; | ||||||
|  |  | ||||||
|  | import { artifacts } from './artifacts'; | ||||||
|  | import { TestDydxBridgeContract, TestDydxBridgeEvents } from './wrappers'; | ||||||
|  |  | ||||||
|  | blockchainTests.resets('DydxBridge unit tests', env => { | ||||||
|  |     const defaultAccountNumber = new BigNumber(1); | ||||||
|  |     const marketId = new BigNumber(2); | ||||||
|  |     const defaultAmount = new BigNumber(4); | ||||||
|  |     const notAuthorized = '0x0000000000000000000000000000000000000001'; | ||||||
|  |     const defaultDepositAction = { | ||||||
|  |         actionType: DydxBridgeActionType.Deposit, | ||||||
|  |         accountIdx: constants.ZERO_AMOUNT, | ||||||
|  |         marketId, | ||||||
|  |         conversionRateNumerator: constants.ZERO_AMOUNT, | ||||||
|  |         conversionRateDenominator: constants.ZERO_AMOUNT, | ||||||
|  |     }; | ||||||
|  |     const defaultWithdrawAction = { | ||||||
|  |         actionType: DydxBridgeActionType.Withdraw, | ||||||
|  |         accountIdx: constants.ZERO_AMOUNT, | ||||||
|  |         marketId, | ||||||
|  |         conversionRateNumerator: constants.ZERO_AMOUNT, | ||||||
|  |         conversionRateDenominator: constants.ZERO_AMOUNT, | ||||||
|  |     }; | ||||||
|  |     let testContract: TestDydxBridgeContract; | ||||||
|  |     let testProxyContract: ERC20BridgeProxyContract; | ||||||
|  |     let assetDataEncoder: IAssetDataContract; | ||||||
|  |     let owner: string; | ||||||
|  |     let authorized: string; | ||||||
|  |     let accountOwner: string; | ||||||
|  |     let receiver: string; | ||||||
|  |  | ||||||
|  |     before(async () => { | ||||||
|  |         // Get accounts | ||||||
|  |         const accounts = await env.web3Wrapper.getAvailableAddressesAsync(); | ||||||
|  |         [owner, authorized, accountOwner, receiver] = accounts; | ||||||
|  |  | ||||||
|  |         // Deploy dydx bridge | ||||||
|  |         testContract = await TestDydxBridgeContract.deployFrom0xArtifactAsync( | ||||||
|  |             artifacts.TestDydxBridge, | ||||||
|  |             env.provider, | ||||||
|  |             env.txDefaults, | ||||||
|  |             artifacts, | ||||||
|  |             [accountOwner, receiver], | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         // Deploy test erc20 bridge proxy | ||||||
|  |         testProxyContract = await ERC20BridgeProxyContract.deployFrom0xArtifactAsync( | ||||||
|  |             artifacts.ERC20BridgeProxy, | ||||||
|  |             env.provider, | ||||||
|  |             env.txDefaults, | ||||||
|  |             artifacts, | ||||||
|  |         ); | ||||||
|  |         await testProxyContract.addAuthorizedAddress(authorized).awaitTransactionSuccessAsync({ from: owner }); | ||||||
|  |  | ||||||
|  |         // Setup asset data encoder | ||||||
|  |         assetDataEncoder = new IAssetDataContract(constants.NULL_ADDRESS, env.provider); | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     describe('bridgeTransferFrom()', () => { | ||||||
|  |         const callBridgeTransferFrom = async ( | ||||||
|  |             from: string, | ||||||
|  |             to: string, | ||||||
|  |             amount: BigNumber, | ||||||
|  |             bridgeData: DydxBridgeData, | ||||||
|  |             sender: string, | ||||||
|  |         ): Promise<string> => { | ||||||
|  |             const returnValue = await testContract | ||||||
|  |                 .bridgeTransferFrom( | ||||||
|  |                     constants.NULL_ADDRESS, | ||||||
|  |                     from, | ||||||
|  |                     to, | ||||||
|  |                     amount, | ||||||
|  |                     dydxBridgeDataEncoder.encode({ bridgeData }), | ||||||
|  |                 ) | ||||||
|  |                 .callAsync({ from: sender }); | ||||||
|  |             return returnValue; | ||||||
|  |         }; | ||||||
|  |         const executeBridgeTransferFromAndVerifyEvents = async ( | ||||||
|  |             from: string, | ||||||
|  |             to: string, | ||||||
|  |             amount: BigNumber, | ||||||
|  |             bridgeData: DydxBridgeData, | ||||||
|  |             sender: string, | ||||||
|  |         ): Promise<void> => { | ||||||
|  |             // Execute transaction. | ||||||
|  |             const txReceipt = await testContract | ||||||
|  |                 .bridgeTransferFrom( | ||||||
|  |                     constants.NULL_ADDRESS, | ||||||
|  |                     from, | ||||||
|  |                     to, | ||||||
|  |                     amount, | ||||||
|  |                     dydxBridgeDataEncoder.encode({ bridgeData }), | ||||||
|  |                 ) | ||||||
|  |                 .awaitTransactionSuccessAsync({ from: sender }); | ||||||
|  |  | ||||||
|  |             // Verify `OperateAccount` event. | ||||||
|  |             const expectedOperateAccountEvents = []; | ||||||
|  |             for (const accountNumber of bridgeData.accountNumbers) { | ||||||
|  |                 expectedOperateAccountEvents.push({ | ||||||
|  |                     owner: accountOwner, | ||||||
|  |                     number: accountNumber, | ||||||
|  |                 }); | ||||||
|  |             } | ||||||
|  |             verifyEventsFromLogs(txReceipt.logs, expectedOperateAccountEvents, TestDydxBridgeEvents.OperateAccount); | ||||||
|  |  | ||||||
|  |             // Verify `OperateAction` event. | ||||||
|  |             const weiDenomination = 0; | ||||||
|  |             const deltaAmountRef = 0; | ||||||
|  |             const expectedOperateActionEvents = []; | ||||||
|  |             for (const action of bridgeData.actions) { | ||||||
|  |                 expectedOperateActionEvents.push({ | ||||||
|  |                     actionType: action.actionType as number, | ||||||
|  |                     accountIdx: action.accountIdx, | ||||||
|  |                     amountSign: action.actionType === DydxBridgeActionType.Deposit ? true : false, | ||||||
|  |                     amountDenomination: weiDenomination, | ||||||
|  |                     amountRef: deltaAmountRef, | ||||||
|  |                     amountValue: action.conversionRateDenominator.gt(0) | ||||||
|  |                         ? amount | ||||||
|  |                               .times(action.conversionRateNumerator) | ||||||
|  |                               .dividedToIntegerBy(action.conversionRateDenominator) | ||||||
|  |                         : amount, | ||||||
|  |                     primaryMarketId: marketId, | ||||||
|  |                     secondaryMarketId: constants.ZERO_AMOUNT, | ||||||
|  |                     otherAddress: action.actionType === DydxBridgeActionType.Deposit ? from : to, | ||||||
|  |                     otherAccountId: constants.ZERO_AMOUNT, | ||||||
|  |                     data: '0x', | ||||||
|  |                 }); | ||||||
|  |             } | ||||||
|  |             verifyEventsFromLogs(txReceipt.logs, expectedOperateActionEvents, TestDydxBridgeEvents.OperateAction); | ||||||
|  |         }; | ||||||
|  |         it('succeeds when calling with zero amount', async () => { | ||||||
|  |             const bridgeData = { | ||||||
|  |                 accountNumbers: [defaultAccountNumber], | ||||||
|  |                 actions: [defaultDepositAction], | ||||||
|  |             }; | ||||||
|  |             await executeBridgeTransferFromAndVerifyEvents( | ||||||
|  |                 accountOwner, | ||||||
|  |                 receiver, | ||||||
|  |                 constants.ZERO_AMOUNT, | ||||||
|  |                 bridgeData, | ||||||
|  |                 authorized, | ||||||
|  |             ); | ||||||
|  |         }); | ||||||
|  |         it('succeeds when calling with no accounts', async () => { | ||||||
|  |             const bridgeData = { | ||||||
|  |                 accountNumbers: [], | ||||||
|  |                 actions: [defaultDepositAction], | ||||||
|  |             }; | ||||||
|  |             await executeBridgeTransferFromAndVerifyEvents( | ||||||
|  |                 accountOwner, | ||||||
|  |                 receiver, | ||||||
|  |                 defaultAmount, | ||||||
|  |                 bridgeData, | ||||||
|  |                 authorized, | ||||||
|  |             ); | ||||||
|  |         }); | ||||||
|  |         it('succeeds when calling with no actions', async () => { | ||||||
|  |             const bridgeData = { | ||||||
|  |                 accountNumbers: [defaultAccountNumber], | ||||||
|  |                 actions: [], | ||||||
|  |             }; | ||||||
|  |             await executeBridgeTransferFromAndVerifyEvents( | ||||||
|  |                 accountOwner, | ||||||
|  |                 receiver, | ||||||
|  |                 defaultAmount, | ||||||
|  |                 bridgeData, | ||||||
|  |                 authorized, | ||||||
|  |             ); | ||||||
|  |         }); | ||||||
|  |         it('succeeds when calling `operate` with the `deposit` action and a single account', async () => { | ||||||
|  |             const bridgeData = { | ||||||
|  |                 accountNumbers: [defaultAccountNumber], | ||||||
|  |                 actions: [defaultDepositAction], | ||||||
|  |             }; | ||||||
|  |             await executeBridgeTransferFromAndVerifyEvents( | ||||||
|  |                 accountOwner, | ||||||
|  |                 receiver, | ||||||
|  |                 defaultAmount, | ||||||
|  |                 bridgeData, | ||||||
|  |                 authorized, | ||||||
|  |             ); | ||||||
|  |         }); | ||||||
|  |         it('succeeds when calling `operate` with the `deposit` action and multiple accounts', async () => { | ||||||
|  |             const bridgeData = { | ||||||
|  |                 accountNumbers: [defaultAccountNumber, defaultAccountNumber.plus(1)], | ||||||
|  |                 actions: [defaultDepositAction], | ||||||
|  |             }; | ||||||
|  |             await executeBridgeTransferFromAndVerifyEvents( | ||||||
|  |                 accountOwner, | ||||||
|  |                 receiver, | ||||||
|  |                 defaultAmount, | ||||||
|  |                 bridgeData, | ||||||
|  |                 authorized, | ||||||
|  |             ); | ||||||
|  |         }); | ||||||
|  |         it('succeeds when calling `operate` with the `withdraw` action and a single account', async () => { | ||||||
|  |             const bridgeData = { | ||||||
|  |                 accountNumbers: [defaultAccountNumber], | ||||||
|  |                 actions: [defaultWithdrawAction], | ||||||
|  |             }; | ||||||
|  |             await executeBridgeTransferFromAndVerifyEvents( | ||||||
|  |                 accountOwner, | ||||||
|  |                 receiver, | ||||||
|  |                 defaultAmount, | ||||||
|  |                 bridgeData, | ||||||
|  |                 authorized, | ||||||
|  |             ); | ||||||
|  |         }); | ||||||
|  |         it('succeeds when calling `operate` with the `withdraw` action and multiple accounts', async () => { | ||||||
|  |             const bridgeData = { | ||||||
|  |                 accountNumbers: [defaultAccountNumber, defaultAccountNumber.plus(1)], | ||||||
|  |                 actions: [defaultWithdrawAction], | ||||||
|  |             }; | ||||||
|  |             await executeBridgeTransferFromAndVerifyEvents( | ||||||
|  |                 accountOwner, | ||||||
|  |                 receiver, | ||||||
|  |                 defaultAmount, | ||||||
|  |                 bridgeData, | ||||||
|  |                 authorized, | ||||||
|  |             ); | ||||||
|  |         }); | ||||||
|  |         it('succeeds when calling `operate` with the `deposit` action and multiple accounts', async () => { | ||||||
|  |             const bridgeData = { | ||||||
|  |                 accountNumbers: [defaultAccountNumber, defaultAccountNumber.plus(1)], | ||||||
|  |                 actions: [defaultWithdrawAction, defaultDepositAction], | ||||||
|  |             }; | ||||||
|  |             await executeBridgeTransferFromAndVerifyEvents( | ||||||
|  |                 accountOwner, | ||||||
|  |                 receiver, | ||||||
|  |                 defaultAmount, | ||||||
|  |                 bridgeData, | ||||||
|  |                 authorized, | ||||||
|  |             ); | ||||||
|  |         }); | ||||||
|  |         it('succeeds when calling `operate` with multiple actions under a single account', async () => { | ||||||
|  |             const bridgeData = { | ||||||
|  |                 accountNumbers: [defaultAccountNumber], | ||||||
|  |                 actions: [defaultWithdrawAction, defaultDepositAction], | ||||||
|  |             }; | ||||||
|  |             await executeBridgeTransferFromAndVerifyEvents( | ||||||
|  |                 accountOwner, | ||||||
|  |                 receiver, | ||||||
|  |                 defaultAmount, | ||||||
|  |                 bridgeData, | ||||||
|  |                 authorized, | ||||||
|  |             ); | ||||||
|  |         }); | ||||||
|  |         it('succeeds when scaling the `amount` to deposit', async () => { | ||||||
|  |             const conversionRateNumerator = new BigNumber(1); | ||||||
|  |             const conversionRateDenominator = new BigNumber(2); | ||||||
|  |             const bridgeData = { | ||||||
|  |                 accountNumbers: [defaultAccountNumber], | ||||||
|  |                 actions: [ | ||||||
|  |                     defaultWithdrawAction, | ||||||
|  |                     { | ||||||
|  |                         ...defaultDepositAction, | ||||||
|  |                         conversionRateNumerator, | ||||||
|  |                         conversionRateDenominator, | ||||||
|  |                     }, | ||||||
|  |                 ], | ||||||
|  |             }; | ||||||
|  |             await executeBridgeTransferFromAndVerifyEvents( | ||||||
|  |                 accountOwner, | ||||||
|  |                 receiver, | ||||||
|  |                 defaultAmount, | ||||||
|  |                 bridgeData, | ||||||
|  |                 authorized, | ||||||
|  |             ); | ||||||
|  |         }); | ||||||
|  |         it('succeeds when scaling the `amount` to withdraw', async () => { | ||||||
|  |             const conversionRateNumerator = new BigNumber(1); | ||||||
|  |             const conversionRateDenominator = new BigNumber(2); | ||||||
|  |             const bridgeData = { | ||||||
|  |                 accountNumbers: [defaultAccountNumber], | ||||||
|  |                 actions: [ | ||||||
|  |                     defaultDepositAction, | ||||||
|  |                     { | ||||||
|  |                         ...defaultWithdrawAction, | ||||||
|  |                         conversionRateNumerator, | ||||||
|  |                         conversionRateDenominator, | ||||||
|  |                     }, | ||||||
|  |                 ], | ||||||
|  |             }; | ||||||
|  |             await executeBridgeTransferFromAndVerifyEvents( | ||||||
|  |                 accountOwner, | ||||||
|  |                 receiver, | ||||||
|  |                 defaultAmount, | ||||||
|  |                 bridgeData, | ||||||
|  |                 authorized, | ||||||
|  |             ); | ||||||
|  |         }); | ||||||
|  |         it('reverts if not called by the ERC20 Bridge Proxy', async () => { | ||||||
|  |             const bridgeData = { | ||||||
|  |                 accountNumbers: [defaultAccountNumber], | ||||||
|  |                 actions: [defaultDepositAction], | ||||||
|  |             }; | ||||||
|  |             const callBridgeTransferFromPromise = callBridgeTransferFrom( | ||||||
|  |                 accountOwner, | ||||||
|  |                 receiver, | ||||||
|  |                 defaultAmount, | ||||||
|  |                 bridgeData, | ||||||
|  |                 notAuthorized, | ||||||
|  |             ); | ||||||
|  |             const expectedError = RevertReason.DydxBridgeOnlyCallableByErc20BridgeProxy; | ||||||
|  |             return expect(callBridgeTransferFromPromise).to.revertWith(expectedError); | ||||||
|  |         }); | ||||||
|  |         it('should return magic bytes if call succeeds', async () => { | ||||||
|  |             const bridgeData = { | ||||||
|  |                 accountNumbers: [defaultAccountNumber], | ||||||
|  |                 actions: [defaultDepositAction], | ||||||
|  |             }; | ||||||
|  |             const returnValue = await callBridgeTransferFrom( | ||||||
|  |                 accountOwner, | ||||||
|  |                 receiver, | ||||||
|  |                 defaultAmount, | ||||||
|  |                 bridgeData, | ||||||
|  |                 authorized, | ||||||
|  |             ); | ||||||
|  |             expect(returnValue).to.equal(AssetProxyId.ERC20Bridge); | ||||||
|  |         }); | ||||||
|  |         it('should revert when `Operate` reverts', async () => { | ||||||
|  |             // Set revert flag. | ||||||
|  |             await testContract.setRevertOnOperate(true).awaitTransactionSuccessAsync(); | ||||||
|  |  | ||||||
|  |             // Execute transfer. | ||||||
|  |             const bridgeData = { | ||||||
|  |                 accountNumbers: [defaultAccountNumber], | ||||||
|  |                 actions: [defaultDepositAction], | ||||||
|  |             }; | ||||||
|  |             const tx = callBridgeTransferFrom(accountOwner, receiver, defaultAmount, bridgeData, authorized); | ||||||
|  |             const expectedError = 'TestDydxBridge/SHOULD_REVERT_ON_OPERATE'; | ||||||
|  |             return expect(tx).to.revertWith(expectedError); | ||||||
|  |         }); | ||||||
|  |         it('should revert when there is a rounding error', async () => { | ||||||
|  |             // Setup a rounding error | ||||||
|  |             const conversionRateNumerator = new BigNumber(5318); | ||||||
|  |             const conversionRateDenominator = new BigNumber(47958); | ||||||
|  |             const amount = new BigNumber(9000); | ||||||
|  |             const bridgeData = { | ||||||
|  |                 accountNumbers: [defaultAccountNumber], | ||||||
|  |                 actions: [ | ||||||
|  |                     defaultDepositAction, | ||||||
|  |                     { | ||||||
|  |                         ...defaultWithdrawAction, | ||||||
|  |                         conversionRateNumerator, | ||||||
|  |                         conversionRateDenominator, | ||||||
|  |                     }, | ||||||
|  |                 ], | ||||||
|  |             }; | ||||||
|  |  | ||||||
|  |             // Execute transfer and assert error. | ||||||
|  |             const tx = callBridgeTransferFrom(accountOwner, receiver, amount, bridgeData, authorized); | ||||||
|  |             const expectedError = new LibMathRevertErrors.RoundingError( | ||||||
|  |                 conversionRateNumerator, | ||||||
|  |                 conversionRateDenominator, | ||||||
|  |                 amount, | ||||||
|  |             ); | ||||||
|  |             return expect(tx).to.revertWith(expectedError); | ||||||
|  |         }); | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     describe('ERC20BridgeProxy.transferFrom()', () => { | ||||||
|  |         const bridgeData = { | ||||||
|  |             accountNumbers: [defaultAccountNumber], | ||||||
|  |             actions: [defaultWithdrawAction], | ||||||
|  |         }; | ||||||
|  |         let assetData: string; | ||||||
|  |  | ||||||
|  |         before(async () => { | ||||||
|  |             const testTokenAddress = await testContract.getTestToken().callAsync(); | ||||||
|  |             assetData = assetDataEncoder | ||||||
|  |                 .ERC20Bridge(testTokenAddress, testContract.address, dydxBridgeDataEncoder.encode({ bridgeData })) | ||||||
|  |                 .getABIEncodedTransactionData(); | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         it('should succeed if `bridgeTransferFrom` succeeds', async () => { | ||||||
|  |             await testProxyContract | ||||||
|  |                 .transferFrom(assetData, accountOwner, receiver, defaultAmount) | ||||||
|  |                 .awaitTransactionSuccessAsync({ from: authorized }); | ||||||
|  |         }); | ||||||
|  |         it('should revert if `bridgeTransferFrom` reverts', async () => { | ||||||
|  |             // Set revert flag. | ||||||
|  |             await testContract.setRevertOnOperate(true).awaitTransactionSuccessAsync(); | ||||||
|  |             const tx = testProxyContract | ||||||
|  |                 .transferFrom(assetData, accountOwner, receiver, defaultAmount) | ||||||
|  |                 .awaitTransactionSuccessAsync({ from: authorized }); | ||||||
|  |             const expectedError = 'TestDydxBridge/SHOULD_REVERT_ON_OPERATE'; | ||||||
|  |             return expect(tx).to.revertWith(expectedError); | ||||||
|  |         }); | ||||||
|  |     }); | ||||||
|  | }); | ||||||
| @@ -1,4 +1,3 @@ | |||||||
| import { DevUtilsContract } from '@0x/contracts-dev-utils'; |  | ||||||
| import { | import { | ||||||
|     artifacts as erc1155Artifacts, |     artifacts as erc1155Artifacts, | ||||||
|     DummyERC1155ReceiverBatchTokenReceivedEventArgs, |     DummyERC1155ReceiverBatchTokenReceivedEventArgs, | ||||||
| @@ -15,15 +14,19 @@ import { | |||||||
|     txDefaults, |     txDefaults, | ||||||
|     web3Wrapper, |     web3Wrapper, | ||||||
| } from '@0x/contracts-test-utils'; | } from '@0x/contracts-test-utils'; | ||||||
|  | import { SafeMathRevertErrors } from '@0x/contracts-utils'; | ||||||
| import { BlockchainLifecycle } from '@0x/dev-utils'; | import { BlockchainLifecycle } from '@0x/dev-utils'; | ||||||
| import { AssetProxyId, RevertReason } from '@0x/types'; | import { AssetProxyId, RevertReason } from '@0x/types'; | ||||||
| import { BigNumber, SafeMathRevertErrors } from '@0x/utils'; | import { BigNumber } from '@0x/utils'; | ||||||
| import * as chai from 'chai'; | import * as chai from 'chai'; | ||||||
| import { LogWithDecodedArgs } from 'ethereum-types'; | import { LogWithDecodedArgs } from 'ethereum-types'; | ||||||
| import * as ethUtil from 'ethereumjs-util'; | import * as ethUtil from 'ethereumjs-util'; | ||||||
| import * as _ from 'lodash'; | import * as _ from 'lodash'; | ||||||
|  |  | ||||||
| import { artifacts, ERC1155ProxyContract, ERC1155ProxyWrapper, IAssetDataContract } from '../src'; | import { ERC1155ProxyWrapper } from '../src/erc1155_proxy_wrapper'; | ||||||
|  | import { ERC1155ProxyContract, IAssetDataContract } from '../src/wrappers'; | ||||||
|  |  | ||||||
|  | import { artifacts } from './artifacts'; | ||||||
|  |  | ||||||
| chaiSetup.configure(); | chaiSetup.configure(); | ||||||
| const expect = chai.expect; | const expect = chai.expect; | ||||||
| @@ -59,8 +62,8 @@ describe('ERC1155Proxy', () => { | |||||||
|     // tokens |     // tokens | ||||||
|     let fungibleTokens: BigNumber[]; |     let fungibleTokens: BigNumber[]; | ||||||
|     let nonFungibleTokensOwnedBySpender: BigNumber[]; |     let nonFungibleTokensOwnedBySpender: BigNumber[]; | ||||||
|     // devUtils for encoding and decoding assetData |     // IAssetData for encoding and decoding assetData | ||||||
|     let devUtils: DevUtilsContract; |     let assetDataContract: IAssetDataContract; | ||||||
|     // tests |     // tests | ||||||
|     before(async () => { |     before(async () => { | ||||||
|         await blockchainLifecycle.startAsync(); |         await blockchainLifecycle.startAsync(); | ||||||
| @@ -74,8 +77,8 @@ describe('ERC1155Proxy', () => { | |||||||
|         const usedAddresses = ([owner, notAuthorized, authorized, spender, receiver] = _.slice(accounts, 0, 5)); |         const usedAddresses = ([owner, notAuthorized, authorized, spender, receiver] = _.slice(accounts, 0, 5)); | ||||||
|         erc1155ProxyWrapper = new ERC1155ProxyWrapper(provider, usedAddresses, owner); |         erc1155ProxyWrapper = new ERC1155ProxyWrapper(provider, usedAddresses, owner); | ||||||
|         erc1155Proxy = await erc1155ProxyWrapper.deployProxyAsync(); |         erc1155Proxy = await erc1155ProxyWrapper.deployProxyAsync(); | ||||||
|         await erc1155Proxy.addAuthorizedAddress.awaitTransactionSuccessAsync(authorized, { from: owner }); |         await erc1155Proxy.addAuthorizedAddress(authorized).awaitTransactionSuccessAsync({ from: owner }); | ||||||
|         await erc1155Proxy.addAuthorizedAddress.awaitTransactionSuccessAsync(erc1155Proxy.address, { from: owner }); |         await erc1155Proxy.addAuthorizedAddress(erc1155Proxy.address).awaitTransactionSuccessAsync({ from: owner }); | ||||||
|         // deploy & configure ERC1155 tokens and receiver |         // deploy & configure ERC1155 tokens and receiver | ||||||
|         [erc1155Wrapper] = await erc1155ProxyWrapper.deployDummyContractsAsync(); |         [erc1155Wrapper] = await erc1155ProxyWrapper.deployDummyContractsAsync(); | ||||||
|         erc1155Contract = erc1155Wrapper.getContract(); |         erc1155Contract = erc1155Wrapper.getContract(); | ||||||
| @@ -97,8 +100,8 @@ describe('ERC1155Proxy', () => { | |||||||
|                 tokenBalances.nonFungible[spender][erc1155Contract.address][nonFungibleTokenAsString][0]; |                 tokenBalances.nonFungible[spender][erc1155Contract.address][nonFungibleTokenAsString][0]; | ||||||
|             nonFungibleTokensOwnedBySpender.push(nonFungibleTokenHeldBySpender); |             nonFungibleTokensOwnedBySpender.push(nonFungibleTokenHeldBySpender); | ||||||
|         }); |         }); | ||||||
|         // set up devUtils |         // set up assetDataContract | ||||||
|         devUtils = new DevUtilsContract(constants.NULL_ADDRESS, provider, { from: owner }); |         assetDataContract = new IAssetDataContract(constants.NULL_ADDRESS, provider, { from: owner }); | ||||||
|     }); |     }); | ||||||
|     beforeEach(async () => { |     beforeEach(async () => { | ||||||
|         await blockchainLifecycle.startAsync(); |         await blockchainLifecycle.startAsync(); | ||||||
| @@ -119,7 +122,7 @@ describe('ERC1155Proxy', () => { | |||||||
|             ); |             ); | ||||||
|         }); |         }); | ||||||
|         it('should have an id of 0xa7cb5fb7', async () => { |         it('should have an id of 0xa7cb5fb7', async () => { | ||||||
|             const proxyId = await erc1155Proxy.getProxyId.callAsync(); |             const proxyId = await erc1155Proxy.getProxyId().callAsync(); | ||||||
|             const expectedProxyId = AssetProxyId.ERC1155; |             const expectedProxyId = AssetProxyId.ERC1155; | ||||||
|             expect(proxyId).to.equal(expectedProxyId); |             expect(proxyId).to.equal(expectedProxyId); | ||||||
|         }); |         }); | ||||||
| @@ -634,12 +637,9 @@ describe('ERC1155Proxy', () => { | |||||||
|                 return value.times(valueMultiplier); |                 return value.times(valueMultiplier); | ||||||
|             }); |             }); | ||||||
|             const erc1155ContractAddress = erc1155Wrapper.getContract().address; |             const erc1155ContractAddress = erc1155Wrapper.getContract().address; | ||||||
|             const assetData = await devUtils.encodeERC1155AssetData.callAsync( |             const assetData = assetDataContract | ||||||
|                 erc1155ContractAddress, |                 .ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData) | ||||||
|                 tokensToTransfer, |                 .getABIEncodedTransactionData(); | ||||||
|                 valuesToTransfer, |  | ||||||
|                 receiverCallbackData, |  | ||||||
|             ); |  | ||||||
|             const extraData = '0102030405060708091001020304050607080910010203040506070809100102'; |             const extraData = '0102030405060708091001020304050607080910010203040506070809100102'; | ||||||
|             const assetDataWithExtraData = `${assetData}${extraData}`; |             const assetDataWithExtraData = `${assetData}${extraData}`; | ||||||
|             // check balances before transfer |             // check balances before transfer | ||||||
| @@ -694,14 +694,16 @@ describe('ERC1155Proxy', () => { | |||||||
|                 // create token |                 // create token | ||||||
|                 await erc1155Wrapper |                 await erc1155Wrapper | ||||||
|                     .getContract() |                     .getContract() | ||||||
|                     .createWithType.awaitTransactionSuccessAsync(tokenToCreate, tokenUri, { |                     .createWithType(tokenToCreate, tokenUri) | ||||||
|  |                     .awaitTransactionSuccessAsync({ | ||||||
|                         from: owner, |                         from: owner, | ||||||
|                     }); |                     }); | ||||||
|  |  | ||||||
|                 // mint balance for spender |                 // mint balance for spender | ||||||
|                 await erc1155Wrapper |                 await erc1155Wrapper | ||||||
|                     .getContract() |                     .getContract() | ||||||
|                     .mintFungible.awaitTransactionSuccessAsync(tokenToCreate, [spender], [spenderInitialBalance], { |                     .mintFungible(tokenToCreate, [spender], [spenderInitialBalance]) | ||||||
|  |                     .awaitTransactionSuccessAsync({ | ||||||
|                         from: owner, |                         from: owner, | ||||||
|                     }); |                     }); | ||||||
|             } |             } | ||||||
| @@ -737,9 +739,8 @@ describe('ERC1155Proxy', () => { | |||||||
|             const valuesToTransfer = tokensToTransfer; |             const valuesToTransfer = tokensToTransfer; | ||||||
|             const valueMultiplier = new BigNumber(2); |             const valueMultiplier = new BigNumber(2); | ||||||
|  |  | ||||||
|             // hand encode optimized assetData because our tooling (based on LibAssetData.sol/encodeERC1155AssetData) does not use optimized encoding |             // hand encode optimized assetData because our tooling (based on LibAssetData.sol/ERC1155Assets) does not use optimized encoding | ||||||
|             const assetDataContract = new IAssetDataContract(constants.NULL_ADDRESS, provider); |             const selector = assetDataContract.getSelector('ERC1155Assets'); | ||||||
|             const selector = assetDataContract.ERC1155Assets.getSelector(); |  | ||||||
|             const assetDataWithoutContractAddress = |             const assetDataWithoutContractAddress = | ||||||
|                 '0000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000040102030400000000000000000000000000000000000000000000000000000000'; |                 '0000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000040102030400000000000000000000000000000000000000000000000000000000'; | ||||||
|             const assetData = `${selector}000000000000000000000000${erc1155ContractAddress.substr( |             const assetData = `${selector}000000000000000000000000${erc1155ContractAddress.substr( | ||||||
| @@ -794,14 +795,16 @@ describe('ERC1155Proxy', () => { | |||||||
|                 // create token |                 // create token | ||||||
|                 await erc1155Wrapper |                 await erc1155Wrapper | ||||||
|                     .getContract() |                     .getContract() | ||||||
|                     .createWithType.awaitTransactionSuccessAsync(tokenToCreate, tokenUri, { |                     .createWithType(tokenToCreate, tokenUri) | ||||||
|  |                     .awaitTransactionSuccessAsync({ | ||||||
|                         from: owner, |                         from: owner, | ||||||
|                     }); |                     }); | ||||||
|  |  | ||||||
|                 // mint balance for spender |                 // mint balance for spender | ||||||
|                 await erc1155Wrapper |                 await erc1155Wrapper | ||||||
|                     .getContract() |                     .getContract() | ||||||
|                     .mintFungible.awaitTransactionSuccessAsync(tokenToCreate, [spender], [spenderInitialBalance], { |                     .mintFungible(tokenToCreate, [spender], [spenderInitialBalance]) | ||||||
|  |                     .awaitTransactionSuccessAsync({ | ||||||
|                         from: owner, |                         from: owner, | ||||||
|                     }); |                     }); | ||||||
|             } |             } | ||||||
| @@ -847,12 +850,9 @@ describe('ERC1155Proxy', () => { | |||||||
|             const valuesToTransfer = [new BigNumber(2), new BigNumber(2)]; |             const valuesToTransfer = [new BigNumber(2), new BigNumber(2)]; | ||||||
|             const valueMultiplier = new BigNumber(2); |             const valueMultiplier = new BigNumber(2); | ||||||
|             // create callback data that is the encoded version of `valuesToTransfer` |             // create callback data that is the encoded version of `valuesToTransfer` | ||||||
|             const generatedAssetData = await devUtils.encodeERC1155AssetData.callAsync( |             const generatedAssetData = assetDataContract | ||||||
|                 erc1155ContractAddress, |                 .ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData) | ||||||
|                 tokensToTransfer, |                 .getABIEncodedTransactionData(); | ||||||
|                 valuesToTransfer, |  | ||||||
|                 receiverCallbackData, |  | ||||||
|             ); |  | ||||||
|             // remove the function selector and contract address from check, as these change on each test |             // remove the function selector and contract address from check, as these change on each test | ||||||
|             const offsetToTokenIds = 74; |             const offsetToTokenIds = 74; | ||||||
|             const assetDataSelectorAndContractAddress = generatedAssetData.substr(0, offsetToTokenIds); |             const assetDataSelectorAndContractAddress = generatedAssetData.substr(0, offsetToTokenIds); | ||||||
| @@ -919,14 +919,16 @@ describe('ERC1155Proxy', () => { | |||||||
|                 // create token |                 // create token | ||||||
|                 await erc1155Wrapper |                 await erc1155Wrapper | ||||||
|                     .getContract() |                     .getContract() | ||||||
|                     .createWithType.awaitTransactionSuccessAsync(tokenToCreate, tokenUri, { |                     .createWithType(tokenToCreate, tokenUri) | ||||||
|  |                     .awaitTransactionSuccessAsync({ | ||||||
|                         from: owner, |                         from: owner, | ||||||
|                     }); |                     }); | ||||||
|  |  | ||||||
|                 // mint balance for spender |                 // mint balance for spender | ||||||
|                 await erc1155Wrapper |                 await erc1155Wrapper | ||||||
|                     .getContract() |                     .getContract() | ||||||
|                     .mintFungible.awaitTransactionSuccessAsync(tokenToCreate, [spender], [spenderInitialBalance], { |                     .mintFungible(tokenToCreate, [spender], [spenderInitialBalance]) | ||||||
|  |                     .awaitTransactionSuccessAsync({ | ||||||
|                         from: owner, |                         from: owner, | ||||||
|                     }); |                     }); | ||||||
|             } |             } | ||||||
| @@ -969,12 +971,9 @@ describe('ERC1155Proxy', () => { | |||||||
|             const valuesToTransfer = [new BigNumber(1), new BigNumber(2)]; |             const valuesToTransfer = [new BigNumber(1), new BigNumber(2)]; | ||||||
|             const valueMultiplier = new BigNumber(2); |             const valueMultiplier = new BigNumber(2); | ||||||
|             // create callback data that is the encoded version of `valuesToTransfer` |             // create callback data that is the encoded version of `valuesToTransfer` | ||||||
|             const generatedAssetData = await devUtils.encodeERC1155AssetData.callAsync( |             const generatedAssetData = assetDataContract | ||||||
|                 erc1155ContractAddress, |                 .ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData) | ||||||
|                 tokensToTransfer, |                 .getABIEncodedTransactionData(); | ||||||
|                 valuesToTransfer, |  | ||||||
|                 receiverCallbackData, |  | ||||||
|             ); |  | ||||||
|             // remove the function selector and contract address from check, as these change on each test |             // remove the function selector and contract address from check, as these change on each test | ||||||
|             const offsetToTokenIds = 74; |             const offsetToTokenIds = 74; | ||||||
|             const assetDataSelectorAndContractAddress = generatedAssetData.substr(0, offsetToTokenIds); |             const assetDataSelectorAndContractAddress = generatedAssetData.substr(0, offsetToTokenIds); | ||||||
| @@ -1032,12 +1031,9 @@ describe('ERC1155Proxy', () => { | |||||||
|             const valuesToTransfer = [fungibleValueToTransferLarge]; |             const valuesToTransfer = [fungibleValueToTransferLarge]; | ||||||
|             const valueMultiplier = valueMultiplierSmall; |             const valueMultiplier = valueMultiplierSmall; | ||||||
|             const erc1155ContractAddress = erc1155Wrapper.getContract().address; |             const erc1155ContractAddress = erc1155Wrapper.getContract().address; | ||||||
|             const assetData = await devUtils.encodeERC1155AssetData.callAsync( |             const assetData = assetDataContract | ||||||
|                 erc1155ContractAddress, |                 .ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData) | ||||||
|                 tokensToTransfer, |                 .getABIEncodedTransactionData(); | ||||||
|                 valuesToTransfer, |  | ||||||
|                 receiverCallbackData, |  | ||||||
|             ); |  | ||||||
|             // The asset data we just generated will look like this: |             // The asset data we just generated will look like this: | ||||||
|             // a7cb5fb7 |             // a7cb5fb7 | ||||||
|             // 0x         0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082 |             // 0x         0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082 | ||||||
| @@ -1079,12 +1075,9 @@ describe('ERC1155Proxy', () => { | |||||||
|             const valuesToTransfer = [fungibleValueToTransferLarge]; |             const valuesToTransfer = [fungibleValueToTransferLarge]; | ||||||
|             const valueMultiplier = valueMultiplierSmall; |             const valueMultiplier = valueMultiplierSmall; | ||||||
|             const erc1155ContractAddress = erc1155Wrapper.getContract().address; |             const erc1155ContractAddress = erc1155Wrapper.getContract().address; | ||||||
|             const assetData = await devUtils.encodeERC1155AssetData.callAsync( |             const assetData = assetDataContract | ||||||
|                 erc1155ContractAddress, |                 .ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData) | ||||||
|                 tokensToTransfer, |                 .getABIEncodedTransactionData(); | ||||||
|                 valuesToTransfer, |  | ||||||
|                 receiverCallbackData, |  | ||||||
|             ); |  | ||||||
|             // The asset data we just generated will look like this: |             // The asset data we just generated will look like this: | ||||||
|             // a7cb5fb7 |             // a7cb5fb7 | ||||||
|             // 0x         0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082 |             // 0x         0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082 | ||||||
| @@ -1130,12 +1123,9 @@ describe('ERC1155Proxy', () => { | |||||||
|             const valuesToTransfer = [fungibleValueToTransferLarge]; |             const valuesToTransfer = [fungibleValueToTransferLarge]; | ||||||
|             const valueMultiplier = valueMultiplierSmall; |             const valueMultiplier = valueMultiplierSmall; | ||||||
|             const erc1155ContractAddress = erc1155Wrapper.getContract().address; |             const erc1155ContractAddress = erc1155Wrapper.getContract().address; | ||||||
|             const assetData = await devUtils.encodeERC1155AssetData.callAsync( |             const assetData = assetDataContract | ||||||
|                 erc1155ContractAddress, |                 .ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData) | ||||||
|                 tokensToTransfer, |                 .getABIEncodedTransactionData(); | ||||||
|                 valuesToTransfer, |  | ||||||
|                 receiverCallbackData, |  | ||||||
|             ); |  | ||||||
|             // The asset data we just generated will look like this: |             // The asset data we just generated will look like this: | ||||||
|             // a7cb5fb7 |             // a7cb5fb7 | ||||||
|             // 0x         0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082 |             // 0x         0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082 | ||||||
| @@ -1181,12 +1171,9 @@ describe('ERC1155Proxy', () => { | |||||||
|             const valuesToTransfer = [fungibleValueToTransferLarge]; |             const valuesToTransfer = [fungibleValueToTransferLarge]; | ||||||
|             const valueMultiplier = valueMultiplierSmall; |             const valueMultiplier = valueMultiplierSmall; | ||||||
|             const erc1155ContractAddress = erc1155Wrapper.getContract().address; |             const erc1155ContractAddress = erc1155Wrapper.getContract().address; | ||||||
|             const assetData = await devUtils.encodeERC1155AssetData.callAsync( |             const assetData = assetDataContract | ||||||
|                 erc1155ContractAddress, |                 .ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData) | ||||||
|                 tokensToTransfer, |                 .getABIEncodedTransactionData(); | ||||||
|                 valuesToTransfer, |  | ||||||
|                 receiverCallbackData, |  | ||||||
|             ); |  | ||||||
|             // The asset data we just generated will look like this: |             // The asset data we just generated will look like this: | ||||||
|             // a7cb5fb7 |             // a7cb5fb7 | ||||||
|             // 0x         0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082 |             // 0x         0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082 | ||||||
| @@ -1232,12 +1219,9 @@ describe('ERC1155Proxy', () => { | |||||||
|             const valuesToTransfer = [fungibleValueToTransferLarge]; |             const valuesToTransfer = [fungibleValueToTransferLarge]; | ||||||
|             const valueMultiplier = valueMultiplierSmall; |             const valueMultiplier = valueMultiplierSmall; | ||||||
|             const erc1155ContractAddress = erc1155Wrapper.getContract().address; |             const erc1155ContractAddress = erc1155Wrapper.getContract().address; | ||||||
|             const assetData = await devUtils.encodeERC1155AssetData.callAsync( |             const assetData = assetDataContract | ||||||
|                 erc1155ContractAddress, |                 .ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData) | ||||||
|                 tokensToTransfer, |                 .getABIEncodedTransactionData(); | ||||||
|                 valuesToTransfer, |  | ||||||
|                 receiverCallbackData, |  | ||||||
|             ); |  | ||||||
|             // The asset data we just generated will look like this: |             // The asset data we just generated will look like this: | ||||||
|             // a7cb5fb7 |             // a7cb5fb7 | ||||||
|             // 0x         0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082 |             // 0x         0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082 | ||||||
| @@ -1284,12 +1268,9 @@ describe('ERC1155Proxy', () => { | |||||||
|             const valuesToTransfer = [fungibleValueToTransferLarge]; |             const valuesToTransfer = [fungibleValueToTransferLarge]; | ||||||
|             const valueMultiplier = valueMultiplierSmall; |             const valueMultiplier = valueMultiplierSmall; | ||||||
|             const erc1155ContractAddress = erc1155Wrapper.getContract().address; |             const erc1155ContractAddress = erc1155Wrapper.getContract().address; | ||||||
|             const assetData = await devUtils.encodeERC1155AssetData.callAsync( |             const assetData = assetDataContract | ||||||
|                 erc1155ContractAddress, |                 .ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData) | ||||||
|                 tokensToTransfer, |                 .getABIEncodedTransactionData(); | ||||||
|                 valuesToTransfer, |  | ||||||
|                 receiverCallbackData, |  | ||||||
|             ); |  | ||||||
|             // The asset data we just generated will look like this: |             // The asset data we just generated will look like this: | ||||||
|             // a7cb5fb7 |             // a7cb5fb7 | ||||||
|             // 0x         0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082 |             // 0x         0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082 | ||||||
| @@ -1331,12 +1312,9 @@ describe('ERC1155Proxy', () => { | |||||||
|             const valuesToTransfer = [fungibleValueToTransferLarge]; |             const valuesToTransfer = [fungibleValueToTransferLarge]; | ||||||
|             const valueMultiplier = valueMultiplierSmall; |             const valueMultiplier = valueMultiplierSmall; | ||||||
|             const erc1155ContractAddress = erc1155Wrapper.getContract().address; |             const erc1155ContractAddress = erc1155Wrapper.getContract().address; | ||||||
|             const assetData = await devUtils.encodeERC1155AssetData.callAsync( |             const assetData = assetDataContract | ||||||
|                 erc1155ContractAddress, |                 .ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData) | ||||||
|                 tokensToTransfer, |                 .getABIEncodedTransactionData(); | ||||||
|                 valuesToTransfer, |  | ||||||
|                 receiverCallbackData, |  | ||||||
|             ); |  | ||||||
|             // The asset data we just generated will look like this: |             // The asset data we just generated will look like this: | ||||||
|             // a7cb5fb7 |             // a7cb5fb7 | ||||||
|             // 0x         0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082 |             // 0x         0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082 | ||||||
| @@ -1382,12 +1360,9 @@ describe('ERC1155Proxy', () => { | |||||||
|             const valuesToTransfer = [fungibleValueToTransferLarge]; |             const valuesToTransfer = [fungibleValueToTransferLarge]; | ||||||
|             const valueMultiplier = valueMultiplierSmall; |             const valueMultiplier = valueMultiplierSmall; | ||||||
|             const erc1155ContractAddress = erc1155Wrapper.getContract().address; |             const erc1155ContractAddress = erc1155Wrapper.getContract().address; | ||||||
|             const assetData = await devUtils.encodeERC1155AssetData.callAsync( |             const assetData = assetDataContract | ||||||
|                 erc1155ContractAddress, |                 .ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData) | ||||||
|                 tokensToTransfer, |                 .getABIEncodedTransactionData(); | ||||||
|                 valuesToTransfer, |  | ||||||
|                 receiverCallbackData, |  | ||||||
|             ); |  | ||||||
|             // The asset data we just generated will look like this: |             // The asset data we just generated will look like this: | ||||||
|             // a7cb5fb7 |             // a7cb5fb7 | ||||||
|             // 0x         0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082 |             // 0x         0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082 | ||||||
| @@ -1429,12 +1404,9 @@ describe('ERC1155Proxy', () => { | |||||||
|             const valuesToTransfer = [fungibleValueToTransferLarge]; |             const valuesToTransfer = [fungibleValueToTransferLarge]; | ||||||
|             const valueMultiplier = valueMultiplierSmall; |             const valueMultiplier = valueMultiplierSmall; | ||||||
|             const erc1155ContractAddress = erc1155Wrapper.getContract().address; |             const erc1155ContractAddress = erc1155Wrapper.getContract().address; | ||||||
|             const assetData = await devUtils.encodeERC1155AssetData.callAsync( |             const assetData = assetDataContract | ||||||
|                 erc1155ContractAddress, |                 .ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData) | ||||||
|                 tokensToTransfer, |                 .getABIEncodedTransactionData(); | ||||||
|                 valuesToTransfer, |  | ||||||
|                 receiverCallbackData, |  | ||||||
|             ); |  | ||||||
|             // The asset data we just generated will look like this: |             // The asset data we just generated will look like this: | ||||||
|             // a7cb5fb7 |             // a7cb5fb7 | ||||||
|             // 0x         0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082 |             // 0x         0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082 | ||||||
| @@ -1480,12 +1452,9 @@ describe('ERC1155Proxy', () => { | |||||||
|             const valuesToTransfer = [fungibleValueToTransferLarge]; |             const valuesToTransfer = [fungibleValueToTransferLarge]; | ||||||
|             const valueMultiplier = valueMultiplierSmall; |             const valueMultiplier = valueMultiplierSmall; | ||||||
|             const erc1155ContractAddress = erc1155Wrapper.getContract().address; |             const erc1155ContractAddress = erc1155Wrapper.getContract().address; | ||||||
|             const assetData = await devUtils.encodeERC1155AssetData.callAsync( |             const assetData = assetDataContract | ||||||
|                 erc1155ContractAddress, |                 .ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData) | ||||||
|                 tokensToTransfer, |                 .getABIEncodedTransactionData(); | ||||||
|                 valuesToTransfer, |  | ||||||
|                 receiverCallbackData, |  | ||||||
|             ); |  | ||||||
|             const txData = await erc1155ProxyWrapper.getTransferFromAbiEncodedTxDataAsync( |             const txData = await erc1155ProxyWrapper.getTransferFromAbiEncodedTxDataAsync( | ||||||
|                 spender, |                 spender, | ||||||
|                 receiverContract, |                 receiverContract, | ||||||
| @@ -1511,12 +1480,9 @@ describe('ERC1155Proxy', () => { | |||||||
|             const valuesToTransfer = [fungibleValueToTransferLarge]; |             const valuesToTransfer = [fungibleValueToTransferLarge]; | ||||||
|             const valueMultiplier = valueMultiplierSmall; |             const valueMultiplier = valueMultiplierSmall; | ||||||
|             const erc1155ContractAddress = erc1155Wrapper.getContract().address; |             const erc1155ContractAddress = erc1155Wrapper.getContract().address; | ||||||
|             const assetData = await devUtils.encodeERC1155AssetData.callAsync( |             const assetData = assetDataContract | ||||||
|                 erc1155ContractAddress, |                 .ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData) | ||||||
|                 tokensToTransfer, |                 .getABIEncodedTransactionData(); | ||||||
|                 valuesToTransfer, |  | ||||||
|                 receiverCallbackData, |  | ||||||
|             ); |  | ||||||
|             const txData = await erc1155ProxyWrapper.getTransferFromAbiEncodedTxDataAsync( |             const txData = await erc1155ProxyWrapper.getTransferFromAbiEncodedTxDataAsync( | ||||||
|                 spender, |                 spender, | ||||||
|                 receiverContract, |                 receiverContract, | ||||||
| @@ -1640,7 +1606,7 @@ describe('ERC1155Proxy', () => { | |||||||
|         it('should propagate revert reason from erc1155 contract failure', async () => { |         it('should propagate revert reason from erc1155 contract failure', async () => { | ||||||
|             // disable transfers |             // disable transfers | ||||||
|             const shouldRejectTransfer = true; |             const shouldRejectTransfer = true; | ||||||
|             await erc1155Receiver.setRejectTransferFlag.awaitTransactionSuccessAsync(shouldRejectTransfer, { |             await erc1155Receiver.setRejectTransferFlag(shouldRejectTransfer).awaitTransactionSuccessAsync({ | ||||||
|                 from: owner, |                 from: owner, | ||||||
|             }); |             }); | ||||||
|             // setup test parameters |             // setup test parameters | ||||||
|   | |||||||
| @@ -3,27 +3,22 @@ import { | |||||||
|     constants, |     constants, | ||||||
|     expect, |     expect, | ||||||
|     getRandomInteger, |     getRandomInteger, | ||||||
|     hexLeftPad, |  | ||||||
|     hexRightPad, |  | ||||||
|     hexSlice, |  | ||||||
|     Numberish, |     Numberish, | ||||||
|     randomAddress, |     randomAddress, | ||||||
| } from '@0x/contracts-test-utils'; | } from '@0x/contracts-test-utils'; | ||||||
|  | import { AuthorizableRevertErrors } from '@0x/contracts-utils'; | ||||||
| import { AssetProxyId } from '@0x/types'; | import { AssetProxyId } from '@0x/types'; | ||||||
| import { AbiEncoder, AuthorizableRevertErrors, BigNumber, StringRevertError } from '@0x/utils'; | import { AbiEncoder, BigNumber, hexUtils, StringRevertError } from '@0x/utils'; | ||||||
| import { DecodedLogs } from 'ethereum-types'; | import { DecodedLogs } from 'ethereum-types'; | ||||||
| import * as _ from 'lodash'; | import * as _ from 'lodash'; | ||||||
|  |  | ||||||
| import { | import { artifacts } from './artifacts'; | ||||||
|     artifacts, |  | ||||||
|     ERC20BridgeProxyContract, | import { ERC20BridgeProxyContract, TestERC20BridgeContract } from './wrappers'; | ||||||
|     TestERC20BridgeBridgeWithdrawToEventArgs, |  | ||||||
|     TestERC20BridgeContract, |  | ||||||
| } from '../src'; |  | ||||||
|  |  | ||||||
| blockchainTests.resets('ERC20BridgeProxy unit tests', env => { | blockchainTests.resets('ERC20BridgeProxy unit tests', env => { | ||||||
|     const PROXY_ID = AssetProxyId.ERC20Bridge; |     const PROXY_ID = AssetProxyId.ERC20Bridge; | ||||||
|     const BRIDGE_SUCCESS_RETURN_DATA = hexRightPad(PROXY_ID); |     const BRIDGE_SUCCESS_RETURN_DATA = hexUtils.rightPad(PROXY_ID); | ||||||
|     let owner: string; |     let owner: string; | ||||||
|     let badCaller: string; |     let badCaller: string; | ||||||
|     let assetProxy: ERC20BridgeProxyContract; |     let assetProxy: ERC20BridgeProxyContract; | ||||||
| @@ -44,8 +39,8 @@ blockchainTests.resets('ERC20BridgeProxy unit tests', env => { | |||||||
|             env.txDefaults, |             env.txDefaults, | ||||||
|             artifacts, |             artifacts, | ||||||
|         ); |         ); | ||||||
|         testTokenAddress = await bridgeContract.testToken.callAsync(); |         testTokenAddress = await bridgeContract.testToken().callAsync(); | ||||||
|         await assetProxy.addAuthorizedAddress.awaitTransactionSuccessAsync(owner); |         await assetProxy.addAuthorizedAddress(owner).awaitTransactionSuccessAsync(); | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|     interface AssetDataOpts { |     interface AssetDataOpts { | ||||||
| @@ -102,7 +97,7 @@ blockchainTests.resets('ERC20BridgeProxy unit tests', env => { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     async function setTestTokenBalanceAsync(_owner: string, balance: Numberish): Promise<void> { |     async function setTestTokenBalanceAsync(_owner: string, balance: Numberish): Promise<void> { | ||||||
|         await bridgeContract.setTestTokenBalance.awaitTransactionSuccessAsync(_owner, new BigNumber(balance)); |         await bridgeContract.setTestTokenBalance(_owner, new BigNumber(balance)).awaitTransactionSuccessAsync(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     describe('transferFrom()', () => { |     describe('transferFrom()', () => { | ||||||
| @@ -132,13 +127,9 @@ blockchainTests.resets('ERC20BridgeProxy unit tests', env => { | |||||||
|  |  | ||||||
|         async function transferFromAsync(opts?: Partial<TransferFromOpts>, caller?: string): Promise<DecodedLogs> { |         async function transferFromAsync(opts?: Partial<TransferFromOpts>, caller?: string): Promise<DecodedLogs> { | ||||||
|             const _opts = createTransferFromOpts(opts); |             const _opts = createTransferFromOpts(opts); | ||||||
|             const { logs } = await assetProxy.transferFrom.awaitTransactionSuccessAsync( |             const { logs } = await assetProxy | ||||||
|                 encodeAssetData(_opts.assetData), |                 .transferFrom(encodeAssetData(_opts.assetData), _opts.from, _opts.to, new BigNumber(_opts.amount)) | ||||||
|                 _opts.from, |                 .awaitTransactionSuccessAsync({ from: caller }); | ||||||
|                 _opts.to, |  | ||||||
|                 new BigNumber(_opts.amount), |  | ||||||
|                 { from: caller }, |  | ||||||
|             ); |  | ||||||
|             return (logs as any) as DecodedLogs; |             return (logs as any) as DecodedLogs; | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -164,7 +155,7 @@ blockchainTests.resets('ERC20BridgeProxy unit tests', env => { | |||||||
|             const opts = createTransferFromOpts(); |             const opts = createTransferFromOpts(); | ||||||
|             const logs = await transferFromAsync(opts); |             const logs = await transferFromAsync(opts); | ||||||
|             expect(logs.length).to.eq(1); |             expect(logs.length).to.eq(1); | ||||||
|             const args = logs[0].args as TestERC20BridgeBridgeWithdrawToEventArgs; |             const args = logs[0].args; | ||||||
|             expect(args.tokenAddress).to.eq(opts.assetData.tokenAddress); |             expect(args.tokenAddress).to.eq(opts.assetData.tokenAddress); | ||||||
|             expect(args.from).to.eq(opts.from); |             expect(args.from).to.eq(opts.from); | ||||||
|             expect(args.to).to.eq(opts.to); |             expect(args.to).to.eq(opts.to); | ||||||
| @@ -179,13 +170,10 @@ blockchainTests.resets('ERC20BridgeProxy unit tests', env => { | |||||||
|  |  | ||||||
|         it('fails if asset data is truncated', async () => { |         it('fails if asset data is truncated', async () => { | ||||||
|             const opts = createTransferFromOpts(); |             const opts = createTransferFromOpts(); | ||||||
|             const truncatedAssetData = hexSlice(encodeAssetData(opts.assetData), 0, -1); |             const truncatedAssetData = hexUtils.slice(encodeAssetData(opts.assetData), 0, -1); | ||||||
|             const tx = assetProxy.transferFrom.awaitTransactionSuccessAsync( |             const tx = assetProxy | ||||||
|                 truncatedAssetData, |                 .transferFrom(truncatedAssetData, opts.from, opts.to, new BigNumber(opts.amount)) | ||||||
|                 opts.from, |                 .awaitTransactionSuccessAsync(); | ||||||
|                 opts.to, |  | ||||||
|                 new BigNumber(opts.amount), |  | ||||||
|             ); |  | ||||||
|             return expect(tx).to.be.rejected(); |             return expect(tx).to.be.rejected(); | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
| @@ -206,7 +194,7 @@ blockchainTests.resets('ERC20BridgeProxy unit tests', env => { | |||||||
|             const tx = transferFromAsync({ |             const tx = transferFromAsync({ | ||||||
|                 assetData: createAssetData({ |                 assetData: createAssetData({ | ||||||
|                     bridgeData: createBridgeData({ |                     bridgeData: createBridgeData({ | ||||||
|                         returnData: hexLeftPad('0x1'), |                         returnData: hexUtils.leftPad('0x1'), | ||||||
|                     }), |                     }), | ||||||
|                 }), |                 }), | ||||||
|             }); |             }); | ||||||
| @@ -219,7 +207,7 @@ blockchainTests.resets('ERC20BridgeProxy unit tests', env => { | |||||||
|             const tx = transferFromAsync({ |             const tx = transferFromAsync({ | ||||||
|                 assetData: createAssetData({ |                 assetData: createAssetData({ | ||||||
|                     bridgeData: createBridgeData({ |                     bridgeData: createBridgeData({ | ||||||
|                         returnData: hexRightPad('0x1'), |                         returnData: hexUtils.rightPad('0x1'), | ||||||
|                     }), |                     }), | ||||||
|                 }), |                 }), | ||||||
|             }); |             }); | ||||||
| @@ -281,18 +269,18 @@ blockchainTests.resets('ERC20BridgeProxy unit tests', env => { | |||||||
|         it('retrieves the balance of the encoded token', async () => { |         it('retrieves the balance of the encoded token', async () => { | ||||||
|             const _owner = randomAddress(); |             const _owner = randomAddress(); | ||||||
|             const balance = getRandomInteger(1, 100e18); |             const balance = getRandomInteger(1, 100e18); | ||||||
|             await bridgeContract.setTestTokenBalance.awaitTransactionSuccessAsync(_owner, balance); |             await bridgeContract.setTestTokenBalance(_owner, balance).awaitTransactionSuccessAsync(); | ||||||
|             const assetData = createAssetData({ |             const assetData = createAssetData({ | ||||||
|                 tokenAddress: testTokenAddress, |                 tokenAddress: testTokenAddress, | ||||||
|             }); |             }); | ||||||
|             const actualBalance = await assetProxy.balanceOf.callAsync(encodeAssetData(assetData), _owner); |             const actualBalance = await assetProxy.balanceOf(encodeAssetData(assetData), _owner).callAsync(); | ||||||
|             expect(actualBalance).to.bignumber.eq(balance); |             expect(actualBalance).to.bignumber.eq(balance); | ||||||
|         }); |         }); | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|     describe('getProxyId()', () => { |     describe('getProxyId()', () => { | ||||||
|         it('returns the correct proxy ID', async () => { |         it('returns the correct proxy ID', async () => { | ||||||
|             const proxyId = await assetProxy.getProxyId.callAsync(); |             const proxyId = await assetProxy.getProxyId().callAsync(); | ||||||
|             expect(proxyId).to.eq(PROXY_ID); |             expect(proxyId).to.eq(PROXY_ID); | ||||||
|         }); |         }); | ||||||
|     }); |     }); | ||||||
|   | |||||||
| @@ -4,28 +4,25 @@ import { | |||||||
|     expect, |     expect, | ||||||
|     filterLogsToArguments, |     filterLogsToArguments, | ||||||
|     getRandomInteger, |     getRandomInteger, | ||||||
|     hexLeftPad, |  | ||||||
|     hexRandom, |  | ||||||
|     Numberish, |     Numberish, | ||||||
|     randomAddress, |     randomAddress, | ||||||
|     TransactionHelper, |  | ||||||
| } from '@0x/contracts-test-utils'; | } from '@0x/contracts-test-utils'; | ||||||
| import { AssetProxyId } from '@0x/types'; | import { AssetProxyId } from '@0x/types'; | ||||||
| import { BigNumber, RawRevertError } from '@0x/utils'; | import { BigNumber, hexUtils, RawRevertError } from '@0x/utils'; | ||||||
| import { DecodedLogs } from 'ethereum-types'; | import { DecodedLogs } from 'ethereum-types'; | ||||||
| import * as _ from 'lodash'; | import * as _ from 'lodash'; | ||||||
|  |  | ||||||
|  | import { artifacts } from './artifacts'; | ||||||
|  |  | ||||||
| import { | import { | ||||||
|     artifacts, |  | ||||||
|     TestEth2DaiBridgeContract, |     TestEth2DaiBridgeContract, | ||||||
|     TestEth2DaiBridgeEvents, |     TestEth2DaiBridgeEvents, | ||||||
|     TestEth2DaiBridgeSellAllAmountEventArgs, |     TestEth2DaiBridgeSellAllAmountEventArgs, | ||||||
|     TestEth2DaiBridgeTokenApproveEventArgs, |     TestEth2DaiBridgeTokenApproveEventArgs, | ||||||
|     TestEth2DaiBridgeTokenTransferEventArgs, |     TestEth2DaiBridgeTokenTransferEventArgs, | ||||||
| } from '../src'; | } from './wrappers'; | ||||||
|  |  | ||||||
| blockchainTests.resets('Eth2DaiBridge unit tests', env => { | blockchainTests.resets('Eth2DaiBridge unit tests', env => { | ||||||
|     const txHelper = new TransactionHelper(env.web3Wrapper, artifacts); |  | ||||||
|     let testContract: TestEth2DaiBridgeContract; |     let testContract: TestEth2DaiBridgeContract; | ||||||
|  |  | ||||||
|     before(async () => { |     before(async () => { | ||||||
| @@ -40,7 +37,9 @@ blockchainTests.resets('Eth2DaiBridge unit tests', env => { | |||||||
|     describe('isValidSignature()', () => { |     describe('isValidSignature()', () => { | ||||||
|         it('returns success bytes', async () => { |         it('returns success bytes', async () => { | ||||||
|             const LEGACY_WALLET_MAGIC_VALUE = '0xb0671381'; |             const LEGACY_WALLET_MAGIC_VALUE = '0xb0671381'; | ||||||
|             const result = await testContract.isValidSignature.callAsync(hexRandom(), hexRandom(_.random(0, 32))); |             const result = await testContract | ||||||
|  |                 .isValidSignature(hexUtils.random(), hexUtils.random(_.random(0, 32))) | ||||||
|  |                 .callAsync(); | ||||||
|             expect(result).to.eq(LEGACY_WALLET_MAGIC_VALUE); |             expect(result).to.eq(LEGACY_WALLET_MAGIC_VALUE); | ||||||
|         }); |         }); | ||||||
|     }); |     }); | ||||||
| @@ -72,7 +71,7 @@ blockchainTests.resets('Eth2DaiBridge unit tests', env => { | |||||||
|                 fillAmount: getRandomInteger(1, 100e18), |                 fillAmount: getRandomInteger(1, 100e18), | ||||||
|                 fromTokenBalance: getRandomInteger(1, 100e18), |                 fromTokenBalance: getRandomInteger(1, 100e18), | ||||||
|                 toTokentransferRevertReason: '', |                 toTokentransferRevertReason: '', | ||||||
|                 toTokenTransferReturnData: hexLeftPad(1), |                 toTokenTransferReturnData: hexUtils.leftPad(1), | ||||||
|                 ...opts, |                 ...opts, | ||||||
|             }; |             }; | ||||||
|         } |         } | ||||||
| @@ -80,32 +79,30 @@ blockchainTests.resets('Eth2DaiBridge unit tests', env => { | |||||||
|         async function withdrawToAsync(opts?: Partial<WithdrawToOpts>): Promise<WithdrawToResult> { |         async function withdrawToAsync(opts?: Partial<WithdrawToOpts>): Promise<WithdrawToResult> { | ||||||
|             const _opts = createWithdrawToOpts(opts); |             const _opts = createWithdrawToOpts(opts); | ||||||
|             // Set the fill behavior. |             // Set the fill behavior. | ||||||
|             await testContract.setFillBehavior.awaitTransactionSuccessAsync( |             await testContract | ||||||
|                 _opts.revertReason, |                 .setFillBehavior(_opts.revertReason, new BigNumber(_opts.fillAmount)) | ||||||
|                 new BigNumber(_opts.fillAmount), |                 .awaitTransactionSuccessAsync(); | ||||||
|             ); |  | ||||||
|             // Create tokens and balances. |             // Create tokens and balances. | ||||||
|             if (_opts.fromTokenAddress === undefined) { |             if (_opts.fromTokenAddress === undefined) { | ||||||
|                 [_opts.fromTokenAddress] = await txHelper.getResultAndReceiptAsync( |                 const createTokenFn = testContract.createToken(new BigNumber(_opts.fromTokenBalance)); | ||||||
|                     testContract.createToken, |                 _opts.fromTokenAddress = await createTokenFn.callAsync(); | ||||||
|                     new BigNumber(_opts.fromTokenBalance), |                 await createTokenFn.awaitTransactionSuccessAsync(); | ||||||
|                 ); |  | ||||||
|             } |             } | ||||||
|             if (_opts.toTokenAddress === undefined) { |             if (_opts.toTokenAddress === undefined) { | ||||||
|                 [_opts.toTokenAddress] = await txHelper.getResultAndReceiptAsync( |                 const createTokenFn = testContract.createToken(constants.ZERO_AMOUNT); | ||||||
|                     testContract.createToken, |                 _opts.toTokenAddress = await createTokenFn.callAsync(); | ||||||
|                     constants.ZERO_AMOUNT, |                 await createTokenFn.awaitTransactionSuccessAsync(); | ||||||
|                 ); |  | ||||||
|             } |             } | ||||||
|             // Set the transfer behavior of `toTokenAddress`. |             // Set the transfer behavior of `toTokenAddress`. | ||||||
|             await testContract.setTransferBehavior.awaitTransactionSuccessAsync( |             await testContract | ||||||
|                 _opts.toTokenAddress, |                 .setTransferBehavior( | ||||||
|                 _opts.toTokentransferRevertReason, |                     _opts.toTokenAddress, | ||||||
|                 _opts.toTokenTransferReturnData, |                     _opts.toTokentransferRevertReason, | ||||||
|             ); |                     _opts.toTokenTransferReturnData, | ||||||
|  |                 ) | ||||||
|  |                 .awaitTransactionSuccessAsync(); | ||||||
|             // Call bridgeTransferFrom(). |             // Call bridgeTransferFrom(). | ||||||
|             const [result, { logs }] = await txHelper.getResultAndReceiptAsync( |             const bridgeTransferFromFn = testContract.bridgeTransferFrom( | ||||||
|                 testContract.bridgeTransferFrom, |  | ||||||
|                 // "to" token address |                 // "to" token address | ||||||
|                 _opts.toTokenAddress, |                 _opts.toTokenAddress, | ||||||
|                 // Random from address. |                 // Random from address. | ||||||
| @@ -114,8 +111,10 @@ blockchainTests.resets('Eth2DaiBridge unit tests', env => { | |||||||
|                 _opts.toAddress, |                 _opts.toAddress, | ||||||
|                 new BigNumber(_opts.amount), |                 new BigNumber(_opts.amount), | ||||||
|                 // ABI-encode the "from" token address as the bridge data. |                 // ABI-encode the "from" token address as the bridge data. | ||||||
|                 hexLeftPad(_opts.fromTokenAddress as string), |                 hexUtils.leftPad(_opts.fromTokenAddress as string), | ||||||
|             ); |             ); | ||||||
|  |             const result = await bridgeTransferFromFn.callAsync(); | ||||||
|  |             const { logs } = await bridgeTransferFromFn.awaitTransactionSuccessAsync(); | ||||||
|             return { |             return { | ||||||
|                 opts: _opts, |                 opts: _opts, | ||||||
|                 result, |                 result, | ||||||
| @@ -180,13 +179,13 @@ blockchainTests.resets('Eth2DaiBridge unit tests', env => { | |||||||
|         }); |         }); | ||||||
|  |  | ||||||
|         it('fails if `toTokenAddress.transfer()` returns false', async () => { |         it('fails if `toTokenAddress.transfer()` returns false', async () => { | ||||||
|             const opts = createWithdrawToOpts({ toTokenTransferReturnData: hexLeftPad(0) }); |             const opts = createWithdrawToOpts({ toTokenTransferReturnData: hexUtils.leftPad(0) }); | ||||||
|             const tx = withdrawToAsync(opts); |             const tx = withdrawToAsync(opts); | ||||||
|             return expect(tx).to.revertWith(new RawRevertError(hexLeftPad(0))); |             return expect(tx).to.revertWith(new RawRevertError(hexUtils.leftPad(0))); | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
|         it('succeeds if `toTokenAddress.transfer()` returns true', async () => { |         it('succeeds if `toTokenAddress.transfer()` returns true', async () => { | ||||||
|             await withdrawToAsync({ toTokenTransferReturnData: hexLeftPad(1) }); |             await withdrawToAsync({ toTokenTransferReturnData: hexUtils.leftPad(1) }); | ||||||
|         }); |         }); | ||||||
|     }); |     }); | ||||||
| }); | }); | ||||||
|   | |||||||
							
								
								
									
										284
									
								
								contracts/asset-proxy/test/kyber_bridge.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										284
									
								
								contracts/asset-proxy/test/kyber_bridge.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,284 @@ | |||||||
|  | import { | ||||||
|  |     blockchainTests, | ||||||
|  |     constants, | ||||||
|  |     expect, | ||||||
|  |     getRandomInteger, | ||||||
|  |     getRandomPortion, | ||||||
|  |     randomAddress, | ||||||
|  |     verifyEventsFromLogs, | ||||||
|  | } from '@0x/contracts-test-utils'; | ||||||
|  | import { AssetProxyId } from '@0x/types'; | ||||||
|  | import { BigNumber, hexUtils } from '@0x/utils'; | ||||||
|  | import { DecodedLogs } from 'ethereum-types'; | ||||||
|  | import * as _ from 'lodash'; | ||||||
|  |  | ||||||
|  | import { artifacts } from './artifacts'; | ||||||
|  |  | ||||||
|  | import { TestKyberBridgeContract, TestKyberBridgeEvents } from './wrappers'; | ||||||
|  |  | ||||||
|  | // TODO(dorothy-zbornak): Tests need to be updated. | ||||||
|  | blockchainTests.resets.skip('KyberBridge unit tests', env => { | ||||||
|  |     const KYBER_ETH_ADDRESS = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee'; | ||||||
|  |     const FROM_TOKEN_DECIMALS = 6; | ||||||
|  |     const TO_TOKEN_DECIMALS = 18; | ||||||
|  |     const FROM_TOKEN_BASE = new BigNumber(10).pow(FROM_TOKEN_DECIMALS); | ||||||
|  |     const TO_TOKEN_BASE = new BigNumber(10).pow(TO_TOKEN_DECIMALS); | ||||||
|  |     const WETH_BASE = new BigNumber(10).pow(18); | ||||||
|  |     const KYBER_RATE_BASE = WETH_BASE; | ||||||
|  |     let testContract: TestKyberBridgeContract; | ||||||
|  |  | ||||||
|  |     before(async () => { | ||||||
|  |         testContract = await TestKyberBridgeContract.deployFrom0xArtifactAsync( | ||||||
|  |             artifacts.TestKyberBridge, | ||||||
|  |             env.provider, | ||||||
|  |             env.txDefaults, | ||||||
|  |             artifacts, | ||||||
|  |         ); | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     describe('isValidSignature()', () => { | ||||||
|  |         it('returns success bytes', async () => { | ||||||
|  |             const LEGACY_WALLET_MAGIC_VALUE = '0xb0671381'; | ||||||
|  |             const result = await testContract | ||||||
|  |                 .isValidSignature(hexUtils.random(), hexUtils.random(_.random(0, 32))) | ||||||
|  |                 .callAsync(); | ||||||
|  |             expect(result).to.eq(LEGACY_WALLET_MAGIC_VALUE); | ||||||
|  |         }); | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     describe('bridgeTransferFrom()', () => { | ||||||
|  |         let fromTokenAddress: string; | ||||||
|  |         let toTokenAddress: string; | ||||||
|  |         let wethAddress: string; | ||||||
|  |  | ||||||
|  |         before(async () => { | ||||||
|  |             wethAddress = await testContract.weth().callAsync(); | ||||||
|  |             fromTokenAddress = await testContract.createToken(FROM_TOKEN_DECIMALS).callAsync(); | ||||||
|  |             await testContract.createToken(FROM_TOKEN_DECIMALS).awaitTransactionSuccessAsync(); | ||||||
|  |             toTokenAddress = await testContract.createToken(TO_TOKEN_DECIMALS).callAsync(); | ||||||
|  |             await testContract.createToken(TO_TOKEN_DECIMALS).awaitTransactionSuccessAsync(); | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         const STATIC_KYBER_TRADE_ARGS = { | ||||||
|  |             maxBuyTokenAmount: constants.MAX_UINT256, | ||||||
|  |             walletId: constants.NULL_ADDRESS, | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         interface TransferFromOpts { | ||||||
|  |             toTokenAddress: string; | ||||||
|  |             fromTokenAddress: string; | ||||||
|  |             toAddress: string; | ||||||
|  |             // Amount to pass into `bridgeTransferFrom()` | ||||||
|  |             amount: BigNumber; | ||||||
|  |             // Amount to convert in `trade()`. | ||||||
|  |             fillAmount: BigNumber; | ||||||
|  |             // Token balance of the bridge. | ||||||
|  |             fromTokenBalance: BigNumber; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         interface TransferFromResult { | ||||||
|  |             opts: TransferFromOpts; | ||||||
|  |             result: string; | ||||||
|  |             logs: DecodedLogs; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         function createTransferFromOpts(opts?: Partial<TransferFromOpts>): TransferFromOpts { | ||||||
|  |             const amount = getRandomInteger(1, TO_TOKEN_BASE.times(100)); | ||||||
|  |             return { | ||||||
|  |                 fromTokenAddress, | ||||||
|  |                 toTokenAddress, | ||||||
|  |                 amount, | ||||||
|  |                 toAddress: randomAddress(), | ||||||
|  |                 fillAmount: getRandomPortion(amount), | ||||||
|  |                 fromTokenBalance: getRandomInteger(1, FROM_TOKEN_BASE.times(100)), | ||||||
|  |                 ...opts, | ||||||
|  |             }; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         async function withdrawToAsync(opts?: Partial<TransferFromOpts>): Promise<TransferFromResult> { | ||||||
|  |             const _opts = createTransferFromOpts(opts); | ||||||
|  |             // Fund the contract with input tokens. | ||||||
|  |             await testContract | ||||||
|  |                 .grantTokensTo(_opts.fromTokenAddress, testContract.address, _opts.fromTokenBalance) | ||||||
|  |                 .awaitTransactionSuccessAsync({ value: _opts.fromTokenBalance }); | ||||||
|  |             // Fund the contract with output tokens. | ||||||
|  |             await testContract.setNextFillAmount(_opts.fillAmount).awaitTransactionSuccessAsync({ | ||||||
|  |                 value: _opts.toTokenAddress === wethAddress ? _opts.fillAmount : constants.ZERO_AMOUNT, | ||||||
|  |             }); | ||||||
|  |             // Call bridgeTransferFrom(). | ||||||
|  |             const bridgeTransferFromFn = testContract.bridgeTransferFrom( | ||||||
|  |                 // Output token | ||||||
|  |                 _opts.toTokenAddress, | ||||||
|  |                 // Random maker address. | ||||||
|  |                 randomAddress(), | ||||||
|  |                 // Recipient address. | ||||||
|  |                 _opts.toAddress, | ||||||
|  |                 // Transfer amount. | ||||||
|  |                 _opts.amount, | ||||||
|  |                 // ABI-encode the input token address as the bridge data. | ||||||
|  |                 hexUtils.concat(hexUtils.leftPad(_opts.fromTokenAddress), hexUtils.leftPad(32), hexUtils.leftPad(0)), | ||||||
|  |             ); | ||||||
|  |             const result = await bridgeTransferFromFn.callAsync(); | ||||||
|  |             const { logs } = await bridgeTransferFromFn.awaitTransactionSuccessAsync(); | ||||||
|  |             return { | ||||||
|  |                 opts: _opts, | ||||||
|  |                 result, | ||||||
|  |                 logs: (logs as any) as DecodedLogs, | ||||||
|  |             }; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         function getMinimumConversionRate(opts: TransferFromOpts): BigNumber { | ||||||
|  |             const fromBase = opts.fromTokenAddress === wethAddress ? WETH_BASE : FROM_TOKEN_BASE; | ||||||
|  |             const toBase = opts.toTokenAddress === wethAddress ? WETH_BASE : TO_TOKEN_BASE; | ||||||
|  |             return opts.amount | ||||||
|  |                 .div(toBase) | ||||||
|  |                 .div(opts.fromTokenBalance.div(fromBase)) | ||||||
|  |                 .times(KYBER_RATE_BASE) | ||||||
|  |                 .integerValue(BigNumber.ROUND_DOWN); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         it('returns magic bytes on success', async () => { | ||||||
|  |             const BRIDGE_SUCCESS_RETURN_DATA = AssetProxyId.ERC20Bridge; | ||||||
|  |             const { result } = await withdrawToAsync(); | ||||||
|  |             expect(result).to.eq(BRIDGE_SUCCESS_RETURN_DATA); | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         it('can trade token -> token', async () => { | ||||||
|  |             const { opts, logs } = await withdrawToAsync(); | ||||||
|  |             verifyEventsFromLogs( | ||||||
|  |                 logs, | ||||||
|  |                 [ | ||||||
|  |                     { | ||||||
|  |                         sellTokenAddress: opts.fromTokenAddress, | ||||||
|  |                         buyTokenAddress: opts.toTokenAddress, | ||||||
|  |                         sellAmount: opts.fromTokenBalance, | ||||||
|  |                         recipientAddress: opts.toAddress, | ||||||
|  |                         minConversionRate: getMinimumConversionRate(opts), | ||||||
|  |                         msgValue: constants.ZERO_AMOUNT, | ||||||
|  |                         ...STATIC_KYBER_TRADE_ARGS, | ||||||
|  |                     }, | ||||||
|  |                 ], | ||||||
|  |                 TestKyberBridgeEvents.KyberBridgeTrade, | ||||||
|  |             ); | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         it('can trade token -> ETH', async () => { | ||||||
|  |             const { opts, logs } = await withdrawToAsync({ | ||||||
|  |                 toTokenAddress: wethAddress, | ||||||
|  |             }); | ||||||
|  |             verifyEventsFromLogs( | ||||||
|  |                 logs, | ||||||
|  |                 [ | ||||||
|  |                     { | ||||||
|  |                         sellTokenAddress: opts.fromTokenAddress, | ||||||
|  |                         buyTokenAddress: KYBER_ETH_ADDRESS, | ||||||
|  |                         sellAmount: opts.fromTokenBalance, | ||||||
|  |                         recipientAddress: testContract.address, | ||||||
|  |                         minConversionRate: getMinimumConversionRate(opts), | ||||||
|  |                         msgValue: constants.ZERO_AMOUNT, | ||||||
|  |                         ...STATIC_KYBER_TRADE_ARGS, | ||||||
|  |                     }, | ||||||
|  |                 ], | ||||||
|  |                 TestKyberBridgeEvents.KyberBridgeTrade, | ||||||
|  |             ); | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         it('can trade ETH -> token', async () => { | ||||||
|  |             const { opts, logs } = await withdrawToAsync({ | ||||||
|  |                 fromTokenAddress: wethAddress, | ||||||
|  |             }); | ||||||
|  |             verifyEventsFromLogs( | ||||||
|  |                 logs, | ||||||
|  |                 [ | ||||||
|  |                     { | ||||||
|  |                         sellTokenAddress: KYBER_ETH_ADDRESS, | ||||||
|  |                         buyTokenAddress: opts.toTokenAddress, | ||||||
|  |                         sellAmount: opts.fromTokenBalance, | ||||||
|  |                         recipientAddress: opts.toAddress, | ||||||
|  |                         minConversionRate: getMinimumConversionRate(opts), | ||||||
|  |                         msgValue: opts.fromTokenBalance, | ||||||
|  |                         ...STATIC_KYBER_TRADE_ARGS, | ||||||
|  |                     }, | ||||||
|  |                 ], | ||||||
|  |                 TestKyberBridgeEvents.KyberBridgeTrade, | ||||||
|  |             ); | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         it('does nothing if bridge has no token balance', async () => { | ||||||
|  |             const { logs } = await withdrawToAsync({ | ||||||
|  |                 fromTokenBalance: constants.ZERO_AMOUNT, | ||||||
|  |             }); | ||||||
|  |             expect(logs).to.be.length(0); | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         it('only transfers the token if trading the same token', async () => { | ||||||
|  |             const { opts, logs } = await withdrawToAsync({ | ||||||
|  |                 toTokenAddress: fromTokenAddress, | ||||||
|  |             }); | ||||||
|  |             verifyEventsFromLogs( | ||||||
|  |                 logs, | ||||||
|  |                 [ | ||||||
|  |                     { | ||||||
|  |                         tokenAddress: fromTokenAddress, | ||||||
|  |                         ownerAddress: testContract.address, | ||||||
|  |                         recipientAddress: opts.toAddress, | ||||||
|  |                         amount: opts.fromTokenBalance, | ||||||
|  |                     }, | ||||||
|  |                 ], | ||||||
|  |                 TestKyberBridgeEvents.KyberBridgeTokenTransfer, | ||||||
|  |             ); | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         it('grants Kyber an allowance when selling non-WETH', async () => { | ||||||
|  |             const { opts, logs } = await withdrawToAsync(); | ||||||
|  |             verifyEventsFromLogs( | ||||||
|  |                 logs, | ||||||
|  |                 [ | ||||||
|  |                     { | ||||||
|  |                         tokenAddress: opts.fromTokenAddress, | ||||||
|  |                         ownerAddress: testContract.address, | ||||||
|  |                         spenderAddress: testContract.address, | ||||||
|  |                         allowance: constants.MAX_UINT256, | ||||||
|  |                     }, | ||||||
|  |                 ], | ||||||
|  |                 TestKyberBridgeEvents.KyberBridgeTokenApprove, | ||||||
|  |             ); | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         it('does not grant Kyber an allowance when selling WETH', async () => { | ||||||
|  |             const { logs } = await withdrawToAsync({ | ||||||
|  |                 fromTokenAddress: wethAddress, | ||||||
|  |             }); | ||||||
|  |             verifyEventsFromLogs(logs, [], TestKyberBridgeEvents.KyberBridgeTokenApprove); | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         it('withdraws WETH and passes it to Kyber when selling WETH', async () => { | ||||||
|  |             const { opts, logs } = await withdrawToAsync({ | ||||||
|  |                 fromTokenAddress: wethAddress, | ||||||
|  |             }); | ||||||
|  |             expect(logs[0].event).to.eq(TestKyberBridgeEvents.KyberBridgeWethWithdraw); | ||||||
|  |             expect(logs[0].args).to.deep.eq({ | ||||||
|  |                 ownerAddress: testContract.address, | ||||||
|  |                 amount: opts.fromTokenBalance, | ||||||
|  |             }); | ||||||
|  |             expect(logs[1].event).to.eq(TestKyberBridgeEvents.KyberBridgeTrade); | ||||||
|  |             expect(logs[1].args.msgValue).to.bignumber.eq(opts.fromTokenBalance); | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         it('wraps WETH and transfers it to the recipient when buyng WETH', async () => { | ||||||
|  |             const { opts, logs } = await withdrawToAsync({ | ||||||
|  |                 toTokenAddress: wethAddress, | ||||||
|  |             }); | ||||||
|  |             expect(logs[0].event).to.eq(TestKyberBridgeEvents.KyberBridgeTokenApprove); | ||||||
|  |             expect(logs[0].args.tokenAddress).to.eq(opts.fromTokenAddress); | ||||||
|  |             expect(logs[1].event).to.eq(TestKyberBridgeEvents.KyberBridgeTrade); | ||||||
|  |             expect(logs[1].args.recipientAddress).to.eq(testContract.address); | ||||||
|  |             expect(logs[2].event).to.eq(TestKyberBridgeEvents.KyberBridgeWethDeposit); | ||||||
|  |             expect(logs[2].args).to.deep.eq({ | ||||||
|  |                 msgValue: opts.fillAmount, | ||||||
|  |                 ownerAddress: testContract.address, | ||||||
|  |                 amount: opts.fillAmount, | ||||||
|  |             }); | ||||||
|  |         }); | ||||||
|  |     }); | ||||||
|  | }); | ||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,8 +1,6 @@ | |||||||
| import { DevUtilsContract } from '@0x/contracts-dev-utils'; |  | ||||||
| import { | import { | ||||||
|     chaiSetup, |     chaiSetup, | ||||||
|     constants, |     constants, | ||||||
|     expectTransactionFailedAsync, |  | ||||||
|     expectTransactionFailedWithoutReasonAsync, |     expectTransactionFailedWithoutReasonAsync, | ||||||
|     provider, |     provider, | ||||||
|     txDefaults, |     txDefaults, | ||||||
| @@ -14,7 +12,14 @@ import { AbiEncoder, BigNumber } from '@0x/utils'; | |||||||
| import * as chai from 'chai'; | import * as chai from 'chai'; | ||||||
| import * as ethUtil from 'ethereumjs-util'; | import * as ethUtil from 'ethereumjs-util'; | ||||||
|  |  | ||||||
| import { artifacts, IAssetProxyContract, StaticCallProxyContract, TestStaticCallTargetContract } from '../src'; | import { artifacts } from './artifacts'; | ||||||
|  |  | ||||||
|  | import { | ||||||
|  |     IAssetDataContract, | ||||||
|  |     IAssetProxyContract, | ||||||
|  |     StaticCallProxyContract, | ||||||
|  |     TestStaticCallTargetContract, | ||||||
|  | } from './wrappers'; | ||||||
|  |  | ||||||
| chaiSetup.configure(); | chaiSetup.configure(); | ||||||
| const expect = chai.expect; | const expect = chai.expect; | ||||||
| @@ -25,7 +30,7 @@ describe('StaticCallProxy', () => { | |||||||
|     let fromAddress: string; |     let fromAddress: string; | ||||||
|     let toAddress: string; |     let toAddress: string; | ||||||
|  |  | ||||||
|     let devUtils: DevUtilsContract; |     let assetDataInterface: IAssetDataContract; | ||||||
|     let staticCallProxy: IAssetProxyContract; |     let staticCallProxy: IAssetProxyContract; | ||||||
|     let staticCallTarget: TestStaticCallTargetContract; |     let staticCallTarget: TestStaticCallTargetContract; | ||||||
|  |  | ||||||
| @@ -44,7 +49,7 @@ describe('StaticCallProxy', () => { | |||||||
|             txDefaults, |             txDefaults, | ||||||
|             artifacts, |             artifacts, | ||||||
|         ); |         ); | ||||||
|         devUtils = new DevUtilsContract(constants.NULL_ADDRESS, provider); |         assetDataInterface = new IAssetDataContract(constants.NULL_ADDRESS, provider); | ||||||
|         staticCallProxy = new IAssetProxyContract( |         staticCallProxy = new IAssetProxyContract( | ||||||
|             staticCallProxyWithoutTransferFrom.address, |             staticCallProxyWithoutTransferFrom.address, | ||||||
|             provider, |             provider, | ||||||
| @@ -79,26 +84,21 @@ describe('StaticCallProxy', () => { | |||||||
|             ); |             ); | ||||||
|         }); |         }); | ||||||
|         it('should have an id of 0xc339d10a', async () => { |         it('should have an id of 0xc339d10a', async () => { | ||||||
|             const proxyId = await staticCallProxy.getProxyId.callAsync(); |             const proxyId = await staticCallProxy.getProxyId().callAsync(); | ||||||
|             const expectedProxyId = AssetProxyId.StaticCall; |             const expectedProxyId = AssetProxyId.StaticCall; | ||||||
|             expect(proxyId).to.equal(expectedProxyId); |             expect(proxyId).to.equal(expectedProxyId); | ||||||
|         }); |         }); | ||||||
|     }); |     }); | ||||||
|     describe('transferFrom', () => { |     describe('transferFrom', () => { | ||||||
|         it('should revert if assetData lies outside the bounds of calldata', async () => { |         it('should revert if assetData lies outside the bounds of calldata', async () => { | ||||||
|             const staticCallData = staticCallTarget.noInputFunction.getABIEncodedTransactionData(); |             const staticCallData = staticCallTarget.noInputFunction().getABIEncodedTransactionData(); | ||||||
|             const expectedResultHash = constants.KECCAK256_NULL; |             const expectedResultHash = constants.KECCAK256_NULL; | ||||||
|             const assetData = await devUtils.encodeStaticCallAssetData.callAsync( |             const assetData = assetDataInterface | ||||||
|                 staticCallTarget.address, |                 .StaticCall(staticCallTarget.address, staticCallData, expectedResultHash) | ||||||
|                 staticCallData, |                 .getABIEncodedTransactionData(); | ||||||
|                 expectedResultHash, |             const txData = staticCallProxy | ||||||
|             ); |                 .transferFrom(assetData, fromAddress, toAddress, amount) | ||||||
|             const txData = staticCallProxy.transferFrom.getABIEncodedTransactionData( |                 .getABIEncodedTransactionData(); | ||||||
|                 assetData, |  | ||||||
|                 fromAddress, |  | ||||||
|                 toAddress, |  | ||||||
|                 amount, |  | ||||||
|             ); |  | ||||||
|             const offsetToAssetData = '0000000000000000000000000000000000000000000000000000000000000080'; |             const offsetToAssetData = '0000000000000000000000000000000000000000000000000000000000000080'; | ||||||
|             const txDataEndBuffer = ethUtil.toBuffer((txData.length - 2) / 2 - 4); |             const txDataEndBuffer = ethUtil.toBuffer((txData.length - 2) / 2 - 4); | ||||||
|             const paddedTxDataEndBuffer = ethUtil.setLengthLeft(txDataEndBuffer, 32); |             const paddedTxDataEndBuffer = ethUtil.setLengthLeft(txDataEndBuffer, 32); | ||||||
| @@ -116,25 +116,22 @@ describe('StaticCallProxy', () => { | |||||||
|         it('should revert if the length of assetData is less than 100 bytes', async () => { |         it('should revert if the length of assetData is less than 100 bytes', async () => { | ||||||
|             const staticCallData = constants.NULL_BYTES; |             const staticCallData = constants.NULL_BYTES; | ||||||
|             const expectedResultHash = constants.KECCAK256_NULL; |             const expectedResultHash = constants.KECCAK256_NULL; | ||||||
|             const assetData = (await devUtils.encodeStaticCallAssetData.callAsync( |             const assetData = assetDataInterface | ||||||
|                 staticCallTarget.address, |                 .StaticCall(staticCallTarget.address, staticCallData, expectedResultHash) | ||||||
|                 staticCallData, |                 .getABIEncodedTransactionData() | ||||||
|                 expectedResultHash, |                 .slice(0, -128); | ||||||
|             )).slice(0, -128); |  | ||||||
|             const assetDataByteLen = (assetData.length - 2) / 2; |             const assetDataByteLen = (assetData.length - 2) / 2; | ||||||
|             expect((assetDataByteLen - 4) % 32).to.equal(0); |             expect((assetDataByteLen - 4) % 32).to.equal(0); | ||||||
|             await expectTransactionFailedWithoutReasonAsync( |             await expectTransactionFailedWithoutReasonAsync( | ||||||
|                 staticCallProxy.transferFrom.sendTransactionAsync(assetData, fromAddress, toAddress, amount), |                 staticCallProxy.transferFrom(assetData, fromAddress, toAddress, amount).sendTransactionAsync(), | ||||||
|             ); |             ); | ||||||
|         }); |         }); | ||||||
|         it('should revert if the offset to `staticCallData` points to outside of assetData', async () => { |         it('should revert if the offset to `staticCallData` points to outside of assetData', async () => { | ||||||
|             const staticCallData = staticCallTarget.noInputFunction.getABIEncodedTransactionData(); |             const staticCallData = staticCallTarget.noInputFunction().getABIEncodedTransactionData(); | ||||||
|             const expectedResultHash = constants.KECCAK256_NULL; |             const expectedResultHash = constants.KECCAK256_NULL; | ||||||
|             const assetData = await devUtils.encodeStaticCallAssetData.callAsync( |             const assetData = assetDataInterface | ||||||
|                 staticCallTarget.address, |                 .StaticCall(staticCallTarget.address, staticCallData, expectedResultHash) | ||||||
|                 staticCallData, |                 .getABIEncodedTransactionData(); | ||||||
|                 expectedResultHash, |  | ||||||
|             ); |  | ||||||
|             const offsetToStaticCallData = '0000000000000000000000000000000000000000000000000000000000000060'; |             const offsetToStaticCallData = '0000000000000000000000000000000000000000000000000000000000000060'; | ||||||
|             const assetDataEndBuffer = ethUtil.toBuffer((assetData.length - 2) / 2 - 4); |             const assetDataEndBuffer = ethUtil.toBuffer((assetData.length - 2) / 2 - 4); | ||||||
|             const paddedAssetDataEndBuffer = ethUtil.setLengthLeft(assetDataEndBuffer, 32); |             const paddedAssetDataEndBuffer = ethUtil.setLengthLeft(assetDataEndBuffer, 32); | ||||||
| @@ -145,94 +142,86 @@ describe('StaticCallProxy', () => { | |||||||
|                 invalidOffsetToStaticCallData, |                 invalidOffsetToStaticCallData, | ||||||
|             )}${newStaticCallData}`; |             )}${newStaticCallData}`; | ||||||
|             await expectTransactionFailedWithoutReasonAsync( |             await expectTransactionFailedWithoutReasonAsync( | ||||||
|                 staticCallProxy.transferFrom.sendTransactionAsync(badAssetData, fromAddress, toAddress, amount), |                 staticCallProxy.transferFrom(badAssetData, fromAddress, toAddress, amount).sendTransactionAsync(), | ||||||
|             ); |             ); | ||||||
|         }); |         }); | ||||||
|         it('should revert if the callTarget attempts to write to state', async () => { |         it('should revert if the callTarget attempts to write to state', async () => { | ||||||
|             const staticCallData = staticCallTarget.updateState.getABIEncodedTransactionData(); |             const staticCallData = staticCallTarget.updateState().getABIEncodedTransactionData(); | ||||||
|             const expectedResultHash = constants.KECCAK256_NULL; |             const expectedResultHash = constants.KECCAK256_NULL; | ||||||
|             const assetData = await devUtils.encodeStaticCallAssetData.callAsync( |             const assetData = assetDataInterface | ||||||
|                 staticCallTarget.address, |                 .StaticCall(staticCallTarget.address, staticCallData, expectedResultHash) | ||||||
|                 staticCallData, |                 .getABIEncodedTransactionData(); | ||||||
|                 expectedResultHash, |  | ||||||
|             ); |  | ||||||
|             await expectTransactionFailedWithoutReasonAsync( |             await expectTransactionFailedWithoutReasonAsync( | ||||||
|                 staticCallProxy.transferFrom.sendTransactionAsync(assetData, fromAddress, toAddress, amount), |                 staticCallProxy.transferFrom(assetData, fromAddress, toAddress, amount).sendTransactionAsync(), | ||||||
|             ); |             ); | ||||||
|         }); |         }); | ||||||
|         it('should revert with data provided by the callTarget if the staticcall reverts', async () => { |         it('should revert with data provided by the callTarget if the staticcall reverts', async () => { | ||||||
|             const staticCallData = staticCallTarget.assertEvenNumber.getABIEncodedTransactionData(new BigNumber(1)); |             const staticCallData = staticCallTarget.assertEvenNumber(new BigNumber(1)).getABIEncodedTransactionData(); | ||||||
|             const expectedResultHash = constants.KECCAK256_NULL; |             const expectedResultHash = constants.KECCAK256_NULL; | ||||||
|             const assetData = await devUtils.encodeStaticCallAssetData.callAsync( |             const assetData = assetDataInterface | ||||||
|                 staticCallTarget.address, |                 .StaticCall(staticCallTarget.address, staticCallData, expectedResultHash) | ||||||
|                 staticCallData, |                 .getABIEncodedTransactionData(); | ||||||
|                 expectedResultHash, |             return expect( | ||||||
|             ); |                 staticCallProxy.transferFrom(assetData, fromAddress, toAddress, amount).awaitTransactionSuccessAsync(), | ||||||
|             await expectTransactionFailedAsync( |             ).to.revertWith(RevertReason.TargetNotEven); | ||||||
|                 staticCallProxy.transferFrom.sendTransactionAsync(assetData, fromAddress, toAddress, amount), |  | ||||||
|                 RevertReason.TargetNotEven, |  | ||||||
|             ); |  | ||||||
|         }); |         }); | ||||||
|         it('should revert if the hash of the output is different than expected expected', async () => { |         it('should revert if the hash of the output is different than expected expected', async () => { | ||||||
|             const staticCallData = staticCallTarget.isOddNumber.getABIEncodedTransactionData(new BigNumber(0)); |             const staticCallData = staticCallTarget.isOddNumber(new BigNumber(0)).getABIEncodedTransactionData(); | ||||||
|             const trueAsBuffer = ethUtil.toBuffer('0x0000000000000000000000000000000000000000000000000000000000000001'); |             const trueAsBuffer = ethUtil.toBuffer('0x0000000000000000000000000000000000000000000000000000000000000001'); | ||||||
|             const expectedResultHash = ethUtil.bufferToHex(ethUtil.sha3(trueAsBuffer)); |             const expectedResultHash = ethUtil.bufferToHex(ethUtil.sha3(trueAsBuffer)); | ||||||
|             const assetData = await devUtils.encodeStaticCallAssetData.callAsync( |             const assetData = assetDataInterface | ||||||
|                 staticCallTarget.address, |                 .StaticCall(staticCallTarget.address, staticCallData, expectedResultHash) | ||||||
|                 staticCallData, |                 .getABIEncodedTransactionData(); | ||||||
|                 expectedResultHash, |             return expect( | ||||||
|             ); |                 staticCallProxy.transferFrom(assetData, fromAddress, toAddress, amount).awaitTransactionSuccessAsync(), | ||||||
|             await expectTransactionFailedAsync( |             ).to.revertWith(RevertReason.UnexpectedStaticCallResult); | ||||||
|                 staticCallProxy.transferFrom.sendTransactionAsync(assetData, fromAddress, toAddress, amount), |  | ||||||
|                 RevertReason.UnexpectedStaticCallResult, |  | ||||||
|             ); |  | ||||||
|         }); |         }); | ||||||
|         it('should be successful if a function call with no inputs and no outputs is successful', async () => { |         it('should be successful if a function call with no inputs and no outputs is successful', async () => { | ||||||
|             const staticCallData = staticCallTarget.noInputFunction.getABIEncodedTransactionData(); |             const staticCallData = staticCallTarget.noInputFunction().getABIEncodedTransactionData(); | ||||||
|             const expectedResultHash = constants.KECCAK256_NULL; |             const expectedResultHash = constants.KECCAK256_NULL; | ||||||
|             const assetData = await devUtils.encodeStaticCallAssetData.callAsync( |             const assetData = assetDataInterface | ||||||
|                 staticCallTarget.address, |                 .StaticCall(staticCallTarget.address, staticCallData, expectedResultHash) | ||||||
|                 staticCallData, |                 .getABIEncodedTransactionData(); | ||||||
|                 expectedResultHash, |             await staticCallProxy | ||||||
|             ); |                 .transferFrom(assetData, fromAddress, toAddress, amount) | ||||||
|             await staticCallProxy.transferFrom.awaitTransactionSuccessAsync(assetData, fromAddress, toAddress, amount); |                 .awaitTransactionSuccessAsync(); | ||||||
|         }); |         }); | ||||||
|         it('should be successful if the staticCallTarget is not a contract and no return value is expected', async () => { |         it('should be successful if the staticCallTarget is not a contract and no return value is expected', async () => { | ||||||
|             const staticCallData = '0x0102030405060708'; |             const staticCallData = '0x0102030405060708'; | ||||||
|             const expectedResultHash = constants.KECCAK256_NULL; |             const expectedResultHash = constants.KECCAK256_NULL; | ||||||
|             const assetData = await devUtils.encodeStaticCallAssetData.callAsync( |             const assetData = assetDataInterface | ||||||
|                 toAddress, |                 .StaticCall(toAddress, staticCallData, expectedResultHash) | ||||||
|                 staticCallData, |                 .getABIEncodedTransactionData(); | ||||||
|                 expectedResultHash, |             await staticCallProxy | ||||||
|             ); |                 .transferFrom(assetData, fromAddress, toAddress, amount) | ||||||
|             await staticCallProxy.transferFrom.awaitTransactionSuccessAsync(assetData, fromAddress, toAddress, amount); |                 .awaitTransactionSuccessAsync(); | ||||||
|         }); |         }); | ||||||
|         it('should be successful if a function call with one static input returns the correct value', async () => { |         it('should be successful if a function call with one static input returns the correct value', async () => { | ||||||
|             const staticCallData = staticCallTarget.isOddNumber.getABIEncodedTransactionData(new BigNumber(1)); |             const staticCallData = staticCallTarget.isOddNumber(new BigNumber(1)).getABIEncodedTransactionData(); | ||||||
|             const trueAsBuffer = ethUtil.toBuffer('0x0000000000000000000000000000000000000000000000000000000000000001'); |             const trueAsBuffer = ethUtil.toBuffer('0x0000000000000000000000000000000000000000000000000000000000000001'); | ||||||
|             const expectedResultHash = ethUtil.bufferToHex(ethUtil.sha3(trueAsBuffer)); |             const expectedResultHash = ethUtil.bufferToHex(ethUtil.sha3(trueAsBuffer)); | ||||||
|             const assetData = await devUtils.encodeStaticCallAssetData.callAsync( |             const assetData = assetDataInterface | ||||||
|                 staticCallTarget.address, |                 .StaticCall(staticCallTarget.address, staticCallData, expectedResultHash) | ||||||
|                 staticCallData, |                 .getABIEncodedTransactionData(); | ||||||
|                 expectedResultHash, |             await staticCallProxy | ||||||
|             ); |                 .transferFrom(assetData, fromAddress, toAddress, amount) | ||||||
|             await staticCallProxy.transferFrom.awaitTransactionSuccessAsync(assetData, fromAddress, toAddress, amount); |                 .awaitTransactionSuccessAsync(); | ||||||
|         }); |         }); | ||||||
|         it('should be successful if a function with one dynamic input is successful', async () => { |         it('should be successful if a function with one dynamic input is successful', async () => { | ||||||
|             const dynamicInput = '0x0102030405060708'; |             const dynamicInput = '0x0102030405060708'; | ||||||
|             const staticCallData = staticCallTarget.dynamicInputFunction.getABIEncodedTransactionData(dynamicInput); |             const staticCallData = staticCallTarget.dynamicInputFunction(dynamicInput).getABIEncodedTransactionData(); | ||||||
|             const expectedResultHash = constants.KECCAK256_NULL; |             const expectedResultHash = constants.KECCAK256_NULL; | ||||||
|             const assetData = await devUtils.encodeStaticCallAssetData.callAsync( |             const assetData = assetDataInterface | ||||||
|                 staticCallTarget.address, |                 .StaticCall(staticCallTarget.address, staticCallData, expectedResultHash) | ||||||
|                 staticCallData, |                 .getABIEncodedTransactionData(); | ||||||
|                 expectedResultHash, |             await staticCallProxy | ||||||
|             ); |                 .transferFrom(assetData, fromAddress, toAddress, amount) | ||||||
|             await staticCallProxy.transferFrom.awaitTransactionSuccessAsync(assetData, fromAddress, toAddress, amount); |                 .awaitTransactionSuccessAsync(); | ||||||
|         }); |         }); | ||||||
|         it('should be successful if a function call returns a complex type', async () => { |         it('should be successful if a function call returns a complex type', async () => { | ||||||
|             const a = new BigNumber(1); |             const a = new BigNumber(1); | ||||||
|             const b = new BigNumber(2); |             const b = new BigNumber(2); | ||||||
|             const staticCallData = staticCallTarget.returnComplexType.getABIEncodedTransactionData(a, b); |             const staticCallData = staticCallTarget.returnComplexType(a, b).getABIEncodedTransactionData(); | ||||||
|             const abiEncoder = new AbiEncoder.DynamicBytes({ |             const abiEncoder = new AbiEncoder.DynamicBytes({ | ||||||
|                 name: '', |                 name: '', | ||||||
|                 type: 'bytes', |                 type: 'bytes', | ||||||
| @@ -245,12 +234,12 @@ describe('StaticCallProxy', () => { | |||||||
|             const expectedResultHash = ethUtil.bufferToHex( |             const expectedResultHash = ethUtil.bufferToHex( | ||||||
|                 ethUtil.sha3(ethUtil.toBuffer(encodedExpectedResultWithOffset)), |                 ethUtil.sha3(ethUtil.toBuffer(encodedExpectedResultWithOffset)), | ||||||
|             ); |             ); | ||||||
|             const assetData = await devUtils.encodeStaticCallAssetData.callAsync( |             const assetData = assetDataInterface | ||||||
|                 staticCallTarget.address, |                 .StaticCall(staticCallTarget.address, staticCallData, expectedResultHash) | ||||||
|                 staticCallData, |                 .getABIEncodedTransactionData(); | ||||||
|                 expectedResultHash, |             await staticCallProxy | ||||||
|             ); |                 .transferFrom(assetData, fromAddress, toAddress, amount) | ||||||
|             await staticCallProxy.transferFrom.awaitTransactionSuccessAsync(assetData, fromAddress, toAddress, amount); |                 .awaitTransactionSuccessAsync(); | ||||||
|         }); |         }); | ||||||
|     }); |     }); | ||||||
| }); | }); | ||||||
|   | |||||||
| @@ -5,19 +5,17 @@ import { | |||||||
|     filterLogs, |     filterLogs, | ||||||
|     filterLogsToArguments, |     filterLogsToArguments, | ||||||
|     getRandomInteger, |     getRandomInteger, | ||||||
|     hexLeftPad, |  | ||||||
|     hexRandom, |  | ||||||
|     Numberish, |     Numberish, | ||||||
|     randomAddress, |     randomAddress, | ||||||
|     TransactionHelper, |  | ||||||
| } from '@0x/contracts-test-utils'; | } from '@0x/contracts-test-utils'; | ||||||
| import { AssetProxyId } from '@0x/types'; | import { AssetProxyId } from '@0x/types'; | ||||||
| import { BigNumber } from '@0x/utils'; | import { BigNumber, hexUtils } from '@0x/utils'; | ||||||
| import { DecodedLogs } from 'ethereum-types'; | import { DecodedLogs } from 'ethereum-types'; | ||||||
| import * as _ from 'lodash'; | import * as _ from 'lodash'; | ||||||
|  |  | ||||||
|  | import { artifacts } from './artifacts'; | ||||||
|  |  | ||||||
| import { | import { | ||||||
|     artifacts, |  | ||||||
|     TestUniswapBridgeContract, |     TestUniswapBridgeContract, | ||||||
|     TestUniswapBridgeEthToTokenTransferInputEventArgs as EthToTokenTransferInputArgs, |     TestUniswapBridgeEthToTokenTransferInputEventArgs as EthToTokenTransferInputArgs, | ||||||
|     TestUniswapBridgeEvents as ContractEvents, |     TestUniswapBridgeEvents as ContractEvents, | ||||||
| @@ -27,10 +25,9 @@ import { | |||||||
|     TestUniswapBridgeTokenTransferEventArgs as TokenTransferArgs, |     TestUniswapBridgeTokenTransferEventArgs as TokenTransferArgs, | ||||||
|     TestUniswapBridgeWethDepositEventArgs as WethDepositArgs, |     TestUniswapBridgeWethDepositEventArgs as WethDepositArgs, | ||||||
|     TestUniswapBridgeWethWithdrawEventArgs as WethWithdrawArgs, |     TestUniswapBridgeWethWithdrawEventArgs as WethWithdrawArgs, | ||||||
| } from '../src'; | } from './wrappers'; | ||||||
|  |  | ||||||
| blockchainTests.resets('UniswapBridge unit tests', env => { | blockchainTests.resets('UniswapBridge unit tests', env => { | ||||||
|     const txHelper = new TransactionHelper(env.web3Wrapper, artifacts); |  | ||||||
|     let testContract: TestUniswapBridgeContract; |     let testContract: TestUniswapBridgeContract; | ||||||
|     let wethTokenAddress: string; |     let wethTokenAddress: string; | ||||||
|  |  | ||||||
| @@ -41,13 +38,15 @@ blockchainTests.resets('UniswapBridge unit tests', env => { | |||||||
|             env.txDefaults, |             env.txDefaults, | ||||||
|             artifacts, |             artifacts, | ||||||
|         ); |         ); | ||||||
|         wethTokenAddress = await testContract.wethToken.callAsync(); |         wethTokenAddress = await testContract.wethToken().callAsync(); | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|     describe('isValidSignature()', () => { |     describe('isValidSignature()', () => { | ||||||
|         it('returns success bytes', async () => { |         it('returns success bytes', async () => { | ||||||
|             const LEGACY_WALLET_MAGIC_VALUE = '0xb0671381'; |             const LEGACY_WALLET_MAGIC_VALUE = '0xb0671381'; | ||||||
|             const result = await testContract.isValidSignature.callAsync(hexRandom(), hexRandom(_.random(0, 32))); |             const result = await testContract | ||||||
|  |                 .isValidSignature(hexUtils.random(), hexUtils.random(_.random(0, 32))) | ||||||
|  |                 .callAsync(); | ||||||
|             expect(result).to.eq(LEGACY_WALLET_MAGIC_VALUE); |             expect(result).to.eq(LEGACY_WALLET_MAGIC_VALUE); | ||||||
|         }); |         }); | ||||||
|     }); |     }); | ||||||
| @@ -89,35 +88,35 @@ blockchainTests.resets('UniswapBridge unit tests', env => { | |||||||
|  |  | ||||||
|         async function withdrawToAsync(opts?: Partial<WithdrawToOpts>): Promise<WithdrawToResult> { |         async function withdrawToAsync(opts?: Partial<WithdrawToOpts>): Promise<WithdrawToResult> { | ||||||
|             const _opts = createWithdrawToOpts(opts); |             const _opts = createWithdrawToOpts(opts); | ||||||
|  |             const callData = { value: new BigNumber(_opts.exchangeFillAmount) }; | ||||||
|             // Create the "from" token and exchange. |             // Create the "from" token and exchange. | ||||||
|             [[_opts.fromTokenAddress]] = await txHelper.getResultAndReceiptAsync( |             const createFromTokenFn = testContract.createTokenAndExchange( | ||||||
|                 testContract.createTokenAndExchange, |  | ||||||
|                 _opts.fromTokenAddress, |                 _opts.fromTokenAddress, | ||||||
|                 _opts.exchangeRevertReason, |                 _opts.exchangeRevertReason, | ||||||
|                 { value: new BigNumber(_opts.exchangeFillAmount) }, |  | ||||||
|             ); |             ); | ||||||
|  |             [_opts.fromTokenAddress] = await createFromTokenFn.callAsync(callData); | ||||||
|  |             await createFromTokenFn.awaitTransactionSuccessAsync(callData); | ||||||
|  |  | ||||||
|             // Create the "to" token and exchange. |             // Create the "to" token and exchange. | ||||||
|             [[_opts.toTokenAddress]] = await txHelper.getResultAndReceiptAsync( |             const createToTokenFn = testContract.createTokenAndExchange( | ||||||
|                 testContract.createTokenAndExchange, |  | ||||||
|                 _opts.toTokenAddress, |                 _opts.toTokenAddress, | ||||||
|                 _opts.exchangeRevertReason, |                 _opts.exchangeRevertReason, | ||||||
|                 { value: new BigNumber(_opts.exchangeFillAmount) }, |  | ||||||
|             ); |  | ||||||
|             await testContract.setTokenRevertReason.awaitTransactionSuccessAsync( |  | ||||||
|                 _opts.toTokenAddress, |  | ||||||
|                 _opts.toTokenRevertReason, |  | ||||||
|             ); |  | ||||||
|             await testContract.setTokenRevertReason.awaitTransactionSuccessAsync( |  | ||||||
|                 _opts.fromTokenAddress, |  | ||||||
|                 _opts.fromTokenRevertReason, |  | ||||||
|             ); |             ); | ||||||
|  |             [_opts.toTokenAddress] = await createToTokenFn.callAsync(callData); | ||||||
|  |             await createToTokenFn.awaitTransactionSuccessAsync(callData); | ||||||
|  |  | ||||||
|  |             await testContract | ||||||
|  |                 .setTokenRevertReason(_opts.toTokenAddress, _opts.toTokenRevertReason) | ||||||
|  |                 .awaitTransactionSuccessAsync(); | ||||||
|  |             await testContract | ||||||
|  |                 .setTokenRevertReason(_opts.fromTokenAddress, _opts.fromTokenRevertReason) | ||||||
|  |                 .awaitTransactionSuccessAsync(); | ||||||
|             // Set the token balance for the token we're converting from. |             // Set the token balance for the token we're converting from. | ||||||
|             await testContract.setTokenBalance.awaitTransactionSuccessAsync(_opts.fromTokenAddress, { |             await testContract.setTokenBalance(_opts.fromTokenAddress).awaitTransactionSuccessAsync({ | ||||||
|                 value: new BigNumber(_opts.fromTokenBalance), |                 value: new BigNumber(_opts.fromTokenBalance), | ||||||
|             }); |             }); | ||||||
|             // Call bridgeTransferFrom(). |             // Call bridgeTransferFrom(). | ||||||
|             const [result, receipt] = await txHelper.getResultAndReceiptAsync( |             const bridgeTransferFromFn = testContract.bridgeTransferFrom( | ||||||
|                 testContract.bridgeTransferFrom, |  | ||||||
|                 // The "to" token address. |                 // The "to" token address. | ||||||
|                 _opts.toTokenAddress, |                 _opts.toTokenAddress, | ||||||
|                 // The "from" address. |                 // The "from" address. | ||||||
| @@ -127,8 +126,10 @@ blockchainTests.resets('UniswapBridge unit tests', env => { | |||||||
|                 // The amount to transfer to "to" |                 // The amount to transfer to "to" | ||||||
|                 new BigNumber(_opts.amount), |                 new BigNumber(_opts.amount), | ||||||
|                 // ABI-encoded "from" token address. |                 // ABI-encoded "from" token address. | ||||||
|                 hexLeftPad(_opts.fromTokenAddress), |                 hexUtils.leftPad(_opts.fromTokenAddress), | ||||||
|             ); |             ); | ||||||
|  |             const result = await bridgeTransferFromFn.callAsync(); | ||||||
|  |             const receipt = await bridgeTransferFromFn.awaitTransactionSuccessAsync(); | ||||||
|             return { |             return { | ||||||
|                 opts: _opts, |                 opts: _opts, | ||||||
|                 result, |                 result, | ||||||
| @@ -138,7 +139,7 @@ blockchainTests.resets('UniswapBridge unit tests', env => { | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         async function getExchangeForTokenAsync(tokenAddress: string): Promise<string> { |         async function getExchangeForTokenAsync(tokenAddress: string): Promise<string> { | ||||||
|             return testContract.getExchange.callAsync(tokenAddress); |             return testContract.getExchange(tokenAddress).callAsync(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         it('returns magic bytes on success', async () => { |         it('returns magic bytes on success', async () => { | ||||||
| @@ -147,11 +148,9 @@ blockchainTests.resets('UniswapBridge unit tests', env => { | |||||||
|         }); |         }); | ||||||
|  |  | ||||||
|         it('just transfers tokens to `to` if the same tokens are in play', async () => { |         it('just transfers tokens to `to` if the same tokens are in play', async () => { | ||||||
|             const [[tokenAddress]] = await txHelper.getResultAndReceiptAsync( |             const createTokenFn = await testContract.createTokenAndExchange(constants.NULL_ADDRESS, ''); | ||||||
|                 testContract.createTokenAndExchange, |             const [tokenAddress] = await createTokenFn.callAsync(); | ||||||
|                 constants.NULL_ADDRESS, |             await createTokenFn.awaitTransactionSuccessAsync(); | ||||||
|                 '', |  | ||||||
|             ); |  | ||||||
|             const { opts, result, logs } = await withdrawToAsync({ |             const { opts, result, logs } = await withdrawToAsync({ | ||||||
|                 fromTokenAddress: tokenAddress, |                 fromTokenAddress: tokenAddress, | ||||||
|                 toTokenAddress: tokenAddress, |                 toTokenAddress: tokenAddress, | ||||||
| @@ -177,7 +176,7 @@ blockchainTests.resets('UniswapBridge unit tests', env => { | |||||||
|                 expect(calls[0].exchange).to.eq(exchangeAddress); |                 expect(calls[0].exchange).to.eq(exchangeAddress); | ||||||
|                 expect(calls[0].tokensSold).to.bignumber.eq(opts.fromTokenBalance); |                 expect(calls[0].tokensSold).to.bignumber.eq(opts.fromTokenBalance); | ||||||
|                 expect(calls[0].minTokensBought).to.bignumber.eq(opts.amount); |                 expect(calls[0].minTokensBought).to.bignumber.eq(opts.amount); | ||||||
|                 expect(calls[0].minEthBought).to.bignumber.eq(0); |                 expect(calls[0].minEthBought).to.bignumber.eq(1); | ||||||
|                 expect(calls[0].deadline).to.bignumber.eq(blockTime); |                 expect(calls[0].deadline).to.bignumber.eq(blockTime); | ||||||
|                 expect(calls[0].recipient).to.eq(opts.toAddress); |                 expect(calls[0].recipient).to.eq(opts.toAddress); | ||||||
|                 expect(calls[0].toTokenAddress).to.eq(opts.toTokenAddress); |                 expect(calls[0].toTokenAddress).to.eq(opts.toTokenAddress); | ||||||
| @@ -203,14 +202,16 @@ blockchainTests.resets('UniswapBridge unit tests', env => { | |||||||
|             }); |             }); | ||||||
|  |  | ||||||
|             it('fails if "from" token does not exist', async () => { |             it('fails if "from" token does not exist', async () => { | ||||||
|                 const tx = testContract.bridgeTransferFrom.awaitTransactionSuccessAsync( |                 const tx = testContract | ||||||
|                     randomAddress(), |                     .bridgeTransferFrom( | ||||||
|                     randomAddress(), |                         randomAddress(), | ||||||
|                     randomAddress(), |                         randomAddress(), | ||||||
|                     getRandomInteger(1, 1e18), |                         randomAddress(), | ||||||
|                     hexLeftPad(randomAddress()), |                         getRandomInteger(1, 1e18), | ||||||
|                 ); |                         hexUtils.leftPad(randomAddress()), | ||||||
|                 return expect(tx).to.revertWith('NO_UNISWAP_EXCHANGE_FOR_TOKEN'); |                     ) | ||||||
|  |                     .awaitTransactionSuccessAsync(); | ||||||
|  |                 return expect(tx).to.eventually.be.rejectedWith('NO_UNISWAP_EXCHANGE_FOR_TOKEN'); | ||||||
|             }); |             }); | ||||||
|  |  | ||||||
|             it('fails if the exchange fails', async () => { |             it('fails if the exchange fails', async () => { | ||||||
| @@ -218,7 +219,7 @@ blockchainTests.resets('UniswapBridge unit tests', env => { | |||||||
|                 const tx = withdrawToAsync({ |                 const tx = withdrawToAsync({ | ||||||
|                     exchangeRevertReason: revertReason, |                     exchangeRevertReason: revertReason, | ||||||
|                 }); |                 }); | ||||||
|                 return expect(tx).to.revertWith(revertReason); |                 return expect(tx).to.eventually.be.rejectedWith(revertReason); | ||||||
|             }); |             }); | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
| @@ -275,14 +276,16 @@ blockchainTests.resets('UniswapBridge unit tests', env => { | |||||||
|             }); |             }); | ||||||
|  |  | ||||||
|             it('fails if "from" token does not exist', async () => { |             it('fails if "from" token does not exist', async () => { | ||||||
|                 const tx = testContract.bridgeTransferFrom.awaitTransactionSuccessAsync( |                 const tx = testContract | ||||||
|                     randomAddress(), |                     .bridgeTransferFrom( | ||||||
|                     randomAddress(), |                         randomAddress(), | ||||||
|                     randomAddress(), |                         randomAddress(), | ||||||
|                     getRandomInteger(1, 1e18), |                         randomAddress(), | ||||||
|                     hexLeftPad(wethTokenAddress), |                         getRandomInteger(1, 1e18), | ||||||
|                 ); |                         hexUtils.leftPad(wethTokenAddress), | ||||||
|                 return expect(tx).to.revertWith('NO_UNISWAP_EXCHANGE_FOR_TOKEN'); |                     ) | ||||||
|  |                     .awaitTransactionSuccessAsync(); | ||||||
|  |                 return expect(tx).to.eventually.be.rejectedWith('NO_UNISWAP_EXCHANGE_FOR_TOKEN'); | ||||||
|             }); |             }); | ||||||
|  |  | ||||||
|             it('fails if `WETH.deposit()` fails', async () => { |             it('fails if `WETH.deposit()` fails', async () => { | ||||||
| @@ -291,7 +294,7 @@ blockchainTests.resets('UniswapBridge unit tests', env => { | |||||||
|                     toTokenAddress: wethTokenAddress, |                     toTokenAddress: wethTokenAddress, | ||||||
|                     toTokenRevertReason: revertReason, |                     toTokenRevertReason: revertReason, | ||||||
|                 }); |                 }); | ||||||
|                 return expect(tx).to.revertWith(revertReason); |                 return expect(tx).to.eventually.be.rejectedWith(revertReason); | ||||||
|             }); |             }); | ||||||
|  |  | ||||||
|             it('fails if the exchange fails', async () => { |             it('fails if the exchange fails', async () => { | ||||||
| @@ -300,7 +303,7 @@ blockchainTests.resets('UniswapBridge unit tests', env => { | |||||||
|                     toTokenAddress: wethTokenAddress, |                     toTokenAddress: wethTokenAddress, | ||||||
|                     exchangeRevertReason: revertReason, |                     exchangeRevertReason: revertReason, | ||||||
|                 }); |                 }); | ||||||
|                 return expect(tx).to.revertWith(revertReason); |                 return expect(tx).to.eventually.be.rejectedWith(revertReason); | ||||||
|             }); |             }); | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
| @@ -333,14 +336,16 @@ blockchainTests.resets('UniswapBridge unit tests', env => { | |||||||
|             }); |             }); | ||||||
|  |  | ||||||
|             it('fails if "to" token does not exist', async () => { |             it('fails if "to" token does not exist', async () => { | ||||||
|                 const tx = testContract.bridgeTransferFrom.awaitTransactionSuccessAsync( |                 const tx = testContract | ||||||
|                     wethTokenAddress, |                     .bridgeTransferFrom( | ||||||
|                     randomAddress(), |                         wethTokenAddress, | ||||||
|                     randomAddress(), |                         randomAddress(), | ||||||
|                     getRandomInteger(1, 1e18), |                         randomAddress(), | ||||||
|                     hexLeftPad(randomAddress()), |                         getRandomInteger(1, 1e18), | ||||||
|                 ); |                         hexUtils.leftPad(randomAddress()), | ||||||
|                 return expect(tx).to.revertWith('NO_UNISWAP_EXCHANGE_FOR_TOKEN'); |                     ) | ||||||
|  |                     .awaitTransactionSuccessAsync(); | ||||||
|  |                 return expect(tx).to.eventually.be.rejectedWith('NO_UNISWAP_EXCHANGE_FOR_TOKEN'); | ||||||
|             }); |             }); | ||||||
|  |  | ||||||
|             it('fails if the `WETH.withdraw()` fails', async () => { |             it('fails if the `WETH.withdraw()` fails', async () => { | ||||||
| @@ -349,7 +354,7 @@ blockchainTests.resets('UniswapBridge unit tests', env => { | |||||||
|                     fromTokenAddress: wethTokenAddress, |                     fromTokenAddress: wethTokenAddress, | ||||||
|                     fromTokenRevertReason: revertReason, |                     fromTokenRevertReason: revertReason, | ||||||
|                 }); |                 }); | ||||||
|                 return expect(tx).to.revertWith(revertReason); |                 return expect(tx).to.eventually.be.rejectedWith(revertReason); | ||||||
|             }); |             }); | ||||||
|  |  | ||||||
|             it('fails if the exchange fails', async () => { |             it('fails if the exchange fails', async () => { | ||||||
| @@ -358,7 +363,7 @@ blockchainTests.resets('UniswapBridge unit tests', env => { | |||||||
|                     fromTokenAddress: wethTokenAddress, |                     fromTokenAddress: wethTokenAddress, | ||||||
|                     exchangeRevertReason: revertReason, |                     exchangeRevertReason: revertReason, | ||||||
|                 }); |                 }); | ||||||
|                 return expect(tx).to.revertWith(revertReason); |                 return expect(tx).to.eventually.be.rejectedWith(revertReason); | ||||||
|             }); |             }); | ||||||
|         }); |         }); | ||||||
|     }); |     }); | ||||||
|   | |||||||
							
								
								
									
										216
									
								
								contracts/asset-proxy/test/uniswapv2_bridge.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										216
									
								
								contracts/asset-proxy/test/uniswapv2_bridge.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,216 @@ | |||||||
|  | import { | ||||||
|  |     blockchainTests, | ||||||
|  |     constants, | ||||||
|  |     expect, | ||||||
|  |     filterLogsToArguments, | ||||||
|  |     getRandomInteger, | ||||||
|  |     randomAddress, | ||||||
|  | } from '@0x/contracts-test-utils'; | ||||||
|  | import { AssetProxyId } from '@0x/types'; | ||||||
|  | import { AbiEncoder, BigNumber, hexUtils } from '@0x/utils'; | ||||||
|  | import { DecodedLogs } from 'ethereum-types'; | ||||||
|  | import * as _ from 'lodash'; | ||||||
|  |  | ||||||
|  | import { artifacts } from './artifacts'; | ||||||
|  |  | ||||||
|  | import { | ||||||
|  |     TestUniswapV2BridgeContract, | ||||||
|  |     TestUniswapV2BridgeEvents as ContractEvents, | ||||||
|  |     TestUniswapV2BridgeSwapExactTokensForTokensInputEventArgs as SwapExactTokensForTokensArgs, | ||||||
|  |     TestUniswapV2BridgeTokenApproveEventArgs as TokenApproveArgs, | ||||||
|  |     TestUniswapV2BridgeTokenTransferEventArgs as TokenTransferArgs, | ||||||
|  | } from './wrappers'; | ||||||
|  |  | ||||||
|  | blockchainTests.resets('UniswapV2 unit tests', env => { | ||||||
|  |     const FROM_TOKEN_DECIMALS = 6; | ||||||
|  |     const TO_TOKEN_DECIMALS = 18; | ||||||
|  |     const FROM_TOKEN_BASE = new BigNumber(10).pow(FROM_TOKEN_DECIMALS); | ||||||
|  |     const TO_TOKEN_BASE = new BigNumber(10).pow(TO_TOKEN_DECIMALS); | ||||||
|  |     let testContract: TestUniswapV2BridgeContract; | ||||||
|  |  | ||||||
|  |     before(async () => { | ||||||
|  |         testContract = await TestUniswapV2BridgeContract.deployFrom0xArtifactAsync( | ||||||
|  |             artifacts.TestUniswapV2Bridge, | ||||||
|  |             env.provider, | ||||||
|  |             env.txDefaults, | ||||||
|  |             artifacts, | ||||||
|  |         ); | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     describe('isValidSignature()', () => { | ||||||
|  |         it('returns success bytes', async () => { | ||||||
|  |             const LEGACY_WALLET_MAGIC_VALUE = '0xb0671381'; | ||||||
|  |             const result = await testContract | ||||||
|  |                 .isValidSignature(hexUtils.random(), hexUtils.random(_.random(0, 32))) | ||||||
|  |                 .callAsync(); | ||||||
|  |             expect(result).to.eq(LEGACY_WALLET_MAGIC_VALUE); | ||||||
|  |         }); | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     describe('bridgeTransferFrom()', () => { | ||||||
|  |         interface TransferFromOpts { | ||||||
|  |             tokenAddressesPath: string[]; | ||||||
|  |             toAddress: string; | ||||||
|  |             // Amount to pass into `bridgeTransferFrom()` | ||||||
|  |             amount: BigNumber; | ||||||
|  |             // Token balance of the bridge. | ||||||
|  |             fromTokenBalance: BigNumber; | ||||||
|  |             // Router reverts with this reason | ||||||
|  |             routerRevertReason: string; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         interface TransferFromResult { | ||||||
|  |             opts: TransferFromOpts; | ||||||
|  |             result: string; | ||||||
|  |             logs: DecodedLogs; | ||||||
|  |             blocktime: number; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         function createTransferFromOpts(opts?: Partial<TransferFromOpts>): TransferFromOpts { | ||||||
|  |             const amount = getRandomInteger(1, TO_TOKEN_BASE.times(100)); | ||||||
|  |             return { | ||||||
|  |                 tokenAddressesPath: Array(2).fill(constants.NULL_ADDRESS), | ||||||
|  |                 amount, | ||||||
|  |                 toAddress: randomAddress(), | ||||||
|  |                 fromTokenBalance: getRandomInteger(1, FROM_TOKEN_BASE.times(100)), | ||||||
|  |                 routerRevertReason: '', | ||||||
|  |                 ...opts, | ||||||
|  |             }; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         const bridgeDataEncoder = AbiEncoder.create('(address[])'); | ||||||
|  |  | ||||||
|  |         async function transferFromAsync(opts?: Partial<TransferFromOpts>): Promise<TransferFromResult> { | ||||||
|  |             const _opts = createTransferFromOpts(opts); | ||||||
|  |  | ||||||
|  |             for (let i = 0; i < _opts.tokenAddressesPath.length; i++) { | ||||||
|  |                 const createFromTokenFn = testContract.createToken(_opts.tokenAddressesPath[i]); | ||||||
|  |                 _opts.tokenAddressesPath[i] = await createFromTokenFn.callAsync(); | ||||||
|  |                 await createFromTokenFn.awaitTransactionSuccessAsync(); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             // Set the token balance for the token we're converting from. | ||||||
|  |             await testContract | ||||||
|  |                 .setTokenBalance(_opts.tokenAddressesPath[0], _opts.fromTokenBalance) | ||||||
|  |                 .awaitTransactionSuccessAsync(); | ||||||
|  |  | ||||||
|  |             // Set revert reason for the router. | ||||||
|  |             await testContract.setRouterRevertReason(_opts.routerRevertReason).awaitTransactionSuccessAsync(); | ||||||
|  |  | ||||||
|  |             // Call bridgeTransferFrom(). | ||||||
|  |             const bridgeTransferFromFn = testContract.bridgeTransferFrom( | ||||||
|  |                 // Output token | ||||||
|  |                 _opts.tokenAddressesPath[_opts.tokenAddressesPath.length - 1], | ||||||
|  |                 // Random maker address. | ||||||
|  |                 randomAddress(), | ||||||
|  |                 // Recipient address. | ||||||
|  |                 _opts.toAddress, | ||||||
|  |                 // Transfer amount. | ||||||
|  |                 _opts.amount, | ||||||
|  |                 // ABI-encode the input token address as the bridge data. // FIXME | ||||||
|  |                 bridgeDataEncoder.encode([_opts.tokenAddressesPath]), | ||||||
|  |             ); | ||||||
|  |             const result = await bridgeTransferFromFn.callAsync(); | ||||||
|  |             const receipt = await bridgeTransferFromFn.awaitTransactionSuccessAsync(); | ||||||
|  |             return { | ||||||
|  |                 opts: _opts, | ||||||
|  |                 result, | ||||||
|  |                 logs: (receipt.logs as any) as DecodedLogs, | ||||||
|  |                 blocktime: await env.web3Wrapper.getBlockTimestampAsync(receipt.blockNumber), | ||||||
|  |             }; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         it('returns magic bytes on success', async () => { | ||||||
|  |             const { result } = await transferFromAsync(); | ||||||
|  |             expect(result).to.eq(AssetProxyId.ERC20Bridge); | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         it('performs transfer when both tokens are the same', async () => { | ||||||
|  |             const createTokenFn = testContract.createToken(constants.NULL_ADDRESS); | ||||||
|  |             const tokenAddress = await createTokenFn.callAsync(); | ||||||
|  |             await createTokenFn.awaitTransactionSuccessAsync(); | ||||||
|  |  | ||||||
|  |             const { opts, result, logs } = await transferFromAsync({ | ||||||
|  |                 tokenAddressesPath: [tokenAddress, tokenAddress], | ||||||
|  |             }); | ||||||
|  |             expect(result).to.eq(AssetProxyId.ERC20Bridge, 'asset proxy id'); | ||||||
|  |             const transfers = filterLogsToArguments<TokenTransferArgs>(logs, ContractEvents.TokenTransfer); | ||||||
|  |  | ||||||
|  |             expect(transfers.length).to.eq(1); | ||||||
|  |             expect(transfers[0].token).to.eq(tokenAddress, 'input token address'); | ||||||
|  |             expect(transfers[0].from).to.eq(testContract.address); | ||||||
|  |             expect(transfers[0].to).to.eq(opts.toAddress, 'recipient address'); | ||||||
|  |             expect(transfers[0].amount).to.bignumber.eq(opts.amount, 'amount'); | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         describe('token -> token', async () => { | ||||||
|  |             it('calls UniswapV2Router01.swapExactTokensForTokens()', async () => { | ||||||
|  |                 const { opts, result, logs, blocktime } = await transferFromAsync(); | ||||||
|  |                 expect(result).to.eq(AssetProxyId.ERC20Bridge, 'asset proxy id'); | ||||||
|  |                 const transfers = filterLogsToArguments<SwapExactTokensForTokensArgs>( | ||||||
|  |                     logs, | ||||||
|  |                     ContractEvents.SwapExactTokensForTokensInput, | ||||||
|  |                 ); | ||||||
|  |  | ||||||
|  |                 expect(transfers.length).to.eq(1); | ||||||
|  |                 expect(transfers[0].toTokenAddress).to.eq( | ||||||
|  |                     opts.tokenAddressesPath[opts.tokenAddressesPath.length - 1], | ||||||
|  |                     'output token address', | ||||||
|  |                 ); | ||||||
|  |                 expect(transfers[0].to).to.eq(opts.toAddress, 'recipient address'); | ||||||
|  |                 expect(transfers[0].amountIn).to.bignumber.eq(opts.fromTokenBalance, 'input token amount'); | ||||||
|  |                 expect(transfers[0].amountOutMin).to.bignumber.eq(opts.amount, 'output token amount'); | ||||||
|  |                 expect(transfers[0].deadline).to.bignumber.eq(blocktime, 'deadline'); | ||||||
|  |             }); | ||||||
|  |  | ||||||
|  |             it('sets allowance for "from" token', async () => { | ||||||
|  |                 const { logs } = await transferFromAsync(); | ||||||
|  |                 const approvals = filterLogsToArguments<TokenApproveArgs>(logs, ContractEvents.TokenApprove); | ||||||
|  |                 const routerAddress = await testContract.getRouterAddress().callAsync(); | ||||||
|  |                 expect(approvals.length).to.eq(1); | ||||||
|  |                 expect(approvals[0].spender).to.eq(routerAddress); | ||||||
|  |                 expect(approvals[0].allowance).to.bignumber.eq(constants.MAX_UINT256); | ||||||
|  |             }); | ||||||
|  |  | ||||||
|  |             it('sets allowance for "from" token on subsequent calls', async () => { | ||||||
|  |                 const { opts } = await transferFromAsync(); | ||||||
|  |                 const { logs } = await transferFromAsync(opts); | ||||||
|  |                 const approvals = filterLogsToArguments<TokenApproveArgs>(logs, ContractEvents.TokenApprove); | ||||||
|  |                 const routerAddress = await testContract.getRouterAddress().callAsync(); | ||||||
|  |                 expect(approvals.length).to.eq(1); | ||||||
|  |                 expect(approvals[0].spender).to.eq(routerAddress); | ||||||
|  |                 expect(approvals[0].allowance).to.bignumber.eq(constants.MAX_UINT256); | ||||||
|  |             }); | ||||||
|  |  | ||||||
|  |             it('fails if the router fails', async () => { | ||||||
|  |                 const revertReason = 'FOOBAR'; | ||||||
|  |                 const tx = transferFromAsync({ | ||||||
|  |                     routerRevertReason: revertReason, | ||||||
|  |                 }); | ||||||
|  |                 return expect(tx).to.eventually.be.rejectedWith(revertReason); | ||||||
|  |             }); | ||||||
|  |         }); | ||||||
|  |         describe('token -> token -> token', async () => { | ||||||
|  |             it('calls UniswapV2Router01.swapExactTokensForTokens()', async () => { | ||||||
|  |                 const { opts, result, logs, blocktime } = await transferFromAsync({ | ||||||
|  |                     tokenAddressesPath: Array(3).fill(constants.NULL_ADDRESS), | ||||||
|  |                 }); | ||||||
|  |                 expect(result).to.eq(AssetProxyId.ERC20Bridge, 'asset proxy id'); | ||||||
|  |                 const transfers = filterLogsToArguments<SwapExactTokensForTokensArgs>( | ||||||
|  |                     logs, | ||||||
|  |                     ContractEvents.SwapExactTokensForTokensInput, | ||||||
|  |                 ); | ||||||
|  |  | ||||||
|  |                 expect(transfers.length).to.eq(1); | ||||||
|  |                 expect(transfers[0].toTokenAddress).to.eq( | ||||||
|  |                     opts.tokenAddressesPath[opts.tokenAddressesPath.length - 1], | ||||||
|  |                     'output token address', | ||||||
|  |                 ); | ||||||
|  |                 expect(transfers[0].to).to.eq(opts.toAddress, 'recipient address'); | ||||||
|  |                 expect(transfers[0].amountIn).to.bignumber.eq(opts.fromTokenBalance, 'input token amount'); | ||||||
|  |                 expect(transfers[0].amountOutMin).to.bignumber.eq(opts.amount, 'output token amount'); | ||||||
|  |                 expect(transfers[0].deadline).to.bignumber.eq(blocktime, 'deadline'); | ||||||
|  |             }); | ||||||
|  |         }); | ||||||
|  |     }); | ||||||
|  | }); | ||||||
| @@ -1,3 +0,0 @@ | |||||||
| export * from './erc20_wrapper'; |  | ||||||
| export * from './erc721_wrapper'; |  | ||||||
| export * from './erc1155_proxy_wrapper'; |  | ||||||
							
								
								
									
										63
									
								
								contracts/asset-proxy/test/wrappers.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								contracts/asset-proxy/test/wrappers.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,63 @@ | |||||||
|  | /* | ||||||
|  |  * ----------------------------------------------------------------------------- | ||||||
|  |  * 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'; | ||||||
|  | export * from '../test/generated-wrappers/erc20_proxy'; | ||||||
|  | export * from '../test/generated-wrappers/erc721_proxy'; | ||||||
|  | export * from '../test/generated-wrappers/eth2_dai_bridge'; | ||||||
|  | export * from '../test/generated-wrappers/i_asset_data'; | ||||||
|  | export * from '../test/generated-wrappers/i_asset_proxy'; | ||||||
|  | export * from '../test/generated-wrappers/i_asset_proxy_dispatcher'; | ||||||
|  | export * from '../test/generated-wrappers/i_authorizable'; | ||||||
|  | export * from '../test/generated-wrappers/i_balancer_pool'; | ||||||
|  | export * from '../test/generated-wrappers/i_bancor_network'; | ||||||
|  | export * from '../test/generated-wrappers/i_chai'; | ||||||
|  | export * from '../test/generated-wrappers/i_curve'; | ||||||
|  | export * from '../test/generated-wrappers/i_dydx'; | ||||||
|  | export * from '../test/generated-wrappers/i_dydx_bridge'; | ||||||
|  | export * from '../test/generated-wrappers/i_erc20_bridge'; | ||||||
|  | export * from '../test/generated-wrappers/i_eth2_dai'; | ||||||
|  | export * from '../test/generated-wrappers/i_gas_token'; | ||||||
|  | export * from '../test/generated-wrappers/i_kyber_network_proxy'; | ||||||
|  | export * from '../test/generated-wrappers/i_m_stable'; | ||||||
|  | export * from '../test/generated-wrappers/i_mooniswap'; | ||||||
|  | export * from '../test/generated-wrappers/i_shell'; | ||||||
|  | export * from '../test/generated-wrappers/i_uniswap_exchange'; | ||||||
|  | export * from '../test/generated-wrappers/i_uniswap_exchange_factory'; | ||||||
|  | export * from '../test/generated-wrappers/i_uniswap_v2_router01'; | ||||||
|  | export * from '../test/generated-wrappers/kyber_bridge'; | ||||||
|  | export * from '../test/generated-wrappers/m_stable_bridge'; | ||||||
|  | export * from '../test/generated-wrappers/mixin_asset_proxy_dispatcher'; | ||||||
|  | export * from '../test/generated-wrappers/mixin_authorizable'; | ||||||
|  | export * from '../test/generated-wrappers/mixin_gas_token'; | ||||||
|  | export * from '../test/generated-wrappers/mooniswap_bridge'; | ||||||
|  | export * from '../test/generated-wrappers/multi_asset_proxy'; | ||||||
|  | export * from '../test/generated-wrappers/ownable'; | ||||||
|  | export * from '../test/generated-wrappers/shell_bridge'; | ||||||
|  | export * from '../test/generated-wrappers/snow_swap_bridge'; | ||||||
|  | export * from '../test/generated-wrappers/static_call_proxy'; | ||||||
|  | export * from '../test/generated-wrappers/sushi_swap_bridge'; | ||||||
|  | export * from '../test/generated-wrappers/swerve_bridge'; | ||||||
|  | export * from '../test/generated-wrappers/test_bancor_bridge'; | ||||||
|  | export * from '../test/generated-wrappers/test_chai_bridge'; | ||||||
|  | export * from '../test/generated-wrappers/test_dex_forwarder_bridge'; | ||||||
|  | export * from '../test/generated-wrappers/test_dydx_bridge'; | ||||||
|  | export * from '../test/generated-wrappers/test_erc20_bridge'; | ||||||
|  | export * from '../test/generated-wrappers/test_eth2_dai_bridge'; | ||||||
|  | export * from '../test/generated-wrappers/test_kyber_bridge'; | ||||||
|  | export * from '../test/generated-wrappers/test_static_call_target'; | ||||||
|  | export * from '../test/generated-wrappers/test_uniswap_bridge'; | ||||||
|  | export * from '../test/generated-wrappers/test_uniswap_v2_bridge'; | ||||||
|  | export * from '../test/generated-wrappers/uniswap_bridge'; | ||||||
|  | export * from '../test/generated-wrappers/uniswap_v2_bridge'; | ||||||
| @@ -84,7 +84,7 @@ module.exports = { | |||||||
|         solc: { |         solc: { | ||||||
|             version: '0.5.9', |             version: '0.5.9', | ||||||
|             settings: { |             settings: { | ||||||
|                 evmVersion: 'constantinople', |                 evmVersion: 'istanbul', | ||||||
|                 optimizer: { |                 optimizer: { | ||||||
|                     enabled: true, |                     enabled: true, | ||||||
|                     runs: 1000000, |                     runs: 1000000, | ||||||
|   | |||||||
| @@ -3,6 +3,14 @@ | |||||||
|     "compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true }, |     "compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true }, | ||||||
|     "include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"], |     "include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"], | ||||||
|     "files": [ |     "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/ERC1155Proxy.json", | ||||||
|         "generated-artifacts/ERC20BridgeProxy.json", |         "generated-artifacts/ERC20BridgeProxy.json", | ||||||
|         "generated-artifacts/ERC20Proxy.json", |         "generated-artifacts/ERC20Proxy.json", | ||||||
| @@ -12,20 +20,105 @@ | |||||||
|         "generated-artifacts/IAssetProxy.json", |         "generated-artifacts/IAssetProxy.json", | ||||||
|         "generated-artifacts/IAssetProxyDispatcher.json", |         "generated-artifacts/IAssetProxyDispatcher.json", | ||||||
|         "generated-artifacts/IAuthorizable.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/IERC20Bridge.json", | ||||||
|         "generated-artifacts/IEth2Dai.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/IUniswapExchange.json", | ||||||
|         "generated-artifacts/IUniswapExchangeFactory.json", |         "generated-artifacts/IUniswapExchangeFactory.json", | ||||||
|  |         "generated-artifacts/IUniswapV2Router01.json", | ||||||
|  |         "generated-artifacts/KyberBridge.json", | ||||||
|  |         "generated-artifacts/MStableBridge.json", | ||||||
|         "generated-artifacts/MixinAssetProxyDispatcher.json", |         "generated-artifacts/MixinAssetProxyDispatcher.json", | ||||||
|         "generated-artifacts/MixinAuthorizable.json", |         "generated-artifacts/MixinAuthorizable.json", | ||||||
|  |         "generated-artifacts/MixinGasToken.json", | ||||||
|  |         "generated-artifacts/MooniswapBridge.json", | ||||||
|         "generated-artifacts/MultiAssetProxy.json", |         "generated-artifacts/MultiAssetProxy.json", | ||||||
|         "generated-artifacts/Ownable.json", |         "generated-artifacts/Ownable.json", | ||||||
|  |         "generated-artifacts/ShellBridge.json", | ||||||
|  |         "generated-artifacts/SnowSwapBridge.json", | ||||||
|         "generated-artifacts/StaticCallProxy.json", |         "generated-artifacts/StaticCallProxy.json", | ||||||
|  |         "generated-artifacts/SushiSwapBridge.json", | ||||||
|  |         "generated-artifacts/SwerveBridge.json", | ||||||
|  |         "generated-artifacts/TestBancorBridge.json", | ||||||
|  |         "generated-artifacts/TestChaiBridge.json", | ||||||
|  |         "generated-artifacts/TestDexForwarderBridge.json", | ||||||
|  |         "generated-artifacts/TestDydxBridge.json", | ||||||
|         "generated-artifacts/TestERC20Bridge.json", |         "generated-artifacts/TestERC20Bridge.json", | ||||||
|         "generated-artifacts/TestEth2DaiBridge.json", |         "generated-artifacts/TestEth2DaiBridge.json", | ||||||
|  |         "generated-artifacts/TestKyberBridge.json", | ||||||
|         "generated-artifacts/TestStaticCallTarget.json", |         "generated-artifacts/TestStaticCallTarget.json", | ||||||
|         "generated-artifacts/TestUniswapBridge.json", |         "generated-artifacts/TestUniswapBridge.json", | ||||||
|         "generated-artifacts/UniswapBridge.json" |         "generated-artifacts/TestUniswapV2Bridge.json", | ||||||
|  |         "generated-artifacts/UniswapBridge.json", | ||||||
|  |         "generated-artifacts/UniswapV2Bridge.json", | ||||||
|  |         "test/generated-artifacts/BalancerBridge.json", | ||||||
|  |         "test/generated-artifacts/BancorBridge.json", | ||||||
|  |         "test/generated-artifacts/ChaiBridge.json", | ||||||
|  |         "test/generated-artifacts/CreamBridge.json", | ||||||
|  |         "test/generated-artifacts/CurveBridge.json", | ||||||
|  |         "test/generated-artifacts/DODOBridge.json", | ||||||
|  |         "test/generated-artifacts/DexForwarderBridge.json", | ||||||
|  |         "test/generated-artifacts/DydxBridge.json", | ||||||
|  |         "test/generated-artifacts/ERC1155Proxy.json", | ||||||
|  |         "test/generated-artifacts/ERC20BridgeProxy.json", | ||||||
|  |         "test/generated-artifacts/ERC20Proxy.json", | ||||||
|  |         "test/generated-artifacts/ERC721Proxy.json", | ||||||
|  |         "test/generated-artifacts/Eth2DaiBridge.json", | ||||||
|  |         "test/generated-artifacts/IAssetData.json", | ||||||
|  |         "test/generated-artifacts/IAssetProxy.json", | ||||||
|  |         "test/generated-artifacts/IAssetProxyDispatcher.json", | ||||||
|  |         "test/generated-artifacts/IAuthorizable.json", | ||||||
|  |         "test/generated-artifacts/IBalancerPool.json", | ||||||
|  |         "test/generated-artifacts/IBancorNetwork.json", | ||||||
|  |         "test/generated-artifacts/IChai.json", | ||||||
|  |         "test/generated-artifacts/ICurve.json", | ||||||
|  |         "test/generated-artifacts/IDydx.json", | ||||||
|  |         "test/generated-artifacts/IDydxBridge.json", | ||||||
|  |         "test/generated-artifacts/IERC20Bridge.json", | ||||||
|  |         "test/generated-artifacts/IEth2Dai.json", | ||||||
|  |         "test/generated-artifacts/IGasToken.json", | ||||||
|  |         "test/generated-artifacts/IKyberNetworkProxy.json", | ||||||
|  |         "test/generated-artifacts/IMStable.json", | ||||||
|  |         "test/generated-artifacts/IMooniswap.json", | ||||||
|  |         "test/generated-artifacts/IShell.json", | ||||||
|  |         "test/generated-artifacts/IUniswapExchange.json", | ||||||
|  |         "test/generated-artifacts/IUniswapExchangeFactory.json", | ||||||
|  |         "test/generated-artifacts/IUniswapV2Router01.json", | ||||||
|  |         "test/generated-artifacts/KyberBridge.json", | ||||||
|  |         "test/generated-artifacts/MStableBridge.json", | ||||||
|  |         "test/generated-artifacts/MixinAssetProxyDispatcher.json", | ||||||
|  |         "test/generated-artifacts/MixinAuthorizable.json", | ||||||
|  |         "test/generated-artifacts/MixinGasToken.json", | ||||||
|  |         "test/generated-artifacts/MooniswapBridge.json", | ||||||
|  |         "test/generated-artifacts/MultiAssetProxy.json", | ||||||
|  |         "test/generated-artifacts/Ownable.json", | ||||||
|  |         "test/generated-artifacts/ShellBridge.json", | ||||||
|  |         "test/generated-artifacts/SnowSwapBridge.json", | ||||||
|  |         "test/generated-artifacts/StaticCallProxy.json", | ||||||
|  |         "test/generated-artifacts/SushiSwapBridge.json", | ||||||
|  |         "test/generated-artifacts/SwerveBridge.json", | ||||||
|  |         "test/generated-artifacts/TestBancorBridge.json", | ||||||
|  |         "test/generated-artifacts/TestChaiBridge.json", | ||||||
|  |         "test/generated-artifacts/TestDexForwarderBridge.json", | ||||||
|  |         "test/generated-artifacts/TestDydxBridge.json", | ||||||
|  |         "test/generated-artifacts/TestERC20Bridge.json", | ||||||
|  |         "test/generated-artifacts/TestEth2DaiBridge.json", | ||||||
|  |         "test/generated-artifacts/TestKyberBridge.json", | ||||||
|  |         "test/generated-artifacts/TestStaticCallTarget.json", | ||||||
|  |         "test/generated-artifacts/TestUniswapBridge.json", | ||||||
|  |         "test/generated-artifacts/TestUniswapV2Bridge.json", | ||||||
|  |         "test/generated-artifacts/UniswapBridge.json", | ||||||
|  |         "test/generated-artifacts/UniswapV2Bridge.json" | ||||||
|     ], |     ], | ||||||
|     "exclude": ["./deploy/solc/solc_bin"] |     "exclude": ["./deploy/solc/solc_bin"] | ||||||
| } | } | ||||||
|   | |||||||
| @@ -3,8 +3,8 @@ | |||||||
| * | * | ||||||
| # Whitelist lib | # Whitelist lib | ||||||
| !lib/**/* | !lib/**/* | ||||||
| # Blacklist tests and publish scripts | # Whitelist Solidity contracts | ||||||
|  | !contracts/src/**/* | ||||||
|  | # Blacklist tests in lib | ||||||
| /lib/test/* | /lib/test/* | ||||||
| /lib/monorepo_scripts/ |  | ||||||
| # Package specific ignore | # Package specific ignore | ||||||
| !bin/**/* |  | ||||||
| @@ -1,146 +1,116 @@ | |||||||
| [ | [ | ||||||
|     { |     { | ||||||
|         "version": "1.1.0-beta.1", |         "timestamp": 1604376968, | ||||||
|  |         "version": "1.1.11", | ||||||
|         "changes": [ |         "changes": [ | ||||||
|             { |             { | ||||||
|                 "note": "Dependencies updated" |                 "note": "Dependencies updated" | ||||||
|             } |             } | ||||||
|  |         ] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |         "timestamp": 1604355662, | ||||||
|  |         "version": "1.1.10", | ||||||
|  |         "changes": [ | ||||||
|  |             { | ||||||
|  |                 "note": "Dependencies updated" | ||||||
|  |             } | ||||||
|  |         ] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |         "timestamp": 1603851023, | ||||||
|  |         "version": "1.1.9", | ||||||
|  |         "changes": [ | ||||||
|  |             { | ||||||
|  |                 "note": "Dependencies updated" | ||||||
|  |             } | ||||||
|  |         ] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |         "timestamp": 1603833198, | ||||||
|  |         "version": "1.1.8", | ||||||
|  |         "changes": [ | ||||||
|  |             { | ||||||
|  |                 "note": "Dependencies updated" | ||||||
|  |             } | ||||||
|  |         ] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |         "timestamp": 1603265572, | ||||||
|  |         "version": "1.1.7", | ||||||
|  |         "changes": [ | ||||||
|  |             { | ||||||
|  |                 "note": "Dependencies updated" | ||||||
|  |             } | ||||||
|  |         ] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |         "timestamp": 1594788383, | ||||||
|  |         "version": "1.1.6", | ||||||
|  |         "changes": [ | ||||||
|  |             { | ||||||
|  |                 "note": "Dependencies updated" | ||||||
|  |             } | ||||||
|  |         ] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |         "version": "1.1.5", | ||||||
|  |         "changes": [ | ||||||
|  |             { | ||||||
|  |                 "note": "Fix broken tests.", | ||||||
|  |                 "pr": 2591 | ||||||
|  |             } | ||||||
|         ], |         ], | ||||||
|         "timestamp": 1573159180 |         "timestamp": 1592969527 | ||||||
|     }, |     }, | ||||||
|     { |     { | ||||||
|         "version": "1.1.0-beta.0", |         "timestamp": 1583220306, | ||||||
|  |         "version": "1.1.4", | ||||||
|         "changes": [ |         "changes": [ | ||||||
|             { |             { | ||||||
|                 "note": "Generate boilerplate for all contracts if none are specified or if all contracts identifier is used", |                 "note": "Dependencies updated" | ||||||
|                 "pr": 2055 |             } | ||||||
|             }, |         ] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |         "timestamp": 1582837861, | ||||||
|  |         "version": "1.1.3", | ||||||
|  |         "changes": [ | ||||||
|             { |             { | ||||||
|                 "note": "Fixed sorting in artifact generation", |                 "note": "Dependencies updated" | ||||||
|                 "pr": 1910 |             } | ||||||
|  |         ] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |         "timestamp": 1582677073, | ||||||
|  |         "version": "1.1.2", | ||||||
|  |         "changes": [ | ||||||
|  |             { | ||||||
|  |                 "note": "Dependencies updated" | ||||||
|  |             } | ||||||
|  |         ] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |         "timestamp": 1582623685, | ||||||
|  |         "version": "1.1.1", | ||||||
|  |         "changes": [ | ||||||
|  |             { | ||||||
|  |                 "note": "Dependencies updated" | ||||||
|  |             } | ||||||
|  |         ] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |         "version": "1.1.0", | ||||||
|  |         "changes": [ | ||||||
|  |             { | ||||||
|  |                 "note": "Added decoders for broker data", | ||||||
|  |                 "pr": 2484 | ||||||
|             } |             } | ||||||
|         ], |         ], | ||||||
|         "timestamp": 1570135330 |         "timestamp": 1581748629 | ||||||
|     }, |     }, | ||||||
|     { |     { | ||||||
|         "timestamp": 1568744790, |         "timestamp": 1581204851, | ||||||
|         "version": "1.0.15", |  | ||||||
|         "changes": [ |  | ||||||
|             { |  | ||||||
|                 "note": "Dependencies updated" |  | ||||||
|             } |  | ||||||
|         ] |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|         "timestamp": 1567521715, |  | ||||||
|         "version": "1.0.14", |  | ||||||
|         "changes": [ |  | ||||||
|             { |  | ||||||
|                 "note": "Dependencies updated" |  | ||||||
|             } |  | ||||||
|         ] |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|         "timestamp": 1565296576, |  | ||||||
|         "version": "1.0.13", |  | ||||||
|         "changes": [ |  | ||||||
|             { |  | ||||||
|                 "note": "Dependencies updated" |  | ||||||
|             } |  | ||||||
|         ] |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|         "timestamp": 1564604963, |  | ||||||
|         "version": "1.0.12", |  | ||||||
|         "changes": [ |  | ||||||
|             { |  | ||||||
|                 "note": "Dependencies updated" |  | ||||||
|             } |  | ||||||
|         ] |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|         "timestamp": 1563957393, |  | ||||||
|         "version": "1.0.11", |  | ||||||
|         "changes": [ |  | ||||||
|             { |  | ||||||
|                 "note": "Dependencies updated" |  | ||||||
|             } |  | ||||||
|         ] |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|         "timestamp": 1563006338, |  | ||||||
|         "version": "1.0.10", |  | ||||||
|         "changes": [ |  | ||||||
|             { |  | ||||||
|                 "note": "Dependencies updated" |  | ||||||
|             } |  | ||||||
|         ] |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|         "timestamp": 1557507213, |  | ||||||
|         "version": "1.0.9", |  | ||||||
|         "changes": [ |  | ||||||
|             { |  | ||||||
|                 "note": "Dependencies updated" |  | ||||||
|             } |  | ||||||
|         ] |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|         "version": "1.0.8", |  | ||||||
|         "changes": [ |  | ||||||
|             { |  | ||||||
|                 "note": "Dependencies updated" |  | ||||||
|             } |  | ||||||
|         ], |  | ||||||
|         "timestamp": 1554997931 |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|         "timestamp": 1553183790, |  | ||||||
|         "version": "1.0.7", |  | ||||||
|         "changes": [ |  | ||||||
|             { |  | ||||||
|                 "note": "Dependencies updated" |  | ||||||
|             } |  | ||||||
|         ] |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|         "timestamp": 1553091633, |  | ||||||
|         "version": "1.0.6", |  | ||||||
|         "changes": [ |  | ||||||
|             { |  | ||||||
|                 "note": "Dependencies updated" |  | ||||||
|             } |  | ||||||
|         ] |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|         "timestamp": 1551479279, |  | ||||||
|         "version": "1.0.5", |  | ||||||
|         "changes": [ |  | ||||||
|             { |  | ||||||
|                 "note": "Dependencies updated" |  | ||||||
|             } |  | ||||||
|         ] |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|         "timestamp": 1551220833, |  | ||||||
|         "version": "1.0.4", |  | ||||||
|         "changes": [ |  | ||||||
|             { |  | ||||||
|                 "note": "Dependencies updated" |  | ||||||
|             } |  | ||||||
|         ] |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|         "timestamp": 1551130135, |  | ||||||
|         "version": "1.0.3", |  | ||||||
|         "changes": [ |  | ||||||
|             { |  | ||||||
|                 "note": "Dependencies updated" |  | ||||||
|             } |  | ||||||
|         ] |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|         "timestamp": 1549733923, |  | ||||||
|         "version": "1.0.2", |         "version": "1.0.2", | ||||||
|         "changes": [ |         "changes": [ | ||||||
|             { |             { | ||||||
| @@ -149,12 +119,21 @@ | |||||||
|         ] |         ] | ||||||
|     }, |     }, | ||||||
|     { |     { | ||||||
|  |         "timestamp": 1580988106, | ||||||
|         "version": "1.0.1", |         "version": "1.0.1", | ||||||
|         "changes": [ |         "changes": [ | ||||||
|             { |             { | ||||||
|                 "note": "Dependencies updated" |                 "note": "Dependencies updated" | ||||||
|             } |             } | ||||||
|         ], |         ] | ||||||
|         "timestamp": 1549547375 |     }, | ||||||
|  |     { | ||||||
|  |         "version": "1.0.0", | ||||||
|  |         "changes": [ | ||||||
|  |             { | ||||||
|  |                 "note": "Created package", | ||||||
|  |                 "pr": "2455" | ||||||
|  |             } | ||||||
|  |         ] | ||||||
|     } |     } | ||||||
| ] | ] | ||||||
							
								
								
									
										66
									
								
								contracts/broker/CHANGELOG.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								contracts/broker/CHANGELOG.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,66 @@ | |||||||
|  | <!-- | ||||||
|  | changelogUtils.file is auto-generated using the monorepo-scripts package. Don't edit directly. | ||||||
|  | Edit the package's CHANGELOG.json file only. | ||||||
|  | --> | ||||||
|  |  | ||||||
|  | CHANGELOG | ||||||
|  |  | ||||||
|  | ## v1.1.11 - _November 3, 2020_ | ||||||
|  |  | ||||||
|  |     * Dependencies updated | ||||||
|  |  | ||||||
|  | ## v1.1.10 - _November 2, 2020_ | ||||||
|  |  | ||||||
|  |     * Dependencies updated | ||||||
|  |  | ||||||
|  | ## v1.1.9 - _October 28, 2020_ | ||||||
|  |  | ||||||
|  |     * Dependencies updated | ||||||
|  |  | ||||||
|  | ## v1.1.8 - _October 27, 2020_ | ||||||
|  |  | ||||||
|  |     * Dependencies updated | ||||||
|  |  | ||||||
|  | ## v1.1.7 - _October 21, 2020_ | ||||||
|  |  | ||||||
|  |     * Dependencies updated | ||||||
|  |  | ||||||
|  | ## v1.1.6 - _July 15, 2020_ | ||||||
|  |  | ||||||
|  |     * Dependencies updated | ||||||
|  |  | ||||||
|  | ## v1.1.5 - _June 24, 2020_ | ||||||
|  |  | ||||||
|  |     * Fix broken tests. (#2591) | ||||||
|  |  | ||||||
|  | ## v1.1.4 - _March 3, 2020_ | ||||||
|  |  | ||||||
|  |     * Dependencies updated | ||||||
|  |  | ||||||
|  | ## v1.1.3 - _February 27, 2020_ | ||||||
|  |  | ||||||
|  |     * Dependencies updated | ||||||
|  |  | ||||||
|  | ## v1.1.2 - _February 26, 2020_ | ||||||
|  |  | ||||||
|  |     * Dependencies updated | ||||||
|  |  | ||||||
|  | ## v1.1.1 - _February 25, 2020_ | ||||||
|  |  | ||||||
|  |     * Dependencies updated | ||||||
|  |  | ||||||
|  | ## v1.1.0 - _February 15, 2020_ | ||||||
|  |  | ||||||
|  |     * Added decoders for broker data (#2484) | ||||||
|  |  | ||||||
|  | ## v1.0.2 - _February 8, 2020_ | ||||||
|  |  | ||||||
|  |     * Dependencies updated | ||||||
|  |  | ||||||
|  | ## v1.0.1 - _February 6, 2020_ | ||||||
|  |  | ||||||
|  |     * Dependencies updated | ||||||
|  |  | ||||||
|  | ## v1.0.0 - _Invalid date_ | ||||||
|  |  | ||||||
|  |     * Created package (#2455) | ||||||
							
								
								
									
										1
									
								
								contracts/broker/DEPLOYS.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								contracts/broker/DEPLOYS.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | [] | ||||||
| @@ -1,6 +1,18 @@ | |||||||
| ## Tests | ## Broker | ||||||
| 
 | 
 | ||||||
| This package implements unit tests against 0x's smart contracts. Its primary purpose is to help avoid circular dependencies between the contract packages. | This package contains the implementation of the [`Broker` contract](https://github.com/0xProject/ZEIPs/issues/75). This contract serves as an entry-point to the 0x Exchange for the filling of property-based orders. Addresses of the deployed contracts can be found in this 0x [guide](https://0x.org/docs/guides/0x-cheat-sheet) or the [DEPLOYS](./DEPLOYS.json) file within this package. | ||||||
|  | 
 | ||||||
|  | ## Installation | ||||||
|  | 
 | ||||||
|  | **Install** | ||||||
|  | 
 | ||||||
|  | ```bash | ||||||
|  | npm install @0x/contracts-broker --save | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ## Bug bounty | ||||||
|  | 
 | ||||||
|  | A bug bounty for the 3.0 contracts is ongoing! Instructions can be found [here](https://0x.org/docs/guides/bug-bounty-program). | ||||||
| 
 | 
 | ||||||
| ## Contributing | ## Contributing | ||||||
| 
 | 
 | ||||||
| @@ -29,39 +41,21 @@ yarn install | |||||||
| To build this package and all other monorepo packages that it depends on, run the following from the monorepo root directory: | To build this package and all other monorepo packages that it depends on, run the following from the monorepo root directory: | ||||||
| 
 | 
 | ||||||
| ```bash | ```bash | ||||||
| PKG=@0x/contracts-tests yarn build | PKG=@0x/contracts-broker yarn build | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| Or continuously rebuild on change: | Or continuously rebuild on change: | ||||||
| 
 | 
 | ||||||
| ```bash | ```bash | ||||||
| PKG=@0x/contracts-tests yarn watch | PKG=@0x/contracts-broker yarn watch | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| If imports are rebuilt in their source packages, they do not need to be rebuilt here. |  | ||||||
| 
 |  | ||||||
| Example: |  | ||||||
| 
 |  | ||||||
| ``` |  | ||||||
| // contracts/tests/test/some-new/some_new_test.ts |  | ||||||
| import { SomeNewContract } from '@0x/contracts-some-new'; |  | ||||||
| 
 |  | ||||||
| describe('should do its thing', () => { |  | ||||||
|     const contractInstance = new SomeNewContract(); |  | ||||||
|     expect(contractInstance.someTruthyFunction.callAsync()).to.be.true(); |  | ||||||
| }) |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| Run `yarn watch` from `contracts/some-new`, and then running `yarn test` from this package should test the new changes. |  | ||||||
| 
 |  | ||||||
| ### Clean | ### Clean | ||||||
| 
 | 
 | ||||||
| ```bash | ```bash | ||||||
| yarn clean | yarn clean | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| Since the purpose of this package is to test other packages, make sure you are running `yarn clean` as necessary in the imported packages as well. |  | ||||||
| 
 |  | ||||||
| ### Lint | ### Lint | ||||||
| 
 | 
 | ||||||
| ```bash | ```bash | ||||||
| @@ -73,3 +67,7 @@ yarn lint | |||||||
| ```bash | ```bash | ||||||
| yarn test | yarn test | ||||||
| ``` | ``` | ||||||
|  | 
 | ||||||
|  | #### Testing options | ||||||
|  | 
 | ||||||
|  | Contracts testing options like coverage, profiling, revert traces or backing node choosing - are described [here](../TESTING.md). | ||||||
| @@ -1,10 +1,11 @@ | |||||||
| { | { | ||||||
|     "artifactsDir": "./generated-artifacts", |     "artifactsDir": "./test/generated-artifacts", | ||||||
|     "contractsDir": "./contracts", |     "contractsDir": "./contracts", | ||||||
|     "useDockerisedSolc": false, |     "useDockerisedSolc": false, | ||||||
|     "isOfflineMode": false, |     "isOfflineMode": false, | ||||||
|  |     "shouldSaveStandardInput": true, | ||||||
|     "compilerSettings": { |     "compilerSettings": { | ||||||
|         "evmVersion": "constantinople", |         "evmVersion": "istanbul", | ||||||
|         "optimizer": { |         "optimizer": { | ||||||
|             "enabled": true, |             "enabled": true, | ||||||
|             "runs": 1000000, |             "runs": 1000000, | ||||||
							
								
								
									
										314
									
								
								contracts/broker/contracts/src/Broker.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										314
									
								
								contracts/broker/contracts/src/Broker.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,314 @@ | |||||||
|  | /* | ||||||
|  |  | ||||||
|  |   Copyright 2019 ZeroEx Intl. | ||||||
|  |  | ||||||
|  |   Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |   you may not use this file except in compliance with the License. | ||||||
|  |   You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |     http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |   Unless required by applicable law or agreed to in writing, software | ||||||
|  |   distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |   See the License for the specific language governing permissions and | ||||||
|  |   limitations under the License. | ||||||
|  |  | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | pragma solidity ^0.5.9; | ||||||
|  | pragma experimental ABIEncoderV2; | ||||||
|  |  | ||||||
|  | import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetData.sol"; | ||||||
|  | import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol"; | ||||||
|  | import "@0x/contracts-erc721/contracts/src/interfaces/IERC721Token.sol"; | ||||||
|  | import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol"; | ||||||
|  | import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol"; | ||||||
|  | import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; | ||||||
|  | import "@0x/contracts-extensions/contracts/src/LibAssetDataTransfer.sol"; | ||||||
|  | import "@0x/contracts-extensions/contracts/src/MixinWethUtils.sol"; | ||||||
|  | import "@0x/contracts-utils/contracts/src/LibBytes.sol"; | ||||||
|  | import "@0x/contracts-utils/contracts/src/LibRichErrors.sol"; | ||||||
|  | import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; | ||||||
|  | import "./interfaces/IBroker.sol"; | ||||||
|  | import "./interfaces/IPropertyValidator.sol"; | ||||||
|  | import "./libs/LibBrokerRichErrors.sol"; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // solhint-disable space-after-comma, var-name-mixedcase | ||||||
|  | contract Broker is | ||||||
|  |     IBroker, | ||||||
|  |     MixinWethUtils | ||||||
|  | { | ||||||
|  |     // Contract addresses | ||||||
|  |  | ||||||
|  |     // Address of the 0x Exchange contract | ||||||
|  |     address internal EXCHANGE; | ||||||
|  |     // Address of the 0x ERC1155 Asset Proxy contract | ||||||
|  |     address internal ERC1155_PROXY; | ||||||
|  |  | ||||||
|  |     // The following storage variables are used to cache data for the duration of the transcation. | ||||||
|  |     // They should always cleared at the end of the transaction. | ||||||
|  |  | ||||||
|  |     // Token IDs specified by the taker to be used to fill property-based orders. | ||||||
|  |     uint256[] internal _cachedTokenIds; | ||||||
|  |     // An index to the above array keeping track of which assets have been transferred. | ||||||
|  |     uint256 internal _cacheIndex; | ||||||
|  |     // The address that called `brokerTrade` or `batchBrokerTrade`. Assets will be transferred to | ||||||
|  |     // and from this address as the effectual taker of the orders. | ||||||
|  |     address internal _sender; | ||||||
|  |  | ||||||
|  |     using LibSafeMath for uint256; | ||||||
|  |     using LibBytes for bytes; | ||||||
|  |     using LibAssetDataTransfer for bytes; | ||||||
|  |  | ||||||
|  |     /// @param exchange Address of the 0x Exchange contract. | ||||||
|  |     /// @param exchange Address of the Wrapped Ether contract. | ||||||
|  |     /// @param exchange Address of the 0x ERC1155 Asset Proxy contract. | ||||||
|  |     constructor ( | ||||||
|  |         address exchange, | ||||||
|  |         address weth | ||||||
|  |     ) | ||||||
|  |         public | ||||||
|  |         MixinWethUtils( | ||||||
|  |             exchange, | ||||||
|  |             weth | ||||||
|  |         ) | ||||||
|  |     { | ||||||
|  |         EXCHANGE = exchange; | ||||||
|  |         ERC1155_PROXY = IExchange(EXCHANGE).getAssetProxy(IAssetData(address(0)).ERC1155Assets.selector); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// @dev The Broker implements the ERC1155 transfer function to be compatible with the ERC1155 asset proxy | ||||||
|  |     /// @param from Since the Broker serves as the taker of the order, this should equal `address(this)` | ||||||
|  |     /// @param to This should be the maker of the order. | ||||||
|  |     /// @param amounts Should be an array of just one `uint256`, specifying the amount of the brokered assets to transfer. | ||||||
|  |     /// @param data Encodes the validator contract address and any auxiliary data it needs for property validation. | ||||||
|  |     function safeBatchTransferFrom( | ||||||
|  |         address from, | ||||||
|  |         address to, | ||||||
|  |         uint256[] calldata /* ids */, | ||||||
|  |         uint256[] calldata amounts, | ||||||
|  |         bytes calldata data | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |     { | ||||||
|  |         // Only the ERC1155 asset proxy contract should be calling this function. | ||||||
|  |         if (msg.sender != ERC1155_PROXY) { | ||||||
|  |             LibRichErrors.rrevert(LibBrokerRichErrors.OnlyERC1155ProxyError( | ||||||
|  |                 msg.sender | ||||||
|  |             )); | ||||||
|  |         } | ||||||
|  |         // Only `takerAssetData` should be using Broker assets | ||||||
|  |         if (from != address(this)) { | ||||||
|  |             LibRichErrors.rrevert( | ||||||
|  |                 LibBrokerRichErrors.InvalidFromAddressError(from) | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|  |         // Only one asset amount should be specified. | ||||||
|  |         if (amounts.length != 1) { | ||||||
|  |             LibRichErrors.rrevert( | ||||||
|  |                 LibBrokerRichErrors.AmountsLengthMustEqualOneError(amounts.length) | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         uint256 cacheIndex = _cacheIndex; | ||||||
|  |         uint256 remainingAmount = amounts[0]; | ||||||
|  |  | ||||||
|  |         // Verify that there are enough broker assets to transfer | ||||||
|  |         if (_cachedTokenIds.length.safeSub(cacheIndex) < remainingAmount) { | ||||||
|  |             LibRichErrors.rrevert( | ||||||
|  |                 LibBrokerRichErrors.TooFewBrokerAssetsProvidedError(_cachedTokenIds.length) | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Decode validator and params from `data` | ||||||
|  |         (address tokenAddress, address validator, bytes memory propertyData) = abi.decode( | ||||||
|  |             data, | ||||||
|  |             (address, address, bytes) | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         while (remainingAmount != 0) { | ||||||
|  |             uint256 tokenId = _cachedTokenIds[cacheIndex]; | ||||||
|  |             cacheIndex++; | ||||||
|  |  | ||||||
|  |             // Validate asset properties | ||||||
|  |             IPropertyValidator(validator).checkBrokerAsset( | ||||||
|  |                 tokenId, | ||||||
|  |                 propertyData | ||||||
|  |             ); | ||||||
|  |  | ||||||
|  |             // Perform the transfer | ||||||
|  |             IERC721Token(tokenAddress).transferFrom( | ||||||
|  |                 _sender, | ||||||
|  |                 to, | ||||||
|  |                 tokenId | ||||||
|  |             ); | ||||||
|  |  | ||||||
|  |             remainingAmount--; | ||||||
|  |         } | ||||||
|  |         // Update cache index in storage | ||||||
|  |         _cacheIndex = cacheIndex; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// @dev Fills a single property-based order by the given amount using the given assets. | ||||||
|  |     ///      Pays protocol fees using either the ETH supplied by the taker to the transaction or | ||||||
|  |     ///      WETH acquired from the maker during settlement. The final WETH balance is sent to the taker. | ||||||
|  |     /// @param brokeredTokenIds Token IDs specified by the taker to be used to fill the orders. | ||||||
|  |     /// @param order The property-based order to fill. The format of a property-based order is the | ||||||
|  |     ///        same as that of a normal order, except the takerAssetData. Instaed of specifying a | ||||||
|  |     ///        specific ERC721 asset, the takerAssetData should be ERC1155 assetData where the | ||||||
|  |     ///        underlying tokenAddress is this contract's address and the desired properties are | ||||||
|  |     ///        encoded in the extra data field. Also note that takerFees must be denominated in | ||||||
|  |     ///        WETH (or zero). | ||||||
|  |     /// @param takerAssetFillAmount The amount to fill the order by. | ||||||
|  |     /// @param signature The maker's signature of the given order. | ||||||
|  |     /// @param fillFunctionSelector The selector for either `fillOrder` or `fillOrKillOrder`. | ||||||
|  |     /// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients. | ||||||
|  |     /// @param feeRecipients Addresses that will receive ETH when orders are filled. | ||||||
|  |     /// @return fillResults Amounts filled and fees paid by the maker and taker. | ||||||
|  |     function brokerTrade( | ||||||
|  |         uint256[] memory brokeredTokenIds, | ||||||
|  |         LibOrder.Order memory order, | ||||||
|  |         uint256 takerAssetFillAmount, | ||||||
|  |         bytes memory signature, | ||||||
|  |         bytes4 fillFunctionSelector, | ||||||
|  |         uint256[] memory ethFeeAmounts, | ||||||
|  |         address payable[] memory feeRecipients | ||||||
|  |     ) | ||||||
|  |         public | ||||||
|  |         payable | ||||||
|  |         returns (LibFillResults.FillResults memory fillResults) | ||||||
|  |     { | ||||||
|  |         // Cache the taker-supplied asset data | ||||||
|  |         _cachedTokenIds = brokeredTokenIds; | ||||||
|  |         // Cache the sender's address | ||||||
|  |         _sender = msg.sender; | ||||||
|  |  | ||||||
|  |         // Sanity-check the provided function selector | ||||||
|  |         if ( | ||||||
|  |             fillFunctionSelector != IExchange(address(0)).fillOrder.selector && | ||||||
|  |             fillFunctionSelector != IExchange(address(0)).fillOrKillOrder.selector | ||||||
|  |         ) { | ||||||
|  |             LibBrokerRichErrors.InvalidFunctionSelectorError(fillFunctionSelector); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Pay ETH affiliate fees to all feeRecipient addresses | ||||||
|  |         _transferEthFeesAndWrapRemaining(ethFeeAmounts, feeRecipients); | ||||||
|  |  | ||||||
|  |         // Perform the fill | ||||||
|  |         bytes memory fillCalldata = abi.encodeWithSelector( | ||||||
|  |             fillFunctionSelector, | ||||||
|  |             order, | ||||||
|  |             takerAssetFillAmount, | ||||||
|  |             signature | ||||||
|  |         ); | ||||||
|  |         // solhint-disable-next-line avoid-call-value | ||||||
|  |         (bool didSucceed, bytes memory returnData) = EXCHANGE.call(fillCalldata); | ||||||
|  |         if (didSucceed) { | ||||||
|  |             fillResults = abi.decode(returnData, (LibFillResults.FillResults)); | ||||||
|  |         } else { | ||||||
|  |             // Re-throw error | ||||||
|  |             LibRichErrors.rrevert(returnData); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Transfer maker asset to taker | ||||||
|  |         if (!order.makerAssetData.equals(WETH_ASSET_DATA)) { | ||||||
|  |             order.makerAssetData.transferOut(fillResults.makerAssetFilledAmount); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Refund remaining ETH to msg.sender. | ||||||
|  |         _unwrapAndTransferEth(WETH.balanceOf(address(this))); | ||||||
|  |  | ||||||
|  |         _clearStorage(); | ||||||
|  |  | ||||||
|  |         return fillResults; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// @dev Fills multiple property-based orders by the given amounts using the given assets. | ||||||
|  |     ///      Pays protocol fees using either the ETH supplied by the taker to the transaction or | ||||||
|  |     ///      WETH acquired from the maker during settlement. The final WETH balance is sent to the taker. | ||||||
|  |     /// @param brokeredTokenIds Token IDs specified by the taker to be used to fill the orders. | ||||||
|  |     /// @param orders The property-based orders to fill. The format of a property-based order is the | ||||||
|  |     ///        same as that of a normal order, except the takerAssetData. Instaed of specifying a | ||||||
|  |     ///        specific ERC721 asset, the takerAssetData should be ERC1155 assetData where the | ||||||
|  |     ///        underlying tokenAddress is this contract's address and the desired properties are | ||||||
|  |     ///        encoded in the extra data field. Also note that takerFees must be denominated in | ||||||
|  |     ///        WETH (or zero). | ||||||
|  |     /// @param takerAssetFillAmounts The amounts to fill the orders by. | ||||||
|  |     /// @param signatures The makers' signatures for the given orders. | ||||||
|  |     /// @param batchFillFunctionSelector The selector for either `batchFillOrders`, | ||||||
|  |     ///        `batchFillOrKillOrders`, or `batchFillOrdersNoThrow`. | ||||||
|  |     /// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients. | ||||||
|  |     /// @param feeRecipients Addresses that will receive ETH when orders are filled. | ||||||
|  |     /// @return fillResults Amounts filled and fees paid by the makers and taker. | ||||||
|  |     function batchBrokerTrade( | ||||||
|  |         uint256[] memory brokeredTokenIds, | ||||||
|  |         LibOrder.Order[] memory orders, | ||||||
|  |         uint256[] memory takerAssetFillAmounts, | ||||||
|  |         bytes[] memory signatures, | ||||||
|  |         bytes4 batchFillFunctionSelector, | ||||||
|  |         uint256[] memory ethFeeAmounts, | ||||||
|  |         address payable[] memory feeRecipients | ||||||
|  |     ) | ||||||
|  |         public | ||||||
|  |         payable | ||||||
|  |         returns (LibFillResults.FillResults[] memory fillResults) | ||||||
|  |     { | ||||||
|  |         // Cache the taker-supplied asset data | ||||||
|  |         _cachedTokenIds = brokeredTokenIds; | ||||||
|  |         // Cache the sender's address | ||||||
|  |         _sender = msg.sender; | ||||||
|  |  | ||||||
|  |         // Sanity-check the provided function selector | ||||||
|  |         if ( | ||||||
|  |             batchFillFunctionSelector != IExchange(address(0)).batchFillOrders.selector && | ||||||
|  |             batchFillFunctionSelector != IExchange(address(0)).batchFillOrKillOrders.selector && | ||||||
|  |             batchFillFunctionSelector != IExchange(address(0)).batchFillOrdersNoThrow.selector | ||||||
|  |         ) { | ||||||
|  |             LibBrokerRichErrors.InvalidFunctionSelectorError(batchFillFunctionSelector); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Pay ETH affiliate fees to all feeRecipient addresses | ||||||
|  |         _transferEthFeesAndWrapRemaining(ethFeeAmounts, feeRecipients); | ||||||
|  |  | ||||||
|  |         // Perform the batch fill | ||||||
|  |         bytes memory batchFillCalldata = abi.encodeWithSelector( | ||||||
|  |             batchFillFunctionSelector, | ||||||
|  |             orders, | ||||||
|  |             takerAssetFillAmounts, | ||||||
|  |             signatures | ||||||
|  |         ); | ||||||
|  |         // solhint-disable-next-line avoid-call-value | ||||||
|  |         (bool didSucceed, bytes memory returnData) = EXCHANGE.call(batchFillCalldata); | ||||||
|  |         if (didSucceed) { | ||||||
|  |             // solhint-disable-next-line indent | ||||||
|  |             fillResults = abi.decode(returnData, (LibFillResults.FillResults[])); | ||||||
|  |         } else { | ||||||
|  |             // Re-throw error | ||||||
|  |             LibRichErrors.rrevert(returnData); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Transfer maker assets to taker | ||||||
|  |         for (uint256 i = 0; i < orders.length; i++) { | ||||||
|  |             if (!orders[i].makerAssetData.equals(WETH_ASSET_DATA)) { | ||||||
|  |                 orders[i].makerAssetData.transferOut(fillResults[i].makerAssetFilledAmount); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Refund remaining ETH to msg.sender. | ||||||
|  |         _unwrapAndTransferEth(WETH.balanceOf(address(this))); | ||||||
|  |  | ||||||
|  |         _clearStorage(); | ||||||
|  |  | ||||||
|  |         return fillResults; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function _clearStorage() | ||||||
|  |         private | ||||||
|  |     { | ||||||
|  |         delete _cachedTokenIds; | ||||||
|  |         _cacheIndex = 0; | ||||||
|  |         _sender = address(0); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										101
									
								
								contracts/broker/contracts/src/interfaces/IBroker.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								contracts/broker/contracts/src/interfaces/IBroker.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,101 @@ | |||||||
|  | /* | ||||||
|  |  | ||||||
|  |   Copyright 2019 ZeroEx Intl. | ||||||
|  |  | ||||||
|  |   Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |   you may not use this file except in compliance with the License. | ||||||
|  |   You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |     http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |   Unless required by applicable law or agreed to in writing, software | ||||||
|  |   distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |   See the License for the specific language governing permissions and | ||||||
|  |   limitations under the License. | ||||||
|  |  | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | pragma solidity ^0.5.9; | ||||||
|  | pragma experimental ABIEncoderV2; | ||||||
|  |  | ||||||
|  | import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol"; | ||||||
|  | import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // solhint-disable space-after-comma | ||||||
|  | interface IBroker { | ||||||
|  |  | ||||||
|  |     /// @dev Fills a single property-based order by the given amount using the given assets. | ||||||
|  |     ///      Pays protocol fees using either the ETH supplied by the taker to the transaction or | ||||||
|  |     ///      WETH acquired from the maker during settlement. The final WETH balance is sent to the taker. | ||||||
|  |     /// @param brokeredTokenIds Token IDs specified by the taker to be used to fill the orders. | ||||||
|  |     /// @param order The property-based order to fill. The format of a property-based order is the | ||||||
|  |     ///        same as that of a normal order, except the takerAssetData. Instaed of specifying a | ||||||
|  |     ///        specific ERC721 asset, the takerAssetData should be ERC1155 assetData where the | ||||||
|  |     ///        underlying tokenAddress is this contract's address and the desired properties are | ||||||
|  |     ///        encoded in the extra data field. Also note that takerFees must be denominated in | ||||||
|  |     ///        WETH (or zero). | ||||||
|  |     /// @param takerAssetFillAmount The amount to fill the order by. | ||||||
|  |     /// @param signature The maker's signature of the given order. | ||||||
|  |     /// @param fillFunctionSelector The selector for either `fillOrder` or `fillOrKillOrder`. | ||||||
|  |     /// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients. | ||||||
|  |     /// @param feeRecipients Addresses that will receive ETH when orders are filled. | ||||||
|  |     /// @return fillResults Amounts filled and fees paid by the maker and taker. | ||||||
|  |     function brokerTrade( | ||||||
|  |         uint256[] calldata brokeredTokenIds, | ||||||
|  |         LibOrder.Order calldata order, | ||||||
|  |         uint256 takerAssetFillAmount, | ||||||
|  |         bytes calldata signature, | ||||||
|  |         bytes4 fillFunctionSelector, | ||||||
|  |         uint256[] calldata ethFeeAmounts, | ||||||
|  |         address payable[] calldata feeRecipients | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         payable | ||||||
|  |         returns (LibFillResults.FillResults memory fillResults); | ||||||
|  |  | ||||||
|  |     /// @dev Fills multiple property-based orders by the given amounts using the given assets. | ||||||
|  |     ///      Pays protocol fees using either the ETH supplied by the taker to the transaction or | ||||||
|  |     ///      WETH acquired from the maker during settlement. The final WETH balance is sent to the taker. | ||||||
|  |     /// @param brokeredTokenIds Token IDs specified by the taker to be used to fill the orders. | ||||||
|  |     /// @param orders The property-based orders to fill. The format of a property-based order is the | ||||||
|  |     ///        same as that of a normal order, except the takerAssetData. Instaed of specifying a | ||||||
|  |     ///        specific ERC721 asset, the takerAssetData should be ERC1155 assetData where the | ||||||
|  |     ///        underlying tokenAddress is this contract's address and the desired properties are | ||||||
|  |     ///        encoded in the extra data field. Also note that takerFees must be denominated in | ||||||
|  |     ///        WETH (or zero). | ||||||
|  |     /// @param takerAssetFillAmounts The amounts to fill the orders by. | ||||||
|  |     /// @param signatures The makers' signatures for the given orders. | ||||||
|  |     /// @param batchFillFunctionSelector The selector for either `batchFillOrders`, | ||||||
|  |     ///        `batchFillOrKillOrders`, or `batchFillOrdersNoThrow`. | ||||||
|  |     /// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients. | ||||||
|  |     /// @param feeRecipients Addresses that will receive ETH when orders are filled. | ||||||
|  |     /// @return fillResults Amounts filled and fees paid by the makers and taker. | ||||||
|  |     function batchBrokerTrade( | ||||||
|  |         uint256[] calldata brokeredTokenIds, | ||||||
|  |         LibOrder.Order[] calldata orders, | ||||||
|  |         uint256[] calldata takerAssetFillAmounts, | ||||||
|  |         bytes[] calldata signatures, | ||||||
|  |         bytes4 batchFillFunctionSelector, | ||||||
|  |         uint256[] calldata ethFeeAmounts, | ||||||
|  |         address payable[] calldata feeRecipients | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         payable | ||||||
|  |         returns (LibFillResults.FillResults[] memory fillResults); | ||||||
|  |  | ||||||
|  |     /// @dev The Broker implements the ERC1155 transfer function to be compatible with the ERC1155 asset proxy | ||||||
|  |     /// @param from Since the Broker serves as the taker of the order, this should equal `address(this)` | ||||||
|  |     /// @param to This should be the maker of the order. | ||||||
|  |     /// @param amounts Should be an array of just one `uint256`, specifying the amount of the brokered assets to transfer. | ||||||
|  |     /// @param data Encodes the validator contract address and any auxiliary data it needs for property validation. | ||||||
|  |     function safeBatchTransferFrom( | ||||||
|  |         address from, | ||||||
|  |         address to, | ||||||
|  |         uint256[] calldata /* ids */, | ||||||
|  |         uint256[] calldata amounts, | ||||||
|  |         bytes calldata data | ||||||
|  |     ) | ||||||
|  |         external; | ||||||
|  | } | ||||||
| @@ -16,22 +16,18 @@ | |||||||
| 
 | 
 | ||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
| pragma solidity ^0.5.5; | pragma solidity ^0.5.9; | ||||||
| pragma experimental ABIEncoderV2; | pragma experimental ABIEncoderV2; | ||||||
| 
 | 
 | ||||||
| import "@0x/contracts-exchange-libs/contracts/src/LibEIP712ExchangeDomain.sol"; |  | ||||||
| import "../src/MixinSignatureValidator.sol"; |  | ||||||
| import "../src/MixinTransactions.sol"; |  | ||||||
| 
 | 
 | ||||||
|  | interface IGodsUnchained { | ||||||
| 
 | 
 | ||||||
| contract TestSignatureValidator is |     /// @dev Returns the proto and quality for a particular card given its token id | ||||||
|     LibEIP712ExchangeDomain, |     /// @param tokenId The id of the card to query. | ||||||
|     MixinSignatureValidator |     /// @return proto The proto of the given card. | ||||||
| { |     /// @return quality The quality of the given card | ||||||
| 
 |     function getDetails(uint256 tokenId) | ||||||
|     // solhint-disable no-empty-blocks |         external | ||||||
|     constructor (uint256 chainId) |         view | ||||||
|         public |         returns (uint16 proto, uint8 quality); | ||||||
|         LibEIP712ExchangeDomain(chainId, address(0)) |  | ||||||
|     {} |  | ||||||
| } | } | ||||||
| @@ -0,0 +1,35 @@ | |||||||
|  | /* | ||||||
|  |  | ||||||
|  |   Copyright 2019 ZeroEx Intl. | ||||||
|  |  | ||||||
|  |   Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |   you may not use this file except in compliance with the License. | ||||||
|  |   You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |     http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |   Unless required by applicable law or agreed to in writing, software | ||||||
|  |   distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |   See the License for the specific language governing permissions and | ||||||
|  |   limitations under the License. | ||||||
|  |  | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | pragma solidity ^0.5.9; | ||||||
|  | pragma experimental ABIEncoderV2; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | interface IPropertyValidator { | ||||||
|  |  | ||||||
|  |     /// @dev Checks that the given asset data satisfies the properties encoded in `propertyData`. | ||||||
|  |     ///      Should revert if the asset does not satisfy the specified properties. | ||||||
|  |     /// @param tokenId The ERC721 tokenId of the asset to check. | ||||||
|  |     /// @param propertyData Encoded properties or auxiliary data needed to perform the check. | ||||||
|  |     function checkBrokerAsset( | ||||||
|  |         uint256 tokenId, | ||||||
|  |         bytes calldata propertyData | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         view; | ||||||
|  | } | ||||||
							
								
								
									
										109
									
								
								contracts/broker/contracts/src/libs/LibBrokerRichErrors.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								contracts/broker/contracts/src/libs/LibBrokerRichErrors.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,109 @@ | |||||||
|  | /* | ||||||
|  |  | ||||||
|  |   Copyright 2019 ZeroEx Intl. | ||||||
|  |  | ||||||
|  |   Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |   you may not use this file except in compliance with the License. | ||||||
|  |   You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |     http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |   Unless required by applicable law or agreed to in writing, software | ||||||
|  |   distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |   See the License for the specific language governing permissions and | ||||||
|  |   limitations under the License. | ||||||
|  |  | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | pragma solidity ^0.5.9; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | library LibBrokerRichErrors { | ||||||
|  |  | ||||||
|  |     // bytes4(keccak256("InvalidFromAddressError(address)")) | ||||||
|  |     bytes4 internal constant INVALID_FROM_ADDRESS_ERROR_SELECTOR = | ||||||
|  |         0x906bfb3c; | ||||||
|  |  | ||||||
|  |     // bytes4(keccak256("AmountsLengthMustEqualOneError(uint256)")) | ||||||
|  |     bytes4 internal constant AMOUNTS_LENGTH_MUST_EQUAL_ONE_ERROR_SELECTOR = | ||||||
|  |         0xba9be200; | ||||||
|  |  | ||||||
|  |     // bytes4(keccak256("TooFewBrokerAssetsProvidedError(uint256)")) | ||||||
|  |     bytes4 internal constant TOO_FEW_BROKER_ASSETS_PROVIDED_ERROR_SELECTOR = | ||||||
|  |         0x55272586; | ||||||
|  |  | ||||||
|  |     // bytes4(keccak256("InvalidFunctionSelectorError(bytes4)")) | ||||||
|  |     bytes4 internal constant INVALID_FUNCTION_SELECTOR_ERROR_SELECTOR = | ||||||
|  |         0x540943f1; | ||||||
|  |  | ||||||
|  |     // bytes4(keccak256("OnlyERC1155ProxyError(address)")) | ||||||
|  |     bytes4 internal constant ONLY_ERC_1155_PROXY_ERROR_SELECTOR = | ||||||
|  |         0xccc529af; | ||||||
|  |  | ||||||
|  |     // solhint-disable func-name-mixedcase | ||||||
|  |     function InvalidFromAddressError( | ||||||
|  |         address from | ||||||
|  |     ) | ||||||
|  |         internal | ||||||
|  |         pure | ||||||
|  |         returns (bytes memory) | ||||||
|  |     { | ||||||
|  |         return abi.encodeWithSelector( | ||||||
|  |             INVALID_FROM_ADDRESS_ERROR_SELECTOR, | ||||||
|  |             from | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function AmountsLengthMustEqualOneError( | ||||||
|  |         uint256 amountsLength | ||||||
|  |     ) | ||||||
|  |         internal | ||||||
|  |         pure | ||||||
|  |         returns (bytes memory) | ||||||
|  |     { | ||||||
|  |         return abi.encodeWithSelector( | ||||||
|  |             AMOUNTS_LENGTH_MUST_EQUAL_ONE_ERROR_SELECTOR, | ||||||
|  |             amountsLength | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function TooFewBrokerAssetsProvidedError( | ||||||
|  |         uint256 numBrokeredAssets | ||||||
|  |     ) | ||||||
|  |         internal | ||||||
|  |         pure | ||||||
|  |         returns (bytes memory) | ||||||
|  |     { | ||||||
|  |         return abi.encodeWithSelector( | ||||||
|  |             TOO_FEW_BROKER_ASSETS_PROVIDED_ERROR_SELECTOR, | ||||||
|  |             numBrokeredAssets | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function InvalidFunctionSelectorError( | ||||||
|  |         bytes4 selector | ||||||
|  |     ) | ||||||
|  |         internal | ||||||
|  |         pure | ||||||
|  |         returns (bytes memory) | ||||||
|  |     { | ||||||
|  |         return abi.encodeWithSelector( | ||||||
|  |             INVALID_FUNCTION_SELECTOR_ERROR_SELECTOR, | ||||||
|  |             selector | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function OnlyERC1155ProxyError( | ||||||
|  |         address sender | ||||||
|  |     ) | ||||||
|  |         internal | ||||||
|  |         pure | ||||||
|  |         returns (bytes memory) | ||||||
|  |     { | ||||||
|  |         return abi.encodeWithSelector( | ||||||
|  |             ONLY_ERC_1155_PROXY_ERROR_SELECTOR, | ||||||
|  |             sender | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,61 @@ | |||||||
|  | /* | ||||||
|  |  | ||||||
|  |   Copyright 2019 ZeroEx Intl. | ||||||
|  |  | ||||||
|  |   Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |   you may not use this file except in compliance with the License. | ||||||
|  |   You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |     http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |   Unless required by applicable law or agreed to in writing, software | ||||||
|  |   distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |   See the License for the specific language governing permissions and | ||||||
|  |   limitations under the License. | ||||||
|  |  | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | pragma solidity ^0.5.9; | ||||||
|  | pragma experimental ABIEncoderV2; | ||||||
|  |  | ||||||
|  | import "@0x/contracts-utils/contracts/src/LibBytes.sol"; | ||||||
|  | import "../interfaces/IGodsUnchained.sol"; | ||||||
|  | import "../interfaces/IPropertyValidator.sol"; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | contract GodsUnchainedValidator is | ||||||
|  |     IPropertyValidator | ||||||
|  | { | ||||||
|  |     IGodsUnchained internal GODS_UNCHAINED; // solhint-disable-line var-name-mixedcase | ||||||
|  |  | ||||||
|  |     using LibBytes for bytes; | ||||||
|  |  | ||||||
|  |     constructor(address _godsUnchained) | ||||||
|  |         public | ||||||
|  |     { | ||||||
|  |         GODS_UNCHAINED = IGodsUnchained(_godsUnchained); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// @dev Checks that the given card (encoded as assetData) has the proto and quality encoded in `propertyData`. | ||||||
|  |     ///      Reverts if the card doesn't match the specified proto and quality. | ||||||
|  |     /// @param tokenId The ERC721 tokenId of the card to check. | ||||||
|  |     /// @param propertyData Encoded proto and quality that the card is expected to have. | ||||||
|  |     function checkBrokerAsset( | ||||||
|  |         uint256 tokenId, | ||||||
|  |         bytes calldata propertyData | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         view | ||||||
|  |     { | ||||||
|  |         (uint16 expectedProto, uint8 expectedQuality) = abi.decode( | ||||||
|  |             propertyData, | ||||||
|  |             (uint16, uint8) | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         // Validate card properties. | ||||||
|  |         (uint16 proto, uint8 quality) = GODS_UNCHAINED.getDetails(tokenId); | ||||||
|  |         require(proto == expectedProto, "GodsUnchainedValidator/PROTO_MISMATCH"); | ||||||
|  |         require(quality == expectedQuality, "GodsUnchainedValidator/QUALITY_MISMATCH"); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										55
									
								
								contracts/broker/contracts/test/TestGodsUnchained.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								contracts/broker/contracts/test/TestGodsUnchained.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -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.9; | ||||||
|  | pragma experimental ABIEncoderV2; | ||||||
|  |  | ||||||
|  | import "@0x/contracts-erc721/contracts/test/DummyERC721Token.sol"; | ||||||
|  | import "../src/interfaces/IGodsUnchained.sol"; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | contract TestGodsUnchained is | ||||||
|  |     IGodsUnchained, | ||||||
|  |     DummyERC721Token | ||||||
|  | { | ||||||
|  |     mapping (uint256 => uint16) internal _protoByTokenId; | ||||||
|  |     mapping (uint256 => uint8) internal _qualityByTokenId; | ||||||
|  |  | ||||||
|  |     constructor ( | ||||||
|  |         string memory _name, | ||||||
|  |         string memory _symbol | ||||||
|  |     ) | ||||||
|  |         public | ||||||
|  |         DummyERC721Token(_name, _symbol) | ||||||
|  |     {} // solhint-disable-line no-empty-blocks | ||||||
|  |  | ||||||
|  |     function setTokenProperties(uint256 tokenId, uint16 proto, uint8 quality) | ||||||
|  |         external | ||||||
|  |     { | ||||||
|  |         _protoByTokenId[tokenId] = proto; | ||||||
|  |         _qualityByTokenId[tokenId] = quality; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function getDetails(uint256 tokenId) | ||||||
|  |         external | ||||||
|  |         view | ||||||
|  |         returns (uint16 proto, uint8 quality) | ||||||
|  |     { | ||||||
|  |         return (_protoByTokenId[tokenId], _qualityByTokenId[tokenId]); | ||||||
|  |     } | ||||||
|  | } | ||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user