{"id":341187,"date":"2022-11-13T15:00:31","date_gmt":"2022-11-13T15:00:31","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=341187"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=341187","title":{"rendered":"<span>\u0414\u0435\u0440\u0435\u0432\u044c\u044f \u041c\u0435\u0440\u043a\u043b\u0430 \u0438 \u044d\u043a\u043e\u043d\u043e\u043c\u0438\u044f \u0433\u0430\u0437\u0430 \u0432 \u0441\u043c\u0430\u0440\u0442-\u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430\u0445 Solidity<\/span>"},"content":{"rendered":"<div><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<h2>\u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435<\/h2>\n<p>\u0412 \u0438\u0434\u0435\u0430\u043b\u044c\u043d\u043e\u043c \u0434\u0435\u0446\u0435\u043d\u0442\u0440\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u043e\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u043c\u044b \u0431\u044b \u0445\u043e\u0442\u0435\u043b\u0438 \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432\u0441\u0435 \u0432 \u0431\u043b\u043e\u043a\u0447\u0435\u0439\u043d\u0435 \u043d\u0430 \u0441\u043c\u0430\u0440\u0442-\u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430\u0445 \u2014 \u0432 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 Ethereum: \u0434\u0430\u043d\u043d\u044b\u0435 \u043d\u0435 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u044b \u043d\u0435\u0441\u0430\u043d\u043a\u0446\u0438\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u043c \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u043c. \u041d\u043e \u0437\u0430\u043f\u0438\u0441\u044c \u043a\u0430\u043a\u043e\u0439-\u043b\u0438\u0431\u043e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438, \u0440\u0430\u0437\u043c\u0435\u0440\u043e\u043c 32 \u0431\u0430\u0439\u0442\u0430 \u043e\u0431\u043e\u0439\u0434\u0435\u0442\u0441\u044f \u043d\u0430\u043c \u0432 20000 \u0433\u0430\u0437\u0430. \u041d\u0430 \u043c\u043e\u043c\u0435\u043d\u0442 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0441\u0442\u0430\u0442\u044c\u0438 \u044d\u0442\u043e \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e $0.26, c \u043e\u0434\u043d\u043e\u0439 \u0441\u0442\u043e\u0440\u043e\u043d\u044b \u043d\u0435 \u043c\u043d\u043e\u0433\u043e, \u043d\u043e \u0447\u0442\u043e \u0435\u0441\u043b\u0438 \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 \u043a\u0430\u043a\u043e\u0439-\u0442\u043e \u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043c\u0430\u0441\u0441\u0438\u0432 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438.  <\/p>\n<p>\u0412 \u043f\u043e\u0438\u0441\u043a\u0430\u0445 \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u043e\u0439 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u044d\u043a\u043e\u0441\u0438\u0441\u0442\u0435\u043c\u0430 Ethereum \u0434\u0430\u0435\u0442 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u043d\u044b\u0445 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432. \u041a\u0430\u043a \u043f\u0440\u0430\u0432\u0438\u043b\u043e, \u0432 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u043c \u043f\u0443\u0442\u0438 \u0435\u0441\u0442\u044c \u043a\u043e\u043c\u043f\u0440\u043e\u043c\u0438\u0441\u0441 \u043c\u0435\u0436\u0434\u0443 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e\u0441\u0442\u044c\u044e \u0438 \u0446\u0435\u043d\u043d\u043e\u0439. \u0412\u0430\u0440\u0438\u0430\u043d\u0442 \u043e\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0439 \u0432 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u043e\u0436\u0435\u0442 \u043e\u0431\u043e\u0439\u0442\u0438\u0441\u044c \u043a\u0440\u0430\u0439\u043d\u0435 \u0434\u0435\u0448\u0435\u0432\u043e \u0432 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438, \u043f\u0440\u0438 \u0434\u043e\u043b\u0436\u043d\u043e\u043c \u043f\u043e\u0434\u0445\u043e\u0434\u0435 \u0438 \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u0438 \u0442\u0435\u043c\u044b.  <\/p>\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u0432\u044b \u0443\u0437\u043d\u0430\u0435\u0442\u0435 \u043f\u0440\u043e \u0414\u0435\u0440\u0435\u0432\u044c\u044f \u041c\u0435\u0440\u043a\u043b\u0430 \u2014 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c \u0445\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445, \u0431\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f \u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443, \u043c\u044b \u0441\u043c\u043e\u0436\u0435\u043c \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432\u0441\u044e \u043f\u043e\u043b\u043d\u043e\u0442\u0443 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438, \u043d\u0435 \u043f\u0440\u0438\u0431\u0435\u0433\u0430\u044f \u043a \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u043e\u043c\u0443 \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u043d\u0438\u044e \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0433\u043e \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430 Ethereum.  <\/p>\n<h2>\u0422\u0435\u043e\u0440\u0438\u044f<\/h2>\n<p>\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0434\u0435\u0440\u0435\u0432\u0430 \u041c\u0435\u0440\u043a\u043b\u0430 \u044d\u0442\u043e \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 \u0445\u044d\u0448, \u043d\u0430\u0445\u043e\u0434\u044f\u0449\u0438\u0439\u0441\u044f \u0432 \u0441\u0430\u043c\u043e\u043c \u0432\u0435\u0440\u0445\u0443 \u043f\u0438\u0440\u0430\u043c\u0438\u0434\u044b \u0445\u044d\u0448\u0435\u0439. \u041d\u0430 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0438 \u043d\u0438\u0436\u0435 \u0445\u044d\u0448 H(AH) &#8212; \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0440\u0430\u0437\u0431\u0435\u0440\u0435\u043c\u0441\u044f \u043a\u0430\u043a \u043e\u043d \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0441\u044f.  <\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/6b3\/a39\/db2\/6b3a39db225d35ef6eab46b04b89c71b.png\" width=\"564\" height=\"329\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/6b3\/a39\/db2\/6b3a39db225d35ef6eab46b04b89c71b.png\"\/><figcaption><\/figcaption><\/figure>\n<p>\u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0438\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u043c\u044b \u0438\u043c\u0435\u0435\u043c 8 \u0445\u044d\u0448\u0435\u0439(A, B, C, D, E, F, G, H) \u043a\u0430\u043a\u0438\u0445-\u0442\u043e \u0434\u0430\u043d\u043d\u044b\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0438\u043a\u0430\u043a \u043d\u0435 \u043e\u0442\u043d\u043e\u0441\u044f\u0442\u0441\u044f \u0434\u0440\u0443\u0433 \u043a \u0434\u0440\u0443\u0433\u0443. \u0417\u0430\u0442\u0435\u043c \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043f\u043e\u043f\u0430\u0440\u043d\u043e\u0435 \u0445\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435(H(AB), H(CD), H(EF), H(GH)), \u0430 \u0438\u043c\u0435\u043d\u043d\u043e: \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043a\u043e\u043d\u043a\u0430\u0442\u0435\u043d\u0430\u0446\u0438\u0438 A \u0438 B \u043f\u043e\u043c\u0435\u0449\u0430\u0435\u0442\u0441\u044f \u0432 \u0445\u044d\u0448-\u0444\u0443\u043d\u043a\u0446\u0438\u044e keccak256, \u0442\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u0445\u044d\u0448 H(AB):  <\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"formula\" source=\"H(AB)=keccak256(A+B)\" alt=\"H(AB)=keccak256(A+B)\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/f01\/cb3\/436\/f01cb34361bf3081c21ea32d50f69ac0.svg\" width=\"240\" height=\"22\"\/><img loading=\"lazy\" decoding=\"async\" class=\"formula\" source=\"H(CD)=keccak256(C+D)\" alt=\"H(CD)=keccak256(C+D)\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/22f\/258\/e8a\/22f258e8a8abab7ce0efae4844ea08e9.svg\" width=\"243\" height=\"22\"\/><\/p>\n<p>\u041f\u043e\u0434\u043e\u0431\u043d\u044b\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u044e\u0442\u0441\u044f \u0442\u0430\u043a\u0436\u0435 H(EF) \u0438 H(GH), \u0435\u0441\u043b\u0438 \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u043d\u0435\u0447\u0435\u0442\u043d\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0445\u044d\u0448\u0435\u0439, \u0442\u043e \u043e\u0441\u0442\u0430\u0432\u0448\u0438\u0439\u0441\u044f \u043f\u0435\u0440\u0435\u0439\u0434\u0435\u0442 \u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0443\u0440\u043e\u0432\u0435\u043d\u044c \u043f\u043e\u043f\u0430\u0440\u043d\u043e\u0433\u043e \u0445\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0438 \u0442\u0430\u043c \u043d\u0430\u0439\u0434\u0435\u0442 \u0441\u0435\u0431\u0435 \u043f\u0430\u0440\u0443, \u0435\u0441\u043b\u0438 \u0438 \u0442\u0430\u043c \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u0430\u0440\u044b, \u0442\u043e \u043e\u043d \u043f\u0435\u0440\u0435\u0439\u0434\u0435\u0442 \u0441\u043d\u043e\u0432\u0430 \u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0443\u0440\u043e\u0432\u0435\u043d\u044c, \u0438 \u0442\u0430\u043a \u0434\u043e \u0442\u0435\u0445 \u043f\u043e\u0440 \u043f\u043e\u043a\u0430 \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u043d\u0430\u0439\u0434\u0435\u043d\u0430 \u043f\u0430\u0440\u0430.   <\/p>\n<p>\u041a\u0430\u043a \u0432\u044b \u0443\u0436\u0435 \u043c\u043e\u0433\u043b\u0438 \u0434\u043e\u0433\u0430\u0434\u0430\u0442\u044c\u0441\u044f H(AD) \u0431\u0443\u0434\u0435\u0442 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u043c \u043f\u043e\u043f\u0430\u0440\u043d\u043e\u0433\u043e \u0445\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f H(AB) \u0438 H(CD), \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u043e \u0442\u043e\u0447\u043d\u043e \u0442\u0430\u043a\u043e\u0439 \u0436\u0435 \u0444\u043e\u0440\u043c\u0443\u043b\u0435:  <\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"formula\" source=\"H(AD)=keccak256(H(AB)+H(CD))\" alt=\"H(AD)=keccak256(H(AB)+H(CD))\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/1fd\/972\/cc5\/1fd972cc5318c7217a8e73eec45cba6f.svg\" width=\"336\" height=\"22\"\/><\/p>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c: <\/p>\n<ol>\n<li>\n<p>\u0447\u0435\u043c \u0431\u043e\u043b\u044c\u0448\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u043d\u0430\u043c \u043d\u0430\u0434\u043e \u0445\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432 \u0434\u0435\u0440\u0435\u0432\u0435 \u041c\u0435\u0440\u043a\u043b\u0430, \u0442\u0435\u043c \u0431\u043e\u043b\u044c\u0448\u0435 \u0443\u0440\u043e\u0432\u043d\u0435\u0439 \u043f\u043e\u043f\u0430\u0440\u043d\u043e\u0433\u043e \u0445\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043d\u0430\u043c \u043f\u0440\u0438\u0434\u0435\u0442\u0441\u044f \u043f\u0440\u0435\u043e\u0434\u043e\u043b\u0435\u0442\u044c, \u0447\u0442\u043e\u0431\u044b \u0432 \u043a\u043e\u043d\u0447\u0435\u043d\u043e\u043c \u0438\u0442\u043e\u0433\u0435 \u043f\u0440\u0438\u0439\u0442\u0438 \u043a \u043e\u0434\u043d\u043e\u043c\u0443 \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u043c\u0443 \u0445\u044d\u0448\u0443;<\/p>\n<\/li>\n<li>\n<p>\u0435\u0441\u043b\u0438 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0445\u044d\u0448\u0435\u0439 \u0434\u043b\u044f \u043f\u043e\u043f\u0430\u0440\u043d\u043e\u0433\u043e \u0445\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043d\u0435\u0447\u0435\u0442\u043d\u043e\u0435, \u0442\u043e \u0445\u044d\u0448 \u043d\u0435 \u0438\u043c\u0435\u044e\u0449\u0438\u0439 \u043f\u0430\u0440\u044b \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u0442 \u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0443\u0440\u043e\u0432\u0435\u043d\u044c \u0438 \u043d\u0430\u0445\u043e\u0434\u0438\u0442 \u043f\u0430\u0440\u0443 \u0442\u0430\u043c, \u0435\u0441\u043b\u0438 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0445\u044d\u0448\u0435\u0439 \u043d\u0435\u0447\u0435\u0442\u043d\u043e\u0435 \u0438 \u0442\u0430\u043c, \u0442\u043e \u0445\u044d\u0448 \u0441\u043d\u043e\u0432\u0430 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u0442 \u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0443\u0440\u043e\u0432\u0435\u043d\u044c \u043f\u043e\u043f\u0430\u0440\u043d\u043e\u0433\u043e \u0445\u0435\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0432\u043f\u043b\u043e\u0442\u044c \u0434\u043e \u0443\u0440\u043e\u0432\u043d\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043f\u0435\u0440\u0435\u0434 \u043a\u043e\u0440\u043d\u0435\u0432\u044b\u043c.<\/p>\n<\/li>\n<\/ol>\n<p>\u041f\u0440\u0438\u043c\u0435\u0447\u0430\u043d\u0438\u0435: \u0437\u0434\u0435\u0441\u044c \u0438 \u0434\u0430\u043b\u0435\u0435 \u0434\u043b\u044f \u043f\u043e\u043f\u0430\u0440\u043d\u043e\u0433\u043e \u0445\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0442\u0441\u044f \u0445\u044d\u0448 \u0444\u0443\u043d\u043a\u0446\u0438\u044f keccak256, \u0432\u044b \u043f\u043e\u0439\u043c\u0435\u0442\u0435 \u0432 \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u043c \u043f\u043e\u0447\u0435\u043c\u0443, \u043d\u043e \u044d\u0442\u043e \u043d\u0435 \u0435\u0441\u0442\u044c \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u043a \u0438\u0441\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044e \u043f\u0440\u0430\u0432\u0438\u043b\u043e, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432\u0445\u043e\u0434\u043d\u044b\u0435 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u044b \u0434\u043b\u044f \u043f\u043e\u043f\u0430\u0440\u043d\u043e\u0433\u043e \u0445\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u043f\u0435\u0440\u0435\u0432\u0435\u0434\u0435\u043d\u044b \u0432 \u0434\u0432\u043e\u0438\u0447\u043d\u044b\u0439 \u043a\u043e\u0434, \u0430 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u043c \u043f\u043e\u043f\u0430\u0440\u043d\u043e\u0433\u043e \u0445\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0431\u0443\u0434\u0435\u0442 \u0441\u0442\u0440\u043e\u0433\u0430\u044f \u0434\u0438\u0437\u044a\u044e\u043d\u043a\u0446\u0438\u044f \u044d\u0442\u0438\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u0434\u0432\u043e\u0438\u0447\u043d\u043e\u043c \u0432\u0438\u0434\u0435 \u0438\u043b\u0438 \u0434\u0440\u0443\u0433\u0438\u043c\u0438 \u0441\u043b\u043e\u0432\u0430\u043c\u0438 \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u0430 \u0438\u0441\u043a\u043b\u044e\u0447\u0430\u044e\u0449\u0435\u0433\u043e \u0418\u041b\u0418(XOR) \u0434\u043b\u044f \u044d\u0442\u0438\u0445 \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<p>\u041c\u044b \u043f\u043e\u043d\u044f\u043b\u0438 \u043a\u0430\u043a \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 \u0445\u044d\u0448 \u0434\u0435\u0440\u0435\u0432\u0430, \u043d\u043e \u043a\u0430\u043a \u043d\u0430\u043c \u0443\u0431\u0435\u0434\u0438\u0442\u0441\u044f, \u0447\u0442\u043e \u0442\u0430 \u0438\u043b\u0438 \u0438\u043d\u0430\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043d\u0430 \u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435 \u043f\u0440\u0438\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0432 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0435 \u0434\u0435\u0440\u0435\u0432\u0430? \u041e\u0442\u0432\u0435\u0442\u043e\u043c \u043d\u0430 \u044d\u0442\u043e\u0442 \u0432\u043e\u043f\u0440\u043e\u0441 \u0431\u0443\u0434\u0435\u0442 \u043c\u0430\u0441\u0441\u0438\u0432 \u0441 \u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u0447\u043d\u044b\u043c\u0438 \u0445\u044d\u0448\u0430\u043c\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u043e\u043c\u043e\u0433\u0443\u0442 \u043d\u0430\u043c \u0443\u0431\u0435\u0434\u0438\u0442\u0441\u044f \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u0442\u0430 \u0438\u043b\u0438 \u0438\u043d\u0430\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u0440\u0438\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0432 \u0434\u0435\u0440\u0435\u0432\u0435. \u041a\u0430\u043a \u0432\u0441\u0435\u0433\u0434\u0430 \u043f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u043a \u043d\u0430\u0433\u043b\u044f\u0434\u043d\u043e\u043c\u0443 \u043f\u0440\u0438\u043c\u0435\u0440\u0443.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/9d2\/0d2\/e5b\/9d20d2e5ba7b31e9ba52aff2ec303238.png\" width=\"564\" height=\"329\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/9d2\/0d2\/e5b\/9d20d2e5ba7b31e9ba52aff2ec303238.png\"\/><figcaption><\/figcaption><\/figure>\n<p>\u041f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u0438\u043c \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u044e, \u0433\u0434\u0435 \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u0443\u0431\u0435\u0434\u0438\u0442\u044c\u0441\u044f \u0432 \u0442\u043e\u043c \u0447\u0442\u043e \u0445\u044d\u0448 C(\u0432\u044b\u0434\u0435\u043b\u0435\u043d \u0441\u0438\u043d\u0438\u043c) \u043f\u0440\u0438\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0432 \u0434\u0435\u0440\u0435\u0432\u0435. \u0412 \u0442\u0430\u043a\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0434\u043e\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u044c\u0441\u0442\u0432\u043e\u043c \u0431\u0443\u0434\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u043c\u0430\u0441\u0441\u0438\u0432 \u0434\u0430\u043d\u043d\u044b\u0445: \u0445\u044d\u0448 D, H(AB), H(EH) (\u0432\u044b\u0434\u0435\u043b\u0435\u043d\u044b \u0437\u0435\u043b\u0435\u043d\u044b\u043c). \u0411\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f \u0438\u043c \u043c\u044b \u0441\u043c\u043e\u0436\u0435\u043c \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 \u0445\u044d\u0448.  <\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"formula\" source=\"H(AH)=keccak256(keccak256(keccak256(C+D)+H(AB))+H(EH))\" alt=\"H(AH)=keccak256(keccak256(keccak256(C+D)+H(AB))+H(EH))\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/03f\/e81\/827\/03fe81827f20022269996bb3bd606598.svg\" width=\"616\" height=\"22\"\/><\/p>\n<p>\u0415\u0441\u043b\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0439 \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 \u0445\u044d\u0448 \u0441\u043e\u0432\u043f\u0430\u0434\u0430\u0435\u0442 \u0441 \u0442\u0435\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0430\u043c \u0438\u0437\u0432\u0435\u0441\u0442\u0435\u043d, \u0437\u043d\u0430\u0447\u0438\u0442 \u0445\u044d\u0448 C \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u0440\u0438\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0432 \u0434\u0435\u0440\u0435\u0432\u0435 \u041c\u0435\u0440\u043a\u043b\u0430.   <\/p>\n<p>\u041f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u0435\u0449\u0451 \u0431\u043e\u043b\u044c\u0448\u0435 \u0443\u0433\u043b\u0443\u0431\u0438\u0442\u044c\u0441\u044f \u0432 \u0442\u0435\u043e\u0440\u0438\u044e \u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044e-\u043f\u043e\u043b\u0438\u0444\u0438\u043b, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0442\u044c \u043c\u0430\u0441\u0441\u0438\u0432 \u0441 \u0445\u044d\u0448\u0430\u043c\u0438, \u0430 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 \u0445\u044d\u0448 \u0434\u0435\u0440\u0435\u0432\u0430 \u041c\u0435\u0440\u043a\u043b\u0430 \u0434\u043b\u044f \u044d\u0442\u0438\u0445 \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<p>\u0421\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u0431\u0443\u0434\u0435\u0442 \u0434\u0430\u043d\u0430 \u0432 \u043a\u043e\u043d\u0446\u0435 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u0430.<\/p>\n<pre><code class=\"typescript\">const addresses = [     '0x70997970C51812dc3A010C7d01b50e0d17dc79C8',     '0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC',     '0x90F79bf6EB2c4f870365E785982E1f101E93b906',     '0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65',     '0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc',     '0x976EA74026E726554dB657fA54763abd0C3a0aa9',     '0x14dC79964da2C08b23698B3D3cc7Ca32193d9955',     '0x23618e81E3f5cdF7f54C3d65f7FBc0aBf5B21E8f',     '0xa0Ee7A142d267C1f36714E4a8F75612F20a79720',     '0xBcd4042DE499D14e55001CcbB24a551F3b954096',     '0x71bE63f3384f5fb98995898A86B02Fb2426c5788',     '0xFABB0ac9d68B0B445fB7357272Ff202C5651694a',     '0x1CBd3b2770909D4e10f157cABC84C7264073C9Ec',     '0xdF3e18d64BC6A983f673Ab319CCaE4f1a57C7097' ]; \/\/ \u043c\u0430\u0441\u0441\u0438\u0432 \u0441 \u0430\u0434\u0440\u0435\u0441\u0430\u043c\u0438 \u0434\u043b\u044f \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043c\u044b \u0432\u044b\u0447\u0438\u0441\u043b\u0438\u043c \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 \u0445\u044d\u0448      \/\/ dataArray - \u043c\u0430\u0441\u0441\u0438\u0432 \u0441 \u0445\u044d\u0448\u0430\u043c\u0438, \u0442\u043e \u0435\u0441\u0442\u044c \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 \u0445\u044d\u0448 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043b\u0443\u0447\u0435\u043d \u0438\u0437 \u0445\u044d\u0448\u0435\u0439 \u0430\u0434\u0440\u0435\u0441\u043e\u0432 \/\/ \u0430 \u043d\u0435 \u0438\u0437 \u0430\u0434\u0440\u0435\u0441\u043e\u0432 \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e const dataArray = addresses.map(address => ethers.utils.keccak256(address));  \/\/ \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0445\u044d\u0448\u0430 \u043e\u0442 \u043f\u0430\u0440\u044b \u0434\u0432\u0443\u0445 \u0434\u0440\u0443\u0433\u0438\u0445 \u0445\u044d\u0448\u0435\u0439 function getPair(hashOne: string, hashTwo: string): string { \/\/ \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0438\u0440\u0443\u044e\u0449\u0438\u0439 \u0445\u044d\u0448 \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u043f\u043e\u0440\u044f\u0434\u043a\u0430 \u043a\u043e\u043d\u0442\u0430\u043a\u0442\u0435\u043d\u0430\u0446\u0438\u0438 \/\/ \u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043f\u0435\u0440\u0432\u044b\u043c \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u043c \u0432\u0441\u0435\u0433\u0434\u0430 \u0431\u0443\u0434\u0435\u0442 \u0438\u0434\u0442\u0438 \u043c\u0435\u043d\u044c\u0448\u0438\u0439 \u0445\u044d\u0448     if (BigInt(hashOne) &lt; BigInt(hashTwo)) { \/\/ \u043f\u0430\u0440\u043d\u043e\u0435 \u0445\u0435\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 ethers         return ethers.utils.solidityKeccak256([ 'bytes32', 'bytes32' ], [ hashOne, hashTwo ]);     } else {         return ethers.utils.solidityKeccak256([ 'bytes32', 'bytes32' ], [ hashTwo, hashOne ]);     } }  \/\/ \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0433\u043e \u0445\u044d\u0448\u0430, \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u043c\u0430\u0441\u0441\u0438\u0432 \u0445\u044d\u0448\u0435\u0439, \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 function getRoot(data: string[]): string { \/\/ \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0447\u0435\u0442\u043d\u043e\u0435 \u043b\u0438 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u0432 \u043c\u0430\u0441\u0441\u0438\u0432\u0435     const parity: boolean = !(data.length % 2);   \/\/ \u0437\u0430\u0442\u0435\u043c \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u043d\u0443\u0436\u043d\u0443\u044e \u043d\u0430\u043c \u0434\u043b\u0438\u043d\u0443 \u0434\u043b\u044f \u0446\u0438\u043a\u043b\u0430 for \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0447\u0435\u0442\u043d\u043e\u0441\u0442\u0438 \/\/ \u0435\u0441\u043b\u0438 \u043a\u043e\u043b\u0438\u0447\u0435\u0442\u0432\u043e \u0447\u0435\u0442\u043d\u043e\u0435, \u0437\u043d\u0430\u0447\u0438\u0442 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u0438\u0441\u0445\u043e\u0434\u043d\u0443\u044e \u0434\u043b\u0438\u043d\u0443 \/\/ \u0438\u043d\u0430\u0447\u0435 \u0434\u043b\u0438\u043d\u0430 \u0431\u0443\u0434\u0435\u0442 \u0443\u043c\u0435\u043d\u044c\u0448\u0435\u043d\u0430 \u043d\u0430 1, \u0442\u0430\u043a \u043a\u0430\u043a \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u043d\u0435\u0447\u0435\u0442\u043d\u043e\u0441\u0442\u0438 \/\/ \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u0445\u044d\u0448 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u0442 \u0441\u0435\u0431\u0435 \u043f\u0430\u0440\u044b     let length = parity ? data.length : data.length - 1;     let result = [];     for (var i = 0; i &lt; length - 1; i += 2) { \/\/ \u0437\u0430\u043f\u043e\u043b\u043d\u044f\u0435\u043c \u043c\u0430\u0441\u0441\u0438\u0432 \u043f\u0430\u0440\u043d\u044b\u043c\u0438 \u0445\u0435\u0448\u0430\u043c\u0438         result.push(getPair(data[i], data[i + 1]));     }        if (!parity) { \/\/ \u0435\u0441\u043b\u0438 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043d\u0435\u0447\u0435\u0442\u043d\u043e\u0435, \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0432 \u043a\u043e\u043d\u0435\u0446 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0438\u0440\u0443\u044e\u0449\u0435\u0433\u043e \u043c\u0430\u0441\u0441\u0438\u0432\u0430  \/\/ \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442, \u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443 \u043d\u0435 \u043d\u0430\u0448\u043b\u043e\u0441\u044c \u043f\u0430\u0440\u044b \u0434\u043b\u044f \u043f\u0430\u0440\u043d\u043e\u0433\u043e \u0445\u0435\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f         result.push(data[data.length - 1]);     } \/\/ \u0435\u0441\u043b\u0438 \u0432 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0438\u0440\u0443\u044e\u0449\u0435\u043c \u043c\u0430\u0441\u0441\u0438\u0432\u0435 \u043e\u0434\u0438\u043d \u044d\u043b\u0435\u043c\u0435\u043d\u0442, \u0442\u043e \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u0435\u0433\u043e,  \/\/ \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u044d\u0442\u043e \u0438 \u0435\u0441\u0442\u044c \u0438\u0441\u043a\u043e\u043c\u044b\u0439 \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 \u0445\u044d\u0448 \/\/ \u0438\u043d\u0430\u0447\u0435 \u0441\u043d\u043e\u0432\u0430 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c getRoot \/\/ \u0442\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044f getRoot \u0431\u0443\u0434\u0435\u0442 \u0440\u0435\u043a\u0443\u0440\u0441\u0438\u0432\u043d\u043e\u0439      return result.length == 1 ? result[0] : getRoot(result);  }  const root = getRoot(dataArray); console.log('root', root);<\/code><\/pre>\n<p> \u0417\u0430\u043f\u0443\u0441\u0442\u0438\u043c \u0441\u043a\u0440\u0438\u043f\u0442 \u0438 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043d\u0430 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442.  <\/p>\n<pre><code class=\"powershell\">npx hardhat run scripts\/example-merkle.ts<\/code><\/pre>\n<p> \u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0438\u0437 \u043b\u043e\u0433\u043e\u0432: \u20180x2e3bc03e1c67b59152c362a773c515a01d9dfdde6aaaa6796ad3bb1ec3b65300\u2019.<\/p>\n<h2>\u041f\u0440\u0430\u043a\u0442\u0438\u043a\u0430<\/h2>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442 \u0431\u0435\u0437 \u0432\u0441\u044f\u043a\u0438\u0445 \u0434\u0435\u0440\u0435\u0432\u044c\u0435\u0432, \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u0442\u0441\u044f \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u043e\u043d \u043f\u0440\u043e\u0441\u0442\u043e \u0440\u0430\u0437\u0434\u0430\u0435\u0442 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0439 \u0442\u043e\u043a\u0435\u043d \u0442\u0435\u043c, \u043a\u0442\u043e \u043d\u0430 \u043d\u0435\u0433\u043e \u043f\u0440\u0435\u0442\u0435\u043d\u0434\u0443\u0435\u0442, \u0438\u043b\u0438 \u0438\u043d\u044b\u043c\u0438 \u0441\u043b\u043e\u0432\u0430\u043c\u0438 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u0442\u0430\u043a \u043d\u0430\u0437\u044b\u0432\u0430\u0435\u043c\u043e\u043c \u0432\u0430\u0439\u0442\u043b\u0438\u0441\u0442\u0435.<\/p>\n<pre><code>\/\/ SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.9;  import \"@openzeppelin\/contracts\/token\/ERC20\/utils\/SafeERC20.sol\"; import \"@openzeppelin\/contracts\/token\/ERC20\/extensions\/IERC20Metadata.sol\";   contract AirdropV1 {     using SafeERC20 for IERC20Metadata;      address owner; \/\/ \u0442\u043e\u043b\u044c\u043a\u043e \u044d\u0442\u043e\u0442 \u0430\u0434\u0440\u0435\u0441 \u0438\u043c\u0435\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0444\u0443\u043d\u043a\u0446\u0438\u0438 addToWhitelist     address dropToken; \/\/ \u0430\u0434\u0440\u0435\u0441 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430 \u0442\u043e\u043a\u0435\u043d\u0430 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u0430 ERC20     uint256 dropAmount; \/\/ \u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u0430\u044f \u0441\u0443\u043c\u043c\u0430, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043f\u043e\u043b\u0443\u0447\u0438\u0442 \u043a\u0430\u0436\u0434\u044b\u0439, \u043a\u0442\u043e \u0435\u0441\u0442\u044c \u0432 \u0432\u0430\u0439\u0442\u043b\u0438\u0441\u0442\u0435     mapping(address => bool) public whitelist; \/\/ mapping \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 true \u0435\u0441\u043b\u0438 \u0430\u0434\u0440\u0435\u0441 \u0435\u0441\u0442\u044c \u0432 \u0432\u0430\u0439\u0442\u043b\u0438\u0441\u0442\u0435          constructor(address _dropToken, uint256 _dropAmount) { \/\/ \u043f\u0440\u0438 \u0434\u0435\u043f\u043b\u043e\u0435 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430 \u0432 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442\u0441\u044f \u0430\u0434\u0440\u0435\u0441 \u0440\u0430\u0437\u0434\u0430\u0432\u0430\u0435\u043c\u043e\u0433\u043e \u0442\u043e\u043a\u0435\u043d\u0430 \/\/ \u0438 \u0441\u0443\u043c\u043c\u0430 \u0435\u0434\u0438\u043d\u0438\u0447\u043d\u043e\u0433\u043e \u043a\u043b\u0435\u0439\u043c\u0430          owner = msg.sender;         dropToken = _dropToken;         dropAmount = _dropAmount;     }    \/\/ \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0432 \u0432\u0430\u0439\u0442\u043b\u0438\u0441\u0442 \u043d\u043e\u0432\u044b\u0445 \u0443\u0447\u0430\u0441\u0442\u043d\u0438\u043a\u043e\u0432 \u0430\u0438\u0440\u0434\u0440\u043e\u043f\u0430 \/\/ \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0430 \u043e\u043d\u0430 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u043c\u0430\u0441\u0441\u0438\u0432 \u0441 \u0430\u0434\u0440\u0435\u0441\u0430\u043c\u0438 \u0443\u0447\u0430\u0441\u0442\u043d\u0438\u043a\u043e\u0432     function addToWhitelist(address[] calldata _users) public {         require(owner == msg.sender, \"Only owner!\");         for(uint i = 0; i &lt; _users.length; i++) {             whitelist[_users[i]] = true;         }     }  \/\/ \u044d\u0442\u0443 \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 \u0443\u0447\u0430\u0441\u0442\u043d\u0438\u043a, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u0432\u0430\u0439\u0442\u043b\u0438\u0441\u0442\u0435 \/\/ \u043f\u043e\u0441\u043b\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0433\u043e \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0438 \u043d\u0430 \u0435\u0433\u043e \u0430\u0434\u0440\u0435\u0441\u0435 \u043e\u043a\u0430\u0436\u0435\u0442\u0441\u044f \u0441\u0443\u043c\u043c\u0430 dropAmount \u0442\u043e\u043a\u0435\u043d\u0430 dropToken     function claim() public {         require(whitelist[msg.sender], \"You are not whitelisted.\");         IERC20Metadata(dropToken).safeTransfer(             msg.sender,             dropAmount         );         whitelist[msg.sender] = false;     } }<\/code><\/pre>\n<p>\u041d\u0430\u043f\u0438\u0448\u0435\u043c \u0434\u043b\u044f \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d \u043f\u043e\u043b\u043d\u044b\u0439 \u0446\u0438\u043a\u043b \u0440\u0430\u0431\u043e\u0442\u044b \u0432\u0441\u0435\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0441\u044f \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u043c \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u043c hardhat gas-reporter, \u0447\u0442\u043e\u0431\u044b \u0432\u044b\u044f\u0441\u043d\u0438\u0442\u044c \u043a\u0430\u043a\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0433\u0430\u0437\u0430 \u0431\u044b\u043b\u043e \u043f\u043e\u0442\u0440\u0430\u0447\u0435\u043d\u043e \u043d\u0430 \u0432\u044b\u0437\u043e\u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u201caddToWhitelist\u201d.<\/p>\n<pre><code class=\"typescript\">import { expect } from \"chai\"; import { ethers } from \"hardhat\"; import { SignerWithAddress } from \"@nomiclabs\/hardhat-ethers\/signers\"; import { BigNumber } from \"ethers\"; import * as mocha from \"mocha-steps\"; import { parseEther } from '@ethersproject\/units'; import { AirdropV1, Token20 } from '..\/typechain-types';  describe(\"AirdropV1.sol testing\", async () => {     let airdrop: AirdropV1;     let dropToken: Token20;     let admin: SignerWithAddress, user1: SignerWithAddress, user2: SignerWithAddress, user3: SignerWithAddress, user4: SignerWithAddress,          user5: SignerWithAddress, user6: SignerWithAddress, user7: SignerWithAddress, user8: SignerWithAddress, user9: SignerWithAddress,         user10: SignerWithAddress, user11: SignerWithAddress, user12: SignerWithAddress, user13: SignerWithAddress, user14: SignerWithAddress,         unwhitelisted: SignerWithAddress;          let dropAmount: BigNumber;      beforeEach(async () => {         [admin, user1, user2, user3, user4,           user5, user6, user7, user8, user9,           user10, user11, user12, user13,           user14, unwhitelisted] = await ethers.getSigners();     });      mocha.step(\"\u0414\u0435\u043f\u043b\u043e\u0439 \u0442\u043e\u043a\u0435\u043d\u0430 ERC20, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0440\u0430\u0437\u0434\u0430\u0432\u0430\u0442\u044c\", async function() {         const dropTokenFactory = await ethers.getContractFactory(\"Token20\");         dropToken = await dropTokenFactory.connect(admin).deploy(             'Drop Token',             'DTN',             parseEther('100000')         )     });      mocha.step(\"\u0414\u0435\u043f\u043b\u043e\u0439 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430 \u0430\u0438\u0440\u0434\u0440\u043e\u043f\u0430\", async function() {         const airdropFactory = await ethers.getContractFactory(\"AirdropV1\");         dropAmount = parseEther('1000');         airdrop = await airdropFactory.deploy(dropToken.address, dropAmount);     });      mocha.step(\"\u0422\u0440\u0430\u043d\u0441\u0444\u0435\u0440 \u0440\u0430\u0437\u0434\u0430\u0432\u0430\u0435\u043c\u043e\u0433\u043e \u0442\u043e\u043a\u0435\u043d\u0430 \u043d\u0430 \u0430\u0434\u0440\u0435\u0441 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430 \u0430\u0438\u0440\u0434\u0440\u043e\u043f\u0430\", async function() {         await dropToken.connect(admin).transfer(airdrop.address, parseEther('100000'));     });      mocha.step(\"\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0432 \u0432\u0430\u0439\u0442\u043b\u0438\u0441\u0442\", async function() {         const whitelist = [             user1.address, user2.address, user3.address,              user4.address, user5.address, user6.address,              user7.address, user8.address, user9.address,             user10.address, user11.address, user12.address,             user13.address, user14.address,         ];         await airdrop.connect(admin).addToWhitelist(whitelist);     });      mocha.step(\"\u0412\u044b\u0437\u043e\u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 claim, \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u043c\u0438 \u0438\u0437 \u0432\u0430\u0439\u0442\u043b\u0438\u0441\u0442\u0430\", async function() {         await airdrop.connect(user1).claim();         await airdrop.connect(user2).claim();         await airdrop.connect(user3).claim(); \/\/ \u0432 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u043c \u043a\u043e\u0434\u0435 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f \u043a\u043b\u0435\u0439\u043c \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0441\u044f \u0434\u043b\u044f 14 \u0430\u0434\u0440\u0435\u0441\u043e\u0432 \u0438\u0437 \u0432\u0430\u0439\u0442\u043b\u0438\u0441\u0442\u0430 \/\/ \u0437\u0434\u0435\u0441\u044c \u0441\u043e\u043a\u0440\u0430\u0449\u0435\u043d\u043d\u043e \u0434\u043b\u044f \u044d\u043a\u043e\u043d\u043e\u043c\u0438\u0438 \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u0430          await airdrop.connect(user14).claim();     });      mocha.step(\"\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0431\u0430\u043b\u0430\u043d\u0441\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u043f\u043e\u0441\u043b\u0435 claim\", async function() {         expect(await dropToken.balanceOf(user1.address)).to.be.equal(dropAmount);                       expect(await dropToken.balanceOf(user2.address)).to.be.equal(dropAmount);                       expect(await dropToken.balanceOf(user3.address)).to.be.equal(dropAmount);    \/\/ \u0432 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u043c \u043a\u043e\u0434\u0435 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0431\u0430\u043b\u0430\u043d\u0441\u0430 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0441\u044f \u0434\u043b\u044f 14 \u0430\u0434\u0440\u0435\u0441\u043e\u0432 \u0438\u0437 \u0432\u0430\u0439\u0442\u043b\u0438\u0441\u0442\u0430 \/\/ \u0437\u0434\u0435\u0441\u044c \u0441\u043e\u043a\u0440\u0430\u0449\u0435\u043d\u043d\u043e \u0434\u043b\u044f \u044d\u043a\u043e\u043d\u043e\u043c\u0438\u0438 \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u0430          expect(await dropToken.balanceOf(user14.address)).to.be.equal(dropAmount);                });      mocha.step(\"\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0437\u0430\u0449\u0438\u0442\u044b \u043e\u0442 \u043d\u0435\u0441\u0430\u043d\u043a\u0446\u0438\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u043a\u043b\u0435\u0439\u043c\u0430\", async function() {         await expect(airdrop.connect(unwhitelisted).claim()).to.be.revertedWith('You are not whitelisted.');     }); });<\/code><\/pre>\n<p> \u0417\u0430\u0444\u0438\u043a\u0441\u0438\u0440\u0443\u0435\u043c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043f\u043e\u0442\u0440\u0430\u0447\u0435\u043d\u043d\u043e\u0433\u043e \u0433\u0430\u0437\u0430 \u043d\u0430 \u0432\u044b\u0437\u043e\u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u201caddToWhitelist\u201d.  <\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/c54\/dbe\/192\/c54dbe19265e1bf8ec2859f058c96d94.png\" width=\"1172\" height=\"457\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/c54\/dbe\/192\/c54dbe19265e1bf8ec2859f058c96d94.png\"\/><figcaption><\/figcaption><\/figure>\n<p>\u0421\u0440\u0435\u0434\u043d\u044f\u044f \u0446\u0435\u043d\u0430 \u0433\u0430\u0437\u0430 \u043d\u0430 \u043c\u043e\u043c\u0435\u043d\u0442 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f 16 gwei, \u043d\u0430 \u0432\u044b\u0437\u043e\u0432 \u201caddToWhitelist\u201d \u0431\u044b\u043b\u043e \u043f\u043e\u0442\u0440\u0430\u0447\u0435\u043d\u043e 348171 \u0433\u0430\u0437\u0430 \u0438\u043b\u0438 8.83 usd \u0432 \u0434\u043e\u043b\u043b\u0430\u0440\u043e\u0432\u043e\u043c \u044d\u043a\u0432\u0438\u0432\u0430\u043b\u0435\u043d\u0442\u0435. \u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u044c\u0442\u0435 \u043a\u0430\u043a\u043e\u0435 \u0431\u044b \u0437\u0434\u0435\u0441\u044c \u0431\u044b\u043b\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435, \u0435\u0441\u043b\u0438 \u0431\u044b \u043c\u044b \u0443\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u043b\u0438 \u0430\u0438\u0440\u0434\u0440\u043e\u043f \u0434\u043b\u044f 100, 1000 \u0430\u0434\u0440\u0435\u0441\u043e\u0432 \u0438 \u0442. \u0434.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u043d\u043e\u0432\u0443\u044e \u0432\u0435\u0440\u0441\u0438\u044e \u0430\u0438\u0440\u0434\u0440\u043e\u043f\u0430, \u0433\u0434\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043d\u0430 \u043d\u0430\u043b\u0438\u0447\u0438\u0435 \u0432 \u0432\u0430\u0439\u0442\u043b\u0438\u0441\u0442\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442\u044c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0434\u0435\u0440\u0435\u0432\u0430 \u041c\u0435\u0440\u043a\u043b\u0430.  <\/p>\n<pre><code>\/\/ SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.9;  import \"@openzeppelin\/contracts\/token\/ERC20\/utils\/SafeERC20.sol\"; import \"@openzeppelin\/contracts\/token\/ERC20\/extensions\/IERC20Metadata.sol\";  \/\/ \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u043c \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u0443\u044e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043d\u0430\u043b\u0438\u0447\u0438\u044f \u0442\u043e\u0433\u043e \u0438\u043b\u0438 \u0438\u043d\u043e\u0433\u043e \u0430\u0434\u0440\u0435\u0441\u0430 \u0432 \u0434\u0435\u0440\u0435\u0432\u0435 import \"@openzeppelin\/contracts\/utils\/cryptography\/MerkleProof.sol\";  contract AirdropV2 {     using SafeERC20 for IERC20Metadata;      address owner; \/\/ \u0442\u043e\u043b\u044c\u043a\u043e \u044d\u0442\u043e\u0442 \u0430\u0434\u0440\u0435\u0441 \u0438\u043c\u0435\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0444\u0443\u043d\u043a\u0446\u0438\u0438 addToWhitelist     address dropToken; \/\/ \u0430\u0434\u0440\u0435\u0441 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430 \u0442\u043e\u043a\u0435\u043d\u0430 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u0430 ERC20     uint256 dropAmount; \/\/ \u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u0430\u044f \u0441\u0443\u043c\u043c\u0430, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043f\u043e\u043b\u0443\u0447\u0438\u0442 \u043a\u0430\u0436\u0434\u044b\u0439, \u043a\u0442\u043e \u0435\u0441\u0442\u044c \u0432 \u0432\u0430\u0439\u0442\u043b\u0438\u0441\u0442\u0435     bytes32 public root; \/\/ \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 \u0445\u044d\u0448 \u0434\u0435\u0440\u0435\u0432\u0430, \u043f\u043e \u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442\u044c \u0441\u0432\u0435\u0440\u043a\u0430 \u043d\u0430 \u043d\u0430\u043b\u0438\u0447\u0438\u0435 \u0430\u0434\u0440\u0435\u0441\u0430 \u0432 \u0432\u0430\u0439\u0442\u043b\u0438\u0441\u0442\u0435     mapping(address => bool) public usersClaimed; \/\/ \u0432 \u044d\u0442\u043e\u0442 \u043c\u0430\u043f\u0438\u043d\u0433 \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u0430\u0434\u0440\u0435\u0441\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0443\u0436\u0435 \u043f\u0440\u043e\u0438\u0437\u0432\u0435\u043b\u0438 \u043a\u043b\u0435\u0439\u043c, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u0435\u0434\u043e\u0442\u0432\u0440\u0430\u0442\u0438\u0442\u044c \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u044b\u0439 \u043a\u043b\u0435\u0439\u043c          constructor(address _dropToken, uint256 _dropAmount) { \/\/ \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 \u0442\u0430\u043a\u043e\u0439 \u0436\u0435 \u043a\u0430\u043a \u0438 \u0443 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430 AirdropV1         owner = msg.sender;         dropToken = _dropToken;         dropAmount = _dropAmount;     }       function setRoot(bytes32 _root) public { \/\/ \u0431\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f \u044d\u0442\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043c\u043e\u0436\u043d\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 \u0445\u044d\u0448         require(owner == msg.sender, \"Only owner!\");         root = _root;     }  \/\/ \u0432 \u043e\u0442\u043b\u0438\u0447\u0438\u0438 \u043e\u0442 \u043f\u0435\u0440\u0432\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u0437\u0434\u0435\u0441\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u043a\u043b\u0435\u0439\u043c \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u043c\u0430\u0441\u0441\u0438\u0432 \u0441 \u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u0447\u043d\u044b\u043c\u0438 \u0445\u0435\u0448\u0430\u043c\u0438 \u0434\u0435\u0440\u0435\u0432\u0430, \/\/ \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0442 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 MerkleProof \u0443\u0431\u0435\u0434\u0438\u0442\u044c\u0441\u044f \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e msg.sender \u043f\u0440\u0438\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0432 \u0434\u0435\u0440\u0435\u0432\u0435     function claim(bytes32[] calldata _proof) public { \/\/ \u0443\u0431\u0435\u0436\u0434\u0430\u0435\u043c\u0441\u044f \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u044e\u0437\u0435\u0440 \u0435\u0449\u0451 \u043d\u0435 \u0441\u043a\u043b\u0435\u0439\u043c\u0438\u043b \u0434\u043e\u043b\u044e \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043e\u043d \u043f\u0440\u0435\u0442\u0435\u043d\u0434\u0443\u0435\u0442         require(!usersClaimed[msg.sender], \"Already claimed\"); \/\/ \u0438\u0437 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 MerkleProof \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e verify, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0435\u0441\u0442\u044c \u043b\u0438 msg.sender \u0432 \u0432\u0430\u0439\u0442\u043b\u0438\u0441\u0442\u0435 \/\/ \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c\u0441\u044f \u043d\u0430 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0430\u0445: \/\/ _proof - \u043c\u0430\u0441\u0441\u0438\u0432 \u0445\u044d\u0448\u0435\u0439 \u0438\u0437 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0431\u0443\u0434\u0435\u0442 \u0432\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 \/\/ root - \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 \u0445\u044d\u0448, \u0435\u0441\u043b\u0438 \u0432\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u044b\u0439 \u0438\u0437 _proof \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 \u0445\u044d\u0448 \u0440\u0430\u0432\u0435\u043d root, \u0442\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u044f verify \u0432\u0435\u0440\u043d\u0435\u0442 true \/\/ keccak256(abi.encodePacked(msg.sender)) - \u0445\u044d\u0448, \u043d\u0430\u043b\u0438\u0447\u0438\u0435 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0432 \u0434\u0435\u0440\u0435\u0432\u0435 \/\/ \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 verify \u043c\u044b \u043f\u0440\u043e\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u0447\u0435\u0440\u0435\u0437 \u0444-\u0446\u0438\u044e keccak256, \u0442\u0430\u043a \u043a\u0430\u043a \u0434\u0435\u0440\u0435\u0432\u043e \u0431\u044b\u043b\u043e \u0441\u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u043e \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0445\u0435\u0448\u0435\u0439 \u0430 \u043d\u0435 \u0430\u0434\u0440\u0435\u0441\u043e\u0432         require(MerkleProof.verify(_proof, root, keccak256(abi.encodePacked(msg.sender))), \"You are not whitelisted.\"); \/\/ \u043f\u043e\u0441\u043b\u0435 \u043f\u0440\u043e\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0438\u043c \u044e\u0437\u0435\u0440\u0443 \u043c\u043e\u043d\u0435\u0442\u044b \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043e\u043d \u043f\u0440\u0435\u0442\u0435\u043d\u0434\u0443\u0435\u0442         IERC20Metadata(dropToken).safeTransfer(             msg.sender,             dropAmount         ); \/\/ \u0434\u0435\u043b\u0430\u0435\u043c \u043e\u0442\u043c\u0435\u0442\u043a\u0443 \u043e \u0442\u043e\u043c, \u0447\u0442\u043e \u044e\u0437\u0435\u0440 \u0441\u043a\u043b\u0435\u0439\u043c\u0438\u043b \u043c\u043e\u043d\u0435\u0442\u044b, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u0435\u0434\u043e\u0442\u0432\u0440\u0430\u0442\u0438\u0442\u044c \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u044b\u0439 \u043a\u043b\u0435\u0439\u043c         usersClaimed[msg.sender] = true;     } }<\/code><\/pre>\n<p>\u041d\u0430 \u044d\u0442\u043e\u043c \u043c\u0435\u0441\u0442\u0435 \u0441\u0447\u0438\u0442\u0430\u044e \u043d\u0443\u0436\u043d\u044b\u043c \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c\u0441\u044f \u043d\u0430 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 MerkleProof \u0438 \u043d\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 verify \u0432 \u0447\u0430\u0441\u0442\u043d\u043e\u0441\u0442\u0438. \u041f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u0434 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043d\u0430 <a href=\"https:\/\/github.com\/OpenZeppelin\/openzeppelin-contracts\/blob\/master\/contracts\/utils\/cryptography\/MerkleProof.sol\" rel=\"noopener noreferrer nofollow\">github OpenZeppelin<\/a>.  <\/p>\n<p>\u041c\u044b \u0436\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0431\u0440\u0430\u0442\u0438\u043c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u044e verify \u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438, \u043a \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u043e\u0431\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f verify.  <\/p>\n<p>\u0414\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u0440 \u0438 \u0431\u043e\u043b\u0435\u0435 \u0434\u0435\u0442\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u044f \u043e\u0431\u0440\u0430\u0442\u0438\u043c\u0441\u044f \u043a \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0435 \u0438\u0437 \u0440\u0430\u0437\u0434\u0435\u043b\u0430 \u0442\u0435\u043e\u0440\u0438\u0438. <\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/9d2\/0d2\/e5b\/9d20d2e5ba7b31e9ba52aff2ec303238.png\" width=\"auto\" height=\"auto\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/9d2\/0d2\/e5b\/9d20d2e5ba7b31e9ba52aff2ec303238.png\"\/><figcaption><\/figcaption><\/figure>\n<p> \u0421\u0438\u0442\u0443\u0446\u0438\u044f: \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c, \u0437\u0430\u0448\u0438\u0432\u0440\u043e\u0432\u0430\u043d \u043b\u0438 \u0445\u044d\u0448 C \u0432 \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u043c \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u043c \u0445\u044d\u0448\u0435 H(AH), \u0442\u043e\u0433\u0434\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u044f verify \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0438\u043d\u043c\u0430\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u044b:  <\/p>\n<ul>\n<li>\n<p> proof &#8212; \u043c\u0430\u0441\u0441\u0438\u0432 [ D, H(AB), H(EH) ]  <\/p>\n<\/li>\n<li>\n<p> root &#8212; H(AH), \u0442\u043e \u0435\u0441\u0442\u044c \u0441\u0430\u043c \u043a\u043e\u0440\u0435\u0432\u043e\u0439 \u0445\u044d\u0448, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043c\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u043d\u0430\u043b\u0438\u0447\u0438\u0435 \u0445\u044d\u0448\u0430 C  <\/p>\n<\/li>\n<li>\n<p> leaf &#8212; \u0445\u044d\u0448 C, \u043d\u0430\u043b\u0438\u0447\u0438\u0435 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043c\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c.  <\/p>\n<\/li>\n<\/ul>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u044f verify \u0432\u043d\u0443\u0442\u0440\u0438 \u0441\u0435\u0431\u044f \u043e\u0431\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u043a processProof, \u0435\u0441\u043b\u0438 \u043e\u043d\u0430 \u0432\u0435\u0440\u043d\u0435\u0442 \u0445\u044d\u0448, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0440\u0430\u0432\u0435\u043d \u0446\u0435\u043b\u0435\u0432\u043e\u043c\u0443 \u0445\u044d\u0448\u0443 \u0437\u043d\u0430\u0447\u0438\u0442 \u0432\u0435\u0440\u0438\u0444\u0438\u043a\u0446\u0438\u044f \u043f\u0440\u043e\u0448\u043b\u0430 \u0443\u0441\u043f\u0435\u0448\u043d\u043e, \u0438 \u0445\u044d\u0448 leaf \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0437\u0430\u0445\u0435\u0448\u0438\u0440\u043e\u0432\u0430\u043d \u0432 root.<\/p>\n<pre><code>function verify(     bytes32[] memory proof,     bytes32 root,     bytes32 leaf ) internal pure returns (bool) {     return processProof(proof, leaf) == root; }<\/code><\/pre>\n<p>\u0412\u043d\u0443\u0442\u0440\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 processProof \u0432\u043e\u0441c\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442\u0441\u044f root, \u0440\u0430\u0437\u0431\u0435\u0440\u0435\u043c \u0440\u0430\u0431\u043e\u0442\u0443 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0438\u0442\u0435\u0440\u0430\u0446\u0438\u044f \u0437\u0430 \u0438\u0442\u0435\u0440\u0430\u0446\u0438\u0435\u0439 \u0446\u0438\u043a\u043b\u0430 for:  <\/p>\n<ul>\n<li>\n<p> 1-\u044f \u0438\u0442\u0435\u0440\u0430\u0446\u0438\u044f: _hashPair(C, D) -> H(CD);  <\/p>\n<\/li>\n<li>\n<p> 2-\u044f \u0438\u0442\u0435\u0440\u0430\u0446\u0438\u044f: _hashPair(H(CD), H(AB)) -> H(AD);  <\/p>\n<\/li>\n<li>\n<p> 3-\u044f \u0438\u0442\u0435\u0440\u0430\u0446\u0438\u044f: _hashPair(H(AD), H(EH)) -> H(AH);  <\/p>\n<\/li>\n<\/ul>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u0432\u043ec\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 \u0445\u044d\u0448 \u0434\u0435\u0440\u0435\u0432\u0430 \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u044e verify \u0434\u043b\u044f \u0441\u0432\u0435\u0440\u043a\u0438.  <\/p>\n<pre><code>function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {     bytes32 computedHash = leaf;     for (uint256 i = 0; i &lt; proof.length; i++) {         computedHash = _hashPair(computedHash, proof[i]);     }     return computedHash; }<\/code><\/pre>\n<p>\u041f\u0435\u0440\u0435\u0434 \u043f\u0430\u0440\u043d\u044b\u043c \u0445\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0430, \u0445\u044d\u0448 \u043c\u0435\u043d\u044c\u0448\u0435\u0433\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0438\u0434\u0435\u0442 \u043f\u0435\u0440\u0432\u044b\u043c, \u044d\u0442\u043e \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0430 \u043f\u0430\u0440, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u044b\u043b\u0430 \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u0430 \u0432 js \u043f\u043e\u043b\u0438\u0444\u0438\u043b\u0435 \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 getPair.  <\/p>\n<pre><code>function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) {     return a &lt; b ? _efficientHash(a, b) : _efficientHash(b, a); }<\/code><\/pre>\n<p>\u0414\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0445\u044d\u0448\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u044f\u0437\u044b\u043a Yul &#8212; \u043e\u043d \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0442 \u043f\u0438\u0441\u0430\u0442\u044c \u043d\u0438\u0437\u043a\u043e\u0443\u0440\u043e\u0432\u043d\u0435\u0432\u044b\u0439 \u043a\u043e\u0434 \u043f\u043e\u0434\u043e\u0431\u043d\u043e \u044f\u0437\u044b\u043a\u0443 \u0410\u0441\u0441\u0435\u043c\u0431\u043b\u0435\u0440\u0430, \u043c\u0430\u043d\u0438\u043f\u0443\u043b\u0438\u0440\u0443\u044f \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u044b\u043c \u0441\u043b\u043e\u0442\u043e\u0432 \u043f\u0430\u043c\u044f\u0442\u0438 \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e.  <\/p>\n<pre><code>function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {     \/\/\/ @solidity memory-safe-assembly     assembly { \/\/ \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e mstore \u043e\u0431\u0440\u0430\u0449\u0430\u0435\u043c\u0441\u044f \u043a \u0441\u043b\u043e\u0442\u0430\u043c \u0431\u044b\u0441\u0442\u0440\u043e\u0439 \u043f\u0430\u043c\u044f\u0442\u0438(memory)         mstore(0x00, a) \/\/ \u0445\u044d\u0448 \u0430 \u0437\u0430\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u044f\u0447\u0435\u0439\u043a\u0438 \u0441 0x00 \u043f\u043e 0x19 \u0432\u043a\u043b\u044e\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e         mstore(0x20, b) \/\/ \u0445\u044d\u0448 b \u0437\u0430\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u044f\u0447\u0435\u0439\u043a\u0438 \u0441 0x20 \u043f\u043e 0x39 \u0432\u043a\u043b\u044e\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e         value := keccak256(0x00, 0x40) \/\/ \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u044f\u0447\u0435\u0435\u043a \u0441 0x00 \u043f\u043e 0x39 \u0432\u043a\u043b\u044e\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \/\/ \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442\u0441\u044f \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u044e keccak256, \u044d\u0442\u043e \u0438 \u0435\u0441\u0442\u044c \u043a\u043e\u043d\u0442\u0430\u043a\u0442\u0435\u043d\u0430\u0446\u0438\u044f     } }<\/code><\/pre>\n<p> \u0412\u0435\u0440\u043d\u0435\u043c\u0441\u044f \u043a \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435 \u0438 \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0434\u043b\u044f \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430 \u043d\u043e\u0432\u043e\u0433\u043e \u0430\u0438\u0440\u0434\u0440\u043e\u043f\u0430 AirdropV2:  <\/p>\n<pre><code class=\"typescript\">import { expect } from \"chai\"; import { ethers } from \"hardhat\"; import { SignerWithAddress } from \"@nomiclabs\/hardhat-ethers\/signers\"; import { BigNumber } from \"ethers\"; import * as mocha from \"mocha-steps\"; import { parseEther } from '@ethersproject\/units'; import { AirdropV2, Token20 } from '..\/typechain-types'; import  keccak256  from \"keccak256\"; \/\/ \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u043c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 MerkleTree \u0434\u043b\u044f \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0434\u0435\u0440\u0435\u0432\u0430 import { MerkleTree } from \"merkletreejs\";   describe(\"AirdropV2.sol testing\", async () => {     let airdrop: AirdropV2;     let dropToken: Token20;     let admin: SignerWithAddress, user1: SignerWithAddress, user2: SignerWithAddress, user3: SignerWithAddress, user4: SignerWithAddress,          user5: SignerWithAddress, user6: SignerWithAddress, user7: SignerWithAddress, user8: SignerWithAddress, user9: SignerWithAddress,         user10: SignerWithAddress, user11: SignerWithAddress, user12: SignerWithAddress, user13: SignerWithAddress, user14: SignerWithAddress,         unwhitelisted: SignerWithAddress;          let dropAmount: BigNumber;     let Tree: MerkleTree;     let RootTree: string;      beforeEach(async () => {         [admin, user1, user2, user3, user4,           user5, user6, user7, user8, user9,           user10, user11, user12, user13,           user14, unwhitelisted] = await ethers.getSigners();     });      mocha.step(\"\u0414\u0435\u043f\u043b\u043e\u0439 \u0442\u043e\u043a\u0435\u043d\u0430 ERC20, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0440\u0430\u0437\u0434\u0430\u0432\u0430\u0442\u044c\", async function() {         const dropTokenFactory = await ethers.getContractFactory(\"Token20\");         dropToken = await dropTokenFactory.connect(admin).deploy(             'Drop Token',             'DTN',             parseEther('100000')         )     });      mocha.step(\"\u0414\u0435\u043f\u043b\u043e\u0439 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430 \u0430\u0438\u0440\u0434\u0440\u043e\u043f\u0430\", async function() {         const airdropFactory = await ethers.getContractFactory(\"AirdropV2\");         dropAmount = parseEther('1000');         airdrop = await airdropFactory.deploy(dropToken.address, dropAmount);     });      mocha.step(\"\u0422\u0440\u0430\u043d\u0441\u0444\u0435\u0440 \u0440\u0430\u0437\u0434\u0430\u0432\u0430\u0435\u043c\u043e\u0433\u043e \u0442\u043e\u043a\u0435\u043d\u0430 \u043d\u0430 \u0430\u0434\u0440\u0435\u0441 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430 \u0430\u0438\u0440\u0434\u0440\u043e\u043f\u0430\", async function() {         await dropToken.connect(admin).transfer(airdrop.address, parseEther('100000'));     });      mocha.step(\"\u0424\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0434\u0435\u0440\u0435\u0432\u0430 \u043c\u0435\u0440\u043a\u043b\u0430 \u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0433\u043e \u0445\u044d\u0448\u0430\", async function () {         const whitelist = [             user1.address, user2.address,              user3.address, user4.address,              user5.address, user6.address,              user7.address, user8.address,             user9.address, user10.address,             user11.address, user12.address,             user13.address, user14.address,         ];                 const leafs = whitelist.map(address => keccak256(address));    \/\/ sortPairs: true - \u0433\u043e\u0432\u043e\u0440\u0438\u0442 \u043e \u0442\u043e\u043c, \u0447\u0442\u043e \u043c\u0435\u043d\u044c\u0448\u0438\u0439 \u0445\u044d\u0448 \u0431\u0443\u0434\u0435\u0442 \u0438\u0434\u0442\u0438 \u043f\u0435\u0440\u0432\u044b\u043c   \/\/ \u043f\u0440\u0438 \u043f\u0430\u0440\u043d\u043e\u043c \u0445\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 (\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044e getPair \u0432 js-\u043f\u043e\u043b\u0438\u0444\u0438\u043b\u0438\u0435)         Tree = new MerkleTree(leafs, keccak256, {sortPairs: true});         RootTree = Tree.getHexRoot();     });      mocha.step(\"\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0433\u043e \u0445\u044d\u0448\u0430 \u0432 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442 \u0430\u0438\u0440\u0434\u0440\u043e\u043f\u0430\", async function () {               console.log('RootTree', RootTree);         await airdrop.connect(admin).setRoot(RootTree);       });      mocha.step(\"\u0412\u044b\u0437\u043e\u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 claim, \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u043c\u0438 \u0438\u0437 \u0432\u0430\u0439\u0442\u043b\u0438\u0441\u0442\u0430\", async function() {         await airdrop.connect(user1).claim(Tree.getHexProof(keccak256(user1.address)));         await airdrop.connect(user2).claim(Tree.getHexProof(keccak256(user2.address))); \/\/ \u0432 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u043c \u043a\u043e\u0434\u0435 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f \u043a\u043b\u0435\u0439\u043c \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0441\u044f \u0434\u043b\u044f 14 \u0430\u0434\u0440\u0435\u0441\u043e\u0432 \u0438\u0437 \u0432\u0430\u0439\u0442\u043b\u0438\u0441\u0442\u0430 \/\/ \u0437\u0434\u0435\u0441\u044c \u0441\u043e\u043a\u0440\u0430\u0449\u0435\u043d\u043d\u043e \u0434\u043b\u044f \u044d\u043a\u043e\u043d\u043e\u043c\u0438\u0438 \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u0430          await airdrop.connect(user14).claim(Tree.getHexProof(keccak256(user14.address)));     });      mocha.step(\"\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0431\u0430\u043b\u0430\u043d\u0441\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u043f\u043e\u0441\u043b\u0435 claim\", async function() {         expect(await dropToken.balanceOf(user1.address)).to.be.equal(dropAmount);                       expect(await dropToken.balanceOf(user2.address)).to.be.equal(dropAmount);               \/\/ \u0432 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u043c \u043a\u043e\u0434\u0435 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0431\u0430\u043b\u0430\u043d\u0441\u0430 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0441\u044f \u0434\u043b\u044f 14 \u0430\u0434\u0440\u0435\u0441\u043e\u0432 \u0438\u0437 \u0432\u0430\u0439\u0442\u043b\u0438\u0441\u0442\u0430 \/\/ \u0437\u0434\u0435\u0441\u044c \u0441\u043e\u043a\u0440\u0430\u0449\u0435\u043d\u043d\u043e \u0434\u043b\u044f \u044d\u043a\u043e\u043d\u043e\u043c\u0438\u0438 \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u0430          expect(await dropToken.balanceOf(user14.address)).to.be.equal(dropAmount);     });      mocha.step(\"\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043d\u0430 \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u044b\u0439 \u043a\u043b\u0435\u0439\u043c\", async function() {         await expect(airdrop.connect(user1).claim(Tree.getHexProof(keccak256(user1.address)))).to.be.revertedWith('Already claimed');     });      mocha.step(\"\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0437\u0430\u0449\u0438\u0442\u044b \u043e\u0442 \u043d\u0435\u0441\u0430\u043d\u043a\u0446\u0438\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u043a\u043b\u0435\u0439\u043c\u0430\", async function() {         await expect(airdrop.connect(unwhitelisted).claim(Tree.getHexProof(keccak256(unwhitelisted.address)))).to.be.revertedWith('You are not whitelisted.');     }); });<\/code><\/pre>\n<p> \u0417\u0430\u0444\u0438\u043a\u0441\u0438\u0440\u0443\u0435\u043c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043f\u043e\u0442\u0440\u0430\u0447\u0435\u043d\u043d\u043e\u0433\u043e \u0433\u0430\u0437\u0430 \u043d\u0430 \u0432\u044b\u0437\u043e\u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u201csetRoot\u201d.  <\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/eb8\/907\/9c9\/eb89079c9475169dbb1682695fab9b11.png\" width=\"1105\" height=\"455\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/eb8\/907\/9c9\/eb89079c9475169dbb1682695fab9b11.png\"\/><figcaption><\/figcaption><\/figure>\n<p>\u0412\u044b\u0437\u043e\u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u201csetRoot\u201d \u043e\u0431\u043e\u0448\u043e\u043b\u0441\u044f \u0432 46273 \u0433\u0430\u0437\u0430, \u043f\u043e \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044e \u0441 \u0432\u044b\u0437\u043e\u0432\u043e\u043c \u201caddToWhitelist\u201d, \u043c\u044b \u0441\u044d\u043a\u043e\u043d\u043e\u043c\u0438\u043b\u0438 \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0432 7.5, \u043f\u0440\u0438 \u044d\u0442\u043e\u043c, \u0435\u0441\u043b\u0438 \u0431\u044b \u0432 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 AirdropV1 \u043c\u044b \u0431\u044b \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u043b\u0438 \u0431\u043e\u043b\u044c\u0448\u0435 \u0430\u0434h\u0435\u0441\u043e\u0432 \u0432 \u0432\u0430\u0439\u0442\u043b\u0438\u0441\u0442, \u0442\u043e \u0438 \u044d\u043a\u043e\u043d\u043e\u043c\u0438\u044f \u0432\u044b\u0448\u043b\u0430 \u0431\u044b \u0431\u043e\u043b\u044c\u0448\u0435, \u0442\u043e \u0435\u0441\u0442\u044c \u0447\u0435\u043c \u0431\u043e\u043b\u044c\u0448\u0435 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c, \u0442\u0435\u043c \u0440\u0435\u043d\u0442\u0430\u0431\u0435\u043b\u044c\u043d\u0435\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u0435\u0440\u0435\u0432\u044c\u044f \u041c\u0435\u0440\u043a\u043b\u0430 \u0432 \u0432\u0430\u0448\u0438\u0445 \u0443\u043c\u043d\u044b\u0445 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430\u0445.<\/p>\n<h2>\u041f\u043e\u0441\u043b\u0435\u0441\u043b\u043e\u0432\u0438\u0435<\/h2>\n<p><a href=\"https:\/\/github.com\/davydovMikhail\/merkle-tree\" rel=\"noopener noreferrer nofollow\">\u0420\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u0434\u0435\u043c\u043e-\u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/a><\/p>\n<p>\u041e\u0441\u0442\u0430\u043b\u0438\u0441\u044c \u0432\u043e\u043f\u0440\u043e\u0441\u044b? \u0421 \u0447\u0435\u043c-\u0442\u043e \u043d\u0435 \u0441\u043e\u0433\u043b\u0430\u0441\u043d\u044b? \u041f\u0438\u0448\u0438\u0442\u0435 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0438  <\/p>\n<p>\u041f\u043e\u0434\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0430\u0432\u0442\u043e\u0440\u0430 \u043a\u0440\u0438\u043f\u0442\u043e\u0432\u0430\u043b\u044e\u0442\u043e\u0439: 0x021Db128ceab47C66419990ad95b3b180dF3f91F  <\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"v-portal\" style=\"display:none;\"><\/div>\n<\/div>\n<p> <!----> <!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/post\/699032\/\"> https:\/\/habr.com\/ru\/post\/699032\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<h2>\u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435<\/h2>\n<p>\u0412 \u0438\u0434\u0435\u0430\u043b\u044c\u043d\u043e\u043c \u0434\u0435\u0446\u0435\u043d\u0442\u0440\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u043e\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u043c\u044b \u0431\u044b \u0445\u043e\u0442\u0435\u043b\u0438 \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432\u0441\u0435 \u0432 \u0431\u043b\u043e\u043a\u0447\u0435\u0439\u043d\u0435 \u043d\u0430 \u0441\u043c\u0430\u0440\u0442-\u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430\u0445 \u2014 \u0432 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 Ethereum: \u0434\u0430\u043d\u043d\u044b\u0435 \u043d\u0435 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u044b \u043d\u0435\u0441\u0430\u043d\u043a\u0446\u0438\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u043c \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u043c. \u041d\u043e \u0437\u0430\u043f\u0438\u0441\u044c \u043a\u0430\u043a\u043e\u0439-\u043b\u0438\u0431\u043e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438, \u0440\u0430\u0437\u043c\u0435\u0440\u043e\u043c 32 \u0431\u0430\u0439\u0442\u0430 \u043e\u0431\u043e\u0439\u0434\u0435\u0442\u0441\u044f \u043d\u0430\u043c \u0432 20000 \u0433\u0430\u0437\u0430. \u041d\u0430 \u043c\u043e\u043c\u0435\u043d\u0442 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0441\u0442\u0430\u0442\u044c\u0438 \u044d\u0442\u043e \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e $0.26, c \u043e\u0434\u043d\u043e\u0439 \u0441\u0442\u043e\u0440\u043e\u043d\u044b \u043d\u0435 \u043c\u043d\u043e\u0433\u043e, \u043d\u043e \u0447\u0442\u043e \u0435\u0441\u043b\u0438 \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 \u043a\u0430\u043a\u043e\u0439-\u0442\u043e \u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043c\u0430\u0441\u0441\u0438\u0432 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438.  <\/p>\n<p>\u0412 \u043f\u043e\u0438\u0441\u043a\u0430\u0445 \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u043e\u0439 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u044d\u043a\u043e\u0441\u0438\u0441\u0442\u0435\u043c\u0430 Ethereum \u0434\u0430\u0435\u0442 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u043d\u044b\u0445 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432. \u041a\u0430\u043a \u043f\u0440\u0430\u0432\u0438\u043b\u043e, \u0432 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u043c \u043f\u0443\u0442\u0438 \u0435\u0441\u0442\u044c \u043a\u043e\u043c\u043f\u0440\u043e\u043c\u0438\u0441\u0441 \u043c\u0435\u0436\u0434\u0443 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e\u0441\u0442\u044c\u044e \u0438 \u0446\u0435\u043d\u043d\u043e\u0439. \u0412\u0430\u0440\u0438\u0430\u043d\u0442 \u043e\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0439 \u0432 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u043e\u0436\u0435\u0442 \u043e\u0431\u043e\u0439\u0442\u0438\u0441\u044c \u043a\u0440\u0430\u0439\u043d\u0435 \u0434\u0435\u0448\u0435\u0432\u043e \u0432 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438, \u043f\u0440\u0438 \u0434\u043e\u043b\u0436\u043d\u043e\u043c \u043f\u043e\u0434\u0445\u043e\u0434\u0435 \u0438 \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u0438 \u0442\u0435\u043c\u044b.  <\/p>\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u0432\u044b \u0443\u0437\u043d\u0430\u0435\u0442\u0435 \u043f\u0440\u043e \u0414\u0435\u0440\u0435\u0432\u044c\u044f \u041c\u0435\u0440\u043a\u043b\u0430 \u2014 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c \u0445\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445, \u0431\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f \u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443, \u043c\u044b \u0441\u043c\u043e\u0436\u0435\u043c \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432\u0441\u044e \u043f\u043e\u043b\u043d\u043e\u0442\u0443 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438, \u043d\u0435 \u043f\u0440\u0438\u0431\u0435\u0433\u0430\u044f \u043a \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u043e\u043c\u0443 \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u043d\u0438\u044e \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0433\u043e \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430 Ethereum.  <\/p>\n<h2>\u0422\u0435\u043e\u0440\u0438\u044f<\/h2>\n<p>\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0434\u0435\u0440\u0435\u0432\u0430 \u041c\u0435\u0440\u043a\u043b\u0430 \u044d\u0442\u043e \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 \u0445\u044d\u0448, \u043d\u0430\u0445\u043e\u0434\u044f\u0449\u0438\u0439\u0441\u044f \u0432 \u0441\u0430\u043c\u043e\u043c \u0432\u0435\u0440\u0445\u0443 \u043f\u0438\u0440\u0430\u043c\u0438\u0434\u044b \u0445\u044d\u0448\u0435\u0439. \u041d\u0430 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0438 \u043d\u0438\u0436\u0435 \u0445\u044d\u0448 H(AH) &#8212; \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0440\u0430\u0437\u0431\u0435\u0440\u0435\u043c\u0441\u044f \u043a\u0430\u043a \u043e\u043d \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0441\u044f.  <\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>\u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0438\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u043c\u044b \u0438\u043c\u0435\u0435\u043c 8 \u0445\u044d\u0448\u0435\u0439(A, B, C, D, E, F, G, H) \u043a\u0430\u043a\u0438\u0445-\u0442\u043e \u0434\u0430\u043d\u043d\u044b\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0438\u043a\u0430\u043a \u043d\u0435 \u043e\u0442\u043d\u043e\u0441\u044f\u0442\u0441\u044f \u0434\u0440\u0443\u0433 \u043a \u0434\u0440\u0443\u0433\u0443. \u0417\u0430\u0442\u0435\u043c \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043f\u043e\u043f\u0430\u0440\u043d\u043e\u0435 \u0445\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435(H(AB), H(CD), H(EF), H(GH)), \u0430 \u0438\u043c\u0435\u043d\u043d\u043e: \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043a\u043e\u043d\u043a\u0430\u0442\u0435\u043d\u0430\u0446\u0438\u0438 A \u0438 B \u043f\u043e\u043c\u0435\u0449\u0430\u0435\u0442\u0441\u044f \u0432 \u0445\u044d\u0448-\u0444\u0443\u043d\u043a\u0446\u0438\u044e keccak256, \u0442\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u0445\u044d\u0448 H(AB):  <\/p>\n<p>\u041f\u043e\u0434\u043e\u0431\u043d\u044b\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u044e\u0442\u0441\u044f \u0442\u0430\u043a\u0436\u0435 H(EF) \u0438 H(GH), \u0435\u0441\u043b\u0438 \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u043d\u0435\u0447\u0435\u0442\u043d\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0445\u044d\u0448\u0435\u0439, \u0442\u043e \u043e\u0441\u0442\u0430\u0432\u0448\u0438\u0439\u0441\u044f \u043f\u0435\u0440\u0435\u0439\u0434\u0435\u0442 \u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0443\u0440\u043e\u0432\u0435\u043d\u044c \u043f\u043e\u043f\u0430\u0440\u043d\u043e\u0433\u043e \u0445\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0438 \u0442\u0430\u043c \u043d\u0430\u0439\u0434\u0435\u0442 \u0441\u0435\u0431\u0435 \u043f\u0430\u0440\u0443, \u0435\u0441\u043b\u0438 \u0438 \u0442\u0430\u043c \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u0430\u0440\u044b, \u0442\u043e \u043e\u043d \u043f\u0435\u0440\u0435\u0439\u0434\u0435\u0442 \u0441\u043d\u043e\u0432\u0430 \u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0443\u0440\u043e\u0432\u0435\u043d\u044c, \u0438 \u0442\u0430\u043a \u0434\u043e \u0442\u0435\u0445 \u043f\u043e\u0440 \u043f\u043e\u043a\u0430 \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u043d\u0430\u0439\u0434\u0435\u043d\u0430 \u043f\u0430\u0440\u0430.   <\/p>\n<p>\u041a\u0430\u043a \u0432\u044b \u0443\u0436\u0435 \u043c\u043e\u0433\u043b\u0438 \u0434\u043e\u0433\u0430\u0434\u0430\u0442\u044c\u0441\u044f H(AD) \u0431\u0443\u0434\u0435\u0442 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u043c \u043f\u043e\u043f\u0430\u0440\u043d\u043e\u0433\u043e \u0445\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f H(AB) \u0438 H(CD), \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u043e \u0442\u043e\u0447\u043d\u043e \u0442\u0430\u043a\u043e\u0439 \u0436\u0435 \u0444\u043e\u0440\u043c\u0443\u043b\u0435:  <\/p>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c: <\/p>\n<ol>\n<li>\n<p>\u0447\u0435\u043c \u0431\u043e\u043b\u044c\u0448\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u043d\u0430\u043c \u043d\u0430\u0434\u043e \u0445\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432 \u0434\u0435\u0440\u0435\u0432\u0435 \u041c\u0435\u0440\u043a\u043b\u0430, \u0442\u0435\u043c \u0431\u043e\u043b\u044c\u0448\u0435 \u0443\u0440\u043e\u0432\u043d\u0435\u0439 \u043f\u043e\u043f\u0430\u0440\u043d\u043e\u0433\u043e \u0445\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043d\u0430\u043c \u043f\u0440\u0438\u0434\u0435\u0442\u0441\u044f \u043f\u0440\u0435\u043e\u0434\u043e\u043b\u0435\u0442\u044c, \u0447\u0442\u043e\u0431\u044b \u0432 \u043a\u043e\u043d\u0447\u0435\u043d\u043e\u043c \u0438\u0442\u043e\u0433\u0435 \u043f\u0440\u0438\u0439\u0442\u0438 \u043a \u043e\u0434\u043d\u043e\u043c\u0443 \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u043c\u0443 \u0445\u044d\u0448\u0443;<\/p>\n<\/li>\n<li>\n<p>\u0435\u0441\u043b\u0438 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0445\u044d\u0448\u0435\u0439 \u0434\u043b\u044f \u043f\u043e\u043f\u0430\u0440\u043d\u043e\u0433\u043e \u0445\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043d\u0435\u0447\u0435\u0442\u043d\u043e\u0435, \u0442\u043e \u0445\u044d\u0448 \u043d\u0435 \u0438\u043c\u0435\u044e\u0449\u0438\u0439 \u043f\u0430\u0440\u044b \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u0442 \u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0443\u0440\u043e\u0432\u0435\u043d\u044c \u0438 \u043d\u0430\u0445\u043e\u0434\u0438\u0442 \u043f\u0430\u0440\u0443 \u0442\u0430\u043c, \u0435\u0441\u043b\u0438 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0445\u044d\u0448\u0435\u0439 \u043d\u0435\u0447\u0435\u0442\u043d\u043e\u0435 \u0438 \u0442\u0430\u043c, \u0442\u043e \u0445\u044d\u0448 \u0441\u043d\u043e\u0432\u0430 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u0442 \u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0443\u0440\u043e\u0432\u0435\u043d\u044c \u043f\u043e\u043f\u0430\u0440\u043d\u043e\u0433\u043e \u0445\u0435\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0432\u043f\u043b\u043e\u0442\u044c \u0434\u043e \u0443\u0440\u043e\u0432\u043d\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043f\u0435\u0440\u0435\u0434 \u043a\u043e\u0440\u043d\u0435\u0432\u044b\u043c.<\/p>\n<\/li>\n<\/ol>\n<p>\u041f\u0440\u0438\u043c\u0435\u0447\u0430\u043d\u0438\u0435: \u0437\u0434\u0435\u0441\u044c \u0438 \u0434\u0430\u043b\u0435\u0435 \u0434\u043b\u044f \u043f\u043e\u043f\u0430\u0440\u043d\u043e\u0433\u043e \u0445\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0442\u0441\u044f \u0445\u044d\u0448 \u0444\u0443\u043d\u043a\u0446\u0438\u044f keccak256, \u0432\u044b \u043f\u043e\u0439\u043c\u0435\u0442\u0435 \u0432 \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u043c \u043f\u043e\u0447\u0435\u043c\u0443, \u043d\u043e \u044d\u0442\u043e \u043d\u0435 \u0435\u0441\u0442\u044c \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u043a \u0438\u0441\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044e \u043f\u0440\u0430\u0432\u0438\u043b\u043e, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432\u0445\u043e\u0434\u043d\u044b\u0435 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u044b \u0434\u043b\u044f \u043f\u043e\u043f\u0430\u0440\u043d\u043e\u0433\u043e \u0445\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u043f\u0435\u0440\u0435\u0432\u0435\u0434\u0435\u043d\u044b \u0432 \u0434\u0432\u043e\u0438\u0447\u043d\u044b\u0439 \u043a\u043e\u0434, \u0430 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u043c \u043f\u043e\u043f\u0430\u0440\u043d\u043e\u0433\u043e \u0445\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0431\u0443\u0434\u0435\u0442 \u0441\u0442\u0440\u043e\u0433\u0430\u044f \u0434\u0438\u0437\u044a\u044e\u043d\u043a\u0446\u0438\u044f \u044d\u0442\u0438\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u0434\u0432\u043e\u0438\u0447\u043d\u043e\u043c \u0432\u0438\u0434\u0435 \u0438\u043b\u0438 \u0434\u0440\u0443\u0433\u0438\u043c\u0438 \u0441\u043b\u043e\u0432\u0430\u043c\u0438 \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u0430 \u0438\u0441\u043a\u043b\u044e\u0447\u0430\u044e\u0449\u0435\u0433\u043e \u0418\u041b\u0418(XOR) \u0434\u043b\u044f \u044d\u0442\u0438\u0445 \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<p>\u041c\u044b \u043f\u043e\u043d\u044f\u043b\u0438 \u043a\u0430\u043a \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 \u0445\u044d\u0448 \u0434\u0435\u0440\u0435\u0432\u0430, \u043d\u043e \u043a\u0430\u043a \u043d\u0430\u043c \u0443\u0431\u0435\u0434\u0438\u0442\u0441\u044f, \u0447\u0442\u043e \u0442\u0430 \u0438\u043b\u0438 \u0438\u043d\u0430\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043d\u0430 \u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435 \u043f\u0440\u0438\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0432 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0435 \u0434\u0435\u0440\u0435\u0432\u0430? \u041e\u0442\u0432\u0435\u0442\u043e\u043c \u043d\u0430 \u044d\u0442\u043e\u0442 \u0432\u043e\u043f\u0440\u043e\u0441 \u0431\u0443\u0434\u0435\u0442 \u043c\u0430\u0441\u0441\u0438\u0432 \u0441 \u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u0447\u043d\u044b\u043c\u0438 \u0445\u044d\u0448\u0430\u043c\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u043e\u043c\u043e\u0433\u0443\u0442 \u043d\u0430\u043c \u0443\u0431\u0435\u0434\u0438\u0442\u0441\u044f \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u0442\u0430 \u0438\u043b\u0438 \u0438\u043d\u0430\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u0440\u0438\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0432 \u0434\u0435\u0440\u0435\u0432\u0435. \u041a\u0430\u043a \u0432\u0441\u0435\u0433\u0434\u0430 \u043f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u043a \u043d\u0430\u0433\u043b\u044f\u0434\u043d\u043e\u043c\u0443 \u043f\u0440\u0438\u043c\u0435\u0440\u0443.<\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>\u041f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u0438\u043c \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u044e, \u0433\u0434\u0435 \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u0443\u0431\u0435\u0434\u0438\u0442\u044c\u0441\u044f \u0432 \u0442\u043e\u043c \u0447\u0442\u043e \u0445\u044d\u0448 C(\u0432\u044b\u0434\u0435\u043b\u0435\u043d \u0441\u0438\u043d\u0438\u043c) \u043f\u0440\u0438\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0432 \u0434\u0435\u0440\u0435\u0432\u0435. \u0412 \u0442\u0430\u043a\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0434\u043e\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u044c\u0441\u0442\u0432\u043e\u043c \u0431\u0443\u0434\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u043c\u0430\u0441\u0441\u0438\u0432 \u0434\u0430\u043d\u043d\u044b\u0445: \u0445\u044d\u0448 D, H(AB), H(EH) (\u0432\u044b\u0434\u0435\u043b\u0435\u043d\u044b \u0437\u0435\u043b\u0435\u043d\u044b\u043c). \u0411\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f \u0438\u043c \u043c\u044b \u0441\u043c\u043e\u0436\u0435\u043c \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 \u0445\u044d\u0448.  <\/p>\n<p>\u0415\u0441\u043b\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0439 \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 \u0445\u044d\u0448 \u0441\u043e\u0432\u043f\u0430\u0434\u0430\u0435\u0442 \u0441 \u0442\u0435\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0430\u043c \u0438\u0437\u0432\u0435\u0441\u0442\u0435\u043d, \u0437\u043d\u0430\u0447\u0438\u0442 \u0445\u044d\u0448 C \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u0440\u0438\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0432 \u0434\u0435\u0440\u0435\u0432\u0435 \u041c\u0435\u0440\u043a\u043b\u0430.   <\/p>\n<p>\u041f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u0435\u0449\u0451 \u0431\u043e\u043b\u044c\u0448\u0435 \u0443\u0433\u043b\u0443\u0431\u0438\u0442\u044c\u0441\u044f \u0432 \u0442\u0435\u043e\u0440\u0438\u044e \u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044e-\u043f\u043e\u043b\u0438\u0444\u0438\u043b, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0442\u044c \u043c\u0430\u0441\u0441\u0438\u0432 \u0441 \u0445\u044d\u0448\u0430\u043c\u0438, \u0430 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 \u0445\u044d\u0448 \u0434\u0435\u0440\u0435\u0432\u0430 \u041c\u0435\u0440\u043a\u043b\u0430 \u0434\u043b\u044f \u044d\u0442\u0438\u0445 \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<p>\u0421\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u0431\u0443\u0434\u0435\u0442 \u0434\u0430\u043d\u0430 \u0432 \u043a\u043e\u043d\u0446\u0435 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u0430.<\/p>\n<pre><code class=\"typescript\">const addresses = [     '0x70997970C51812dc3A010C7d01b50e0d17dc79C8',     '0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC',     '0x90F79bf6EB2c4f870365E785982E1f101E93b906',     '0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65',     '0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc',     '0x976EA74026E726554dB657fA54763abd0C3a0aa9',     '0x14dC79964da2C08b23698B3D3cc7Ca32193d9955',     '0x23618e81E3f5cdF7f54C3d65f7FBc0aBf5B21E8f',     '0xa0Ee7A142d267C1f36714E4a8F75612F20a79720',     '0xBcd4042DE499D14e55001CcbB24a551F3b954096',     '0x71bE63f3384f5fb98995898A86B02Fb2426c5788',     '0xFABB0ac9d68B0B445fB7357272Ff202C5651694a',     '0x1CBd3b2770909D4e10f157cABC84C7264073C9Ec',     '0xdF3e18d64BC6A983f673Ab319CCaE4f1a57C7097' ]; \/\/ \u043c\u0430\u0441\u0441\u0438\u0432 \u0441 \u0430\u0434\u0440\u0435\u0441\u0430\u043c\u0438 \u0434\u043b\u044f \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043c\u044b \u0432\u044b\u0447\u0438\u0441\u043b\u0438\u043c \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 \u0445\u044d\u0448      \/\/ dataArray - \u043c\u0430\u0441\u0441\u0438\u0432 \u0441 \u0445\u044d\u0448\u0430\u043c\u0438, \u0442\u043e \u0435\u0441\u0442\u044c \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 \u0445\u044d\u0448 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043b\u0443\u0447\u0435\u043d \u0438\u0437 \u0445\u044d\u0448\u0435\u0439 \u0430\u0434\u0440\u0435\u0441\u043e\u0432 \/\/ \u0430 \u043d\u0435 \u0438\u0437 \u0430\u0434\u0440\u0435\u0441\u043e\u0432 \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e const dataArray = addresses.map(address => ethers.utils.keccak256(address));  \/\/ \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0445\u044d\u0448\u0430 \u043e\u0442 \u043f\u0430\u0440\u044b \u0434\u0432\u0443\u0445 \u0434\u0440\u0443\u0433\u0438\u0445 \u0445\u044d\u0448\u0435\u0439 function getPair(hashOne: string, hashTwo: string): string { \/\/ \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0438\u0440\u0443\u044e\u0449\u0438\u0439 \u0445\u044d\u0448 \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u043f\u043e\u0440\u044f\u0434\u043a\u0430 \u043a\u043e\u043d\u0442\u0430\u043a\u0442\u0435\u043d\u0430\u0446\u0438\u0438 \/\/ \u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043f\u0435\u0440\u0432\u044b\u043c \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u043c \u0432\u0441\u0435\u0433\u0434\u0430 \u0431\u0443\u0434\u0435\u0442 \u0438\u0434\u0442\u0438 \u043c\u0435\u043d\u044c\u0448\u0438\u0439 \u0445\u044d\u0448     if (BigInt(hashOne) &lt; BigInt(hashTwo)) { \/\/ \u043f\u0430\u0440\u043d\u043e\u0435 \u0445\u0435\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 ethers         return ethers.utils.solidityKeccak256([ 'bytes32', 'bytes32' ], [ hashOne, hashTwo ]);     } else {         return ethers.utils.solidityKeccak256([ 'bytes32', 'bytes32' ], [ hashTwo, hashOne ]);     } }  \/\/ \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0433\u043e \u0445\u044d\u0448\u0430, \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u043c\u0430\u0441\u0441\u0438\u0432 \u0445\u044d\u0448\u0435\u0439, \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 function getRoot(data: string[]): string { \/\/ \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0447\u0435\u0442\u043d\u043e\u0435 \u043b\u0438 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u0432 \u043c\u0430\u0441\u0441\u0438\u0432\u0435     const parity: boolean = !(data.length % 2);   \/\/ \u0437\u0430\u0442\u0435\u043c \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u043d\u0443\u0436\u043d\u0443\u044e \u043d\u0430\u043c \u0434\u043b\u0438\u043d\u0443 \u0434\u043b\u044f \u0446\u0438\u043a\u043b\u0430 for \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0447\u0435\u0442\u043d\u043e\u0441\u0442\u0438 \/\/ \u0435\u0441\u043b\u0438 \u043a\u043e\u043b\u0438\u0447\u0435\u0442\u0432\u043e \u0447\u0435\u0442\u043d\u043e\u0435, \u0437\u043d\u0430\u0447\u0438\u0442 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u0438\u0441\u0445\u043e\u0434\u043d\u0443\u044e \u0434\u043b\u0438\u043d\u0443 \/\/ \u0438\u043d\u0430\u0447\u0435 \u0434\u043b\u0438\u043d\u0430 \u0431\u0443\u0434\u0435\u0442 \u0443\u043c\u0435\u043d\u044c\u0448\u0435\u043d\u0430 \u043d\u0430 1, \u0442\u0430\u043a \u043a\u0430\u043a \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u043d\u0435\u0447\u0435\u0442\u043d\u043e\u0441\u0442\u0438 \/\/ \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u0445\u044d\u0448 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u0442 \u0441\u0435\u0431\u0435 \u043f\u0430\u0440\u044b     let length = parity ? data.length : data.length - 1;     let result = [];     for (var i = 0; i &lt; length - 1; i += 2) { \/\/ \u0437\u0430\u043f\u043e\u043b\u043d\u044f\u0435\u043c \u043c\u0430\u0441\u0441\u0438\u0432 \u043f\u0430\u0440\u043d\u044b\u043c\u0438 \u0445\u0435\u0448\u0430\u043c\u0438         result.push(getPair(data[i], data[i + 1]));     }        if (!parity) { \/\/ \u0435\u0441\u043b\u0438 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043d\u0435\u0447\u0435\u0442\u043d\u043e\u0435, \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0432 \u043a\u043e\u043d\u0435\u0446 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0438\u0440\u0443\u044e\u0449\u0435\u0433\u043e \u043c\u0430\u0441\u0441\u0438\u0432\u0430  \/\/ \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442, \u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443 \u043d\u0435 \u043d\u0430\u0448\u043b\u043e\u0441\u044c \u043f\u0430\u0440\u044b \u0434\u043b\u044f \u043f\u0430\u0440\u043d\u043e\u0433\u043e \u0445\u0435\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f         result.push(data[data.length - 1]);     } \/\/ \u0435\u0441\u043b\u0438 \u0432 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0438\u0440\u0443\u044e\u0449\u0435\u043c \u043c\u0430\u0441\u0441\u0438\u0432\u0435 \u043e\u0434\u0438\u043d \u044d\u043b\u0435\u043c\u0435\u043d\u0442, \u0442\u043e \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u0435\u0433\u043e,  \/\/ \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u044d\u0442\u043e \u0438 \u0435\u0441\u0442\u044c \u0438\u0441\u043a\u043e\u043c\u044b\u0439 \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 \u0445\u044d\u0448 \/\/ \u0438\u043d\u0430\u0447\u0435 \u0441\u043d\u043e\u0432\u0430 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c getRoot \/\/ \u0442\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044f getRoot \u0431\u0443\u0434\u0435\u0442 \u0440\u0435\u043a\u0443\u0440\u0441\u0438\u0432\u043d\u043e\u0439      return result.length == 1 ? result[0] : getRoot(result);  }  const root = getRoot(dataArray); console.log('root', root);<\/code><\/pre>\n<p> \u0417\u0430\u043f\u0443\u0441\u0442\u0438\u043c \u0441\u043a\u0440\u0438\u043f\u0442 \u0438 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043d\u0430 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442.  <\/p>\n<pre><code class=\"powershell\">npx hardhat run scripts\/example-merkle.ts<\/code><\/pre>\n<p> \u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0438\u0437 \u043b\u043e\u0433\u043e\u0432: \u20180x2e3bc03e1c67b59152c362a773c515a01d9dfdde6aaaa6796ad3bb1ec3b65300\u2019.<\/p>\n<h2>\u041f\u0440\u0430\u043a\u0442\u0438\u043a\u0430<\/h2>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442 \u0431\u0435\u0437 \u0432\u0441\u044f\u043a\u0438\u0445 \u0434\u0435\u0440\u0435\u0432\u044c\u0435\u0432, \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u0442\u0441\u044f \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u043e\u043d \u043f\u0440\u043e\u0441\u0442\u043e \u0440\u0430\u0437\u0434\u0430\u0435\u0442 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0439 \u0442\u043e\u043a\u0435\u043d \u0442\u0435\u043c, \u043a\u0442\u043e \u043d\u0430 \u043d\u0435\u0433\u043e \u043f\u0440\u0435\u0442\u0435\u043d\u0434\u0443\u0435\u0442, \u0438\u043b\u0438 \u0438\u043d\u044b\u043c\u0438 \u0441\u043b\u043e\u0432\u0430\u043c\u0438 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u0442\u0430\u043a \u043d\u0430\u0437\u044b\u0432\u0430\u0435\u043c\u043e\u043c \u0432\u0430\u0439\u0442\u043b\u0438\u0441\u0442\u0435.<\/p>\n<pre><code>\/\/ SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.9;  import \"@openzeppelin\/contracts\/token\/ERC20\/utils\/SafeERC20.sol\"; import \"@openzeppelin\/contracts\/token\/ERC20\/extensions\/IERC20Metadata.sol\";   contract AirdropV1 {     using SafeERC20 for IERC20Metadata;      address owner; \/\/ \u0442\u043e\u043b\u044c\u043a\u043e \u044d\u0442\u043e\u0442 \u0430\u0434\u0440\u0435\u0441 \u0438\u043c\u0435\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0444\u0443\u043d\u043a\u0446\u0438\u0438 addToWhitelist     address dropToken; \/\/ \u0430\u0434\u0440\u0435\u0441 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430 \u0442\u043e\u043a\u0435\u043d\u0430 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u0430 ERC20     uint256 dropAmount; \/\/ \u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u0430\u044f \u0441\u0443\u043c\u043c\u0430, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043f\u043e\u043b\u0443\u0447\u0438\u0442 \u043a\u0430\u0436\u0434\u044b\u0439, \u043a\u0442\u043e \u0435\u0441\u0442\u044c \u0432 \u0432\u0430\u0439\u0442\u043b\u0438\u0441\u0442\u0435     mapping(address => bool) public whitelist; \/\/ mapping \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 true \u0435\u0441\u043b\u0438 \u0430\u0434\u0440\u0435\u0441 \u0435\u0441\u0442\u044c \u0432 \u0432\u0430\u0439\u0442\u043b\u0438\u0441\u0442\u0435          constructor(address _dropToken, uint256 _dropAmount) { \/\/ \u043f\u0440\u0438 \u0434\u0435\u043f\u043b\u043e\u0435 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430 \u0432 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442\u0441\u044f \u0430\u0434\u0440\u0435\u0441 \u0440\u0430\u0437\u0434\u0430\u0432\u0430\u0435\u043c\u043e\u0433\u043e \u0442\u043e\u043a\u0435\u043d\u0430 \/\/ \u0438 \u0441\u0443\u043c\u043c\u0430 \u0435\u0434\u0438\u043d\u0438\u0447\u043d\u043e\u0433\u043e \u043a\u043b\u0435\u0439\u043c\u0430          owner = msg.sender;         dropToken = _dropToken;         dropAmount = _dropAmount;     }    \/\/ \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0432 \u0432\u0430\u0439\u0442\u043b\u0438\u0441\u0442 \u043d\u043e\u0432\u044b\u0445 \u0443\u0447\u0430\u0441\u0442\u043d\u0438\u043a\u043e\u0432 \u0430\u0438\u0440\u0434\u0440\u043e\u043f\u0430 \/\/ \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0430 \u043e\u043d\u0430 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u043c\u0430\u0441\u0441\u0438\u0432 \u0441 \u0430\u0434\u0440\u0435\u0441\u0430\u043c\u0438 \u0443\u0447\u0430\u0441\u0442\u043d\u0438\u043a\u043e\u0432     function addToWhitelist(address[] calldata _users) public {         require(owner == msg.sender, \"Only owner!\");         for(uint i = 0; i &lt; _users.length; i++) {             whitelist[_users[i]] = true;         }     }  \/\/ \u044d\u0442\u0443 \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 \u0443\u0447\u0430\u0441\u0442\u043d\u0438\u043a, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u0432\u0430\u0439\u0442\u043b\u0438\u0441\u0442\u0435 \/\/ \u043f\u043e\u0441\u043b\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0433\u043e \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0438 \u043d\u0430 \u0435\u0433\u043e \u0430\u0434\u0440\u0435\u0441\u0435 \u043e\u043a\u0430\u0436\u0435\u0442\u0441\u044f \u0441\u0443\u043c\u043c\u0430 dropAmount \u0442\u043e\u043a\u0435\u043d\u0430 dropToken     function claim() public {         require(whitelist[msg.sender], \"You are not whitelisted.\");         IERC20Metadata(dropToken).safeTransfer(             msg.sender,             dropAmount         );         whitelist[msg.sender] = false;     } }<\/code><\/pre>\n<p>\u041d\u0430\u043f\u0438\u0448\u0435\u043c \u0434\u043b\u044f \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d \u043f\u043e\u043b\u043d\u044b\u0439 \u0446\u0438\u043a\u043b \u0440\u0430\u0431\u043e\u0442\u044b \u0432\u0441\u0435\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0441\u044f \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u043c \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u043c hardhat gas-reporter, \u0447\u0442\u043e\u0431\u044b \u0432\u044b\u044f\u0441\u043d\u0438\u0442\u044c \u043a\u0430\u043a\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0433\u0430\u0437\u0430 \u0431\u044b\u043b\u043e \u043f\u043e\u0442\u0440\u0430\u0447\u0435\u043d\u043e \u043d\u0430 \u0432\u044b\u0437\u043e\u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u201caddToWhitelist\u201d.<\/p>\n<pre><code class=\"typescript\">import { expect } from \"chai\"; import { ethers } from \"hardhat\"; import { SignerWithAddress } from \"@nomiclabs\/hardhat-ethers\/signers\"; import { BigNumber } from \"ethers\"; import * as mocha from \"mocha-steps\"; import { parseEther } from '@ethersproject\/units'; import { AirdropV1, Token20 } from '..\/typechain-types';  describe(\"AirdropV1.sol testing\", async () => {     let airdrop: AirdropV1;     let dropToken: Token20;     let admin: SignerWithAddress, user1: SignerWithAddress, user2: SignerWithAddress, user3: SignerWithAddress, user4: SignerWithAddress,          user5: SignerWithAddress, user6: SignerWithAddress, user7: SignerWithAddress, user8: SignerWithAddress, user9: SignerWithAddress,         user10: SignerWithAddress, user11: SignerWithAddress, user12: SignerWithAddress, user13: SignerWithAddress, user14: SignerWithAddress,         unwhitelisted: SignerWithAddress;          let dropAmount: BigNumber;      beforeEach(async () => {         [admin, user1, user2, user3, user4,           user5, user6, user7, user8, user9,           user10, user11, user12, user13,           user14, unwhitelisted] = await ethers.getSigners();     });      mocha.step(\"\u0414\u0435\u043f\u043b\u043e\u0439<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-341187","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/341187","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=341187"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/341187\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=341187"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=341187"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=341187"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}