diff --git a/packages/hardhat/hardhat.config.ts b/packages/hardhat/hardhat.config.ts index fd4a6d41a..4bbddc054 100644 --- a/packages/hardhat/hardhat.config.ts +++ b/packages/hardhat/hardhat.config.ts @@ -13,8 +13,7 @@ import { task } from "hardhat/config"; import generateTsAbis from "./scripts/generateTsAbis"; // If not set, it uses the hardhat account 0 private key. -const deployerPrivateKey = - process.env.DEPLOYER_PRIVATE_KEY ?? "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"; +const deployerPrivateKey = "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"; // If not set, it uses our block explorers default API keys. const etherscanApiKey = process.env.ETHERSCAN_MAINNET_API_KEY || "DNXJA8RX2Q3VZ4URQIWP7Z68CJXQZSC6AW"; const etherscanOptimisticApiKey = process.env.ETHERSCAN_OPTIMISTIC_API_KEY || "RM62RDISS1RH448ZY379NX625ASG1N633R"; diff --git a/packages/hardhat/package.json b/packages/hardhat/package.json index 2a17b3ebe..5791678ab 100644 --- a/packages/hardhat/package.json +++ b/packages/hardhat/package.json @@ -49,6 +49,7 @@ "typescript": "<5.6.0" }, "dependencies": { + "@inquirer/password": "^4.0.2", "@openzeppelin/contracts": "^5.0.2", "@typechain/ethers-v6": "^0.5.1", "dotenv": "^16.4.5", diff --git a/packages/hardhat/scripts/generateAccount.ts b/packages/hardhat/scripts/generateAccount.ts index 5de8e458c..1fc127ccb 100644 --- a/packages/hardhat/scripts/generateAccount.ts +++ b/packages/hardhat/scripts/generateAccount.ts @@ -1,42 +1,55 @@ import { ethers } from "ethers"; import { parse, stringify } from "envfile"; import * as fs from "fs"; +import password from "@inquirer/password"; const envFilePath = "./.env"; -/** - * Generate a new random private key and write it to the .env file - */ -const setNewEnvConfig = (existingEnvConfig = {}) => { - console.log("šŸ‘› Generating new Wallet"); +const getValidatedPassword = async () => { + while (true) { + const pass = await password({ message: "Enter a password to encrypt your private key:", mask: true }); + const confirmation = await password({ message: "Confirm password:", mask: true }); + + if (pass === confirmation) { + return pass; + } + console.log("āŒ Passwords don't match. Please try again."); + } +}; + +const setNewEnvConfig = async (existingEnvConfig = {}) => { + console.log("šŸ‘› Generating new Wallet\n"); const randomWallet = ethers.Wallet.createRandom(); + const pass = await getValidatedPassword(); + const encryptedJson = await randomWallet.encrypt(pass); + const newEnvConfig = { ...existingEnvConfig, - DEPLOYER_PRIVATE_KEY: randomWallet.privateKey, + DEPLOYER_PRIVATE_KEY: encryptedJson, }; // Store in .env fs.writeFileSync(envFilePath, stringify(newEnvConfig)); - console.log("šŸ“„ Private Key saved to packages/hardhat/.env file"); - console.log("šŸŖ„ Generated wallet address:", randomWallet.address); + console.log("\nšŸ“„ Encrypted Private Key saved to packages/hardhat/.env file"); + console.log("šŸŖ„ Generated wallet address:", randomWallet.address, "\n"); + console.log("āš ļø Make sure to remember your password! You'll need it to decrypt the private key."); }; async function main() { if (!fs.existsSync(envFilePath)) { // No .env file yet. - setNewEnvConfig(); + await setNewEnvConfig(); return; } - // .env file exists const existingEnvConfig = parse(fs.readFileSync(envFilePath).toString()); if (existingEnvConfig.DEPLOYER_PRIVATE_KEY) { console.log("āš ļø You already have a deployer account. Check the packages/hardhat/.env file"); return; } - setNewEnvConfig(existingEnvConfig); + await setNewEnvConfig(existingEnvConfig); } main().catch(error => { diff --git a/packages/hardhat/scripts/listAccount.ts b/packages/hardhat/scripts/listAccount.ts index 4fc5f2da1..84273dd32 100644 --- a/packages/hardhat/scripts/listAccount.ts +++ b/packages/hardhat/scripts/listAccount.ts @@ -3,17 +3,26 @@ dotenv.config(); import { ethers, Wallet } from "ethers"; import QRCode from "qrcode"; import { config } from "hardhat"; +import password from "@inquirer/password"; async function main() { - const privateKey = process.env.DEPLOYER_PRIVATE_KEY; + const encryptedKey = process.env.DEPLOYER_PRIVATE_KEY; - if (!privateKey) { + if (!encryptedKey) { console.log("šŸš«ļø You don't have a deployer account. Run `yarn generate` first"); return; } - // Get account from private key. - const wallet = new Wallet(privateKey); + const pass = await password({ message: "Enter your password to decrypt the private key:", mask: true }); + let wallet: Wallet; + try { + wallet = (await Wallet.fromEncryptedJson(encryptedKey, pass)) as Wallet; + // eslint-disable-next-line @typescript-eslint/no-unused-vars + } catch (e) { + console.log("āŒ Failed to decrypt private key. Wrong password?"); + return; + } + const address = wallet.address; console.log(await QRCode.toString(address, { type: "terminal", small: true })); console.log("Public address:", address, "\n"); diff --git a/yarn.lock b/yarn.lock index 0260af23f..e0d7cca62 100644 --- a/yarn.lock +++ b/yarn.lock @@ -903,6 +903,52 @@ __metadata: languageName: node linkType: hard +"@inquirer/core@npm:^10.1.0": + version: 10.1.0 + resolution: "@inquirer/core@npm:10.1.0" + dependencies: + "@inquirer/figures": ^1.0.8 + "@inquirer/type": ^3.0.1 + ansi-escapes: ^4.3.2 + cli-width: ^4.1.0 + mute-stream: ^2.0.0 + signal-exit: ^4.1.0 + strip-ansi: ^6.0.1 + wrap-ansi: ^6.2.0 + yoctocolors-cjs: ^2.1.2 + checksum: c52be9ef04497a2b82ed6b1258ebd24ad0950b4b83a96e6fbde1a801eeced4e4b32ed5b2217eac98e504cc1d16ddc8d9d39243c96bdb5390ff13629b28c96591 + languageName: node + linkType: hard + +"@inquirer/figures@npm:^1.0.8": + version: 1.0.8 + resolution: "@inquirer/figures@npm:1.0.8" + checksum: 24c5c70f49a5f0e9d38f5552fb6936c258d2fc545f6a4944b17ba357c9ca4a729e8cffd77666971554ebc2a57948cfe5003331271a259c406b3f2de0e9c559b7 + languageName: node + linkType: hard + +"@inquirer/password@npm:^4.0.2": + version: 4.0.2 + resolution: "@inquirer/password@npm:4.0.2" + dependencies: + "@inquirer/core": ^10.1.0 + "@inquirer/type": ^3.0.1 + ansi-escapes: ^4.3.2 + peerDependencies: + "@types/node": ">=18" + checksum: 69dc3986098cdfb4ed73653b690f7db7d88e483fdd9026b7308d1f6ff1208e5a7599f8c49910735e1fd8008fb367a9bf8f0ff80e7551831c6de15733980277af + languageName: node + linkType: hard + +"@inquirer/type@npm:^3.0.1": + version: 3.0.1 + resolution: "@inquirer/type@npm:3.0.1" + peerDependencies: + "@types/node": ">=18" + checksum: af412f1e7541d43554b02199ae71a2039a1bff5dc51ceefd87de9ece55b199682733b28810fb4b6cb3ed4a159af4cc4a26d4bb29c58dd127e7d9dbda0797d8e7 + languageName: node + linkType: hard + "@ioredis/commands@npm:^1.1.1": version: 1.2.0 resolution: "@ioredis/commands@npm:1.2.0" @@ -2264,6 +2310,7 @@ __metadata: dependencies: "@ethersproject/abi": ^5.7.0 "@ethersproject/providers": ^5.7.2 + "@inquirer/password": ^4.0.2 "@nomicfoundation/hardhat-chai-matchers": ^2.0.7 "@nomicfoundation/hardhat-ethers": ^3.0.8 "@nomicfoundation/hardhat-network-helpers": ^1.0.11 @@ -4063,7 +4110,7 @@ __metadata: languageName: node linkType: hard -"ansi-escapes@npm:^4.3.0": +"ansi-escapes@npm:^4.3.0, ansi-escapes@npm:^4.3.2": version: 4.3.2 resolution: "ansi-escapes@npm:4.3.2" dependencies: @@ -5066,6 +5113,13 @@ __metadata: languageName: node linkType: hard +"cli-width@npm:^4.1.0": + version: 4.1.0 + resolution: "cli-width@npm:4.1.0" + checksum: 0a79cff2dbf89ef530bcd54c713703ba94461457b11e5634bd024c78796ed21401e32349c004995954e06f442d82609287e7aabf6a5f02c919a1cf3b9b6854ff + languageName: node + linkType: hard + "client-only@npm:0.0.1": version: 0.0.1 resolution: "client-only@npm:0.0.1" @@ -9971,6 +10025,13 @@ __metadata: languageName: node linkType: hard +"mute-stream@npm:^2.0.0": + version: 2.0.0 + resolution: "mute-stream@npm:2.0.0" + checksum: d2e4fd2f5aa342b89b98134a8d899d8ef9b0a6d69274c4af9df46faa2d97aeb1f2ce83d867880d6de63643c52386579b99139801e24e7526c3b9b0a6d1e18d6c + languageName: node + linkType: hard + "mz@npm:^2.7.0": version: 2.7.0 resolution: "mz@npm:2.7.0" @@ -14353,6 +14414,13 @@ __metadata: languageName: node linkType: hard +"yoctocolors-cjs@npm:^2.1.2": + version: 2.1.2 + resolution: "yoctocolors-cjs@npm:2.1.2" + checksum: 1c474d4b30a8c130e679279c5c2c33a0d48eba9684ffa0252cc64846c121fb56c3f25457fef902edbe1e2d7a7872130073a9fc8e795299d75e13fa3f5f548f1b + languageName: node + linkType: hard + "zksync-ethers@npm:^5.0.0": version: 5.9.2 resolution: "zksync-ethers@npm:5.9.2"