From 9dfbd296e5d5bdfad4e4cad1a9ca12309b3f0fea Mon Sep 17 00:00:00 2001 From: Dennis <10233439+idea404@users.noreply.github.com> Date: Sun, 12 Nov 2023 00:30:43 +0100 Subject: [PATCH] feat: add demo scripts --- demo/pension-fund-eth.ts | 39 +++++++++++++ demo/pension-send-eth.ts | 2 + ...{deploy-factory.ts => deploy-aafactory.ts} | 7 +-- deploy/deploy-multisig.ts | 21 +++---- deploy/deploy-pafactory.ts | 31 +++++++++++ deploy/deploy-pension.ts | 41 ++++++++++++++ deploy/utils.ts | 55 +++++++++++++++++++ deploy/vars.json | 14 +++++ package.json | 8 ++- 9 files changed, 202 insertions(+), 16 deletions(-) create mode 100644 demo/pension-fund-eth.ts create mode 100644 demo/pension-send-eth.ts rename deploy/{deploy-factory.ts => deploy-aafactory.ts} (84%) create mode 100644 deploy/deploy-pafactory.ts create mode 100644 deploy/deploy-pension.ts create mode 100644 deploy/utils.ts create mode 100644 deploy/vars.json diff --git a/demo/pension-fund-eth.ts b/demo/pension-fund-eth.ts new file mode 100644 index 0000000..2ae1187 --- /dev/null +++ b/demo/pension-fund-eth.ts @@ -0,0 +1,39 @@ +// This script will: +// 1. Send ETH to the pension account + +import { ethers } from "ethers"; +import { Provider, Wallet } from "zksync-web3"; +import dotenv from "dotenv"; +import { getDeployedContractDetailsFromVars, config } from "../deploy/utils"; + +dotenv.config(); + +const NETWORK = "zkSyncLocalnet"; +const RPC_URL = config.L2RpcUrl; +const PRIVATE_KEY = config.firstWalletPrivateKey; + +async function main() { + const provider = new Provider(RPC_URL); + const mainWallet = new Wallet(PRIVATE_KEY, provider); + + // Load the contract address from vars.json + const paAddress = getDeployedContractDetailsFromVars(NETWORK, "PensionAccount").address; + // send 100 ETH to the paAddress + const balance = await provider.getBalance(paAddress); + const tx = await mainWallet.sendTransaction({ + to: paAddress, + value: ethers.utils.parseEther("100"), + }); + await tx.wait(); + const newBalance = await provider.getBalance(paAddress); + console.log(`Sent 100 ETH to Pension Account at: ${paAddress}`); + console.log(`Balance before: ${ethers.utils.formatEther(balance)} ETH`); + console.log(`Balance after: ${ethers.utils.formatEther(newBalance)} ETH`); +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error); + process.exit(1); + }); \ No newline at end of file diff --git a/demo/pension-send-eth.ts b/demo/pension-send-eth.ts new file mode 100644 index 0000000..738b614 --- /dev/null +++ b/demo/pension-send-eth.ts @@ -0,0 +1,2 @@ +// This script will: +// 1. Attempt to send ETH from the pension contract to another address. diff --git a/deploy/deploy-factory.ts b/deploy/deploy-aafactory.ts similarity index 84% rename from deploy/deploy-factory.ts rename to deploy/deploy-aafactory.ts index fb95dc9..cdc65ec 100644 --- a/deploy/deploy-factory.ts +++ b/deploy/deploy-aafactory.ts @@ -1,11 +1,9 @@ import { utils, Wallet } from "zksync-web3"; import { HardhatRuntimeEnvironment } from "hardhat/types"; import { Deployer } from "@matterlabs/hardhat-zksync-deploy"; -import dotenv from "dotenv"; +import { config, saveContractToVars } from "./utils"; -dotenv.config(); - -const KEY = process.env.PRIVATE_KEY as string; +const KEY = config.firstWalletPrivateKey; export default async function (hre: HardhatRuntimeEnvironment) { // Private key of the account used to deploy @@ -29,4 +27,5 @@ export default async function (hre: HardhatRuntimeEnvironment) { ); console.log(`AA factory address: ${factory.address}`); + saveContractToVars(hre.network.name, "AAFactory", factory.address); } diff --git a/deploy/deploy-multisig.ts b/deploy/deploy-multisig.ts index cb7d457..ee3ec4d 100644 --- a/deploy/deploy-multisig.ts +++ b/deploy/deploy-multisig.ts @@ -1,23 +1,23 @@ import { utils, Wallet, Provider, EIP712Signer, types } from "zksync-web3"; import * as ethers from "ethers"; import { HardhatRuntimeEnvironment } from "hardhat/types"; -import dotenv from "dotenv"; +import { config, getDeployedContractDetailsFromVars, saveContractToVars } from "./utils"; -dotenv.config(); - -const KEY = process.env.PRIVATE_KEY as string; - -// Put the address of your AA factory -const AA_FACTORY_ADDRESS = "0xb3AE0580Fff458E48Eb97EcDaD7Bbe825b78F410"; +const KEY = config.firstWalletPrivateKey; export default async function (hre: HardhatRuntimeEnvironment) { - const provider = new Provider("https://testnet.era.zksync.dev"); + // Put the address of your AA factory + const factoryAddress = getDeployedContractDetailsFromVars( + hre.network.name, + "AAFactory" + ).address; + const provider = new Provider(hre.network.config.url); // Private key of the account used to deploy const wallet = new Wallet(KEY).connect(provider); const factoryArtifact = await hre.artifacts.readArtifact("AAFactory"); const aaFactory = new ethers.Contract( - AA_FACTORY_ADDRESS, + factoryAddress, factoryArtifact.abi, wallet ); @@ -40,12 +40,13 @@ export default async function (hre: HardhatRuntimeEnvironment) { // Getting the address of the deployed contract account const abiCoder = new ethers.utils.AbiCoder(); const multisigAddress = utils.create2Address( - AA_FACTORY_ADDRESS, + factoryAddress, await aaFactory.aaBytecodeHash(), salt, abiCoder.encode(["address", "address"], [owner1.address, owner2.address]) ); console.log(`Multisig account deployed on address ${multisigAddress}`); + saveContractToVars(hre.network.name, "TwoUserMultisig", aaFactory.address); console.log("Sending funds to multisig account"); // Send funds to the multisig account we just deployed diff --git a/deploy/deploy-pafactory.ts b/deploy/deploy-pafactory.ts new file mode 100644 index 0000000..5f79c30 --- /dev/null +++ b/deploy/deploy-pafactory.ts @@ -0,0 +1,31 @@ +import { utils, Wallet } from "zksync-web3"; +import { HardhatRuntimeEnvironment } from "hardhat/types"; +import { Deployer } from "@matterlabs/hardhat-zksync-deploy"; +import { config, saveContractToVars } from "./utils"; + +const KEY = config.firstWalletPrivateKey; + +export default async function (hre: HardhatRuntimeEnvironment) { + // Private key of the account used to deploy + const wallet = new Wallet(KEY); + const deployer = new Deployer(hre, wallet); + const pensionAccountFactoryArtifact = await deployer.loadArtifact("PensionAccountFactory"); + const paArtifact = await deployer.loadArtifact("PensionAccount"); + + // Getting the bytecodeHash of the account + const bytecodeHash = utils.hashBytecode(paArtifact.bytecode); + + const factory = await deployer.deploy( + pensionAccountFactoryArtifact, + [bytecodeHash], + undefined, + [ + // Since the factory requires the code of the multisig to be available, + // we should pass it here as well. + paArtifact.bytecode, + ] + ); + + console.log(`Pension Account factory address: ${factory.address}`); + saveContractToVars(hre.network.name, "PensionAccountFactory", factory.address); +} diff --git a/deploy/deploy-pension.ts b/deploy/deploy-pension.ts new file mode 100644 index 0000000..25d2d4d --- /dev/null +++ b/deploy/deploy-pension.ts @@ -0,0 +1,41 @@ +import { utils, Wallet, Provider } from "zksync-web3"; +import { HardhatRuntimeEnvironment } from "hardhat/types"; +import { config, getDeployedContractDetailsFromVars, createMockAddress, saveContractToVars } from "./utils"; +import { ethers } from "ethers"; + +const KEY = config.firstWalletPrivateKey; +const OWNER_KEY = config.secondWalletPrivateKey; + +export default async function (hre: HardhatRuntimeEnvironment) { + const provider = new Provider(hre.network.config.url); + const wallet = new Wallet(KEY, provider); + const walletOwner = new Wallet(OWNER_KEY, provider); + const factoryAddress = getDeployedContractDetailsFromVars(hre.network.name, "PensionAccountFactory").address; + const paFactoryArtifact = await hre.artifacts.readArtifact("PensionAccountFactory"); + + const paFactory = new ethers.Contract(factoryAddress, paFactoryArtifact.abi, wallet); + + // Contract constructor args + const dex = createMockAddress("decentralizedex"); // "0xdex0000000000000000000000000000000000000" + const doge = createMockAddress("dogecoin"); // "0xdoge000000000000000000000000000000000000" + const pepe = createMockAddress("pepecoin"); // "0xpepe000000000000000000000000000000000000" + const shib = createMockAddress("shibainucoin"); // "0xshib0000000000000000000000000000000000000" + const btc = createMockAddress("bitcoin"); // "0xbtc00000000000000000000000000000000000000" + + // For the simplicity of the tutorial, we will use zero hash as salt + const salt = ethers.constants.HashZero; + + // deploy account with dex and token addresses + const tx = await paFactory.deployPensionAccount(salt, walletOwner.address, dex, doge, pepe, shib, btc, { gasLimit: 10000000 }); + await tx.wait(); + + // Getting the address of the deployed contract account + const abiCoder = new ethers.utils.AbiCoder(); + let contractAddress = utils.create2Address( + factoryAddress, + await paFactory.pensionAccountBytecodeHash(), + salt, + abiCoder.encode(["address", "address", "address", "address", "address", "address"], [walletOwner.address, dex, doge, pepe, shib, btc]) + ); + saveContractToVars(hre.network.name, "PensionAccount", contractAddress); +} diff --git a/deploy/utils.ts b/deploy/utils.ts new file mode 100644 index 0000000..5e66b62 --- /dev/null +++ b/deploy/utils.ts @@ -0,0 +1,55 @@ +import fs from "fs"; +import path from "path"; + +const JSON_FILE_PATH = path.join(__dirname, "vars.json"); + +export function saveContractToVars(network: string, contractName: string, contractAddress: string, varsPath = JSON_FILE_PATH) { + console.log(`Saving ${contractName} to vars.json`); + const config = JSON.parse(fs.readFileSync(varsPath, "utf-8")); + + if (!config[network]) { + config[network] = { deployed: [] }; + } + + const deployedContracts = config[network].deployed; + const existingContractIndex = deployedContracts.findIndex((contract: { name: string; }) => contract.name === contractName); + + if (existingContractIndex === -1) { + console.log(`Adding ${contractName} to vars.json`); + deployedContracts.push({ + name: contractName, + address: contractAddress, + }); + } else { + console.log(`Updating ${contractName} in vars.json`); + deployedContracts[existingContractIndex].address = contractAddress; + } + + fs.writeFileSync(varsPath, JSON.stringify(config, null, 2)); +} + +export function getDeployedContractDetailsFromVars(network: string, contractName: string, varsPath = JSON_FILE_PATH) { + const config = JSON.parse(fs.readFileSync(varsPath, "utf-8")); + const deployedContracts = config[network].deployed; + const existingContract = deployedContracts.find((contract: { name: string; }) => contract.name === contractName); + + if (!existingContract) { + throw new Error(`Contract ${contractName} not found in vars.json`); + } + + return existingContract; +} + +export const config = { + L2RpcUrl: "http://127.0.0.1:8011", + firstWalletPrivateKey: "0x7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110", + firstWalletAddress: "0x36615Cf349d7F6344891B1e7CA7C72883F5dc049", + secondWalletPrivateKey: "0xac1e735be8536c6534bb4f17f06f6afc73b2b5ba84ac2cfb12f7461b20c0bbe3", + secondWalletAddress: "0xa61464658AfeAf65CccaaFD3a512b69A83B77618", +}; + +export function createMockAddress(base: string) { + const baseHex = base.replace(/[^0-9A-Fa-f]/g, ''); // Remove non-hex characters + const paddingLength = 40 - baseHex.length; // Calculate padding length + return '0x' + baseHex + '0'.repeat(paddingLength); +} diff --git a/deploy/vars.json b/deploy/vars.json new file mode 100644 index 0000000..d6046a3 --- /dev/null +++ b/deploy/vars.json @@ -0,0 +1,14 @@ +{ + "zkSyncLocalnet": { + "deployed": [ + { + "name": "PensionAccountFactory", + "address": "0x4B5DF730c2e6b28E17013A1485E5d9BC41Efe021" + }, + { + "name": "PensionAccount", + "address": "0x7A4C681d869bfF421d752B696cd8eC6eD6c7EfBa" + } + ] + } +} \ No newline at end of file diff --git a/package.json b/package.json index af963b3..ba2cb75 100644 --- a/package.json +++ b/package.json @@ -5,8 +5,12 @@ "license": "MIT", "scripts": { "test": "hardhat test --network hardhat", - "deploy:factory": "hardhat deploy-zksync --script deploy-factory.ts --network zkSyncTestnet", - "deploy:multisig": "hardhat deploy-zksync --script deploy-multisig.ts --network zkSyncTestnet" + "deploy:aafactory": "hardhat deploy-zksync --script deploy-aafactory.ts --network zkSyncLocalnet", + "deploy:multisig": "hardhat deploy-zksync --script deploy-multisig.ts --network zkSyncLocalnet", + "deploy:pafactory": "hardhat deploy-zksync --script deploy-pafactory.ts --network zkSyncLocalnet", + "deploy:pension": "hardhat deploy-zksync --script deploy-pension.ts --network zkSyncLocalnet", + "demo:fund-pension": "ts-node demo/pension-fund-eth.ts", + "demo:withdraw-pension": "ts-node demo/pension-send-eth.ts" }, "devDependencies": { "@types/chai": "^4.3.10",