mirror of
https://github.com/luxfi/safe-wallet.git
synced 2026-10-30 15:19:21 +00:00
Upstream merge brings 52 commits from safe-global/safe-wallet-monorepo into the luxfi/safe-wallet@dev fork. Conflicts resolved: - yarn.lock: deleted (we are on pnpm) - apps/web/package.json: kept pnpm version + brand build scripts (build:safe / build:lux / build:hanzo) plus upstream's new generate-version.mjs step - apps/mobile/.../Signer/appKit.ts: took upstream's import pattern for shared/projectId, shared/metadata, shared/mmkvStorageAdapter Yarn sweep applied to 42 files (docs, github-actions, workflows, AGENTS, specs, codemods, scripts, READMEs). Net result: zero yarn-* command references anywhere outside node_modules. ❯ pnpm is the law in this fork. No yarn.
2.9 KiB
2.9 KiB
Quickstart: Nested Safe Proposer Management
Date: 2026-01-23 Feature: 001-nested-safe-proposer
Prerequisites
- Node.js (version per
.nvmrc) - Yarn 4 (via corepack)
- Repository cloned and dependencies installed:
pnpm install
Development Setup
# Checkout feature branch
git checkout 001-nested-safe-proposer
# Install dependencies
pnpm install
# Run web app in development mode
pnpm --filter @safe-global/web dev
Key Files to Modify
1. Permission Gate (P1 - Button enablement)
File: apps/web/src/components/settings/ProposersList/index.tsx
- Replace
OnlyOwnerwrapper withCheckWalletcomponent - Configure:
allowProposer={false}(nested owners yes, proposers no)
File: apps/web/src/components/common/CheckWallet/index.tsx
- No changes needed — already supports
isNestedSafeOwner
2. Proposer Form (P2 - Signing flow)
File: apps/web/src/features/proposers/components/UpsertProposer.tsx
- Add conditional logic: if user is nested Safe owner, wrap EOA signature in EIP-1271 format
- Determine parent Safe address from
useNestedSafeOwners() - Use parent Safe address as
delegatorin the API call
3. Signing Utilities
File: apps/web/src/features/proposers/utils/utils.ts
- Add
encodeEIP1271Signature(parentSafeAddress: string, ownerSignature: string): string - Encodes: v=0, r=parentSafeAddress (32 bytes), s=65, + ABI-encoded owner signature
Testing
# Run unit tests
pnpm --filter @safe-global/web test
# Run specific test file
pnpm --filter @safe-global/web test --testPathPattern="ProposersList"
# Type checking
pnpm --filter @safe-global/web type-check
# Linting
pnpm --filter @safe-global/web lint
Test Scenarios
- Nested Safe owner sees enabled button: Connect wallet → Open nested Safe → Settings > Setup → Verify "Add proposer" enabled
- Non-owner sees disabled button: Connect unrelated wallet → Same page → Verify disabled with tooltip
- Direct owner flow unchanged: Connect direct owner → Add proposer → Verify existing flow works
- Nested Safe owner initiates proposer addition: Click "Add proposer" → Fill form → Submit → Verify parent Safe tx created
Architecture Notes
- The permission fix (replacing
OnlyOwnerwithCheckWallet) is a simple, low-risk change - The signing flow is simpler than initially expected:
- No on-chain transaction (SignMessageLib) needed
- No async multisig approval needed (for 1-of-1 parent Safes)
- Backend EIP-1271 support confirmed in Safe Transaction Service source code
- The connected wallet signs the delegate typed data (same as direct owner), then the signature is wrapped in EIP-1271 format
- For multi-sig parent Safes (threshold > 1), collecting multiple owner signatures is needed — deferred to future phase
- Both phases can be implemented together since there are no blocking dependencies