Safe Contract v2

Abstract

The current version of the Safe contracts (1.3.0) is stable, but is not following all standards. Therefore I would propose to start planing a new version of the Safe contract. The general goal is to make the contracts more explicit and therefore more secure and allow a more configuration possibilities.

I would love to get some feedback on the changes proposed and if there is anything missing.

Changes

Breaking Changes

New functionality

  • Add module guard
    • Motivation
      • Improve security of module usage.
    • Notes
      • This functionality already exists for the normal multi-signature flow and should be applied in a similar manner for transactions executed by modules
  • Allow to set signature parser for an address
    • Motivation
      • Make the contracts more flexible in regards to contract signatures and other new signature schemes
  • Changes
    • Allow to set a signature parser per address. This signature parser should follow a predefined interface and check if a specific signature for a specific address is valid.
  • Notes
    • add signature parser for EIP-1271
    • add signature parser for BLS signatures

Additional Notes

Support for EIP-4337 was also evaluated. For now this is being tested as a module before we would start adding full native support.

7 Likes

A link to the “standards” you mention in the abstract would help contextualizing this post a little better, IMO.

1 Like

The standards are mentioned in with the related features:

3 Likes

Really glad to see this! We’ve run into a few people sending to an undeployed safe address with Hop and this will be a huge security upgrade for cross-chain users.

It might be off topic but a cool frontend feature could be a “deploy this safe on XXX network” to allow users to easily claim the same address across different chains. Reasoning:

  • allow users to prevent malicious deployments in the future if they used createProxy to deploy
  • allow a user to easily recover funds if sent to an undeployed address. (we’ve had to help users do this manually with +$2m at risk before :grimacing:)
  • connivence even if they they use createProxyWithNonce to deploy

Detecting and flagging malicious deployments in the UI could help as well.

4 Likes

As cross reference: Safe Contract v1.4.0

1 Like

A big open question for the Safe v2 contracts would be which Solidity compiler version should be used.

The current version uses 0.7.6, which has been superseded by 0.8.x version which provide many benefits.

The challenge with 0.8.x is that this version is designed with the assumption that the optimizer is used, which is another processing step providing additional risk that unexpected errors happen (i.e. Storage Write Removal Bug On Conditional Early Termination | Solidity Blog)

In this case it seems to have manifested from optimisations around assembly…
I wouldn’t think the compiler would do this with solidity, but can appreciate how it might get tripped up with assembly.

“The bug was introduced in version 0.8.13 and Solidity version 0.8.17, released on September 08, 2022, provides a fix.”
“If you’re using optimized legacy code generation, you only need to be concerned, if you use large inline assembly blocks that contain user-defined assembly functions that involve the return(...) or stop() instructions.”

Yes, it is true that this is a very specific case, with limited impact.

But if we think about contracts like the Safe or the EIP-4337 entrypoint which are the core for many accounts even a small issue might become large.

Personally I am very much looking forward to 0.9.x as this should bring more complete IR support which should make it easier to “prove” the correctness of optimization afaik … but maybe something for the solidity forum :smiley:

1 Like

Not sure I fully understand how / what part of EIP-1271 signature verification you want to remove, isn’t it essential for compatibility with certain dApps?

1 Like

The part that is required for dapp compatibility is that other contracts can call into the Safe with EIP-1271 support. This implementation is handled via the FallbackHandler functionality. This is very flexible as you can change it without having to upgrade the core contract.

The change proposed here is that the Safe calls into other contracts using the legacy EIP-1271 specification to support contract signatures for owner addresses that are contracts.

As it is not using the latest version of EIP-1271 the usability of this one can be challenged. There seems to be very little demand for this feature (as it is not compatible with other wallets, but noone is providing feedback on this) and it just opens up an alternative path which could be exploited if wrongly configured.

1 Like

Ah I see, makes sense

Hi @rimeissner sorry if i don’t fully understand your reply. If we remove EIP-1271 from the 2.0 contract, will users still be able to signMessage log into dapps such as OpenSea and Blur? Is there any alternative message signing mechanisms that are being considered. I am a huge fan of Safe and had been a users for a long time. Would love to get your thoughts on this.

Hey rimeissner, I have identified two issues with Safe that could greatly benefit developers like us who build on top of it. I am listing them below and would appreciate it if you could confirm if solutions for these are planned for the v2 release.

  1. handlePayment - Although native token payments work well, in the case of ERC20 payments, there are scenarios where the gasUnits quoted by the provider might be over or underestimated due to gasFee change from time transaction is proposed to signed by all owners. A potential solution could be to create a paymentMaster contract as proposed in ERC4337 spec that handles this conversion, allowing providers to charge the exact fee.
  2. execTransaction - This function does not return any output, which makes it difficult to chain transaction calls directly with Safe transactions. While modules have the execTransactionFromModuleReturnData function, it would be useful to have a similar method for direct Safe transactions as well.
2 Likes

Hi Brian, according to my understanding from comment by @rimeissner. The EIP-1271 compatible
isValidSignature can be implemented by the handler called via FallbackHandler module.

Since the signature by contract in Safe v1.3.0 is not compatible with the latest EIP-1271 and the EIP-1271 compatible signature can be implemented as mentioned above, it’s ideal to remove the contract signature part and keep Safe from potential exploit.

During my evaluation for AA stacks, I compared the Diamond proxy accounts vs safe architecture.

Benefits of Safe
Safe’s architecture presents a number of benefits over Diamond proxy accounts. One key reason for favoring Safe’s architecture is that during the development of a proof of concept, I found myself recreating a structure similar to what Safe already offers (guards, validators, and modifiers). In this scenario, significant engineering resources and audit costs would be expended on an EIP-6900 / RhinestoneV1 based Diamond account. Our main interest lies in solving the modular / registry problem, rather than creating a competing smart account.

Moreover, Safe supports module execution via delegatecall , meaning that even if the EIP-6900 / RhinestoneV1/Diamond implementation were the optimal choice, it would be relatively simple to develop a Safe module with a similar execution flow (with one delegatecall overhead). However, I question whether reimplementing the msg.sig → moduleAddress mapping is a wise approach, as function signature conflicts across modules could arise. Consequently, a modular registry for EIP-6900 / Diamond smart accounts would need to ensure both storage slot safety and standardized function names to avoid function signature collisions.

Furthermore, I believe that Safe’s architecture offers greater flexibility in execution flow since modules can directly call the avatar. This can be particularly useful for security-related ‘auto-tasks’, similar to OpenZeppelin Defender Sentinel. While developing a new smart account from scratch might seem attractive, as it could allow for a tailored solution and execution layer for the Registry features we envision, I think that by collaborating closely with the Safe team and fully leveraging Safe’s architecture, we can achieve the best of both worlds and create an optimal experience for users.

Registry
We are currently prototyping several ideas we have for a registry. Optimally, a standard that works with safe modules and modules used by other implementations that might arise in the future would be the best. I think it would be great to collab with safe, and brainstorm some guidance and requirements for modules / registry and then focus on making this as open as possible.

Feature Wishlist
I firmly believe that in 18-24 months, most users will migrate to smart accounts. But this also means different use-cases and user stories for smart accounts. In order to retain secure operation of the smart accounts but support a flourishing module ecosystem, I believe that it’s important to allow for different type of modules, depending on the access / functionality they have.

Here is a non-exhaustive Wishlist.

  • staticcall option in the Executor.sol
  • enforceable guards for execFromModule (it is my understanding, that Safe trusts the module to call it’s Guard)
  • Run Levels( there might be a usecase for different module runlevels)
    • kernel (delegatecall)
    • user land
    • view only (staticcall)
  • this could also restrict which 3rd party modules can executed via delegatecall or can execFromModule via delegatecall

Note: staticcall
@rimeissner mentioned the simulateAndRevert() function as a possible solution to staticcall.

It is possible that I misunderstand the execution flow, but I think due to the delegatecall it would not allow to call a function on a 3rd party contract that reads a value from said contract storage (since delegatecall would retain the msg.sender of the Safe/Avatar.
It would an interesting security features for Modules that call execFromModule to ensure that no state changes can be made by the callee

happy to elaborate on any points if there are any questions or further details needed!

Is V2 public yet? Is there a place we can see track the progress?

2 Likes