Skip to content

Commit

Permalink
EIP 712
Browse files Browse the repository at this point in the history
  • Loading branch information
yann300 committed Oct 1, 2024
1 parent 2d3a46d commit 589a766
Show file tree
Hide file tree
Showing 16 changed files with 141 additions and 65 deletions.
4 changes: 3 additions & 1 deletion apps/remix-ide/src/app/tabs/locales/en/filePanel.json
Original file line number Diff line number Diff line change
Expand Up @@ -148,5 +148,7 @@
"filePanel.saveCodeSample": "This code-sample workspace will not be persisted. Click here to save it.",
"filePanel.logInGithub": "Sign in to GitHub.",
"filePanel.gitHubLoggedAs": "Signed in as {githubuser}",
"filePanel.updateSubmodules": "Update all submodules of repository. Click to pull dependencies."
"filePanel.updateSubmodules": "Update all submodules of repository. Click to pull dependencies.",
"filePanel.signTypedData": "Sign Typed Data",
"filePanel.signTypedDataError": "Error while signing this typed data."
}
7 changes: 6 additions & 1 deletion apps/remix-ide/src/app/tabs/locales/en/udapp.json
Original file line number Diff line number Diff line change
Expand Up @@ -161,5 +161,10 @@
"udapp.ganacheProviderText1": "Note: To run Ganache on your system, run:",
"udapp.ganacheProviderText2": "For more info, visit: <a>Ganache Documentation</a>",
"udapp.hardhatProviderText1": "Note: To run Hardhat network node on your system, go to hardhat project folder and run command:",
"udapp.hardhatProviderText2": "For more info, visit: <a>Hardhat Documentation</a>"
"udapp.hardhatProviderText2": "For more info, visit: <a>Hardhat Documentation</a>",
"udapp.EIP712-1": "Signing message now only supports EIP-712.",
"udapp.EIP712-2": "Please follow <a>this link</a> to get more information.",
"udapp.EIP712-3": "In Remix, signing typed data is possible by right clicking (right click / Sign Typed Data) on a JSON file whose content is EIP-712 compatible.",
"udapp.EIP712-create-template": "Create a JSON compliant with EIP-712",
"udapp.EIP712-close": "Close"
}
22 changes: 17 additions & 5 deletions apps/remix-ide/src/blockchain/providers/vm.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Web3, FMT_BYTES, FMT_NUMBER, LegacySendAsyncProvider } from 'web3'
import { Web3, FMT_BYTES, FMT_NUMBER, LegacySendAsyncProvider, LegacyRequestProvider } from 'web3'
import { fromWei, toBigInt } from 'web3-utils'
import { privateToAddress, hashPersonalMessage, isHexString, bytesToHex } from '@ethereumjs/util'
import { extend, JSONRPCRequestPayload, JSONRPCResponseCallback } from '@remix-project/remix-simulator'
Expand All @@ -10,6 +10,7 @@ export class VMProvider {
worker: Worker
provider: {
sendAsync: (query: JSONRPCRequestPayload, callback: JSONRPCResponseCallback) => void
request: (query: JSONRPCRequestPayload) => Promise<any>
}
newAccountCallback: {[stamp: number]: (error: Error, address: string) => void}
constructor (executionContext: ExecutionContext) {
Expand Down Expand Up @@ -38,14 +39,17 @@ export class VMProvider {
return new Promise((resolve, reject) => {
this.worker.addEventListener('message', (msg) => {
if (msg.data.cmd === 'sendAsyncResult' && stamps[msg.data.stamp]) {
let result = msg.data.result
if (stamps[msg.data.stamp].request && msg.data.result) result = msg.data.result.result

if (stamps[msg.data.stamp].callback) {
stamps[msg.data.stamp].callback(msg.data.error, msg.data.result)
stamps[msg.data.stamp].callback(msg.data.error, result)
return
}
if (msg.data.error) {
stamps[msg.data.stamp].reject(msg.data.error)
} else {
stamps[msg.data.stamp].resolve(msg.data.result)
stamps[msg.data.stamp].resolve(result)
}
} else if (msg.data.cmd === 'initiateResult') {
if (!msg.data.error) {
Expand All @@ -54,12 +58,20 @@ export class VMProvider {
return new Promise((resolve, reject) => {
const stamp = Date.now() + incr
incr++
stamps[stamp] = { callback, resolve, reject }
stamps[stamp] = { callback, resolve, reject, sendAsync: true }
this.worker.postMessage({ cmd: 'sendAsync', query, stamp })
})
},
request: (query) => {
return new Promise((resolve, reject) => {
const stamp = Date.now() + incr
incr++
stamps[stamp] = { resolve, reject, request: true }
this.worker.postMessage({ cmd: 'sendAsync', query, stamp })
})
}
}
this.web3 = new Web3(this.provider as LegacySendAsyncProvider)
this.web3 = new Web3(this.provider as (LegacySendAsyncProvider | LegacyRequestProvider))
this.web3.setConfig({ defaultTransactionType: '0x0' })
extend(this.web3)
this.executionContext.setWeb3(this.executionContext.getProvider(), this.web3)
Expand Down
5 changes: 5 additions & 0 deletions libs/remix-ui/run-tab/src/lib/actions/account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,3 +95,8 @@ export const signMessageWithAddress = (plugin: RunTab, dispatch: React.Dispatch<
dispatch(displayNotification('Signed Message', modalContent(msgHash, signedData), 'OK', null, () => {}, null))
})
}

export const addFileInternal = async (plugin: RunTab, path: string, content: string) => {
const file = await plugin.call('fileManager', 'writeFileNoRewrite', path, content)
await plugin.call('fileManager', 'open', file.newPath)
}
3 changes: 2 additions & 1 deletion libs/remix-ui/run-tab/src/lib/actions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import React from 'react'
import { RunTab } from '../types/run-tab'
import { resetAndInit, setupEvents, setEventsDispatch } from './events'
import { createNewBlockchainAccount, setExecutionContext, signMessageWithAddress } from './account'
import { createNewBlockchainAccount, setExecutionContext, signMessageWithAddress, addFileInternal } from './account'
import { clearInstances, clearPopUp, removeInstance, pinInstance, unpinInstance, setAccount, setGasFee, setMatchPassphrasePrompt,
setNetworkNameFromProvider, setPassphrasePrompt, setSelectedContract, setSendTransactionValue, setUnit,
updateBaseFeePerGas, updateConfirmSettings, updateGasPrice, updateGasPriceStatus, updateMaxFee, updateMaxPriorityFee, updateScenarioPath } from './actions'
Expand Down Expand Up @@ -32,6 +32,7 @@ export const initRunTab = (udapp: RunTab, resetEventsAndAccounts: boolean) => as
}
}

export const addFile = (path: string, content: string) => addFileInternal(plugin, path, content)
export const setAccountAddress = (account: string) => setAccount(dispatch, account)
export const setUnitValue = (unit: 'ether' | 'finney' | 'gwei' | 'wei') => setUnit(dispatch, unit)
export const setGasFeeAmount = (value: number) => setGasFee(dispatch, value)
Expand Down
94 changes: 41 additions & 53 deletions libs/remix-ui/run-tab/src/lib/components/account.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,41 +100,22 @@ export function AccountUI(props: AccountProps) {
return props.tooltip(intl.formatMessage({ id: 'udapp.tooltipText1' }))
}

if (selectExEnv === 'web3') {
return props.modal(
intl.formatMessage({ id: 'udapp.modalTitle1' }),
<PassphrasePrompt message={intl.formatMessage({ id: 'udapp.modalMessage1' })} setPassphrase={props.setPassphrase} />,
intl.formatMessage({ id: 'udapp.ok' }),
() => {
props.modal(
intl.formatMessage({ id: 'udapp.signAMessage' }),
signMessagePrompt(),
intl.formatMessage({ id: 'udapp.ok' }),
() => {
props.signMessageWithAddress(selectedAccount, messageRef.current, signedMessagePrompt, props.passphrase)
props.setPassphrase('')
},
intl.formatMessage({ id: 'udapp.cancel' }),
null
)
},
intl.formatMessage({ id: 'udapp.cancel' }),
() => {
props.setPassphrase('')
}
)
}

props.modal(
intl.formatMessage({ id: 'udapp.signAMessage' }),
signMessagePrompt(),
intl.formatMessage({ id: 'udapp.ok' }),
() => {
props.signMessageWithAddress(selectedAccount, messageRef.current, signedMessagePrompt)
},
intl.formatMessage({ id: 'udapp.cancel' }),
null
)
'Message signing',
<div>
<div>{intl.formatMessage({ id: 'udapp.EIP712-1' })}</div>
<div>{intl.formatMessage({ id: 'udapp.EIP712-2' }, {
a: (chunks) => (
<a href='https://eips.ethereum.org/EIPS/eip-712' target="_blank" rel="noreferrer">
{chunks}
</a>
)
})}</div>
<div>{intl.formatMessage({ id: 'udapp.EIP712-3' })}</div></div>,
intl.formatMessage({ id: 'udapp.EIP712-create-template' }),
() => { props.addFile('EIP-712-data.json', JSON.stringify(EIP712_Example, null, '\t')) },
intl.formatMessage({ id: 'udapp.EIP712-close' }),
() => {})
}

const handlePassphrase = (e) => {
Expand Down Expand Up @@ -177,25 +158,6 @@ export function AccountUI(props: AccountProps) {
)
}

const signedMessagePrompt = (msgHash: string, signedData: string) => {
return (
<div className="d-flex flex-column">
<label className="text-uppercase">
<FormattedMessage id="udapp.hash" />
</label>
<span id="remixRunSignMsgHash" data-id="settingsRemixRunSignMsgHash">
{msgHash}
</span>
<label className="pt-2 text-uppercase">
<FormattedMessage id="udapp.signature" />
</label>
<span id="remixRunSignMsgSignature" data-id="settingsRemixRunSignMsgSignature">
{signedData}
</span>
</div>
)
}

return (
<div className="udapp_crow">
<label className="udapp_settingsLabel">
Expand Down Expand Up @@ -234,3 +196,29 @@ export function AccountUI(props: AccountProps) {
</div>
)
}

const EIP712_Example = {
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: 1718570375196,
},
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' },
],
},
}
1 change: 1 addition & 0 deletions libs/remix-ui/run-tab/src/lib/components/settingsUI.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export function SettingsUI(props: SettingsProps) {
<EnvironmentUI selectedEnv={props.selectExEnv} providers={props.providers} setExecutionContext={props.setExecutionContext} />
<NetworkUI networkName={props.networkName} />
<AccountUI
addFile={props.addFile}
personalMode={props.personalMode}
selectExEnv={props.selectExEnv}
accounts={props.accounts}
Expand Down
4 changes: 3 additions & 1 deletion libs/remix-ui/run-tab/src/lib/run-tab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ import {
updateSelectedContract,
syncContracts,
isValidProxyAddress,
isValidProxyUpgrade
isValidProxyUpgrade,
addFile
} from './actions'
import './css/run-tab.css'
import { PublishToStorage } from '@remix-ui/publish-to-storage'
Expand Down Expand Up @@ -280,6 +281,7 @@ export function RunTabUI(props: RunTabProps) {
<div className="udapp_runTabView run-tab" id="runTabView" data-id="runTabView">
<div className="list-group pb-4 list-group-flush">
<SettingsUI
addFile={addFile}
networkName={runTab.networkName}
personalMode={runTab.personalMode}
selectExEnv={runTab.selectExEnv}
Expand Down
2 changes: 2 additions & 0 deletions libs/remix-ui/run-tab/src/lib/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ export interface SettingsProps {
isSuccessful: boolean,
error: string
},
addFile: (path: string, content: string) => void,
setExecutionContext: (executionContext: { context: string, fork: string }) => void,
createNewBlockchainAccount: (cbMessage: JSX.Element) => void,
setPassphrase: (passphrase: string) => void,
Expand Down Expand Up @@ -180,6 +181,7 @@ export interface AccountProps {
isSuccessful: boolean,
error: string
},
addFile: (path: string, content: string) => void,
setAccount: (account: string) => void,
personalMode: boolean,
createNewBlockchainAccount: (cbMessage: JSX.Element) => void,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@ import { fetchContractFromEtherscan, fetchContractFromBlockscout } from '@remix-
import JSZip from 'jszip'
import { Actions, FileTree } from '../types'
import IpfsHttpClient from 'ipfs-http-client'
import { AppModal } from '@remix-ui/app'
import { MessageWrapper } from '../components/file-explorer'
import { AppModal, ModalTypes } from '@remix-ui/app'

export * from './events'
export * from './workspace'
Expand Down Expand Up @@ -510,6 +509,33 @@ export const runScript = async (path: string) => {
})
}

export const signTypedData = async (path: string) => {
const typedData = await plugin.call('fileManager', 'readFile', path)
const web3 = await plugin.call('blockchain', 'web3')
const accounts = await web3.eth.getAccounts()

let parsed
try {
parsed = JSON.parse(typedData)
} catch (err) {
dispatch(displayPopUp(`${path} isn't a valid JSON.`))
return
}

try {
const result = await web3.currentProvider.request({
method: 'eth_signTypedData',
params: [accounts[0], parsed]
})

plugin.call('terminal', 'log', { type: 'log', value: `${path} signature : ${result}` })
} catch (e) {
console.error(e)
plugin.call('terminal', 'log', { type: 'error', value: `error while signing ${path}: ${e}` })
dispatch(displayPopUp(e.message))
}
}

export const emitContextMenuEvent = async (cmd: customAction) => {
await plugin.call(cmd.id, cmd.name, cmd)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export const FileExplorerContextMenu = (props: FileExplorerContextMenuProps) =>
downloadPath,
uploadFile,
publishManyFilesToGist,
signTypedData,
...otherProps
} = props
const contextMenuRef = useRef(null)
Expand Down Expand Up @@ -233,7 +234,11 @@ export const FileExplorerContextMenu = (props: FileExplorerContextMenuProps) =>
case 'Publish Workspace to Gist':
_paq.push(['trackEvent', 'fileExplorer', 'contextMenu', 'publishWorkspace'])
publishFolderToGist(path)
break
break
case 'Sign Typed Data':
_paq.push(['trackEvent', 'fileExplorer', 'contextMenu', 'signTypedData'])
signTypedData(path)
break
default:
_paq.push(['trackEvent', 'fileExplorer', 'contextMenu', `${item.id}/${item.name}`])
emit && emit({ ...item, path: [path]} as customAction)
Expand Down
1 change: 1 addition & 0 deletions libs/remix-ui/workspace/src/lib/contexts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export const FileSystemContext = createContext<{
dispatchCopyShareURL: (path: string) => Promise<void>,
dispatchCopyFolder: (src: string, dest: string) => Promise<void>,
dispatchRunScript: (path: string) => Promise<void>,
dispatchSignTypedData: (path: string) => Promise<void>,
dispatchEmitContextMenuEvent: (cmd: customAction) => Promise<void>,
dispatchHandleClickFile: (path: string, type: 'file' | 'folder' ) => Promise<void>
dispatchHandleExpandPath: (paths: string[]) => Promise<void>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
copyShareURL,
copyFolder,
runScript,
signTypedData,
emitContextMenuEvent,
handleClickFile,
handleExpandPath,
Expand Down Expand Up @@ -171,6 +172,10 @@ export const FileSystemProvider = (props: WorkspaceProps) => {
await runScript(path)
}

const dispatchSignTypedData = async (path: string) => {
await signTypedData(path)
}

const dispatchEmitContextMenuEvent = async (cmd: customAction) => {
await emitContextMenuEvent(cmd)
}
Expand Down Expand Up @@ -358,6 +363,7 @@ export const FileSystemProvider = (props: WorkspaceProps) => {
dispatchCopyShareURL,
dispatchCopyFolder,
dispatchRunScript,
dispatchSignTypedData,
dispatchEmitContextMenuEvent,
dispatchHandleClickFile,
dispatchHandleExpandPath,
Expand Down
11 changes: 11 additions & 0 deletions libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -706,6 +706,14 @@ export function Workspace() {
}
}

const signTypedData = async (path: string) => {
try {
global.dispatchSignTypedData(path)
} catch (error) {
global.toast(intl.formatMessage({ id: 'filePanel.signTypedDataError' }))
}
}

const emitContextMenuEvent = (cmd: customAction) => {
try {
global.dispatchEmitContextMenuEvent(cmd)
Expand Down Expand Up @@ -1135,6 +1143,7 @@ export function Workspace() {
dispatchCopyFolder={global.dispatchCopyFolder}
dispatchPublishToGist={global.dispatchPublishToGist}
dispatchRunScript={global.dispatchRunScript}
dispatchSignTypedData={global.dispatchSignTypedData}
dispatchEmitContextMenuEvent={global.dispatchEmitContextMenuEvent}
dispatchHandleClickFile={global.dispatchHandleClickFile}
dispatchSetFocusElement={global.dispatchSetFocusElement}
Expand Down Expand Up @@ -1211,6 +1220,7 @@ export function Workspace() {
dispatchCopyFolder={global.dispatchCopyFolder}
dispatchPublishToGist={global.dispatchPublishToGist}
dispatchRunScript={global.dispatchRunScript}
dispatchSignTypedData={global.dispatchSignTypedData} //
dispatchEmitContextMenuEvent={global.dispatchEmitContextMenuEvent}
dispatchHandleClickFile={global.dispatchHandleClickFile}
dispatchSetFocusElement={global.dispatchSetFocusElement}
Expand Down Expand Up @@ -1385,6 +1395,7 @@ export function Workspace() {
deletePath={deletePath}
renamePath={editModeOn}
runScript={runScript}
signTypedData={signTypedData}
copy={handleCopyClick}
paste={handlePasteClick}
copyFileName={handleCopyFileNameClick}
Expand Down
Loading

0 comments on commit 589a766

Please sign in to comment.