From 6fb91aa5fb9b9f799c9b186aaeb3a3bb3cf1fc7b Mon Sep 17 00:00:00 2001 From: Dustin Brickwood Date: Wed, 10 Apr 2024 20:55:11 -0500 Subject: [PATCH] chore: content updates --- content/10.quick-start/4.upgrading.md | 43 ++-- .../_hardhat_beacon_contract_upgradability.md | 197 +++++++----------- ...dhat_transparent_contract_upgradability.md | 80 ++++--- .../_partials/compile-solidity-contracts.md | 28 +++ cspell-config/cspell-blockchain.txt | 3 +- 5 files changed, 158 insertions(+), 193 deletions(-) create mode 100644 content/_partials/compile-solidity-contracts.md diff --git a/content/10.quick-start/4.upgrading.md b/content/10.quick-start/4.upgrading.md index 64c811ab..90edbf30 100644 --- a/content/10.quick-start/4.upgrading.md +++ b/content/10.quick-start/4.upgrading.md @@ -36,23 +36,26 @@ items: [{ --- :: -## Takeaways - -- **EVM Compatibility:** zkSync is EVM compatible and you can write smart contracts in Solidity or Vyper. -- **Development Tools:** zkSync supports your favorite development toolkit Hardhat and Foundry. -- **Custom Compilation:** Contracts deployed to zkSync are compiled using `zksolc` or `zkvyper` as -they generate a special bytecode for zkSync's ZKEVM. - -## Next steps - -Having successfully deployed your first contract on zkSync, you're well on your way to becoming -a proficient zkSync developer. To expand your expertise: - -- **Explore Contract Factories:** Enhance your project by building a contract factory -for the `CrowdfundingCampaign` contract in the next guide. This will allow you to efficiently -manage multiple crowdfunding campaigns, each with its own unique parameters. -- **Dive Deeper into zkSync Features:** Investigate advanced zkSync features such as account abstraction, -and paymasters. -- **Join the Community:** Engage with the zkSync developer community through forums, -Discord channels, Dev Discussions, or GitHub repositories. Share your experiences, ask questions, -and collaborate on projects. +## Takeaways and Next Steps + +### Takeaways + +- **Upgradability:** The guide highlights the critical aspect of smart contract upgradability, introducing techniques +for using transparent, beacon, and UUPS proxies. +This ensures your contracts remain adaptable, allowing for seamless updates to business logic or enhancements in efficiency. + +- **Flexibility:** Emphasizing flexibility, the guide demonstrates how upgradable +contracts maintain continuity of state and fund security, even as underlying +functionalities evolve. This approach provides a resilient framework for your dApps to grow and adapt over time. + +### Next Steps + +- **Exploring Paymasters:** Dive into the next guide focused on using paymasters +with your smart contracts. Paymasters abstract gas payments in transactions, +offering new models for transaction fee management and enhancing user experience in dApps. +- **Advanced zkSync Integrations:** Explore deeper into zkSync's ecosystem by +implementing features like account abstraction and paymasters to enhance user +experience and contract flexibility. +- **Community Engagement and Contribution:** Join the vibrant zkSync community. +Participate in forums, Discord, or GitHub discussions. Sharing insights, asking queries, +and contributing can enrich the ecosystem and your understanding of zkSync. diff --git a/content/10.quick-start/_upgrading/_beacon/_hardhat_beacon_contract_upgradability.md b/content/10.quick-start/_upgrading/_beacon/_hardhat_beacon_contract_upgradability.md index 85e8b1fe..c573bc47 100644 --- a/content/10.quick-start/_upgrading/_beacon/_hardhat_beacon_contract_upgradability.md +++ b/content/10.quick-start/_upgrading/_beacon/_hardhat_beacon_contract_upgradability.md @@ -19,7 +19,7 @@ For testnet deployments, follow these steps to secure your funds: ## Step 3: Adapting `CrowdfundingCampaign.sol` contract for upgradability -To adapt our `CrowdfundingCampaign.sol` contract for upgradability, we're +To adapt our `CrowdfundingCampaign.sol` contract for upgradability, we are transitioning to a proxy pattern. This approach separates the contract's logic (which can be upgraded) from its persistent state (stored in the proxy). @@ -28,7 +28,7 @@ contract's logic (which can be upgraded) from its persistent state We're refactoring the contract to initialize state variables through an `initialize` function instead of the constructor, in line with the -Transparent Proxy pattern. +proxy pattern. **Updated Contract Structure:** @@ -83,9 +83,10 @@ This restructuring prepares the `CrowdfundingCampaign` contract for upgradeabili ## Step 4: Deploy the `CrowdfundingCampaign` contract -Now that the `CrowdfundingCampaign` contract is adapted for contract upgradability, let's proceed to deploy -the contract so we may upgrade it in later steps. Since we've made changes to our contract we will -need to re-compile. +This initial deployment sets the stage for future upgrades, enabling us +to iterate on the contract's functionality without starting from scratch. +As modifications have been made to the contract to support upgradability, +a fresh compilation is necessary to reflect these changes in the deployment artifact. To compile the contracts in the project, run the following command: @@ -125,8 +126,9 @@ The compiled artifacts will be located in the `/artifacts-zk` folder. ### Deploy -This section outlines the steps to deploy the `CrowdfundingCampaign` contract that we recently updated for upgradability. -The deployment script is located at `/deploy/deployBeaconProxy.ts`. +This guide details the process for deploying the upgraded `CrowdfundingCampaign` +contract, now enhanced with upgradability features. +You'll find the necessary deployment script at `/deploy/deployBeaconProxy.ts`. ```typescript import { getWallet } from "./utils"; @@ -153,7 +155,18 @@ export default async function (hre: HardhatRuntimeEnvironment) { } ``` -Key Components: +**Key Components:** + +- **`deployBeacon` Method:** Initiates the deployment of a beacon contract, +which acts as a central point for managing future upgrades of the `CrowdfundingCampaign` +contract. The beacon's address is a critical component as it links the deployed proxy +to the actual contract logic. + +- **`deployBeaconProxy` Method:** This step involves deploying the beacon proxy, +which serves as the user-facing contract instance. It references the beacon for its logic, +allowing for seamless upgrades without altering the proxy's address. +The `fundingGoalInWei parameter`, converted from ether to wei, is passed during +this step to initialize the contract with a funding goal. #### Deploy contract Execute the deployment command corresponding to your package manager. The default command @@ -192,7 +205,7 @@ bun run hardhat deploy-zksync --script deployBeaconProxy.ts Upon successful deployment, you'll receive output detailing the deployment process, including the contract addresses of the implementation -contract, the admin contract, and the transparent +contract, the admin contract, and the beacon proxy contract. ```bash @@ -221,83 +234,21 @@ this constraint, ensuring contributions are made within the allowed period. **Enhanced Contract:** -Let's review the `CrowdfundingCampaignV2.sol` contract in the `/contracts` directory to view the updated contract: - -```solidity -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import "@openzeppelin/contracts/proxy/utils/Initializable.sol"; - -contract CrowdfundingCampaignV2 is Initializable { - address public owner; - uint256 public fundingGoal; - uint256 public totalFundsRaised; - mapping(address => uint256) public contributions; - - uint256 public deadline; - bool private initializedV2; - - event ContributionReceived(address contributor, uint256 amount); - event GoalReached(uint256 totalFundsRaised); - - // Original initialization function for V1 - function initialize(uint256 _fundingGoal) public initializer { - owner = msg.sender; - fundingGoal = _fundingGoal; - } - - // Additional initialization function for V2 - function initializeV2(uint256 _duration) public { - require(!initializedV2, "V2 already initialized"); - require(msg.sender == owner, "Only the owner can initialize V2"); - - deadline = block.timestamp + _duration; - initializedV2 = true; - } - - modifier withinDeadline() { - require(block.timestamp <= deadline, "Funding period has ended"); - _; - } - - function contribute() public payable withinDeadline { - require(msg.value > 0, "Contribution must be greater than 0"); - contributions[msg.sender] += msg.value; - totalFundsRaised += msg.value; +The upgraded contract, `CrowdfundingCampaignV2.sol`, located in the `/contracts` directory, +incorporates these changes: - emit ContributionReceived(msg.sender, msg.value); +- **Deadline Variable:** A new state variable deadline defines the campaign's end time, +enhancing the contract with time-based logic. - if (totalFundsRaised >= fundingGoal) { - emit GoalReached(totalFundsRaised); - } - } - - function withdrawFunds() public { - require(msg.sender == owner, "Only the owner can withdraw funds"); - require(totalFundsRaised >= fundingGoal, "Funding goal not reached"); - - uint256 amount = address(this).balance; - totalFundsRaised = 0; - - (bool success, ) = payable(owner).call{value: amount}(""); - require(success, "Transfer failed."); - } - - function getTotalFundsRaised() public view returns (uint256) { - return totalFundsRaised; - } +- **Initialization Logic:** An additional initialization method, `initializeV2`, sets the deadline +based on a duration provided during the upgrade. This function ensures that the upgrade is +backward-compatible and maintains the contract's integrity. - function getFundingGoal() public view returns (uint256) { - return fundingGoal; - } +- **Contribution Logic with Deadline:** The `contribute` method now includes a `withinDeadline` modifier, +ensuring all contributions are made within the set timeframe. - function extendDeadline(uint256 _newDuration) public { - require(msg.sender == owner, "Only the owner can extend the deadline"); - deadline = block.timestamp + _newDuration; - } -} -``` +- **Deadline Enforcement:** The `withinDeadline` modifier checks the current time against the deadline, +safeguarding the contract from late contributions. **Deadline Extension Capability:** @@ -316,30 +267,7 @@ exemplifies the use of `modifiers` for enforcing contract conditions. ### Compile contract -Smart contracts deployed to zkSync must be compiled using our custom compiler. -For this particular guide we are making use of `zksolc`. - -To compile the contracts in the project, run the following command: - -::code-group - -```bash [yarn] -yarn compile -``` - -```bash [pnpm] -pnpm run compile -``` - -```bash [npm] -npm run compile -``` - -```bash [bun] -bun run compile -``` - -:: +:display-partial{partial = "Compile Solidity Contract"} #### Expected Output @@ -355,7 +283,7 @@ Successfully compiled 2 Solidity file The compiled artifacts will be located in the `/artifacts-zk` folder. -### Upgrading `CrowdfundingCampaign` to `CrowdfundingCampaignV2` +### Upgrading to `CrowdfundingCampaignV2` This section describes the initating the upgrade to `CrowdfundingCampaign.sol` contract. Let's start by reviewing the `upgradeBeaconCrowdfundingCampaign.ts` script in the `deploy/upgrade-scripts` directory: @@ -370,11 +298,16 @@ import { Contract } from 'ethers'; export default async function (hre: HardhatRuntimeEnvironment) { const wallet = getWallet(); const deployer = new Deployer(hre, wallet); - const beaconAddress = 'beacon address here'; + + // Placeholder for the deployed beacon address + const beaconAddress = 'YOUR_BEACON_ADDRESS_HERE'; - const crowdfundingCampaignV2 = await deployer.loadArtifact('CrowdfundingCampaignV2'); - await hre.zkUpgrades.upgradeBeacon(deployer.zkWallet, beaconAddress, crowdfundingCampaignV2); - console.log('Successfully upgraded crowdfundingCampaign to crowdfundingCampaignV2', beaconAddress); + const contractV2Artifact = await deployer.loadArtifact('CrowdfundingCampaignV2'); + + // Upgrade the proxy to V2 + await hre.zkUpgrades.upgradeBeacon(deployer.zkWallet, beaconAddress, contractV2Artifact); + + console.log('Successfully upgraded crowdfundingCampaign to crowdfundingCampaignV2'); const attachTo = new zk.ContractFactory( crowdfundingCampaignV2.abi, @@ -383,29 +316,37 @@ export default async function (hre: HardhatRuntimeEnvironment) { deployer.deploymentType, ); - const beaconProxyAddress = "beacon proxy address here"; - const upgradedCrowdfundingCampaign = attachTo.attach(beaconProxyAddress); + // Placeholder for the deployed beacon proxy address + const proxyAddress = 'YOUR_PROXY_ADDRESS_HERE'; + + const upgradedContract = attachTo.attach(proxyAddress); - upgradedCrowdfundingCampaign.connect(deployer.zkWallet); + upgradedContract.connect(deployer.zkWallet); // wait some time before the next call await new Promise((resolve) => setTimeout(resolve, 2000)); - - const durationInSeconds = 30 * 24 * 60 * 60; // For example, setting a 30-day duration - const initTx = await upgradedCrowdfundingCampaign.initializeV2(durationInSeconds); + // Initialize V2 with a new campaign duration + const durationInSeconds = 30 * 24 * 60 * 60; // For example, setting a 30-day duration + const initTx = await upgradedContract.initializeV2(durationInSeconds); const receipt = await initTx.wait(); - console.log('CrowdfundingCampaignV2 initialized!', receipt.hash); - - const fundraisingGoal = await upgradedCrowdfundingCampaign.getFundingGoal(); - console.log('Fundraising goal:', fundraisingGoal.toString()); + console.log(`CrowdfundingCampaignV2 initialized. Transaction Hash: ${receipt.hash}`); } ``` -Add the **Beacon** address and the **Beacon proxy** address from our deployment -process to the `beaconAddress`, `beaconProxyAddress` variables in the above script. +Ensure to replace `YOUR_BEACON_ADDRESS_HERE` with the address of your deployed beacon and +`YOUR_PROXY_ADDRESS_HERE` with the actual address of your +deployed Beacon Proxy from the previous deployment step. -Key Components: +**Key Components:** + +- **`upgradeBeacon`**: This method from the `hre.zkUpgrades` module is used to update the beacon contract +with the new version of the contract logic, `CrowdfundingCampaignV2`. +It ensures that all proxies pointing to this beacon will now execute the updated contract code. +- **`initializeV2`:** This method is specifically called post-upgrade to initialize or reconfigure any new state +variables or logic introduced in the `CrowdfundingCampaignV2`. +Here, it's used to set a new campaign duration, seamlessly +integrating new functionalities while retaining the existing contract state and funds. #### Upgrade contract Execute the test command corresponding to your package manager: @@ -444,8 +385,10 @@ Fundraising goal: 100000000000000000 ## Step 6: Verify upgradable contracts -To verify our upgradable contracts we need to the proxy address we previously used in our upgrade script. -With that execute the following command: +For the verification of our upgradable contracts, it's essential to utilize the proxy address that was specified in our +upgrade script. + +To proceed with verification, execute the following command: ::code-group @@ -483,4 +426,4 @@ Your verification ID is: 10549 Contract successfully verified on zkSync block explorer! ``` -🎉 Congratulations! The `CrowdfundingCampaign` contract has been upgraded and verified! +🎉 Congratulations! The `CrowdfundingCampaignV2` contract has been upgraded and verified! diff --git a/content/10.quick-start/_upgrading/_transparent/_hardhat_transparent_contract_upgradability.md b/content/10.quick-start/_upgrading/_transparent/_hardhat_transparent_contract_upgradability.md index 8ce9fc88..05071cf6 100644 --- a/content/10.quick-start/_upgrading/_transparent/_hardhat_transparent_contract_upgradability.md +++ b/content/10.quick-start/_upgrading/_transparent/_hardhat_transparent_contract_upgradability.md @@ -158,8 +158,8 @@ export default async function (hre: HardhatRuntimeEnvironment) { - **`hre.zkUpgrades.deployProxy`**: The method call to deploy the `CrowdfundingCampaign` contract via a transparent proxy, leveraging Hardhat's runtime environment for zkSync upgrades. This ensures the deployed contract can be upgraded in the future without losing its state or funds. -- **`initializer`**: Specifies the initialization method of the contract, initialize in this case, -which is crucial for setting up the proxy's state upon deployment. +- **`initializer`**: Specifies the initialization method of the contract, `initialize` in this case, +which is required for setting up the proxy's state upon deployment. #### Deploy contract Execute the deployment command corresponding to your package manager. The default command @@ -260,30 +260,7 @@ exemplifies the use of `modifiers` for enforcing contract conditions. ### Compile contract -Smart contracts deployed to zkSync must be compiled using our custom compiler. -For this particular guide we are making use of `zksolc`. - -To compile the contracts in the project, run the following command: - -::code-group - -```bash [yarn] -yarn compile -``` - -```bash [pnpm] -pnpm run compile -``` - -```bash [npm] -npm run compile -``` - -```bash [bun] -bun run compile -``` - -:: +:display-partial{partial = "Compile Solidity Contract"} #### Expected Output @@ -299,10 +276,11 @@ Successfully compiled 2 Solidity file The compiled artifacts will be located in the `/artifacts-zk` folder. -### Upgrading `CrowdfundingCampaign` to `CrowdfundingCampaignV2` +### Upgrading to `CrowdfundingCampaignV2` -This section describes the initating the upgrade to `CrowdfundingCampaign.sol` contract. Let's -start by reviewing the `upgradeCrowdfundingCampaign.ts` script in the `deploy/upgrade-scripts` directory: +This section guides you through upgrading the `CrowdfundingCampaign` contract +to its second version, `CrowdfundingCampaignV2`. Review the `upgradeCrowdfundingCampaign.ts` +script located within the `deploy/upgrade-scripts` directory to begin. ```typescript import { getWallet } from "../utils"; @@ -313,34 +291,42 @@ export default async function (hre: HardhatRuntimeEnvironment) { const wallet = getWallet(); const deployer = new Deployer(hre, wallet); - const crowdfundingCampaignProxyAddress = 'Proxy address here'; + // Placeholder for the deployed proxy address + const proxyAddress = 'YOUR_PROXY_ADDRESS_HERE'; - const crowdfundingCampaignV2 = await deployer.loadArtifact('CrowdfundingCampaignV2'); + const contractV2Artifact = await deployer.loadArtifact('CrowdfundingCampaignV2'); - const upgradedCrowdfundingCampaign = await hre.zkUpgrades.upgradeProxy(deployer.zkWallet, crowdfundingCampaignAddress, crowdfundingCampaignV2); + // Upgrade the proxy to V2 + const upgradedContract = await hre.zkUpgrades.upgradeProxy(deployer.zkWallet, proxyAddress, contractV2Artifact); console.log('Successfully upgraded crowdfundingCampaign to crowdfundingCampaignV2'); - upgradedCrowdfundingCampaign.connect(deployer.zkWallet); + upgradedContract.connect(deployer.zkWallet); // wait some time before the next call await new Promise((resolve) => setTimeout(resolve, 2000)); + // Initialize V2 with a new campaign duration const durationInSeconds = 30 * 24 * 60 * 60; // For example, setting a 30-day duration - - const initTx = await upgradedCrowdfundingCampaign.initializeV2(durationInSeconds); + const initTx = await upgradedContract.initializeV2(durationInSeconds); const receipt = await initTx.wait(); - console.log('CrowdfundingCampaignV2 initialized!', receipt.hash); - - const fundraisingGoal = await upgradedCrowdfundingCampaign.getFundingGoal(); - console.log('Fundraising goal:', fundraisingGoal.toString()); + console.log(`CrowdfundingCampaignV2 initialized. Transaction Hash: ${receipt.hash}`); } ``` -We will need to add the **Transparent proxy** address from our deployment process to the -`crowdfundingCampaignProxyAddress` in the above script. +Ensure to replace `YOUR_PROXY_ADDRESS_HERE` with the actual address of your +deployed Transparent Proxy from the previous deployment step. + +**Key Components:** -Key Components: +- **`upgradeProxy`:** A critical method from the `hre.zkUpgrades` module that +performs the contract upgrade. It takes the wallet, the proxy address, and the +new contract artifact as arguments to transition the proxy to use the `CrowdfundingCampaignV2` logic. + +- **`initializeV2`:** Post-upgrade, this function is invoked to initialize the new +variables or logic introduced in `CrowdfundingCampaignV2`. In this example, +it sets a new campaign duration, illustrating how contract upgrades can add +functionalities without losing the existing state or funds. #### Upgrade contract Execute the test command corresponding to your package manager: @@ -379,8 +365,10 @@ Fundraising goal: 100000000000000000 ## Step 6: Verify upgradable contracts -To verify our upgradable contracts we need to the proxy address we previously used in our upgrade script. -With that execute the following command: +For the verification of our upgradable contracts, it's essential to utilize the proxy address that was specified in our +upgrade script. + +To proceed with verification, execute the following command: ::code-group @@ -402,6 +390,8 @@ bun run hardhat verify :: +Ensure to replace with the actual proxy address from your deployment. + #### Expected Output Upon successful verification, you'll receive output detailing the verification process: @@ -418,4 +408,4 @@ Your verification ID is: 10545 Contract successfully verified on zkSync block explorer! ``` -🎉 Congratulations! The `CrowdfundingCampaign` contract has been upgraded and verified! +🎉 Congratulations! The `CrowdfundingCampaignV2` contract has been upgraded and verified! diff --git a/content/_partials/compile-solidity-contracts.md b/content/_partials/compile-solidity-contracts.md new file mode 100644 index 00000000..edd54343 --- /dev/null +++ b/content/_partials/compile-solidity-contracts.md @@ -0,0 +1,28 @@ +--- +title: Compile Solidity Contract +--- + +Smart contracts deployed to zkSync must be compiled using our custom compiler. +For this particular guide we are making use of `zksolc`. + +To compile the contracts in the project, run the following command: + +::code-group + +```bash [yarn] +yarn compile +``` + +```bash [pnpm] +pnpm run compile +``` + +```bash [npm] +npm run compile +``` + +```bash [bun] +bun run compile +``` + +:: diff --git a/cspell-config/cspell-blockchain.txt b/cspell-config/cspell-blockchain.txt index a56a69cc..fc5b6b03 100644 --- a/cspell-config/cspell-blockchain.txt +++ b/cspell-config/cspell-blockchain.txt @@ -5,4 +5,5 @@ Initializable initializable UUPS merkle -uups \ No newline at end of file +uups +Sepolia \ No newline at end of file