Files
FbartoliandGitHub e3eb5e13c1 feat(web): enhance proposer functionality with nested safe support (#7028)
* feat(web): enhance proposer functionality with nested safe support

- Updated ProposersList component to use CheckWallet for wallet validation.
- Refactored UpsertProposer to support signing for nested safes, including new utility functions for EIP-1271 signature encoding.
- Added TypeScript dependencies for improved compatibility with Next.js and React.

This update improves the handling of nested safes and enhances the overall proposer management experience.

* feat(web): enhance proposer management with multi-sig support
- Added support for multi-signature delegation in UpsertProposer and DeleteProposerDialog components.
- Integrated PendingDelegationsList to display pending actions for nested safe owners.
- Updated utility functions for EIP-1271 signature encoding to handle multi-owner scenarios.
- Enhanced ProposersList to conditionally show pending delegations based on nested safe ownership.
These changes improve the user experience for managing proposers in nested safe environments.

* fix(workflows): update preview URL format in tx-builder deploy workflow

* feat(web): enhance proposer management and delegation handling
- Updated ProposersList to remove the New chip and conditionally display pending delegations.
- Modified DeleteProposerDialog to allow nested safe owners to delete proposers.
- Enhanced PendingDelegation component to include expiration date and shareable link functionality.
- Implemented accordion layout in PendingDelegationsList for better organization of pending confirmations.
- Updated utility functions to compute TOTP expiration dates.
These changes improve the user experience for managing proposers and pending delegations in nested safe environments.

* fix(web): refine wallet and delegation handling logic
- Updated CheckWallet component to include a check for nested safe owners.
- Changed background color in PendingDelegationCard and PendingDelegationsList for better visual consistency.
- Enhanced TOTP extraction logic in usePendingDelegations hook to ensure valid number conversion.
These changes improve the accuracy of wallet checks and enhance the user interface for pending delegations.

* feat(web): improve edit proposer logic and UI consistency
- Enhanced EditProposerDialog to allow nested safe owners to edit proposers.
- Updated PendingDelegationsList to use a consistent background color for better visual clarity.
These changes enhance the user experience for managing proposer edits and improve the overall interface.

* feat(web): enhance pending delegation handling and UI consistency
- Updated PendingDelegation component to improve shareable link functionality and streamline UI elements.
- Refined PendingDelegationsList to ensure consistent background color across components.
- Enhanced usePendingDelegations hook to implement polling for new signatures and optimize delegation filtering logic.
These changes improve the user experience for managing pending delegations and ensure a more cohesive interface.

* fix(tests): mock useChains hook to return default configs in ProposersList tests

* feat(web): refactor usePendingDelegations hook for improved delegation parsing and filtering
- Introduced parseMessageToDelegation function to streamline the extraction of delegation data from messages.
- Implemented keepLatestPerDelegate and filterActedUponDelegations functions to enhance delegation management logic.
- Optimized the usePendingDelegations hook to improve performance and clarity in handling pending delegations.
These changes enhance the overall efficiency and maintainability of the delegation handling process.

* feat(tests): add comprehensive tests for delegation hooks and services
- Introduced unit tests for useParentSafeThreshold, usePendingDelegations, and useSubmitDelegation hooks to ensure correct functionality and edge case handling.
- Added tests for delegation message creation and confirmation logic to validate proper integration with the messaging system.
- Enhanced test coverage for delegation-related services, improving reliability and maintainability of the codebase.
These additions strengthen the testing framework and ensure robust delegation management in the application.

* refactor(web): update background color in PendingDelegationsList for UI consistency
- Changed background color from a hardcoded value to a CSS variable for improved theming and maintainability.
- Ensured consistent background color across all accordion components within the PendingDelegationsList.
These updates enhance the visual coherence of the user interface for pending delegations.

* fix(md): revert claude claude MD changes

* fix(workflow): update preview URL in tx-builder deployment configuration
- Modified the preview URL in the tx-builder-deploy.yml workflow to include the '/tx-builder/' path for accurate deployment previews.
This change ensures that the deployment preview links direct users to the correct location.

* fix(web): improve delegation handling and error logging
- Updated the PendingDelegation component to include a countdown timer for expiration and enhanced error handling with logging for better debugging.
- Refactored the useSubmitDelegation hook to validate TOTP expiration and improved error management by utilizing the asError utility.
- Adjusted the encodeEIP1271Signature function to return a promise, ensuring consistent handling of asynchronous operations.
These changes enhance the reliability and user experience of delegation management in the application.

* chore(web): remove unused dependency from package.json
- Deleted the "@next/swc-linux-arm64-gnu" dependency from package.json as it is no longer needed. This cleanup helps maintain a leaner and more efficient project structure.

* chore(deps): remove deprecated "@next/swc-linux-arm64-gnu" entry from yarn.lock
- Deleted the "@next/swc-linux-arm64-gnu" entry from yarn.lock as it is no longer required, following the recent cleanup of the package.json. This helps maintain an up-to-date and efficient dependency tree.

* feat(web): enhance delegation polling and error handling in UI components
- Updated constants to include a backoff multiplier for delegation polling.
- Refactored PendingDelegation component to utilize the sameAddress utility for address comparison.
- Introduced DelegationErrorBoundary in PendingDelegationsList to handle loading errors gracefully.
- Improved usePendingDelegations hook with custom polling logic and stable key for dependency comparison.
These changes enhance the reliability and user experience of delegation management in the application.

* refactor(web): enhance delegation components and hooks for improved type safety and functionality
- Updated DelegationErrorBoundary and PendingDelegation components to use function declarations for better readability and type inference.
- Refactored useDelegationPolling and usePendingDelegations hooks to streamline polling logic and improve type definitions.
- Introduced utility functions for delegation origin parsing and filtering, enhancing code clarity and maintainability.
These changes improve the overall structure and reliability of delegation management in the application.

* feat(web): enhance delegation management with edit functionality and improved error handling
- Updated delegation-related types and constants to support 'edit' actions for better delegation management.
- Refactored PendingDelegation and UpsertProposer components to handle edit actions and improve user feedback.
- Streamlined error handling in delegation submission and deletion processes using the asError utility.
- Removed the deprecated useDelegationPolling hook, simplifying the polling logic in usePendingDelegations.
These changes improve the functionality and reliability of delegation operations within the application.

* fix(tests): update delegationMessages tests to include additional properties in origin object
- Enhanced the test cases for delegationMessages by adding 'delegate', 'nestedSafe', and 'label' properties to the origin object for both 'add' and 'remove' actions. This improves the accuracy and coverage of the tests related to delegation management.
2026-02-18 15:10:37 +01:00

6.2 KiB

Data Model: Nested Safe Proposer Management

Date: 2026-01-23 Feature: 001-nested-safe-proposer

Entities

Safe Account

Represents a multi-signature wallet contract on an EVM chain.

Field Type Description
address Address The Safe's contract address
chainId string The chain where this Safe is deployed
owners Address[] List of addresses authorized as signers
threshold number Minimum signatures required for execution
deployed boolean Whether the Safe contract exists on-chain
version string Safe contract version (e.g., "1.3.0")

Delegate (Proposer)

Represents a delegation granting proposal rights to an address.

Field Type Description
delegate Address The address granted proposer rights
delegator Address The address that authorized the delegation (EOA or Safe)
safe Address | null The Safe this delegation applies to
label string Human-readable name for the proposer
signature HexString The authorization signature (EIP-712 or EIP-1271)

Nested Safe Ownership Relationship

Represents the ownership chain between a user's wallet and a nested Safe.

Field Type Description
userWallet Address The connected EOA wallet
parentSafe Address The Safe controlled by the user (one of nested Safe's owners)
nestedSafe Address The target Safe where the proposer is being added
chainId string The chain (must be same for all three)

Relationships

UserWallet ──owns──> ParentSafe ──owns──> NestedSafe
                         │
                         └── delegator for ──> Delegate (Proposer)
                                                   │
                                                   └── can propose on ──> NestedSafe

State Transitions

Delegation Creation (Nested Safe Owner Flow — 1-of-1 parent Safe)

States:
  IDLE → FORM_OPEN → SIGNING → DELEGATION_SUBMITTED → COMPLETE

Transitions:
  IDLE → FORM_OPEN
    Trigger: User clicks "Add proposer" button
    Condition: User is nested Safe owner, Safe is deployed

  FORM_OPEN → SIGNING
    Trigger: User submits form with valid proposer address and label
    Action: Sign delegate typed data with connected wallet (EOA)
    Condition: Address validation passes

  SIGNING → DELEGATION_SUBMITTED
    Trigger: EOA signature obtained
    Action: Wrap signature in EIP-1271 format (v=0, r=parentSafe, s=65, + ABI-encoded signature)
            POST to delegate API with delegator=parentSafeAddress
    Condition: Signature valid

  DELEGATION_SUBMITTED → COMPLETE
    Trigger: API accepts the delegation (HTTP 201)
    Action: Cache invalidation, proposer appears in list

Note: For multi-sig parent Safes (threshold > 1), additional states would be needed to collect multiple owner signatures before wrapping in EIP-1271 format. This is deferred to a future phase.

Delegation Creation (Direct Owner Flow - existing, unchanged)

States:
  IDLE → FORM_OPEN → SIGNING → DELEGATION_SUBMITTED → COMPLETE

Transitions:
  IDLE → FORM_OPEN
    Trigger: User clicks "Add proposer" button

  FORM_OPEN → SIGNING
    Trigger: User submits form
    Action: Wallet signs EIP-712 typed data directly

  SIGNING → DELEGATION_SUBMITTED
    Trigger: Signature obtained
    Action: POST to delegate API with EOA signature

  DELEGATION_SUBMITTED → COMPLETE
    Trigger: API accepts
    Action: Cache invalidation

Validation Rules

Rule Entity Constraint
Not self-delegation Delegate delegate address != Safe address
Not existing owner Delegate delegate address not in Safe.owners
Valid Ethereum address Delegate delegate must be a valid checksummed address
Safe must be deployed Safe deployed == true for proposer management
Chain consistency All parentSafe.chainId == nestedSafe.chainId
Nested ownership exists Ownership parentSafe.address must be in nestedSafe.owners
User controls parent Ownership userWallet must be in parentSafe.owners

Key Data Flows

Permission Check Data Flow

useOwnedSafes(wallet.address)          → owned Safe addresses on current chain
useSafeInfo().safe.owners               → current Safe's owner addresses
intersection(owned, owners)             → parent Safes the user controls
length > 0                              → isNestedSafeOwner = true

Delegate Typed Data (for signature)

Domain: { name: "Safe Transaction Service", version: "1.0", chainId }
Types: { Delegate: [{ delegateAddress: address }, { totp: uint256 }] }
Message: { delegateAddress: <proposer>, totp: floor(now / 3600) }

EIP-1271 Signature Construction (inline owner signatures)

signature = concat(
  r: parentSafe.address (32 bytes, left-padded with zeros),
  s: 0x41 (32 bytes, = 65, offset to dynamic signature data),
  v: 0x00 (1 byte, indicates contract signature type),
  --- dynamic data starts at byte 65 ---
  ABI-encoded bytes of concatenated owner signatures
)

For a 1-of-1 parent Safe with a single EOA owner:

bytes 0-31:   parentSafe address (left-padded to 32 bytes)
bytes 32-63:  0x0000...0041 (offset = 65)
byte 64:      0x00 (v = contract signature)
bytes 65+:    abi.encode(["bytes"], [ownerEOASignature])[32:]
              (length-prefixed owner signature, 65 bytes for ECDSA)