Sign messages with a Safe
Collect owner signatures for a Safe message and verify the resulting EIP-1271 signature.
Propose a message, collect message approvals, then verify the signature. See Need Help for support.
Prerequisites: a deployed Safe, owner accounts and a shared coordinator. Show every owner the exact message and its intended use before signing. A valid signature is not consent to a different message or domain.
Propose a Message
Use proposeMessage() to sign and share a message:
import { account, requiredEnv } from './safe-account.mjs'
const message = requiredEnv('MESSAGE_TO_SIGN')
const proposed = await account.proposeMessage(message)
console.log(proposed.messageId)sign() also creates and shares a message proposal, then returns only this owner's signature. It is not a local-only signing helper and does not return the combined Safe signature.
Collect Message Approvals
After another owner reviews the message, use approveMessageProposal() from that owner's account:
const approved = await account.approveMessageProposal(requiredEnv('MESSAGE_ID'))
console.log(approved.confirmations, approved.threshold)The module checks that the coordinator's message hashes to the requested identifier before signing. A missing combinedSignature means the coordinator has not supplied an assembled signature; a signature from one owner alone does not establish the threshold.
Verify the Signature
Use getMessageProposal() and verify() to check the coordinator-provided combined signature against the deployed Safe:
const result = await account.getMessageProposal(requiredEnv('MESSAGE_ID'))
if (!result?.combinedSignature || result.confirmations < result.threshold) {
throw new Error('Combined signature is not ready')
}
const valid = await account.verify(result.message, result.combinedSignature)
console.log('EIP-1271 valid:', valid)Verification can return false for a revert or invalid signature, and can throw for other RPC failures. Do not present an RPC failure as a valid signature.