Wallet Configuration
Every Sequence wallet has a configuration defined by a threshold and a list of signers with their corresponding weights.
Configuration layout
Name | Type | Range | Description |
---|---|---|---|
Threshold | uint16 | 1 - 65535 | Required combined total "weight" of signers for a signature to be considered valid. |
Signers | signer[] | unlimited - bounded by gas | List of signers that with their corresponding "weight"s. |
Signer layout
Name | Type | Range | Description |
---|---|---|---|
"weight" | uint8 | 0 - 255 | "weight" of every signature of the signer. |
"address" | "address" | -- | "address" of the signer, it may be an EOA or another smart contract wallet with EIP-1271 support. |
Example
{
"threshold": 5,
"signers": [
{
"address": "0x4fbf69aa2a75f9942a768dc8da7804ec965f7bea",
"weight": 2
},
{
"address": "0x596af90cecdbf9a768886e771178fd5561dd27ab",
"weight": 3
},
{
"address": "0x6192e0fdcd868b3de01c7fbc0ad98baebd7330c1",
"weight": 2
},
{
"address": "0xec9a7204a43d3f4a82c84fde92d25bfc9110981e",
"weight": 1
}
]
}
This example has a threshold of 5 and 4 signers.
The valid combinations of signers are:
- 0x4fbf69aa2a75f9942a768dc8da7804ec965f7bea & 0x596af90cecdbf9a768886e771178fd5561dd27ab - combined weight of 2 + 3 = 5
- 0x6192e0fdcd868b3de01c7fbc0ad98baebd7330c1 & 0x596af90cecdbf9a768886e771178fd5561dd27ab - combined weight of 2 + 3 = 5
- 0x4fbf69aa2a75f9942a768dc8da7804ec965f7bea, 0x6192e0fdcd868b3de01c7fbc0ad98baebd7330c1 & 0xec9a7204a43d3f4a82c84fde92d25bfc9110981e - combined weight of 2 + 2 + 1 = 5
Any combination of signers with a combined weight under the threshold is considered invalid; any additional signers above the threshold are ignored.
Configuration hash - ImageHash
The configuration is never stored directly on the contract, but instead is hashed and checked against every time a signature is validated. This allows the wallet contracts to reduce the usage of storage and therefore the gas cost.
Wallets that never have been updated don't store the imageHash
directly, instead the imageHash
is used as the salt
during the contract creation, and signatures are validated against the address of the wallet.
Compute image hash
keccak256(abi.encode( uint8 weight_1, address signer_1,
keccak256(abi.encode( uint8 weight_2, address signer_2,
keccak256(abi.encode( uint8 weight_3, address signer_3,
keccak256(abi.encode( uint256 threshold )) )) )) ))
Initial wallet configuration
The initial wallet configuration determines the address of the wallet, subsequent updates don't change the address.
The wallet address can be computed using the imageHash
, the factory
and mainModule
of the wallet.
Compute wallet address
// The code of the wallet proxy contract
const WalletProxyBytecode =
"0x603a600e3d39601a805130553df3363d3d373d3d3d363d30545af43d82803e903d91601857fd5bf3";
// These values are defined by the wallet context
// they must be known in order to validate the counter-factual wallet imageHash
const factory = "0xf9D09D634Fb818b05149329C1dcCFAeA53639d96";
const mainModule = "0xd01F11855bCcb95f88D7A48492F66410d4637313";
// Append the `mainModule` to the `WalletProxyBytecode`
// this completed the creation code of the proxy contract
// used for computing the wallet address as defined by the CREATE2 opcode
const codeHash = ethers.solidityPackedKeccak256(
ethers.solidityPackedKeccak256(
["bytes", "bytes32"],
[WalletContractBytecode, ethers.hexZeroPad(mainModule, 32)]
)
);
// Compute the wallet address
const hash = ethers.solidityPackedKeccak256(
ethers.solidityPackedKeccak256(
["bytes1", "address", "bytes32", "bytes32"],
["0xff", factory, salt, codeHash]
)
);
const address = ethers.getAddress(ethers.dataSlice(hash, 12));