Skip to content

Commit

Permalink
Add signTypedData support for waas connector
Browse files Browse the repository at this point in the history
  • Loading branch information
tolgahan-arikan committed Dec 19, 2024
1 parent 9ad2c90 commit ec95388
Show file tree
Hide file tree
Showing 5 changed files with 239 additions and 31 deletions.
4 changes: 2 additions & 2 deletions examples/react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
"@0xsequence/kit-wallet": "workspace:*",
"@0xsequence/kit-example-shared-components": "workspace:*",
"@tanstack/react-query": "^5.37.1",
"@0xsequence/network": "2.1.4",
"@0xsequence/waas": "2.1.4",
"@0xsequence/network": ">= 2.1.4",
"@0xsequence/waas": "0.0.0-20241218203257",
"framer-motion": "^8.5.2",
"react": "^18.3.1",
"react-dom": "^18.3.1",
Expand Down
97 changes: 97 additions & 0 deletions examples/react/src/components/Connected.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ export const Connected = () => {
const [isSigningMessage, setIsSigningMessage] = React.useState(false)
const [isMessageValid, setIsMessageValid] = React.useState<boolean | undefined>()
const [messageSig, setMessageSig] = React.useState<string | undefined>()
const [isSigningTypedData, setIsSigningTypedData] = React.useState(false)
const [typedDataSig, setTypedDataSig] = React.useState<string | undefined>()
const [isTypedDataValid, setIsTypedDataValid] = React.useState<boolean | undefined>()

const [lastTxnDataHash, setLastTxnDataHash] = React.useState<string | undefined>()
const [lastTxnDataHash2, setLastTxnDataHash2] = React.useState<string | undefined>()
Expand Down Expand Up @@ -192,6 +195,69 @@ export const Connected = () => {
}
}, [txnData, txnData2, txnData3])

const domain = {
name: 'Sequence Example',
version: '1',
chainId: chainId,
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC'
} as const

const types = {
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' }
]
} as const

const value = {
name: 'John Doe',
wallet: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC'
} as const

const signTypedData = async () => {
if (!walletClient || !address || !publicClient) {
return
}

setIsSigningTypedData(true)

try {
const sig = await walletClient.signTypedData({
account: address,
domain,
types,
primaryType: 'Person',
message: value
})

console.log('signature:', sig)

const [account] = await walletClient.getAddresses()

const isValid = await publicClient.verifyTypedData({
address: account,
domain,
types,
primaryType: 'Person',
message: value,
signature: sig
})

console.log('isValid?', isValid)

setTypedDataSig(sig)
setIsTypedDataValid(isValid)
setIsSigningTypedData(false)
} catch (e) {
setIsSigningTypedData(false)
if (e instanceof Error) {
console.error(e.cause)
} else {
console.error(e)
}
}
}

const signMessage = async () => {
if (!walletClient || !publicClient) {
return
Expand Down Expand Up @@ -411,6 +477,7 @@ export const Connected = () => {
setLastTxnDataHash2(undefined)
setLastTxnDataHash3(undefined)
setIsMessageValid(undefined)
setTypedDataSig(undefined)
resetWriteContract()
resetSendUnsponsoredTransaction()
resetSendTransaction()
Expand Down Expand Up @@ -503,6 +570,36 @@ export const Connected = () => {
</Text>
</Card>
)}
<CardButton
title="Sign typed data"
description="Sign typed data with your wallet"
onClick={signTypedData}
isPending={isSigningTypedData}
/>
{typedDataSig && (
<Card style={{ width: '332px' }} color={'text100'} flexDirection={'column'} gap={'2'}>
<Text variant="medium">Signed typed data:</Text>
<Text variant="code" as="p">
{JSON.stringify(
{
domain,
types,
primaryType: 'Person',
message: value
},
null,
2
)}
</Text>
<Text variant="medium">Signature:</Text>
<Text variant="code" as="p" ellipsis>
{typedDataSig}
</Text>
<Text variant="medium">
isValid: <Text variant="code">{isTypedDataValid?.toString()}</Text>
</Text>
</Card>
)}
<CardButton title="Add Funds" description="Buy Cryptocurrency with a Credit Card" onClick={() => onClickAddFunds()} />
{(chainId === ChainId.ARBITRUM_NOVA || chainId === ChainId.ARBITRUM_SEPOLIA) && (
<CardButton
Expand Down
18 changes: 9 additions & 9 deletions packages/kit/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,17 @@
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@0xsequence/api": "^2.1.4",
"@0xsequence/auth": "^2.1.4",
"@0xsequence/core": "^2.1.4",
"@0xsequence/api": ">= 2.1.4",
"@0xsequence/auth": ">= 2.1.4",
"@0xsequence/core": ">= 2.1.4",
"@0xsequence/design-system": "^1.7.8",
"@0xsequence/ethauth": "^1.0.0",
"@0xsequence/indexer": "^2.1.4",
"@0xsequence/metadata": "^2.1.4",
"@0xsequence/network": "^2.1.4",
"@0xsequence/provider": "^2.1.4",
"@0xsequence/utils": "^2.1.4",
"@0xsequence/waas": "^2.1.4",
"@0xsequence/indexer": ">= 2.1.4",
"@0xsequence/metadata": ">= 2.1.4",
"@0xsequence/network": ">= 2.1.4",
"@0xsequence/provider": ">= 2.1.4",
"@0xsequence/utils": ">= 2.1.4",
"@0xsequence/waas": "0.0.0-20241218203257",
"framer-motion": "^8.5.2",
"uuid": "^10.0.0"
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -379,12 +379,7 @@ export class SequenceWaasProvider extends ethers.AbstractProvider implements EIP
}
}

if (
method === 'eth_sign' ||
method === 'eth_signTypedData' ||
method === 'eth_signTypedData_v4' ||
method === 'personal_sign'
) {
if (method === 'eth_sign' || method === 'personal_sign') {
if (this.requestConfirmationHandler && this.showConfirmation) {
const id = uuidv4()
const confirmation = await this.requestConfirmationHandler.confirmSignMessageRequest(
Expand Down Expand Up @@ -422,6 +417,47 @@ export class SequenceWaasProvider extends ethers.AbstractProvider implements EIP
return sig.data.signature
}

if (method === 'eth_signTypedData' || method === 'eth_signTypedData_v4') {
if (this.requestConfirmationHandler && this.showConfirmation) {
const id = uuidv4()
const confirmation = await this.requestConfirmationHandler.confirmSignMessageRequest(
id,
JSON.stringify(JSON.parse(params?.[1]), null, 2), // Pretty print the typed data for confirmation
Number(this.currentNetwork.chainId)
)

if (!confirmation.confirmed) {
throw new UserRejectedRequestError(new Error('User rejected sign typed data request'))
}

if (id !== confirmation.id) {
throw new UserRejectedRequestError(new Error('User confirmation ids do not match'))
}
}

let sig

try {
sig = await this.sequenceWaas.signTypedData({
typedData: JSON.parse(params?.[1]),
network: Number(this.currentNetwork.chainId)
})
} catch (error) {
if (isSessionInvalidOrNotFoundError(error)) {
await this.emit('error', error)
throw new ProviderDisconnectedError(new Error('Provider is not connected'))
} else {
const message =
typeof error === 'object' && error !== null && 'cause' in error
? (String(error.cause) ?? 'Failed to sign typed data')
: 'Failed to sign typed data'
throw new InternalRpcError(new Error(message))
}
}

return sig.data.signature
}

return await this.jsonRpcProvider.send(method, params ?? [])
}

Expand Down
Loading

0 comments on commit ec95388

Please sign in to comment.