import { Provider, Wallet } from "zksync-web3";
import * as ethers from "ethers";
import { HardhatRuntimeEnvironment } from "hardhat/types";
import { Deployer } from "@matterlabs/hardhat-zksync-deploy";
require("dotenv").config();
// Define constants and environment variables
const ZKSYNC_CHAINSTACK_ENDPOINT = process.env.ZKSYNC_TESTNET_CHAINSTACK;
const PRIVATE_KEY = process.env.PRIVATE_KEY;
const initialFunding = 0.01;
const tokensToMint = 10;
const CONFIRMATIONS = 4;
const TOKEN_NAME = "Chainstack gas";
const TOKEN_SYMBOL = "CSG";
const TOKEN_DECIMALS = 18;
const TOKEN_CONTRACT_PATH = "contracts/CSgas.sol:CSgas";
const PAYMASTER_CONTRACT_PATH = "contracts/Paymaster.sol:Paymaster";
// Check if environment variables are set
if (!ZKSYNC_CHAINSTACK_ENDPOINT) {
throw new Error(
"ZKSYNC_TESTNET_CHAINSTACK is not set in the environment variables"
);
}
if (!PRIVATE_KEY) {
throw new Error("Private key is not set in the environment variables");
}
// Function to create a new wallet
async function createWallet() {
console.log("Creating new test wallet...");
const wallet = Wallet.createRandom();
console.log(`New wallet address: ${wallet.address}`);
console.log(`New wallet private key: ${wallet.privateKey}`);
return wallet;
}
// Function to deploy a contract
async function deployContract(
deployer: Deployer,
contractName: string,
args: any[]
) {
console.log(`Deploying ${contractName}...`);
const contractArtifact = await deployer.loadArtifact(contractName);
const contractInstance = await deployer.deploy(contractArtifact, args);
await contractInstance.deployTransaction.wait(CONFIRMATIONS);
console.log(`${contractName} deployed at: ${contractInstance.address}`);
return contractInstance;
}
// Function to verify a contract
async function verifyContract(
hre: HardhatRuntimeEnvironment,
address: string,
contractPath: string,
args: any[]
) {
console.log(`Verifying contract...`);
return await hre.run("verify:verify", {
address: address,
contract: contractPath,
constructorArguments: args,
});
}
// Function to fund the Paymaster contract
async function fundPaymaster(deployer: Deployer, paymasterAddress: string) {
console.log(`Funding Paymaster with ${initialFunding} ETH on zkSync...`);
return await (
await deployer.zkWallet.sendTransaction({
to: paymasterAddress,
value: ethers.utils.parseEther(String(initialFunding)),
})
).wait(CONFIRMATIONS);
}
// Function to mint tokens
async function mintTokens(contract: any, address: string) {
console.log(`Minting ${tokensToMint} tokens to ${address}`);
return await (
await contract.mint(address, ethers.utils.parseEther(String(tokensToMint)))
).wait();
}
// Main function for deployment
export default async function (hre: HardhatRuntimeEnvironment) {
try {
// Initialize provider, wallet, and deployer
const provider = new Provider(ZKSYNC_CHAINSTACK_ENDPOINT);
const wallet = new Wallet(PRIVATE_KEY);
const deployer = new Deployer(hre, wallet);
// Create a new wallet, this is only for showing how an wallet with no ETH can be sponsored by the paymaster
const newWallet = await createWallet();
//Deploy the Gas token
const deployedChainstackGas = await deployContract(deployer, "CSgas", [
TOKEN_NAME,
TOKEN_SYMBOL,
TOKEN_DECIMALS,
]);
// Deploy the Paymaster
const deployedPaymaster = await deployContract(deployer, "Paymaster", [
deployedChainstackGas.address,
]);
// Verify the 2 contracts
await verifyContract(
hre,
deployedChainstackGas.address,
TOKEN_CONTRACT_PATH,
[TOKEN_NAME, TOKEN_SYMBOL, TOKEN_DECIMALS]
);
await verifyContract(
hre,
deployedPaymaster.address,
PAYMASTER_CONTRACT_PATH,
[deployedChainstackGas.address]
);
// Fund the Paymaster contract and mint tokens
await fundPaymaster(deployer, deployedPaymaster.address);
await mintTokens(deployedChainstackGas, newWallet.address);
console.log(`Paymaster and new wallet funded!`);
// Get and log the balance of the Paymaster contract
const paymasterBalance = await provider.getBalance(
deployedPaymaster.address
);
console.log(
`Paymaster balance: ${ethers.utils.formatEther(paymasterBalance)}`
);
// Get and log the balance of the new wallet
const newWalletTokenBalance = await deployedChainstackGas.balanceOf(
newWallet.address
);
const newWalletTokenBalanceInEther = ethers.utils.formatEther(
newWalletTokenBalance
);
console.log(
`New wallet's Chainstack gas token balance: ${newWalletTokenBalanceInEther}`
);
} catch (error) {
console.error(`Error during deployment: ${error}`);
}
}