|
| 1 | +import { getNodeUrl } from "../utils"; |
| 2 | +import { ethers } from "../utils/utils"; |
| 3 | +import { hre } from "../utils/utils.hre"; |
| 4 | +import Safe, { SafeAccountConfig, PredictedSafeProps } from "@safe-global/protocol-kit"; |
| 5 | + |
| 6 | +const safeAccountConfig: SafeAccountConfig = { |
| 7 | + owners: [ |
| 8 | + "0x868CF19464e17F76D6419ACC802B122c22D2FD34", |
| 9 | + "0xcc400c09ecBAC3e0033e4587BdFAABB26223e37d", |
| 10 | + "0x837219D7a9C666F5542c4559Bf17D7B804E5c5fe", |
| 11 | + "0x1d933Fd71FF07E69f066d50B39a7C34EB3b69F05", |
| 12 | + "0x996267d7d1B7f5046543feDe2c2Db473Ed4f65e9", |
| 13 | + ], |
| 14 | + threshold: 2, |
| 15 | +}; |
| 16 | +const EXPECTED_SAFE_ADDRESS = "0x0Fc8E2BB9bEd4FDb51a0d36f2415c4C7F9e75F6e"; |
| 17 | +const predictedSafe: PredictedSafeProps = { |
| 18 | + safeAccountConfig, |
| 19 | + safeDeploymentConfig: { |
| 20 | + // Safe addresses are deterministic based on owners and salt nonce. |
| 21 | + saltNonce: "0x1234", |
| 22 | + }, |
| 23 | +}; |
| 24 | + |
| 25 | +/** |
| 26 | + * Script to deploy a new Safe Multisig contract via the Safe SDK. Run via: |
| 27 | + * ``` |
| 28 | + * yarn hardhat run ./scripts/deployMultisig.ts \ |
| 29 | + * --network hyperevm \ |
| 30 | + * ``` |
| 31 | + */ |
| 32 | +async function main() { |
| 33 | + const chainId = parseInt(await hre.getChainId()); |
| 34 | + const nodeUrl = getNodeUrl(chainId); |
| 35 | + const wallet = ethers.Wallet.fromMnemonic((hre.network.config.accounts as any).mnemonic); |
| 36 | + const privateKey = wallet._signingKey().privateKey; |
| 37 | + console.log(`Connected to node ${nodeUrl} for chain ${chainId}`); |
| 38 | + const signer = wallet.connect(new ethers.providers.JsonRpcProvider(nodeUrl)); |
| 39 | + |
| 40 | + const protocolKit = await Safe.init({ |
| 41 | + provider: nodeUrl, |
| 42 | + signer: privateKey, |
| 43 | + predictedSafe, |
| 44 | + }); |
| 45 | + |
| 46 | + // Check if the safe already exists: |
| 47 | + const existingProtocolKit = await protocolKit.connect({ |
| 48 | + safeAddress: EXPECTED_SAFE_ADDRESS, |
| 49 | + }); |
| 50 | + const isDeployed = await existingProtocolKit.isSafeDeployed(); |
| 51 | + if (isDeployed) { |
| 52 | + const safeAddress = await existingProtocolKit.getAddress(); |
| 53 | + const safeOwners = await existingProtocolKit.getOwners(); |
| 54 | + const safeThreshold = await existingProtocolKit.getThreshold(); |
| 55 | + console.log(`Safe already exists at ${EXPECTED_SAFE_ADDRESS}:`, { |
| 56 | + safeAddress, |
| 57 | + safeOwners, |
| 58 | + safeThreshold, |
| 59 | + }); |
| 60 | + return; |
| 61 | + } |
| 62 | + |
| 63 | + // Deploy a new safe: |
| 64 | + const safeAddress = await protocolKit.getAddress(); |
| 65 | + if (safeAddress !== EXPECTED_SAFE_ADDRESS) { |
| 66 | + throw new Error(`Safe address ${safeAddress} does not match expected ${EXPECTED_SAFE_ADDRESS}`); |
| 67 | + } |
| 68 | + console.log(`Deploying a new safe with determinstic address: ${safeAddress}`); |
| 69 | + const deploymentTransaction = await protocolKit.createSafeDeploymentTransaction(); |
| 70 | + console.log(`Deployment txn data`, deploymentTransaction); |
| 71 | + const client = await protocolKit.getSafeProvider().getExternalSigner(); |
| 72 | + if (!client) { |
| 73 | + throw new Error("Unable to get external signer from safe provider"); |
| 74 | + } |
| 75 | + const deployerAccount = client.account.address; |
| 76 | + console.log(`Deployer account: ${deployerAccount}`); |
| 77 | + const clientConnectedChain = client.chain; |
| 78 | + if (client.chain?.id !== chainId) { |
| 79 | + throw new Error(`Client connected to chain ${clientConnectedChain?.id}, but expected ${chainId}`); |
| 80 | + } |
| 81 | + if (deploymentTransaction.value.toString() !== "0") { |
| 82 | + throw new Error(`Deployment transaction value should be 0, but is ${deploymentTransaction.value}`); |
| 83 | + } |
| 84 | + console.log(`Sending deployment transaction...`); |
| 85 | + const txnHash = await signer.sendTransaction({ |
| 86 | + to: deploymentTransaction.to, |
| 87 | + value: 0, |
| 88 | + data: deploymentTransaction.data, |
| 89 | + }); |
| 90 | + const txnReceipt = await txnHash.wait(); |
| 91 | + console.log(`Success! Deployment transaction receipt:`, txnReceipt); |
| 92 | +} |
| 93 | + |
| 94 | +main().catch((error) => { |
| 95 | + console.error(error); |
| 96 | + process.exitCode = 1; |
| 97 | +}); |
0 commit comments