{"id":356607,"date":"2024-05-20T23:33:24","date_gmt":"2024-05-20T23:33:24","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=356607"},"modified":"-0001-11-30T00:00:00","modified_gmt":"2024-05-20T23:33:24","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=356607","title":{"rendered":"<span>\u0422\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0441\u043c\u0430\u0440\u0442-\u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u043e\u0432 \u0432 Foundry (\u0447\u0430\u0441\u0442\u044c 3)<\/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<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/01e\/d21\/019\/01ed210191d501972ed1eaedffcbee3b.png\" width=\"14268\" height=\"8788\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/01e\/d21\/019\/01ed210191d501972ed1eaedffcbee3b.png\"\/><\/figure>\n<p>\u0417\u0430 \u043f\u0440\u043e\u0448\u0435\u0434\u0448\u0438\u0435 \u0434\u0432\u0435 \u0447\u0430\u0441\u0442\u0438 \u043c\u044b \u043e\u0441\u0432\u043e\u0438\u043b\u0438 \u043f\u043e\u0447\u0442\u0438 \u0432\u0441\u044e \u0431\u0430\u0437\u0443, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043d\u0443\u0436\u043d\u0430 \u043d\u0430\u043c \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0438 \u043e\u0442\u043b\u0430\u0434\u043a\u0438 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u043e\u0432 \u0432 <strong>Foundry<\/strong>. \u041f\u0440\u0438\u0448\u043b\u043e \u0432\u0440\u0435\u043c\u044f \u0437\u0430\u043a\u0440\u0435\u043f\u0438\u0442\u044c \u0443\u0441\u043f\u0435\u0445! \u0412 \u044d\u0442\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u043c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u0440\u043e\u0441\u0442\u044b\u0445 <strong>\u043f\u0440\u043e\u043a\u0441\u0438-\u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u043e\u0432<\/strong> (Proxy Upgradable Contracts, UUPS) \u0438 \u043d\u0430 \u0438\u0445 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c <strong>\u0441\u043a\u0440\u0438\u043f\u0442<\/strong> \u0434\u043b\u044f <strong>\u0434\u0435\u043f\u043b\u043e\u044f<\/strong> \u0438 \u0432\u044b\u0437\u043e\u0432\u0430 <strong>\u0444\u0443\u043d\u043a\u0446\u0438\u0438<\/strong>, \u043f\u043e\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u043c \u0441 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u043c\u0438 \u0441\u0440\u0435\u0434\u044b (<strong>env<\/strong>), \u0447\u0430\u0441\u0442\u0438\u0447\u043d\u043e \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0438\u0440\u0443\u0435\u043c \u0440\u0430\u0431\u043e\u0442\u0443 \u0441 \u0437\u0430\u043f\u0443\u0441\u043a\u043e\u043c \u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0432 (<strong>Makefile<\/strong>), \u0440\u0430\u0437\u0431\u0435\u0440\u0451\u043c\u0441\u044f \u0432 <strong>\u0444\u043e\u0440\u043a-\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438<\/strong> \u0438 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u043c \u043d\u0430\u0448 \u043f\u0440\u043e\u0435\u043a\u0442 \u0432 \u0442\u0435\u0441\u0442\u043d\u0435\u0442\u0435!<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/5d6\/ab6\/2af\/5d6ab62af93f38ec7670c7a944dffa5c.gif\" alt=\"\u041f\u043e\u0435\u0445\u0430\u043b\u0438!\" title=\"\u041f\u043e\u0435\u0445\u0430\u043b\u0438!\" width=\"320\" height=\"240\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/5d6\/ab6\/2af\/5d6ab62af93f38ec7670c7a944dffa5c.gif\"\/><\/p>\n<div><figcaption>\u041f\u043e\u0435\u0445\u0430\u043b\u0438!<\/figcaption><\/div>\n<\/figure>\n<p><a href=\"https:\/\/habr.com\/ru\/articles\/764576\/\" rel=\"noopener noreferrer nofollow\"><u>1 \u0447\u0430\u0441\u0442\u044c<\/u><\/a><\/p>\n<p><a href=\"https:\/\/github.com\/sudovag3\/foundry-course\/tree\/part-3\" rel=\"noopener noreferrer nofollow\"><u>\u0418\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434 \u043a \u0434\u0430\u043d\u043d\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u043a\u0443\u0440\u0441\u0430<\/u><\/a><\/p>\n<p><a href=\"https:\/\/career.habr.com\/andrey-sudov\" rel=\"noopener noreferrer nofollow\"><u>\u0421\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043c\u043e\u0439 \u0430\u043a\u043a\u0430\u0443\u043d\u0442 \u0432 \u0425\u0430\u0431\u0440 \u041a\u0430\u0440\u044c\u0435\u0440\u0435 (\u0431\u0443\u0434\u0443 \u0440\u0430\u0434 \u0437\u043d\u0430\u043a\u043e\u043c\u0441\u0442\u0432\u0443)<\/u><\/a><\/p>\n<h2>\u0422\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u0440\u043e\u043a\u0441\u0438-\u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u043e\u0432<\/h2>\n<p>\u041d\u0430 \u0440\u0443\u0441\u0441\u043a\u043e\u043c \u044e\u0442\u0443\u0431\u0435 \u0435\u0441\u0442\u044c \u0434\u0432\u0430 \u0437\u0430\u043c\u0435\u0447\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0440\u043e\u043b\u0438\u043a\u0430 \u043f\u0440\u043e \u043f\u0440\u043e\u043a\u0441\u0438-\u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u044b, \u0435\u0441\u043b\u0438 \u0432\u0434\u0440\u0443\u0433 \u0432\u044b \u043d\u0435 \u0437\u043d\u0430\u0435\u0442\u0435, \u0447\u0442\u043e \u044d\u0442\u043e (<a href=\"https:\/\/www.youtube.com\/watch?v=jLoJTc0oj0I&amp;t=4s\" rel=\"noopener noreferrer nofollow\">\u0442\u044b\u043a1 <\/a>\u0438 <a href=\"https:\/\/www.youtube.com\/watch?v=WON6VttFTe0&amp;t=389s\" rel=\"noopener noreferrer nofollow\">\u0442\u044b\u043a2<\/a>). \u042f \u043f\u0440\u0435\u0434\u043f\u043e\u043b\u0430\u0433\u0430\u044e, \u0447\u0442\u043e \u0432\u044b \u043f\u043e\u043d\u0438\u043c\u0430\u0435\u0442\u0435 \u043e\u0441\u043d\u043e\u0432\u043d\u0443\u044e \u0442\u0435\u043e\u0440\u0438\u044e \u0438 \u043d\u0430 \u043d\u0435\u0439 \u043c\u043e\u0436\u043d\u043e \u0441\u0438\u043b\u044c\u043d\u043e \u043d\u0435 \u043e\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0442\u044c\u0441\u044f. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u043f\u0440\u0438\u043c\u0435\u0440 \u043f\u0440\u043e\u043a\u0441\u0438-\u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430 (CounterV1.sol):<\/p>\n<pre><code class=\"cs\">\/\/ SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.19;  import {OwnableUpgradeable} from \"@openzeppelin\/contracts-upgradeable\/access\/OwnableUpgradeable.sol\"; import {UUPSUpgradeable} from \"@openzeppelin\/contracts-upgradeable\/proxy\/utils\/UUPSUpgradeable.sol\"; import {Initializable} from \"@openzeppelin\/contracts-upgradeable\/proxy\/utils\/Initializable.sol\";  \/**  * \u0421\u043e\u0437\u0434\u0430\u0451\u043c \u0430\u0431\u0441\u043e\u043b\u044e\u0442\u043d\u043e \u0442\u0440\u0438\u0432\u0438\u0430\u043b\u044c\u043d\u044b\u0439 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u043e\u0436\u0435\u0442  * \u0434\u043e\u0441\u0442\u0430\u0432\u0430\u0442\u044c \u043e\u0434\u043d\u0443 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e \u0438\u0437 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430  * \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u043e\u0434\u043d\u043e \u043a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435  *\/ contract CounterV1 is Initializable, OwnableUpgradeable, UUPSUpgradeable {     uint256 internal number;      \/\/\/ @custom:oz-upgrades-unsafe-allow constructor     constructor() {         _disableInitializers();     }      function initialize() public initializer {         __Ownable_init(); \/\/\u0434\u0435\u043b\u0430\u0435\u043c transferOwnership \u043d\u0430 msg.sender         __UUPSUpgradeable_init(); \/\/ \u041d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u0434\u0435\u043b\u0430\u0435\u043c :)     }      function getNumber() external view returns (uint256) {         return number;     }      function version() external pure returns (uint256) {         return 1;     }      \/**      * \u0414\u0430\u043d\u043d\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0439, \u0442\u0430\u043a \u043a\u0430\u043a \u043e\u043d\u0430 \u043e\u0431\u044a\u044f\u0432\u043b\u0435\u043d\u0430 \u0432      * \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0442\u043d\u043e\u043c \u043a\u043b\u0430\u0441\u0441\u0435 UUPSUpgradeable, \u043d\u043e \u043d\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0430      * \u0417\u0434\u0435\u0441\u044c \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u043b\u0438\u0448\u044c \u0443\u043a\u0430\u0437\u0430\u0442\u044c, \u043a\u0430\u043a\u0438\u0435 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f \u043c\u044b \u0441\u0442\u0430\u0432\u0438\u043c \u043d\u0430      * \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0442\u044c \u043d\u0430\u0448 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442      * \u0412 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c onlyOwner      * @param newImplementation \u0430\u0434\u0440\u0435\u0441 \u043d\u043e\u0432\u043e\u0433\u043e \u043f\u0440\u043e\u043a\u0441\u0438\u0440\u0443\u0435\u043c\u043e\u0433\u043e \u0430\u0434\u0440\u0435\u0441\u0430      *\/     function _authorizeUpgrade(address newImplementation) internal override onlyOwner {} } <\/code><\/pre>\n<p>CounterV2.sol:<\/p>\n<pre><code class=\"cs\">\/\/ SPDX-License-Identifier: MIT pragma solidity ^0.8.19;  import {OwnableUpgradeable} from \"@openzeppelin\/contracts-upgradeable\/access\/OwnableUpgradeable.sol\"; import {Initializable} from \"@openzeppelin\/contracts-upgradeable\/proxy\/utils\/Initializable.sol\"; import {UUPSUpgradeable} from \"@openzeppelin\/contracts-upgradeable\/proxy\/utils\/UUPSUpgradeable.sol\";  contract CounterV2 is Initializable, OwnableUpgradeable, UUPSUpgradeable {     uint256 internal value;      \/\/\/ @custom:oz-upgrades-unsafe-allow constructor     constructor() {         _disableInitializers();     }      function initialize() public initializer {         __Ownable_init();         __UUPSUpgradeable_init();     }      \/**      * \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043d\u043e\u0432\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u044e, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e\u0441\u0442\u044c      * \u0440\u0430\u0431\u043e\u0442\u044b \u0430\u043f\u0440\u0433\u0440\u0435\u0439\u0434\u0430      *\/     function increment() public {         value++;     }      function getValue() public view returns (uint256) {         return value;     }      \/**      * \u041c\u0435\u043d\u044f\u0435\u043c \u0432\u0435\u0440\u0441\u0438\u044e \u043d\u0430 \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u0443\u044e      *\/     function version() public pure returns (uint256) {         return 2;     }      function _authorizeUpgrade(address newImplementation) internal override onlyOwner {} } <\/code><\/pre>\n<p>\u0418\u0442\u0430\u043a, \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0434\u0432\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u0445 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043e\u0442\u043b\u0438\u0447\u0430\u044e\u0442\u0441\u044f \u0434\u0432\u0443\u043c\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f\u043c\u0438 \u0438 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c. \u041e\u0431\u0430 \u043e\u043d\u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u044b \u043a \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u043c\u044b\u043c \u043f\u0440\u043e\u043a\u0441\u0438-\u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430\u043c.<br \/>\u041d\u0430\u0448\u0430 \u0437\u0430\u0434\u0430\u0447\u0430:<\/p>\n<ul>\n<li>\n<p>\u041d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u043a\u0440\u0438\u043f\u0442 \u0434\u043b\u044f \u0434\u0435\u043f\u043b\u043e\u044f \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430 \u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u043a\u0441\u0438<\/p>\n<\/li>\n<li>\n<p>\u041d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u043a\u0440\u0438\u043f\u0442 \u0434\u043b\u044f \u0430\u043f\u0433\u0440\u0435\u0439\u0434\u0430 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430 \u043d\u0430 V2<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u043e\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0440\u0430\u0431\u043e\u0442\u0443 \u0434\u0430\u043d\u043d\u044b\u0445 \u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0432 \u0438 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u043e\u0432 \u0432 \u0446\u0435\u043b\u043e\u043c<\/p>\n<\/li>\n<\/ul>\n<p>\u0418\u0442\u0430\u043a, \u0432 \u043f\u0430\u043f\u043a\u0435 script \u0441\u043e\u0437\u0434\u0430\u0451\u043c \u043d\u0430\u0448 \u043f\u0435\u0440\u0432\u044b\u0439 \u0441\u043a\u0440\u0438\u043f\u0442 &#8212; DeployCounter.s.sol:<\/p>\n<pre><code class=\"cs\">\/\/ SPDX-License-Identifier: MIT pragma solidity ^0.8.19;  \/\/\u0414\u0430\u043d\u043d\u044b\u0439 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442 \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430 \u0438\u043c\u043f\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044e \u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0432, \u043e\u043d \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0434\u043e\u043b\u0436\u0435\u043d \u043d\u0430\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u044c\u0441\u044f \/\/ \u0432 \u043b\u044e\u0431\u043e\u043c \u0441\u043a\u0440\u0438\u043f\u0442\u0435 import {Script} from \"forge-std\/Script.sol\"; import {CounterV1} from \"..\/src\/CounterV1.sol\"; import {ERC1967Proxy} from \"@openzeppelin\/contracts\/proxy\/ERC1967\/ERC1967Proxy.sol\";  \/**  * \u041a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u044b \u043f\u043e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440 \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043d\u0438\u0447\u0435\u043c \u043d\u0435 \u043e\u0442\u043b\u0438\u0447\u0430\u044e\u0442\u0441\u044f \u043e\u0442 \u0442\u0435\u0441\u0442\u043e\u0432  *\/ contract DeployCounter is Script {     \/**      * \u0417\u0430\u0434\u0430\u0447\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 run() \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u0430:      * \u0417\u0430\u0434\u0435\u043f\u043b\u043e\u0438\u0442\u044c \u043d\u0430\u0448 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442      * \u041e\u043d\u0430 \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c\u0441\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u0440\u0438 \u0432\u044b\u0437\u043e\u0432\u0435      * \u0441\u043a\u0440\u0438\u043f\u0442\u0430, \u0447\u0442\u043e-\u0442\u043e \u0432\u0440\u043e\u0434\u0435 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0430      *\/     function run() external returns (address) {         address proxy = deployCounter();         return proxy;     }      \/**      * \u0417\u0434\u0435\u0441\u044c \u043c\u044b \u0432\u0441\u0442\u0440\u0435\u0447\u0430\u0435\u043c \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0439 \u043c\u0435\u0442\u043e\u0434: vm.startBroadcast()      * \u0414\u0430\u043d\u043d\u044b\u0439 \u043c\u0435\u0442\u043e\u0434 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0443 \u0441\u043e\u0437\u0434\u0430\u0442\u044c      * \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0443\u044e \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u044e \u043e\u043d-\u0447\u0435\u0439\u043d      * \u0417\u0434\u0435\u0441\u044c \u043d\u0435 \u0431\u0443\u0434\u0443\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0447\u0438\u0442-\u043a\u043e\u0434\u044b \u0438 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u044f \u0431\u0443\u0434\u0435\u0442 \"\u043a\u0430\u043a \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0430\u044f\"      * \u0412 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043c\u044b \u0445\u043e\u0442\u0438\u043c, \u0447\u0442\u043e\u0431\u044b \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0435\u0439 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0435\u0439 \u0443 \u043d\u0430\u0441 \u0437\u0430\u0434\u0435\u043f\u043b\u043e\u0438\u043b\u0441\u044f      * \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442 \u0438 \u043f\u0440\u043e\u043a\u0441\u0438 \u043a \u043d\u0435\u043c\u0443      *\/     function deployCounter() public returns (address) {         vm.startBroadcast();         \/\/\u0414\u0435\u043f\u043b\u043e\u0438\u043c \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442 \u043f\u0435\u0440\u0432\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438         CounterV1 counter = new CounterV1();         \/\/\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u0441\u0435\u043b\u0435\u043a\u0442\u043e\u0440 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0441 \u043d\u0443\u0436\u043d\u044b\u043c\u0438 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0430\u043c\u0438         \/\/\u0412 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043d\u0435\u0442, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 ()         bytes memory data = abi.encodeCall(CounterV1.initialize, ());         \/\/\u0414\u0435\u043f\u043b\u043e\u0438\u043c \u043f\u0440\u043e\u043a\u0441\u0438-\u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u044f \u0430\u0434\u0440\u0435\u0441 \u0438\u043c\u043f\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u0438 \u0434\u0430\u043d\u043d\u044b\u0435         \/\/\u043e\u0431 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u044e\u0449\u0435\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438         ERC1967Proxy proxy = new ERC1967Proxy(address(counter), data);         vm.stopBroadcast();         return address(proxy);     } } <\/code><\/pre>\n<p>\u0423\u0440\u0430, \u0441\u043a\u0440\u0438\u043f\u0442 \u0434\u043b\u044f \u0434\u0435\u043f\u043b\u043e\u044f \u0433\u043e\u0442\u043e\u0432! \u041e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u043a\u0440\u0438\u043f\u0442 \u0434\u043b\u044f \u0430\u043f\u0433\u0440\u0435\u0439\u0434\u0430. \u041e\u0434\u043d\u0430\u043a\u043e \u044d\u0442\u043e\u0442 \u0441\u043a\u0440\u0438\u043f\u0442 \u0443\u0436\u0435 \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0432 \u043a\u0443\u0440\u0441\u0435, \u043a\u0430\u043a\u043e\u0439 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442 \u0435\u043c\u0443 \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0442\u044c. \u0421 \u043e\u0434\u043d\u043e\u0439 \u0441\u0442\u043e\u0440\u043e\u043d\u044b, \u043c\u043e\u0436\u043d\u043e \u0445\u0430\u0440\u0434\u043a\u043e\u0434\u0438\u0442\u044c \u0430\u0434\u0440\u0435\u0441 \u0437\u0430\u0434\u0435\u043f\u043b\u043e\u0435\u043d\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u043a\u0441\u0438 \u0432 \u0441\u043a\u0440\u0438\u043f\u0442\u0435 \u0430\u043f\u0433\u0440\u0435\u0439\u0434\u0430, \u043d\u043e \u0441 \u0434\u0440\u0443\u0433\u043e\u0439 \u0441\u0442\u043e\u0440\u043e\u043d\u044b, \u0432 \u0431\u043e\u043b\u044c\u0448\u0438\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445 \u044d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043d\u0438\u043c\u0430\u0442\u044c \u043e\u0447\u0435\u043d\u044c \u043c\u043d\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0438 \u0441\u043e\u0432\u0441\u0435\u043c \u043d\u0435 \u043f\u043e-\u043d\u0430\u0448\u0435\u043c\u0443 \ud83d\ude42 <\/p>\n<h2>Foundry-devops<\/h2>\n<p>\u041a\u043e\u0433\u0434\u0430 \u043c\u044b \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u043a\u0430\u043a\u043e\u0439-\u0442\u043e \u0441\u043a\u0440\u0438\u043f\u0442, <strong>Foundry<\/strong> \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442 \u0432\u0441\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u0434\u0435\u043f\u043b\u043e\u044f\u0445 \u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0439 \u043f\u0430\u043f\u043a\u0435, \u0440\u0430\u0437\u0434\u0435\u043b\u044f\u044f \u0432\u044b\u0437\u043e\u0432\u044b \u043e\u0442 \u043a\u0430\u0436\u0434\u043e\u0439 \u0441\u0435\u0442\u0438. \u041f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u0438\u043c \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0430\u0440\u0441\u0438\u0442 \u044d\u0442\u0443 \u0438\u043d\u0444\u0443 (\u043d\u0430\u0445\u043e\u0434\u0438\u0442 \u0430\u0434\u0440\u0435\u0441 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0433\u043e \u0437\u0430\u0434\u0435\u043f\u043b\u043e\u0435\u043d\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u043a\u0441\u0438) \u0438 \u0432\u044b\u0432\u043e\u0434\u0438\u0442 \u0435\u0451 \u0432 \u0441\u043a\u0440\u0438\u043f\u0442 \u0430\u043f\u0433\u0440\u0435\u0439\u0434\u0430, \u0442\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u043c\u044b \u0438\u0437\u0431\u0430\u0432\u0438\u043c\u0441\u044f \u043e\u0442 \u0445\u0430\u0440\u0434\u043a\u043e\u0434\u0430 \u0438 \u0434\u043e\u0431\u044c\u0451\u043c\u0441\u044f \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0439 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0438. \u0418\u043c\u0435\u043d\u043d\u043e \u0442\u0430\u043a \u043f\u043e\u0441\u0442\u0443\u043f\u0438\u043b\u0430 \u043a\u043e\u043c\u0430\u043d\u0434\u0430 <a href=\"https:\/\/github.com\/Cyfrin\" rel=\"noopener noreferrer nofollow\">Cyfrin<\/a> \u0438 \u0441\u0434\u0435\u043b\u0430\u043b\u0430 \u043e\u0447\u0435\u043d\u044c \u0443\u0434\u043e\u0431\u043d\u044b\u0439 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u0434\u043b\u044f Foundry &#8212; <a href=\"https:\/\/github.com\/Cyfrin\/foundry-devops\" rel=\"noopener noreferrer nofollow\">foundry-devops<\/a>. \u041e\u0446\u0435\u043d\u0438\u043c \u0435\u0433\u043e \u0440\u0430\u0431\u043e\u0442\u0443:<\/p>\n<p>\u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c foundry-devops:<\/p>\n<pre><code class=\"bash\">$ forge install Cyfrin\/foundry-devops@0.0.11 --no-commit<\/code><\/pre>\n<p>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u0435\u0433\u043e, \u043f\u0438\u0448\u0435\u043c \u0441\u043a\u0440\u0438\u043f\u0442 \u0434\u043b\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u043a\u0441\u0438(UpgradeCounter.s.sol):<\/p>\n<pre><code class=\"cs\">\/\/ SPDX-License-Identifier: MIT pragma solidity ^0.8.19;  import {Script, console} from \"forge-std\/Script.sol\"; import {CounterV1} from \"..\/src\/CounterV1.sol\"; import {CounterV2} from \"..\/src\/CounterV2.sol\"; import {ERC1967Proxy} from \"@openzeppelin\/contracts\/proxy\/ERC1967\/ERC1967Proxy.sol\"; import {Helper} from \".\/Helper.s.sol\";  \/\/\u0418\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0439 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442, \u043e\u043d \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u043d\u0430\u043c \u0432 \u0440\u0430\u0431\u043e\u0442\u0435 \u0441 \u043d\u0435\u0434\u0430\u0432\u043d\u043e \u0437\u0430\u0434\u0435\u043f\u043b\u043e\u0435\u043d\u043d\u044b\u043c\u0438 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430\u043c\u0438 import {DevOpsTools} from \"lib\/foundry-devops\/src\/DevOpsTools.sol\";  \/**  * \u041c\u044b \u0441\u043e\u0437\u0434\u0430\u0451\u043c \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442, \u0443 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0431\u0443\u0434\u0435\u0442 \u043b\u0438\u0448\u044c \u043e\u0434\u043d\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u044f:  * \u041e\u0431\u043d\u043e\u0432\u043b\u044f\u0442\u044c \u043d\u0430\u0448 \u043f\u0440\u043e\u043a\u0441\u0438\u0440\u0443\u0435\u043c\u044b\u0439 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442  *\/ contract UpgradeCounter is Helper {     function run() external returns (address) {         \/\/ \u041c\u0435\u0442\u043e\u0434 get_most_recent_deployment()         \/\/ \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0434\u043e\u0441\u0442\u0430\u0442\u044c \u0430\u0434\u0440\u0435\u0441 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0433\u043e \u0437\u0430\u0434\u0435\u043f\u043b\u043e\u0435\u043d\u043d\u043e\u0433\u043e \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430         \/\/ \u043f\u043e \u0437\u0430\u0434\u0430\u043d\u043d\u044b\u043c \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f\u043c: \u041d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430 \u0438 id \u0446\u0435\u043f\u0438,         \/\/ \u0433\u0434\u0435 \u0434\u0430\u043d\u043d\u044b\u0439 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442 \u0434\u0435\u043f\u043b\u043e\u0438\u043b\u0441\u044f         address mostRecentlyDeployedProxy = DevOpsTools.get_most_recent_deployment(\"ERC1967Proxy\", block.chainid);          \/\/\u041c\u044b \u0445\u043e\u0442\u0438\u043c \u043f\u043e-\u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0435\u043c\u0443 \u0437\u0430\u0434\u0435\u043f\u043b\u043e\u0438\u0442\u044c \u043d\u043e\u0432\u0443\u044e \u0432\u0435\u0440\u0441\u0438\u044e \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430,         \/\/\u043f\u043e\u044d\u0442\u043e\u043c\u0443 startBroadcast()         vm.startBroadcast();         CounterV2 newCounter = new CounterV2();         vm.stopBroadcast();         \/\/\u041e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u043c \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442         address proxy = upgradeCounter(mostRecentlyDeployedProxy, address(newCounter));          return proxy;     }      function upgradeCounter(address proxyAddress, address newCounter) public returns (address) {         vm.startBroadcast();         \/\/payable - \u044d\u0442\u043e \u0432\u0430\u0436\u043d\u044b\u0439 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440, \u043d\u0435 \u0437\u0430\u0431\u044b\u0432\u0430\u0435\u043c \u043f\u0440\u043e \u043d\u0435\u0433\u043e         \/\/(\u043d\u044e\u0430\u043d\u0441 \u043f\u0440\u043e\u043a\u0438-\u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u043e\u0432)         CounterV1 proxy = CounterV1(payable(proxyAddress));         proxy.upgradeTo(address(newCounter));         vm.stopBroadcast();         return address(proxy);     } } <\/code><\/pre>\n<p>\u0423\u0440\u0430! \u0422\u0435\u043f\u0435\u0440\u044c \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0442\u0435\u0441\u0442, \u043d\u043e \u043f\u0435\u0440\u0435\u0434 \u044d\u0442\u0438\u043c \u0441\u0442\u043e\u0438\u0442 \u0435\u0433\u043e \u043f\u0440\u043e\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c. \u0422\u0435\u0441\u0442\u044b \u043c\u044b \u043f\u0438\u0441\u0430\u0442\u044c \u0443\u0436\u0435 \u0443\u043c\u0435\u0435\u043c, \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u043e\u0432\u043e\u0433\u043e \u0437\u0434\u0435\u0441\u044c \u043c\u044b \u043d\u0435 \u043d\u0430\u0439\u0434\u0451\u043c \u0437\u0430 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435\u043c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0438\u0445 \u0445\u0438\u0442\u0440\u043e\u0441\u0442\u0435\u0439, \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0445 \u0441 \u043f\u0440\u043e\u043a\u0441\u0438 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430\u043c\u0438 (CounterTest.t.sol):<\/p>\n<pre><code class=\"cs\">\/\/ SPDX-License-Identifier: MIT  pragma solidity ^0.8.19;  import {DeployCounter} from \"..\/script\/DeployCounter.s.sol\"; import {UpgradeCounter} from \"..\/script\/UpgradeCounter.s.sol\"; import {Test, console} from \"forge-std\/Test.sol\"; import {CounterV1} from \"..\/src\/CounterV1.sol\"; import {CounterV2} from \"..\/src\/CounterV2.sol\"; import {Helper} from \"..\/script\/Helper.s.sol\"; import {ERC20} from \"@openzeppelin\/contracts\/token\/ERC20\/ERC20.sol\";  \/**  * \u041e\u0447\u0435\u043d\u044c \u0432\u0430\u0436\u043d\u043e \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0440\u0430\u0431\u043e\u0442\u0443 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0445 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u043e\u0432,  * \u043d\u043e \u0438 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u043e\u0432-\u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0432, \u0432\u0435\u0434\u044c \u043e\u043d\u0438 \u0442\u043e\u0436\u0435 \u0431\u0443\u0434\u0443\u0442 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0442\u044c \u0443\u0447\u0430\u0441\u0442\u0438\u0435  * \u0432 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0445 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0439  * \u0412 \u0440\u0430\u043c\u043a\u0430\u0445 \u044d\u0442\u043e\u0433\u043e \u0442\u0435\u0441\u0442\u0430 \u043c\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u043c \u0440\u0430\u0431\u043e\u0442\u0443 \u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0432 \u043d\u0430 \u0434\u0435\u043f\u043b\u043e\u0439 \u0438 \u0430\u043f\u0433\u0440\u0435\u0439\u0434  * \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u043e\u0432  *\/ contract DeployAndUpgradeTest is Test {     DeployCounter public deployCounter;     UpgradeCounter public upgradeCounter;      function setUp() public {         deployCounter = new DeployCounter();         upgradeCounter = new UpgradeCounter();     }      \/**      * \u0412 \u044d\u0442\u043e\u043c \u0442\u0435\u0441\u0442\u0435 \u043c\u044b \u0434\u0435\u043f\u043b\u043e\u0438\u043c \u043f\u0435\u0440\u0432\u0443\u044e \u0432\u0435\u0440\u0441\u0438\u044e \u043d\u0430\u0448\u0435\u0433\u043e \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430      * \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e\u0441\u0442\u044c \u0440\u0430\u0431\u043e\u0442\u044b \u0447\u0435\u0440\u0435\u0437 \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430      * version      *\/     function testCounterWorks() public {         address proxyAddress = deployCounter.deployCounter();         uint256 expectedValue = 1;         assertEq(expectedValue, CounterV1(proxyAddress).version());     }      \/**      * \u0412 \u044d\u0442\u043e\u043c \u0442\u0435\u0441\u0442\u0435 \u0438\u0434\u0451\u0442 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0437\u0430\u0441\u0447\u0451\u0442      * \u043f\u043e\u043f\u044b\u0442\u043a\u0438 \u0432\u044b\u0437\u043e\u0432\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0438\u0437 \u0434\u0440\u0443\u0433\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438      * \u0412 Foundry \u0440\u0430\u0431\u043e\u0442\u0430 \u0441 UUPS \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u0442\u0440\u0438\u0432\u0438\u0430\u043b\u044c\u043d\u0430:      * \u0414\u043b\u044f \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u043a \u043f\u0440\u043e\u043a\u0441\u0438 \u043c\u044b \u043f\u0440\u043e\u0441\u0442\u043e \u043e\u0431\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0435\u043c \u0435\u0433\u043e \u0430\u0434\u0440\u0435\u0441      * \u0432 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0443\u044e\u0449\u0438\u0439 \u043d\u0430\u0441 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442, \u0442.\u0435.      * \u0432\u0441\u044f \u043e\u0442\u0432\u0435\u0442\u0441\u0432\u0435\u043d\u043d\u043e\u0441\u0442\u044c \u0437\u0430 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e\u0441\u0442\u044c \u043b\u0435\u0436\u0438\u0442 \u043d\u0430 \u043d\u0430\u0441      *\/     function testDeploymentIsV1() public {         address proxyAddress = deployCounter.deployCounter();         vm.expectRevert();         CounterV2(proxyAddress).increment();     }      \/**      * \u0410\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e \u0437\u0434\u0435\u0441\u044c \u043c\u044b \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e upgradeCounter \u0438 \u043f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e      * \u043e\u0431\u0440\u0430\u0449\u0430\u0435\u043c\u0441\u044f \u043a \u0430\u0434\u0440\u0435\u0441\u0443 \u0443\u0436\u0435 \u043a\u0430\u043a \u043a\u043e \u0432\u0442\u043e\u0440\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u0438 \u0443\u0431\u0435\u0436\u0434\u0430\u0435\u043c\u0441\u044f, \u0447\u0442\u043e \u0432\u0441\u0451 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442      *\/     function testUpgradeWorks() public {         address proxyAddress = deployCounter.deployCounter();          CounterV2 Counter2 = new CounterV2();          address proxy = upgradeCounter.upgradeCounter(proxyAddress, address(Counter2));          uint256 expectedValue = 2;         assertEq(expectedValue, CounterV2(proxy).version());          CounterV2(proxy).increment();         assertEq(1, CounterV2(proxy).getValue());     } } <\/code><\/pre>\n<p>\u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u0442\u0435\u0441\u0442\u044b \u0438 \u0443\u0431\u0435\u0436\u0434\u0430\u0435\u043c\u0441\u044f \u0432 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e\u0441\u0442\u0438 \u0440\u0430\u0431\u043e\u0442\u044b.<\/p>\n<h2>\u0414\u0435\u043f\u043b\u043e\u0439 \u0432 \u0442\u0435\u0441\u0442\u043d\u0435\u0442<\/h2>\n<p>\u041f\u043e\u0440\u0430 \u0440\u0430\u0437\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0442\u044c \u0432\u0441\u0451 \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0439 \u0431\u043b\u043e\u043a\u0447\u0435\u0439\u043d! \u041f\u0435\u0440\u0435\u0434 \u044d\u0442\u0438\u043c \u043f\u0440\u043e\u0434\u0435\u043b\u0430\u0435\u043c \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0448\u0430\u0433\u043e\u0432:<\/p>\n<ul>\n<li>\n<p>\u0421\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u0444\u0430\u0439\u043b .env, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0431\u0443\u0434\u0443\u0442 \u0445\u0440\u0430\u043d\u0438\u0442\u0441\u044f \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0441\u0440\u0435\u0434\u044b:<br \/>(<strong>\u0412\u041d\u0418\u041c\u0410\u041d\u0418\u0415<\/strong>: \u0414\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u044d\u0442\u043e\u0442 \u0444\u0430\u0439\u043b \u0432 .gitignore, \u043d\u0435 \u0434\u043e\u043f\u0443\u0441\u043a\u0430\u0439\u0442\u0435 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u044d\u0442\u043e\u0442 \u0444\u0430\u0439\u043b \u0443\u0448\u0451\u043b \u043a\u0443\u0434\u0430-\u0442\u043e \u0437\u0430 \u043f\u0440\u0435\u0434\u0435\u043b\u044b \u0432\u0430\u0448\u0435\u0433\u043e \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440\u0430)<\/p>\n<\/li>\n<\/ul>\n<pre><code>SEPOLIA_RPC= PRIVATE_KEY= ETHERSCAN_API_KEY=<\/code><\/pre>\n<ul>\n<li>\n<p>\u0427\u0435\u0440\u0435\u0437 \u041c\u0435\u0442\u0430\u043c\u0430\u0441\u043a (\u0438\u043b\u0438 \u043b\u044e\u0431\u043e\u0439 \u0434\u0440\u0443\u0433\u043e\u0439 \u043a\u043e\u0448\u0435\u043b\u0451\u043a) <a href=\"https:\/\/www.youtube.com\/watch?v=4MO2jn22aa8\" rel=\"noopener noreferrer nofollow\">\u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u0435\u043c\u0441\u044f \u043d\u0430 \u0442\u0435\u0441\u0442\u043e\u0432\u0443\u044e \u0441\u0435\u0442\u044c Sepolia<\/a> \u0438 <a href=\"https:\/\/sepoliafaucet.com\/\" rel=\"noopener noreferrer nofollow\">\u0434\u043e\u0441\u0442\u0430\u0451\u043c \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0435 \u044d\u0444\u0438\u0440\u044b<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/www.youtube.com\/watch?v=nRK8Z2jytr8\" rel=\"noopener noreferrer nofollow\">\u0414\u043e\u0441\u0442\u0430\u0451\u043c \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u0439 \u043a\u043b\u044e\u0447<\/a> \u043e\u0442 \u0430\u043a\u043a\u0430\u0443\u043d\u0442\u0430, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0439 \u044d\u0444\u0438\u0440 \u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0435\u0433\u043e \u0432 .env<\/p>\n<\/li>\n<li>\n<p>\u0414\u043e\u0441\u0442\u0430\u0451\u043c \u0430\u0434\u0440\u0435\u0441 RPC-\u043d\u043e\u0434\u044b \u043e\u0442 \u043d\u0430\u0448\u0435\u0433\u043e \u0442\u0435\u0441\u0442\u043d\u0435\u0442\u0430<br \/><strong>\u0420\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u0435\u043c\u044b\u0439 \u0441\u043f\u043e\u0441\u043e\u0431<\/strong>: \u0420\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0443\u0435\u043c\u0441\u044f \u0432 <a href=\"https:\/\/www.alchemy.com\/\" rel=\"noopener noreferrer nofollow\">alchemy <\/a>(c \u0412\u041f\u041d), \u043f\u043e\u043f\u0430\u0434\u0430\u0435\u043c \u043d\u0430 \u0433\u043b\u0430\u0432\u043d\u044b\u0439 \u0434\u044d\u0448\u0431\u043e\u0440\u0434 \u0438 \u0437\u0430\u0445\u043e\u0434\u0438\u043c \u043d\u0430 <a href=\"https:\/\/dashboard.alchemy.com\/apps\" rel=\"noopener noreferrer nofollow\">\u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 \u0441 \u043d\u0430\u0448\u0438\u043c\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u043c\u0438<\/a>, \u041d\u0430\u0436\u0438\u043c\u0430\u0435\u043c <strong>Create new app, <\/strong>\u0432\u044b\u0431\u0438\u0440\u0430\u0435\u043c \u043d\u0443\u0436\u043d\u0443\u044e \u043d\u0430\u043c \u0441\u0435\u0442\u044c (Ethereum, Sepolia) \u0438 \u0437\u0430\u043f\u043e\u043b\u043d\u044f\u0435\u043c \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u043f\u043e\u043b\u044f. \u041f\u043e\u0441\u043b\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043d\u0430\u0445\u043e\u0434\u0438\u043c \u043a\u043d\u043e\u043f\u043a\u0443 API Key \u0438 \u043a\u043e\u043f\u0438\u0440\u0443\u0435\u043c \u0432 .env \u0444\u0430\u0439\u043b \u043f\u0443\u043d\u043a\u0442 <strong>HTTPS<\/strong> <\/p>\n<\/li>\n<li>\n<p>ETHERSCAN_API_KEY \u043d\u0430\u043c \u043d\u0443\u0436\u0435\u043d \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u044b \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0432\u0435\u0440\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u043b\u0438\u0441\u044c \u043f\u0440\u0438 \u0434\u0435\u043f\u043b\u043e\u0435 (<a href=\"https:\/\/docs.etherscan.io\/getting-started\/viewing-api-usage-statistics\" rel=\"noopener noreferrer nofollow\">\u043d\u0430\u0433\u043b\u044f\u0434\u043d\u0430\u044f \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f \u043f\u043e \u0442\u043e\u043c\u0443, \u043a\u0430\u043a \u0435\u0433\u043e \u0434\u043e\u0431\u044b\u0442\u044c<\/a>)<\/p>\n<\/li>\n<\/ul>\n<p>\u041e\u0442\u043b\u0438\u0447\u043d\u043e, \u0442\u0435\u043f\u0435\u0440\u044c \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u0439 \u043a\u043b\u044e\u0447, RPC \u0438 \u0434\u0430\u0436\u0435 API \u0434\u043b\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0439 \u0432\u0435\u0440\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438!<\/p>\n<p>\u041f\u0440\u0438\u0448\u043b\u0430 \u043f\u043e\u0440\u0430 \u0434\u0435\u043f\u043b\u043e\u0438\u0442\u044c \u043d\u0430\u0448 \u043f\u0440\u043e\u043a\u0441\u0438.<\/p>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u043c \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0441\u0440\u0435\u0434\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u043b\u0438:<\/p>\n<pre><code class=\"bash\">$ source .env<\/code><\/pre>\n<p>\u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u043d\u0430\u0448 \u0441\u043a\u0440\u0438\u043f\u0442:<\/p>\n<pre><code class=\"bash\">$ forge script script\/DeployCounter.s.sol:DeployCounter --rpc-url $SEPOLIA_RPC --private-key $PRIVATE_KEY --broadcast --verify --etherscan-api-key $ETHERSCAN_API_KEY -vvvv<\/code><\/pre>\n<ul>\n<li>\n<p><code>forge script script\/DeployCounter.s.sol:DeployCounter<\/code> &#8212; \u0437\u0434\u0435\u0441\u044c \u043c\u044b \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c, \u043a\u0430\u043a\u043e\u0439 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u043a\u0430\u043a \u0441\u043a\u0440\u0438\u043f\u0442, \u0432\u0435\u0434\u044c \u0432 \u043e\u0434\u043d\u043e\u043c \u0444\u0430\u0439\u043b\u0435 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u043e\u0432<\/p>\n<\/li>\n<li>\n<p><code>--rpc-url $SEPOLIA_RPC<\/code> &#8212; \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c Foundry, \u043a\u0443\u0434\u0430 \u043e\u0431\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u0441\u043e \u0432\u0441\u0435\u043c\u0438 \u043e\u043d-\u0447\u0435\u0439\u043d \u043a\u043e\u043c\u0430\u043d\u0434\u0430\u043c\u0438<\/p>\n<\/li>\n<li>\n<p> <code>--private-key $PRIVATE_KEY<\/code> &#8212; \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u0439 \u043a\u043b\u044e\u0447, \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u043d\u0443\u0436\u043d\u043e \u043f\u043e\u0434\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u0432\u0441\u0435 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0438<\/p>\n<\/li>\n<li>\n<p><code>--verify --etherscan-api-key $ETHERSCAN_API_KEY<\/code> &#8212; \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c Foundry, \u0447\u0442\u043e \u0432\u0441\u0435 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u044b \u043f\u0440\u0438 \u0434\u0435\u043f\u043b\u043e\u0435 \u043d\u0443\u0436\u043d\u043e \u0432\u0435\u0440\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438 \u043f\u043e \u043a\u0430\u043a\u043e\u043c\u0443 API \u043a\u043b\u044e\u0447\u0443<\/p>\n<\/li>\n<\/ul>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043a\u043e\u043c\u0430\u043d\u0434\u044b, \u0435\u0441\u043b\u0438 \u0432\u0441\u0451 \u043f\u0440\u043e\u0448\u043b\u043e \u0443\u0441\u043f\u0435\u0448\u043d\u043e, \u0432\u044b \u0443\u0432\u0438\u0434\u0438\u0442\u0435 \u043c\u043d\u043e\u0433\u043e \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u043b\u043e\u0433\u043e\u0432, \u0434\u0432\u0430 \u0437\u0430\u0434\u0435\u043f\u043b\u043e\u0435\u043d\u043d\u044b\u0445 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430 \u0438 \u0441\u0442\u0430\u0442\u0443\u0441 \u0438\u0445 \u0432\u0435\u0440\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438. \u0422\u0435\u043f\u0435\u0440\u044c \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0437\u0430\u0439\u0442\u0438 \u043d\u0430 <a href=\"https:\/\/sepolia.etherscan.io\/\" rel=\"noopener noreferrer nofollow\">etherscan \u0442\u0435\u0441\u0442\u043d\u0435\u0442\u0430<\/a> \u0438 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043d\u0430 \u0432\u0430\u0448\u0438 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u044b. <\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e, \u043a\u0430\u043a \u0432\u044b \u043f\u043e\u0442\u044b\u043a\u0430\u043b\u0438 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442 \u0438 \u0443\u0434\u043e\u0441\u0442\u043e\u0432\u0435\u0440\u0438\u043b\u0438\u0441\u044c, \u0447\u0442\u043e \u044d\u0442\u043e \u0442\u043e\u0447\u043d\u043e \u043f\u0435\u0440\u0432\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0435\u0451 \u043e\u0431\u043d\u043e\u0432\u0438\u043c!<\/p>\n<pre><code class=\"bash\">$ forge script script\/UpgradeCounter.s.sol:UpgradeCounter --rpc-url $SEPOLIA_RPC --private-key $PRIVATE_KEY --broadcast --verify --etherscan-api-key $ETHERSCAN_API_KEY --ffi -vvvv<\/code><\/pre>\n<ul>\n<li>\n<p><code>--ffi<\/code> \u0444\u043b\u0430\u0433 \u0440\u0430\u0437\u0440\u0435\u0448\u0430\u0435\u0442 <strong>Foundry<\/strong> \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <strong>external<\/strong> \u0432\u044b\u0437\u043e\u0432\u044b \u043a \u043b\u044e\u0431\u044b\u043c \u0432\u043d\u0435\u0448\u043d\u0438\u043c \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430\u043c. \u041f\u0440\u0438\u0434\u0443\u043c\u0430\u043d \u0434\u043b\u044f \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0435\u043d\u0438\u044f \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438.<\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u044f \u0441\u043a\u0440\u0438\u043f\u0442\u0430 \u0443\u0434\u043e\u0441\u0442\u043e\u0432\u0435\u0440\u044f\u0435\u043c\u0441\u044f \u0432 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e\u0441\u0442\u0438 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f!<\/p>\n<\/li>\n<\/ul>\n<h2>\u0420\u0430\u0431\u043e\u0442\u0430 \u0441 \u043e\u0448\u0438\u0431\u043a\u0430\u043c\u0438 \u0441 Foundry-Devops<\/h2>\n<p>\u0412 \u043c\u043e\u0451\u043c \u043e\u043f\u044b\u0442\u0435 \u0440\u0430\u0431\u043e\u0442\u044b \u044f \u0432\u0441\u0442\u0440\u0435\u0447\u0430\u043b \u0434\u0432\u0435 \u043e\u0448\u0438\u0431\u043a\u0438 \u043f\u0440\u0438 \u0440\u0430\u0431\u043e\u0442\u0435 \u0441 \u043c\u0435\u0442\u043e\u0434\u043e\u043c <strong>get_most_recent_deployment():<\/strong><\/p>\n<ul>\n<li>\n<p>\u041f\u0435\u0440\u0432\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430 (<strong>Error: No contract deployed<\/strong>) \u0431\u044b\u043b\u0430 \u0441\u0432\u044f\u0437\u0430\u043d\u0430 \u0441 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0435\u043c \u043f\u0430\u043a\u0435\u0442\u0430 <strong>jq<\/strong> (<a href=\"https:\/\/github.com\/Cyfrin\/foundry-full-course-f23\/discussions\/58\" rel=\"noopener noreferrer nofollow\">\u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0438 \u0440\u0435\u0448\u0435\u043d\u0438\u0435<\/a>)<\/p>\n<\/li>\n<li>\n<p>\u0412\u0442\u043e\u0440\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430 (<strong>&#8216;\\r&#8217;: command not found<\/strong>) \u0441\u0432\u044f\u0437\u0430\u043d\u0430 \u0441 \u043d\u044e\u0430\u043d\u0441\u0430\u043c\u0438 WSL (<a href=\"https:\/\/stackoverflow.com\/a\/11617204\" rel=\"noopener noreferrer nofollow\">\u0440\u0435\u0448\u0435\u043d\u0438\u0435 <\/a>&#8212; \u0441\u0434\u0435\u043b\u0430\u0442\u044c <strong>doc2unix<\/strong> \u043d\u0430 \u0438\u0441\u043f\u043e\u043b\u043d\u044f\u0435\u043c\u044b\u0439 \u0444\u0430\u0439\u043b (&#8230;<em>lib\/foundry-devops\/src\/get_recent_deployment.sh<\/em>))<\/p>\n<\/li>\n<\/ul>\n<h2>Makefile<\/h2>\n<p>\u041a\u043e\u043c\u0430\u043d\u0434\u044b \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0432 \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0433\u0440\u043e\u043c\u043e\u0437\u0434\u043a\u0438\u0435 \u0438 \u0431\u044b\u043b\u043e \u0431\u044b \u043d\u0435\u043f\u043b\u043e\u0445\u043e \u0438\u0445 \u0441\u043e\u043a\u0440\u0430\u0442\u0438\u0442\u044c. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0442 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0435 Makefile&#8217;\u044b. \u0414\u043b\u044f \u043b\u044e\u0431\u043e\u043f\u044b\u0442\u043d\u044b\u0445 <a href=\"https:\/\/blog.skillfactory.ru\/glossary\/makefile\/\" rel=\"noopener noreferrer nofollow\">\u0441\u044e\u0434\u0430<\/a>, \u0434\u043b\u044f \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0445 &#8212; \u0432 \u0434\u0430\u043d\u043d\u043e\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c make \u043a\u0430\u043a \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0449\u0438\u0439 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c  \u0434\u043b\u0438\u043d\u043d\u044b\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u043a\u043e\u043c\u0430\u043d\u0434\u0430\u043c\u0438 \u043f\u043e\u043a\u043e\u0440\u043e\u0447\u0435. <br \/>\u0421\u043e\u0437\u0434\u0430\u0451\u043c \u0432 \u043f\u0430\u043f\u043a\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0444\u0430\u0439\u043b (Makefile):<\/p>\n<pre><code class=\"bash\">-include .env  build:; forge build  deploy-sepolia: forge script script\/DeployCounter.s.sol:DeployCounter --rpc-url $(SEPOLIA_RPC) --private-key $(PRIVATE_KEY) --broadcast --verify --etherscan-api-key $(ETHERSCAN_API_KEY) -vvvv  upgrade-sepolia: forge script script\/UpgradeCounter.s.sol:UpgradeCounter --rpc-url $(SEPOLIA_RPC) --private-key $(PRIVATE_KEY) --broadcast --verify --etherscan-api-key $(ETHERSCAN_API_KEY) --ffi -vvvv <\/code><\/pre>\n<p>\u041c\u043d\u0435 \u043a\u0430\u0436\u0435\u0442\u0441\u044f, \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043d\u044f\u0442\u044c, \u0447\u0442\u043e \u0437\u0434\u0435\u0441\u044c \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442:<\/p>\n<p>\u0412 \u043f\u0435\u0440\u0432\u043e\u0439 \u0441\u0442\u0440\u043e\u0447\u043a\u0435 \u043c\u044b \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u043c \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0441\u0440\u0435\u0434\u044b, \u0430 \u0434\u0430\u043b\u0435\u0435 \u043e\u0431\u044a\u044f\u0432\u043b\u044f\u0435\u043c \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0438 \u0442\u0435 \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0434\u043e\u043b\u0436\u043d\u044b \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f \u043f\u043e \u044d\u0442\u0438\u043c \u043a\u043e\u043c\u0430\u043d\u0434\u0430\u043c. \u0422\u0435\u043f\u0435\u0440\u044c, \u0447\u0442\u043e\u0431\u044b \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0442\u043e\u0442 \u0436\u0435 \u0441\u043a\u0440\u0438\u043f\u0442 \u0434\u0435\u043f\u043b\u043e\u044f, \u043d\u0430\u043c \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c:<\/p>\n<pre><code class=\"bash\">$ make deploy-sepolia<\/code><\/pre>\n<p>\u0423\u0434\u043e\u0431\u043d\u043e!<\/p>\n<h2>Fork tests (&#8212;fork-url)<\/h2>\n<p>\u0418\u043d\u043e\u0433\u0434\u0430 \u043d\u0430\u043c \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043d\u0443\u0436\u043d\u044b \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0441 \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0445 \u0441\u0435\u0442\u0435\u0439 (\u043c\u0435\u0439\u043d\u043d\u0435\u0442\u0430, \u0442\u0435\u0441\u0442\u043d\u0435\u0442\u0430), \u043d\u043e \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u043d\u0435 \u0445\u043e\u0447\u0435\u0442\u0441\u044f \u0442\u0440\u0430\u0442\u0438\u0442\u044c \u0433\u0430\u0437, \u0434\u0435\u043f\u043b\u043e\u0438\u0442\u044c \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u044b \u0438 \u0432\u0441\u0451 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c.<br \/>\u0412 \u043a\u043e\u043c\u0430\u043d\u0434\u0435 \u0437\u0430\u043f\u0443\u0441\u043a\u043e\u0432 \u0442\u0435\u0441\u0442\u043e\u0432 \u0435\u0441\u0442\u044c \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0439 \u043a\u043b\u044e\u0447 &#8212; (&#8212;fork-url), \u043f\u043e\u0441\u043b\u0435 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043d\u0443\u0436\u043d\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c RPC-\u0430\u0434\u0440\u0435\u0441 \u043d\u0443\u0436\u043d\u043e\u0439 \u0441\u0435\u0442\u0438<br \/>\u0415\u0441\u043b\u0438 \u0435\u0433\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c, \u043f\u0440\u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 Foundry \u0441\u043c\u043e\u0436\u0435\u0442 \u043e\u0431\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u043a \u0432\u043d\u0435\u0448\u043d\u0438\u043c \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430\u043c \u0438\u0437 \u0434\u0440\u0443\u0433\u043e\u0439 \u0441\u0435\u0442\u0438 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0440\u0430\u0437\u0431\u0435\u0440\u0451\u043c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u043f\u0440\u0438\u043c\u0435\u0440 \u0438 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u043c \u043d\u0430\u0448 \u0442\u0435\u0441\u0442:<\/p>\n<pre><code class=\"cs\">...     \/**      * \u0414\u0430\u043d\u043d\u0430\u044f \u0442\u0435\u0441\u0442\u043e\u0432\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u043d\u0435 \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0441\u044f \u043a \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e \u043f\u0440\u043e\u043a\u0441\u0438-\u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u043e\u0432,      * \u043e\u0434\u043d\u0430\u043a\u043e \u043e\u043d\u0430 \u043e\u0447\u0435\u043d\u044c \u043d\u0430\u0433\u043b\u044f\u0434\u043d\u043e \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0438\u0440\u0443\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0443 \u0444\u043e\u0440\u043a\u043e\u0432      * \u0412 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0440\u0430\u0431\u043e\u0430\u0442\u0430\u0442\u044c \u0441 \u0444\u043e\u0440\u043a\u043e\u043c \u0442\u0435\u0441\u0442\u043d\u0435\u0442\u0430 Sepolia      * \u0421\u0443\u0442\u044c \u0440\u0430\u0431\u043e\u0442\u044b \u043f\u0440\u043e\u0441\u0442\u0430:      * \u041f\u0440\u0438 \u0440\u0430\u0431\u043e\u0442\u0435 \u0441 \u0444\u043e\u0440\u043a\u043e\u043c \u043d\u0430\u0448\u0438 \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u0431\u0443\u0434\u0443\u0442 \u0438\u0434\u0442\u0438 \u043a RPC-\u043d\u043e\u0434\u0435 \u043d\u0430\u0448\u0435\u0433\u043e \u0442\u0435\u0441\u0442\u043d\u0435\u0442\u0430      * \u041f\u0440\u0438 \u044d\u0442\u043e\u043c \u0440\u0435\u0430\u043b\u044c\u043d\u043e \u043c\u044b \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u0434\u0435\u043f\u043b\u043e\u0438\u043c, \u0430 \u043f\u0440\u043e\u0441\u0442\u043e \u0447\u0438\u0442\u0430\u0435\u043c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e      * \u042d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0438 \u0441 \u043f\u0440\u043e\u0434\u0430\u043a\u0448\u043d\u0430 \u0431\u0435\u0437 \u043d\u0430\u0434\u043e\u0431\u043d\u043e\u0441\u0442\u0438 \u0447\u0442\u043e-\u0442\u043e      * \u0434\u0435\u043f\u043b\u043e\u0438\u0442\u044c \u0438\u043b\u0438 \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0445 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u044f\u0445      *\/      function testForkTotalSupply() public {         \/\/\u0417\u0430 \u043f\u0440\u0438\u043c\u0435\u0440 \u0432\u043e\u0437\u044c\u043c\u0451\u043c \u0442\u0430\u043a\u043e\u0439 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u0442\u043e\u043a\u0435\u043d\u043e\u0432, \u043a\u0430\u043a decimals         \/\/\u042d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0430\u0431\u0441\u043e\u043b\u044e\u0442\u043d\u043e \u043b\u044e\u0431\u043e\u0439 \u0434\u0440\u0443\u0433\u043e\u0439 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440         \/\/\u0413\u043b\u0430\u0432\u043d\u043e\u0435, \u0447\u0442\u043e\u0431\u044b \u043e\u043d \u0445\u0440\u0430\u043d\u0438\u043b\u0441\u044f \u0432 \u043a\u0430\u043a\u043e\u0439-\u0442\u043e \u0441\u0435\u0442\u0438.         \/\/\u041d\u0430\u043c \u0435\u0433\u043e \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0442\u044c         uint256 decimals;         \/\/chainId - id \u0446\u0435\u043f\u0438, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043c\u044b \u0441\u0435\u0447\u0430\u0441 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u043c         \/\/ 11155111 - \u044d\u0442\u043e id \u043e\u0442 Sepolia         \/\/ \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0435 chainId \u043c\u043e\u0436\u043d\u043e \u0431\u0435\u0437 \u043f\u0440\u043e\u0431\u043b\u0435\u043c \u043d\u0430\u0439\u0442\u0438 \u0432 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0430\u0445         if (block.chainid == 11155111) {             console.log(\"Fork testing!\");             \/\/\u0415\u0441\u043b\u0438 \u043c\u044b \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u043c \u0441 \u0444\u043e\u0440\u043a\u043e\u043c \u0441\u0435\u043f\u043e\u043b\u0438\u0438, \u0442\u043e \u043c\u044b \u043e\u0431\u0440\u0430\u0449\u0430\u0435\u043c\u0441\u044f \u043a \u0440\u0435\u0430\u043b\u044c\u043d\u043e             \/\/\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u043c\u0443 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0443 \u0442\u043e\u043a\u0435\u043d\u0430 ERC20 \u043d\u0430 \u0442\u0435\u0441\u0442\u043d\u0435\u0442\u0435 \u0438 \u0447\u0438\u0442\u0430\u0435\u043c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440             \/\/decimals()             decimals = ERC20(0x94a9D9AC8a22534E3FaCa9F4e7F2E2cf85d5E4C8).decimals();             assertEq(decimals, 6);         } else {             console.log(\"Standart testing!\");             \/\/\u0412 \u043f\u0440\u043e\u0442\u0438\u0432\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0443\u0431\u0435\u0434\u0438\u0442\u044c\u0441\u044f, \u0447\u0442\u043e \u0442\u0430\u043a\u043e\u0433\u043e \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430 \u0432\u043e\u043e\u0431\u0449\u0435             \/\/\u043d\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 - \u043e\u043d \u0434\u0430\u0436\u0435 \u043d\u0435 \u0437\u0430\u0434\u0435\u043f\u043b\u043e\u0435\u043d             \/\/\u0425\u0438\u0442\u0440\u043e\u0441\u0442\u044c: \u0443 \u0430\u0434\u0440\u0435\u0441\u0430 \u0435\u0441\u0442\u044c \u043f\u043e\u043b\u0435 code, \u0433\u0434\u0435 \u0445\u0440\u0430\u043d\u0438\u0442\u0441\u044f \u043a\u043e\u0434 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430             \/\/(\u0432 \u0441\u043b\u0443\u0447\u0430\u0435, \u0435\u0441\u043b\u0438 \u044d\u0442\u043e\u0442 \u0430\u0434\u0440\u0435\u0441 \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0441\u044f \u043a \u0441\u043c\u0430\u0440\u0442-\u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0443)             \/\/\u0412 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u043d \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u043f\u0443\u0441\u0442\u044b\u043c             assertEq(address(0x94a9D9AC8a22534E3FaCa9F4e7F2E2cf85d5E4C8).code.length, 0);         }     } ...   <\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043e\u0431\u043d\u043e\u0432\u0438\u043c \u043d\u0430\u0448 MakeFile:<\/p>\n<pre><code class=\"bash\">... test-sepolia: forge test --fork-url $(SEPOLIA_RPC) -vvv<\/code><\/pre>\n<p>\u0417\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u0435 \u0442\u0435\u0441\u0442 \u0441 \u0444\u043e\u0440\u043a\u043e\u043c \u0438 \u0431\u0435\u0437 \u0438 \u0443\u0431\u0435\u0434\u0438\u0442\u0435\u0441\u044c \u0432 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e\u0441\u0442\u0438 \u0440\u0430\u0431\u043e\u0442\u044b \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b!<\/p>\n<h2>\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/h2>\n<p>\u0414\u043e\u0440\u043e\u0433\u0438\u0435 \u0434\u0440\u0443\u0437\u044c\u044f! \u0422\u0435\u043f\u0435\u0440\u044c \u0432\u044b \u043e\u0431\u043b\u0430\u0434\u0430\u0435\u0442\u0435 <strong>\u0432\u0441\u0435\u043c\u0438 \u0431\u0430\u0437\u043e\u0432\u044b\u043c\u0438 \u043d\u0430\u0432\u044b\u043a\u0430\u043c\u0438 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 Foundry<\/strong>. \u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442\u044b, \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0442\u044c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438, \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0442\u044c \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438, \u043f\u0438\u0441\u0430\u0442\u044c \u0442\u0435\u0441\u0442\u044b \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u0439, \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u0438 \u043e\u0448\u0438\u0431\u043e\u043a. \u0412\u044b \u0442\u0430\u043a\u0436\u0435 \u0431\u0435\u0437 \u043f\u0440\u043e\u0431\u043b\u0435\u043c \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u0442\u0435 \u0441\u0440\u0435\u0434\u0443 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0434\u043b\u044f \u043a\u043e\u043c\u0444\u043e\u0440\u0442\u043d\u043e\u0439 \u0440\u0430\u0431\u043e\u0442\u044b. \u0412\u044b \u0443\u043c\u0435\u0435\u0442\u0435 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0431\u0430\u043b\u0430\u043d\u0441\u043e\u043c \u0438 \u043c\u0435\u043d\u044f\u0442\u044c \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u0431\u043b\u043e\u043a\u0430. \u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442 \u043a \u0440\u0435\u043b\u0438\u0437\u0443 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u043e\u0432, \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0435 \u0441\u043a\u0440\u0438\u043f\u0442\u044b \u0438 \u043f\u0440\u043e\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438\u0445 \u0440\u0430\u0431\u043e\u0442\u0443 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430 \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u043e\u0439 \u043d\u043e\u0434\u0435, \u043d\u043e \u0438 \u043d\u0430 \u0442\u0435\u0441\u0442\u043d\u0435\u0442\u0435 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440)! \u0421 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0444\u043e\u0440\u043a\u043e\u0432 \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u0441 \u0434\u0440\u0443\u0433\u043e\u0439 \u0441\u0435\u0442\u0438 \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f. \u0410 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Makefile \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043e\u0447\u0435\u043d\u044c \u0443\u0434\u043e\u0431\u043d\u043e \u043a\u043e\u043c\u043f\u043e\u043d\u043e\u0432\u0430\u0442\u044c  \u0431\u043e\u043b\u044c\u0448\u0438\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u043e\u0442 forge.<\/p>\n<p><strong>\u0412\u044b &#8212; \u0431\u043e\u043b\u044c\u0448\u0438\u0435 \u043c\u043e\u043b\u043e\u0434\u0446\u044b, \u0442\u0430\u043a \u0434\u0435\u0440\u0436\u0430\u0442\u044c!<\/strong><\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/3d6\/236\/4d4\/3d62364d4f9bcc689c53a435549370bd.gif\" width=\"400\" height=\"225\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/3d6\/236\/4d4\/3d62364d4f9bcc689c53a435549370bd.gif\"\/><\/figure>\n<p><a href=\"https:\/\/habr.com\/ru\/articles\/766078\/\" rel=\"noopener noreferrer nofollow\">4 \u0447\u0430\u0441\u0442\u044c >>><\/a><\/p>\n<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/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\/articles\/765266\/\"> https:\/\/habr.com\/ru\/articles\/765266\/<\/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<figure class=\"full-width\"><\/figure>\n<p>\u0417\u0430 \u043f\u0440\u043e\u0448\u0435\u0434\u0448\u0438\u0435 \u0434\u0432\u0435 \u0447\u0430\u0441\u0442\u0438 \u043c\u044b \u043e\u0441\u0432\u043e\u0438\u043b\u0438 \u043f\u043e\u0447\u0442\u0438 \u0432\u0441\u044e \u0431\u0430\u0437\u0443, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043d\u0443\u0436\u043d\u0430 \u043d\u0430\u043c \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0438 \u043e\u0442\u043b\u0430\u0434\u043a\u0438 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u043e\u0432 \u0432 <strong>Foundry<\/strong>. \u041f\u0440\u0438\u0448\u043b\u043e \u0432\u0440\u0435\u043c\u044f \u0437\u0430\u043a\u0440\u0435\u043f\u0438\u0442\u044c \u0443\u0441\u043f\u0435\u0445! \u0412 \u044d\u0442\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u043c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u0440\u043e\u0441\u0442\u044b\u0445 <strong>\u043f\u0440\u043e\u043a\u0441\u0438-\u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u043e\u0432<\/strong> (Proxy Upgradable Contracts, UUPS) \u0438 \u043d\u0430 \u0438\u0445 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c <strong>\u0441\u043a\u0440\u0438\u043f\u0442<\/strong> \u0434\u043b\u044f <strong>\u0434\u0435\u043f\u043b\u043e\u044f<\/strong> \u0438 \u0432\u044b\u0437\u043e\u0432\u0430 <strong>\u0444\u0443\u043d\u043a\u0446\u0438\u0438<\/strong>, \u043f\u043e\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u043c \u0441 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u043c\u0438 \u0441\u0440\u0435\u0434\u044b (<strong>env<\/strong>), \u0447\u0430\u0441\u0442\u0438\u0447\u043d\u043e \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0438\u0440\u0443\u0435\u043c \u0440\u0430\u0431\u043e\u0442\u0443 \u0441 \u0437\u0430\u043f\u0443\u0441\u043a\u043e\u043c \u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0432 (<strong>Makefile<\/strong>), \u0440\u0430\u0437\u0431\u0435\u0440\u0451\u043c\u0441\u044f \u0432 <strong>\u0444\u043e\u0440\u043a-\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438<\/strong> \u0438 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u043c \u043d\u0430\u0448 \u043f\u0440\u043e\u0435\u043a\u0442 \u0432 \u0442\u0435\u0441\u0442\u043d\u0435\u0442\u0435!<\/p>\n<figure class=\"\">\n<div><figcaption>\u041f\u043e\u0435\u0445\u0430\u043b\u0438!<\/figcaption><\/div>\n<\/figure>\n<p><a href=\"https:\/\/habr.com\/ru\/articles\/764576\/\" rel=\"noopener noreferrer nofollow\"><u>1 \u0447\u0430\u0441\u0442\u044c<\/u><\/a><\/p>\n<p><a href=\"https:\/\/github.com\/sudovag3\/foundry-course\/tree\/part-3\" rel=\"noopener noreferrer nofollow\"><u>\u0418\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434 \u043a \u0434\u0430\u043d\u043d\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u043a\u0443\u0440\u0441\u0430<\/u><\/a><\/p>\n<p><a href=\"https:\/\/career.habr.com\/andrey-sudov\" rel=\"noopener noreferrer nofollow\"><u>\u0421\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043c\u043e\u0439 \u0430\u043a\u043a\u0430\u0443\u043d\u0442 \u0432 \u0425\u0430\u0431\u0440 \u041a\u0430\u0440\u044c\u0435\u0440\u0435 (\u0431\u0443\u0434\u0443 \u0440\u0430\u0434 \u0437\u043d\u0430\u043a\u043e\u043c\u0441\u0442\u0432\u0443)<\/u><\/a><\/p>\n<h2>\u0422\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u0440\u043e\u043a\u0441\u0438-\u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u043e\u0432<\/h2>\n<p>\u041d\u0430 \u0440\u0443\u0441\u0441\u043a\u043e\u043c \u044e\u0442\u0443\u0431\u0435 \u0435\u0441\u0442\u044c \u0434\u0432\u0430 \u0437\u0430\u043c\u0435\u0447\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0440\u043e\u043b\u0438\u043a\u0430 \u043f\u0440\u043e \u043f\u0440\u043e\u043a\u0441\u0438-\u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u044b, \u0435\u0441\u043b\u0438 \u0432\u0434\u0440\u0443\u0433 \u0432\u044b \u043d\u0435 \u0437\u043d\u0430\u0435\u0442\u0435, \u0447\u0442\u043e \u044d\u0442\u043e (<a href=\"https:\/\/www.youtube.com\/watch?v=jLoJTc0oj0I&amp;t=4s\" rel=\"noopener noreferrer nofollow\">\u0442\u044b\u043a1 <\/a>\u0438 <a href=\"https:\/\/www.youtube.com\/watch?v=WON6VttFTe0&amp;t=389s\" rel=\"noopener noreferrer nofollow\">\u0442\u044b\u043a2<\/a>). \u042f \u043f\u0440\u0435\u0434\u043f\u043e\u043b\u0430\u0433\u0430\u044e, \u0447\u0442\u043e \u0432\u044b \u043f\u043e\u043d\u0438\u043c\u0430\u0435\u0442\u0435 \u043e\u0441\u043d\u043e\u0432\u043d\u0443\u044e \u0442\u0435\u043e\u0440\u0438\u044e \u0438 \u043d\u0430 \u043d\u0435\u0439 \u043c\u043e\u0436\u043d\u043e \u0441\u0438\u043b\u044c\u043d\u043e \u043d\u0435 \u043e\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0442\u044c\u0441\u044f. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u043f\u0440\u0438\u043c\u0435\u0440 \u043f\u0440\u043e\u043a\u0441\u0438-\u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430 (CounterV1.sol):<\/p>\n<pre><code class=\"cs\">\/\/ SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.19;  import {OwnableUpgradeable} from \"@openzeppelin\/contracts-upgradeable\/access\/OwnableUpgradeable.sol\"; import {UUPSUpgradeable} from \"@openzeppelin\/contracts-upgradeable\/proxy\/utils\/UUPSUpgradeable.sol\"; import {Initializable} from \"@openzeppelin\/contracts-upgradeable\/proxy\/utils\/Initializable.sol\";  \/**  * \u0421\u043e\u0437\u0434\u0430\u0451\u043c \u0430\u0431\u0441\u043e\u043b\u044e\u0442\u043d\u043e \u0442\u0440\u0438\u0432\u0438\u0430\u043b\u044c\u043d\u044b\u0439 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u043e\u0436\u0435\u0442  * \u0434\u043e\u0441\u0442\u0430\u0432\u0430\u0442\u044c \u043e\u0434\u043d\u0443 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e \u0438\u0437 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430  * \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u043e\u0434\u043d\u043e \u043a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435  *\/ contract CounterV1 is Initializable, OwnableUpgradeable, UUPSUpgradeable {     uint256 internal number;      \/\/\/ @custom:oz-upgrades-unsafe-allow constructor     constructor() {         _disableInitializers();     }      function initialize() public initializer {         __Ownable_init(); \/\/\u0434\u0435\u043b\u0430\u0435\u043c transferOwnership \u043d\u0430 msg.sender         __UUPSUpgradeable_init(); \/\/ \u041d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u0434\u0435\u043b\u0430\u0435\u043c :)     }      function getNumber() external view returns (uint256) {         return number;     }      function version() external pure returns (uint256) {         return 1;     }      \/**      * \u0414\u0430\u043d\u043d\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0439, \u0442\u0430\u043a \u043a\u0430\u043a \u043e\u043d\u0430 \u043e\u0431\u044a\u044f\u0432\u043b\u0435\u043d\u0430 \u0432      * \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0442\u043d\u043e\u043c \u043a\u043b\u0430\u0441\u0441\u0435 UUPSUpgradeable, \u043d\u043e \u043d\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0430      * \u0417\u0434\u0435\u0441\u044c \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u043b\u0438\u0448\u044c \u0443\u043a\u0430\u0437\u0430\u0442\u044c, \u043a\u0430\u043a\u0438\u0435 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f \u043c\u044b \u0441\u0442\u0430\u0432\u0438\u043c \u043d\u0430      * \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0442\u044c \u043d\u0430\u0448 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442      * \u0412 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c onlyOwner      * @param newImplementation \u0430\u0434\u0440\u0435\u0441 \u043d\u043e\u0432\u043e\u0433\u043e \u043f\u0440\u043e\u043a\u0441\u0438\u0440\u0443\u0435\u043c\u043e\u0433\u043e \u0430\u0434\u0440\u0435\u0441\u0430      *\/     function _authorizeUpgrade(address newImplementation) internal override onlyOwner {} } <\/code><\/pre>\n<p>CounterV2.sol:<\/p>\n<pre><code class=\"cs\">\/\/ SPDX-License-Identifier: MIT pragma solidity ^0.8.19;  import {OwnableUpgradeable} from \"@openzeppelin\/contracts-upgradeable\/access\/OwnableUpgradeable.sol\"; import {Initializable} from \"@openzeppelin\/contracts-upgradeable\/proxy\/utils\/Initializable.sol\"; import {UUPSUpgradeable} from \"@openzeppelin\/contracts-upgradeable\/proxy\/utils\/UUPSUpgradeable.sol\";  contract CounterV2 is Initializable, OwnableUpgradeable, UUPSUpgradeable {     uint256 internal value;      \/\/\/ @custom:oz-upgrades-unsafe-allow constructor     constructor() {         _disableInitializers();     }      function initialize() public initializer {         __Ownable_init();         __UUPSUpgradeable_init();     }      \/**      * \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043d\u043e\u0432\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u044e, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e\u0441\u0442\u044c      * \u0440\u0430\u0431\u043e\u0442\u044b \u0430\u043f\u0440\u0433\u0440\u0435\u0439\u0434\u0430      *\/     function increment() public {         value++;     }      function getValue() public view returns (uint256) {         return value;     }      \/**      * \u041c\u0435\u043d\u044f\u0435\u043c \u0432\u0435\u0440\u0441\u0438\u044e \u043d\u0430 \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u0443\u044e      *\/     function version() public pure returns (uint256) {         return 2;     }      function _authorizeUpgrade(address newImplementation) internal override onlyOwner {} } <\/code><\/pre>\n<p>\u0418\u0442\u0430\u043a, \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0434\u0432\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u0445 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043e\u0442\u043b\u0438\u0447\u0430\u044e\u0442\u0441\u044f \u0434\u0432\u0443\u043c\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f\u043c\u0438 \u0438 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c. \u041e\u0431\u0430 \u043e\u043d\u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u044b \u043a \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u043c\u044b\u043c \u043f\u0440\u043e\u043a\u0441\u0438-\u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430\u043c.<br \/>\u041d\u0430\u0448\u0430 \u0437\u0430\u0434\u0430\u0447\u0430:<\/p>\n<ul>\n<li>\n<p>\u041d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u043a\u0440\u0438\u043f\u0442 \u0434\u043b\u044f \u0434\u0435\u043f\u043b\u043e\u044f \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430 \u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u043a\u0441\u0438<\/p>\n<\/li>\n<li>\n<p>\u041d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u043a\u0440\u0438\u043f\u0442 \u0434\u043b\u044f \u0430\u043f\u0433\u0440\u0435\u0439\u0434\u0430 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430 \u043d\u0430 V2<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u043e\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0440\u0430\u0431\u043e\u0442\u0443 \u0434\u0430\u043d\u043d\u044b\u0445 \u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0432 \u0438 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u043e\u0432 \u0432 \u0446\u0435\u043b\u043e\u043c<\/p>\n<\/li>\n<\/ul>\n<p>\u0418\u0442\u0430\u043a, \u0432 \u043f\u0430\u043f\u043a\u0435 script \u0441\u043e\u0437\u0434\u0430\u0451\u043c \u043d\u0430\u0448 \u043f\u0435\u0440\u0432\u044b\u0439 \u0441\u043a\u0440\u0438\u043f\u0442 &#8212; DeployCounter.s.sol:<\/p>\n<pre><code class=\"cs\">\/\/ SPDX-License-Identifier: MIT pragma solidity ^0.8.19;  \/\/\u0414\u0430\u043d\u043d\u044b\u0439 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442 \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430 \u0438\u043c\u043f\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044e \u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0432, \u043e\u043d \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0434\u043e\u043b\u0436\u0435\u043d \u043d\u0430\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u044c\u0441\u044f \/\/ \u0432 \u043b\u044e\u0431\u043e\u043c \u0441\u043a\u0440\u0438\u043f\u0442\u0435 import {Script} from \"forge-std\/Script.sol\"; import {CounterV1} from \"..\/src\/CounterV1.sol\"; import {ERC1967Proxy} from \"@openzeppelin\/contracts\/proxy\/ERC1967\/ERC1967Proxy.sol\";  \/**  * \u041a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u044b \u043f\u043e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440 \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043d\u0438\u0447\u0435\u043c \u043d\u0435 \u043e\u0442\u043b\u0438\u0447\u0430\u044e\u0442\u0441\u044f \u043e\u0442 \u0442\u0435\u0441\u0442\u043e\u0432  *\/ contract DeployCounter is Script {     \/**      * \u0417\u0430\u0434\u0430\u0447\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 run() \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u0430:      * \u0417\u0430\u0434\u0435\u043f\u043b\u043e\u0438\u0442\u044c \u043d\u0430\u0448 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442      * \u041e\u043d\u0430 \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c\u0441\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u0440\u0438 \u0432\u044b\u0437\u043e\u0432\u0435      * \u0441\u043a\u0440\u0438\u043f\u0442\u0430, \u0447\u0442\u043e-\u0442\u043e \u0432\u0440\u043e\u0434\u0435 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0430      *\/     function run() external returns (address) {         address proxy = deployCounter();         return proxy;     }      \/**      * \u0417\u0434\u0435\u0441\u044c \u043c\u044b \u0432\u0441\u0442\u0440\u0435\u0447\u0430\u0435\u043c \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0439 \u043c\u0435\u0442\u043e\u0434: vm.startBroadcast()      * \u0414\u0430\u043d\u043d\u044b\u0439 \u043c\u0435\u0442\u043e\u0434 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0443 \u0441\u043e\u0437\u0434\u0430\u0442\u044c      * \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0443\u044e \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u044e \u043e\u043d-\u0447\u0435\u0439\u043d      * \u0417\u0434\u0435\u0441\u044c \u043d\u0435 \u0431\u0443\u0434\u0443\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0447\u0438\u0442-\u043a\u043e\u0434\u044b \u0438 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u044f \u0431\u0443\u0434\u0435\u0442 \"\u043a\u0430\u043a \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0430\u044f\"      * \u0412 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043c\u044b \u0445\u043e\u0442\u0438\u043c, \u0447\u0442\u043e\u0431\u044b \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0435\u0439 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0435\u0439 \u0443 \u043d\u0430\u0441 \u0437\u0430\u0434\u0435\u043f\u043b\u043e\u0438\u043b\u0441\u044f      * \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442 \u0438 \u043f\u0440\u043e\u043a\u0441\u0438 \u043a \u043d\u0435\u043c\u0443      *\/     function deployCounter() public returns (address) {         vm.startBroadcast();         \/\/\u0414\u0435\u043f\u043b\u043e\u0438\u043c \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442 \u043f\u0435\u0440\u0432\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438         CounterV1 counter = new CounterV1();         \/\/\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u0441\u0435\u043b\u0435\u043a\u0442\u043e\u0440 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0441 \u043d\u0443\u0436\u043d\u044b\u043c\u0438 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0430\u043c\u0438         \/\/\u0412 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043d\u0435\u0442, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 ()         bytes memory data = abi.encodeCall(CounterV1.initialize, ());         \/\/\u0414\u0435\u043f\u043b\u043e\u0438\u043c \u043f\u0440\u043e\u043a\u0441\u0438-\u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u044f \u0430\u0434\u0440\u0435\u0441 \u0438\u043c\u043f\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u0438 \u0434\u0430\u043d\u043d\u044b\u0435         \/\/\u043e\u0431 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u044e\u0449\u0435\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438         ERC1967Proxy proxy = new ERC1967Proxy(address(counter), data);         vm.stopBroadcast();         return address(proxy);     } } <\/code><\/pre>\n<p>\u0423\u0440\u0430, \u0441\u043a\u0440\u0438\u043f\u0442 \u0434\u043b\u044f \u0434\u0435\u043f\u043b\u043e\u044f \u0433\u043e\u0442\u043e\u0432! \u041e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u043a\u0440\u0438\u043f\u0442 \u0434\u043b\u044f \u0430\u043f\u0433\u0440\u0435\u0439\u0434\u0430. \u041e\u0434\u043d\u0430\u043a\u043e \u044d\u0442\u043e\u0442 \u0441\u043a\u0440\u0438\u043f\u0442 \u0443\u0436\u0435 \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0432 \u043a\u0443\u0440\u0441\u0435, \u043a\u0430\u043a\u043e\u0439 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442 \u0435\u043c\u0443 \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0442\u044c. \u0421 \u043e\u0434\u043d\u043e\u0439 \u0441\u0442\u043e\u0440\u043e\u043d\u044b, \u043c\u043e\u0436\u043d\u043e \u0445\u0430\u0440\u0434\u043a\u043e\u0434\u0438\u0442\u044c \u0430\u0434\u0440\u0435\u0441 \u0437\u0430\u0434\u0435\u043f\u043b\u043e\u0435\u043d\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u043a\u0441\u0438 \u0432 \u0441\u043a\u0440\u0438\u043f\u0442\u0435 \u0430\u043f\u0433\u0440\u0435\u0439\u0434\u0430, \u043d\u043e \u0441 \u0434\u0440\u0443\u0433\u043e\u0439 \u0441\u0442\u043e\u0440\u043e\u043d\u044b, \u0432 \u0431\u043e\u043b\u044c\u0448\u0438\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445 \u044d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043d\u0438\u043c\u0430\u0442\u044c \u043e\u0447\u0435\u043d\u044c \u043c\u043d\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0438 \u0441\u043e\u0432\u0441\u0435\u043c \u043d\u0435 \u043f\u043e-\u043d\u0430\u0448\u0435\u043c\u0443 \ud83d\ude42 <\/p>\n<h2>Foundry-devops<\/h2>\n<p>\u041a\u043e\u0433\u0434\u0430 \u043c\u044b \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u043a\u0430\u043a\u043e\u0439-\u0442\u043e \u0441\u043a\u0440\u0438\u043f\u0442, <strong>Foundry<\/strong> \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442 \u0432\u0441\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u0434\u0435\u043f\u043b\u043e\u044f\u0445 \u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0439 \u043f\u0430\u043f\u043a\u0435, \u0440\u0430\u0437\u0434\u0435\u043b\u044f\u044f \u0432\u044b\u0437\u043e\u0432\u044b \u043e\u0442 \u043a\u0430\u0436\u0434\u043e\u0439 \u0441\u0435\u0442\u0438. \u041f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u0438\u043c \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0430\u0440\u0441\u0438\u0442 \u044d\u0442\u0443 \u0438\u043d\u0444\u0443 (\u043d\u0430\u0445\u043e\u0434\u0438\u0442 \u0430\u0434\u0440\u0435\u0441 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0433\u043e \u0437\u0430\u0434\u0435\u043f\u043b\u043e\u0435\u043d\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u043a\u0441\u0438) \u0438 \u0432\u044b\u0432\u043e\u0434\u0438\u0442 \u0435\u0451 \u0432 \u0441\u043a\u0440\u0438\u043f\u0442 \u0430\u043f\u0433\u0440\u0435\u0439\u0434\u0430, \u0442\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u043c\u044b \u0438\u0437\u0431\u0430\u0432\u0438\u043c\u0441\u044f \u043e\u0442 \u0445\u0430\u0440\u0434\u043a\u043e\u0434\u0430 \u0438 \u0434\u043e\u0431\u044c\u0451\u043c\u0441\u044f \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0439 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0438. \u0418\u043c\u0435\u043d\u043d\u043e \u0442\u0430\u043a \u043f\u043e\u0441\u0442\u0443\u043f\u0438\u043b\u0430 \u043a\u043e\u043c\u0430\u043d\u0434\u0430 <a href=\"https:\/\/github.com\/Cyfrin\" rel=\"noopener noreferrer nofollow\">Cyfrin<\/a> \u0438 \u0441\u0434\u0435\u043b\u0430\u043b\u0430 \u043e\u0447\u0435\u043d\u044c \u0443\u0434\u043e\u0431\u043d\u044b\u0439 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u0434\u043b\u044f Foundry &#8212; <a href=\"https:\/\/github.com\/Cyfrin\/foundry-devops\" rel=\"noopener noreferrer nofollow\">foundry-devops<\/a>. \u041e\u0446\u0435\u043d\u0438\u043c \u0435\u0433\u043e \u0440\u0430\u0431\u043e\u0442\u0443:<\/p>\n<p>\u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c foundry-devops:<\/p>\n<pre><code class=\"bash\">$ forge install Cyfrin\/foundry-devops@0.0.11 --no-commit<\/code><\/pre>\n<p>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u0435\u0433\u043e, \u043f\u0438\u0448\u0435\u043c \u0441\u043a\u0440\u0438\u043f\u0442 \u0434\u043b\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u043a\u0441\u0438(UpgradeCounter.s.sol):<\/p>\n<pre><code class=\"cs\">\/\/ SPDX-License-Identifier: MIT pragma solidity ^0.8.19;  import {Script, console} from \"forge-std\/Script.sol\"; import {CounterV1} from \"..\/src\/CounterV1.sol\"; import {CounterV2} from \"..\/src\/CounterV2.sol\"; import {ERC1967Proxy} from \"@openzeppelin\/contracts\/proxy\/ERC1967\/ERC1967Proxy.sol\"; import {Helper} from \".\/Helper.s.sol\";  \/\/\u0418\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0439 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442, \u043e\u043d \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u043d\u0430\u043c \u0432 \u0440\u0430\u0431\u043e\u0442\u0435 \u0441 \u043d\u0435\u0434\u0430\u0432\u043d\u043e \u0437\u0430\u0434\u0435\u043f\u043b\u043e\u0435\u043d\u043d\u044b\u043c\u0438 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430\u043c\u0438 import {DevOpsTools} from \"lib\/foundry-devops\/src\/DevOpsTools.sol\";  \/**  * \u041c\u044b \u0441\u043e\u0437\u0434\u0430\u0451\u043c \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442, \u0443 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0431\u0443\u0434\u0435\u0442 \u043b\u0438\u0448\u044c \u043e\u0434\u043d\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u044f:  * \u041e\u0431\u043d\u043e\u0432\u043b\u044f\u0442\u044c \u043d\u0430\u0448 \u043f\u0440\u043e\u043a\u0441\u0438\u0440\u0443\u0435\u043c\u044b\u0439 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442  *\/ contract UpgradeCounter is Helper {     function run() external returns (address) {         \/\/ \u041c\u0435\u0442\u043e\u0434 get_most_recent_deployment()         \/\/ \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0434\u043e\u0441\u0442\u0430\u0442\u044c \u0430\u0434\u0440\u0435\u0441 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0433\u043e \u0437\u0430\u0434\u0435\u043f\u043b\u043e\u0435\u043d\u043d\u043e\u0433\u043e \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430         \/\/ \u043f\u043e \u0437\u0430\u0434\u0430\u043d\u043d\u044b\u043c \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f\u043c: \u041d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430 \u0438 id \u0446\u0435\u043f\u0438,         \/\/ \u0433\u0434\u0435 \u0434\u0430\u043d\u043d\u044b\u0439 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442 \u0434\u0435\u043f\u043b\u043e\u0438\u043b\u0441\u044f         address mostRecentlyDeployedProxy = DevOpsTools.get_most_recent_deployment(\"ERC1967Proxy\", block.chainid);          \/\/\u041c\u044b \u0445\u043e\u0442\u0438\u043c \u043f\u043e-\u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0435\u043c\u0443 \u0437\u0430\u0434\u0435\u043f\u043b\u043e\u0438\u0442\u044c \u043d\u043e\u0432\u0443\u044e \u0432\u0435\u0440\u0441\u0438\u044e \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430,         \/\/\u043f\u043e\u044d\u0442\u043e\u043c\u0443 startBroadcast()         vm.startBroadcast();         CounterV2 newCounter = new CounterV2();         vm.stopBroadcast();         \/\/\u041e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u043c \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442         address proxy = upgradeCounter(mostRecentlyDeployedProxy, address(newCounter));          return proxy;     }      function upgradeCounter(address proxyAddress, address newCounter) public returns (address) {         vm.startBroadcast();         \/\/payable - \u044d\u0442\u043e \u0432\u0430\u0436\u043d\u044b\u0439 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440, \u043d\u0435 \u0437\u0430\u0431\u044b\u0432\u0430\u0435\u043c \u043f\u0440\u043e \u043d\u0435\u0433\u043e         \/\/(\u043d\u044e\u0430\u043d\u0441 \u043f\u0440\u043e\u043a\u0438-\u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u043e\u0432)         CounterV1 proxy = CounterV1(payable(proxyAddress));         proxy.upgradeTo(address(newCounter));         vm.stopBroadcast();         return address(proxy);     } } <\/code><\/pre>\n<p>\u0423\u0440\u0430! \u0422\u0435\u043f\u0435\u0440\u044c \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0442\u0435\u0441\u0442, \u043d\u043e \u043f\u0435\u0440\u0435\u0434 \u044d\u0442\u0438\u043c \u0441\u0442\u043e\u0438\u0442 \u0435\u0433\u043e \u043f\u0440\u043e\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c. \u0422\u0435\u0441\u0442\u044b \u043c\u044b \u043f\u0438\u0441\u0430\u0442\u044c \u0443\u0436\u0435 \u0443\u043c\u0435\u0435\u043c, \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u043e\u0432\u043e\u0433\u043e \u0437\u0434\u0435\u0441\u044c \u043c\u044b \u043d\u0435 \u043d\u0430\u0439\u0434\u0451\u043c \u0437\u0430 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435\u043c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0438\u0445 \u0445\u0438\u0442\u0440\u043e\u0441\u0442\u0435\u0439, \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0445 \u0441 \u043f\u0440\u043e\u043a\u0441\u0438 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430\u043c\u0438 (CounterTest.t.sol):<\/p>\n<pre><code class=\"cs\">\/\/ SPDX-License-Identifier: MIT  pragma solidity ^0.8.19;  import {DeployCounter} from \"..\/script\/DeployCounter.s.sol\"; import {UpgradeCounter} from \"..\/script\/UpgradeCounter.s.sol\"; import {Test, console} from \"forge-std\/Test.sol\"; import {CounterV1} from \"..\/src\/CounterV1.sol\"; import {CounterV2} from \"..\/src\/CounterV2.sol\"; import {Helper} from \"..\/script\/Helper.s.sol\"; import {ERC20} from \"@openzeppelin\/contracts\/token\/ERC20\/ERC20.sol\";  \/**  * \u041e\u0447\u0435\u043d\u044c \u0432\u0430\u0436\u043d\u043e \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0440\u0430\u0431\u043e\u0442\u0443 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0445 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u043e\u0432,  * \u043d\u043e \u0438 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u043e\u0432-\u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0432, \u0432\u0435\u0434\u044c \u043e\u043d\u0438 \u0442\u043e\u0436\u0435 \u0431\u0443\u0434\u0443\u0442 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0442\u044c \u0443\u0447\u0430\u0441\u0442\u0438\u0435  * \u0432 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0445 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0439  * \u0412 \u0440\u0430\u043c\u043a\u0430\u0445 \u044d\u0442\u043e\u0433\u043e \u0442\u0435\u0441\u0442\u0430 \u043c\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u043c \u0440\u0430\u0431\u043e\u0442\u0443 \u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0432 \u043d\u0430 \u0434\u0435\u043f\u043b\u043e\u0439 \u0438 \u0430\u043f\u0433\u0440\u0435\u0439\u0434  * \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u043e\u0432  *\/ contract DeployAndUpgradeTest is Test {     DeployCounter public deployCounter;     UpgradeCounter public upgradeCounter;      function setUp() public {         deployCounter = new DeployCounter();         upgradeCounter = new UpgradeCounter();     }      \/**      * \u0412 \u044d\u0442\u043e\u043c \u0442\u0435\u0441\u0442\u0435 \u043c\u044b \u0434\u0435\u043f\u043b\u043e\u0438\u043c \u043f\u0435\u0440\u0432\u0443\u044e \u0432\u0435\u0440\u0441\u0438\u044e \u043d\u0430\u0448\u0435\u0433\u043e \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430      * \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c<\/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-356607","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/356607","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=356607"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/356607\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=356607"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=356607"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=356607"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}