### Step-by-Step Guide to Signing and Validating a Message for `COWShed` Execution 1. **Prepare the Message Data to Sign** - In `COWShed`, the message data includes the following parameters: - `calls`: An array of `Call` structs, each containing the `target`, `value`, `callData`, `allowFailure`, and `isDelegateCall`. - `nonce`: A unique identifier for the transaction, preventing replay attacks. - `deadline`: The timestamp until which the message is valid. - Using these parameters, the message data to be signed is constructed by `LibAuthenticatedHooks` as follows: ```solidity bytes32 messageData = keccak256( abi.encode( LibAuthenticatedHooks.EXECUTE_HOOKS_TYPE_HASH, LibAuthenticatedHooks.callsHash(calls), nonce, deadline ) ); ``` - This `messageData` is the core data you want the Safe to recognize as valid. 2. **Generate the Domain Separator in `COWShed`** - `COWShed` provides its own domain separator for EIP-712 compatibility, which includes the contract’s name, version, chain ID, and address: ```solidity bytes32 domainSeparator = COWShed.domainSeparator(); ``` - This domain separator is essential to make the hash specific to `COWShed`. 3. **Create the Full Message Hash for Signing** - Using the domain separator and `messageData`, we generate the final `msgHash`: ```solidity bytes32 msgHash = keccak256( abi.encodePacked( bytes1(0x19), bytes1(0x01), domainSeparator, messageData ) ); ``` 4. **Delegate Call to `SignMessageLib`** - To mark the `msgHash` as approved by the Safe, perform a `delegatecall` to `SignMessageLib` from within the Safe, calling `SignMessageLib.signMessage` with `_data` as the encoded message data: ```solidity SignMessageLib(signMessageLibAddress).signMessage(_data); ``` - This ensures that the message is stored as signed in the Safe’s `signedMessages` mapping. 5. **Sign the Message Hash within the Safe** - When `signMessage` is called, it calculates `msgHash` internally and sets `signedMessages[msgHash] = 1`, marking it as approved. - An event `SignMsg(bytes32 msgHash)` is emitted, confirming the signing and approval of the message hash. 6. **Execute the Call in `COWShed`** - Now that the message hash is approved in the Safe’s storage, `COWShed` can execute actions based on it. - When `COWShed` receives the message for execution, it uses `LibAuthenticatedHooks` to validate the signed message. The `LibAuthenticatedHooks.authenticateHooks` function checks that the Safe’s `signedMessages` mapping contains the `msgHash`. 7. **Validate the Signature with `CompatibilityFallbackHandler`** - `CompatibilityFallbackHandler` in the Safe validates that `signedMessages[msgHash]` is set. - This verification confirms the message’s authenticity, allowing `COWShed` to execute the actions specified in the signed message. --- ### Complete Process Summary 1. **Define Message Data:** Include `calls`, `nonce`, and `deadline` for `COWShed` as part of the message data. 2. **Generate Domain Separator and Message Hash:** Combine the domain separator and message data for the full `msgHash`. 3. **Delegate Call to SignMessageLib:** Use `delegatecall` to mark `msgHash` as signed within the Safe’s `signedMessages`. 4. **Approve Message in Safe:** `SignMessageLib` sets `signedMessages[msgHash] = 1` and emits an event. 5. **Execute in COWShed:** With the approved message, `COWShed` performs the intended actions after verifying the signature via the Safe’s `CompatibilityFallbackHandler`.