From 588de467a3e0ac22eac185f8c62d09e4bc2aacc7 Mon Sep 17 00:00:00 2001 From: Julien Genestoux Date: Tue, 19 Mar 2024 15:22:19 -0400 Subject: [PATCH] feat(governance) refactored the script to check multisig signers and settings (#13488) refactored the script to check multisig signers and settings --- governance/scripts/multisig/_helpers.js | 9 ++--- governance/scripts/multisig/addOwner.js | 1 - governance/scripts/multisig/info.js | 54 +++++++++++++++++++------ 3 files changed, 46 insertions(+), 18 deletions(-) diff --git a/governance/scripts/multisig/_helpers.js b/governance/scripts/multisig/_helpers.js index 0cad588dea6..490f005eb6b 100644 --- a/governance/scripts/multisig/_helpers.js +++ b/governance/scripts/multisig/_helpers.js @@ -18,11 +18,10 @@ const getProvider = async (chainId) => { // custom services URL for network not supported by Safe const safeServiceURLs = { - 42220: 'http://mainnet-tx-svc.celo-safe-prod.celo-networks-dev.org/', - // mumbai isnt supported by Safe Global, you need to run Safe infrastructure locally - 80001: 'http://localhost:8000/cgw/', - // for some reasons, zkevm throws in lib - 1101: 'https://safe-transaction-zkevm.safe.global', + 324: 'https://safe-transaction-zksync.safe.global/api', + 1101: 'https://safe-transaction-zkevm.safe.global/api', + 534352: 'https://transaction.safe.scroll.xyz/api', + 59144: 'https://safe.linea.build/api', } // get safeAddress directly from unlock if needed diff --git a/governance/scripts/multisig/addOwner.js b/governance/scripts/multisig/addOwner.js index b67d4f1c42d..df32c6e2a18 100644 --- a/governance/scripts/multisig/addOwner.js +++ b/governance/scripts/multisig/addOwner.js @@ -1,5 +1,4 @@ const { ethers } = require('hardhat') - const { getNetwork } = require('@unlock-protocol/hardhat-helpers') const Safe = require('@safe-global/protocol-kit').default const { EthersAdapter } = require('@safe-global/protocol-kit') diff --git a/governance/scripts/multisig/info.js b/governance/scripts/multisig/info.js index e1673cba7f9..41325d20ba1 100644 --- a/governance/scripts/multisig/info.js +++ b/governance/scripts/multisig/info.js @@ -5,8 +5,25 @@ const { networks } = require('@unlock-protocol/networks') const SafeApiKit = require('@safe-global/api-kit').default -const getMultigiInfo = async (chainId, multisig) => { +const prodSigners = [ + '0x9d3ea9e9adde71141f4534dB3b9B80dF3D03Ee5f', // cc + '0x4Ce2DD8373ECe0d7baAA16E559A5817CC875b16a', // jg + '0x4011d09a86D0acA8377a4A8baD691F1ACeeCd672', // nf + '0xcFd35259E3A468E7bDF84a95bCddAc0B614A9212', // aa + '0xccb5D94FbfBFDc4953Ca8a114f88773C2fF98e80', // sm + '0x246A13358Fb27523642D86367a51C2aEB137Ac6C', // cr +].sort() + +const devSigners = [ + '0x4Ce2DD8373ECe0d7baAA16E559A5817CC875b16a', // jg + '0x246A13358Fb27523642D86367a51C2aEB137Ac6C', // cr + '0x9d3ea9e9adde71141f4534dB3b9B80dF3D03Ee5f', // cc +].sort() + +const getMultiSigInfo = async (chainId, multisig) => { const errors = [] + const { isTestNetwork } = networks[chainId] + const expectedSigners = isTestNetwork ? devSigners : prodSigners const provider = await getProvider(chainId) // get Safe service const safeService = new SafeApiKit({ @@ -26,24 +43,37 @@ const getMultigiInfo = async (chainId, multisig) => { // queued: false, // }) - const safe = new ethers.Contract(multisig, multisigABI, provider) - const owners = await safe.getOwners() - const policy = await safe.getThreshold() if (!multisig) { errors.push('Missing multisig') } else { - if (policy == 1) { - errors.push('❌ Single policy owner!') + const safe = new ethers.Contract(multisig, multisigABI, provider) + const owners = await safe.getOwners() + const policy = await safe.getThreshold() + + if (isTestNetwork && policy < 2) { + errors.push('❌ Policy below 2!') + } + if (!isTestNetwork && policy < 4) { + errors.push( + `❌ Unexpected policy: ${policy}/${owners.length} for 4/${expectedSigners.length} expected` + ) } - if (policy <= 2 || policy / BigInt(owners.length) > 1.5) { - errors.push(`Low policy owner (${policy}/${owners.length})`) + + let extraSigners = owners.filter((x) => !expectedSigners.includes(x)) + if (extraSigners.length > 0) { + errors.push(`❌ Extra signers: ${[...extraSigners].sort()}`) + } + + let missingSigners = expectedSigners.filter((x) => !owners.includes(x)) + if (missingSigners.length > 0) { + errors.push(`❌ Missing signers: ${missingSigners}`) } } return errors } -const log = (name, chainId, msg) => - console.log(`[${name} (${chainId})]: ${msg}`) +const log = (name, chainId, multisig, msg) => + console.log(`[${name} (${chainId})]: ${multisig} ${msg}`) async function main() { for (let chainId in networks) { @@ -52,11 +82,11 @@ async function main() { const { multisig, name } = networks[chainId] try { - errors = await getMultigiInfo(chainId, multisig) + errors = await getMultiSigInfo(chainId, multisig) } catch (error) { errors = [`Couldn't fetch multisig info: ${error.message}`] } - errors.forEach((error) => log(name, chainId, error)) + errors.forEach((error) => log(name, chainId, multisig, error)) } }