diff --git a/libs/remix-simulator/src/methods/accounts.ts b/libs/remix-simulator/src/methods/accounts.ts index 5151499d9f..63d3729c45 100644 --- a/libs/remix-simulator/src/methods/accounts.ts +++ b/libs/remix-simulator/src/methods/accounts.ts @@ -1,11 +1,17 @@ +import { signTypedData, SignTypedDataVersion, TypedMessage, MessageTypes } from '@metamask/eth-sig-util' import { privateToAddress, toChecksumAddress, isValidPrivate, Address, toBytes, bytesToHex, Account } from '@ethereumjs/util' import { privateKeyToAccount } from 'web3-eth-accounts' import { toBigInt } from 'web3-utils' import * as crypto from 'crypto' +type AccountType = { + nonce: number, + privateKey: Uint8Array +} + export class Web3Accounts { - accounts: Record - accountsKeys: Record + accounts: Record + accountsKeys: Record vmContext constructor (vmContext) { @@ -73,7 +79,9 @@ export class Web3Accounts { eth_accounts: this.eth_accounts.bind(this), eth_getBalance: this.eth_getBalance.bind(this), eth_sign: this.eth_sign.bind(this), - eth_chainId: this.eth_chainId.bind(this) + eth_chainId: this.eth_chainId.bind(this), + eth_signTypedData: this.eth_signTypedData.bind(this), + eth_signTypedData_v4: this.eth_signTypedData_v4.bind(this) } } @@ -108,4 +116,53 @@ export class Web3Accounts { eth_chainId (_payload, cb) { return cb(null, '0x539') // 0x539 is hex of 1337 } + + eth_signTypedData (payload, cb) { + this.eth_signTypedData_v4(payload, cb) + } + + eth_signTypedData_v4 (payload, cb) { + const address: string = payload.params[0] + const typedData: TypedMessage = payload.params[1] + + try { + if (this.accounts[toChecksumAddress(address)] == null) { + throw new Error("cannot sign data; no private key"); + } + + if (typeof typedData === "string") { + throw new Error("cannot sign data; string sent, expected object"); + } + + if (!typedData.types) { + throw new Error("cannot sign data; types missing"); + } + + if (!typedData.types.EIP712Domain) { + throw new Error("cannot sign data; EIP712Domain definition missing"); + } + + if (!typedData.domain) { + throw new Error("cannot sign data; domain missing"); + } + + if (!typedData.primaryType) { + throw new Error("cannot sign data; primaryType missing"); + } + + if (!typedData.message) { + throw new Error("cannot sign data; message missing"); + } + + const ret = signTypedData({ + privateKey: Buffer.from(this.accounts[toChecksumAddress(address)].privateKey), + data: typedData, + version: SignTypedDataVersion.V4 + }) + + cb(null, ret) + } catch (e) { + cb(e.message) + } + } } diff --git a/libs/remix-simulator/src/provider.ts b/libs/remix-simulator/src/provider.ts index 27918a4359..3e56a2e4e7 100644 --- a/libs/remix-simulator/src/provider.ts +++ b/libs/remix-simulator/src/provider.ts @@ -11,7 +11,6 @@ import { Transactions } from './methods/transactions' import { Debug } from './methods/debug' import { VMContext } from './vm-context' import { Web3PluginBase } from 'web3' -import { Block } from '@ethereumjs/block' export interface JSONRPCRequestPayload { params: any[]; diff --git a/libs/remix-simulator/test/accounts.ts b/libs/remix-simulator/test/accounts.ts index cb923e209a..8d435b1808 100644 --- a/libs/remix-simulator/test/accounts.ts +++ b/libs/remix-simulator/test/accounts.ts @@ -39,4 +39,42 @@ describe('Accounts', () => { assert.deepEqual(typeof signature === 'string' ? signature.length : signature.signature.length, 132) }) }) + + describe('eth_signTypedData', () => { + it('should sign typed data', async () => { + const accounts: string[] = await web3.eth.getAccounts() + const typedData = { + domain: { + chainId: 1, + name: "Example App", + verifyingContract: "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC", + version: "1", + }, + message: { + prompt: "Welcome! In order to authenticate to this website, sign this request and your public address will be sent to the server in a verifiable way.", + createdAt: `${Date.now()}`, + }, + primaryType: 'AuthRequest', + types: { + EIP712Domain: [ + { name: 'name', type: 'string' }, + { name: 'version', type: 'string' }, + { name: 'chainId', type: 'uint256' }, + { name: 'verifyingContract', type: 'address' }, + ], + AuthRequest: [ + { name: 'prompt', type: 'string' }, + { name: 'createdAt', type: 'uint256' }, + ], + }, + }; + web3.currentProvider.sendAsync({ + method: 'eth_signTypedData', + params: [accounts[0], typedData] + }, function (err, result) { + console.log(err, result) + assert.equal(result.result, '0xe4ee76332af49888d86a09eea70dfd5b9a7085e2e013cbba4c0cb41766eab69a6216f18b80d9277241ce35b74b6c46add36d5189eb5a94a258f076dfc4dd21161b') + }) + }) + }) }) diff --git a/package.json b/package.json index 4de5d00c80..e49a728d3c 100644 --- a/package.json +++ b/package.json @@ -100,6 +100,7 @@ "@floating-ui/react": "^0.26.15", "@gradio/client": "^0.10.1", "@isomorphic-git/lightning-fs": "^4.4.1", + "@metamask/eth-sig-util": "^7.0.2", "@microlink/react-json-view": "^1.23.0", "@openzeppelin/contracts": "^5.0.0", "@openzeppelin/upgrades-core": "^1.30.0", @@ -364,6 +365,7 @@ "webpack-cli": "^4.10.0" }, "resolutions": { + "@metamask/eth-sig-util/@ethereumjs/util": "^8.1.0", "@types/react": "^18.2.0", "@ethereumjs/blockchain": "7.2.0", "@ethereumjs/block": "5.2.0", diff --git a/yarn.lock b/yarn.lock index 0a9d3258c2..c5ea40bc83 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2379,6 +2379,15 @@ "@ethereumjs/rlp" "^5.0.2" ethereum-cryptography "^2.1.3" +"@ethereumjs/util@^8.1.0": + version "8.1.0" + resolved "https://registry.yarnpkg.com/@ethereumjs/util/-/util-8.1.0.tgz#299df97fb6b034e0577ce9f94c7d9d1004409ed4" + integrity sha512-zQ0IqbdX8FZ9aw11vP+dZkKDkS+kgIvQPHnSAXzP9pLu+Rfu3D3XEeLbicvoXJTYnhZiPmsZUxgdzXwNKxRPbA== + dependencies: + "@ethereumjs/rlp" "^4.0.1" + ethereum-cryptography "^2.0.0" + micro-ftch "^0.3.1" + "@ethereumjs/verkle@^0.0.2": version "0.0.2" resolved "https://registry.yarnpkg.com/@ethereumjs/verkle/-/verkle-0.0.2.tgz#1c3c3d23e859e15b61c3d60a125962e761f3e135" @@ -4025,6 +4034,14 @@ dependencies: cross-spawn "^7.0.1" +"@metamask/abi-utils@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@metamask/abi-utils/-/abi-utils-2.0.2.tgz#ad394e9cb8a95ac177cad942daadd88a246c0de8" + integrity sha512-B/A1dY/w4F/t6cDHUscklO6ovb/ztFsrsTXFd8QlqSByk/vyy+QbPE3VVpmmyI/7RX+PA1AJcvBdzCIz+r9dVQ== + dependencies: + "@metamask/utils" "^8.0.0" + superstruct "^1.0.3" + "@metamask/eth-json-rpc-provider@^1.0.0": version "1.0.1" resolved "https://registry.yarnpkg.com/@metamask/eth-json-rpc-provider/-/eth-json-rpc-provider-1.0.1.tgz#3fd5316c767847f4ca107518b611b15396a5a32c" @@ -4045,6 +4062,18 @@ tweetnacl "^1.0.3" tweetnacl-util "^0.15.1" +"@metamask/eth-sig-util@^7.0.2": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@metamask/eth-sig-util/-/eth-sig-util-7.0.2.tgz#741de634b0d6ca96ce1ee3d064ac6a27756d8d21" + integrity sha512-DhTDMNEtED0ihIc4Tysm6qUJTvArCdgSTeeJWdo526W/cAk5mrSAvEYYgv8idAiBumDtcPWGimMTaB7MvY64bg== + dependencies: + "@ethereumjs/util" "^8.1.0" + "@metamask/abi-utils" "^2.0.2" + "@metamask/utils" "^8.1.0" + "@scure/base" "~1.1.3" + ethereum-cryptography "^2.1.2" + tweetnacl "^1.0.3" + "@metamask/json-rpc-engine@^7.0.0": version "7.3.2" resolved "https://registry.yarnpkg.com/@metamask/json-rpc-engine/-/json-rpc-engine-7.3.2.tgz#e8f0695811619eef7b7c894ba5cf782db9f1c2cb" @@ -4072,6 +4101,11 @@ resolved "https://registry.yarnpkg.com/@metamask/safe-event-emitter/-/safe-event-emitter-3.0.0.tgz#8c2b9073fe0722d48693143b0dc8448840daa3bd" integrity sha512-j6Z47VOmVyGMlnKXZmL0fyvWfEYtKWCA9yGZkU3FCsGZUT5lHGmvaV9JA5F2Y+010y7+ROtR3WMXIkvl/nVzqQ== +"@metamask/superstruct@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@metamask/superstruct/-/superstruct-3.0.0.tgz#0200d0a627522904a7e0fd751dcc6fb863cefacb" + integrity sha512-TOm+Lt/lCJk9j/3QT2LucrPewRmqI7/GKT+blK2IIOAkBMS+9TmeNjd2Y+TlfpSSYstaYsGZyz1XwpiTCg6RLA== + "@metamask/utils@^5.0.1": version "5.0.2" resolved "https://registry.yarnpkg.com/@metamask/utils/-/utils-5.0.2.tgz#140ba5061d90d9dac0280c19cab101bc18c8857c" @@ -4083,6 +4117,21 @@ semver "^7.3.8" superstruct "^1.0.3" +"@metamask/utils@^8.0.0": + version "8.5.0" + resolved "https://registry.yarnpkg.com/@metamask/utils/-/utils-8.5.0.tgz#ddd0d4012d5191809404c97648a837ea9962cceb" + integrity sha512-I6bkduevXb72TIM9q2LRO63JSsF9EXduh3sBr9oybNX2hNNpr/j1tEjXrsG0Uabm4MJ1xkGAQEMwifvKZIkyxQ== + dependencies: + "@ethereumjs/tx" "^4.2.0" + "@metamask/superstruct" "^3.0.0" + "@noble/hashes" "^1.3.1" + "@scure/base" "^1.1.3" + "@types/debug" "^4.1.7" + debug "^4.3.4" + pony-cause "^2.1.10" + semver "^7.5.4" + uuid "^9.0.1" + "@metamask/utils@^8.1.0", "@metamask/utils@^8.3.0": version "8.3.0" resolved "https://registry.yarnpkg.com/@metamask/utils/-/utils-8.3.0.tgz#a20de447aeb9ffb75924d822a186a597033984b6" @@ -4234,6 +4283,13 @@ dependencies: "@noble/hashes" "1.3.3" +"@noble/curves@1.4.0", "@noble/curves@~1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.4.0.tgz#f05771ef64da724997f69ee1261b2417a49522d6" + integrity sha512-p+4cb332SFCrReJkCYe8Xzm0OWi4Jji5jVdIZRL/PmacmDkFNw6MrrV+gGpiPxLHbV+zKFRywUWbaseT+tZRXg== + dependencies: + "@noble/hashes" "1.4.0" + "@noble/hashes@1.2.0", "@noble/hashes@~1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.2.0.tgz#a3150eeb09cc7ab207ebf6d7b9ad311a9bdbed12" @@ -4249,6 +4305,11 @@ resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.3.tgz#39908da56a4adc270147bb07968bf3b16cfe1699" integrity sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA== +"@noble/hashes@1.4.0", "@noble/hashes@~1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.4.0.tgz#45814aa329f30e4fe0ba49426f49dfccdd066426" + integrity sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg== + "@noble/secp256k1@1.7.1", "@noble/secp256k1@~1.7.0": version "1.7.1" resolved "https://registry.yarnpkg.com/@noble/secp256k1/-/secp256k1-1.7.1.tgz#b251c70f824ce3ca7f8dc3df08d58f005cc0507c" @@ -5575,6 +5636,11 @@ resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.1.tgz#ebb651ee52ff84f420097055f4bf46cfba403938" integrity sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA== +"@scure/base@~1.1.3", "@scure/base@~1.1.6": + version "1.1.6" + resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.6.tgz#8ce5d304b436e4c84f896e0550c83e4d88cb917d" + integrity sha512-ok9AWwhcgYuGG3Zfhyqg+zwl+Wn5uE+dwC0NV/2qQkx4dABbb/bx96vWu8NSj+BNjjSjno+JRYRjle1jV08k3g== + "@scure/bip32@1.1.5": version "1.1.5" resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.1.5.tgz#d2ccae16dcc2e75bc1d75f5ef3c66a338d1ba300" @@ -5602,6 +5668,15 @@ "@noble/hashes" "~1.3.2" "@scure/base" "~1.1.4" +"@scure/bip32@1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.4.0.tgz#4e1f1e196abedcef395b33b9674a042524e20d67" + integrity sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg== + dependencies: + "@noble/curves" "~1.4.0" + "@noble/hashes" "~1.4.0" + "@scure/base" "~1.1.6" + "@scure/bip39@1.1.1": version "1.1.1" resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.1.1.tgz#b54557b2e86214319405db819c4b6a370cf340c5" @@ -5626,6 +5701,14 @@ "@noble/hashes" "~1.3.2" "@scure/base" "~1.1.4" +"@scure/bip39@1.3.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.3.0.tgz#0f258c16823ddd00739461ac31398b4e7d6a18c3" + integrity sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ== + dependencies: + "@noble/hashes" "~1.4.0" + "@scure/base" "~1.1.6" + "@sentry/core@5.30.0": version "5.30.0" resolved "https://registry.yarnpkg.com/@sentry/core/-/core-5.30.0.tgz#6b203664f69e75106ee8b5a2fe1d717379b331f3" @@ -13744,6 +13827,16 @@ ethereum-cryptography@^2.0.0: "@scure/bip32" "1.3.0" "@scure/bip39" "1.2.0" +ethereum-cryptography@^2.1.2: + version "2.2.0" + resolved "https://registry.yarnpkg.com/ethereum-cryptography/-/ethereum-cryptography-2.2.0.tgz#06e2d9c0d89f98ffc6a83818f55bf85afecd50dc" + integrity sha512-hsm9JhfytIf8QME/3B7j4bc8V+VdTU+Vas1aJlvIS96ffoNAosudXvGoEvWmc7QZYdkC8mrMJz9r0fcbw7GyCA== + dependencies: + "@noble/curves" "1.4.0" + "@noble/hashes" "1.4.0" + "@scure/bip32" "1.4.0" + "@scure/bip39" "1.3.0" + ethereum-cryptography@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/ethereum-cryptography/-/ethereum-cryptography-2.1.3.tgz#1352270ed3b339fe25af5ceeadcf1b9c8e30768a" @@ -20235,6 +20328,11 @@ methods@~1.1.2: resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= +micro-ftch@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/micro-ftch/-/micro-ftch-0.3.1.tgz#6cb83388de4c1f279a034fb0cf96dfc050853c5f" + integrity sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg== + micromark-core-commonmark@^1.0.0, micromark-core-commonmark@^1.0.1: version "1.0.6" resolved "https://registry.yarnpkg.com/micromark-core-commonmark/-/micromark-core-commonmark-1.0.6.tgz#edff4c72e5993d93724a3c206970f5a15b0585ad" @@ -29076,6 +29174,11 @@ uuid@^8.3.2: resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== +uuid@^9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" + integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== + uvu@^0.5.0: version "0.5.6" resolved "https://registry.yarnpkg.com/uvu/-/uvu-0.5.6.tgz#2754ca20bcb0bb59b64e9985e84d2e81058502df"