Skip to content

MultiSigDeleGator: support smart contract accounts as signers (ERC-1271) #213

Open

Description

@Muhammad-Altabba

Description

MultiSigDeleGator accepts only EOAs as signers:

As a result, any account that validates its signature through ERC-1271 (isValidSignature) instead of ECDSA cannot be a signer today. This rules out:

  • Another MultiSigDeleGator (a nested multisig).
  • A HybridDeleGator, for example a user who signs with a passkey.
  • An EOA that already has EIP-7702 code, for example one upgraded to EIP7702StatelessDeleGator.
  • Any other smart contract wallet that implements ERC-1271.

The EIP-7702 case is also inconsistent. The code check runs only when a signer is added. An EOA that already has EIP-7702 code is rejected. An EOA that gets EIP-7702 code after it was added stays a signer and keeps signing with ECDSA.

Proposal

Accept smart contract accounts as signers and check their signatures with ERC-1271. EOA signers keep using ECDSA. One multisig signature can contain both.

Use cases

  • Nested groups. Boards, DAOs or family trusts where one member is itself a group. For example, a 2-of-3 team multisig is one signer of a 3-of-5 treasury multisig.
  • Passkey users. A member who signs with a passkey through a HybridDeleGator.
  • EIP-7702 users. A member whose EOA is upgraded with EIP-7702 can be added at any time, not only before the upgrade.

Context

The EOA-only rule was added on 2024-07-07 (874329e). EIP-7702 was then a two-month-old draft, and "has no code" was a reliable way to tell an EOA from a contract. Since then, this repo added its own EIP-7702 account, EIP7702StatelessDeleGator (2025-01-31, d522a38), and EIP-7702 went live on Ethereum mainnet with Pectra (2025-05-07). An EOA can now have code, so the check no longer reliably tells EOAs and contracts apart. This causes the inconsistency described above, and is one more reason to revisit the rule now.

Accepting only EOAs was a deliberate design choice. The contract documents that signers "MUST be EOAs" (NatSpec), and a test checks that a DeleGator is rejected as a signer (test).

I have a working implementation with tests and docs, and will open a PR shortly after this issue. If there are other reasons for the EOA-only rule, I am happy to address them, change the approach, or close both.

Technical Details

  • Signer management (the initializer, addSigner and replaceSigner) accepts smart contract accounts. address(0) and the DeleGator's own address are rejected.
  • One multisig signature can combine ECDSA signatures from EOA signers and ERC-1271 signatures from contract signers. The current rules stay: exactly threshold signatures, sorted by signer address.
  • Existing ECDSA signatures stay valid, so existing multisigs and clients keep working.
  • Existing proxies can upgrade without a storage migration.
  • A contract signer that rejects the signature, or fails, makes the whole multisig signature invalid. Validation reports this as an invalid signature and does not revert.

Trade-offs

  • Trust in signer code. A contract signer's approval depends on its own validation logic, and that logic can change, for example through a proxy upgrade or a new EIP-7702 delegation. Only the signer's own controller can make such changes, so trust stays with the signer. But the multisig no longer decides how each approval is checked.
  • Security-sensitive scope. Signature validation becomes more complex and calls external contracts.
  • Cost for EOA signers. Validation must tell EOA and contract signatures apart. Depending on the signature encoding, this can add a cost to multisigs that use only EOA signers.

Limitations

  • ERC-4337 bundlers. This proposal targets EntryPoint v0.8 and later. Some contract signers, such as a nested MultiSigDeleGator or a HybridDeleGator, read their own storage to validate a signature. The bundler validation rules (ERC-7562) do not allow this for unstaked accounts, so public mempool bundlers reject such UserOps. The EntryPoint v0.8 release notes extend this storage access to all staked entities (see References). Unstaked accounts with such signers need a stake or a private bundler, also after the upgrade. Delegation redemption is not affected.
  • Gas per contract signer. Each contract signer, and each nested level, adds validation gas.
  • Signers that are not deployed yet. A contract signer must be deployed before it can sign. Support for ERC-6492 can be a follow-up.

Acceptance Criteria

  • Existing EOA-only multisigs accept and reject the same signatures as before.
  • An EOA signer that gets EIP-7702 code after it was added can still sign with a plain ECDSA signature.
  • A smart contract account can be set as a signer with the initializer, addSigner and replaceSigner. address(0) and the DeleGator's own address are rejected.
  • One multisig signature can mix EOA and contract signers. It still needs exactly threshold signatures, sorted by signer address.
  • If a contract signer's isValidSignature reverts, returns no data or returns anything other than 0x1626ba7e, the multisig signature is invalid. The multisig's own isValidSignature then returns 0xffffffff and does not revert.
  • Existing proxies can upgrade to the new implementation without a storage migration.
  • documents/MultisigDeleGator.md describes the signature format for contract signers, and the trade-offs and limitations above.
  • Tests cover the scenarios below.

Scenario: nested multisig

  • GIVEN a 2-of-3 MultiSigDeleGator Root with signers Alice (EOA), Bob (EOA) and Sub
  • AND Sub is a 2-of-2 MultiSigDeleGator with signers Carol (EOA) and Dave (EOA)
  • WHEN Alice signs a hash
  • AND Carol and Dave sign the same hash for Sub
  • THEN Root.isValidSignature accepts the combined signature

Scenario: contract signer fails

  • GIVEN a MultiSigDeleGator Root with a contract signer Faulty
  • AND Faulty.isValidSignature reverts, which ERC-1271 allows for an invalid signature
  • WHEN a multisig signature for Root includes an entry for Faulty
  • THEN Root.isValidSignature returns 0xffffffff (invalid signature) and does not revert

Scenario: EIP-7702 account as signer

  • GIVEN an EOA upgraded with EIP-7702 to EIP7702StatelessDeleGator
  • WHEN it is added with addSigner
  • THEN the call succeeds
  • AND a signature from this account counts as one of the threshold signatures

References

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions