(This article is meant for a broad audience. Hence it is missing some of the lower level details and contains several simplifications. In case you are a Solidity dev or otherwise experienced person with smart contracts, we recommend taking a look at the contract code.)
Purpose of fallback handlers
The Safe is supposed to be an Ethereum account which can handle arbitrary function calls and tokens. Users should be enabled to use their Safe exactly like how they would be able to do it with a private key based account ("externally owned account" or "EOA).
One of the differences to a private key based account is though that access control to assets in a Safe is defined in the smart contract code.
Since the Safe is supposed to be 100% flexible to anything users would want to do, we would have to define in this contract code really 100% everything. That’s obviously not possible. Hence we used this Solidity feature called “fallback functions” which basically says “if something is not implemented or known, just fallback to this function”. The Safe in particular says “If I see something unknown, then I just let the fallback handler deal with it.”
Since the fallback handler can be changed, the user could add the required functionality (which wasn’t known at Safe creation time) later on by using a different fallback handler.
If even the fallback handler doesn’t know how to deal with a function call, then it is just disregarded or an error occurs.
Example use case for a fallback handler: ERC721
An example is the ERC721 token standard. Among other things, the standard defines a way to check if the receiver can actually handle ERC721 tokens. To do that, a function like
doesSupportERC721 is called on the receiver (i.e. the receiving Safe). A pure Safe (i.e. without a fallback handler) does not have this function and would error. But the fallback handler has it.
Safes created via the official interfaces use the DefaultCallbackHandler as their fallback handler. A fallback handler can be replaced or extended anytime via a regular Safe transaction (respecting threshold and owners of the Safe).
Let us assume there is now a new token token ERC772211 with a similar function
doesSupportERC772211. In order for the Safe to support it, we could just write a new fallback handler and implement this new method. Existing Safes have to switch their fallback handler to the new one. That means we do not need to deploy a completely new Safe with new address etc. Instead, existing Safes can be reused.