Compare commits
849 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6e070c91e8 | |||
| 59afaca753 | |||
| f35eeed0eb | |||
| 8b19e3c215 | |||
| dca62efba9 | |||
| 923bbb44a8 | |||
| d4c455c180 | |||
| 5ac618681a | |||
| d191247505 | |||
| 9b55e96fa0 | |||
| 8868c0b6d3 | |||
| 534ff92ba5 | |||
| 31ec824aef | |||
| b732b6417e | |||
| 998b5f43fb | |||
| ff31995104 | |||
| 48a7cd4e60 | |||
| acd34a9372 | |||
| 2ce67a25ef | |||
| 700b811813 | |||
| 16f04b13d7 | |||
| e3ad4a5e14 | |||
| 579446d5d9 | |||
| fc07f7a0ff | |||
| dd6054efeb | |||
| 27a6a15d66 | |||
| 32e93579fa | |||
| c8719ce418 | |||
| 39fe05dfad | |||
| be101154fa | |||
| c329fc0a5f | |||
| e55dbc9681 | |||
| 6f1c67af0d | |||
| 5284a6df88 | |||
| 8bce0a4f2e | |||
| 11d2bbc092 | |||
| 4a10f727c4 | |||
| e79dc645e4 | |||
| 0e5799c93b | |||
| 90413e75f1 | |||
| 9c262571ae | |||
| 76fe1548ae | |||
| 8f2a4785cb | |||
| 16535fbb87 | |||
| ff69c54497 | |||
| 6669f3fcee | |||
| 18e16a5db0 | |||
| 95fdc7bd8a | |||
| 77cc33fc5c | |||
| 27d696aa7d | |||
| ff6a565452 | |||
| 5f079c8605 | |||
| ea335ebc64 | |||
| b1a801566c | |||
| 2eac2a79b7 | |||
| f9fc8d2e96 | |||
| 89c32f5dd7 | |||
| eff3d7ca8e | |||
| 85225ef6ae | |||
| 2010c6b464 | |||
| 03891b00a7 | |||
| 0b33d29e41 | |||
| d0ec491b1f | |||
| 38536f42f4 | |||
| 61dfdde6c4 | |||
| e8be9a7bd0 | |||
| dd8758fedf | |||
| c63b203c1d | |||
| c191757c6e | |||
| f4bdaf49a1 | |||
| 6a7114fdb4 | |||
| 0926729c8f | |||
| 9e1c934ffd | |||
| a7e91856f3 | |||
| 06666be93a | |||
| 915f74c5f6 | |||
| 3d3f20f7e3 | |||
| 03a3302abd | |||
| bd5f7f5774 | |||
| a6bef44790 | |||
| a9c777faa6 | |||
| 44a404aae5 | |||
| 1d2d18f9da | |||
| 82ce197e44 | |||
| 42787e2a75 | |||
| 9bc43c8d0f | |||
| cacf03641c | |||
| e96164feea | |||
| 9f52e94339 | |||
| c9936e231d | |||
| e299a7950e | |||
| b33260ac44 | |||
| 3fb8ecad76 | |||
| c3cbdb4599 | |||
| 7586e383c2 | |||
| d1146e8c8b | |||
| 8d4eee412d | |||
| 903751ce0d | |||
| 9fd61177c3 | |||
| 3c48912730 | |||
| b3a8602928 | |||
| 5ef8554727 | |||
| 9ea4bae313 | |||
| c05918c3cc | |||
| 108d5f3b4a | |||
| 61b6a733c8 | |||
| 6ad275befb | |||
| 7a0bfdfbb4 | |||
| f4228f1b49 | |||
| a5d5867092 | |||
| 4d7c3cca75 | |||
| 0541347034 | |||
| c5d66183ab | |||
| 1eea95f9ac | |||
| e16c4042c1 | |||
| e1d32acae8 | |||
| 3b499a9cc3 | |||
| 4e77aaa0c3 | |||
| 4be30dc3ae | |||
| 370e6a882a | |||
| 9cc55ef2a5 | |||
| 48594890cf | |||
| 6979e3c83a | |||
| 96e0d35f11 | |||
| 66402e9fec | |||
| 5b40202dd3 | |||
| da95df6be5 | |||
| 250572f48d | |||
| ff9e9c4d85 | |||
| c8c0f21a3f | |||
| 3a9a2c8888 | |||
| a5ea0af65c | |||
| 42553ec0c0 | |||
| c01203b0b7 | |||
| 9d005b492d | |||
| 22c1403e5b | |||
| 3009553925 | |||
| 5ea9bd44a1 | |||
| 51c2c50437 | |||
| 52b6181d78 | |||
| fe712c678a | |||
| c70ee937e6 | |||
| 46736da489 | |||
| 82c85121bb | |||
| e5960465a7 | |||
| 5716492ebd | |||
| c7807c5b58 | |||
| 433213537f | |||
| 560a855dc7 | |||
| 80ae074c57 | |||
| d808e49b51 | |||
| a8afb20c20 | |||
| a613cd03c9 | |||
| b709206f9f | |||
| 2a560ad82f | |||
| 4fe2157e36 | |||
| 5a42a450ac | |||
| 49adfea68b | |||
| a29fce9cbd | |||
| 7f591a9181 | |||
| 23afc74b59 | |||
| dcf1f8d22d | |||
| c7f2138da1 | |||
| b67856c69d | |||
| 4fbd44fd40 | |||
| 2887393712 | |||
| af337047a4 | |||
| b0522b9c58 | |||
| 969466b8fd | |||
| 2b008f4cb6 | |||
| d060d29912 | |||
| 75439c1dd3 | |||
| c8878adcbd | |||
| d95c3ade8f | |||
| 7811370000 | |||
| b1e1aadba1 | |||
| 7ddd66fb74 | |||
| 0cdc5e13ce | |||
| 5b50e99a0d | |||
| b09d7aada4 | |||
| 5fc5ded661 | |||
| 146a22cd96 | |||
| b925b2dae6 | |||
| 87f5916341 | |||
| 8854966847 | |||
| 685d2087ca | |||
| 7532dab17d | |||
| 73a8be1449 | |||
| c9fff647f4 | |||
| ec2f7ba8d1 | |||
| a4029e7472 | |||
| ad5edd329f | |||
| 955517dc2e | |||
| 3b48a671fd | |||
| bd2f1773cd | |||
| e60aee61f2 | |||
| b2e2d9ab1c | |||
| 4d263b7fc3 | |||
| e0f3fea97f | |||
| d4dc4b25c8 | |||
| c1244d6297 | |||
| 462c52bcbf | |||
| 9f68c00855 | |||
| 4dcf8f5bd0 | |||
| ea1cb5c54e | |||
| 49b42e8696 | |||
| beea818f4e | |||
| 13b75bd5af | |||
| e911b4d556 | |||
| 7bd95b1e31 | |||
| 4ecdf312df | |||
| f36f8e96dc | |||
| e57f4be1fb | |||
| a806520d6f | |||
| a4b1cd6e31 | |||
| 21297e2b2c | |||
| 94697726f5 | |||
| a58e3e151a | |||
| 790b3b20c2 | |||
| ed6e51494e | |||
| 17884e91a1 | |||
| 59cd714b84 | |||
| a24031854b | |||
| 6cd84ffceb | |||
| 29edd4e15e | |||
| 6af6efc198 | |||
| 586c88802d | |||
| edbc64f337 | |||
| c73861d8b3 | |||
| d78bcbbae5 | |||
| 326df13bf3 | |||
| 7852583fde | |||
| 5993f5b371 | |||
| 04946211a5 | |||
| 2f2ef68652 | |||
| ebdba08218 | |||
| a74b7bd4b1 | |||
| 090e2fca16 | |||
| dbe8898d00 | |||
| 52b2a619c7 | |||
| 58ecbd6104 | |||
| 9aa61ad273 | |||
| 7aa6f21147 | |||
| 323d1fa941 | |||
| 4073cf6585 | |||
| 4ce0e211c5 | |||
| 9af6ad5ddf | |||
| 2f336f7aaf | |||
| 5751eac444 | |||
| cda518d353 | |||
| f446f5c5cd | |||
| 1455a5a942 | |||
| 207b92f63c | |||
| b217ef6314 | |||
| 687dc19a4a | |||
| 161f25fc12 | |||
| 4bb26c32b6 | |||
| d91f4d4bc1 | |||
| ddcae6254e | |||
| fdfd90e6a4 | |||
| f162638cde | |||
| 8375b6085f | |||
| 83b941c76c | |||
| 63c8751e06 | |||
| 306132f823 | |||
| 677d05743c | |||
| aef0f63aee | |||
| 5e55569db6 | |||
| 9bb2c958ec | |||
| e931c1cbfc | |||
| dd1fd0002a | |||
| ac3808885a | |||
| 258c001f7f | |||
| d07bdccc0c | |||
| 227a335399 | |||
| 58abd66969 | |||
| 8662846838 | |||
| 6ea0577bfe | |||
| b9b26e1d8a | |||
| 887c1bb925 | |||
| cc5e898250 | |||
| 1cef36b5c0 | |||
| c95be493c3 | |||
| bddc8755c1 | |||
| 3ad555bb01 | |||
| 846b0714ad | |||
| f79f7b00e3 | |||
| 47585b1117 | |||
| b7e7c765e0 | |||
| 9e1da49f23 | |||
| c29dd086d3 | |||
| b9cbea1c9c | |||
| b254b74b87 | |||
| bb1736e376 | |||
| 11349835e9 | |||
| c6e0edb268 | |||
| b50391862c | |||
| 0bcf0a2001 | |||
| 0eaa5f50ac | |||
| ce86029f6a | |||
| 815d9e1f45 | |||
| e6213767fa | |||
| f28c245a3c | |||
| 12303ceaf5 | |||
| 9001ce9d3a | |||
| 492ef4a419 | |||
| 5f67dd7868 | |||
| 3c5a268da4 | |||
| db5a12cfdd | |||
| 03ad0efd29 | |||
| 5fc53b6f2f | |||
| 99f3e26f83 | |||
| 151371cc86 | |||
| 376208bd96 | |||
| 11b63d4fc1 | |||
| 39ae5b4cca | |||
| 670b843b63 | |||
| 070d25dc9e | |||
| 9684ce76c5 | |||
| d919f0dde2 | |||
| 689e18aab5 | |||
| 8765e2a53f | |||
| 7a19bcf6d9 | |||
| 088897150e | |||
| 34be16d939 | |||
| 14ae881e26 | |||
| 666a3a73e0 | |||
| 84bffb854a | |||
| 365c875ced | |||
| 7dd0ee6212 | |||
| 7123faff9f | |||
| 61b5921ab2 | |||
| e72c7ce91b | |||
| c4ca7f03e3 | |||
| 9be77ddd54 | |||
| 70a17d0b96 | |||
| ad2282456e | |||
| fe3e360483 | |||
| 5a857fc1a7 | |||
| c5cd35b2ea | |||
| a808b0b03f | |||
| 4e8f422a81 | |||
| 070226d624 | |||
| 2413f83504 | |||
| be692e59eb | |||
| e74652415f | |||
| 5ad07e1892 | |||
| 575372f660 | |||
| 7a26a0ecf1 | |||
| 8e01dd14f9 | |||
| 5088c64140 | |||
| ac4a19dd7d | |||
| 09b1926c41 | |||
| d7b67eca52 | |||
| e4427befbb | |||
| ca1babe1f7 | |||
| 1d54b86a7c | |||
| 2d83c557b1 | |||
| dfb9ebd647 | |||
| b60e434e0b | |||
| 39d6c92069 | |||
| eb9f88bafc | |||
| aa431dfb20 | |||
| fff8e040b7 | |||
| 74636b7333 | |||
| 647fc13963 | |||
| d5e0714faf | |||
| a184013d1e | |||
| 7d08c4da7f | |||
| 01b92d1d56 | |||
| 790833e5d4 | |||
| 2cb2799a51 | |||
| 9dcf37dd19 | |||
| 0d89e99ceb | |||
| a5a1be7219 | |||
| 5aba967db9 | |||
| ffd1090718 | |||
| 22b9263674 | |||
| d21d35ca6f | |||
| 4e39f50aec | |||
| 9e0e80e820 | |||
| 562fb6945f | |||
| 822de45bfc | |||
| bd56163900 | |||
| 696615d392 | |||
| 645edfc936 | |||
| a227b212f5 | |||
| c11265e694 | |||
| 6344a76f83 | |||
| 3da7c31484 | |||
| 998c72ab5b | |||
| 00f323d132 | |||
| 80e591f487 | |||
| 1333f45cdc | |||
| 2ad88b59f6 | |||
| a9055f5ce2 | |||
| 9b0e89c4bf | |||
| 27f8609ac9 | |||
| 5cf503673f | |||
| 3837319141 | |||
| e70dd18734 | |||
| 158a7a881d | |||
| 725ed40a57 | |||
| 3733c069c9 | |||
| 1df75a951f | |||
| adfd8fb6a9 | |||
| 98f672b534 | |||
| e9068859b6 | |||
| 1203a2473d | |||
| 4a1ff913ab | |||
| 83918cad4b | |||
| d3c5ce268f | |||
| f60c5ad88a | |||
| bcda5bfe9b | |||
| 33eb8b1da5 | |||
| b069827bad | |||
| 74e416f04f | |||
| b395b06b65 | |||
| bd84db735d | |||
| bd99b207c9 | |||
| 2438557255 | |||
| 9f1826d83e | |||
| 676f5f6931 | |||
| 6d8bb497c8 | |||
| 5fd8684a5a | |||
| 1737555b0d | |||
| eda63c75c4 | |||
| 61f62eb3c7 | |||
| f96ebfca31 | |||
| fac580d1a9 | |||
| dc1017c929 | |||
| 07b688a0e6 | |||
| 20187f2970 | |||
| 84be318ca9 | |||
| 5035718e4b | |||
| fdc8fbaa45 | |||
| 99887da49a | |||
| 7a36a6c92a | |||
| 6beac0f215 | |||
| b59469c151 | |||
| b07466a477 | |||
| 0bd22e78d3 | |||
| 69e83e5086 | |||
| 8336785a9b | |||
| f073352632 | |||
| aad25205cd | |||
| dcdc453a55 | |||
| 5636575327 | |||
| 00f80c726a | |||
| 74db6c2b3b | |||
| d095ba84bf | |||
| 209e2de93b | |||
| c37c233d22 | |||
| 7b463769a5 | |||
| c7636bdc4c | |||
| 307d34e05a | |||
| 69e21dacb8 | |||
| f27a1ac040 | |||
| af6fdae3dd | |||
| 6ae22e084a | |||
| d463b26709 | |||
| 271e6192e8 | |||
| 51906bae6c | |||
| 406004a99a | |||
| b50894aabe | |||
| d6f07267ee | |||
| 1827cbfd2a | |||
| a0c0cb66c5 | |||
| 47aa4bbf8f | |||
| 33de70158c | |||
| f45a4e8243 | |||
| ac75f4e2ed | |||
| 631748480e | |||
| 3d5c759d62 | |||
| 2e0440e549 | |||
| 86beb5b730 | |||
| 289fd87ef8 | |||
| 8b11035b39 | |||
| 21f251eafb | |||
| e7b1c33955 | |||
| 1da0467820 | |||
| 05609de044 | |||
| 02fb43ff52 | |||
| 1626c0095f | |||
| 341ce621a9 | |||
| 52efe2412c | |||
| 84e3e76bb8 | |||
| 1d162e95c5 | |||
| 060843d912 | |||
| d3bc0a4ef7 | |||
| d1a82dde63 | |||
| 99efe80c61 | |||
| b12db57f34 | |||
| 9333fec5f1 | |||
| 6f94af9264 | |||
| 0ed98ea9b9 | |||
| 0b66144942 | |||
| b91a3eded3 | |||
| 7c9c0f6538 | |||
| 0d6846a882 | |||
| 84a68e0c25 | |||
| e82fa4eae0 | |||
| c79c6d76d8 | |||
| 36452136f1 | |||
| 17cfb0fc78 | |||
| e86ac90853 | |||
| 99e0f5b5cb | |||
| 4fc6bb7977 | |||
| 6e66ba321e | |||
| 2c2067ecc1 | |||
| e6a7a978d1 | |||
| 3e02f45f67 | |||
| b972f43513 | |||
| 30d02b1c78 | |||
| 479d01101d | |||
| 2b079136fb | |||
| 46c5759b88 | |||
| 7c883b6368 | |||
| 69daed7746 | |||
| 0b9afefa93 | |||
| 52490b92bf | |||
| 2261039d52 | |||
| 24323d3ce3 | |||
| c6e055689b | |||
| 2b5192b9ce | |||
| 77dfcb6e23 | |||
| 4fe837704b | |||
| cf58330936 | |||
| 287b873add | |||
| 115e7afe0b | |||
| a9e1fcd623 | |||
| 04e0b2e5c2 | |||
| 2403508e1b | |||
| b414545b6e | |||
| 3296471bda | |||
| eb5b6252bc | |||
| e5da857d4f | |||
| 09a8da5d6a | |||
| 863ad48a81 | |||
| de0e6ba222 | |||
| 91e5a925d9 | |||
| 5e7c168b25 | |||
| 6fccd202fe | |||
| 18e98fbba8 | |||
| a799d218fd | |||
| 9f0cbd3303 | |||
| 93fb8f35a8 | |||
| 2303fd51a3 | |||
| 910fc4915e | |||
| 002acb984e | |||
| bebe704688 | |||
| 9a006f3a68 | |||
| 58e2e4d742 | |||
| 60bc6a6da5 | |||
| b3f60b9320 | |||
| e9cf6dfb60 | |||
| 5e7847537a | |||
| 64787b1ac5 | |||
| 58fdb956b5 | |||
| 4d91118dd9 | |||
| ed872ca0a1 | |||
| 1bb1d41beb | |||
| 1db46aa5d5 | |||
| c991eaf916 | |||
| 86a69fd6d6 | |||
| 6735a3ccd6 | |||
| 6d565ef841 | |||
| b2e36314cb | |||
| 6904f12032 | |||
| c3a30e9be3 | |||
| 93b953fb48 | |||
| e2fdf09e9b | |||
| 4f44427966 | |||
| f8c0fab5d8 | |||
| 478d1b1a93 | |||
| a68eaa4e2d | |||
| 68c2bcb9dd | |||
| 635c04378d | |||
| 227c7aae0f | |||
| 641b751385 | |||
| 4201d50dcf | |||
| b05fb9c200 | |||
| 4f34d41523 | |||
| 91fc295a42 | |||
| 67d3a759a7 | |||
| 950b6a5e56 | |||
| db40fd314a | |||
| 6035bd522b | |||
| b8884687df | |||
| 18581f138f | |||
| f3867f8477 | |||
| 353285e5d9 | |||
| a56bcbf8fd | |||
| 81297fac88 | |||
| 6331dd125d | |||
| f8790c1ed7 | |||
| 5afbdf00db | |||
| 322a9598ab | |||
| ba86e8e095 | |||
| 5e423bc353 | |||
| 6eac859781 | |||
| f2c2c01f8e | |||
| 7434b3d6d2 | |||
| 63b5fc5971 | |||
| f507a0ea29 | |||
| c254d8703d | |||
| 981ec2dbdc | |||
| d5a75362ec | |||
| e748c3ea36 | |||
| 421ed4f8ab | |||
| 0b1f08043b | |||
| 759f8de81f | |||
| 96b550b722 | |||
| b961eea89d | |||
| d2dd6e40b6 | |||
| 070bcbcdbd | |||
| 46fe7ee76d | |||
| ba383a6d20 | |||
| a66f5f8f03 | |||
| 262b7dd7dd | |||
| 5d847ed4d9 | |||
| b3ca0c73b3 | |||
| d6a45ef14e | |||
| 54d74b1c26 | |||
| 657c56c650 | |||
| 50a903a62d | |||
| 0791e6639a | |||
| 59e9609926 | |||
| fadb2cf47e | |||
| 4d55d8fa8e | |||
| e31abffcb6 | |||
| cd47fbe953 | |||
| 42c6392533 | |||
| 3c9638b62e | |||
| 60ef284a9a | |||
| b40a01e97b | |||
| 34e3ce4ab4 | |||
| 4d6b48f39e | |||
| de99e7bf34 | |||
| 3430c7a289 | |||
| daf1784be4 | |||
| de92a02127 | |||
| 549590d105 | |||
| 82ca385725 | |||
| e33d9bb41b | |||
| 79b3a1b1a2 | |||
| c6a3c29eb4 | |||
| dd34d8df0f | |||
| 80d052d43f | |||
| 710f77dfe1 | |||
| b1e504d6c6 | |||
| 7deaee04c8 | |||
| 2020d56ba4 | |||
| a49fe53fa1 | |||
| bc3db5d4c1 | |||
| 30e202313d | |||
| 2e0bd06da2 | |||
| 3c4d0d0a77 | |||
| 403e7336a9 | |||
| fea2a8383c | |||
| ffe464a43e | |||
| 3fbcb1b282 | |||
| 28b2a0c881 | |||
| 7b9c1429d9 | |||
| d53ddd4a95 | |||
| 6ede3d9001 | |||
| c3cb0dcf80 | |||
| f214dccab9 | |||
| c0cce27703 | |||
| 2eded7a337 | |||
| 41a6f1cd84 | |||
| e1eed257f1 | |||
| 2bcb54b3cb | |||
| 7100e30bed | |||
| 7f6921e787 | |||
| 73ec224c93 | |||
| a62621eb59 | |||
| 84843d42da | |||
| d08185fc3e | |||
| efe09575e3 | |||
| c4796bb918 | |||
| 111f13f0ce | |||
| d357cf3a2e | |||
| 83f2849446 | |||
| d85be4a866 | |||
| f6f91298f0 | |||
| 1547922b61 | |||
| 602c18b394 | |||
| b5d4120adb | |||
| e851938199 | |||
| 48a2e11dfe | |||
| 22f60eace0 | |||
| b788f33c6a | |||
| 592548715f | |||
| 0983f0065d | |||
| c4f78a5dd5 | |||
| e032b86231 | |||
| a6a2ee2bf1 | |||
| 929367f0ab | |||
| 5a6340395f | |||
| f812433706 | |||
| 713b472253 | |||
| a1d2b673c6 | |||
| 5b2f0aa93d | |||
| ecbfcbb302 | |||
| 964185dec3 | |||
| 5c491987f3 | |||
| e1cf602487 | |||
| a3446507ec | |||
| ff61c7d92d | |||
| 726593c0a2 | |||
| 7826fddba7 | |||
| 38a450460d | |||
| de7751aae2 | |||
| cf7bc06856 | |||
| 7ac697be2c | |||
| 4de772f5ed | |||
| f7a7fc3b06 | |||
| b4b6029f66 | |||
| 071040f3eb | |||
| cd78c20e0e | |||
| 453a198250 | |||
| 7592122e4d | |||
| 609869f087 | |||
| 4fad1505c7 | |||
| 5881429952 | |||
| 526ed43d61 | |||
| ab9591ba80 | |||
| a8bcb0fcfe | |||
| b420316783 | |||
| 37c6782f95 | |||
| 70a4395a97 | |||
| 31c05c4c7d | |||
| 22018fd374 | |||
| d1f63f5c7e | |||
| 5d75264f0f | |||
| a605f66972 | |||
| 0328250554 | |||
| 70b5ffd928 | |||
| d9b9ed227b | |||
| 14274f8677 | |||
| af604379d3 | |||
| 7d83a08658 | |||
| 2ccbfea8c5 | |||
| fad287007b | |||
| cd9f820b85 | |||
| 582166d378 | |||
| ab9eecb104 | |||
| 52120a8c42 | |||
| a1aa74f96d | |||
| 6ae7ac97f6 | |||
| ba6c036628 | |||
| 7a2fda9076 | |||
| 41d2fde952 | |||
| f0e7396619 | |||
| 6139500e97 | |||
| 0b88944b38 | |||
| 61e33197b2 | |||
| 025e7db765 | |||
| 6f311e72b3 | |||
| a344d42a00 | |||
| f2159be68d | |||
| 7f7238378c | |||
| 1d2b989e8e | |||
| bc0f9b0ea5 | |||
| a885dabc81 | |||
| 6673da46b1 | |||
| 2e9587477c | |||
| 967ee13565 | |||
| a2bd1bb7f6 | |||
| ac3b3652c3 | |||
| 166a1070e5 | |||
| 94d3c447b7 | |||
| 9ff82aecef | |||
| d1af3ef1b3 | |||
| ffce7e3b08 | |||
| f896790ca3 | |||
| 960500a078 | |||
| ce25e2db98 | |||
| 463ae97117 | |||
| 350ab09855 | |||
| 312220fe63 | |||
| 72029b6847 | |||
| 525a5522b0 | |||
| 9c5975a706 | |||
| 9006f89f9f | |||
| 15169b245b | |||
| cc222c02a9 | |||
| 29ab824e5c | |||
| 8d828bc789 | |||
| f038cdc9c9 | |||
| 72d31c2471 | |||
| b31c92c27c | |||
| eb2cb5dd06 | |||
| 52d0df7961 | |||
| 12aadbed51 | |||
| 23703280ee | |||
| 5e50090da0 | |||
| b9257a1092 | |||
| 8cd58303f9 | |||
| b134645637 | |||
| d41cc437b3 | |||
| 26335e669e | |||
| 52b66c744f | |||
| 65c9711754 | |||
| 3d6988cf90 | |||
| c10a2cf15c | |||
| 44082c029f | |||
| 8ba0f008df | |||
| fcabd9957e | |||
| 9f12e870a9 | |||
| d24a2ed9a8 | |||
| b1cb7b5975 | |||
| 9ab997d788 | |||
| 90654cb2c9 | |||
| 9bd51db2b2 | |||
| 7e7193ae61 | |||
| a69333e2b8 | |||
| 1f35727442 | |||
| cbc18e6dcc | |||
| 60b48b0235 | |||
| f4624837a3 | |||
| 0a5af4b8ac | |||
| 74dfd3511f | |||
| ee56abcc8a | |||
| b67f60929c | |||
| 0b71dcded2 | |||
| f305382ef4 | |||
| 917b129517 | |||
| abc646a95c | |||
| 1697518da8 | |||
| 93e7984c61 | |||
| 8d9e12eda3 | |||
| fb0a96332c | |||
| ba7a0f7649 | |||
| a72de719c9 | |||
| ec6e728c0f | |||
| 70fbc7fe27 | |||
| ced4e2da3f | |||
| ae73f1a564 | |||
| 26127ee36a | |||
| 2f0471fff2 | |||
| ad833fb40d | |||
| a544f1517c | |||
| 67ad6abdaa | |||
| 0dfb27ff5f | |||
| ca8f2f2362 | |||
| 2de7fec6dc | |||
| 342e7bf9ff |
5
.env.example
Normal file
5
.env.example
Normal file
@ -0,0 +1,5 @@
|
||||
# configure your infura api key (not technically required)
|
||||
INFURA_API_KEY=
|
||||
|
||||
# change the mnemonic that your hd wallet is seeded with
|
||||
MNEMONIC=
|
||||
51
.eslintrc
Normal file
51
.eslintrc
Normal file
@ -0,0 +1,51 @@
|
||||
{
|
||||
"extends" : [
|
||||
"standard",
|
||||
"plugin:promise/recommended"
|
||||
],
|
||||
"plugins": [
|
||||
"promise"
|
||||
],
|
||||
"env": {
|
||||
"browser" : true,
|
||||
"node" : true,
|
||||
"mocha" : true,
|
||||
"jest" : true
|
||||
},
|
||||
"globals" : {
|
||||
"artifacts": false,
|
||||
"contract": false,
|
||||
"assert": false,
|
||||
"web3": false
|
||||
},
|
||||
"rules": {
|
||||
|
||||
// Strict mode
|
||||
"strict": [2, "global"],
|
||||
|
||||
// Code style
|
||||
"indent": [2, 2],
|
||||
"quotes": [2, "single"],
|
||||
"semi": ["error", "always"],
|
||||
"space-before-function-paren": ["error", "always"],
|
||||
"no-use-before-define": 0,
|
||||
"eqeqeq": [2, "smart"],
|
||||
"dot-notation": [2, {"allowKeywords": true, "allowPattern": ""}],
|
||||
"no-redeclare": [2, {"builtinGlobals": true}],
|
||||
"no-trailing-spaces": [2, { "skipBlankLines": true }],
|
||||
"eol-last": 1,
|
||||
"comma-spacing": [2, {"before": false, "after": true}],
|
||||
"camelcase": [2, {"properties": "always"}],
|
||||
"no-mixed-spaces-and-tabs": [2, "smart-tabs"],
|
||||
"comma-dangle": [1, "always-multiline"],
|
||||
"no-dupe-args": 2,
|
||||
"no-dupe-keys": 2,
|
||||
"no-debugger": 0,
|
||||
"no-undef": 2,
|
||||
"object-curly-spacing": [2, "always"],
|
||||
"max-len": [2, 120, 2],
|
||||
"generator-star-spacing": ["error", "before"],
|
||||
"promise/avoid-new": 0,
|
||||
"promise/always-return": 0
|
||||
}
|
||||
}
|
||||
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
@ -0,0 +1 @@
|
||||
*.sol linguist-language=Solidity
|
||||
34
.github/ISSUE_TEMPLATE.md
vendored
Normal file
34
.github/ISSUE_TEMPLATE.md
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
## 🎉 Description
|
||||
|
||||
<!-- Briefly describe the issue you are experiencing (or the feature you want to see added to OpenZeppelin). Tell us what you were trying to do and what happened instead. **Remember, this is _not_ a place to ask for help debugging code; for that, we welcome you in the [OpenZeppelin Slack Channel](https://slack.openzeppelin.org/).** -->
|
||||
|
||||
- [ ] 🐛 This is a bug report.
|
||||
- [ ] 📈 This is a feature request.
|
||||
|
||||
<!-- Please check one of the above by placing an x in the box. -->
|
||||
|
||||
## 💻 Environment
|
||||
|
||||
Next, we need to know what your environment looks like.
|
||||
|
||||
- Which version of OpenZeppelin are you using?
|
||||
- What network are you deploying to? Ganache? Ropsten?
|
||||
- How are you deploying your OpenZeppelin-backed contracts? truffle? Remix? Let us know!
|
||||
|
||||
## 📝 Details
|
||||
|
||||
Describe the problem you have been experiencing in more detail. Include as much information as you think is relevant. Keep in mind that transactions can fail for many reasons; context is key here.
|
||||
|
||||
## 🔢 Code To Reproduce Issue [ Good To Have ]
|
||||
|
||||
Please remember that with sample code it's easier to reproduce the bug and it's much faster to fix it.
|
||||
|
||||
```
|
||||
insert short code snippets here
|
||||
```
|
||||
|
||||
<!-- If your code is larger, consider linking us to a repo illustrating your issue. -->
|
||||
|
||||
## 👍 Other Information
|
||||
|
||||
<!-- List any other information that is relevant to your issue. Error logs, related issues, suggestions on how to fix, Stack Overflow links, forum links, etc. -->
|
||||
17
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
17
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
<!-- 0. 🎉 Thank you for submitting a PR! -->
|
||||
|
||||
<!-- 1. **Does this close any open issues?** If so, list them here. If not, remove the `Fixes #` line. -->
|
||||
|
||||
Fixes #
|
||||
|
||||
# 🚀 Description
|
||||
|
||||
<!-- 2. Describe the changes introduced in this pull request -->
|
||||
<!-- Include any context necessary for understanding the PR's purpose. -->
|
||||
|
||||
<!-- 3. Before submitting, please review the following checklist: -->
|
||||
|
||||
- [ ] 📘 I've reviewed the [OpenZeppelin Contributor Guidelines](../blob/master/CONTRIBUTING.md)
|
||||
- [ ] ✅ I've added tests where applicable to test my new functionality.
|
||||
- [ ] 📖 I've made sure that my contracts are well-documented.
|
||||
- [ ] 🎨 I've run the JS/Solidity linters and fixed any issues (`npm run lint:all:fix`).
|
||||
33
.gitignore
vendored
33
.gitignore
vendored
@ -1,5 +1,36 @@
|
||||
*.swp
|
||||
*.swo
|
||||
node_modules/
|
||||
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
allFiredEvents
|
||||
scTopics
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
coverage.json
|
||||
coverageEnv
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Dependency directory
|
||||
node_modules
|
||||
|
||||
# Debug log from npm
|
||||
npm-debug.log
|
||||
|
||||
# local env variables
|
||||
.env
|
||||
|
||||
# truffle build directory
|
||||
build/
|
||||
|
||||
# lol macs
|
||||
.DS_Store/
|
||||
|
||||
48
.jshintrc
Normal file
48
.jshintrc
Normal file
@ -0,0 +1,48 @@
|
||||
{
|
||||
"bitwise": false, // Prohibit bitwise operators (&, |, ^, etc.).
|
||||
"browser": true, // Standard browser globals e.g. `window`, `document`.
|
||||
"camelcase": false, // Permit only camelcase for `var` and `object indexes`.
|
||||
"curly": true, // Require {} for every new block or scope.
|
||||
"devel": false, // Allow development statements e.g. `console.log();`.
|
||||
"eqeqeq": true, // Require triple equals i.e. `===`.
|
||||
"esnext": true, // Allow ES.next specific features such as `const` and `let`.
|
||||
"freeze": true, // Forbid overwriting prototypes of native objects such as Array, Date and so on.
|
||||
"immed": true, // Require immediate invocations to be wrapped in parens e.g. `( function(){}() );`
|
||||
"indent": 2, // Specify indentation spacing
|
||||
"latedef": true, // Prohibit variable use before definition.
|
||||
"newcap": false, // Require capitalization of all constructor functions e.g. `new F()`.
|
||||
"noarg": true, // Prohibit use of `arguments.caller` and `arguments.callee`.
|
||||
"node": true, // Enable globals available when code is running inside of the NodeJS runtime environment.
|
||||
"noempty": true, // Prohibit use of empty blocks.
|
||||
"nonew": true, // Prohibits the use of constructor functions for side-effects
|
||||
"quotmark": "single", // Define quotes to string values.
|
||||
"regexp": true, // Prohibit `.` and `[^...]` in regular expressions.
|
||||
"smarttabs": false, // Supress warnings about mixed tabs and spaces
|
||||
"strict": true, // Require `use strict` pragma in every file.
|
||||
"trailing": true, // Prohibit trailing whitespaces.
|
||||
"undef": true, // Require all non-global variables be declared before they are used.
|
||||
"unused": true, // Warn unused variables.
|
||||
|
||||
"maxparams": 4, // Maximum number of parameters for a function
|
||||
"maxstatements": 15, // Maximum number of statements in a function
|
||||
"maxcomplexity": 10, // Cyclomatic complexity (http://en.wikipedia.org/wiki/Cyclomatic_complexity)
|
||||
"maxdepth": 4, // Maximum depth of nested control structures
|
||||
"maxlen": 120, // Maximum number of cols in a line
|
||||
"multistr": true, // Allow use of multiline EOL escaping
|
||||
"experimental": ["asyncawait", "asyncreqawait"],
|
||||
|
||||
"predef": [ // Extra globals.
|
||||
"after",
|
||||
"afterEach",
|
||||
"before",
|
||||
"beforeEach",
|
||||
"define",
|
||||
"describe",
|
||||
"exports",
|
||||
"it",
|
||||
"web3",
|
||||
"artifacts",
|
||||
"contract",
|
||||
"assert"
|
||||
]
|
||||
}
|
||||
1
.node-version
Normal file
1
.node-version
Normal file
@ -0,0 +1 @@
|
||||
v8.9.1
|
||||
9
.solcover.js
Normal file
9
.solcover.js
Normal file
@ -0,0 +1,9 @@
|
||||
module.exports = {
|
||||
norpc: true,
|
||||
testCommand: 'node --max-old-space-size=4096 ../node_modules/.bin/truffle test --network coverage',
|
||||
compileCommand: 'node --max-old-space-size=4096 ../node_modules/.bin/truffle compile --network coverage',
|
||||
skipFiles: [
|
||||
'lifecycle/Migrations.sol',
|
||||
'mocks'
|
||||
]
|
||||
}
|
||||
1
.soliumignore
Normal file
1
.soliumignore
Normal file
@ -0,0 +1 @@
|
||||
node_modules
|
||||
13
.soliumrc.json
Normal file
13
.soliumrc.json
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"extends": "solium:all",
|
||||
"plugins": ["security"],
|
||||
"rules": {
|
||||
"quotes": ["error", "double"],
|
||||
"no-empty-blocks": "off",
|
||||
"indentation": ["error", 2],
|
||||
"arg-overflow": ["warning", 3],
|
||||
"security/enforce-explicit-visibility": ["error"],
|
||||
"security/no-block-members": ["warning"],
|
||||
"security/no-inline-assembly": ["warning"]
|
||||
}
|
||||
}
|
||||
33
.travis.yml
33
.travis.yml
@ -1,12 +1,31 @@
|
||||
dist: trusty
|
||||
sudo: false
|
||||
sudo: required
|
||||
group: beta
|
||||
language: node_js
|
||||
node_js:
|
||||
- "6"
|
||||
before_install:
|
||||
- npm i -g ethereumjs-testrpc
|
||||
- npm i -g truffle
|
||||
- "8"
|
||||
cache:
|
||||
directories:
|
||||
- node_modules
|
||||
env:
|
||||
-
|
||||
- SOLIDITY_COVERAGE=true
|
||||
- SOLC_NIGHTLY=true
|
||||
matrix:
|
||||
fast_finish: true
|
||||
allow_failures:
|
||||
- env: SOLIDITY_COVERAGE=true
|
||||
- env: SOLC_NIGHTLY=true
|
||||
before_script:
|
||||
- truffle version
|
||||
script:
|
||||
- testrpc&
|
||||
- npm test
|
||||
- npm run lint
|
||||
- npm run lint:sol
|
||||
- npm run test
|
||||
notifications:
|
||||
slack:
|
||||
rooms:
|
||||
- secure: uEhwUkuwJp5pBNh+VTEytPHz3FDKsnPrKO+8MTAKv5hKi4PCRoVhLv6pklr82HUpL6pvSvJbUPA0HVebOXA+MMSxdny/BHZTh2mtw5Y78l2Ad0svDTWuV2Lus2pmhYigRhT0Wo00/SRX9+pxm0kg4EIFJSTS+uR9G76x0l9NljpEGXrqxlDxjxoHBgk8Ciru2LHaLzX/utE3jlABts4Sb1F3wc2BwFkjd6BDCRTGAPhVJwwFk41ZfnmLVbgSNUyk46Cb38oG5oXHb0FI3d3jV/k1OUhRyFfmA2fLXRk0wavibW8TG1gGJJWZ7xTCKzw/Cvup6mpehSAeQef8eekMdjpWEhF9hYRq1BvOs0384UU8NQ0O+BtdXU+X3Nyr84TMJN/iIfgN7gYX7AsvXH3jC0JfNUcIkWlJvyXdE6l2GV1hMmhL09GFEBbSpuSXRIWlOXTcYBlp5NbvE8xO8PUW+T6N5RG2XXjv1g8wCpr6Wwk1+LmRkX5trv8MFBZ2pM8p4H5da5++Ov8egLonNGK2jbx6aBLBX3tPf+g70LZEkiQ4eBfZw8VIgXIvKreisicppNuCD27gNmSEPNt0NkwiEBcTCJ9GSVAO0CU2g4ggvHDX2A+RW5XPET9bGkBXKLfFyV7Qe+MSQjXkCnW3bIRh7Wo1V31XiUiYOLuZPIiH3EQ=
|
||||
on_success: change
|
||||
on_failure: always
|
||||
on_pull_requests: false
|
||||
|
||||
121
CONTRIBUTING.md
121
CONTRIBUTING.md
@ -1,105 +1,58 @@
|
||||
Contributing to Zeppelin
|
||||
Contributing to OpenZeppelin
|
||||
=======
|
||||
|
||||
## Design Guidelines
|
||||
We really appreciate and value contributions to OpenZeppelin. Please take 5' to review the items listed below to make sure that your contributions are merged as soon as possible.
|
||||
|
||||
These are some global design goals in Zeppelin.
|
||||
## Contribution guidelines
|
||||
|
||||
### D0 - Security in Depth
|
||||
We strive to provide secure, tested, audited code. To achieve this, we need to match intention with function. Thus, documentation, code clarity, community review and security discussions are fundamental.
|
||||
Smart contracts manage value and are highly vulnerable to errors and attacks. We have very strict guidelines, please make sure to review them: ["Contribution guidelines wiki entry"](https://github.com/OpenZeppelin/openzeppelin-solidity/wiki/Contribution-guidelines).
|
||||
|
||||
### D1 - Simple and Modular
|
||||
Simpler code means easier audits, and better understanding of what each component does. We look for small files, small contracts, and small functions. If you can separate a contract into two independent functionalities you should probably do it.
|
||||
## Creating Pull Requests (PRs)
|
||||
|
||||
### D2 - Naming Matters
|
||||
As a contributor, you are expected to fork this repository, work on your own fork and then submit pull requests. The pull requests will be reviewed and eventually merged into the main repo. See ["Fork-a-Repo"](https://help.github.com/articles/fork-a-repo/) for how this works.
|
||||
|
||||
We take our time with picking names. Code is going to be written once, and read hundreds of times. Renaming for clarity is encouraged.
|
||||
*IMPORTANT*
|
||||
* Please see ["Git flow wiki entry"](https://github.com/OpenZeppelin/openzeppelin-solidity/wiki/Git-flow) for understanding how to use branches in this repository.
|
||||
|
||||
### D3 - Tests
|
||||
## A typical workflow
|
||||
|
||||
Write tests for all your code. We encourage Test Driven Development so we know when our code is right. Even though not all code in the repository is tested at the moment, we aim to test every line of code in the future.
|
||||
1) Make sure your fork is up to date with the main repository:
|
||||
|
||||
### D4 - Check preconditions and post-conditions
|
||||
```
|
||||
cd openzeppelin-solidity
|
||||
git fetch upstream
|
||||
git checkout development
|
||||
git pull --rebase upstream development
|
||||
```
|
||||
NOTE: The directory `openzeppelin-solidity` represents your fork's local copy.
|
||||
|
||||
A very important way to prevent vulnerabilities is to catch a contract’s inconsistent state as early as possible. This is why we want functions to check pre- and post-conditions for executing its logic. When writing code, ask yourself what you are expecting to be true before and after the function runs, and express it in code.
|
||||
|
||||
### D5 - Code Consistency
|
||||
|
||||
Consistency on the way classes are used is paramount to an easier understanding of the library. The codebase should be as unified as possible. Read existing code and get inspired before you write your own. Follow the style guidelines. Don’t hesitate to ask for help on how to best write a specific piece of code.
|
||||
|
||||
### D6 - Regular Audits
|
||||
Following good programming practices is a way to reduce the risk of vulnerabilities, but professional code audits are still needed. We will perform regular code audits on major releases, and hire security professionals to provide independent review.
|
||||
|
||||
## Style Guidelines
|
||||
|
||||
The design guidelines have quite a high abstraction level. These style guidelines are more concrete and easier to apply, and also more opinionated.
|
||||
|
||||
### General
|
||||
|
||||
#### G0 - Default to Solidity's official style guide.
|
||||
|
||||
Follow the official Solidity style guide: http://solidity.readthedocs.io/en/latest/style-guide.html
|
||||
|
||||
#### G1 - No Magic Constants
|
||||
|
||||
Avoid constants in the code as much as possible. Magic strings are also magic constants.
|
||||
|
||||
#### G2 - Code that Fails Early
|
||||
|
||||
We ask our code to fail as soon as possible when an unexpected input was provided or unexpected state was found.
|
||||
|
||||
#### G3 - Internal Amounts Must be Signed Integers and Represent the Smallest Units.
|
||||
|
||||
Avoid representation errors by always dealing with weis when handling ether. GUIs can convert to more human-friendly representations. Use Signed Integers (int) to prevent underflow problems.
|
||||
|
||||
|
||||
### Testing
|
||||
|
||||
#### T1 - Tests Must be Written Elegantly
|
||||
|
||||
Style guidelines are not relaxed for tests. Tests are a good way to show how to use the library, and maintaining them is extremely necessary.
|
||||
|
||||
Don't write long tests, write helper functions to make them be as short and concise as possible (they should take just a few lines each), and use good variable names.
|
||||
|
||||
#### T2 - Tests Must not be Random
|
||||
|
||||
Inputs for tests should not be generated randomly. Accounts used to create test contracts are an exception, those can be random. Also, the type and structure of outputs should be checked.
|
||||
|
||||
|
||||
### Documentation
|
||||
|
||||
TODO
|
||||
|
||||
## Pull Request Workflow
|
||||
|
||||
Our workflow is based on GitHub's pull requests. We use feature branches, prepended with: `test`, `feature`, `fix`, `refactor`, or `remove` according to the change the branch introduces. Some examples for such branches are:
|
||||
```sh
|
||||
git checkout -b test/some-module
|
||||
git checkout -b feature/some-new-stuff
|
||||
git checkout -b fix/some-bug
|
||||
git checkout -b remove/some-file
|
||||
2) Branch out from `development` into `fix/some-bug-#123`:
|
||||
(Postfixing #123 will associate your PR with the issue #123 and make everyone's life easier =D)
|
||||
```
|
||||
git checkout -b fix/some-bug-#123
|
||||
```
|
||||
|
||||
We expect pull requests to be rebased to the master branch before merging:
|
||||
```sh
|
||||
git remote add zep git@github.com:OpenZeppelin/zeppelin-solidity.git
|
||||
git pull --rebase zep master
|
||||
3) Make your changes, add your files, commit and push to your fork.
|
||||
|
||||
```
|
||||
git add SomeFile.js
|
||||
git commit "Fix some bug #123"
|
||||
git push origin fix/some-bug-#123
|
||||
```
|
||||
|
||||
Note that we require rebasing your branch instead of merging it, for commit readability reasons.
|
||||
4) Go to [github.com/OpenZeppelin/openzeppelin-solidity](https://github.com/OpenZeppelin/zeppelin-solidity) in your web browser and issue a new pull request.
|
||||
|
||||
After that, you can push the changes to your fork, by doing:
|
||||
```sh
|
||||
git push origin your_branch_name
|
||||
git push origin feature/some-new-stuff
|
||||
git push origin fix/some-bug
|
||||
```
|
||||
*IMPORTANT* Read the PR template very carefully and make sure to follow all the instructions. These instructions
|
||||
refer to some very important conditions that your PR must meet in order to be accepted, such as making sure that all tests pass, JS linting tests pass, solidity linting tests pass, etc.
|
||||
|
||||
Finally go to [github.com/OpenZeppelin/zeppelin-solidity](https://github.com/OpenZeppelin/zeppelin-solidity) in your web browser and issue a new pull request.
|
||||
5) Maintainers will review your code and possibly ask for changes before your code is pulled in to the main repository. We'll check that all tests pass, review the coding style, and check for general code correctness. If everything is OK, we'll merge your pull request and your code will be part of OpenZeppelin.
|
||||
|
||||
Main contributors will review your code and possibly ask for changes before your code is pulled in to the main repository. We'll check that all tests pass, review the coding style, and check for general code correctness. If everything is OK, we'll merge your pull request and your code will be part of Zeppelin.
|
||||
*IMPORTANT* Please pay attention to the maintainer's feedback, since its a necessary step to keep up with the standards OpenZeppelin attains to.
|
||||
|
||||
If you have any questions feel free to post them to
|
||||
[github.com/OpenZeppelin/zeppelin-solidity/issues](https://github.com/OpenZeppelin/zeppelin-solidity/issues).
|
||||
## All set!
|
||||
|
||||
If you have any questions feel free to post them to github.com/OpenZeppelin/openzeppelin-solidity/issues.
|
||||
|
||||
Finally, if you're looking to collaborate and want to find easy tasks to start, look at the issues we marked as ["Good first issue"](https://github.com/OpenZeppelin/openzeppelin-solidity/labels/good%20first%20issue).
|
||||
|
||||
Thanks for your time and code!
|
||||
|
||||
16
LICENSE
16
LICENSE
@ -5,18 +5,18 @@ Copyright (c) 2016 Smart Contract Solutions, Inc.
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
77
README.md
77
README.md
@ -1,89 +1,64 @@
|
||||
# Zeppelin Solidity
|
||||
[](https://www.npmjs.org/package/zeppelin-solidity)
|
||||
[](https://travis-ci.org/OpenZeppelin/zeppelin-solidity)
|
||||
# OpenZeppelin Solidity
|
||||
[](https://www.npmjs.org/package/openzeppelin-solidity)
|
||||
[](https://travis-ci.org/OpenZeppelin/openzeppelin-solidity)
|
||||
[](https://coveralls.io/github/OpenZeppelin/openzeppelin-solidity?branch=master)
|
||||
|
||||
Zeppelin is a library for writing secure [Smart Contracts](https://en.wikipedia.org/wiki/Smart_contract) on Ethereum.
|
||||
OpenZeppelin is a library for writing secure [Smart Contracts](https://en.wikipedia.org/wiki/Smart_contract) on Ethereum.
|
||||
|
||||
With Zeppelin, you can build distributed applications, protocols and organizations:
|
||||
With OpenZeppelin, you can build distributed applications, protocols and organizations:
|
||||
- using common contract security patterns (See [Onward with Ethereum Smart Contract Security](https://medium.com/bitcorps-blog/onward-with-ethereum-smart-contract-security-97a827e47702#.y3kvdetbz))
|
||||
- in the [Solidity language](http://solidity.readthedocs.io/en/develop/).
|
||||
- in the [Solidity language](https://solidity.readthedocs.io/en/develop/).
|
||||
|
||||
> NOTE: New to smart contract development? Check our [introductory guide](https://medium.com/zeppelin-blog/the-hitchhikers-guide-to-smart-contracts-in-ethereum-848f08001f05#.cox40d2ut).
|
||||
|
||||
## Getting Started
|
||||
|
||||
Zeppelin integrates with [Truffle](https://github.com/ConsenSys/truffle), an Ethereum development environment. Please install Truffle and initialize your project with `truffle init`.
|
||||
OpenZeppelin integrates with [Truffle](https://github.com/ConsenSys/truffle), an Ethereum development environment. Please install Truffle and initialize your project with `truffle init`.
|
||||
|
||||
```sh
|
||||
npm install -g truffle
|
||||
mkdir myproject && cd myproject
|
||||
truffle init
|
||||
```
|
||||
|
||||
To install the Zeppelin library, run:
|
||||
To install the OpenZeppelin library, run the following in your Solidity project root directory:
|
||||
```sh
|
||||
npm i zeppelin-solidity
|
||||
npm init -y
|
||||
npm install -E openzeppelin-solidity
|
||||
```
|
||||
|
||||
After that, you'll get all the library's contracts in the `contracts/zeppelin` folder. You can use the contracts in the library like so:
|
||||
**Note that OpenZeppelin does not currently follow semantic versioning.** You may encounter breaking changes upon a minor version bump. We recommend pinning the version of OpenZeppelin you use, as done by the `-E` (`--save-exact`) option.
|
||||
|
||||
```js
|
||||
import "./zeppelin/Ownable.sol";
|
||||
After that, you'll get all the library's contracts in the `node_modules/openzeppelin-solidity/contracts` folder. You can use the contracts in the library like so:
|
||||
|
||||
```solidity
|
||||
import 'openzeppelin-solidity/contracts/ownership/Ownable.sol';
|
||||
|
||||
contract MyContract is Ownable {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
> NOTE: The current distribution channel is npm, which is not ideal. [We're looking into providing a better tool for code distribution](https://github.com/OpenZeppelin/zeppelin-solidity/issues/13), and ideas are welcome.
|
||||
|
||||
#### Truffle Beta Support
|
||||
We also support Truffle Beta npm integration. If you're using Truffle Beta, the contracts in `node_modules` will be enough, so feel free to delete the copies at your `contracts` folder. If you're using Truffle Beta, you can use Zeppelin contracts like so:
|
||||
|
||||
```js
|
||||
import "zeppelin-solidity/contracts/Ownable.sol";
|
||||
|
||||
contract MyContract is Ownable {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
For more info see [the Truffle Beta package management tutorial](http://truffleframework.com/tutorials/package-management).
|
||||
|
||||
|
||||
## Security
|
||||
Zeppelin is meant to provide secure, tested and community-audited code, but please use common sense when doing anything that deals with real money! We take no responsibility for your implementation decisions and any security problem you might experience.
|
||||
OpenZeppelin is meant to provide secure, tested and community-audited code, but please use common sense when doing anything that deals with real money! We take no responsibility for your implementation decisions and any security problem you might experience.
|
||||
|
||||
If you find a security issue, please email [security@openzeppelin.org](mailto:security@openzeppelin.org).
|
||||
|
||||
## Developer Resources
|
||||
|
||||
Building a distributed application, protocol or organization with Zeppelin?
|
||||
Building a distributed application, protocol or organization with OpenZeppelin?
|
||||
|
||||
- Read documentation: http://zeppelin-solidity.readthedocs.io/en/latest/
|
||||
- Read documentation: https://openzeppelin.org/api/docs/open-zeppelin.html
|
||||
|
||||
- Ask for help and follow progress at: https://zeppelin-slackin.herokuapp.com/
|
||||
- Ask for help and follow progress at: https://slack.openzeppelin.org/
|
||||
|
||||
Interested in contributing to Zeppelin?
|
||||
Interested in contributing to OpenZeppelin?
|
||||
|
||||
- Framework proposal and roadmap: https://medium.com/zeppelin-blog/zeppelin-framework-proposal-and-development-roadmap-fdfa9a3a32ab#.iain47pak
|
||||
- Issue tracker: https://github.com/OpenZeppelin/zeppelin-solidity/issues
|
||||
- Contribution guidelines: https://github.com/OpenZeppelin/zeppelin-solidity/blob/master/CONTRIBUTING.md
|
||||
|
||||
## Collaborating organizations and audits by Zeppelin
|
||||
- [Golem](https://golem.network/)
|
||||
- [Mediachain](https://golem.network/)
|
||||
- [Truffle](http://truffleframework.com/)
|
||||
- [Firstblood](http://firstblood.io/)
|
||||
- [Rootstock](http://www.rsk.co/)
|
||||
- [Consensys](https://consensys.net/)
|
||||
- [DigixGlobal](https://www.dgx.io/)
|
||||
- [Coinfund](https://coinfund.io/)
|
||||
- [DemocracyEarth](http://democracy.earth/)
|
||||
- [Signatura](https://signatura.co/)
|
||||
- [Ether.camp](http://www.ether.camp/)
|
||||
|
||||
among others...
|
||||
|
||||
- Issue tracker: https://github.com/OpenZeppelin/openzeppelin-solidity/issues
|
||||
- Contribution guidelines: https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/CONTRIBUTING.md
|
||||
- Wiki: https://github.com/OpenZeppelin/openzeppelin-solidity/wiki
|
||||
|
||||
## License
|
||||
Code released under the [MIT License](https://github.com/OpenZeppelin/zeppelin-solidity/blob/master/LICENSE).
|
||||
Code released under the [MIT License](https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/LICENSE).
|
||||
|
||||
290
audit/ZeppelinAudit.md
Normal file
290
audit/ZeppelinAudit.md
Normal file
@ -0,0 +1,290 @@
|
||||
# OpenZeppelin Audit
|
||||
|
||||
March, 2017
|
||||
Authored by Dennis Peterson and Peter Vessenes
|
||||
|
||||
# Introduction
|
||||
|
||||
Zeppelin requested that New Alchemy perform an audit of the contracts in their OpenZeppelin library. The OpenZeppelin contracts are a set of contracts intended to be a safe building block for a variety of uses by parties that may not be as sophisticated as the OpenZeppelin team. It is a design goal that the contracts be deployable safely and "as-is".
|
||||
|
||||
The contracts are hosted at:
|
||||
|
||||
https://github.com/OpenZeppelin/zeppelin-solidity
|
||||
|
||||
All the contracts in the "contracts" folder are in scope.
|
||||
|
||||
The git commit hash we evaluated is:
|
||||
9c5975a706b076b7000e8179f8101e0c61024c87
|
||||
|
||||
# Disclaimer
|
||||
|
||||
The audit makes no statements or warrantees about utility of the code, safety of the code, suitability of the business model, regulatory regime for the business model, or any other statements about fitness of the contracts to purpose, or their bugfree status. The audit documentation is for discussion purposes only.
|
||||
|
||||
# Executive Summary
|
||||
|
||||
Overall the OpenZeppelin codebase is of reasonably high quality -- it is clean, modular and follows best practices throughout.
|
||||
|
||||
It is still in flux as a codebase, and needs better documentation per file as to expected behavior and future plans. It probably needs more comprehensive and aggressive tests written by people less nice than the current OpenZeppelin team.
|
||||
|
||||
We identified two critical errors and one moderate issue, and would not recommend this commit hash for public use until these bugs are remedied.
|
||||
|
||||
The repository includes a set of Truffle unit tests, a requirement and best practice for smart contracts like these; we recommend these be bulked up.
|
||||
|
||||
# Discussion
|
||||
|
||||
## Big Picture: Is This A Worthwhile Project?
|
||||
|
||||
As soon as a developer touches OpenZeppelin contracts, they will modify something, leaving them in an un-audited state. We do not recommend developers deploy any unaudited code to the Blockchain if it will handle money, information or other things of value.
|
||||
|
||||
> "In accordance with Unix philosophy, Perl gives you enough rope to hang yourself"
|
||||
> --Larry Wall
|
||||
|
||||
We think this is an incredibly worthwhile project -- aided by the high code quality. Creating a framework that can be easily extended helps increase the average code quality on the Blockchain by charting a course for developers and encouraging containment of modifications to certain sections.
|
||||
|
||||
> "Rust: The language that makes you take the safety off before shooting yourself in the foot"
|
||||
> -- (@mbrubeck)
|
||||
|
||||
We think much more could be done here, and recommend the OpenZeppelin team keep at this and keep focusing on the design goal of removing rope and adding safety.
|
||||
|
||||
## Solidity Version Updates Recommended
|
||||
|
||||
Most of the code uses Solidity 0.4.11, but some files under `Ownership` are marked 0.4.0. These should be updated.
|
||||
|
||||
Solidity 0.4.10 will add several features which could be useful in these contracts:
|
||||
|
||||
- `assert(condition)`, which throws if the condition is false
|
||||
|
||||
- `revert()`, which rolls back without consuming all remaining gas.
|
||||
|
||||
- `address.transfer(value)`, which is like `send` but automatically propagates exceptions, and supports `.gas()`. See https://github.com/ethereum/solidity/issues/610 for more on this.
|
||||
|
||||
## Error Handling: Throw vs Return False
|
||||
Solidity standards allow two ways to handle an error -- either calling `throw` or returning `false`. Both have benefits. In particular, a `throw` guarantees a complete wipe of the call stack (up to the preceding external call), whereas `false` allows a function to continue.
|
||||
|
||||
In general we prefer `throw` in our code audits, because it is simpler -- it's less for an engineer to keep track of. Returning `false` and using logic to check results can quickly become a poorly-tracked state machine, and this sort of complexity can cause errors.
|
||||
|
||||
In the OpenZeppelin contracts, both styles are used in different parts of the codebase. `SimpleToken` transfers throw upon failure, while the full ERC20 token returns `false`. Some modifiers `throw`, others just wrap the function body in a conditional, effectively allowing the function to return false if the condition is not met.
|
||||
|
||||
We don't love this, and would usually recommend you stick with one style or the other throughout the codebase.
|
||||
|
||||
In at least one case, these different techniques are combined cleverly (see the Multisig comments, line 65). As a set of contracts intended for general use, we recommend you either strive for more consistency or document explicit design criteria that govern which techniques are used where.
|
||||
|
||||
Note that it may be impossible to use either one in all situations. For example, SafeMath functions pretty much have to throw upon failure, but ERC20 specifies returning booleans. Therefore we make no particular recommendations, but simply point out inconsistencies to consider.
|
||||
|
||||
# Critical Issues
|
||||
|
||||
## Stuck Ether in Crowdsale contract
|
||||
CrowdsaleToken.sol has no provision for withdrawing the raised ether. We *strongly* recommend a standard `withdraw` function be added. There is no scenario in which someone should deploy this contract as is, whether for testing or live.
|
||||
|
||||
## Recursive Call in MultisigWallet
|
||||
Line 45 of `MultisigWallet.sol` checks if the amount being sent by `execute` is under a daily limit.
|
||||
|
||||
This function can only be called by the "Owner". As a first angle of attack, it's worth asking what will happen if the multisig wallet owners reset the daily limit by approving a call to `resetSpentToday`.
|
||||
|
||||
If a chain of calls can be constructed in which the owner confirms the `resetSpentToday` function and then withdraws through `execute` in a recursive call, the contract can be drained. In fact, this could be done without a recursive call, just through repeated `execute` calls alternating with the `confirm` calls.
|
||||
|
||||
We are still working through the confirmation protocol in `Shareable.sol`, but we are not convinced that this is impossible, in fact it looks possible. The flexibility any shared owner has in being able to revoke confirmation later is another worrisome angle of approach even if some simple patches are included.
|
||||
|
||||
This bug has a number of causes that need to be addressed:
|
||||
|
||||
1. `resetSpentToday` and `confirm` together do not limit the days on which the function can be called or (it appears) the number of times it can be called.
|
||||
1. Once a call has been confirmed and `execute`d it appears that it can be re-executed. This is not good.
|
||||
3. `confirmandCheck` doesn't seem to have logic about whether or not the function in question has been called.
|
||||
4. Even if it did, `revoke` would need updates and logic to deal with revocation requests after a function call had been completed.
|
||||
|
||||
We do not recommend using the MultisigWallet until these issues are fixed.
|
||||
|
||||
# Moderate to Minor Issues
|
||||
|
||||
## PullPayment
|
||||
PullPayment.sol needs some work. It has no explicit provision for cancelling a payment. This would be desirable in a number of scenarios; consider a payee losing their wallet, or giving a griefing address, or just an address that requires more than the default gas offered by `send`.
|
||||
|
||||
`asyncSend` has no overflow checking. This is a bad plan. We recommend overflow and underflow checking at the layer closest to the data manipulation.
|
||||
|
||||
`asyncSend` allows more balance to be queued up for sending than the contract holds. This is probably a bad idea, or at the very least should be called something different. If the intent is to allow this, it should have provisions for dealing with race conditions between competing `withdrawPayments` calls.
|
||||
|
||||
It would be nice to see how many payments are pending. This would imply a bit of a rewrite; we recommend this contract get some design time, and that developers don't rely on it in its current state.
|
||||
|
||||
## Shareable Contract
|
||||
|
||||
We do not believe the `Shareable.sol` contract is ready for primetime. It is missing functions, and as written may be vulnerable to a reordering attack -- an attack in which a miner or other party "racing" with a smart contract participant inserts their own information into a list or mapping.
|
||||
|
||||
The confirmation and revocation code needs to be looked over with a very careful eye imagining extraordinarily bad behavior by shared owners before this contract can be called safe.
|
||||
|
||||
No sanity checks on the initial constructor's `required` argument are worrisome as well.
|
||||
|
||||
# Line by Line Comments
|
||||
|
||||
## Lifecycle
|
||||
|
||||
### Killable
|
||||
|
||||
Very simple, allows owner to call selfdestruct, sending funds to owner. No issues. However, note that `selfdestruct` should typically not be used; it is common that a developer may want to access data in a former contract, and they may not understand that `selfdestruct` limits access to the contract. We recommend better documentation about this dynamic, and an alternate function name for `kill` like `completelyDestroy` while `kill` would perhaps merely send funds to the owner.
|
||||
|
||||
Also note that a killable function allows the owner to take funds regardless of other logic. This may be desirable or undesirable depending on the circumstances. Perhaps `Killable` should have a different name as well.
|
||||
|
||||
### Migrations
|
||||
|
||||
I presume that the goal of this contract is to allow and annotate a migration to a new smart contract address. We are not clear here how this would be accomplished by the code; we'd like to review with the OpenZeppelin team.
|
||||
|
||||
### Pausable
|
||||
|
||||
We like these pauses! Note that these allow significant griefing potential by owners, and that this might not be obvious to participants in smart contracts using the OpenZeppelin framework. We would recommend that additional sample logic be added to for instance the TokenContract showing safer use of the pause and resume functions. In particular, we would recommend a timelock after which anyone could unpause the contract.
|
||||
|
||||
The modifers use the pattern `if(bool){_;}`. This is fine for functions that return false upon failure, but could be problematic for functions expected to throw upon failure. See our comments above on standardizing on `throw` or `return(false)`.
|
||||
|
||||
## Ownership
|
||||
|
||||
### Ownable
|
||||
|
||||
Line 19: Modifier throws if doesn't meet condition, in contrast to some other inheritable modifiers (e.g. in Pausable) that use `if(bool){_;}`.
|
||||
|
||||
### Claimable
|
||||
|
||||
Inherits from Ownable but the existing owner sets a pendingOwner who has to claim ownership.
|
||||
|
||||
Line 17: Another modifier that throws.
|
||||
|
||||
### DelayedClaimable
|
||||
|
||||
Is there any reason to descend from Ownable directly, instead of just Claimable, which descends from Ownable? If not, descending from both just adds confusion.
|
||||
|
||||
### Contactable
|
||||
|
||||
Allows owner to set a public string of contract information. No issues.
|
||||
|
||||
### Shareable
|
||||
|
||||
This needs some work. Doesn't check if `_required <= len(_owners)` for instance, that would be a bummer. What if _required were like `MAX - 1`?
|
||||
|
||||
I have a general concern about the difference between `owners`, `_owners`, and `owner` in `Ownable.sol`. I recommend "Owners" be renamed. In general we do not recomment single character differences in variable names, although a preceding underscore is not uncommon in Solidity code.
|
||||
|
||||
Line 34: "this contract only has six types of events"...actually only two.
|
||||
|
||||
Line 61: Why is `ownerIndex` keyed by addresses hashed to `uint`s? Why not use the addresses directly, so `ownerIndex` is less obscure, and so there's stronger typing?
|
||||
|
||||
Line 62: Do not love `++i) ... owners[2+ i]`. Makes me do math, which is not what I want to do. I want to not have to do math.
|
||||
|
||||
There should probably be a function for adding a new operation, so the developer doesn't have to work directly with the internal data. (This would make the multisig contract even shorter.)
|
||||
|
||||
There's a `revoke` function but not a `propose` function that we can see.
|
||||
|
||||
Beware reordering. If `propose` allows the user to choose a bytes string for their proposal, bad things(TM) will happen as currently written.
|
||||
|
||||
|
||||
### Multisig
|
||||
|
||||
Just an interface. Note it allows changing an owner address, but not changing the number of owners. This is somewhat limiting but also simplifies implementation.
|
||||
|
||||
## Payment
|
||||
|
||||
### PullPayment
|
||||
|
||||
Safe from reentrance attack since ether send is at the end, plus it uses `.send()` rather than `.call.value()`.
|
||||
|
||||
There's an argument to be made that `.call.value()` is a better option *if* you're sure that it will be done after all state updates, since `.send` will fail if the recipient has an expensive fallback function. However, in the context of a function meant to be embedded in other contracts, it's probably better to use `.send`. One possible compromise is to add a function which allows only the owner to send ether via `.call.value`.
|
||||
|
||||
If you don't use `call.value` you should implement a `cancel` function in case some value is pending here.
|
||||
|
||||
Line 14:
|
||||
Doesn't use safeAdd. Although it appears that payout amounts can only be increased, in fact the payer could lower the payout as much as desired via overflow. Also, the payer could add a large non-overflowing amount, causing the payment to exceed the contract balance and therefore fail when withdraw is attempted.
|
||||
|
||||
Recommendation: track the sum of non-withdrawn asyncSends, and don't allow a new one which exceeds the leftover balance. If it's ever desirable to make payments revocable, it should be done explicitly.
|
||||
|
||||
## Tokens
|
||||
|
||||
### ERC20
|
||||
|
||||
Standard ERC20 interface only.
|
||||
|
||||
There's a security hole in the standard, reported at Edcon: `approve` does not protect against race conditions and simply replaces the current value. An approved spender could wait for the owner to call `approve` again, then attempt to spend the old limit before the new limit is applied. If successful, this attacker could successfully spend the sum of both limits.
|
||||
|
||||
This could be fixed by either (1) including the old limit as a parameter, so the update will fail if some gets spent, or (2) using the value parameter as a delta instead of replacement value.
|
||||
|
||||
This is not fixable while adhering to the current full ERC20 standard, though it would be possible to add a "secureApprove" function. The impact isn't extreme since at least you can only be attacked by addresses you approved. Also, users could mitigate this by always setting spending limits to zero and checking for spends, before setting the new limit.
|
||||
|
||||
Edcon slides:
|
||||
https://drive.google.com/file/d/0ByMtMw2hul0EN3NCaVFHSFdxRzA/view
|
||||
|
||||
### ERC20Basic
|
||||
|
||||
Simpler interface skipping the Approve function. Note this departs from ERC20 in another way: transfer throws instead of returning false.
|
||||
|
||||
### BasicToken
|
||||
|
||||
Uses `SafeSub` and `SafeMath`, so transfer `throw`s instead of returning false. This complies with ERC20Basic but not the actual ERC20 standard.
|
||||
|
||||
### StandardToken
|
||||
|
||||
Implementation of full ERC20 token.
|
||||
|
||||
Transfer() and transferFrom() use SafeMath functions, which will cause them to throw instead of returning false. Not a security issue but departs from standard.
|
||||
|
||||
### SimpleToken
|
||||
|
||||
Sample instantiation of StandardToken. Note that in this sample, decimals is 18 and supply only 10,000, so the supply is a small fraction of a single nominal token.
|
||||
|
||||
### CrowdsaleToken
|
||||
|
||||
StandardToken which mints tokens at a fixed price when sent ether.
|
||||
|
||||
There's no provision for owner withdrawing the ether. As a sample for crowdsales it should be Ownable and allow the owner to withdraw ether, rather than stranding the ether in the contract.
|
||||
|
||||
Note: an alternative pattern is a mint() function which is only callable from a separate crowdsale contract, so any sort of rules can be added without modifying the token itself.
|
||||
|
||||
### VestedToken
|
||||
|
||||
Lines 23, 27:
|
||||
Functions `transfer()` and `transferFrom()` have a modifier canTransfer which throws if not enough tokens are available. However, transfer() returns a boolean success. Inconsistent treatment of failure conditions may cause problems for other contracts using the token. (Note that transferableTokens() relies on safeSub(), so will also throw if there's insufficient balance.)
|
||||
|
||||
Line 64:
|
||||
Delete not actually necessary since the value is overwritten in the next line anyway.
|
||||
|
||||
## Root level
|
||||
|
||||
### Bounty
|
||||
|
||||
Avoids potential race condition by having each researcher deploy a separate contract for attack; if a research manages to break his associated contract, other researchers can't immediately claim the reward, they have to reproduce the attack in their own contracts.
|
||||
|
||||
A developer could subvert this intent by implementing `deployContract()` to always return the same address. However, this would break the `researchers` mapping, updating the researcher address associated with the contract. This could be prevented by blocking rewrites in `researchers`.
|
||||
|
||||
### DayLimit
|
||||
|
||||
The modifier `limitedDaily` calls `underLimit`, which both checks that the spend is below the daily limit, and adds the input value to the daily spend. This is fine if all functions throw upon failure. However, not all OpenZeppelin functions do this; there are functions that returns false, and modifiers that wrap the function body in `if (bool) {_;}`. In these cases, `_value` will be added to `spentToday`, but ether may not actually be sent because other preconditions were not met. (However in the OpenZeppelin multisig this is not a problem.)
|
||||
|
||||
Lines 4, 11:
|
||||
Comment claims that `DayLimit` is multiowned, and Shareable is imported, but DayLimit does not actually inherit from Shareable. The intent may be for child contracts to inherit from Shareable (as Multisig does); in this case the import should be removed and the comment altered.
|
||||
|
||||
Line 46:
|
||||
Manual overflow check instead of using safeAdd. Since this is called from a function that throws upon failure anyway, there's no real downside to using safeAdd.
|
||||
|
||||
### LimitBalance
|
||||
|
||||
No issues.
|
||||
|
||||
### MultisigWallet
|
||||
|
||||
Lines 28, 76, 80:
|
||||
`kill`, `setDailyLimit`, and `resetSpentToday` only happen with multisig approval, and hashes for these actions are logged by Shareable. However, they should probably post their own events for easy reading.
|
||||
|
||||
Line 45:
|
||||
This call to underLimit will reduce the daily limit, and then either throw or return 0. So in this case there's no danger that the limit will be reduced without the operation going through.
|
||||
|
||||
Line 65:
|
||||
Shareable's onlyManyOwners will take the user's confirmation, and execute the function body if and only if enough users have confirmed. Whole thing throws if the send fails, which will roll back the confirmation. Confirm returns false if not enough have confirmed yet, true if the whole thing succeeds, and throws only in the exceptional circumstance that the designated transaction unexpectedly fails. Elegant design.
|
||||
|
||||
Line 68:
|
||||
Throw here is good but note this function can fail either by returning false or by throwing.
|
||||
|
||||
Line 92:
|
||||
A bit odd to split `clearPending()` between this contract and Shareable. However this does allow contracts inheriting from Shareable to use custom structs for pending transactions.
|
||||
|
||||
|
||||
### SafeMath
|
||||
|
||||
Another interesting comment from the same Edcon presentation was that the overflow behavior of Solidity is undocumented, so in theory, source code that relies on it could break with a future revision.
|
||||
|
||||
However, compiled code should be fine, and in the unlikely event that the compiler is revised in this way, there should be plenty of warning. (But this is an argument for keeping overflow checks isolated in SafeMath.)
|
||||
|
||||
Aside from that small caveat, these are fine.
|
||||
|
||||
2
contracts/.npmignore
Normal file
2
contracts/.npmignore
Normal file
@ -0,0 +1,2 @@
|
||||
mocks
|
||||
examples
|
||||
28
contracts/AddressUtils.sol
Normal file
28
contracts/AddressUtils.sol
Normal file
@ -0,0 +1,28 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
|
||||
/**
|
||||
* Utility library of inline functions on addresses
|
||||
*/
|
||||
library AddressUtils {
|
||||
|
||||
/**
|
||||
* Returns whether the target address is a contract
|
||||
* @dev This function will return false if invoked during the constructor of a contract,
|
||||
* as the code is not actually created until after the constructor finishes.
|
||||
* @param addr address to check
|
||||
* @return whether the target address is a contract
|
||||
*/
|
||||
function isContract(address addr) internal view returns (bool) {
|
||||
uint256 size;
|
||||
// XXX Currently there is no better way to check if there is a contract in an address
|
||||
// than to check the size of the code at that address.
|
||||
// See https://ethereum.stackexchange.com/a/14016/36603
|
||||
// for more details about how this works.
|
||||
// TODO Check this again before the Serenity release, because all addresses will be
|
||||
// contracts then.
|
||||
assembly { size := extcodesize(addr) } // solium-disable-line security/no-inline-assembly
|
||||
return size > 0;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,58 +0,0 @@
|
||||
pragma solidity ^0.4.4;
|
||||
|
||||
|
||||
import './PullPayment.sol';
|
||||
import './Killable.sol';
|
||||
|
||||
|
||||
/*
|
||||
* Bounty
|
||||
*
|
||||
* This bounty will pay out to a researcher if they break invariant logic of the contract.
|
||||
*/
|
||||
contract Bounty is PullPayment, Killable {
|
||||
Target target;
|
||||
bool public claimed;
|
||||
mapping(address => address) public researchers;
|
||||
|
||||
event TargetCreated(address createdAddress);
|
||||
|
||||
function() payable {
|
||||
if (claimed) throw;
|
||||
}
|
||||
|
||||
function createTarget() returns(Target) {
|
||||
target = Target(deployContract());
|
||||
researchers[target] = msg.sender;
|
||||
TargetCreated(target);
|
||||
return target;
|
||||
}
|
||||
|
||||
function deployContract() internal returns(address);
|
||||
|
||||
function checkInvariant() returns(bool){
|
||||
return target.checkInvariant();
|
||||
}
|
||||
|
||||
function claim(Target target) {
|
||||
address researcher = researchers[target];
|
||||
if (researcher == 0) throw;
|
||||
// Check Target contract invariants
|
||||
if (target.checkInvariant()) {
|
||||
throw;
|
||||
}
|
||||
asyncSend(researcher, this.balance);
|
||||
claimed = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Target
|
||||
*
|
||||
* Your main contract should inherit from this class and implement the checkInvariant method. This is a function that should check everything your contract assumes to be true all the time. If this function returns false, it means your contract was broken in some way and is in an inconsistent state. This is what security researchers will try to acomplish when trying to get the bounty.
|
||||
*/
|
||||
contract Target {
|
||||
function checkInvariant() returns(bool);
|
||||
}
|
||||
|
||||
@ -1,29 +0,0 @@
|
||||
pragma solidity ^0.4.0;
|
||||
|
||||
|
||||
import './Ownable.sol';
|
||||
|
||||
|
||||
/*
|
||||
* Claimable
|
||||
*
|
||||
* Extension for the Ownable contract, where the ownership needs to be claimed. This allows the new owner to accept the transfer.
|
||||
*/
|
||||
contract Claimable is Ownable {
|
||||
address public pendingOwner;
|
||||
|
||||
modifier onlyPendingOwner() {
|
||||
if (msg.sender == pendingOwner)
|
||||
_;
|
||||
}
|
||||
|
||||
function transferOwnership(address newOwner) onlyOwner {
|
||||
pendingOwner = newOwner;
|
||||
}
|
||||
|
||||
function claimOwnership() onlyPendingOwner {
|
||||
owner = pendingOwner;
|
||||
pendingOwner = 0x0;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,75 +0,0 @@
|
||||
pragma solidity ^0.4.4;
|
||||
|
||||
|
||||
import './Shareable.sol';
|
||||
|
||||
|
||||
/*
|
||||
* DayLimit
|
||||
*
|
||||
* inheritable "property" contract that enables methods to be protected by placing a linear limit (specifiable)
|
||||
* on a particular resource per calendar day. is multiowned to allow the limit to be altered. resource that method
|
||||
* uses is specified in the modifier.
|
||||
*/
|
||||
contract DayLimit {
|
||||
// FIELDS
|
||||
|
||||
uint public dailyLimit;
|
||||
uint public spentToday;
|
||||
uint public lastDay;
|
||||
|
||||
|
||||
// MODIFIERS
|
||||
|
||||
// simple modifier for daily limit.
|
||||
modifier limitedDaily(uint _value) {
|
||||
if (underLimit(_value))
|
||||
_;
|
||||
}
|
||||
|
||||
|
||||
// CONSTRUCTOR
|
||||
// stores initial daily limit and records the present day's index.
|
||||
function DayLimit(uint _limit) {
|
||||
dailyLimit = _limit;
|
||||
lastDay = today();
|
||||
}
|
||||
|
||||
|
||||
// METHODS
|
||||
|
||||
// (re)sets the daily limit. doesn't alter the amount already spent today.
|
||||
function _setDailyLimit(uint _newLimit) internal {
|
||||
dailyLimit = _newLimit;
|
||||
}
|
||||
|
||||
// resets the amount already spent today.
|
||||
function _resetSpentToday() internal {
|
||||
spentToday = 0;
|
||||
}
|
||||
|
||||
|
||||
// INTERNAL METHODS
|
||||
|
||||
// checks to see if there is at least `_value` left from the daily limit today. if there is, subtracts it and
|
||||
// returns true. otherwise just returns false.
|
||||
function underLimit(uint _value) internal returns (bool) {
|
||||
// reset the spend limit if we're on a different day to last time.
|
||||
if (today() > lastDay) {
|
||||
spentToday = 0;
|
||||
lastDay = today();
|
||||
}
|
||||
// check to see if there's enough left - if so, subtract and return true.
|
||||
// overflow protection // dailyLimit check
|
||||
if (spentToday + _value >= spentToday && spentToday + _value <= dailyLimit) {
|
||||
spentToday += _value;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// determines today's index.
|
||||
function today() private constant returns (uint) {
|
||||
return now / 1 days;
|
||||
}
|
||||
}
|
||||
@ -1,30 +0,0 @@
|
||||
pragma solidity ^0.4.4;
|
||||
import './Ownable.sol';
|
||||
import './Claimable.sol';
|
||||
|
||||
/*
|
||||
* DelayedClaimable
|
||||
* Extension for the Claimable contract, where the ownership needs to be claimed before/after certain block number
|
||||
*/
|
||||
|
||||
contract DelayedClaimable is Ownable, Claimable {
|
||||
|
||||
uint public claimBeforeBlock;
|
||||
uint public claimAfterBlock;
|
||||
|
||||
function setClaimBlocks(uint _claimBeforeBlock, uint _claimAfterBlock) onlyOwner {
|
||||
if (_claimAfterBlock > claimBeforeBlock)
|
||||
throw;
|
||||
claimBeforeBlock = _claimBeforeBlock;
|
||||
claimAfterBlock = _claimAfterBlock;
|
||||
}
|
||||
|
||||
function claimOwnership() onlyPendingOwner {
|
||||
if ((block.number > claimBeforeBlock) || (block.number < claimAfterBlock))
|
||||
throw;
|
||||
owner = pendingOwner;
|
||||
pendingOwner = 0x0;
|
||||
claimBeforeBlock = 0;
|
||||
}
|
||||
|
||||
}
|
||||
76
contracts/ECRecovery.sol
Normal file
76
contracts/ECRecovery.sol
Normal file
@ -0,0 +1,76 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
|
||||
/**
|
||||
* @title Eliptic curve signature operations
|
||||
*
|
||||
* @dev Based on https://gist.github.com/axic/5b33912c6f61ae6fd96d6c4a47afde6d
|
||||
*
|
||||
* TODO Remove this library once solidity supports passing a signature to ecrecover.
|
||||
* See https://github.com/ethereum/solidity/issues/864
|
||||
*
|
||||
*/
|
||||
|
||||
library ECRecovery {
|
||||
|
||||
/**
|
||||
* @dev Recover signer address from a message by using their signature
|
||||
* @param hash bytes32 message, the hash is the signed message. What is recovered is the signer address.
|
||||
* @param sig bytes signature, the signature is generated using web3.eth.sign()
|
||||
*/
|
||||
function recover(bytes32 hash, bytes sig)
|
||||
internal
|
||||
pure
|
||||
returns (address)
|
||||
{
|
||||
bytes32 r;
|
||||
bytes32 s;
|
||||
uint8 v;
|
||||
|
||||
// Check the signature length
|
||||
if (sig.length != 65) {
|
||||
return (address(0));
|
||||
}
|
||||
|
||||
// Divide the signature in r, s and v variables
|
||||
// ecrecover takes the signature parameters, and the only way to get them
|
||||
// currently is to use assembly.
|
||||
// solium-disable-next-line security/no-inline-assembly
|
||||
assembly {
|
||||
r := mload(add(sig, 32))
|
||||
s := mload(add(sig, 64))
|
||||
v := byte(0, mload(add(sig, 96)))
|
||||
}
|
||||
|
||||
// Version of signature should be 27 or 28, but 0 and 1 are also possible versions
|
||||
if (v < 27) {
|
||||
v += 27;
|
||||
}
|
||||
|
||||
// If the version is correct return the signer address
|
||||
if (v != 27 && v != 28) {
|
||||
return (address(0));
|
||||
} else {
|
||||
// solium-disable-next-line arg-overflow
|
||||
return ecrecover(hash, v, r, s);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* toEthSignedMessageHash
|
||||
* @dev prefix a bytes32 value with "\x19Ethereum Signed Message:"
|
||||
* @dev and hash the result
|
||||
*/
|
||||
function toEthSignedMessageHash(bytes32 hash)
|
||||
internal
|
||||
pure
|
||||
returns (bytes32)
|
||||
{
|
||||
// 32 is the length in bytes of hash,
|
||||
// enforced by the type signature above
|
||||
return keccak256(
|
||||
"\x19Ethereum Signed Message:\n32",
|
||||
hash
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1,15 +0,0 @@
|
||||
pragma solidity ^0.4.4;
|
||||
|
||||
|
||||
import "./Ownable.sol";
|
||||
|
||||
|
||||
/*
|
||||
* Killable
|
||||
* Base contract that can be killed by owner. All funds in contract will be sent to the owner.
|
||||
*/
|
||||
contract Killable is Ownable {
|
||||
function kill() onlyOwner {
|
||||
selfdestruct(owner);
|
||||
}
|
||||
}
|
||||
@ -1,27 +0,0 @@
|
||||
pragma solidity ^0.4.4;
|
||||
|
||||
|
||||
/**
|
||||
* LimitBalance
|
||||
* Simple contract to limit the balance of child contract.
|
||||
* Note this doesn't prevent other contracts to send funds
|
||||
* by using selfdestruct(address);
|
||||
* See: https://github.com/ConsenSys/smart-contract-best-practices#remember-that-ether-can-be-forcibly-sent-to-an-account
|
||||
*/
|
||||
contract LimitBalance {
|
||||
|
||||
uint public limit;
|
||||
|
||||
function LimitBalance(uint _limit) {
|
||||
limit = _limit;
|
||||
}
|
||||
|
||||
modifier limitedPayable() {
|
||||
if (this.balance > limit) {
|
||||
throw;
|
||||
}
|
||||
_;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
35
contracts/MerkleProof.sol
Normal file
35
contracts/MerkleProof.sol
Normal file
@ -0,0 +1,35 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
|
||||
/*
|
||||
* @title MerkleProof
|
||||
* @dev Merkle proof verification
|
||||
* @note Based on https://github.com/ameensol/merkle-tree-solidity/blob/master/src/MerkleProof.sol
|
||||
*/
|
||||
library MerkleProof {
|
||||
/*
|
||||
* @dev Verifies a Merkle proof proving the existence of a leaf in a Merkle tree. Assumes that each pair of leaves
|
||||
* and each pair of pre-images is sorted.
|
||||
* @param _proof Merkle proof containing sibling hashes on the branch from the leaf to the root of the Merkle tree
|
||||
* @param _root Merkle root
|
||||
* @param _leaf Leaf of Merkle tree
|
||||
*/
|
||||
function verifyProof(bytes32[] _proof, bytes32 _root, bytes32 _leaf) internal pure returns (bool) {
|
||||
bytes32 computedHash = _leaf;
|
||||
|
||||
for (uint256 i = 0; i < _proof.length; i++) {
|
||||
bytes32 proofElement = _proof[i];
|
||||
|
||||
if (computedHash < proofElement) {
|
||||
// Hash(current computed hash + current element of the proof)
|
||||
computedHash = keccak256(computedHash, proofElement);
|
||||
} else {
|
||||
// Hash(current element of the proof + current computed hash)
|
||||
computedHash = keccak256(proofElement, computedHash);
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the computed hash (root) is equal to the provided root
|
||||
return computedHash == _root;
|
||||
}
|
||||
}
|
||||
@ -1,18 +0,0 @@
|
||||
pragma solidity ^0.4.4;
|
||||
|
||||
|
||||
import './Ownable.sol';
|
||||
|
||||
|
||||
contract Migrations is Ownable {
|
||||
uint public lastCompletedMigration;
|
||||
|
||||
function setCompleted(uint completed) onlyOwner {
|
||||
lastCompletedMigration = completed;
|
||||
}
|
||||
|
||||
function upgrade(address newAddress) onlyOwner {
|
||||
Migrations upgraded = Migrations(newAddress);
|
||||
upgraded.setCompleted(lastCompletedMigration);
|
||||
}
|
||||
}
|
||||
@ -1,29 +0,0 @@
|
||||
pragma solidity ^0.4.4;
|
||||
|
||||
|
||||
/*
|
||||
* Multisig
|
||||
* Interface contract for multisig proxy contracts; see below for docs.
|
||||
*/
|
||||
contract Multisig {
|
||||
// EVENTS
|
||||
|
||||
// logged events:
|
||||
// Funds has arrived into the wallet (record how much).
|
||||
event Deposit(address _from, uint value);
|
||||
// Single transaction going out of the wallet (record who signed for it, how much, and to whom it's going).
|
||||
event SingleTransact(address owner, uint value, address to, bytes data);
|
||||
// Multi-sig transaction going out of the wallet (record who signed for it last, the operation hash, how much, and to whom it's going).
|
||||
event MultiTransact(address owner, bytes32 operation, uint value, address to, bytes data);
|
||||
// Confirmation still needed for a transaction.
|
||||
event ConfirmationNeeded(bytes32 operation, address initiator, uint value, address to, bytes data);
|
||||
|
||||
|
||||
// FUNCTIONS
|
||||
|
||||
// TODO: document
|
||||
function changeOwner(address _from, address _to) external;
|
||||
function execute(address _to, uint _value, bytes _data) external returns (bytes32);
|
||||
function confirm(bytes32 _h) returns (bool);
|
||||
}
|
||||
|
||||
@ -1,110 +0,0 @@
|
||||
pragma solidity ^0.4.4;
|
||||
|
||||
|
||||
import "./Multisig.sol";
|
||||
import "./Shareable.sol";
|
||||
import "./DayLimit.sol";
|
||||
|
||||
|
||||
/*
|
||||
* MultisigWallet
|
||||
* usage:
|
||||
* bytes32 h = Wallet(w).from(oneOwner).execute(to, value, data);
|
||||
* Wallet(w).from(anotherOwner).confirm(h);
|
||||
*/
|
||||
contract MultisigWallet is Multisig, Shareable, DayLimit {
|
||||
// TYPES
|
||||
|
||||
// Transaction structure to remember details of transaction lest it need be saved for a later call.
|
||||
struct Transaction {
|
||||
address to;
|
||||
uint value;
|
||||
bytes data;
|
||||
}
|
||||
|
||||
|
||||
// CONSTRUCTOR
|
||||
|
||||
// just pass on the owner array to the multiowned and
|
||||
// the limit to daylimit
|
||||
function MultisigWallet(address[] _owners, uint _required, uint _daylimit)
|
||||
Shareable(_owners, _required)
|
||||
DayLimit(_daylimit) { }
|
||||
|
||||
|
||||
// METHODS
|
||||
|
||||
// kills the contract sending everything to `_to`.
|
||||
function kill(address _to) onlymanyowners(sha3(msg.data)) external {
|
||||
suicide(_to);
|
||||
}
|
||||
|
||||
// gets called when no other function matches
|
||||
function() payable {
|
||||
// just being sent some cash?
|
||||
if (msg.value > 0)
|
||||
Deposit(msg.sender, msg.value);
|
||||
}
|
||||
|
||||
// Outside-visible transact entry point. Executes transaction immediately if below daily spend limit.
|
||||
// If not, goes into multisig process. We provide a hash on return to allow the sender to provide
|
||||
// shortcuts for the other confirmations (allowing them to avoid replicating the _to, _value
|
||||
// and _data arguments). They still get the option of using them if they want, anyways.
|
||||
function execute(address _to, uint _value, bytes _data) external onlyOwner returns (bytes32 _r) {
|
||||
// first, take the opportunity to check that we're under the daily limit.
|
||||
if (underLimit(_value)) {
|
||||
SingleTransact(msg.sender, _value, _to, _data);
|
||||
// yes - just execute the call.
|
||||
if (!_to.call.value(_value)(_data)) {
|
||||
throw;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
// determine our operation hash.
|
||||
_r = sha3(msg.data, block.number);
|
||||
if (!confirm(_r) && txs[_r].to == 0) {
|
||||
txs[_r].to = _to;
|
||||
txs[_r].value = _value;
|
||||
txs[_r].data = _data;
|
||||
ConfirmationNeeded(_r, msg.sender, _value, _to, _data);
|
||||
}
|
||||
}
|
||||
|
||||
// confirm a transaction through just the hash. we use the previous transactions map, txs, in order
|
||||
// to determine the body of the transaction from the hash provided.
|
||||
function confirm(bytes32 _h) onlymanyowners(_h) returns (bool) {
|
||||
if (txs[_h].to != 0) {
|
||||
if (!txs[_h].to.call.value(txs[_h].value)(txs[_h].data)) {
|
||||
throw;
|
||||
}
|
||||
MultiTransact(msg.sender, _h, txs[_h].value, txs[_h].to, txs[_h].data);
|
||||
delete txs[_h];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
function setDailyLimit(uint _newLimit) onlymanyowners(sha3(msg.data)) external {
|
||||
_setDailyLimit(_newLimit);
|
||||
}
|
||||
|
||||
function resetSpentToday() onlymanyowners(sha3(msg.data)) external {
|
||||
_resetSpentToday();
|
||||
}
|
||||
|
||||
|
||||
// INTERNAL METHODS
|
||||
|
||||
function clearPending() internal {
|
||||
uint length = pendingsIndex.length;
|
||||
for (uint i = 0; i < length; ++i) {
|
||||
delete txs[pendingsIndex[i]];
|
||||
}
|
||||
super.clearPending();
|
||||
}
|
||||
|
||||
|
||||
// FIELDS
|
||||
|
||||
// pending transactions we have at present.
|
||||
mapping (bytes32 => Transaction) txs;
|
||||
}
|
||||
@ -1,26 +0,0 @@
|
||||
pragma solidity ^0.4.4;
|
||||
|
||||
|
||||
/*
|
||||
* Ownable
|
||||
*
|
||||
* Base contract with an owner.
|
||||
* Provides onlyOwner modifier, which prevents function from running if it is called by anyone other than the owner.
|
||||
*/
|
||||
contract Ownable {
|
||||
address public owner;
|
||||
|
||||
function Ownable() {
|
||||
owner = msg.sender;
|
||||
}
|
||||
|
||||
modifier onlyOwner() {
|
||||
if (msg.sender == owner)
|
||||
_;
|
||||
}
|
||||
|
||||
function transferOwnership(address newOwner) onlyOwner {
|
||||
if (newOwner != address(0)) owner = newOwner;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,30 +0,0 @@
|
||||
pragma solidity ^0.4.4;
|
||||
|
||||
|
||||
/*
|
||||
* PullPayment
|
||||
* Base contract supporting async send for pull payments.
|
||||
* Inherit from this contract and use asyncSend instead of send.
|
||||
*/
|
||||
contract PullPayment {
|
||||
mapping(address => uint) public payments;
|
||||
|
||||
// store sent amount as credit to be pulled, called by payer
|
||||
function asyncSend(address dest, uint amount) internal {
|
||||
payments[dest] += amount;
|
||||
}
|
||||
|
||||
// withdraw accumulated balance, called by payee
|
||||
function withdrawPayments() {
|
||||
address payee = msg.sender;
|
||||
uint payment = payments[payee];
|
||||
|
||||
if (payment == 0) throw;
|
||||
if (this.balance < payment) throw;
|
||||
|
||||
payments[payee] = 0;
|
||||
if (!payee.send(payment)) {
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,29 +0,0 @@
|
||||
pragma solidity ^0.4.4;
|
||||
|
||||
|
||||
/**
|
||||
* Math operations with safety checks
|
||||
*/
|
||||
contract SafeMath {
|
||||
function safeMul(uint a, uint b) internal returns (uint) {
|
||||
uint c = a * b;
|
||||
assert(a == 0 || c / a == b);
|
||||
return c;
|
||||
}
|
||||
|
||||
function safeSub(uint a, uint b) internal returns (uint) {
|
||||
assert(b <= a);
|
||||
return a - b;
|
||||
}
|
||||
|
||||
function safeAdd(uint a, uint b) internal returns (uint) {
|
||||
uint c = a + b;
|
||||
assert(c>=a && c>=b);
|
||||
return c;
|
||||
}
|
||||
|
||||
function assert(bool assertion) internal {
|
||||
if (!assertion) throw;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,164 +0,0 @@
|
||||
pragma solidity ^0.4.4;
|
||||
|
||||
|
||||
/*
|
||||
* Shareable
|
||||
*
|
||||
* Based on https://github.com/ethereum/dapp-bin/blob/master/wallet/wallet.sol
|
||||
*
|
||||
* inheritable "property" contract that enables methods to be protected by requiring the acquiescence of either a single, or, crucially, each of a number of, designated owners.
|
||||
*
|
||||
* usage:
|
||||
* use modifiers onlyowner (just own owned) or onlymanyowners(hash), whereby the same hash must be provided by some number (specified in constructor) of the set of owners (specified in the constructor) before the interior is executed.
|
||||
*/
|
||||
contract Shareable {
|
||||
// TYPES
|
||||
|
||||
// struct for the status of a pending operation.
|
||||
struct PendingState {
|
||||
uint yetNeeded;
|
||||
uint ownersDone;
|
||||
uint index;
|
||||
}
|
||||
|
||||
|
||||
// FIELDS
|
||||
|
||||
// the number of owners that must confirm the same operation before it is run.
|
||||
uint public required;
|
||||
|
||||
// list of owners
|
||||
uint[256] owners;
|
||||
uint constant c_maxOwners = 250;
|
||||
// index on the list of owners to allow reverse lookup
|
||||
mapping(uint => uint) ownerIndex;
|
||||
// the ongoing operations.
|
||||
mapping(bytes32 => PendingState) pendings;
|
||||
bytes32[] pendingsIndex;
|
||||
|
||||
|
||||
// EVENTS
|
||||
|
||||
// this contract only has six types of events: it can accept a confirmation, in which case
|
||||
// we record owner and operation (hash) alongside it.
|
||||
event Confirmation(address owner, bytes32 operation);
|
||||
event Revoke(address owner, bytes32 operation);
|
||||
|
||||
|
||||
// MODIFIERS
|
||||
|
||||
// simple single-sig function modifier.
|
||||
modifier onlyOwner {
|
||||
if (isOwner(msg.sender))
|
||||
_;
|
||||
}
|
||||
|
||||
// multi-sig function modifier: the operation must have an intrinsic hash in order
|
||||
// that later attempts can be realised as the same underlying operation and
|
||||
// thus count as confirmations.
|
||||
modifier onlymanyowners(bytes32 _operation) {
|
||||
if (confirmAndCheck(_operation))
|
||||
_;
|
||||
}
|
||||
|
||||
|
||||
// CONSTRUCTOR
|
||||
|
||||
// constructor is given number of sigs required to do protected "onlymanyowners" transactions
|
||||
// as well as the selection of addresses capable of confirming them.
|
||||
function Shareable(address[] _owners, uint _required) {
|
||||
owners[1] = uint(msg.sender);
|
||||
ownerIndex[uint(msg.sender)] = 1;
|
||||
for (uint i = 0; i < _owners.length; ++i) {
|
||||
owners[2 + i] = uint(_owners[i]);
|
||||
ownerIndex[uint(_owners[i])] = 2 + i;
|
||||
}
|
||||
required = _required;
|
||||
}
|
||||
|
||||
|
||||
// METHODS
|
||||
|
||||
// Revokes a prior confirmation of the given operation
|
||||
function revoke(bytes32 _operation) external {
|
||||
uint index = ownerIndex[uint(msg.sender)];
|
||||
// make sure they're an owner
|
||||
if (index == 0) return;
|
||||
uint ownerIndexBit = 2**index;
|
||||
var pending = pendings[_operation];
|
||||
if (pending.ownersDone & ownerIndexBit > 0) {
|
||||
pending.yetNeeded++;
|
||||
pending.ownersDone -= ownerIndexBit;
|
||||
Revoke(msg.sender, _operation);
|
||||
}
|
||||
}
|
||||
|
||||
// Gets an owner by 0-indexed position (using numOwners as the count)
|
||||
function getOwner(uint ownerIndex) external constant returns (address) {
|
||||
return address(owners[ownerIndex + 1]);
|
||||
}
|
||||
|
||||
function isOwner(address _addr) constant returns (bool) {
|
||||
return ownerIndex[uint(_addr)] > 0;
|
||||
}
|
||||
|
||||
function hasConfirmed(bytes32 _operation, address _owner) constant returns (bool) {
|
||||
var pending = pendings[_operation];
|
||||
uint index = ownerIndex[uint(_owner)];
|
||||
|
||||
// make sure they're an owner
|
||||
if (index == 0) return false;
|
||||
|
||||
// determine the bit to set for this owner.
|
||||
uint ownerIndexBit = 2**index;
|
||||
return !(pending.ownersDone & ownerIndexBit == 0);
|
||||
}
|
||||
|
||||
// INTERNAL METHODS
|
||||
|
||||
function confirmAndCheck(bytes32 _operation) internal returns (bool) {
|
||||
// determine what index the present sender is:
|
||||
uint index = ownerIndex[uint(msg.sender)];
|
||||
// make sure they're an owner
|
||||
if (index == 0) return;
|
||||
|
||||
var pending = pendings[_operation];
|
||||
// if we're not yet working on this operation, switch over and reset the confirmation status.
|
||||
if (pending.yetNeeded == 0) {
|
||||
// reset count of confirmations needed.
|
||||
pending.yetNeeded = required;
|
||||
// reset which owners have confirmed (none) - set our bitmap to 0.
|
||||
pending.ownersDone = 0;
|
||||
pending.index = pendingsIndex.length++;
|
||||
pendingsIndex[pending.index] = _operation;
|
||||
}
|
||||
// determine the bit to set for this owner.
|
||||
uint ownerIndexBit = 2**index;
|
||||
// make sure we (the message sender) haven't confirmed this operation previously.
|
||||
if (pending.ownersDone & ownerIndexBit == 0) {
|
||||
Confirmation(msg.sender, _operation);
|
||||
// ok - check if count is enough to go ahead.
|
||||
if (pending.yetNeeded <= 1) {
|
||||
// enough confirmations: reset and run interior.
|
||||
delete pendingsIndex[pendings[_operation].index];
|
||||
delete pendings[_operation];
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// not enough: record that this owner in particular confirmed.
|
||||
pending.yetNeeded--;
|
||||
pending.ownersDone |= ownerIndexBit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function clearPending() internal {
|
||||
uint length = pendingsIndex.length;
|
||||
for (uint i = 0; i < length; ++i)
|
||||
if (pendingsIndex[i] != 0)
|
||||
delete pendings[pendingsIndex[i]];
|
||||
delete pendingsIndex;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,28 +0,0 @@
|
||||
pragma solidity ^0.4.4;
|
||||
|
||||
|
||||
import "./Ownable.sol";
|
||||
|
||||
|
||||
/*
|
||||
* Stoppable
|
||||
* Abstract contract that allows children to implement an
|
||||
* emergency stop mechanism.
|
||||
*/
|
||||
contract Stoppable is Ownable {
|
||||
bool public stopped;
|
||||
|
||||
modifier stopInEmergency { if (!stopped) _; }
|
||||
modifier onlyInEmergency { if (stopped) _; }
|
||||
|
||||
// called by the owner on emergency, triggers stopped state
|
||||
function emergencyStop() external onlyOwner {
|
||||
stopped = true;
|
||||
}
|
||||
|
||||
// called by the owner on end of emergency, returns to normal state
|
||||
function release() external onlyOwner onlyInEmergency {
|
||||
stopped = false;
|
||||
}
|
||||
|
||||
}
|
||||
98
contracts/access/SignatureBouncer.sol
Normal file
98
contracts/access/SignatureBouncer.sol
Normal file
@ -0,0 +1,98 @@
|
||||
pragma solidity ^0.4.18;
|
||||
|
||||
import "../ownership/Ownable.sol";
|
||||
import "../ownership/rbac/RBAC.sol";
|
||||
import "../ECRecovery.sol";
|
||||
|
||||
|
||||
/**
|
||||
* @title SignatureBouncer
|
||||
* @author PhABC and Shrugs
|
||||
* @dev Bouncer allows users to submit a signature as a permission to do an action.
|
||||
* @dev If the signature is from one of the authorized bouncer addresses, the signature
|
||||
* @dev is valid. The owner of the contract adds/removes bouncers.
|
||||
* @dev Bouncer addresses can be individual servers signing grants or different
|
||||
* @dev users within a decentralized club that have permission to invite other members.
|
||||
* @dev
|
||||
* @dev This technique is useful for whitelists and airdrops; instead of putting all
|
||||
* @dev valid addresses on-chain, simply sign a grant of the form
|
||||
* @dev keccak256(`:contractAddress` + `:granteeAddress`) using a valid bouncer address.
|
||||
* @dev Then restrict access to your crowdsale/whitelist/airdrop using the
|
||||
* @dev `onlyValidSignature` modifier (or implement your own using isValidSignature).
|
||||
* @dev
|
||||
* @dev See the tests Bouncer.test.js for specific usage examples.
|
||||
*/
|
||||
contract SignatureBouncer is Migratable, Ownable, RBAC {
|
||||
using ECRecovery for bytes32;
|
||||
|
||||
string public constant ROLE_BOUNCER = "bouncer";
|
||||
|
||||
function initialize(address _sender)
|
||||
isInitializer("SignatureBouncer", "1.9.0")
|
||||
public
|
||||
{
|
||||
Ownable.initialize(_sender);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev requires that a valid signature of a bouncer was provided
|
||||
*/
|
||||
modifier onlyValidSignature(bytes _sig)
|
||||
{
|
||||
require(isValidSignature(msg.sender, _sig));
|
||||
_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev allows the owner to add additional bouncer addresses
|
||||
*/
|
||||
function addBouncer(address _bouncer)
|
||||
onlyOwner
|
||||
public
|
||||
{
|
||||
require(_bouncer != address(0));
|
||||
addRole(_bouncer, ROLE_BOUNCER);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev allows the owner to remove bouncer addresses
|
||||
*/
|
||||
function removeBouncer(address _bouncer)
|
||||
onlyOwner
|
||||
public
|
||||
{
|
||||
require(_bouncer != address(0));
|
||||
removeRole(_bouncer, ROLE_BOUNCER);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev is the signature of `this + sender` from a bouncer?
|
||||
* @return bool
|
||||
*/
|
||||
function isValidSignature(address _address, bytes _sig)
|
||||
internal
|
||||
view
|
||||
returns (bool)
|
||||
{
|
||||
return isValidDataHash(
|
||||
keccak256(address(this), _address),
|
||||
_sig
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev internal function to convert a hash to an eth signed message
|
||||
* @dev and then recover the signature and check it against the bouncer role
|
||||
* @return bool
|
||||
*/
|
||||
function isValidDataHash(bytes32 hash, bytes _sig)
|
||||
internal
|
||||
view
|
||||
returns (bool)
|
||||
{
|
||||
address signer = hash
|
||||
.toEthSignedMessageHash()
|
||||
.recover(_sig);
|
||||
return hasRole(signer, ROLE_BOUNCER);
|
||||
}
|
||||
}
|
||||
@ -1,23 +0,0 @@
|
||||
pragma solidity ^0.4.4;
|
||||
|
||||
|
||||
import '../PullPayment.sol';
|
||||
|
||||
|
||||
// UNSAFE CODE, DO NOT USE!
|
||||
contract BadArrayUse is PullPayment {
|
||||
address[] employees;
|
||||
|
||||
function payBonus() {
|
||||
for (var i = 0; i < employees.length; i++) {
|
||||
address employee = employees[i];
|
||||
uint bonus = calculateBonus(employee);
|
||||
asyncSend(employee, bonus);
|
||||
}
|
||||
}
|
||||
|
||||
function calculateBonus(address employee) returns (uint) {
|
||||
// some expensive computation...
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,17 +0,0 @@
|
||||
pragma solidity ^0.4.4;
|
||||
|
||||
|
||||
// UNSAFE CODE, DO NOT USE!
|
||||
contract BadFailEarly {
|
||||
|
||||
uint constant DEFAULT_SALARY = 50000;
|
||||
mapping(string => uint) nameToSalary;
|
||||
|
||||
function getSalary(string name) constant returns (uint) {
|
||||
if (bytes(name).length != 0 && nameToSalary[name] != 0) {
|
||||
return nameToSalary[name];
|
||||
} else {
|
||||
return DEFAULT_SALARY;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,23 +0,0 @@
|
||||
pragma solidity ^0.4.4;
|
||||
|
||||
|
||||
// UNSAFE CODE, DO NOT USE!
|
||||
contract BadPushPayments {
|
||||
|
||||
address highestBidder;
|
||||
uint highestBid;
|
||||
|
||||
function bid() payable {
|
||||
if (msg.value < highestBid) throw;
|
||||
|
||||
if (highestBidder != 0) {
|
||||
// return bid to previous winner
|
||||
if (!highestBidder.send(highestBid)) {
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
highestBidder = msg.sender;
|
||||
highestBid = msg.value;
|
||||
}
|
||||
}
|
||||
@ -1,25 +0,0 @@
|
||||
pragma solidity ^0.4.4;
|
||||
|
||||
|
||||
import '../PullPayment.sol';
|
||||
|
||||
|
||||
contract GoodArrayUse is PullPayment {
|
||||
address[] employees;
|
||||
mapping(address => uint) bonuses;
|
||||
|
||||
function payBonus() {
|
||||
for (uint i = 0; i < employees.length; i++) {
|
||||
address employee = employees[i];
|
||||
uint bonus = bonuses[employee];
|
||||
asyncSend(employee, bonus);
|
||||
}
|
||||
}
|
||||
|
||||
function calculateBonus(address employee) returns (uint) {
|
||||
uint bonus = 0;
|
||||
// some expensive computation...
|
||||
bonuses[employee] = bonus;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,15 +0,0 @@
|
||||
pragma solidity ^0.4.4;
|
||||
|
||||
|
||||
contract GoodFailEarly {
|
||||
|
||||
uint constant DEFAULT_SALARY = 50000;
|
||||
mapping(string => uint) nameToSalary;
|
||||
|
||||
function getSalary(string name) constant returns (uint) {
|
||||
if (bytes(name).length == 0) throw;
|
||||
if (nameToSalary[name] == 0) throw;
|
||||
|
||||
return nameToSalary[name];
|
||||
}
|
||||
}
|
||||
@ -1,27 +0,0 @@
|
||||
pragma solidity ^0.4.4;
|
||||
|
||||
|
||||
contract GoodPullPayments {
|
||||
address highestBidder;
|
||||
uint highestBid;
|
||||
mapping(address => uint) refunds;
|
||||
|
||||
function bid() external payable {
|
||||
if (msg.value < highestBid) throw;
|
||||
|
||||
if (highestBidder != 0) {
|
||||
refunds[highestBidder] += highestBid;
|
||||
}
|
||||
|
||||
highestBidder = msg.sender;
|
||||
highestBid = msg.value;
|
||||
}
|
||||
|
||||
function withdrawBid() external {
|
||||
uint refund = refunds[msg.sender];
|
||||
refunds[msg.sender] = 0;
|
||||
if (!msg.sender.send(refund)) {
|
||||
refunds[msg.sender] = refund;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,38 +0,0 @@
|
||||
pragma solidity ^0.4.4;
|
||||
|
||||
|
||||
/*
|
||||
* Proof of Existence example contract
|
||||
* see https://medium.com/zeppelin-blog/the-hitchhikers-guide-to-smart-contracts-in-ethereum-848f08001f05
|
||||
*/
|
||||
contract ProofOfExistence {
|
||||
|
||||
mapping (bytes32 => bool) public proofs;
|
||||
|
||||
// store a proof of existence in the contract state
|
||||
function storeProof(bytes32 proof) {
|
||||
proofs[proof] = true;
|
||||
}
|
||||
|
||||
// calculate and store the proof for a document
|
||||
function notarize(string document) {
|
||||
var proof = calculateProof(document);
|
||||
storeProof(proof);
|
||||
}
|
||||
|
||||
// helper function to get a document's sha256
|
||||
function calculateProof(string document) constant returns (bytes32) {
|
||||
return sha256(document);
|
||||
}
|
||||
|
||||
// check if a document has been notarized
|
||||
function checkDocument(string document) constant returns (bool) {
|
||||
var proof = calculateProof(document);
|
||||
return hasProof(proof);
|
||||
}
|
||||
|
||||
// returns true if proof is stored
|
||||
function hasProof(bytes32 proof) constant returns (bool) {
|
||||
return proofs[proof];
|
||||
}
|
||||
}
|
||||
@ -1,20 +0,0 @@
|
||||
pragma solidity ^0.4.4;
|
||||
|
||||
|
||||
import '../PullPayment.sol';
|
||||
|
||||
|
||||
contract PullPaymentBid is PullPayment {
|
||||
address public highestBidder;
|
||||
uint public highestBid;
|
||||
|
||||
function bid() external payable {
|
||||
if (msg.value <= highestBid) throw;
|
||||
|
||||
if (highestBidder != 0) {
|
||||
asyncSend(highestBidder, highestBid);
|
||||
}
|
||||
highestBidder = msg.sender;
|
||||
highestBid = msg.value;
|
||||
}
|
||||
}
|
||||
@ -1,26 +0,0 @@
|
||||
pragma solidity ^0.4.4;
|
||||
|
||||
|
||||
import '../PullPayment.sol';
|
||||
import '../Stoppable.sol';
|
||||
|
||||
|
||||
contract StoppableBid is Stoppable, PullPayment {
|
||||
address public highestBidder;
|
||||
uint public highestBid;
|
||||
|
||||
function bid() external payable stopInEmergency {
|
||||
if (msg.value <= highestBid) throw;
|
||||
|
||||
if (highestBidder != 0) {
|
||||
asyncSend(highestBidder, highestBid);
|
||||
}
|
||||
highestBidder = msg.sender;
|
||||
highestBid = msg.value;
|
||||
}
|
||||
|
||||
function withdraw() onlyInEmergency {
|
||||
selfdestruct(owner);
|
||||
}
|
||||
|
||||
}
|
||||
53
contracts/lifecycle/Pausable.sol
Normal file
53
contracts/lifecycle/Pausable.sol
Normal file
@ -0,0 +1,53 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
|
||||
import "../ownership/Ownable.sol";
|
||||
|
||||
|
||||
/**
|
||||
* @title Pausable
|
||||
* @dev Base contract which allows children to implement an emergency stop mechanism.
|
||||
*/
|
||||
contract Pausable is Migratable, Ownable {
|
||||
event Pause();
|
||||
event Unpause();
|
||||
|
||||
bool public paused = false;
|
||||
|
||||
|
||||
function initialize(address _sender) isInitializer("Pausable", "1.9.0") public {
|
||||
Ownable.initialize(_sender);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Modifier to make a function callable only when the contract is not paused.
|
||||
*/
|
||||
modifier whenNotPaused() {
|
||||
require(!paused);
|
||||
_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Modifier to make a function callable only when the contract is paused.
|
||||
*/
|
||||
modifier whenPaused() {
|
||||
require(paused);
|
||||
_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev called by the owner to pause, triggers stopped state
|
||||
*/
|
||||
function pause() onlyOwner whenNotPaused public {
|
||||
paused = true;
|
||||
emit Pause();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev called by the owner to unpause, returns to normal state
|
||||
*/
|
||||
function unpause() onlyOwner whenPaused public {
|
||||
paused = false;
|
||||
emit Unpause();
|
||||
}
|
||||
}
|
||||
24
contracts/math/Math.sol
Normal file
24
contracts/math/Math.sol
Normal file
@ -0,0 +1,24 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
|
||||
/**
|
||||
* @title Math
|
||||
* @dev Assorted math operations
|
||||
*/
|
||||
library Math {
|
||||
function max64(uint64 a, uint64 b) internal pure returns (uint64) {
|
||||
return a >= b ? a : b;
|
||||
}
|
||||
|
||||
function min64(uint64 a, uint64 b) internal pure returns (uint64) {
|
||||
return a < b ? a : b;
|
||||
}
|
||||
|
||||
function max256(uint256 a, uint256 b) internal pure returns (uint256) {
|
||||
return a >= b ? a : b;
|
||||
}
|
||||
|
||||
function min256(uint256 a, uint256 b) internal pure returns (uint256) {
|
||||
return a < b ? a : b;
|
||||
}
|
||||
}
|
||||
48
contracts/math/SafeMath.sol
Normal file
48
contracts/math/SafeMath.sol
Normal file
@ -0,0 +1,48 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
|
||||
/**
|
||||
* @title SafeMath
|
||||
* @dev Math operations with safety checks that throw on error
|
||||
*/
|
||||
library SafeMath {
|
||||
|
||||
/**
|
||||
* @dev Multiplies two numbers, throws on overflow.
|
||||
*/
|
||||
function mul(uint256 a, uint256 b) internal pure returns (uint256 c) {
|
||||
if (a == 0) {
|
||||
return 0;
|
||||
}
|
||||
c = a * b;
|
||||
assert(c / a == b);
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Integer division of two numbers, truncating the quotient.
|
||||
*/
|
||||
function div(uint256 a, uint256 b) internal pure returns (uint256) {
|
||||
// assert(b > 0); // Solidity automatically throws when dividing by 0
|
||||
// uint256 c = a / b;
|
||||
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
|
||||
return a / b;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
|
||||
*/
|
||||
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
|
||||
assert(b <= a);
|
||||
return a - b;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Adds two numbers, throws on overflow.
|
||||
*/
|
||||
function add(uint256 a, uint256 b) internal pure returns (uint256 c) {
|
||||
c = a + b;
|
||||
assert(c >= a);
|
||||
return c;
|
||||
}
|
||||
}
|
||||
15
contracts/mocks/BasicTokenMock.sol
Normal file
15
contracts/mocks/BasicTokenMock.sol
Normal file
@ -0,0 +1,15 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
|
||||
import "../token/ERC20/BasicToken.sol";
|
||||
|
||||
|
||||
// mock class using BasicToken
|
||||
contract BasicTokenMock is BasicToken {
|
||||
|
||||
function BasicTokenMock(address initialAccount, uint256 initialBalance) public {
|
||||
balances[initialAccount] = initialBalance;
|
||||
totalSupply_ = initialBalance;
|
||||
}
|
||||
|
||||
}
|
||||
29
contracts/mocks/BouncerMock.sol
Normal file
29
contracts/mocks/BouncerMock.sol
Normal file
@ -0,0 +1,29 @@
|
||||
pragma solidity ^0.4.18;
|
||||
|
||||
import "../access/SignatureBouncer.sol";
|
||||
|
||||
|
||||
contract SignatureBouncerMock is SignatureBouncer {
|
||||
function initialize(address _sender)
|
||||
isInitializer("SignatureBouncerMock", "1.9.0")
|
||||
public
|
||||
{
|
||||
SignatureBouncer.initialize(_sender);
|
||||
}
|
||||
|
||||
function checkValidSignature(address _address, bytes _sig)
|
||||
public
|
||||
view
|
||||
returns (bool)
|
||||
{
|
||||
return isValidSignature(_address, _sig);
|
||||
}
|
||||
|
||||
function onlyWithValidSignature(bytes _sig)
|
||||
onlyValidSignature(_sig)
|
||||
public
|
||||
view
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
13
contracts/mocks/BurnableTokenMock.sol
Normal file
13
contracts/mocks/BurnableTokenMock.sol
Normal file
@ -0,0 +1,13 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "../token/ERC20/BurnableToken.sol";
|
||||
|
||||
|
||||
contract BurnableTokenMock is BurnableToken {
|
||||
|
||||
function BurnableTokenMock(address initialAccount, uint initialBalance) public {
|
||||
balances[initialAccount] = initialBalance;
|
||||
totalSupply_ = initialBalance;
|
||||
}
|
||||
|
||||
}
|
||||
11
contracts/mocks/DetailedERC20Mock.sol
Normal file
11
contracts/mocks/DetailedERC20Mock.sol
Normal file
@ -0,0 +1,11 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "../token/ERC20/StandardToken.sol";
|
||||
import "../token/ERC20/DetailedERC20.sol";
|
||||
|
||||
|
||||
contract DetailedERC20Mock is StandardToken, DetailedERC20 {
|
||||
function DetailedERC20Mock(string _name, string _symbol, uint8 _decimals) public {
|
||||
DetailedERC20.initialize(_name, _symbol, _decimals);
|
||||
}
|
||||
}
|
||||
25
contracts/mocks/ECRecoveryMock.sol
Normal file
25
contracts/mocks/ECRecoveryMock.sol
Normal file
@ -0,0 +1,25 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
|
||||
import "../ECRecovery.sol";
|
||||
|
||||
|
||||
contract ECRecoveryMock {
|
||||
using ECRecovery for bytes32;
|
||||
|
||||
function recover(bytes32 hash, bytes sig)
|
||||
public
|
||||
pure
|
||||
returns (address)
|
||||
{
|
||||
return hash.recover(sig);
|
||||
}
|
||||
|
||||
function toEthSignedMessageHash(bytes32 hash)
|
||||
public
|
||||
pure
|
||||
returns (bytes32)
|
||||
{
|
||||
return hash.toEthSignedMessageHash();
|
||||
}
|
||||
}
|
||||
18
contracts/mocks/ERC721BasicTokenMock.sol
Normal file
18
contracts/mocks/ERC721BasicTokenMock.sol
Normal file
@ -0,0 +1,18 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "../token/ERC721/ERC721BasicToken.sol";
|
||||
|
||||
|
||||
/**
|
||||
* @title ERC721BasicTokenMock
|
||||
* This mock just provides a public mint and burn functions for testing purposes
|
||||
*/
|
||||
contract ERC721BasicTokenMock is ERC721BasicToken {
|
||||
function mint(address _to, uint256 _tokenId) public {
|
||||
super._mint(_to, _tokenId);
|
||||
}
|
||||
|
||||
function burn(uint256 _tokenId) public {
|
||||
super._burn(ownerOf(_tokenId), _tokenId);
|
||||
}
|
||||
}
|
||||
34
contracts/mocks/ERC721ReceiverMock.sol
Normal file
34
contracts/mocks/ERC721ReceiverMock.sol
Normal file
@ -0,0 +1,34 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "../token/ERC721/ERC721Receiver.sol";
|
||||
|
||||
|
||||
contract ERC721ReceiverMock is ERC721Receiver {
|
||||
bytes4 retval;
|
||||
bool reverts;
|
||||
|
||||
event Received(address _address, uint256 _tokenId, bytes _data, uint256 _gas);
|
||||
|
||||
function ERC721ReceiverMock(bytes4 _retval, bool _reverts) public {
|
||||
retval = _retval;
|
||||
reverts = _reverts;
|
||||
}
|
||||
|
||||
function onERC721Received(
|
||||
address _address,
|
||||
uint256 _tokenId,
|
||||
bytes _data
|
||||
)
|
||||
public
|
||||
returns(bytes4)
|
||||
{
|
||||
require(!reverts);
|
||||
emit Received(
|
||||
_address,
|
||||
_tokenId,
|
||||
_data,
|
||||
gasleft() // msg.gas was deprecated in solidityv0.4.21
|
||||
);
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
27
contracts/mocks/ERC721TokenMock.sol
Normal file
27
contracts/mocks/ERC721TokenMock.sol
Normal file
@ -0,0 +1,27 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "../token/ERC721/ERC721Token.sol";
|
||||
|
||||
|
||||
/**
|
||||
* @title ERC721TokenMock
|
||||
* This mock just provides a public mint and burn functions for testing purposes,
|
||||
* and a public setter for metadata URI
|
||||
*/
|
||||
contract ERC721TokenMock is ERC721Token {
|
||||
function ERC721TokenMock(string name, string symbol) public {
|
||||
ERC721Token.initialize(name, symbol);
|
||||
}
|
||||
|
||||
function mint(address _to, uint256 _tokenId) public {
|
||||
super._mint(_to, _tokenId);
|
||||
}
|
||||
|
||||
function burn(uint256 _tokenId) public {
|
||||
super._burn(ownerOf(_tokenId), _tokenId);
|
||||
}
|
||||
|
||||
function setTokenURI(uint256 _tokenId, string _uri) public {
|
||||
super._setTokenURI(_tokenId, _uri);
|
||||
}
|
||||
}
|
||||
26
contracts/mocks/MathMock.sol
Normal file
26
contracts/mocks/MathMock.sol
Normal file
@ -0,0 +1,26 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
|
||||
import "../../contracts/math/Math.sol";
|
||||
|
||||
|
||||
contract MathMock {
|
||||
uint64 public result64;
|
||||
uint256 public result256;
|
||||
|
||||
function max64(uint64 a, uint64 b) public {
|
||||
result64 = Math.max64(a, b);
|
||||
}
|
||||
|
||||
function min64(uint64 a, uint64 b) public {
|
||||
result64 = Math.min64(a, b);
|
||||
}
|
||||
|
||||
function max256(uint256 a, uint256 b) public {
|
||||
result256 = Math.max256(a, b);
|
||||
}
|
||||
|
||||
function min256(uint256 a, uint256 b) public {
|
||||
result256 = Math.min256(a, b);
|
||||
}
|
||||
}
|
||||
11
contracts/mocks/MerkleProofWrapper.sol
Normal file
11
contracts/mocks/MerkleProofWrapper.sol
Normal file
@ -0,0 +1,11 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import { MerkleProof } from "../MerkleProof.sol";
|
||||
|
||||
|
||||
contract MerkleProofWrapper {
|
||||
|
||||
function verifyProof(bytes32[] _proof, bytes32 _root, bytes32 _leaf) public pure returns (bool) {
|
||||
return MerkleProof.verifyProof(_proof, _root, _leaf);
|
||||
}
|
||||
}
|
||||
27
contracts/mocks/PausableMock.sol
Normal file
27
contracts/mocks/PausableMock.sol
Normal file
@ -0,0 +1,27 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
|
||||
import "../lifecycle/Pausable.sol";
|
||||
|
||||
|
||||
// mock class using Pausable
|
||||
contract PausableMock is Pausable {
|
||||
bool public drasticMeasureTaken;
|
||||
uint256 public count;
|
||||
|
||||
function PausableMock() public {
|
||||
Ownable.initialize(msg.sender);
|
||||
|
||||
drasticMeasureTaken = false;
|
||||
count = 0;
|
||||
}
|
||||
|
||||
function normalProcess() external whenNotPaused {
|
||||
count++;
|
||||
}
|
||||
|
||||
function drasticMeasure() external whenPaused {
|
||||
drasticMeasureTaken = true;
|
||||
}
|
||||
|
||||
}
|
||||
15
contracts/mocks/PausableTokenMock.sol
Normal file
15
contracts/mocks/PausableTokenMock.sol
Normal file
@ -0,0 +1,15 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "../token/ERC20/PausableToken.sol";
|
||||
|
||||
|
||||
// mock class using PausableToken
|
||||
contract PausableTokenMock is PausableToken {
|
||||
|
||||
function PausableTokenMock(address initialAccount, uint initialBalance) public {
|
||||
Ownable.initialize(msg.sender);
|
||||
|
||||
balances[initialAccount] = initialBalance;
|
||||
}
|
||||
|
||||
}
|
||||
17
contracts/mocks/PullPaymentMock.sol
Normal file
17
contracts/mocks/PullPaymentMock.sol
Normal file
@ -0,0 +1,17 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
|
||||
import "../payment/PullPayment.sol";
|
||||
|
||||
|
||||
// mock class using PullPayment
|
||||
contract PullPaymentMock is PullPayment {
|
||||
|
||||
function PullPaymentMock() public payable { }
|
||||
|
||||
// test helper function to call asyncSend
|
||||
function callSend(address dest, uint256 amount) public {
|
||||
asyncSend(dest, amount);
|
||||
}
|
||||
|
||||
}
|
||||
71
contracts/mocks/RBACMock.sol
Normal file
71
contracts/mocks/RBACMock.sol
Normal file
@ -0,0 +1,71 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "../ownership/rbac/RBACWithAdmin.sol";
|
||||
|
||||
|
||||
contract RBACMock is RBACWithAdmin {
|
||||
|
||||
string constant ROLE_ADVISOR = "advisor";
|
||||
|
||||
modifier onlyAdminOrAdvisor()
|
||||
{
|
||||
require(
|
||||
hasRole(msg.sender, ROLE_ADMIN) ||
|
||||
hasRole(msg.sender, ROLE_ADVISOR)
|
||||
);
|
||||
_;
|
||||
}
|
||||
|
||||
function RBACMock(address[] _advisors)
|
||||
public
|
||||
{
|
||||
RBACWithAdmin.initialize(msg.sender);
|
||||
|
||||
addRole(msg.sender, ROLE_ADVISOR);
|
||||
|
||||
for (uint256 i = 0; i < _advisors.length; i++) {
|
||||
addRole(_advisors[i], ROLE_ADVISOR);
|
||||
}
|
||||
}
|
||||
|
||||
function onlyAdminsCanDoThis()
|
||||
onlyAdmin
|
||||
view
|
||||
external
|
||||
{
|
||||
}
|
||||
|
||||
function onlyAdvisorsCanDoThis()
|
||||
onlyRole(ROLE_ADVISOR)
|
||||
view
|
||||
external
|
||||
{
|
||||
}
|
||||
|
||||
function eitherAdminOrAdvisorCanDoThis()
|
||||
onlyAdminOrAdvisor
|
||||
view
|
||||
external
|
||||
{
|
||||
}
|
||||
|
||||
function nobodyCanDoThis()
|
||||
onlyRole("unknown")
|
||||
view
|
||||
external
|
||||
{
|
||||
}
|
||||
|
||||
// admins can remove advisor's role
|
||||
function removeAdvisor(address _addr)
|
||||
onlyAdmin
|
||||
public
|
||||
{
|
||||
// revert if the user isn't an advisor
|
||||
// (perhaps you want to soft-fail here instead?)
|
||||
checkRole(_addr, ROLE_ADVISOR);
|
||||
|
||||
// remove the advisor's role
|
||||
removeRole(_addr, ROLE_ADVISOR);
|
||||
}
|
||||
}
|
||||
95
contracts/mocks/SafeERC20Helper.sol
Normal file
95
contracts/mocks/SafeERC20Helper.sol
Normal file
@ -0,0 +1,95 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "../token/ERC20/ERC20.sol";
|
||||
import "../token/ERC20/SafeERC20.sol";
|
||||
|
||||
|
||||
contract ERC20FailingMock is ERC20 {
|
||||
function totalSupply() public view returns (uint256) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
function transfer(address, uint256) public returns (bool) {
|
||||
return false;
|
||||
}
|
||||
|
||||
function transferFrom(address, address, uint256) public returns (bool) {
|
||||
return false;
|
||||
}
|
||||
|
||||
function approve(address, uint256) public returns (bool) {
|
||||
return false;
|
||||
}
|
||||
|
||||
function balanceOf(address) public view returns (uint256) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
function allowance(address, address) public view returns (uint256) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
contract ERC20SucceedingMock is ERC20 {
|
||||
function totalSupply() public view returns (uint256) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
function transfer(address, uint256) public returns (bool) {
|
||||
return true;
|
||||
}
|
||||
|
||||
function transferFrom(address, address, uint256) public returns (bool) {
|
||||
return true;
|
||||
}
|
||||
|
||||
function approve(address, uint256) public returns (bool) {
|
||||
return true;
|
||||
}
|
||||
|
||||
function balanceOf(address) public view returns (uint256) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
function allowance(address, address) public view returns (uint256) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
contract SafeERC20Helper {
|
||||
using SafeERC20 for ERC20;
|
||||
|
||||
ERC20 failing;
|
||||
ERC20 succeeding;
|
||||
|
||||
function SafeERC20Helper() public {
|
||||
failing = new ERC20FailingMock();
|
||||
succeeding = new ERC20SucceedingMock();
|
||||
}
|
||||
|
||||
function doFailingTransfer() public {
|
||||
failing.safeTransfer(0, 0);
|
||||
}
|
||||
|
||||
function doFailingTransferFrom() public {
|
||||
failing.safeTransferFrom(0, 0, 0);
|
||||
}
|
||||
|
||||
function doFailingApprove() public {
|
||||
failing.safeApprove(0, 0);
|
||||
}
|
||||
|
||||
function doSucceedingTransfer() public {
|
||||
succeeding.safeTransfer(0, 0);
|
||||
}
|
||||
|
||||
function doSucceedingTransferFrom() public {
|
||||
succeeding.safeTransferFrom(0, 0, 0);
|
||||
}
|
||||
|
||||
function doSucceedingApprove() public {
|
||||
succeeding.safeApprove(0, 0);
|
||||
}
|
||||
}
|
||||
24
contracts/mocks/SafeMathMock.sol
Normal file
24
contracts/mocks/SafeMathMock.sol
Normal file
@ -0,0 +1,24 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
|
||||
import "../math/SafeMath.sol";
|
||||
|
||||
|
||||
contract SafeMathMock {
|
||||
|
||||
function mul(uint256 a, uint256 b) public pure returns (uint256) {
|
||||
return SafeMath.mul(a, b);
|
||||
}
|
||||
|
||||
function div(uint256 a, uint256 b) public pure returns (uint256) {
|
||||
return SafeMath.div(a, b);
|
||||
}
|
||||
|
||||
function sub(uint256 a, uint256 b) public pure returns (uint256) {
|
||||
return SafeMath.sub(a, b);
|
||||
}
|
||||
|
||||
function add(uint256 a, uint256 b) public pure returns (uint256) {
|
||||
return SafeMath.add(a, b);
|
||||
}
|
||||
}
|
||||
13
contracts/mocks/StandardBurnableTokenMock.sol
Normal file
13
contracts/mocks/StandardBurnableTokenMock.sol
Normal file
@ -0,0 +1,13 @@
|
||||
pragma solidity ^0.4.18;
|
||||
|
||||
import "../token/ERC20/StandardBurnableToken.sol";
|
||||
|
||||
|
||||
contract StandardBurnableTokenMock is StandardBurnableToken {
|
||||
|
||||
function StandardBurnableTokenMock(address initialAccount, uint initialBalance) public {
|
||||
balances[initialAccount] = initialBalance;
|
||||
totalSupply_ = initialBalance;
|
||||
}
|
||||
|
||||
}
|
||||
14
contracts/mocks/StandardTokenMock.sol
Normal file
14
contracts/mocks/StandardTokenMock.sol
Normal file
@ -0,0 +1,14 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "../token/ERC20/StandardToken.sol";
|
||||
|
||||
|
||||
// mock class using StandardToken
|
||||
contract StandardTokenMock is StandardToken {
|
||||
|
||||
function StandardTokenMock(address initialAccount, uint256 initialBalance) public {
|
||||
balances[initialAccount] = initialBalance;
|
||||
totalSupply_ = initialBalance;
|
||||
}
|
||||
|
||||
}
|
||||
43
contracts/ownership/Ownable.sol
Normal file
43
contracts/ownership/Ownable.sol
Normal file
@ -0,0 +1,43 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "zos-lib/contracts/migrations/Migratable.sol";
|
||||
|
||||
|
||||
/**
|
||||
* @title Ownable
|
||||
* @dev The Ownable contract has an owner address, and provides basic authorization control
|
||||
* functions, this simplifies the implementation of "user permissions".
|
||||
*/
|
||||
contract Ownable is Migratable {
|
||||
address public owner;
|
||||
|
||||
|
||||
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
|
||||
|
||||
/**
|
||||
* @dev The Ownable constructor sets the original `owner` of the contract to the sender
|
||||
* account.
|
||||
*/
|
||||
function initialize(address _sender) public isInitializer("Ownable", "1.9.0") {
|
||||
owner = _sender;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Throws if called by any account other than the owner.
|
||||
*/
|
||||
modifier onlyOwner() {
|
||||
require(msg.sender == owner);
|
||||
_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Allows the current owner to transfer control of the contract to a newOwner.
|
||||
* @param newOwner The address to transfer ownership to.
|
||||
*/
|
||||
function transferOwnership(address newOwner) public onlyOwner {
|
||||
require(newOwner != address(0));
|
||||
emit OwnershipTransferred(owner, newOwner);
|
||||
owner = newOwner;
|
||||
}
|
||||
|
||||
}
|
||||
108
contracts/ownership/rbac/RBAC.sol
Normal file
108
contracts/ownership/rbac/RBAC.sol
Normal file
@ -0,0 +1,108 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "./Roles.sol";
|
||||
|
||||
|
||||
/**
|
||||
* @title RBAC (Role-Based Access Control)
|
||||
* @author Matt Condon (@Shrugs)
|
||||
* @dev Stores and provides setters and getters for roles and addresses.
|
||||
* @dev Supports unlimited numbers of roles and addresses.
|
||||
* @dev See //contracts/mocks/RBACMock.sol for an example of usage.
|
||||
* This RBAC method uses strings to key roles. It may be beneficial
|
||||
* for you to write your own implementation of this interface using Enums or similar.
|
||||
* It's also recommended that you define constants in the contract, like ROLE_ADMIN below,
|
||||
* to avoid typos.
|
||||
*/
|
||||
contract RBAC {
|
||||
using Roles for Roles.Role;
|
||||
|
||||
mapping (string => Roles.Role) private roles;
|
||||
|
||||
event RoleAdded(address addr, string roleName);
|
||||
event RoleRemoved(address addr, string roleName);
|
||||
|
||||
/**
|
||||
* @dev reverts if addr does not have role
|
||||
* @param addr address
|
||||
* @param roleName the name of the role
|
||||
* // reverts
|
||||
*/
|
||||
function checkRole(address addr, string roleName)
|
||||
view
|
||||
public
|
||||
{
|
||||
roles[roleName].check(addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev determine if addr has role
|
||||
* @param addr address
|
||||
* @param roleName the name of the role
|
||||
* @return bool
|
||||
*/
|
||||
function hasRole(address addr, string roleName)
|
||||
view
|
||||
public
|
||||
returns (bool)
|
||||
{
|
||||
return roles[roleName].has(addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev add a role to an address
|
||||
* @param addr address
|
||||
* @param roleName the name of the role
|
||||
*/
|
||||
function addRole(address addr, string roleName)
|
||||
internal
|
||||
{
|
||||
roles[roleName].add(addr);
|
||||
emit RoleAdded(addr, roleName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev remove a role from an address
|
||||
* @param addr address
|
||||
* @param roleName the name of the role
|
||||
*/
|
||||
function removeRole(address addr, string roleName)
|
||||
internal
|
||||
{
|
||||
roles[roleName].remove(addr);
|
||||
emit RoleRemoved(addr, roleName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev modifier to scope access to a single role (uses msg.sender as addr)
|
||||
* @param roleName the name of the role
|
||||
* // reverts
|
||||
*/
|
||||
modifier onlyRole(string roleName)
|
||||
{
|
||||
checkRole(msg.sender, roleName);
|
||||
_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev modifier to scope access to a set of roles (uses msg.sender as addr)
|
||||
* @param roleNames the names of the roles to scope access to
|
||||
* // reverts
|
||||
*
|
||||
* @TODO - when solidity supports dynamic arrays as arguments to modifiers, provide this
|
||||
* see: https://github.com/ethereum/solidity/issues/2467
|
||||
*/
|
||||
// modifier onlyRoles(string[] roleNames) {
|
||||
// bool hasAnyRole = false;
|
||||
// for (uint8 i = 0; i < roleNames.length; i++) {
|
||||
// if (hasRole(msg.sender, roleNames[i])) {
|
||||
// hasAnyRole = true;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
// require(hasAnyRole);
|
||||
|
||||
// _;
|
||||
// }
|
||||
}
|
||||
62
contracts/ownership/rbac/RBACWithAdmin.sol
Normal file
62
contracts/ownership/rbac/RBACWithAdmin.sol
Normal file
@ -0,0 +1,62 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "./RBAC.sol";
|
||||
import "zos-lib/contracts/migrations/Migratable.sol";
|
||||
|
||||
|
||||
/**
|
||||
* @title RBACWithAdmin
|
||||
* @author Matt Condon (@Shrugs)
|
||||
* @dev It's recommended that you define constants in the contract,
|
||||
* @dev like ROLE_ADMIN below, to avoid typos.
|
||||
*/
|
||||
contract RBACWithAdmin is RBAC, Migratable {
|
||||
/**
|
||||
* A constant role name for indicating admins.
|
||||
*/
|
||||
string public constant ROLE_ADMIN = "admin";
|
||||
|
||||
/**
|
||||
* @dev modifier to scope access to admins
|
||||
* // reverts
|
||||
*/
|
||||
modifier onlyAdmin()
|
||||
{
|
||||
checkRole(msg.sender, ROLE_ADMIN);
|
||||
_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev constructor. Sets initialAdmin as admin.
|
||||
*/
|
||||
function initialize(address initialAdmin)
|
||||
isInitializer("RBACWithAdmin", "1.9.0")
|
||||
public
|
||||
{
|
||||
addRole(initialAdmin, ROLE_ADMIN);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev add a role to an address
|
||||
* @param addr address
|
||||
* @param roleName the name of the role
|
||||
*/
|
||||
function adminAddRole(address addr, string roleName)
|
||||
onlyAdmin
|
||||
public
|
||||
{
|
||||
addRole(addr, roleName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev remove a role from an address
|
||||
* @param addr address
|
||||
* @param roleName the name of the role
|
||||
*/
|
||||
function adminRemoveRole(address addr, string roleName)
|
||||
onlyAdmin
|
||||
public
|
||||
{
|
||||
removeRole(addr, roleName);
|
||||
}
|
||||
}
|
||||
55
contracts/ownership/rbac/Roles.sol
Normal file
55
contracts/ownership/rbac/Roles.sol
Normal file
@ -0,0 +1,55 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
|
||||
/**
|
||||
* @title Roles
|
||||
* @author Francisco Giordano (@frangio)
|
||||
* @dev Library for managing addresses assigned to a Role.
|
||||
* See RBAC.sol for example usage.
|
||||
*/
|
||||
library Roles {
|
||||
struct Role {
|
||||
mapping (address => bool) bearer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev give an address access to this role
|
||||
*/
|
||||
function add(Role storage role, address addr)
|
||||
internal
|
||||
{
|
||||
role.bearer[addr] = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev remove an address' access to this role
|
||||
*/
|
||||
function remove(Role storage role, address addr)
|
||||
internal
|
||||
{
|
||||
role.bearer[addr] = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev check if an address has this role
|
||||
* // reverts
|
||||
*/
|
||||
function check(Role storage role, address addr)
|
||||
view
|
||||
internal
|
||||
{
|
||||
require(has(role, addr));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev check if an address has this role
|
||||
* @return bool
|
||||
*/
|
||||
function has(Role storage role, address addr)
|
||||
view
|
||||
internal
|
||||
returns (bool)
|
||||
{
|
||||
return role.bearer[addr];
|
||||
}
|
||||
}
|
||||
43
contracts/payment/PullPayment.sol
Normal file
43
contracts/payment/PullPayment.sol
Normal file
@ -0,0 +1,43 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
|
||||
import "../math/SafeMath.sol";
|
||||
|
||||
|
||||
/**
|
||||
* @title PullPayment
|
||||
* @dev Base contract supporting async send for pull payments. Inherit from this
|
||||
* contract and use asyncSend instead of send or transfer.
|
||||
*/
|
||||
contract PullPayment {
|
||||
using SafeMath for uint256;
|
||||
|
||||
mapping(address => uint256) public payments;
|
||||
uint256 public totalPayments;
|
||||
|
||||
/**
|
||||
* @dev Withdraw accumulated balance, called by payee.
|
||||
*/
|
||||
function withdrawPayments() public {
|
||||
address payee = msg.sender;
|
||||
uint256 payment = payments[payee];
|
||||
|
||||
require(payment != 0);
|
||||
require(address(this).balance >= payment);
|
||||
|
||||
totalPayments = totalPayments.sub(payment);
|
||||
payments[payee] = 0;
|
||||
|
||||
payee.transfer(payment);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Called by the payer to store the sent amount as credit to be pulled.
|
||||
* @param dest The destination address of the funds.
|
||||
* @param amount The amount to transfer.
|
||||
*/
|
||||
function asyncSend(address dest, uint256 amount) internal {
|
||||
payments[dest] = payments[dest].add(amount);
|
||||
totalPayments = totalPayments.add(amount);
|
||||
}
|
||||
}
|
||||
76
contracts/payment/SplitPayment.sol
Normal file
76
contracts/payment/SplitPayment.sol
Normal file
@ -0,0 +1,76 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "../math/SafeMath.sol";
|
||||
import "zos-lib/contracts/migrations/Migratable.sol";
|
||||
|
||||
|
||||
/**
|
||||
* @title SplitPayment
|
||||
* @dev Base contract that supports multiple payees claiming funds sent to this contract
|
||||
* according to the proportion they own.
|
||||
*/
|
||||
contract SplitPayment is Migratable {
|
||||
using SafeMath for uint256;
|
||||
|
||||
uint256 public totalShares = 0;
|
||||
uint256 public totalReleased = 0;
|
||||
|
||||
mapping(address => uint256) public shares;
|
||||
mapping(address => uint256) public released;
|
||||
address[] public payees;
|
||||
|
||||
/**
|
||||
* @dev Constructor
|
||||
*/
|
||||
function initialize(address[] _payees, uint256[] _shares)
|
||||
isInitializer("SplitPayment", "1.9.0")
|
||||
public
|
||||
payable
|
||||
{
|
||||
require(_payees.length == _shares.length);
|
||||
|
||||
for (uint256 i = 0; i < _payees.length; i++) {
|
||||
addPayee(_payees[i], _shares[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev payable fallback
|
||||
*/
|
||||
function () public payable {}
|
||||
|
||||
/**
|
||||
* @dev Claim your share of the balance.
|
||||
*/
|
||||
function claim() public {
|
||||
address payee = msg.sender;
|
||||
|
||||
require(shares[payee] > 0);
|
||||
|
||||
uint256 totalReceived = address(this).balance.add(totalReleased);
|
||||
uint256 payment = totalReceived.mul(shares[payee]).div(totalShares).sub(released[payee]);
|
||||
|
||||
require(payment != 0);
|
||||
require(address(this).balance >= payment);
|
||||
|
||||
released[payee] = released[payee].add(payment);
|
||||
totalReleased = totalReleased.add(payment);
|
||||
|
||||
payee.transfer(payment);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Add a new payee to the contract.
|
||||
* @param _payee The address of the payee to add.
|
||||
* @param _shares The number of shares owned by the payee.
|
||||
*/
|
||||
function addPayee(address _payee, uint256 _shares) internal {
|
||||
require(_payee != address(0));
|
||||
require(_shares > 0);
|
||||
require(shares[_payee] == 0);
|
||||
|
||||
payees.push(_payee);
|
||||
shares[_payee] = _shares;
|
||||
totalShares = totalShares.add(_shares);
|
||||
}
|
||||
}
|
||||
@ -1,15 +0,0 @@
|
||||
pragma solidity ^0.4.4;
|
||||
|
||||
|
||||
import '../token/BasicToken.sol';
|
||||
|
||||
|
||||
// mock class using BasicToken
|
||||
contract BasicTokenMock is BasicToken {
|
||||
|
||||
function BasicTokenMock(address initialAccount, uint initialBalance) {
|
||||
balances[initialAccount] = initialBalance;
|
||||
totalSupply = initialBalance;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,23 +0,0 @@
|
||||
pragma solidity ^0.4.4;
|
||||
import "../DayLimit.sol";
|
||||
|
||||
contract DayLimitMock is DayLimit {
|
||||
uint public totalSpending;
|
||||
|
||||
function DayLimitMock(uint _value) DayLimit(_value) {
|
||||
totalSpending = 0;
|
||||
}
|
||||
|
||||
function attemptSpend(uint _value) external limitedDaily(_value) {
|
||||
totalSpending += _value;
|
||||
}
|
||||
|
||||
function setDailyLimit(uint _newLimit) external {
|
||||
_setDailyLimit(_newLimit);
|
||||
}
|
||||
|
||||
function resetSpentToday() external {
|
||||
_resetSpentToday();
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,17 +0,0 @@
|
||||
pragma solidity ^0.4.4;
|
||||
|
||||
|
||||
import {Bounty, Target} from "../Bounty.sol";
|
||||
|
||||
|
||||
contract InsecureTargetMock is Target {
|
||||
function checkInvariant() returns(bool){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
contract InsecureTargetBounty is Bounty {
|
||||
function deployContract() internal returns (address) {
|
||||
return new InsecureTargetMock();
|
||||
}
|
||||
}
|
||||
@ -1,13 +0,0 @@
|
||||
pragma solidity ^0.4.4;
|
||||
|
||||
|
||||
import '../LimitBalance.sol';
|
||||
|
||||
|
||||
// mock class using LimitBalance
|
||||
contract LimitBalanceMock is LimitBalance(1000) {
|
||||
|
||||
function limitedDeposit() payable limitedPayable {
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,12 +0,0 @@
|
||||
pragma solidity ^0.4.4;
|
||||
import "../MultisigWallet.sol";
|
||||
|
||||
contract MultisigWalletMock is MultisigWallet {
|
||||
uint public totalSpending;
|
||||
|
||||
function MultisigWalletMock(address[] _owners, uint _required, uint _daylimit)
|
||||
MultisigWallet(_owners, _required, _daylimit) payable { }
|
||||
|
||||
function changeOwner(address _from, address _to) external { }
|
||||
|
||||
}
|
||||
@ -1,17 +0,0 @@
|
||||
pragma solidity ^0.4.4;
|
||||
|
||||
|
||||
import '../PullPayment.sol';
|
||||
|
||||
|
||||
// mock class using PullPayment
|
||||
contract PullPaymentMock is PullPayment {
|
||||
|
||||
function PullPaymentMock() payable { }
|
||||
|
||||
// test helper function to call asyncSend
|
||||
function callSend(address dest, uint amount) {
|
||||
asyncSend(dest, amount);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,21 +0,0 @@
|
||||
pragma solidity ^0.4.4;
|
||||
|
||||
|
||||
import '../SafeMath.sol';
|
||||
|
||||
|
||||
contract SafeMathMock is SafeMath {
|
||||
uint public result;
|
||||
|
||||
function multiply(uint a, uint b) {
|
||||
result = safeMul(a, b);
|
||||
}
|
||||
|
||||
function subtract(uint a, uint b) {
|
||||
result = safeSub(a, b);
|
||||
}
|
||||
|
||||
function add(uint a, uint b) {
|
||||
result = safeAdd(a, b);
|
||||
}
|
||||
}
|
||||
@ -1,17 +0,0 @@
|
||||
pragma solidity ^0.4.4;
|
||||
|
||||
|
||||
import {Bounty, Target} from "../Bounty.sol";
|
||||
|
||||
|
||||
contract SecureTargetMock is Target {
|
||||
function checkInvariant() returns(bool) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
contract SecureTargetBounty is Bounty {
|
||||
function deployContract() internal returns (address) {
|
||||
return new SecureTargetMock();
|
||||
}
|
||||
}
|
||||
@ -1,16 +0,0 @@
|
||||
pragma solidity ^0.4.4;
|
||||
import "../Shareable.sol";
|
||||
|
||||
contract ShareableMock is Shareable {
|
||||
|
||||
uint public count = 0;
|
||||
|
||||
function ShareableMock(address[] _owners, uint _required) Shareable(_owners, _required) {
|
||||
|
||||
}
|
||||
|
||||
function increaseCount(bytes32 action) onlymanyowners(action) {
|
||||
count = count + 1;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,15 +0,0 @@
|
||||
pragma solidity ^0.4.4;
|
||||
|
||||
|
||||
import '../token/StandardToken.sol';
|
||||
|
||||
|
||||
// mock class using StandardToken
|
||||
contract StandardTokenMock is StandardToken {
|
||||
|
||||
function StandardTokenMock(address initialAccount, uint initialBalance) {
|
||||
balances[initialAccount] = initialBalance;
|
||||
totalSupply = initialBalance;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,25 +0,0 @@
|
||||
pragma solidity ^0.4.4;
|
||||
|
||||
|
||||
import '../Stoppable.sol';
|
||||
|
||||
|
||||
// mock class using Stoppable
|
||||
contract StoppableMock is Stoppable {
|
||||
bool public drasticMeasureTaken;
|
||||
uint public count;
|
||||
|
||||
function StoppableMock() {
|
||||
drasticMeasureTaken = false;
|
||||
count = 0;
|
||||
}
|
||||
|
||||
function normalProcess() external stopInEmergency {
|
||||
count++;
|
||||
}
|
||||
|
||||
function drasticMeasure() external onlyInEmergency {
|
||||
drasticMeasureTaken = true;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,29 +0,0 @@
|
||||
pragma solidity ^0.4.4;
|
||||
|
||||
|
||||
import './ERC20Basic.sol';
|
||||
import '../SafeMath.sol';
|
||||
|
||||
|
||||
/*
|
||||
* Basic token
|
||||
* Basic version of StandardToken, with no allowances
|
||||
*/
|
||||
contract BasicToken is ERC20Basic, SafeMath {
|
||||
|
||||
mapping(address => uint) balances;
|
||||
|
||||
function transfer(address _to, uint _value) {
|
||||
if (balances[msg.sender] < _value) {
|
||||
throw;
|
||||
}
|
||||
balances[msg.sender] = safeSub(balances[msg.sender], _value);
|
||||
balances[_to] = safeAdd(balances[_to], _value);
|
||||
Transfer(msg.sender, _to, _value);
|
||||
}
|
||||
|
||||
function balanceOf(address _owner) constant returns (uint balance) {
|
||||
return balances[_owner];
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,38 +0,0 @@
|
||||
pragma solidity ^0.4.4;
|
||||
|
||||
|
||||
import "./StandardToken.sol";
|
||||
|
||||
|
||||
/*
|
||||
* CrowdsaleToken
|
||||
*
|
||||
* Simple ERC20 Token example, with crowdsale token creation
|
||||
*/
|
||||
contract CrowdsaleToken is StandardToken {
|
||||
|
||||
string public name = "CrowdsaleToken";
|
||||
string public symbol = "CRW";
|
||||
uint public decimals = 18;
|
||||
|
||||
// 1 ether = 500 example tokens
|
||||
uint PRICE = 500;
|
||||
|
||||
function () payable {
|
||||
createTokens(msg.sender);
|
||||
}
|
||||
|
||||
function createTokens(address recipient) payable {
|
||||
if (msg.value == 0) throw;
|
||||
|
||||
uint tokens = safeMul(msg.value, getPrice());
|
||||
|
||||
totalSupply = safeAdd(totalSupply, tokens);
|
||||
balances[recipient] = safeAdd(balances[recipient], tokens);
|
||||
}
|
||||
|
||||
// replace this with any other price function
|
||||
function getPrice() constant returns (uint result){
|
||||
return PRICE;
|
||||
}
|
||||
}
|
||||
@ -1,18 +0,0 @@
|
||||
pragma solidity ^0.4.4;
|
||||
|
||||
|
||||
/*
|
||||
* ERC20 interface
|
||||
* see https://github.com/ethereum/EIPs/issues/20
|
||||
*/
|
||||
contract ERC20 {
|
||||
uint public totalSupply;
|
||||
function balanceOf(address who) constant returns (uint);
|
||||
function allowance(address owner, address spender) constant returns (uint);
|
||||
|
||||
function transfer(address to, uint value) returns (bool ok);
|
||||
function transferFrom(address from, address to, uint value) returns (bool ok);
|
||||
function approve(address spender, uint value) returns (bool ok);
|
||||
event Transfer(address indexed from, address indexed to, uint value);
|
||||
event Approval(address indexed owner, address indexed spender, uint value);
|
||||
}
|
||||
50
contracts/token/ERC20/BasicToken.sol
Normal file
50
contracts/token/ERC20/BasicToken.sol
Normal file
@ -0,0 +1,50 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
|
||||
import "./ERC20Basic.sol";
|
||||
import "../../math/SafeMath.sol";
|
||||
|
||||
|
||||
/**
|
||||
* @title Basic token
|
||||
* @dev Basic version of StandardToken, with no allowances.
|
||||
*/
|
||||
contract BasicToken is ERC20Basic {
|
||||
using SafeMath for uint256;
|
||||
|
||||
mapping(address => uint256) balances;
|
||||
|
||||
uint256 totalSupply_;
|
||||
|
||||
/**
|
||||
* @dev total number of tokens in existence
|
||||
*/
|
||||
function totalSupply() public view returns (uint256) {
|
||||
return totalSupply_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev transfer token for a specified address
|
||||
* @param _to The address to transfer to.
|
||||
* @param _value The amount to be transferred.
|
||||
*/
|
||||
function transfer(address _to, uint256 _value) public returns (bool) {
|
||||
require(_to != address(0));
|
||||
require(_value <= balances[msg.sender]);
|
||||
|
||||
balances[msg.sender] = balances[msg.sender].sub(_value);
|
||||
balances[_to] = balances[_to].add(_value);
|
||||
emit Transfer(msg.sender, _to, _value);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Gets the balance of the specified address.
|
||||
* @param _owner The address to query the the balance of.
|
||||
* @return An uint256 representing the amount owned by the passed address.
|
||||
*/
|
||||
function balanceOf(address _owner) public view returns (uint256) {
|
||||
return balances[_owner];
|
||||
}
|
||||
|
||||
}
|
||||
32
contracts/token/ERC20/BurnableToken.sol
Normal file
32
contracts/token/ERC20/BurnableToken.sol
Normal file
@ -0,0 +1,32 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "./BasicToken.sol";
|
||||
|
||||
|
||||
/**
|
||||
* @title Burnable Token
|
||||
* @dev Token that can be irreversibly burned (destroyed).
|
||||
*/
|
||||
contract BurnableToken is BasicToken {
|
||||
|
||||
event Burn(address indexed burner, uint256 value);
|
||||
|
||||
/**
|
||||
* @dev Burns a specific amount of tokens.
|
||||
* @param _value The amount of token to be burned.
|
||||
*/
|
||||
function burn(uint256 _value) public {
|
||||
_burn(msg.sender, _value);
|
||||
}
|
||||
|
||||
function _burn(address _who, uint256 _value) internal {
|
||||
require(_value <= balances[_who]);
|
||||
// no need to require value <= totalSupply, since that would imply the
|
||||
// sender's balance is greater than the totalSupply, which *should* be an assertion failure
|
||||
|
||||
balances[_who] = balances[_who].sub(_value);
|
||||
totalSupply_ = totalSupply_.sub(_value);
|
||||
emit Burn(_who, _value);
|
||||
emit Transfer(_who, address(0), _value);
|
||||
}
|
||||
}
|
||||
17
contracts/token/ERC20/DetailedERC20.sol
Normal file
17
contracts/token/ERC20/DetailedERC20.sol
Normal file
@ -0,0 +1,17 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "./ERC20.sol";
|
||||
import "zos-lib/contracts/migrations/Migratable.sol";
|
||||
|
||||
|
||||
contract DetailedERC20 is Migratable, ERC20 {
|
||||
string public name;
|
||||
string public symbol;
|
||||
uint8 public decimals;
|
||||
|
||||
function initialize(string _name, string _symbol, uint8 _decimals) public isInitializer("DetailedERC20", "1.9.0") {
|
||||
name = _name;
|
||||
symbol = _symbol;
|
||||
decimals = _decimals;
|
||||
}
|
||||
}
|
||||
21
contracts/token/ERC20/DetailedMintableToken.sol
Normal file
21
contracts/token/ERC20/DetailedMintableToken.sol
Normal file
@ -0,0 +1,21 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "zos-lib/contracts/migrations/Migratable.sol";
|
||||
import "./DetailedERC20.sol";
|
||||
import "./MintableToken.sol";
|
||||
|
||||
|
||||
contract DetailedMintableToken is Migratable, DetailedERC20, MintableToken {
|
||||
function initialize(
|
||||
address _sender,
|
||||
string _name,
|
||||
string _symbol,
|
||||
uint8 _decimals
|
||||
)
|
||||
isInitializer("DetailedMintableToken", "1.9.0")
|
||||
public
|
||||
{
|
||||
DetailedERC20.initialize(_name, _symbol, _decimals);
|
||||
MintableToken.initialize(_sender);
|
||||
}
|
||||
}
|
||||
29
contracts/token/ERC20/DetailedPremintedToken.sol
Normal file
29
contracts/token/ERC20/DetailedPremintedToken.sol
Normal file
@ -0,0 +1,29 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "zos-lib/contracts/migrations/Migratable.sol";
|
||||
import "./DetailedERC20.sol";
|
||||
import "./MintableToken.sol";
|
||||
|
||||
|
||||
contract DetailedPremintedToken is Migratable, DetailedERC20, StandardToken {
|
||||
function initialize(
|
||||
address _sender,
|
||||
string _name,
|
||||
string _symbol,
|
||||
uint8 _decimals,
|
||||
uint256 _initialBalance
|
||||
)
|
||||
isInitializer("DetailedPremintedToken", "1.9.0")
|
||||
public
|
||||
{
|
||||
DetailedERC20.initialize(_name, _symbol, _decimals);
|
||||
|
||||
_premint(_sender, _initialBalance);
|
||||
}
|
||||
|
||||
function _premint(address _to, uint256 _value) internal {
|
||||
totalSupply_ += _value;
|
||||
balances[_to] += _value;
|
||||
emit Transfer(0, _to, _value);
|
||||
}
|
||||
}
|
||||
15
contracts/token/ERC20/ERC20.sol
Normal file
15
contracts/token/ERC20/ERC20.sol
Normal file
@ -0,0 +1,15 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "./ERC20Basic.sol";
|
||||
|
||||
|
||||
/**
|
||||
* @title ERC20 interface
|
||||
* @dev see https://github.com/ethereum/EIPs/issues/20
|
||||
*/
|
||||
contract ERC20 is ERC20Basic {
|
||||
function allowance(address owner, address spender) public view returns (uint256);
|
||||
function transferFrom(address from, address to, uint256 value) public returns (bool);
|
||||
function approve(address spender, uint256 value) public returns (bool);
|
||||
event Approval(address indexed owner, address indexed spender, uint256 value);
|
||||
}
|
||||
14
contracts/token/ERC20/ERC20Basic.sol
Normal file
14
contracts/token/ERC20/ERC20Basic.sol
Normal file
@ -0,0 +1,14 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
|
||||
/**
|
||||
* @title ERC20Basic
|
||||
* @dev Simpler version of ERC20 interface
|
||||
* @dev see https://github.com/ethereum/EIPs/issues/179
|
||||
*/
|
||||
contract ERC20Basic {
|
||||
function totalSupply() public view returns (uint256);
|
||||
function balanceOf(address who) public view returns (uint256);
|
||||
function transfer(address to, uint256 value) public returns (bool);
|
||||
event Transfer(address indexed from, address indexed to, uint256 value);
|
||||
}
|
||||
53
contracts/token/ERC20/MintableToken.sol
Normal file
53
contracts/token/ERC20/MintableToken.sol
Normal file
@ -0,0 +1,53 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "./StandardToken.sol";
|
||||
import "../../ownership/Ownable.sol";
|
||||
import "zos-lib/contracts/migrations/Migratable.sol";
|
||||
|
||||
|
||||
/**
|
||||
* @title Mintable token
|
||||
* @dev Simple ERC20 Token example, with mintable token creation
|
||||
* @dev Issue: * https://github.com/OpenZeppelin/openzeppelin-solidity/issues/120
|
||||
* Based on code by TokenMarketNet: https://github.com/TokenMarketNet/ico/blob/master/contracts/MintableToken.sol
|
||||
*/
|
||||
contract MintableToken is Migratable, Ownable, StandardToken {
|
||||
event Mint(address indexed to, uint256 amount);
|
||||
event MintFinished();
|
||||
|
||||
bool public mintingFinished = false;
|
||||
|
||||
|
||||
modifier canMint() {
|
||||
require(!mintingFinished);
|
||||
_;
|
||||
}
|
||||
|
||||
function initialize(address _sender) isInitializer("MintableToken", "1.9.0") public {
|
||||
Ownable.initialize(_sender);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Function to mint tokens
|
||||
* @param _to The address that will receive the minted tokens.
|
||||
* @param _amount The amount of tokens to mint.
|
||||
* @return A boolean that indicates if the operation was successful.
|
||||
*/
|
||||
function mint(address _to, uint256 _amount) onlyOwner canMint public returns (bool) {
|
||||
totalSupply_ = totalSupply_.add(_amount);
|
||||
balances[_to] = balances[_to].add(_amount);
|
||||
emit Mint(_to, _amount);
|
||||
emit Transfer(address(0), _to, _amount);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Function to stop minting new tokens.
|
||||
* @return True if the operation was successful.
|
||||
*/
|
||||
function finishMinting() onlyOwner canMint public returns (bool) {
|
||||
mintingFinished = true;
|
||||
emit MintFinished();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
36
contracts/token/ERC20/PausableToken.sol
Normal file
36
contracts/token/ERC20/PausableToken.sol
Normal file
@ -0,0 +1,36 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "./StandardToken.sol";
|
||||
import "../../lifecycle/Pausable.sol";
|
||||
|
||||
|
||||
/**
|
||||
* @title Pausable token
|
||||
* @dev StandardToken modified with pausable transfers.
|
||||
**/
|
||||
contract PausableToken is Migratable, StandardToken, Pausable {
|
||||
|
||||
function initialize(address _sender) isInitializer("PausableToken", "1.9.0") public {
|
||||
Pausable.initialize(_sender);
|
||||
}
|
||||
|
||||
function transfer(address _to, uint256 _value) public whenNotPaused returns (bool) {
|
||||
return super.transfer(_to, _value);
|
||||
}
|
||||
|
||||
function transferFrom(address _from, address _to, uint256 _value) public whenNotPaused returns (bool) {
|
||||
return super.transferFrom(_from, _to, _value);
|
||||
}
|
||||
|
||||
function approve(address _spender, uint256 _value) public whenNotPaused returns (bool) {
|
||||
return super.approve(_spender, _value);
|
||||
}
|
||||
|
||||
function increaseApproval(address _spender, uint _addedValue) public whenNotPaused returns (bool success) {
|
||||
return super.increaseApproval(_spender, _addedValue);
|
||||
}
|
||||
|
||||
function decreaseApproval(address _spender, uint _subtractedValue) public whenNotPaused returns (bool success) {
|
||||
return super.decreaseApproval(_spender, _subtractedValue);
|
||||
}
|
||||
}
|
||||
32
contracts/token/ERC20/SafeERC20.sol
Normal file
32
contracts/token/ERC20/SafeERC20.sol
Normal file
@ -0,0 +1,32 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "./ERC20Basic.sol";
|
||||
import "./ERC20.sol";
|
||||
|
||||
|
||||
/**
|
||||
* @title SafeERC20
|
||||
* @dev Wrappers around ERC20 operations that throw on failure.
|
||||
* To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract,
|
||||
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
|
||||
*/
|
||||
library SafeERC20 {
|
||||
function safeTransfer(ERC20Basic token, address to, uint256 value) internal {
|
||||
assert(token.transfer(to, value));
|
||||
}
|
||||
|
||||
function safeTransferFrom(
|
||||
ERC20 token,
|
||||
address from,
|
||||
address to,
|
||||
uint256 value
|
||||
)
|
||||
internal
|
||||
{
|
||||
assert(token.transferFrom(from, to, value));
|
||||
}
|
||||
|
||||
function safeApprove(ERC20 token, address spender, uint256 value) internal {
|
||||
assert(token.approve(spender, value));
|
||||
}
|
||||
}
|
||||
25
contracts/token/ERC20/StandardBurnableToken.sol
Normal file
25
contracts/token/ERC20/StandardBurnableToken.sol
Normal file
@ -0,0 +1,25 @@
|
||||
pragma solidity ^0.4.18;
|
||||
|
||||
import "./BurnableToken.sol";
|
||||
import "./StandardToken.sol";
|
||||
|
||||
|
||||
/**
|
||||
* @title Standard Burnable Token
|
||||
* @dev Adds burnFrom method to ERC20 implementations
|
||||
*/
|
||||
contract StandardBurnableToken is BurnableToken, StandardToken {
|
||||
|
||||
/**
|
||||
* @dev Burns a specific amount of tokens from the target address and decrements allowance
|
||||
* @param _from address The address which you want to send tokens from
|
||||
* @param _value uint256 The amount of token to be burned
|
||||
*/
|
||||
function burnFrom(address _from, uint256 _value) public {
|
||||
require(_value <= allowed[_from][msg.sender]);
|
||||
// Should https://github.com/OpenZeppelin/zeppelin-solidity/issues/707 be accepted,
|
||||
// this function needs to emit an event with the updated approval.
|
||||
allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
|
||||
_burn(_from, _value);
|
||||
}
|
||||
}
|
||||
100
contracts/token/ERC20/StandardToken.sol
Normal file
100
contracts/token/ERC20/StandardToken.sol
Normal file
@ -0,0 +1,100 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "./BasicToken.sol";
|
||||
import "./ERC20.sol";
|
||||
|
||||
|
||||
/**
|
||||
* @title Standard ERC20 token
|
||||
*
|
||||
* @dev Implementation of the basic standard token.
|
||||
* @dev https://github.com/ethereum/EIPs/issues/20
|
||||
* @dev Based on code by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
|
||||
*/
|
||||
contract StandardToken is ERC20, BasicToken {
|
||||
|
||||
mapping (address => mapping (address => uint256)) internal allowed;
|
||||
|
||||
|
||||
/**
|
||||
* @dev Transfer tokens from one address to another
|
||||
* @param _from address The address which you want to send tokens from
|
||||
* @param _to address The address which you want to transfer to
|
||||
* @param _value uint256 the amount of tokens to be transferred
|
||||
*/
|
||||
function transferFrom(address _from, address _to, uint256 _value) public returns (bool) {
|
||||
require(_to != address(0));
|
||||
require(_value <= balances[_from]);
|
||||
require(_value <= allowed[_from][msg.sender]);
|
||||
|
||||
balances[_from] = balances[_from].sub(_value);
|
||||
balances[_to] = balances[_to].add(_value);
|
||||
allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
|
||||
emit Transfer(_from, _to, _value);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
|
||||
*
|
||||
* Beware that changing an allowance with this method brings the risk that someone may use both the old
|
||||
* and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this
|
||||
* race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:
|
||||
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
|
||||
* @param _spender The address which will spend the funds.
|
||||
* @param _value The amount of tokens to be spent.
|
||||
*/
|
||||
function approve(address _spender, uint256 _value) public returns (bool) {
|
||||
allowed[msg.sender][_spender] = _value;
|
||||
emit Approval(msg.sender, _spender, _value);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Function to check the amount of tokens that an owner allowed to a spender.
|
||||
* @param _owner address The address which owns the funds.
|
||||
* @param _spender address The address which will spend the funds.
|
||||
* @return A uint256 specifying the amount of tokens still available for the spender.
|
||||
*/
|
||||
function allowance(address _owner, address _spender) public view returns (uint256) {
|
||||
return allowed[_owner][_spender];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Increase the amount of tokens that an owner allowed to a spender.
|
||||
*
|
||||
* approve should be called when allowed[_spender] == 0. To increment
|
||||
* allowed value is better to use this function to avoid 2 calls (and wait until
|
||||
* the first transaction is mined)
|
||||
* From MonolithDAO Token.sol
|
||||
* @param _spender The address which will spend the funds.
|
||||
* @param _addedValue The amount of tokens to increase the allowance by.
|
||||
*/
|
||||
function increaseApproval(address _spender, uint _addedValue) public returns (bool) {
|
||||
allowed[msg.sender][_spender] = allowed[msg.sender][_spender].add(_addedValue);
|
||||
emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Decrease the amount of tokens that an owner allowed to a spender.
|
||||
*
|
||||
* approve should be called when allowed[_spender] == 0. To decrement
|
||||
* allowed value is better to use this function to avoid 2 calls (and wait until
|
||||
* the first transaction is mined)
|
||||
* From MonolithDAO Token.sol
|
||||
* @param _spender The address which will spend the funds.
|
||||
* @param _subtractedValue The amount of tokens to decrease the allowance by.
|
||||
*/
|
||||
function decreaseApproval(address _spender, uint _subtractedValue) public returns (bool) {
|
||||
uint oldValue = allowed[msg.sender][_spender];
|
||||
if (_subtractedValue > oldValue) {
|
||||
allowed[msg.sender][_spender] = 0;
|
||||
} else {
|
||||
allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue);
|
||||
}
|
||||
emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
52
contracts/token/ERC20/TokenTimelock.sol
Normal file
52
contracts/token/ERC20/TokenTimelock.sol
Normal file
@ -0,0 +1,52 @@
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "./SafeERC20.sol";
|
||||
import "zos-lib/contracts/migrations/Migratable.sol";
|
||||
|
||||
|
||||
/**
|
||||
* @title TokenTimelock
|
||||
* @dev TokenTimelock is a token holder contract that will allow a
|
||||
* beneficiary to extract the tokens after a given release time
|
||||
*/
|
||||
contract TokenTimelock is Migratable {
|
||||
using SafeERC20 for ERC20Basic;
|
||||
|
||||
// ERC20 basic token contract being held
|
||||
ERC20Basic public token;
|
||||
|
||||
// beneficiary of tokens after they are released
|
||||
address public beneficiary;
|
||||
|
||||
// timestamp when token release is enabled
|
||||
uint256 public releaseTime;
|
||||
|
||||
function initialize(
|
||||
address _sender,
|
||||
ERC20Basic _token,
|
||||
address _beneficiary,
|
||||
uint256 _releaseTime
|
||||
)
|
||||
isInitializer("TokenTimelock", "1.9.0")
|
||||
public
|
||||
{
|
||||
// solium-disable-next-line security/no-block-members
|
||||
require(_releaseTime > block.timestamp);
|
||||
token = _token;
|
||||
beneficiary = _beneficiary;
|
||||
releaseTime = _releaseTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Transfers tokens held by timelock to beneficiary.
|
||||
*/
|
||||
function release() public {
|
||||
// solium-disable-next-line security/no-block-members
|
||||
require(block.timestamp >= releaseTime);
|
||||
|
||||
uint256 amount = token.balanceOf(this);
|
||||
require(amount > 0);
|
||||
|
||||
token.safeTransfer(beneficiary, amount);
|
||||
}
|
||||
}
|
||||
130
contracts/token/ERC20/TokenVesting.sol
Normal file
130
contracts/token/ERC20/TokenVesting.sol
Normal file
@ -0,0 +1,130 @@
|
||||
/* solium-disable security/no-block-members */
|
||||
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "./ERC20Basic.sol";
|
||||
import "./SafeERC20.sol";
|
||||
import "../../ownership/Ownable.sol";
|
||||
import "../../math/SafeMath.sol";
|
||||
import "zos-lib/contracts/migrations/Migratable.sol";
|
||||
|
||||
|
||||
/**
|
||||
* @title TokenVesting
|
||||
* @dev A token holder contract that can release its token balance gradually like a
|
||||
* typical vesting scheme, with a cliff and vesting period. Optionally revocable by the
|
||||
* owner.
|
||||
*/
|
||||
contract TokenVesting is Migratable, Ownable {
|
||||
using SafeMath for uint256;
|
||||
using SafeERC20 for ERC20Basic;
|
||||
|
||||
event Released(uint256 amount);
|
||||
event Revoked();
|
||||
|
||||
// beneficiary of tokens after they are released
|
||||
address public beneficiary;
|
||||
|
||||
uint256 public cliff;
|
||||
uint256 public start;
|
||||
uint256 public duration;
|
||||
|
||||
bool public revocable;
|
||||
|
||||
mapping (address => uint256) public released;
|
||||
mapping (address => bool) public revoked;
|
||||
|
||||
/**
|
||||
* @dev Creates a vesting contract that vests its balance of any ERC20 token to the
|
||||
* _beneficiary, gradually in a linear fashion until _start + _duration. By then all
|
||||
* of the balance will have vested.
|
||||
* @param _beneficiary address of the beneficiary to whom vested tokens are transferred
|
||||
* @param _cliff duration in seconds of the cliff in which tokens will begin to vest
|
||||
* @param _duration duration in seconds of the period in which the tokens will vest
|
||||
* @param _revocable whether the vesting is revocable or not
|
||||
*/
|
||||
function initialize(
|
||||
address _sender,
|
||||
address _beneficiary,
|
||||
uint256 _start,
|
||||
uint256 _cliff,
|
||||
uint256 _duration,
|
||||
bool _revocable
|
||||
)
|
||||
public
|
||||
isInitializer("TokenVesting", "1.9.0")
|
||||
{
|
||||
Ownable.initialize(_sender);
|
||||
|
||||
require(_beneficiary != address(0));
|
||||
require(_cliff <= _duration);
|
||||
|
||||
beneficiary = _beneficiary;
|
||||
revocable = _revocable;
|
||||
duration = _duration;
|
||||
cliff = _start.add(_cliff);
|
||||
start = _start;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Transfers vested tokens to beneficiary.
|
||||
* @param token ERC20 token which is being vested
|
||||
*/
|
||||
function release(ERC20Basic token) public {
|
||||
uint256 unreleased = releasableAmount(token);
|
||||
|
||||
require(unreleased > 0);
|
||||
|
||||
released[token] = released[token].add(unreleased);
|
||||
|
||||
token.safeTransfer(beneficiary, unreleased);
|
||||
|
||||
emit Released(unreleased);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Allows the owner to revoke the vesting. Tokens already vested
|
||||
* remain in the contract, the rest are returned to the owner.
|
||||
* @param token ERC20 token which is being vested
|
||||
*/
|
||||
function revoke(ERC20Basic token) public onlyOwner {
|
||||
require(revocable);
|
||||
require(!revoked[token]);
|
||||
|
||||
uint256 balance = token.balanceOf(this);
|
||||
|
||||
uint256 unreleased = releasableAmount(token);
|
||||
uint256 refund = balance.sub(unreleased);
|
||||
|
||||
revoked[token] = true;
|
||||
|
||||
token.safeTransfer(owner, refund);
|
||||
|
||||
emit Revoked();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Calculates the amount that has already vested but hasn't been released yet.
|
||||
* @param token ERC20 token which is being vested
|
||||
*/
|
||||
function releasableAmount(ERC20Basic token) public view returns (uint256) {
|
||||
return vestedAmount(token).sub(released[token]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Calculates the amount that has already vested.
|
||||
* @param token ERC20 token which is being vested
|
||||
*/
|
||||
function vestedAmount(ERC20Basic token) public view returns (uint256) {
|
||||
uint256 currentBalance = token.balanceOf(this);
|
||||
uint256 totalBalance = currentBalance.add(released[token]);
|
||||
|
||||
if (block.timestamp < cliff) {
|
||||
return 0;
|
||||
} else if (block.timestamp >= start.add(duration) || revoked[token]) {
|
||||
return totalBalance;
|
||||
} else {
|
||||
return totalBalance.mul(block.timestamp.sub(start)).div(duration);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,14 +0,0 @@
|
||||
pragma solidity ^0.4.4;
|
||||
|
||||
|
||||
/*
|
||||
* ERC20Basic
|
||||
* Simpler version of ERC20 interface
|
||||
* see https://github.com/ethereum/EIPs/issues/20
|
||||
*/
|
||||
contract ERC20Basic {
|
||||
uint public totalSupply;
|
||||
function balanceOf(address who) constant returns (uint);
|
||||
function transfer(address to, uint value);
|
||||
event Transfer(address indexed from, address indexed to, uint value);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user