Skip to content

Allow Safe to Own Itself#998

Merged
nlordell merged 3 commits intomainfrom
feat/safe-7702
Jul 10, 2025
Merged

Allow Safe to Own Itself#998
nlordell merged 3 commits intomainfrom
feat/safe-7702

Conversation

@nlordell
Copy link
Copy Markdown
Collaborator

@nlordell nlordell commented Jun 20, 2025

This change was originally proposed by @akshay-ap

This PR reverts an old change (See #229 and #259) and allows the Safe to once again own itself. This is a step towards 7702 support (#997), whereby we want the EOA that delegates to a Safe to be able to sign transactions for itself.

The restriction was originally put in place because execTransaction would call isValidSignature on itself (which used to be implemented on the Safe itself and not as part of the compatibility fallback handler), where the msg.sender would be the Safe itself, and allow for trivial "approved hash" signatures (through
this mechanism).

This is no longer possible since v1.3.0, as the isValidSignature call would be handled by the fallback handler, meaning that the msg.sender that can trivially sign "approve hash" signatures is no longer the Safe itself but the configured fallback handler. Since #866 and starting in v1.5.0 the CompatibilityFallbackHandler is implemented to disallow "approve hash" signatures regardless of the caller, further eliminating the requirement for the restriction.

Increasing Threshold Concerns

One concern with this change, and removing the restriction on having the Safe own itself, is that the Safe cannot sign for itself, so you can potentially block access to the account completely, by requiring the Safe "self-owner" to be included as part of the signing threshold. For example, if you have a n/n Safe (so threshold == ownerCount) and one of the owners is the Safe itself, then the Safe will not be able to ever produce a valid signature.

This PR reverts an old change (See #229 and #259) and allows the Safe
to once again own itself. This is a step towards 7702 support, whereby
we want the EOA that delegates to a Safe to be able to sign
transactions for itself.

The restriction was originally put in place because `execTransaction`
would call `isValidSignature` (which used to be implemented on the
Safe itself and not as part of the compatibility fallback handler) on
itself, where the `msg.sender` would be the Safe itself, and allow for
trivial "approved hash" signatures (through
[this](https://github.com/safe-global/safe-smart-account/blob/36db12a140331c522e773849ebc87d39f5abae1e/contracts/GnosisSafe.sol#L244-L245)
mechanism).

This is no longer possible since v1.3.0, as the `isValidSignature`
call would be handled by the fallback handler, meaning that the
`msg.sender` that can trivially sign "approve hash" signatures is no
longer the Safe itself but the configured fallback handler. Since #866
and starting in v1.5.0 the `CompatibilityFallbackHandler` is
implemented to disallow "approve hash" signatures regardless of the
caller, further eliminating the requirement for the restriction.

 ### Increasing Threshold Concerns

One concern with this change, and removing the restriction on having
the Safe own itself, is that the Safe cannot sign for itself, so you
can potentially block access to the account completely, by requiring
the Safe "self-owner" to be included as part of the signing threshold.
For example, if you have a n/n Safe (so `threshold == ownerCount` and
one of the owners is the Safe itself, then the Safe will not be able
to ever produce a valid signature).
@nlordell nlordell requested a review from a team as a code owner June 20, 2025 12:09
@nlordell nlordell requested review from akshay-ap, mmv08, remedcu and rmeissner and removed request for a team June 20, 2025 12:09
await expect(
template.setup([user2.address, user2.address], 2, AddressZero, "0x", AddressZero, AddressZero, 0, AddressZero),
).to.be.revertedWith("GS203");
).to.be.revertedWith("GS204");
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

The error duplicate owner is now consistently "GS204".

} as const;
const signatures = buildSignatureBytes([selfSignature]);

await expect(safe["checkSignatures(address,bytes32,bytes)"](user1.address, txHash, signatures)).to.be.revertedWith("GS025");
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Note that if we change the CompatibilityFallbackHandler to not use address(0) as the executor, then this test would fail:

diff --git a/contracts/handler/CompatibilityFallbackHandler.sol b/contracts/handler/CompatibilityFallbackHandler.sol
index 275797d..e652ad0 100644
--- a/contracts/handler/CompatibilityFallbackHandler.sol
+++ b/contracts/handler/CompatibilityFallbackHandler.sol
@@ -80,7 +80,7 @@ contract CompatibilityFallbackHandler is TokenCallbackHandler, ISignatureValidat
         } else {
             // We explicitly do not allow caller approved signatures for EIP-1271 to prevent unexpected behaviour. This
             // is done by setting the executor address to `0` which can never be an owner of the Safe.
-            safe.checkSignatures(address(0), messageHash, _signature);
+            safe.checkSignatures(msg.sender, messageHash, _signature);
         }
         return EIP1271_MAGIC_VALUE;
     }
  1) Safe
       checkSignatures
         should not allow trivial signatures when the Safe owns itself:
     AssertionError: Expected transaction to be reverted with reason 'GS025', but it didn't revert
      at async Context.<anonymous> (test/core/Safe.Signatures.spec.ts:511:13)

@nlordell
Copy link
Copy Markdown
Collaborator Author

Tagging with do not merge as I want this to be applied after the Safe v1.5.0 release.

@nlordell nlordell mentioned this pull request Jun 20, 2025
1 task
It is no longer true, and is allowed.
@nlordell nlordell merged commit 034184d into main Jul 10, 2025
33 checks passed
@nlordell nlordell deleted the feat/safe-7702 branch July 10, 2025 09:11
@github-actions github-actions Bot locked and limited conversation to collaborators Jul 10, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants