Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(governance): script to add an owner to multisig #13439

Merged
merged 8 commits into from Mar 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions governance/package.json
Expand Up @@ -13,8 +13,8 @@
"@nomiclabs/hardhat-ethers": "2.2.3",
"@openzeppelin/hardhat-upgrades": "3.0.2",
"@openzeppelin/upgrades-core": "1.32.5",
"@safe-global/api-kit": "2.0.0",
"@safe-global/protocol-kit": "2.0.0",
"@safe-global/api-kit": "2.2.0",
"@safe-global/protocol-kit": "3.0.1",
"@tenderly/hardhat-tenderly": "2.2.2",
"@unlock-protocol/contracts": "workspace:./packages/contracts",
"@unlock-protocol/eslint-config": "workspace:./packages/eslint-config",
Expand Down
43 changes: 43 additions & 0 deletions governance/scripts/all_networks
@@ -0,0 +1,43 @@
#!/usr/bin/env node
/**
*
* Just a small util to run a hardhat script for all networks
*
* Usage: scripts/all_networks run scripts/etc...
* Usage: scripts/all_networks unlock:info
*/

const allNetworks = require('@unlock-protocol/networks')
const { execSync } = require('child_process')

// if any network is present this array, only these will be executed
const only = []

// these networks will be excluded from run
const toExclude = ['localhost', 'default', 'networks']
const excludeTestnets = true

const networks = only.length
? only
: Object.keys(allNetworks).filter(
(n) =>
!toExclude.includes(n) &&
(excludeTestnets ? !allNetworks[n].isTestNetwork : true)
)

console.log(`Running task for the following networks: ${networks.toString()}`)

for (let i = 0; i < networks.length; i++) {
const cmd = `yarn hardhat`
const args = ['--network', networks[i], ...process.argv.slice(2)]

console.log(cmd, args)
try {
execSync(`${cmd} ${args.join(' ')}`, {
stdio: 'inherit',
})
} catch (error) {
console.log(`Network ${networks[i]} failed`)
console.log(error.message)
}
}
80 changes: 80 additions & 0 deletions governance/scripts/multisig/addOwner.js
@@ -0,0 +1,80 @@
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')
const SafeApiKit = require('@safe-global/api-kit').default

async function main({ newOwner, safeAddress, threshold } = {}) {
const { id, multisig, name } = await getNetwork()
let [signer] = await ethers.getSigners()

if (!safeAddress) {
safeAddress = multisig
}

if (!safeAddress) {
throw new Error(`Missing multisig address for ${name} [${id}].`)
}

// default to ccarfi.eth
console.log(`Adding signer ${newOwner} on chain on ${id}:
- multisig: ${safeAddress}
- signer: ${signer.address}
`)

// Use Safe v1+ with SDK
const ethAdapter = new EthersAdapter({
ethers,
signerOrProvider: signer,
})

const safeSdk = await Safe.create({ ethAdapter, safeAddress })
const safeService = new SafeApiKit({
chainId: id,
})

// get nonce so we make sure we dont erase current pending tx
const nonce = await safeService.getNextNonce(safeAddress)
const safeTransaction = await safeSdk.createAddOwnerTx(
{
ownerAddress: newOwner,
// threshold
},
{ nonce }
)

// Get the transaction hash of the safeTransaction
const safeTransactionHash = await safeSdk.getTransactionHash(safeTransaction)
console.log(`submitting tx with hash : ${safeTransactionHash} ...`)

// get signature
const senderSignature = await safeSdk.signTransactionHash(safeTransactionHash)

// Propose the transaction
const txParams = {
safeAddress,
safeTransactionData: safeTransaction.data,
safeTxHash: safeTransactionHash,
senderAddress: signer.address,
senderSignature: senderSignature.data,
}

await safeService.proposeTransaction(txParams)
const { nonce: actualNonce } = await safeService.getTransaction(
safeTransactionHash
)
console.log(`tx submitted - nonce: [${actualNonce}].`)
}

// execute as standalone
if (require.main === module) {
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error)
process.exit(1)
})
}

module.exports = main
10 changes: 10 additions & 0 deletions governance/tasks/safe.js
Expand Up @@ -89,3 +89,13 @@ task('safe:submit', 'Submit to multisig from a proposal file')
const submitTx = require('../scripts/multisig/submitTx')
await submitTx({ safeAddress, tx: calls })
})

task('safe:add-owner', 'Submit a new owner to a multisig')
.addParam('newOwner', 'The address of the new safe owner')
.addOptionalParam('safeAddress', 'the address of the multisig contract')
.addOptionalParam('threshold', 'new threshold for the multisig contract')
.setAction(async ({ newOwner, safeAddress }) => {
// eslint-disable-next-line global-require
const addOwner = require('../scripts/multisig/addOwner')
await addOwner({ safeAddress, newOwner })
})
51 changes: 21 additions & 30 deletions yarn.lock
Expand Up @@ -10799,7 +10799,7 @@ __metadata:
languageName: node
linkType: hard

"@noble/hashes@npm:1.3.3, @noble/hashes@npm:^1.3.0, @noble/hashes@npm:^1.3.1, @noble/hashes@npm:^1.3.2, @noble/hashes@npm:~1.3.0, @noble/hashes@npm:~1.3.2":
"@noble/hashes@npm:1.3.3, @noble/hashes@npm:^1.3.0, @noble/hashes@npm:^1.3.1, @noble/hashes@npm:^1.3.3, @noble/hashes@npm:~1.3.0, @noble/hashes@npm:~1.3.2":
version: 1.3.3
resolution: "@noble/hashes@npm:1.3.3"
checksum: 10/1025ddde4d24630e95c0818e63d2d54ee131b980fe113312d17ed7468bc18f54486ac86c907685759f8a7e13c2f9b9e83ec7b67d1cc20836f36b5e4a65bb102d
Expand Down Expand Up @@ -13446,31 +13446,31 @@ __metadata:
languageName: node
linkType: hard

"@safe-global/api-kit@npm:2.0.0":
version: 2.0.0
resolution: "@safe-global/api-kit@npm:2.0.0"
"@safe-global/api-kit@npm:2.2.0":
version: 2.2.0
resolution: "@safe-global/api-kit@npm:2.2.0"
dependencies:
"@safe-global/protocol-kit": "npm:^2.0.0"
"@safe-global/safe-core-sdk-types": "npm:^3.0.0"
"@safe-global/protocol-kit": "npm:^3.0.1"
"@safe-global/safe-core-sdk-types": "npm:^4.0.1"
ethers: "npm:^6.7.1"
node-fetch: "npm:^2.7.0"
checksum: 10/6a16aaa49954382ef308d736fb6193a37eb389f6e0d12f5784a86964f11a46892ddf9180b94e993dcb92e89b79073a574e64b5d93c2ac4bba05aca137c0d087b
checksum: 10/5e65e2346775f07c8ea9c509b0b2e2eb3d4062d20f894bebab5eaa8bef96e57b5bd77dd7fabf9ada5f058ff1b4e794143fdc0f97be532b30fd0f253a73133ba2
languageName: node
linkType: hard

"@safe-global/protocol-kit@npm:2.0.0, @safe-global/protocol-kit@npm:^2.0.0":
version: 2.0.0
resolution: "@safe-global/protocol-kit@npm:2.0.0"
"@safe-global/protocol-kit@npm:3.0.1, @safe-global/protocol-kit@npm:^3.0.1":
version: 3.0.1
resolution: "@safe-global/protocol-kit@npm:3.0.1"
dependencies:
"@noble/hashes": "npm:^1.3.2"
"@safe-global/safe-deployments": "npm:^1.28.0"
"@noble/hashes": "npm:^1.3.3"
"@safe-global/safe-deployments": "npm:^1.33.0"
ethereumjs-util: "npm:^7.1.5"
ethers: "npm:^6.7.1"
semver: "npm:^7.5.4"
web3: "npm:^1.10.3"
web3-core: "npm:^1.10.3"
web3-utils: "npm:^1.10.3"
checksum: 10/d284447f7046bcc56c0a1e3ebb25d3e995df0e0cdc78dc8529628abc1b635e98c15edeb09d3b2b9d0da1751065af90c52ddd769601d71e9e3df3f99aa31ec239
checksum: 10/cbf620e4b2a48db988d2acc36b7857c1601d6958fe9afe0d8f46ffdc30e411d5f95f0bcd21abd917b1800888a78225f6f98eea53b9cbaade919f8cb0e0602ebb
languageName: node
linkType: hard

Expand All @@ -13487,15 +13487,15 @@ __metadata:
languageName: node
linkType: hard

"@safe-global/safe-core-sdk-types@npm:^3.0.0":
version: 3.0.1
resolution: "@safe-global/safe-core-sdk-types@npm:3.0.1"
"@safe-global/safe-core-sdk-types@npm:^4.0.1":
version: 4.0.1
resolution: "@safe-global/safe-core-sdk-types@npm:4.0.1"
dependencies:
"@safe-global/safe-deployments": "npm:^1.28.0"
"@safe-global/safe-deployments": "npm:^1.33.0"
ethers: "npm:^6.7.1"
web3-core: "npm:^1.10.3"
web3-utils: "npm:^1.10.3"
checksum: 10/afbe289dbcb99841fdb864f29ddad8e15ad9f75a66c2e3d1ff40f82e93f0665ef4eaaa6dc0cbbaf7bbdd2176f88d6c14eab1cb159a0ad3984c8931a3f02a1739
checksum: 10/fc68538ab0bfa17a00c33fe3eb2ad80d150947edb2f345060c5794f3b753001f368653af87960e707d92addec1a37a30376463481f8d7a8aa23319ae5b3d9484
languageName: node
linkType: hard

Expand Down Expand Up @@ -13526,7 +13526,7 @@ __metadata:
languageName: node
linkType: hard

"@safe-global/safe-deployments@npm:^1.20.2":
"@safe-global/safe-deployments@npm:^1.20.2, @safe-global/safe-deployments@npm:^1.33.0":
version: 1.33.0
resolution: "@safe-global/safe-deployments@npm:1.33.0"
dependencies:
Expand All @@ -13544,15 +13544,6 @@ __metadata:
languageName: node
linkType: hard

"@safe-global/safe-deployments@npm:^1.28.0":
version: 1.30.0
resolution: "@safe-global/safe-deployments@npm:1.30.0"
dependencies:
semver: "npm:^7.3.7"
checksum: 10/0d8eca465d9e9b2ecf4f0d1cb95fd8d4ae0c0104b5f9f0cba71e07a0268122badc40ab23863d867368a9e0f5d81f284de61359c306ad3f88b63d7e5771efd46a
languageName: node
linkType: hard

"@safe-global/safe-ethers-lib@npm:1.9.3":
version: 1.9.3
resolution: "@safe-global/safe-ethers-lib@npm:1.9.3"
Expand Down Expand Up @@ -19911,8 +19902,8 @@ __metadata:
"@nomiclabs/hardhat-ethers": "npm:2.2.3"
"@openzeppelin/hardhat-upgrades": "npm:3.0.2"
"@openzeppelin/upgrades-core": "npm:1.32.5"
"@safe-global/api-kit": "npm:2.0.0"
"@safe-global/protocol-kit": "npm:2.0.0"
"@safe-global/api-kit": "npm:2.2.0"
"@safe-global/protocol-kit": "npm:3.0.1"
"@tenderly/hardhat-tenderly": "npm:2.2.2"
"@unlock-protocol/contracts": "workspace:./packages/contracts"
"@unlock-protocol/eslint-config": "workspace:./packages/eslint-config"
Expand Down