From 929779f213c8db6fc01f15d22649915fe66240bd Mon Sep 17 00:00:00 2001 From: Ben Kremer Date: Thu, 10 Mar 2022 12:03:37 +0100 Subject: [PATCH] fix(dapps): aligns EIP712 example with the one used in spec Reference: https://eips.ethereum.org/EIPS/eip-712 --- dapps/react-dapp-v2-with-ethers/src/App.tsx | 50 +++++----------- .../src/helpers/eip712.ts | 46 ++++++--------- dapps/react-dapp-v2-with-web3js/src/App.tsx | 57 +++++++------------ .../src/helpers/eip712.ts | 46 ++++++--------- .../src/contexts/JsonRpcContext.tsx | 50 +++++----------- dapps/react-dapp-v2/src/helpers/eip712.ts | 46 ++++++--------- 6 files changed, 99 insertions(+), 196 deletions(-) diff --git a/dapps/react-dapp-v2-with-ethers/src/App.tsx b/dapps/react-dapp-v2-with-ethers/src/App.tsx index 637a2b4..e06dc5d 100644 --- a/dapps/react-dapp-v2-with-ethers/src/App.tsx +++ b/dapps/react-dapp-v2-with-ethers/src/App.tsx @@ -10,6 +10,7 @@ import Modal from "./components/Modal"; import { DEFAULT_MAIN_CHAINS, DEFAULT_TEST_CHAINS } from "./constants"; import { AccountAction, + eip712, formatTestTransaction, getLocalStorageTestnetFlag, setLocaleStorageTestnetFlag, @@ -28,6 +29,7 @@ import { } from "./components/app"; import { useWalletConnectClient } from "./contexts/ClientContext"; import { BigNumber, utils } from "ethers"; +import { TypedDataField } from "@ethersproject/abstract-signer"; interface IFormattedRpcResponse { method: string; @@ -177,39 +179,7 @@ export default function App() { throw new Error("web3Provider not connected"); } - const typedData = { - types: { - Person: [ - { name: "name", type: "string" }, - { name: "wallet", type: "address" }, - ], - Mail: [ - { name: "from", type: "Person" }, - { name: "to", type: "Person" }, - { name: "contents", type: "string" }, - ], - }, - primaryType: "Mail", - domain: { - name: "Ether Mail", - version: "1", - chainId: 1, - verifyingContract: "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC", - }, - message: { - from: { - name: "Cow", - wallet: "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826", - }, - to: { - name: "Bob", - wallet: "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB", - }, - contents: "Hello, Bob!", - }, - }; - - const message = JSON.stringify(typedData); + const message = JSON.stringify(eip712.example); const [address] = await web3Provider.listAccounts(); @@ -218,9 +188,19 @@ export default function App() { // send message const signature = await web3Provider.send("eth_signTypedData", params); + + // Separate `EIP712Domain` type from remaining types to verify, otherwise `ethers.utils.verifyTypedData` + // will throw due to "unused" `EIP712Domain` type. + const { EIP712Domain, ...nonDomainTypes }: Record = + eip712.example.types; + const valid = - utils.verifyTypedData(typedData.domain, typedData.types, typedData.message, signature) === - address; + utils.verifyTypedData( + eip712.example.domain, + nonDomainTypes, + eip712.example.message, + signature, + ) === address; return { method: "eth_signTypedData", address, diff --git a/dapps/react-dapp-v2-with-ethers/src/helpers/eip712.ts b/dapps/react-dapp-v2-with-ethers/src/helpers/eip712.ts index d1f3b9e..9dcf66e 100644 --- a/dapps/react-dapp-v2-with-ethers/src/helpers/eip712.ts +++ b/dapps/react-dapp-v2-with-ethers/src/helpers/eip712.ts @@ -1,47 +1,33 @@ +// From spec: https://eips.ethereum.org/EIPS/eip-712 const example = { types: { EIP712Domain: [ { name: "name", type: "string" }, { name: "version", type: "string" }, + { name: "chainId", type: "uint256" }, { name: "verifyingContract", type: "address" }, ], - RelayRequest: [ - { name: "target", type: "address" }, - { name: "encodedFunction", type: "bytes" }, - { name: "gasData", type: "GasData" }, - { name: "relayData", type: "RelayData" }, + Person: [ + { name: "name", type: "string" }, + { name: "wallet", type: "address" }, ], - GasData: [ - { name: "gasLimit", type: "uint256" }, - { name: "gasPrice", type: "uint256" }, - { name: "pctRelayFee", type: "uint256" }, - { name: "baseRelayFee", type: "uint256" }, - ], - RelayData: [ - { name: "senderAddress", type: "address" }, - { name: "senderNonce", type: "uint256" }, - { name: "relayWorker", type: "address" }, - { name: "paymaster", type: "address" }, + Mail: [ + { name: "from", type: "Person" }, + { name: "to", type: "Person" }, + { name: "contents", type: "string" }, ], }, + primaryType: "Mail", domain: { - name: "GSN Relayed Transaction", + name: "Ether Mail", version: "1", - chainId: 42, - verifyingContract: "0x6453D37248Ab2C16eBd1A8f782a2CBC65860E60B", + chainId: 1, + verifyingContract: "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC", }, - primaryType: "RelayRequest", message: { - target: "0x9cf40ef3d1622efe270fe6fe720585b4be4eeeff", - encodedFunction: - "0xa9059cbb0000000000000000000000002e0d94754b348d208d64d52d78bcd443afa9fa520000000000000000000000000000000000000000000000000000000000000007", - gasData: { gasLimit: "39507", gasPrice: "1700000000", pctRelayFee: "70", baseRelayFee: "0" }, - relayData: { - senderAddress: "0x22d491bde2303f2f43325b2108d26f1eaba1e32b", - senderNonce: "3", - relayWorker: "0x3baee457ad824c94bd3953183d725847d023a2cf", - paymaster: "0x957F270d45e9Ceca5c5af2b49f1b5dC1Abb0421c", - }, + from: { name: "Cow", wallet: "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826" }, + to: { name: "Bob", wallet: "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB" }, + contents: "Hello, Bob!", }, }; diff --git a/dapps/react-dapp-v2-with-web3js/src/App.tsx b/dapps/react-dapp-v2-with-web3js/src/App.tsx index 19091b1..b2d83dc 100644 --- a/dapps/react-dapp-v2-with-web3js/src/App.tsx +++ b/dapps/react-dapp-v2-with-web3js/src/App.tsx @@ -8,7 +8,12 @@ import Column from "./components/Column"; import Header from "./components/Header"; import Modal from "./components/Modal"; import { DEFAULT_MAIN_CHAINS, DEFAULT_TEST_CHAINS } from "./constants"; -import { AccountAction, getLocalStorageTestnetFlag, setLocaleStorageTestnetFlag } from "./helpers"; +import { + AccountAction, + eip712, + getLocalStorageTestnetFlag, + setLocaleStorageTestnetFlag, +} from "./helpers"; import Toggle from "./components/Toggle"; import RequestModal from "./modals/RequestModal"; import PingModal from "./modals/PingModal"; @@ -23,6 +28,7 @@ import { } from "./components/app"; import { useWalletConnectClient } from "./contexts/ClientContext"; import { utils } from "ethers"; +import { TypedDataField } from "@ethersproject/abstract-signer"; interface IFormattedRpcResponse { method: string; @@ -175,39 +181,7 @@ export default function App() { throw new Error("web3Provider.currentProvider is not set"); } - const typedData = { - types: { - Person: [ - { name: "name", type: "string" }, - { name: "wallet", type: "address" }, - ], - Mail: [ - { name: "from", type: "Person" }, - { name: "to", type: "Person" }, - { name: "contents", type: "string" }, - ], - }, - primaryType: "Mail", - domain: { - name: "Ether Mail", - version: "1", - chainId: 1, - verifyingContract: "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC", - }, - message: { - from: { - name: "Cow", - wallet: "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826", - }, - to: { - name: "Bob", - wallet: "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB", - }, - contents: "Hello, Bob!", - }, - }; - - const message = JSON.stringify(typedData); + const message = JSON.stringify(eip712.example); const [address] = await web3Provider.eth.getAccounts(); @@ -222,9 +196,20 @@ export default function App() { method: "eth_signTypedData", params, }); + + // Separate `EIP712Domain` type from remaining types to verify, otherwise `ethers.utils.verifyTypedData` + // will throw due to "unused" `EIP712Domain` type. + const { EIP712Domain, ...nonDomainTypes }: Record = + eip712.example.types; + const valid = - utils.verifyTypedData(typedData.domain, typedData.types, typedData.message, signature) === - address; + utils.verifyTypedData( + eip712.example.domain, + nonDomainTypes, + eip712.example.message, + signature, + ) === address; + return { method: "eth_signTypedData", address, diff --git a/dapps/react-dapp-v2-with-web3js/src/helpers/eip712.ts b/dapps/react-dapp-v2-with-web3js/src/helpers/eip712.ts index d1f3b9e..9dcf66e 100644 --- a/dapps/react-dapp-v2-with-web3js/src/helpers/eip712.ts +++ b/dapps/react-dapp-v2-with-web3js/src/helpers/eip712.ts @@ -1,47 +1,33 @@ +// From spec: https://eips.ethereum.org/EIPS/eip-712 const example = { types: { EIP712Domain: [ { name: "name", type: "string" }, { name: "version", type: "string" }, + { name: "chainId", type: "uint256" }, { name: "verifyingContract", type: "address" }, ], - RelayRequest: [ - { name: "target", type: "address" }, - { name: "encodedFunction", type: "bytes" }, - { name: "gasData", type: "GasData" }, - { name: "relayData", type: "RelayData" }, + Person: [ + { name: "name", type: "string" }, + { name: "wallet", type: "address" }, ], - GasData: [ - { name: "gasLimit", type: "uint256" }, - { name: "gasPrice", type: "uint256" }, - { name: "pctRelayFee", type: "uint256" }, - { name: "baseRelayFee", type: "uint256" }, - ], - RelayData: [ - { name: "senderAddress", type: "address" }, - { name: "senderNonce", type: "uint256" }, - { name: "relayWorker", type: "address" }, - { name: "paymaster", type: "address" }, + Mail: [ + { name: "from", type: "Person" }, + { name: "to", type: "Person" }, + { name: "contents", type: "string" }, ], }, + primaryType: "Mail", domain: { - name: "GSN Relayed Transaction", + name: "Ether Mail", version: "1", - chainId: 42, - verifyingContract: "0x6453D37248Ab2C16eBd1A8f782a2CBC65860E60B", + chainId: 1, + verifyingContract: "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC", }, - primaryType: "RelayRequest", message: { - target: "0x9cf40ef3d1622efe270fe6fe720585b4be4eeeff", - encodedFunction: - "0xa9059cbb0000000000000000000000002e0d94754b348d208d64d52d78bcd443afa9fa520000000000000000000000000000000000000000000000000000000000000007", - gasData: { gasLimit: "39507", gasPrice: "1700000000", pctRelayFee: "70", baseRelayFee: "0" }, - relayData: { - senderAddress: "0x22d491bde2303f2f43325b2108d26f1eaba1e32b", - senderNonce: "3", - relayWorker: "0x3baee457ad824c94bd3953183d725847d023a2cf", - paymaster: "0x957F270d45e9Ceca5c5af2b49f1b5dC1Abb0421c", - }, + from: { name: "Cow", wallet: "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826" }, + to: { name: "Bob", wallet: "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB" }, + contents: "Hello, Bob!", }, }; diff --git a/dapps/react-dapp-v2/src/contexts/JsonRpcContext.tsx b/dapps/react-dapp-v2/src/contexts/JsonRpcContext.tsx index 126a234..7d3b48d 100644 --- a/dapps/react-dapp-v2/src/contexts/JsonRpcContext.tsx +++ b/dapps/react-dapp-v2/src/contexts/JsonRpcContext.tsx @@ -5,6 +5,7 @@ import { formatDirectSignDoc, stringifySignDocValues } from "cosmos-wallet"; import { ChainNamespaces, + eip712, formatTestTransaction, getAllChainNamespaces, hashPersonalMessage, @@ -12,6 +13,7 @@ import { } from "../helpers"; import { useWalletConnectClient } from "./ClientContext"; import { apiGetChainNamespace, ChainsMap } from "caip-api"; +import { TypedDataField } from "@ethersproject/abstract-signer"; /** * Types @@ -294,39 +296,7 @@ export function JsonRpcContextProvider({ children }: { children: ReactNode | Rea }; }), testSignTypedData: _createJsonRpcRequestHandler(async (chainId: string, address: string) => { - const typedData = { - types: { - Person: [ - { name: "name", type: "string" }, - { name: "wallet", type: "address" }, - ], - Mail: [ - { name: "from", type: "Person" }, - { name: "to", type: "Person" }, - { name: "contents", type: "string" }, - ], - }, - primaryType: "Mail", - domain: { - name: "Ether Mail", - version: "1", - chainId: 1, - verifyingContract: "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC", - }, - message: { - from: { - name: "Cow", - wallet: "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826", - }, - to: { - name: "Bob", - wallet: "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB", - }, - contents: "Hello, Bob!", - }, - }; - - const message = JSON.stringify(typedData); + const message = JSON.stringify(eip712.example); // eth_signTypedData params const params = [address, message]; @@ -340,9 +310,19 @@ export function JsonRpcContextProvider({ children }: { children: ReactNode | Rea params, }, }); + + // Separate `EIP712Domain` type from remaining types to verify, otherwise `ethers.utils.verifyTypedData` + // will throw due to "unused" `EIP712Domain` type. + const { EIP712Domain, ...nonDomainTypes }: Record = + eip712.example.types; + const valid = - utils.verifyTypedData(typedData.domain, typedData.types, typedData.message, signature) === - address; + utils.verifyTypedData( + eip712.example.domain, + nonDomainTypes, + eip712.example.message, + signature, + ) === address; return { method: "eth_signTypedData", diff --git a/dapps/react-dapp-v2/src/helpers/eip712.ts b/dapps/react-dapp-v2/src/helpers/eip712.ts index d1f3b9e..9dcf66e 100644 --- a/dapps/react-dapp-v2/src/helpers/eip712.ts +++ b/dapps/react-dapp-v2/src/helpers/eip712.ts @@ -1,47 +1,33 @@ +// From spec: https://eips.ethereum.org/EIPS/eip-712 const example = { types: { EIP712Domain: [ { name: "name", type: "string" }, { name: "version", type: "string" }, + { name: "chainId", type: "uint256" }, { name: "verifyingContract", type: "address" }, ], - RelayRequest: [ - { name: "target", type: "address" }, - { name: "encodedFunction", type: "bytes" }, - { name: "gasData", type: "GasData" }, - { name: "relayData", type: "RelayData" }, + Person: [ + { name: "name", type: "string" }, + { name: "wallet", type: "address" }, ], - GasData: [ - { name: "gasLimit", type: "uint256" }, - { name: "gasPrice", type: "uint256" }, - { name: "pctRelayFee", type: "uint256" }, - { name: "baseRelayFee", type: "uint256" }, - ], - RelayData: [ - { name: "senderAddress", type: "address" }, - { name: "senderNonce", type: "uint256" }, - { name: "relayWorker", type: "address" }, - { name: "paymaster", type: "address" }, + Mail: [ + { name: "from", type: "Person" }, + { name: "to", type: "Person" }, + { name: "contents", type: "string" }, ], }, + primaryType: "Mail", domain: { - name: "GSN Relayed Transaction", + name: "Ether Mail", version: "1", - chainId: 42, - verifyingContract: "0x6453D37248Ab2C16eBd1A8f782a2CBC65860E60B", + chainId: 1, + verifyingContract: "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC", }, - primaryType: "RelayRequest", message: { - target: "0x9cf40ef3d1622efe270fe6fe720585b4be4eeeff", - encodedFunction: - "0xa9059cbb0000000000000000000000002e0d94754b348d208d64d52d78bcd443afa9fa520000000000000000000000000000000000000000000000000000000000000007", - gasData: { gasLimit: "39507", gasPrice: "1700000000", pctRelayFee: "70", baseRelayFee: "0" }, - relayData: { - senderAddress: "0x22d491bde2303f2f43325b2108d26f1eaba1e32b", - senderNonce: "3", - relayWorker: "0x3baee457ad824c94bd3953183d725847d023a2cf", - paymaster: "0x957F270d45e9Ceca5c5af2b49f1b5dC1Abb0421c", - }, + from: { name: "Cow", wallet: "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826" }, + to: { name: "Bob", wallet: "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB" }, + contents: "Hello, Bob!", }, };