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

improve SAFE ownership and threshold change script #1015

Open
wants to merge 8 commits into
base: main
Choose a base branch
from

Conversation

0xDEnYO
Copy link
Contributor

@0xDEnYO 0xDEnYO commented Feb 20, 2025

Which Jira task belongs to this PR?

Why did I implement it this way?

This PR helps further automating the tasks associated to adding a new chain.
With the updated script we can now add SAFE owners and change threshold from 1 to 3 all in one step (which used to consist of several manual steps)

Checklist before requesting a review

Checklist for reviewer (DO NOT DEPLOY and contracts BEFORE CHECKING THIS!!!)

  • I have checked that any arbitrary calls to external contracts are validated and or restricted
  • I have checked that any privileged calls (i.e. storage modifications) are validated and or restricted
  • I have ensured that any new contracts have had AT A MINIMUM 1 preliminary audit conducted on by <company/auditor>

@lifi-action-bot lifi-action-bot marked this pull request as draft February 20, 2025 04:39
Copy link
Contributor

coderabbitai bot commented Feb 20, 2025

Walkthrough

This pull request modifies the management of safe owners by replacing the "add-safe-owners" script in the package.json with a new script called "add-safe-owners-and-threshold". The new script, located at a different file path, enhances functionality by including a threshold mechanism for managing Gnosis Safe transactions. Additionally, the script for loading environment variables has been updated to improve error handling related to the RPC URL.

Changes

File(s) Change Summary
package.json, script/deploy/safe/add-safe-owners-and-threshold.ts Removed the "add-safe-owners" script and added "add-safe-owners-and-threshold" in package.json. The new script manages Gnosis Safe transactions, adds owners, adjusts the threshold, and executes transactions.
script/utils/viemScriptHelpers.ts Changed the dotenv import from a named import to a namespace import and updated the call to load environment variables to dotenv.config(), adding error handling for the rpcUrl.

Possibly related PRs

Suggested reviewers

  • ezynda3
  • mirooon

Tip

CodeRabbit's docstrings feature is now available as part of our Pro Plan! Simply use the command @coderabbitai generate docstrings to have CodeRabbit automatically generate docstrings for your pull request. We would love to hear your feedback on Discord.

Warning

Review ran into problems

🔥 Problems

Errors were encountered while retrieving linked issues.

Errors (1)
  • JIRA integration encountered authorization issues. Please disconnect and reconnect the integration in the CodeRabbit UI.
✨ Finishing Touches
  • 📝 Generate Docstrings

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
script/deploy/safe/add-safe-owners-and-threshold.ts (1)

55-62: Improve private key handling with validation.

The private key handling includes good error messaging but could benefit from additional validation.

 const privateKey = String(
   privateKeyArg || process.env.PRIVATE_KEY_PRODUCTION
 )

 if (!privateKey)
   throw new Error(
     'Private key is missing, either provide it as argument or add PRIVATE_KEY_PRODUCTION to your .env'
   )
+
+// Validate private key format
+if (!privateKey.match(/^0x[0-9a-fA-F]{64}$/)) {
+  throw new Error('Invalid private key format')
+}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2ae6688 and dd064ac.

📒 Files selected for processing (4)
  • package.json (1 hunks)
  • script/deploy/safe/add-safe-owners-and-threshold.ts (5 hunks)
  • script/deploy/safe/confirm-safe-tx.ts (2 hunks)
  • script/utils/viemScriptHelpers.ts (3 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: run-unit-tests
🔇 Additional comments (7)
script/utils/viemScriptHelpers.ts (2)

3-4: LGTM! Environment variable configuration is properly initialized.

The dotenv package is imported and configured correctly to load environment variables.


46-48: LGTM! Environment variable naming follows best practices.

The dynamic construction of environment variable names using ETH_NODE_URI_${networkName.toUpperCase()} follows standard naming conventions and provides good flexibility.

Also applies to: 59-59

script/deploy/safe/add-safe-owners-and-threshold.ts (2)

143-169: LGTM! Transaction submission helper is well structured.

The submitAndExecuteTransaction function properly handles transaction proposal, signing, and execution with appropriate error handling and logging.


85-85:

✅ Verification successful

Verify the safe owners configuration.

The owners list is sourced from global config without validation.


🏁 Script executed:

#!/bin/bash
# Description: Verify that safeOwners exists in global config and contains valid addresses

# Check if safeOwners exists and is an array
jq -e '.safeOwners | type == "array"' config/global.json || echo "Error: safeOwners must be an array in global.json"

# Verify each address format
jq -r '.safeOwners[]' config/global.json | while read -r address; do
  if [[ ! $address =~ ^0x[a-fA-F0-9]{40}$ ]]; then
    echo "Invalid address format: $address"
  fi
done

Length of output: 688


Safe owners configuration validated.

After running the verification script, we confirmed that:

  • globalConfig.safeOwners exists in config/global.json and is an array.
  • Every address in the list adheres to the expected Ethereum address format.

Since the global configuration already ensures valid safe owner entries, no additional validation is required in the code at line 85.

script/deploy/safe/confirm-safe-tx.ts (2)

337-388: LGTM! Command is properly exported for reuse.

The command definition is well structured and maintains all existing functionality while being made reusable.


390-393: LGTM! Entry point check prevents unintended execution.

The module.url check ensures the script only runs when directly executed, enabling safe imports from other scripts.

package.json (1)

77-77: LGTM! Script reference updated correctly.

The script name and path have been updated to reflect the new functionality that handles both owner addition and threshold changes.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dd064ac and 9da4b6f.

📒 Files selected for processing (1)
  • script/deploy/safe/add-safe-owners-and-threshold.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
script/deploy/safe/add-safe-owners-and-threshold.ts (2)
Learnt from: ezynda3
PR: lifinance/contracts#861
File: script/deploy/safe/add-owners-to-safe.ts:8-13
Timestamp: 2024-11-21T08:22:38.484Z
Learning: In `script/deploy/safe/add-owners-to-safe.ts`, runtime validation for network configuration using Zod is not required; type assertions are acceptable.
Learnt from: ezynda3
PR: lifinance/contracts#861
File: script/deploy/safe/add-owners-to-safe.ts:48-48
Timestamp: 2024-11-21T08:23:50.099Z
Learning: In the script `script/deploy/safe/add-owners-to-safe.ts`, additional defensive checks for network configuration may be unnecessary because the script will fail anyway when the network configuration is missing.
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: generate-tag
🔇 Additional comments (2)
script/deploy/safe/add-safe-owners-and-threshold.ts (2)

1-20: LGTM! Well-organized imports and configuration.

The imports are properly structured, with appropriate use of dynamic imports for ESM compatibility and clear type definitions.


128-137: Add confirmation prompt before changing threshold.

The threshold change to 3 is hardcoded and executed without user confirmation.

 if (currentThreshold != 3) {
+  const proceed = await consola.prompt(
+    `Are you sure you want to change threshold from ${currentThreshold} to 3?`,
+    { type: 'confirm' }
+  )
+  if (!proceed) {
+    console.info('Threshold change skipped')
+    return
+  }
   console.info('Now changing threshold from 1 to 3')
   const changeThresholdTx = await protocolKit.createChangeThresholdTx(3)
   await submitAndExecuteTransaction(
     protocolKit,
     safeService,
     changeThresholdTx,
     senderAddress
   )
 } else console.log('Threshold is already set to 3 - no action required')

@0xDEnYO 0xDEnYO marked this pull request as ready for review February 20, 2025 04:50
@0xDEnYO 0xDEnYO changed the title confirm ownership and threshold changes automatically improve SAFE ownership and threshold change script Feb 20, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
script/deploy/safe/add-safe-owners-and-threshold.ts (1)

66-67: 🛠️ Refactor suggestion

Add validation for RPC URL.

There's no validation to ensure that either the chain's default RPC URL or the provided RPC URL exists before creating the provider.

-    const rpcUrl = chain.rpcUrls.default.http[0] || args.rpcUrl
+    const rpcUrl = chain.rpcUrls.default.http[0] || args.rpcUrl
+    if (!rpcUrl) {
+      throw new Error('No RPC URL available for this network. Please provide one with the --rpcUrl argument.')
+    }
     const provider = new ethers.JsonRpcProvider(rpcUrl)
🧹 Nitpick comments (3)
script/deploy/safe/add-safe-owners-and-threshold.ts (3)

15-16: Consider placing dotenv configuration before any imports.

It's generally best practice to configure environment variables before any imports so that imported modules can access the environment variables if needed.

-import * as dotenv from 'dotenv'
-dotenv.config()
-import { SafeTransaction } from '@safe-global/safe-core-sdk-types'
+import * as dotenv from 'dotenv'
+dotenv.config()
+
+import { SafeTransaction } from '@safe-global/safe-core-sdk-types'

83-89: Improve safe info retrieval pattern.

The current pattern for retrieving and using safe info could be clearer if you await the promise first and then access the property.

     let nextNonce = await safeService.getNextNonce(safeAddress)
-    const info = safeService.getSafeInfo(safeAddress)
+    const safeInfo = await safeService.getSafeInfo(safeAddress)
     console.info('Safe Address', safeAddress)
     const senderAddress = await signer.getAddress()
     console.info('Signer Address', senderAddress)
 
-    const currentThreshold = (await info).threshold
+    const currentThreshold = safeInfo.threshold
+    if (!currentThreshold) {
+      throw new Error('Failed to retrieve current threshold from safe')
+    }

124-126: Make threshold value configurable.

The target threshold value is hardcoded to 3, which might not be flexible for different scenarios. Consider making it configurable via arguments or configuration file.

+    const targetThreshold = args.threshold ? parseInt(args.threshold) : 3
-    if (currentThreshold != 3) {
-      console.info('Now changing threshold from 1 to 3')
+    if (currentThreshold != targetThreshold) {
+      console.info(`Now changing threshold from ${currentThreshold} to ${targetThreshold}`)
       const changeThresholdTx = await protocolKit.createChangeThresholdTx(3)

This would require adding a new argument in the command definition:

threshold: {
  type: 'string',
  description: 'Target threshold to set (defaults to 3)',
},
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9da4b6f and abece46.

📒 Files selected for processing (3)
  • package.json (1 hunks)
  • script/deploy/safe/add-safe-owners-and-threshold.ts (1 hunks)
  • script/utils/viemScriptHelpers.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • script/utils/viemScriptHelpers.ts
  • package.json
🧰 Additional context used
🧠 Learnings (1)
script/deploy/safe/add-safe-owners-and-threshold.ts (5)
Learnt from: 0xDEnYO
PR: lifinance/contracts#1015
File: script/deploy/safe/add-safe-owners-and-threshold.ts:140-145
Timestamp: 2025-02-20T07:49:30.907Z
Learning: In Safe SDK integration, using `any` type for Safe and SafeApiKit parameters is acceptable as these are both values and types, which can cause typing conflicts when used directly as parameter types.
Learnt from: 0xDEnYO
PR: lifinance/contracts#1015
File: script/deploy/safe/add-safe-owners-and-threshold.ts:117-123
Timestamp: 2025-02-20T04:50:33.488Z
Learning: The `submitAndExecuteTransaction` function in Safe management scripts includes comprehensive error handling that covers transaction proposal, execution, and receipt verification. It uses try-catch blocks, verifies transaction receipt status, logs errors, and properly propagates them up the call stack, making additional error handling around its calls unnecessary.
Learnt from: 0xDEnYO
PR: lifinance/contracts#1015
File: script/deploy/safe/add-safe-owners-and-threshold.ts:117-123
Timestamp: 2025-02-20T04:50:33.488Z
Learning: In the Safe owners management scripts, error handling for transaction submission is implemented within the `submitAndExecuteTransaction` function, making additional try-catch blocks around its calls unnecessary.
Learnt from: ezynda3
PR: lifinance/contracts#861
File: script/deploy/safe/add-owners-to-safe.ts:8-13
Timestamp: 2024-11-21T08:22:38.484Z
Learning: In `script/deploy/safe/add-owners-to-safe.ts`, runtime validation for network configuration using Zod is not required; type assertions are acceptable.
Learnt from: ezynda3
PR: lifinance/contracts#861
File: script/deploy/safe/add-owners-to-safe.ts:48-48
Timestamp: 2024-11-21T08:23:50.099Z
Learning: In the script `script/deploy/safe/add-owners-to-safe.ts`, additional defensive checks for network configuration may be unnecessary because the script will fail anyway when the network configuration is missing.
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: run-unit-tests
  • GitHub Check: generate-tag
🔇 Additional comments (4)
script/deploy/safe/add-safe-owners-and-threshold.ts (4)

124-126: Add user confirmation before changing threshold.

The threshold change to 3 is hardcoded and executed without user confirmation. Consider adding a confirmation prompt.


140-145: Using 'any' type for Safe SDK parameters is acceptable.

According to previous feedback, using any type for Safe and SafeApiKit parameters is acceptable as these are both values and types, which can cause typing conflicts when used directly as parameter types.


113-119: Error handling is sufficient as implemented.

The error handling in the submitAndExecuteTransaction function is comprehensive and covers transaction proposal, execution, and receipt verification. No additional error handling is needed around the function call.


1-176: Good implementation of safe owners management with threshold control.

The script effectively automates the process of adding new owners to a Safe contract and changing the threshold in a single workflow, which streamlines what would otherwise be multiple manual steps. The implementation includes proper error handling, owner existence checks, and transaction management.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
script/deploy/safe/add-safe-owners-and-threshold.ts (3)

2-17: Import order should be fixed and dotenv.config() called immediately after imports.

The current order of imports has dotenv.config() called after importing SafeTransaction, which is not ideal. Best practice is to load environment variables as early as possible in the execution flow to ensure they're available when needed by other imports.

import { defineCommand, runMain } from 'citty'
import { type SafeApiKitConfig } from '@safe-global/api-kit'
import { getAddress } from 'viem'
import { EthersAdapter } from '@safe-global/protocol-kit'
const { default: SafeApiKit } = await import('@safe-global/api-kit')
const { default: Safe } = await import('@safe-global/protocol-kit')
import { ethers } from 'ethers6'
import { getSafeUtilityContracts } from './config'
import {
  NetworksObject,
  getViemChainForNetworkName,
} from '../../utils/viemScriptHelpers'
import data from '../../../config/networks.json'
import globalConfig from '../../../config/global.json'
import * as dotenv from 'dotenv'
import { SafeTransaction } from '@safe-global/safe-core-sdk-types'
+
dotenv.config()

81-85: Improved error handling for threshold retrieval.

The current code first unwraps the promise and then uses optional chaining to access the threshold property, which is less readable. A more straightforward approach would be to await the promise first and then check if the threshold exists.

-const currentThreshold = (await safeService.getSafeInfo(safeAddress))
-  ?.threshold
-if (!currentThreshold)
+const safeInfo = await safeService.getSafeInfo(safeAddress)
+if (!safeInfo || !safeInfo.threshold)
  throw new Error('Could not get current signature threshold')
+const currentThreshold = safeInfo.threshold

124-133: Update hardcoded messaging to match the actual threshold change.

The log message hardcodes "from 1 to 3" but the actual change is from the current threshold to 3. This could be confusing if the current threshold is not 1.

if (currentThreshold != 3) {
-  console.info('Now changing threshold from 1 to 3')
+  console.info(`Now changing threshold from ${currentThreshold} to 3`)
  const changeThresholdTx = await protocolKit.createChangeThresholdTx(3)
  await submitAndExecuteTransaction(
    protocolKit,
    safeService,
    changeThresholdTx,
    senderAddress
  )
} else console.log('Threshold is already set to 3 - no action required')
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between abece46 and 58330cb.

📒 Files selected for processing (2)
  • script/deploy/safe/add-safe-owners-and-threshold.ts (1 hunks)
  • script/utils/viemScriptHelpers.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • script/utils/viemScriptHelpers.ts
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: 0xDEnYO
PR: lifinance/contracts#1015
File: script/deploy/safe/add-safe-owners-and-threshold.ts:117-123
Timestamp: 2025-02-20T04:50:33.488Z
Learning: In the Safe owners management scripts, error handling for transaction submission is implemented within the `submitAndExecuteTransaction` function, making additional try-catch blocks around its calls unnecessary.
script/deploy/safe/add-safe-owners-and-threshold.ts (5)
Learnt from: 0xDEnYO
PR: lifinance/contracts#1015
File: script/deploy/safe/add-safe-owners-and-threshold.ts:140-145
Timestamp: 2025-02-20T07:49:30.907Z
Learning: In Safe SDK integration, using `any` type for Safe and SafeApiKit parameters is acceptable as these are both values and types, which can cause typing conflicts when used directly as parameter types.
Learnt from: 0xDEnYO
PR: lifinance/contracts#1015
File: script/deploy/safe/add-safe-owners-and-threshold.ts:117-123
Timestamp: 2025-02-20T04:50:33.488Z
Learning: The `submitAndExecuteTransaction` function in Safe management scripts includes comprehensive error handling that covers transaction proposal, execution, and receipt verification. It uses try-catch blocks, verifies transaction receipt status, logs errors, and properly propagates them up the call stack, making additional error handling around its calls unnecessary.
Learnt from: 0xDEnYO
PR: lifinance/contracts#1015
File: script/deploy/safe/add-safe-owners-and-threshold.ts:117-123
Timestamp: 2025-02-20T04:50:33.488Z
Learning: In the Safe owners management scripts, error handling for transaction submission is implemented within the `submitAndExecuteTransaction` function, making additional try-catch blocks around its calls unnecessary.
Learnt from: ezynda3
PR: lifinance/contracts#861
File: script/deploy/safe/add-owners-to-safe.ts:48-48
Timestamp: 2024-11-21T08:23:50.099Z
Learning: In the script `script/deploy/safe/add-owners-to-safe.ts`, additional defensive checks for network configuration may be unnecessary because the script will fail anyway when the network configuration is missing.
Learnt from: ezynda3
PR: lifinance/contracts#861
File: script/deploy/safe/add-owners-to-safe.ts:8-13
Timestamp: 2024-11-21T08:22:38.484Z
Learning: In `script/deploy/safe/add-owners-to-safe.ts`, runtime validation for network configuration using Zod is not required; type assertions are acceptable.
⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: CodeQL
  • GitHub Check: run-unit-tests
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: generate-tag
🔇 Additional comments (5)
script/deploy/safe/add-safe-owners-and-threshold.ts (5)

140-145: Use of 'any' types for Safe SDK parameters is acceptable.

While using explicit types instead of 'any' is generally preferred, I understand from the retrieved learnings that using 'any' type for Safe and SafeApiKit parameters is acceptable in this case as these are both values and types, which can cause typing conflicts.


161-171: Error handling in transaction execution is appropriately implemented.

The implementation includes proper error handling with try-catch blocks, verification of transaction receipt status, and error logging with propagation.


24-26: Informative and clear command description.

The command description clearly explains the purpose of the script, which is to add SAFE owners from the global.json file and set the threshold to 3.


91-120: Well-structured owner management loop with proper validation.

The code efficiently iterates through all owner addresses, validates if they already exist before attempting to add them, and provides clear console output about the process. The transaction nonce management is also handled correctly.


48-55: Good fallback handling for private key.

The implementation properly prioritizes the private key provided as an argument, falls back to an environment variable, and throws a clear error message if neither is available.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants