-
Notifications
You must be signed in to change notification settings - Fork 20
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
f4e5cae
commit ab8fc2c
Showing
55 changed files
with
2,748 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
WALLET_PRIVATE_KEY= |
23 changes: 23 additions & 0 deletions
23
templates/quickstart/factories/contracts/CrowdfundFactory.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.0; | ||
|
||
// Crowdfunding campaign contract | ||
import "./CrowdfundingCampaign.sol"; | ||
|
||
// Factory contract to create and manage crowdfunding campaigns | ||
contract CrowdfundingFactory { | ||
CrowdfundingCampaign[] public campaigns; | ||
|
||
event CampaignCreated(address campaignAddress, uint256 fundingGoal); | ||
|
||
function createCampaign(uint256 fundingGoal) public { | ||
CrowdfundingCampaign newCampaign = new CrowdfundingCampaign(fundingGoal); | ||
campaigns.push(newCampaign); | ||
|
||
emit CampaignCreated(address(newCampaign), fundingGoal); | ||
} | ||
|
||
function getCampaigns() public view returns (CrowdfundingCampaign[] memory) { | ||
return campaigns; | ||
} | ||
} |
48 changes: 48 additions & 0 deletions
48
templates/quickstart/factories/contracts/CrowdfundingCampaign.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.0; | ||
|
||
contract CrowdfundingCampaign { | ||
address public owner; | ||
uint256 public fundingGoal; | ||
uint256 public totalFundsRaised; | ||
mapping(address => uint256) public contributions; | ||
|
||
event ContributionReceived(address contributor, uint256 amount); | ||
event GoalReached(uint256 totalFundsRaised); | ||
|
||
constructor(uint256 _fundingGoal) { | ||
owner = msg.sender; | ||
fundingGoal = _fundingGoal; | ||
} | ||
|
||
function contribute() public payable { | ||
require(msg.value > 0, "Contribution must be greater than 0"); | ||
contributions[msg.sender] += msg.value; | ||
totalFundsRaised += msg.value; | ||
|
||
emit ContributionReceived(msg.sender, msg.value); | ||
|
||
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; | ||
} | ||
|
||
function getFundingGoal() public view returns (uint256) { | ||
return fundingGoal; | ||
} | ||
} |
32 changes: 32 additions & 0 deletions
32
templates/quickstart/factories/deploy/deployUsingFactory.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import { deployContract, getWallet } from "./utils"; | ||
import { ethers } from "ethers"; | ||
import { HardhatRuntimeEnvironment } from "hardhat/types"; | ||
|
||
export default async function (hre: HardhatRuntimeEnvironment) { | ||
const contractArtifactName = "CrowdfundingFactory"; | ||
const constructorArguments = []; | ||
const crowdfundingFactory = await deployContract(contractArtifactName, constructorArguments); | ||
|
||
console.log(`🏭 CrowdfundingFactory address: ${crowdfundingFactory.target}`); | ||
|
||
const contractArtifact = await hre.artifacts.readArtifact("CrowdfundingFactory"); | ||
const factoryContract = new ethers.Contract( | ||
crowdfundingFactory.target, | ||
contractArtifact.abi, | ||
getWallet() | ||
); | ||
|
||
// Define funding goal for the campaign, e.g., 0.1 ether | ||
const fundingGoalInWei = ethers.parseEther('0.1').toString(); | ||
|
||
// Use the factory to create a new CrowdfundingCampaign | ||
const createTx = await factoryContract.createCampaign(fundingGoalInWei); | ||
await createTx.wait(); | ||
|
||
// Retrieve the address of the newly created CrowdfundingCampaign | ||
const campaigns = await factoryContract.getCampaigns(); | ||
const newCampaignAddress = campaigns[campaigns.length - 1]; | ||
|
||
console.log(`🚀 New CrowdfundingCampaign deployed at: ${newCampaignAddress}`); | ||
console.log('✅ Deployment and campaign creation complete!'); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
import { Provider, Wallet } from "zksync-ethers"; | ||
import * as hre from "hardhat"; | ||
import { Deployer } from "@matterlabs/hardhat-zksync"; | ||
import dotenv from "dotenv"; | ||
import { ethers } from "ethers"; | ||
|
||
import "@matterlabs/hardhat-zksync-node/dist/type-extensions"; | ||
import "@matterlabs/hardhat-zksync-verify/dist/src/type-extensions"; | ||
|
||
// Load env file | ||
dotenv.config(); | ||
|
||
export const getProvider = () => { | ||
const rpcUrl = hre.network.config.url; | ||
if (!rpcUrl) throw `⛔️ RPC URL wasn't found in "${hre.network.name}"! Please add a "url" field to the network config in hardhat.config.ts`; | ||
|
||
// Initialize zkSync Provider | ||
const provider = new Provider(rpcUrl); | ||
|
||
return provider; | ||
} | ||
|
||
export const getWallet = (privateKey?: string) => { | ||
if (!privateKey) { | ||
// Get wallet private key from .env file | ||
if (!process.env.WALLET_PRIVATE_KEY) throw "⛔️ Wallet private key wasn't found in .env file!"; | ||
} | ||
|
||
const provider = getProvider(); | ||
|
||
// Initialize zkSync Wallet | ||
const wallet = new Wallet(privateKey ?? process.env.WALLET_PRIVATE_KEY!, provider); | ||
|
||
return wallet; | ||
} | ||
|
||
export const verifyEnoughBalance = async (wallet: Wallet, amount: bigint) => { | ||
// Check if the wallet has enough balance | ||
const balance = await wallet.getBalance(); | ||
if (balance < amount) throw `⛔️ Wallet balance is too low! Required ${ethers.formatEther(amount)} ETH, but current ${wallet.address} balance is ${ethers.formatEther(balance)} ETH`; | ||
} | ||
|
||
/** | ||
* @param {string} data.contract The contract's path and name. E.g., "contracts/Greeter.sol:Greeter" | ||
*/ | ||
export const verifyContract = async (data: { | ||
address: string, | ||
contract: string, | ||
constructorArguments: string, | ||
bytecode: string | ||
}) => { | ||
const verificationRequestId: number = await hre.run("verify:verify", { | ||
...data, | ||
noCompile: true, | ||
}); | ||
return verificationRequestId; | ||
} | ||
|
||
type DeployContractOptions = { | ||
/** | ||
* If true, the deployment process will not print any logs | ||
*/ | ||
silent?: boolean | ||
/** | ||
* If true, the contract will not be verified on Block Explorer | ||
*/ | ||
noVerify?: boolean | ||
/** | ||
* If specified, the contract will be deployed using this wallet | ||
*/ | ||
wallet?: Wallet | ||
} | ||
export const deployContract = async (contractArtifactName: string, constructorArguments?: any[], options?: DeployContractOptions) => { | ||
const log = (message: string) => { | ||
if (!options?.silent) console.log(message); | ||
} | ||
|
||
log(`\nStarting deployment process of "${contractArtifactName}"...`); | ||
|
||
const wallet = options?.wallet ?? getWallet(); | ||
const deployer = new Deployer(hre, wallet); | ||
const artifact = await deployer.loadArtifact(contractArtifactName).catch((error) => { | ||
if (error?.message?.includes(`Artifact for contract "${contractArtifactName}" not found.`)) { | ||
console.error(error.message); | ||
throw `⛔️ Please make sure you have compiled your contracts or specified the correct contract name!`; | ||
} else { | ||
throw error; | ||
} | ||
}); | ||
|
||
// Estimate contract deployment fee | ||
const deploymentFee = await deployer.estimateDeployFee(artifact, constructorArguments || []); | ||
log(`Estimated deployment cost: ${ethers.formatEther(deploymentFee)} ETH`); | ||
|
||
// Check if the wallet has enough balance | ||
await verifyEnoughBalance(wallet, deploymentFee); | ||
|
||
// Deploy the contract to zkSync | ||
const contract = await deployer.deploy(artifact, constructorArguments); | ||
const address = await contract.getAddress(); | ||
const constructorArgs = contract.interface.encodeDeploy(constructorArguments); | ||
const fullContractSource = `${artifact.sourceName}:${artifact.contractName}`; | ||
|
||
// Display contract deployment info | ||
log(`\n"${artifact.contractName}" was successfully deployed:`); | ||
log(` - Contract address: ${address}`); | ||
log(` - Contract source: ${fullContractSource}`); | ||
log(` - Encoded constructor arguments: ${constructorArgs}\n`); | ||
|
||
if (!options?.noVerify && hre.network.config.verifyURL) { | ||
log(`Requesting contract verification...`); | ||
await verifyContract({ | ||
address, | ||
contract: fullContractSource, | ||
constructorArguments: constructorArgs, | ||
bytecode: artifact.bytecode, | ||
}); | ||
} | ||
|
||
return contract; | ||
} | ||
|
||
/** | ||
* Rich wallets can be used for testing purposes. | ||
* Available on zkSync In-memory node and Dockerized node. | ||
*/ | ||
export const LOCAL_RICH_WALLETS = [ | ||
{ | ||
address: "0x36615Cf349d7F6344891B1e7CA7C72883F5dc049", | ||
privateKey: "0x7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110" | ||
}, | ||
{ | ||
address: "0xa61464658AfeAf65CccaaFD3a512b69A83B77618", | ||
privateKey: "0xac1e735be8536c6534bb4f17f06f6afc73b2b5ba84ac2cfb12f7461b20c0bbe3" | ||
}, | ||
{ | ||
address: "0x0D43eB5B8a47bA8900d84AA36656c92024e9772e", | ||
privateKey: "0xd293c684d884d56f8d6abd64fc76757d3664904e309a0645baf8522ab6366d9e" | ||
}, | ||
{ | ||
address: "0xA13c10C0D5bd6f79041B9835c63f91de35A15883", | ||
privateKey: "0x850683b40d4a740aa6e745f889a6fdc8327be76e122f5aba645a5b02d0248db8" | ||
}, | ||
{ | ||
address: "0x8002cD98Cfb563492A6fB3E7C8243b7B9Ad4cc92", | ||
privateKey: "0xf12e28c0eb1ef4ff90478f6805b68d63737b7f33abfa091601140805da450d93" | ||
}, | ||
{ | ||
address: "0x4F9133D1d3F50011A6859807C837bdCB31Aaab13", | ||
privateKey: "0xe667e57a9b8aaa6709e51ff7d093f1c5b73b63f9987e4ab4aa9a5c699e024ee8" | ||
}, | ||
{ | ||
address: "0xbd29A1B981925B94eEc5c4F1125AF02a2Ec4d1cA", | ||
privateKey: "0x28a574ab2de8a00364d5dd4b07c4f2f574ef7fcc2a86a197f65abaec836d1959" | ||
}, | ||
{ | ||
address: "0xedB6F5B4aab3dD95C7806Af42881FF12BE7e9daa", | ||
privateKey: "0x74d8b3a188f7260f67698eb44da07397a298df5427df681ef68c45b34b61f998" | ||
}, | ||
{ | ||
address: "0xe706e60ab5Dc512C36A4646D719b889F398cbBcB", | ||
privateKey: "0xbe79721778b48bcc679b78edac0ce48306a8578186ffcb9f2ee455ae6efeace1" | ||
}, | ||
{ | ||
address: "0xE90E12261CCb0F3F7976Ae611A29e84a6A85f424", | ||
privateKey: "0x3eb15da85647edd9a1159a4a13b9e7c56877c4eb33f614546d4db06a51868b1c" | ||
} | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import { HardhatUserConfig } from "hardhat/config"; | ||
|
||
import "@matterlabs/hardhat-zksync"; | ||
|
||
const config: HardhatUserConfig = { | ||
defaultNetwork: "zkSyncSepoliaTestnet", | ||
networks: { | ||
zkSyncSepoliaTestnet: { | ||
url: "https://sepolia.era.zksync.dev", | ||
ethNetwork: "sepolia", | ||
zksync: true, | ||
verifyURL: "https://explorer.sepolia.era.zksync.dev/contract_verification", | ||
}, | ||
zkSyncMainnet: { | ||
url: "https://mainnet.era.zksync.io", | ||
ethNetwork: "mainnet", | ||
zksync: true, | ||
verifyURL: "https://zksync2-mainnet-explorer.zksync.io/contract_verification", | ||
}, | ||
zkSyncGoerliTestnet: { // deprecated network | ||
url: "https://testnet.era.zksync.dev", | ||
ethNetwork: "goerli", | ||
zksync: true, | ||
verifyURL: "https://zksync2-testnet-explorer.zksync.dev/contract_verification", | ||
}, | ||
dockerizedNode: { | ||
url: "http://localhost:3050", | ||
ethNetwork: "http://localhost:8545", | ||
zksync: true, | ||
}, | ||
inMemoryNode: { | ||
url: "http://127.0.0.1:8011", | ||
ethNetwork: "localhost", // in-memory node doesn't support eth node; removing this line will cause an error | ||
zksync: true, | ||
}, | ||
hardhat: { | ||
zksync: true, | ||
}, | ||
}, | ||
zksolc: { | ||
version: "latest", | ||
settings: { | ||
// find all available options in the official documentation | ||
// https://era.zksync.io/docs/tools/hardhat/hardhat-zksync-solc.html#configuration | ||
}, | ||
}, | ||
solidity: { | ||
version: "0.8.17", | ||
}, | ||
}; | ||
|
||
export default config; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
{ | ||
"name": "hello-zksync-quickstart", | ||
"description": "A template for zkSync smart contracts development with Hardhat", | ||
"private": true, | ||
"author": "Matter Labs", | ||
"license": "MIT", | ||
"repository": "https://github.com/matter-labs/zksync-hardhat-template.git", | ||
"scripts": { | ||
"deploy": "hardhat deploy-zksync --script deploy.ts", | ||
"compile": "hardhat compile", | ||
"clean": "hardhat clean" | ||
}, | ||
"devDependencies": { | ||
"@matterlabs/hardhat-zksync": "^1.0.0", | ||
"@matterlabs/zksync-contracts": "^0.6.1", | ||
"@nomiclabs/hardhat-etherscan": "^3.1.7", | ||
"@nomicfoundation/hardhat-chai-matchers": "^2.0.6", | ||
"@openzeppelin/contracts": "^4.6.0", | ||
"@types/chai": "^4.3.4", | ||
"@types/mocha": "^10.0.1", | ||
"chai": "^4.3.7", | ||
"dotenv": "^16.0.3", | ||
"ethers": "^6.9.2", | ||
"hardhat": "^2.12.4", | ||
"mocha": "^10.2.0", | ||
"ts-node": "^10.9.1", | ||
"typescript": "^4.9.5", | ||
"zksync-ethers": "^6.7.0" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
WALLET_PRIVATE_KEY= |
Oops, something went wrong.