This content explains how Sequence wallets are implemented using modules and how the wallet configuration can be updated.
MainModule
is the initial module of every Sequence wallet; it differs from the other modules because it doesn’t store the set of signers on contract storage; it uses the salt provided to the Factory contract.
updateImplementation
allows to update the underlying implementation of the wallet proxy. This implementation contains all the core code that defines the wallet’s behaviour.
updateImplementation
with an invalid implementation will result in the corruption of the wallet.Corrupt wallets may lead to the loss of funds.Name | Type | Description |
---|---|---|
_implementation | address | Address of the new wallet implementation. |
onlySelf
modifier, which means that it can only be called by the wallet itself using a self-referencing transaction. Calls to this method coming from other addresses, even if these addresses are signers of the wallet, will be rejected.
MainModule
can’t be changed. The only way to change the set of signers or threshold is by updating the module of the wallet.ModuleAuth
interface, this interface allows the rest of the module to validate signatures for the wallet. In the case of MainModule
this interface is implemented as a counter-factual validation of hash passed to the factory during the contract wallet creation.
imageHash
corresponds to the one configured in the wallet. This function is called internally to validate transaction and message signatures.
The imageHash
is a hash of the wallet configuration, which contains the wallet’s threshold, signers and weights.
Name | Type | Description |
---|---|---|
_imageHash | bytes32 | Hash of wallet configuration to be validated. |
Name | Type | Description |
---|---|---|
_isValid | bool | True if the given imageHash corresponds to the current wallet configuration. |
MainModuleUpgradable
is a module that mimics the behaviour of the MainModule
but allows the wallet configuration to be updated.
updateImageHash
imageHash
, this is the hash that defines the wallet configuration (signers, weights, threshold).
Name | Type | Description |
---|---|---|
_imageHash | bytes32 | Hash of the new configuration for the wallet. |
imageHash
is not validated, it is the responsibility of the caller to ensure that the hash is correct. Reasons for incorrect hashes include:imageHash
doesn’t correspond to any wallet configuration (may be a random string).imageHash
corresponds to an unknown wallet configuration.onlySelf
modifier, which means that it can only be called by the wallet itself using a self-referencing transaction. Calls to this method coming from other addresses, even if these addresses are signers of the wallet, will be rejected.
initialize
function. The configuration is instead defined by the salt
provided to the factory, the MainModule
then checks the counterfactual validity of all signatures against the wallet address.
This means there is no direct way to update the configuration of a wallet while still using the MainModule
. Given that the first configuration update needs to also change the wallet implementation to the MainModuleUpgradable
, the MainModule
is updated to the MainModuleUpgradable
and the updateImageHash
method is called to update the wallet configuration.
delegateCall
is used to extend the wallet functionality beyond what’s allowed by the module. In this case the called methods are defined on the modules themselves, so there is no need to use delegateCall
.
revertOnError
is used to revert the whole transaction bundle if a transaction flagged by it fails. In this case the operation should be atomic given that a partial wallet configuration update will render the wallet unusable.
to
address is the wallet itself.
value
of the transaction is always zero, since the transaction is a self-referencing transaction and doesn’t require transferring funds.
gasLimit
of the transaction is always zero, since it represents an unlimited amount of gas.
MainModuleUpgradable
it doesn’t have a valid imageHash
yet. It’s imperative that the imageHash
is updated before the transaction bundle finishes executing.
If the imageHash
is not updated before the transaction bundle finishes executing, the wallet will be rendered unusable.For this reason the following considerations should be taken when updating the wallet for the first time:revertOnError = true
.updateImplementation
and updateImageHash
should both be declared on the same transaction bundle.gasLimit
of both transactions should be set to unlimited (0
).MainModuleUpgradable
it can be updated by calling the updateImageHash
method, without any additional transaction.
MainModuleUpgradable
it can be queried for the current configuration by calling the getImageHash
method.
This method should return the wallet’s current configuration hash, which can be compared to a list of known wallet configurations to find the correct one.
imageHash
method returns bytes32(0)
if the wallet is not yet updated to the MainModuleUpgradable
.
In this case the wallet is in a counter-factual state and the imageHash
can’t be directly queried.
This is also the case for non-deployed wallets.
To find the imageHash
of a non-deployed or non-updated wallet, a candidate known imageHash
needs to be compared against the wallet address.
See Compute wallet address.