Skip to content

Commit

Permalink
feat: display SafeMessage message hash when signing off-chain (#4687)
Browse files Browse the repository at this point in the history
* fix: don't use `chainId` when calculating domain hash of <=1.2.0

* Extract check to variable

* fix: use `dataGas` when calculating message hash of <1.0.0

* feat: display `SafeMessage` message hash when signing off-chain
  • Loading branch information
iamacook authored Dec 19, 2024
1 parent 914fd3b commit cb19058
Show file tree
Hide file tree
Showing 5 changed files with 282 additions and 164 deletions.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,53 +1,8 @@
import { TypedDataEncoder } from 'ethers'
import { TxDataRow, generateDataRowValue } from '../TxDataRow'
import { type SafeTransactionData, type SafeVersion } from '@safe-global/safe-core-sdk-types'
import { getEip712TxTypes } from '@safe-global/protocol-kit/dist/src/utils'
import useSafeAddress from '@/hooks/useSafeAddress'
import useChainId from '@/hooks/useChainId'
import semverSatisfies from 'semver/functions/satisfies'

const NEW_DOMAIN_TYPE_HASH_VERSION = '>=1.3.0'

export function getDomainHash({
chainId,
safeAddress,
safeVersion,
}: {
chainId: string
safeAddress: string
safeVersion: SafeVersion
}): string {
const includeChainId = semverSatisfies(safeVersion, NEW_DOMAIN_TYPE_HASH_VERSION)
return TypedDataEncoder.hashDomain({
...(includeChainId && { chainId }),
verifyingContract: safeAddress,
})
}

const NEW_SAFE_TX_TYPE_HASH_VERSION = '>=1.0.0'

export function getMessageHash({
safeVersion,
safeTxData,
}: {
safeVersion: SafeVersion
safeTxData: SafeTransactionData
}): string {
const usesBaseGas = semverSatisfies(safeVersion, NEW_SAFE_TX_TYPE_HASH_VERSION)
const SafeTx = getEip712TxTypes(safeVersion).SafeTx

// Clone to not modify the original
const tx: any = { ...safeTxData }

if (!usesBaseGas) {
tx.dataGas = tx.baseGas
delete tx.baseGas

SafeTx[5].name = 'dataGas'
}

return TypedDataEncoder.hashStruct('SafeTx', { SafeTx }, tx)
}
import { getDomainHash, getSafeTxMessageHash } from '@/utils/safe-hashes'

export const SafeTxHashDataRow = ({
safeTxHash,
Expand All @@ -62,7 +17,7 @@ export const SafeTxHashDataRow = ({
const safeAddress = useSafeAddress()

const domainHash = getDomainHash({ chainId, safeAddress, safeVersion })
const messageHash = safeTxData ? getMessageHash({ safeVersion, safeTxData }) : undefined
const messageHash = safeTxData ? getSafeTxMessageHash({ safeVersion, safeTxData }) : undefined

return (
<>
Expand Down
10 changes: 10 additions & 0 deletions src/components/tx-flow/flows/SignMessage/SignMessage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ import LinkIcon from '@/public/images/messages/link.svg'
import { Blockaid } from '@/components/tx/security/blockaid'
import CheckWallet from '@/components/common/CheckWallet'
import NetworkWarning from '@/components/new-safe/create/NetworkWarning'
import { getDomainHash, getSafeMessageMessageHash } from '@/utils/safe-hashes'
import type { SafeVersion } from '@safe-global/safe-core-sdk-types'

const createSkeletonMessage = (confirmationsRequired: number): SafeMessage => {
return {
Expand Down Expand Up @@ -260,6 +262,12 @@ const SignMessage = ({ message, origin, requestId }: SignMessageProps): ReactEle

const { decodedMessage, safeMessageMessage, safeMessageHash } = useDecodedSafeMessage(message, safe)
const [safeMessage, setSafeMessage] = useSafeMessage(safeMessageHash)
const domainHash = getDomainHash({
chainId: safe.chainId,
safeAddress: safe.address.value,
safeVersion: safe.version as SafeVersion,
})
const messageHash = getSafeMessageMessageHash({ message: decodedMessage, safeVersion: safe.version as SafeVersion })
const isPlainTextMessage = typeof decodedMessage === 'string'
const decodedMessageAsString = isPlainTextMessage ? decodedMessage : JSON.stringify(decodedMessage, null, 2)
const signedByCurrentSafe = !!safeMessage?.confirmations.some(({ owner }) => owner.value === wallet?.address)
Expand Down Expand Up @@ -346,6 +354,8 @@ const SignMessage = ({ message, origin, requestId }: SignMessageProps): ReactEle
<AccordionDetails>
<MessageHashField label="SafeMessage" hashValue={safeMessageMessage} />
<MessageHashField label="SafeMessage hash" hashValue={safeMessageHash} />
<MessageHashField label="Domain hash" hashValue={domainHash} />
<MessageHashField label="Message hash" hashValue={messageHash} />
</AccordionDetails>
</Accordion>

Expand Down
Loading

0 comments on commit cb19058

Please sign in to comment.