fix(dapps): aligns EIP712 example with the one used in spec

Reference: https://eips.ethereum.org/EIPS/eip-712
This commit is contained in:
Ben Kremer 2022-03-10 12:03:37 +01:00
parent 86987454eb
commit 929779f213
6 changed files with 99 additions and 196 deletions

View File

@ -10,6 +10,7 @@ import Modal from "./components/Modal";
import { DEFAULT_MAIN_CHAINS, DEFAULT_TEST_CHAINS } from "./constants"; import { DEFAULT_MAIN_CHAINS, DEFAULT_TEST_CHAINS } from "./constants";
import { import {
AccountAction, AccountAction,
eip712,
formatTestTransaction, formatTestTransaction,
getLocalStorageTestnetFlag, getLocalStorageTestnetFlag,
setLocaleStorageTestnetFlag, setLocaleStorageTestnetFlag,
@ -28,6 +29,7 @@ import {
} from "./components/app"; } from "./components/app";
import { useWalletConnectClient } from "./contexts/ClientContext"; import { useWalletConnectClient } from "./contexts/ClientContext";
import { BigNumber, utils } from "ethers"; import { BigNumber, utils } from "ethers";
import { TypedDataField } from "@ethersproject/abstract-signer";
interface IFormattedRpcResponse { interface IFormattedRpcResponse {
method: string; method: string;
@ -177,39 +179,7 @@ export default function App() {
throw new Error("web3Provider not connected"); throw new Error("web3Provider not connected");
} }
const typedData = { const message = JSON.stringify(eip712.example);
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 [address] = await web3Provider.listAccounts(); const [address] = await web3Provider.listAccounts();
@ -218,9 +188,19 @@ export default function App() {
// send message // send message
const signature = await web3Provider.send("eth_signTypedData", params); 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<string, TypedDataField[]> =
eip712.example.types;
const valid = const valid =
utils.verifyTypedData(typedData.domain, typedData.types, typedData.message, signature) === utils.verifyTypedData(
address; eip712.example.domain,
nonDomainTypes,
eip712.example.message,
signature,
) === address;
return { return {
method: "eth_signTypedData", method: "eth_signTypedData",
address, address,

View File

@ -1,47 +1,33 @@
// From spec: https://eips.ethereum.org/EIPS/eip-712
const example = { const example = {
types: { types: {
EIP712Domain: [ EIP712Domain: [
{ name: "name", type: "string" }, { name: "name", type: "string" },
{ name: "version", type: "string" }, { name: "version", type: "string" },
{ name: "chainId", type: "uint256" },
{ name: "verifyingContract", type: "address" }, { name: "verifyingContract", type: "address" },
], ],
RelayRequest: [ Person: [
{ name: "target", type: "address" }, { name: "name", type: "string" },
{ name: "encodedFunction", type: "bytes" }, { name: "wallet", type: "address" },
{ name: "gasData", type: "GasData" },
{ name: "relayData", type: "RelayData" },
], ],
GasData: [ Mail: [
{ name: "gasLimit", type: "uint256" }, { name: "from", type: "Person" },
{ name: "gasPrice", type: "uint256" }, { name: "to", type: "Person" },
{ name: "pctRelayFee", type: "uint256" }, { name: "contents", type: "string" },
{ name: "baseRelayFee", type: "uint256" },
],
RelayData: [
{ name: "senderAddress", type: "address" },
{ name: "senderNonce", type: "uint256" },
{ name: "relayWorker", type: "address" },
{ name: "paymaster", type: "address" },
], ],
}, },
primaryType: "Mail",
domain: { domain: {
name: "GSN Relayed Transaction", name: "Ether Mail",
version: "1", version: "1",
chainId: 42, chainId: 1,
verifyingContract: "0x6453D37248Ab2C16eBd1A8f782a2CBC65860E60B", verifyingContract: "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC",
}, },
primaryType: "RelayRequest",
message: { message: {
target: "0x9cf40ef3d1622efe270fe6fe720585b4be4eeeff", from: { name: "Cow", wallet: "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826" },
encodedFunction: to: { name: "Bob", wallet: "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB" },
"0xa9059cbb0000000000000000000000002e0d94754b348d208d64d52d78bcd443afa9fa520000000000000000000000000000000000000000000000000000000000000007", contents: "Hello, Bob!",
gasData: { gasLimit: "39507", gasPrice: "1700000000", pctRelayFee: "70", baseRelayFee: "0" },
relayData: {
senderAddress: "0x22d491bde2303f2f43325b2108d26f1eaba1e32b",
senderNonce: "3",
relayWorker: "0x3baee457ad824c94bd3953183d725847d023a2cf",
paymaster: "0x957F270d45e9Ceca5c5af2b49f1b5dC1Abb0421c",
},
}, },
}; };

View File

@ -8,7 +8,12 @@ import Column from "./components/Column";
import Header from "./components/Header"; import Header from "./components/Header";
import Modal from "./components/Modal"; import Modal from "./components/Modal";
import { DEFAULT_MAIN_CHAINS, DEFAULT_TEST_CHAINS } from "./constants"; 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 Toggle from "./components/Toggle";
import RequestModal from "./modals/RequestModal"; import RequestModal from "./modals/RequestModal";
import PingModal from "./modals/PingModal"; import PingModal from "./modals/PingModal";
@ -23,6 +28,7 @@ import {
} from "./components/app"; } from "./components/app";
import { useWalletConnectClient } from "./contexts/ClientContext"; import { useWalletConnectClient } from "./contexts/ClientContext";
import { utils } from "ethers"; import { utils } from "ethers";
import { TypedDataField } from "@ethersproject/abstract-signer";
interface IFormattedRpcResponse { interface IFormattedRpcResponse {
method: string; method: string;
@ -175,39 +181,7 @@ export default function App() {
throw new Error("web3Provider.currentProvider is not set"); throw new Error("web3Provider.currentProvider is not set");
} }
const typedData = { const message = JSON.stringify(eip712.example);
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 [address] = await web3Provider.eth.getAccounts(); const [address] = await web3Provider.eth.getAccounts();
@ -222,9 +196,20 @@ export default function App() {
method: "eth_signTypedData", method: "eth_signTypedData",
params, params,
}); });
// Separate `EIP712Domain` type from remaining types to verify, otherwise `ethers.utils.verifyTypedData`
// will throw due to "unused" `EIP712Domain` type.
const { EIP712Domain, ...nonDomainTypes }: Record<string, TypedDataField[]> =
eip712.example.types;
const valid = const valid =
utils.verifyTypedData(typedData.domain, typedData.types, typedData.message, signature) === utils.verifyTypedData(
address; eip712.example.domain,
nonDomainTypes,
eip712.example.message,
signature,
) === address;
return { return {
method: "eth_signTypedData", method: "eth_signTypedData",
address, address,

View File

@ -1,47 +1,33 @@
// From spec: https://eips.ethereum.org/EIPS/eip-712
const example = { const example = {
types: { types: {
EIP712Domain: [ EIP712Domain: [
{ name: "name", type: "string" }, { name: "name", type: "string" },
{ name: "version", type: "string" }, { name: "version", type: "string" },
{ name: "chainId", type: "uint256" },
{ name: "verifyingContract", type: "address" }, { name: "verifyingContract", type: "address" },
], ],
RelayRequest: [ Person: [
{ name: "target", type: "address" }, { name: "name", type: "string" },
{ name: "encodedFunction", type: "bytes" }, { name: "wallet", type: "address" },
{ name: "gasData", type: "GasData" },
{ name: "relayData", type: "RelayData" },
], ],
GasData: [ Mail: [
{ name: "gasLimit", type: "uint256" }, { name: "from", type: "Person" },
{ name: "gasPrice", type: "uint256" }, { name: "to", type: "Person" },
{ name: "pctRelayFee", type: "uint256" }, { name: "contents", type: "string" },
{ name: "baseRelayFee", type: "uint256" },
],
RelayData: [
{ name: "senderAddress", type: "address" },
{ name: "senderNonce", type: "uint256" },
{ name: "relayWorker", type: "address" },
{ name: "paymaster", type: "address" },
], ],
}, },
primaryType: "Mail",
domain: { domain: {
name: "GSN Relayed Transaction", name: "Ether Mail",
version: "1", version: "1",
chainId: 42, chainId: 1,
verifyingContract: "0x6453D37248Ab2C16eBd1A8f782a2CBC65860E60B", verifyingContract: "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC",
}, },
primaryType: "RelayRequest",
message: { message: {
target: "0x9cf40ef3d1622efe270fe6fe720585b4be4eeeff", from: { name: "Cow", wallet: "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826" },
encodedFunction: to: { name: "Bob", wallet: "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB" },
"0xa9059cbb0000000000000000000000002e0d94754b348d208d64d52d78bcd443afa9fa520000000000000000000000000000000000000000000000000000000000000007", contents: "Hello, Bob!",
gasData: { gasLimit: "39507", gasPrice: "1700000000", pctRelayFee: "70", baseRelayFee: "0" },
relayData: {
senderAddress: "0x22d491bde2303f2f43325b2108d26f1eaba1e32b",
senderNonce: "3",
relayWorker: "0x3baee457ad824c94bd3953183d725847d023a2cf",
paymaster: "0x957F270d45e9Ceca5c5af2b49f1b5dC1Abb0421c",
},
}, },
}; };

View File

@ -5,6 +5,7 @@ import { formatDirectSignDoc, stringifySignDocValues } from "cosmos-wallet";
import { import {
ChainNamespaces, ChainNamespaces,
eip712,
formatTestTransaction, formatTestTransaction,
getAllChainNamespaces, getAllChainNamespaces,
hashPersonalMessage, hashPersonalMessage,
@ -12,6 +13,7 @@ import {
} from "../helpers"; } from "../helpers";
import { useWalletConnectClient } from "./ClientContext"; import { useWalletConnectClient } from "./ClientContext";
import { apiGetChainNamespace, ChainsMap } from "caip-api"; import { apiGetChainNamespace, ChainsMap } from "caip-api";
import { TypedDataField } from "@ethersproject/abstract-signer";
/** /**
* Types * Types
@ -294,39 +296,7 @@ export function JsonRpcContextProvider({ children }: { children: ReactNode | Rea
}; };
}), }),
testSignTypedData: _createJsonRpcRequestHandler(async (chainId: string, address: string) => { testSignTypedData: _createJsonRpcRequestHandler(async (chainId: string, address: string) => {
const typedData = { const message = JSON.stringify(eip712.example);
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);
// eth_signTypedData params // eth_signTypedData params
const params = [address, message]; const params = [address, message];
@ -340,9 +310,19 @@ export function JsonRpcContextProvider({ children }: { children: ReactNode | Rea
params, params,
}, },
}); });
// Separate `EIP712Domain` type from remaining types to verify, otherwise `ethers.utils.verifyTypedData`
// will throw due to "unused" `EIP712Domain` type.
const { EIP712Domain, ...nonDomainTypes }: Record<string, TypedDataField[]> =
eip712.example.types;
const valid = const valid =
utils.verifyTypedData(typedData.domain, typedData.types, typedData.message, signature) === utils.verifyTypedData(
address; eip712.example.domain,
nonDomainTypes,
eip712.example.message,
signature,
) === address;
return { return {
method: "eth_signTypedData", method: "eth_signTypedData",

View File

@ -1,47 +1,33 @@
// From spec: https://eips.ethereum.org/EIPS/eip-712
const example = { const example = {
types: { types: {
EIP712Domain: [ EIP712Domain: [
{ name: "name", type: "string" }, { name: "name", type: "string" },
{ name: "version", type: "string" }, { name: "version", type: "string" },
{ name: "chainId", type: "uint256" },
{ name: "verifyingContract", type: "address" }, { name: "verifyingContract", type: "address" },
], ],
RelayRequest: [ Person: [
{ name: "target", type: "address" }, { name: "name", type: "string" },
{ name: "encodedFunction", type: "bytes" }, { name: "wallet", type: "address" },
{ name: "gasData", type: "GasData" },
{ name: "relayData", type: "RelayData" },
], ],
GasData: [ Mail: [
{ name: "gasLimit", type: "uint256" }, { name: "from", type: "Person" },
{ name: "gasPrice", type: "uint256" }, { name: "to", type: "Person" },
{ name: "pctRelayFee", type: "uint256" }, { name: "contents", type: "string" },
{ name: "baseRelayFee", type: "uint256" },
],
RelayData: [
{ name: "senderAddress", type: "address" },
{ name: "senderNonce", type: "uint256" },
{ name: "relayWorker", type: "address" },
{ name: "paymaster", type: "address" },
], ],
}, },
primaryType: "Mail",
domain: { domain: {
name: "GSN Relayed Transaction", name: "Ether Mail",
version: "1", version: "1",
chainId: 42, chainId: 1,
verifyingContract: "0x6453D37248Ab2C16eBd1A8f782a2CBC65860E60B", verifyingContract: "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC",
}, },
primaryType: "RelayRequest",
message: { message: {
target: "0x9cf40ef3d1622efe270fe6fe720585b4be4eeeff", from: { name: "Cow", wallet: "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826" },
encodedFunction: to: { name: "Bob", wallet: "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB" },
"0xa9059cbb0000000000000000000000002e0d94754b348d208d64d52d78bcd443afa9fa520000000000000000000000000000000000000000000000000000000000000007", contents: "Hello, Bob!",
gasData: { gasLimit: "39507", gasPrice: "1700000000", pctRelayFee: "70", baseRelayFee: "0" },
relayData: {
senderAddress: "0x22d491bde2303f2f43325b2108d26f1eaba1e32b",
senderNonce: "3",
relayWorker: "0x3baee457ad824c94bd3953183d725847d023a2cf",
paymaster: "0x957F270d45e9Ceca5c5af2b49f1b5dC1Abb0421c",
},
}, },
}; };