UNPKG

@kadena/hardhat-chainweb

Version:
113 lines 5.97 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.deployOnChainsUsingCreate2 = void 0; exports.predictCreate2Address = predictCreate2Address; const ethers_1 = require("ethers"); const hardhat_1 = __importDefault(require("hardhat")); const utils_1 = require("../utils"); const pure_utils_1 = require("../pure-utils"); const deployCreate2Factory_1 = require("./deployCreate2Factory"); const networkStem = (0, pure_utils_1.getNetworkStem)(hardhat_1.default.config.defaultChainweb); const { ethers } = hardhat_1.default; function isContractDeployed(address) { return ethers.provider.getCode(address).then((code) => code !== '0x'); } function createSalt(sender, userSalt) { const ADDRESS_LENGTH = 20; const USER_SALT_LENGTH = 12; // Convert the sender address and user salt to bytes // The sender address is expected to be 20 bytes (Ethereum address) const senderBytes = (0, ethers_1.getBytes)(sender); // The user salt is expected to be 12 bytes (Kadena user salt) const userSaltBytes = (0, ethers_1.getBytes)(ethers.dataSlice(ethers.id(userSalt), 0, USER_SALT_LENGTH)); if (senderBytes.length !== ADDRESS_LENGTH) { throw new Error(`Sender address must be ${ADDRESS_LENGTH} bytes`); } if (userSaltBytes.length !== USER_SALT_LENGTH) { throw new Error(`User salt must be ${USER_SALT_LENGTH} bytes`); } // Concatenate the sender address and user salt const result = new Uint8Array(USER_SALT_LENGTH + ADDRESS_LENGTH); result.set(senderBytes, 0); result.set(userSaltBytes, ADDRESS_LENGTH); return [result, ethers.toBigInt(userSaltBytes)]; } async function predictCreate2Address(contractBytecode, signer, userSalt) { const factoryAddress = await (0, deployCreate2Factory_1.getCreate2FactoryAddress)(signer); const [salt] = createSalt(await signer.getAddress(), userSalt); const predictedAddress = ethers.getCreate2Address(factoryAddress, salt, ethers.keccak256(contractBytecode)); return predictedAddress; } async function deployUsingCreate2(contractBytecode, signer, userSalt) { const factoryAddress = await (0, deployCreate2Factory_1.getCreate2FactoryAddress)(signer); const Factory = await hardhat_1.default.ethers.getContractFactory(deployCreate2Factory_1.create2Artifacts.abi, deployCreate2Factory_1.create2Artifacts.bin, signer); const create2 = Factory.attach(factoryAddress); const senderAddress = await signer.getAddress(); const [salt, userSaltBigInt] = createSalt(senderAddress, userSalt); // Compute the predicted address const predictedAddress = ethers.getCreate2Address(factoryAddress, salt, ethers.keccak256(contractBytecode)); const computedAddress = await create2.computeAddress(contractBytecode, userSaltBigInt); if (computedAddress !== predictedAddress) { console.log(`ADDRESS MISMATCH: computed address (${computedAddress}) != predicted address (${predictedAddress})`); throw new Error(`ADDRESS MISMATCH: computed address (${computedAddress}) != predicted address (${predictedAddress})`); } if (await isContractDeployed(predictedAddress)) { console.log(`Contract already deployed at ${predictedAddress}. Skipping deployment.`); return predictedAddress; } // Deploy using CREATE2 const tx = await create2.deploy(contractBytecode, userSaltBigInt); await tx.wait(); if (!(await isContractDeployed(predictedAddress))) { console.log(`CREATE2 failed: No contract at predicted address ${predictedAddress}`); throw new Error(`CREATE2 failed: No contract at predicted address ${predictedAddress}`); } return predictedAddress; } /** * Deploy a contract on all chains in the network using create2. */ const deployOnChainsUsingCreate2 = async ({ name, signer, factoryOptions, constructorArgs = [], overrides, userSalt = 'KADENA/CREATE2/SALT', }) => { const deployments = await (0, utils_1.runOverChains)(async (cwId) => { var _a; try { const [defaultDeployer] = await ethers.getSigners(); const contractDeployer = (_a = signer !== null && signer !== void 0 ? signer : factoryOptions === null || factoryOptions === void 0 ? void 0 : factoryOptions.signer) !== null && _a !== void 0 ? _a : defaultDeployer; const deployerAddress = await contractDeployer.getAddress(); console.log(`Deploying with signer: ${deployerAddress} on network ${cwId}`); const factory = await ethers.getContractFactory(name, { signer: contractDeployer, ...factoryOptions, }); const transaction = await factory.getDeployTransaction(...(overrides ? [...constructorArgs, overrides] : constructorArgs)); // Prepare the bytecode of the contract to deploy const bytecode = transaction.data; const contractAddress = await deployUsingCreate2(bytecode, contractDeployer, userSalt); const contract = factory.attach(contractAddress); // Store deployment info in both formats return { // eslint-disable-next-line @typescript-eslint/no-explicit-any contract: contract, address: contractAddress, chain: cwId, deployer: deployerAddress, network: { chainId: cwId, name: `${networkStem}${cwId}`, }, }; } catch (error) { console.error(`Failed to deploy to network ${cwId}:`, error); return null; } }); return { deployments: deployments.filter((d) => d !== null), }; }; exports.deployOnChainsUsingCreate2 = deployOnChainsUsingCreate2; //# sourceMappingURL=deployUsingCreate2.js.map