Safe
ArchitectureThis document outlines an extensible Safe
architecture, increasing the novel integrations / applications for Safe
.
The following guiding principles have been strictly employed:
SafeProxy
MUST not be modified, ensuring maximum security.delegatecall
within the architecture.Currently, a safe
may only be interacted with via either:
owners
via execTransaction
; ormodule
via execTransactionFromModule
; orsignature
(ERC-1271).Use cases that this revised architecture seeks to enable include:
SafeProxy
. As an example, this would make it theoretically possible to convert a SafeProxy
into an ERC20 token by implementing ERC20 methods.Safe
. As an example, one could delegate the CoW Protocol EIP-712 domain to a contract that verified all signatures for selling any ERC20 token to ETH, ie. Max ETH The execution path of any method call that is not implemented in the Safe
singleton follows this path:
CompatibilityFallbackHandler
provides:
If a developer wishes to extend the functionality of a Safe
, they have to replace the CompatibilityFallbackHandler
, requiring significant heavy lifting, being careful to not remove any existing functionality so as to not break Safe
(some parts of existing infrastructure require the use of threshold signatures, and some apps are using approved hashes such as CoW Protocol dapp).
A developer may extend CompatibilityFallbackHandler
, though it can be made much easier if one could simply specify a custom handler for arbitrary individual methods. This is where ExtensibleFallbackHandler
comes in.
ExtensibleFallbackHandler
This handler replaces CompatibilityFallbackHandler
, but preserves backwards compatibility with:
Safe
approved hashes / threshold signatures.In addition to the backwards compatibility, a user may:
Safe
now supports an interface.Security requirements:
Safe
SHALL determine (based on the authorisation in the setter) whether a custom method is view
or not (ie. whether or not the custom method can modify state on invocation).Execution Path:
User requirements:
bytes
payload.Security requirements:
EIP-712
domain separator MUST be checked against the hash
, ensuring a 1:1 relationship between domain separator and ISafeSignatureVerifier
.Execution Path for isValidSignature(bytes32,bytes)
:
signature
approvedhash
- signature
is set to zero-length bytes
.threshold
- signature
is a multiple of 65 bytes (for r
, s
, v
).custom
(ie. ISafeSignatureVerifier
) - signature
is an ABI encoded function call safeSignature(bytes32,bytes32,bytes32,bytes)
where the tuple equates to (bytes32 domainSeparator, bytes32 typeHash, bytes32 encodeData, bytes payload)
. It is the 4bytes
selector in the ABI encoded function call that is used to trigger the custom signer.Before SignatureVerifierMuxer
calls a custom verifier, it MUST match the domainSeparator
to the hash
. Therefore, this then means that typeHash
, and encodeData
can be trusted within ISafeSignatureVerifier
if called from SignatureVerifierMuxer
.
ISafeSignatureVerifier
Security requirements:
_hash = h(abi.encodePacked("\x19\x01", domainSeparator, h(typeHash || encodeData)))
.Storage of custom method handlers and custom domain verifiers is contained within the ExtensibleFallbackhandler
deployment. Therefore, any update of the fallbackHandler
for a Safe
would in-effect "reset" the custom methods / domain verifiers for the Safe.