Merge branch 'master' of https://github.com/ethereum/remix-project into git4refactor2

pull/4791/head
Your Name 5 months ago
commit c5915b0ad6
  1. 10
      apps/remix-ide-e2e/src/tests/url.test.ts
  2. 9
      apps/remix-ide/src/app/tabs/locales/en/udapp.json
  3. 1
      apps/remix-ide/src/assets/css/themes/remix-dark_tvx1s2.css
  4. 3
      libs/remix-ui/app/src/lib/remix-app/context/provider.tsx
  5. 1
      libs/remix-ui/app/src/lib/remix-app/interface/index.ts
  6. 1
      libs/remix-ui/app/src/lib/remix-app/reducer/modals.ts
  7. 2
      libs/remix-ui/modal-dialog/src/lib/remix-ui-modal-dialog.tsx
  8. 1
      libs/remix-ui/modal-dialog/src/lib/types/index.ts
  9. 46
      libs/remix-ui/run-tab/src/lib/components/solScanTable.tsx
  10. 111
      libs/remix-ui/run-tab/src/lib/components/universalDappUI.tsx
  11. 5
      libs/remix-ui/run-tab/src/lib/css/run-tab.css
  12. 5
      libs/remix-ui/workspace/src/lib/actions/index.ts

@ -97,9 +97,19 @@ module.exports = {
.refreshPage() .refreshPage()
.pause(7000) .pause(7000)
.currentWorkspaceIs('code-sample') .currentWorkspaceIs('code-sample')
.waitForElementVisible('*[data-id=treeViewLitreeViewItemsepolia]')
.waitForElementVisible('*[data-id="treeViewLitreeViewItemsepolia/0xdac17f958d2ee523a2206206994597c13d831ec7/contracts/MetaMultiSigWallet.sol"]')
.getEditorValue((content) => {
browser.assert.ok(content && content.indexOf(
'contract MetaMultiSigWallet {') !== -1)
})
.waitForElementVisible('*[data-id=treeViewLitreeViewItemmainnet]') .waitForElementVisible('*[data-id=treeViewLitreeViewItemmainnet]')
.click('*[data-id=treeViewLitreeViewItemmainnet]')
.waitForElementVisible('*[data-id="treeViewLitreeViewItemmainnet/0xdac17f958d2ee523a2206206994597c13d831ec7"]') .waitForElementVisible('*[data-id="treeViewLitreeViewItemmainnet/0xdac17f958d2ee523a2206206994597c13d831ec7"]')
.click('*[data-id="treeViewLitreeViewItemmainnet/0xdac17f958d2ee523a2206206994597c13d831ec7"]')
.waitForElementVisible('*[data-id="treeViewLitreeViewItemmainnet/0xdac17f958d2ee523a2206206994597c13d831ec7/TetherToken.sol"]') .waitForElementVisible('*[data-id="treeViewLitreeViewItemmainnet/0xdac17f958d2ee523a2206206994597c13d831ec7/TetherToken.sol"]')
.click('*[data-id="treeViewLitreeViewItemmainnet/0xdac17f958d2ee523a2206206994597c13d831ec7/TetherToken.sol"]')
.getEditorValue((content) => { .getEditorValue((content) => {
browser.assert.ok(content && content.indexOf( browser.assert.ok(content && content.indexOf(
'contract TetherToken is Pausable, StandardToken, BlackList {') !== -1) 'contract TetherToken is Pausable, StandardToken, BlackList {') !== -1)

@ -80,6 +80,15 @@
"udapp.pinnedAt": "Pinned at", "udapp.pinnedAt": "Pinned at",
"udapp.filePath": "File path", "udapp.filePath": "File path",
"udapp.solScan.iconTooltip": "Click to scan this contract for vulnerabilities using third-party SolidityScan [BETA]",
"udapp.solScan.modalTitle": "Permission to share code",
"udapp.solScan.modalMessage": "To scan the contract for vulnerabilities & possible risks, smart contract code will be shared to third-party SolidityScan (https://solidityscan.com/).\n\n Would you like to continue?",
"udapp.solScan.modalOkLabel": "Continue",
"udapp.solScan.modalCancelLabel": "Cancel",
"udapp.solScan.errModalTitle": "Scan error",
"udapp.solScan.successModalTitle": "Scan result",
"udapp._comment_recorderCardUI.tsx": "libs/remix-ui/run-tab/src/lib/components/recorderCardUI.tsx", "udapp._comment_recorderCardUI.tsx": "libs/remix-ui/run-tab/src/lib/components/recorderCardUI.tsx",
"udapp.transactionsRecorded": "Transactions recorded", "udapp.transactionsRecorded": "Transactions recorded",
"udapp.transactionsCountTooltip": "The number of recorded transactions", "udapp.transactionsCountTooltip": "The number of recorded transactions",

@ -25,6 +25,7 @@
--text-background: #222336; --text-background: #222336;
--text-bg-mark: #8388b2; --text-bg-mark: #8388b2;
--custom-select: #35384c; --custom-select: #35384c;
--runtab: #8A93B0;
--body-bg: #222336; --body-bg: #222336;
--breakpoint-xs: 0; --breakpoint-xs: 0;
--breakpoint-sm: 576px; --breakpoint-sm: 576px;

@ -23,7 +23,7 @@ export const ModalProvider = ({ children = [], reducer = modalReducer, initialSt
} }
const modal = (modalData: AppModal) => { const modal = (modalData: AppModal) => {
const { id, title, message, validationFn, okLabel, okFn, cancelLabel, cancelFn, modalType, defaultValue, hideFn, data } = modalData const { id, title, message, validationFn, okLabel, okFn, cancelLabel, cancelFn, modalType, modalParentClass, defaultValue, hideFn, data } = modalData
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
dispatch({ dispatch({
type: modalActionTypes.setModal, type: modalActionTypes.setModal,
@ -37,6 +37,7 @@ export const ModalProvider = ({ children = [], reducer = modalReducer, initialSt
cancelLabel, cancelLabel,
cancelFn, cancelFn,
modalType: modalType || ModalTypes.default, modalType: modalType || ModalTypes.default,
modalParentClass,
defaultValue: defaultValue, defaultValue: defaultValue,
hideFn, hideFn,
resolve, resolve,

@ -18,6 +18,7 @@ export interface AppModal {
cancelLabel?: string | JSX.Element cancelLabel?: string | JSX.Element
cancelFn?: () => void, cancelFn?: () => void,
modalType?: ModalTypes, modalType?: ModalTypes,
modalParentClass?: string
defaultValue?: string defaultValue?: string
hideFn?: () => void, hideFn?: () => void,
resolve?: (value?:any) => void, resolve?: (value?:any) => void,

@ -18,6 +18,7 @@ export const modalReducer = (state: ModalState = ModalInitialState, action: Moda
cancelLabel: action.payload.cancelLabel, cancelLabel: action.payload.cancelLabel,
cancelFn: action.payload.cancelFn, cancelFn: action.payload.cancelFn,
modalType: action.payload.modalType, modalType: action.payload.modalType,
modalParentClass: action.payload.modalParentClass,
defaultValue: action.payload.defaultValue, defaultValue: action.payload.defaultValue,
hideFn: action.payload.hideFn, hideFn: action.payload.hideFn,
resolve: action.payload.resolve, resolve: action.payload.resolve,

@ -85,7 +85,7 @@ export const ModalDialog = (props: ModalDialogProps) => {
style={{ display: props.hide ? 'none' : 'block' }} style={{ display: props.hide ? 'none' : 'block' }}
role="dialog" role="dialog"
> >
<div className="modal-dialog" role="document"> <div className={'modal-dialog ' + (props.modalParentClass ? props.modalParentClass : '')} role="document">
<div <div
ref={modal} ref={modal}
tabIndex={-1} tabIndex={-1}

@ -17,6 +17,7 @@ export interface ModalDialogProps {
cancelLabel?: string | JSX.Element, cancelLabel?: string | JSX.Element,
cancelFn?: () => void, cancelFn?: () => void,
modalClass?: string, modalClass?: string,
modalParentClass?: string
showCancelIcon?: boolean, showCancelIcon?: boolean,
hide?: boolean, hide?: boolean,
handleHide: (hideState?: boolean) => void, handleHide: (hideState?: boolean) => void,

@ -0,0 +1,46 @@
// eslint-disable-next-line no-use-before-define
import React from 'react'
import parse from 'html-react-parser';
interface SolScanTableProps {
scanDetails: Record<string, any>[],
fileName: string
}
export function SolScanTable(props: SolScanTableProps) {
const { scanDetails, fileName } = props
return (
<>
<p>Scanning successful! <b>{scanDetails.length} warnings </b> found for file: <b>{fileName}</b></p>
<p>See the warning details below. For more details, <a href="https://solidityscan.com/signup" target='blank'>Go to SolidityScan</a></p>
<table className="table table-bordered table-hover">
<thead>
<tr>
<td scope="col" style={{ wordBreak: "keep-all" }}>NAME</td>
<td scope="col" style={{ wordBreak: "keep-all" }}>SEVERITY</td>
<td scope="col" style={{ wordBreak: "keep-all" }}>CONFIDENCE</td>
<td scope="col" style={{ wordBreak: "keep-all" }}>DESCRIPTION</td>
<td scope="col" style={{ wordBreak: "keep-all" }}>REMEDIATION</td>
</tr>
</thead>
<tbody>
{
Array.from(scanDetails, (template) => {
return (
<tr key={template.template_details.issue_id}>
<td scope="col">{template.template_details.issue_name}</td>
<td scope="col">{template.template_details.issue_severity}</td>
<td scope="col">{template.template_details.issue_confidence}</td>
<td scope="col">{parse(template.template_details.static_issue_description)}</td>
<td scope="col">{template.template_details.issue_remediation ? parse(template.template_details.issue_remediation) : 'Not Available' }</td>
</tr>
)
})
}
</tbody>
</table>
</>
)
}

@ -6,7 +6,10 @@ import { FuncABI } from '@remix-project/core-plugin'
import { CopyToClipboard } from '@remix-ui/clipboard' import { CopyToClipboard } from '@remix-ui/clipboard'
import * as remixLib from '@remix-project/remix-lib' import * as remixLib from '@remix-project/remix-lib'
import * as ethJSUtil from '@ethereumjs/util' import * as ethJSUtil from '@ethereumjs/util'
import axios from 'axios'
import { AppModal } from '@remix-ui/app'
import { ContractGUI } from './contractGUI' import { ContractGUI } from './contractGUI'
import { SolScanTable } from './solScanTable'
import { TreeView, TreeViewItem } from '@remix-ui/tree-view' import { TreeView, TreeViewItem } from '@remix-ui/tree-view'
import { BN } from 'bn.js' import { BN } from 'bn.js'
import { CustomTooltip, is0XPrefixed, isHexadecimal, isNumeric, shortenAddress } from '@remix-ui/helper' import { CustomTooltip, is0XPrefixed, isHexadecimal, isNumeric, shortenAddress } from '@remix-ui/helper'
@ -217,6 +220,100 @@ export function UniversalDappUI(props: UdappProps) {
setCalldataValue(value) setCalldataValue(value)
} }
const handleScanContinue = async () => {
await props.plugin.call('notification', 'toast', 'Processing data to scan...')
_paq.push(['trackEvent', 'udapp', 'solidityScan', 'initiateScan'])
const workspace = await props.plugin.call('filePanel', 'getCurrentWorkspace')
const fileName = props.instance.filePath || `${workspace.name}/${props.instance.contractData.contract.file}`
const filePath = `.workspaces/${fileName}`
const file = await props.plugin.call('fileManager', 'readFile', filePath)
const urlResponse = await axios.post(`https://solidityscan.remixproject.org/uploadFile`, { file, fileName })
if (urlResponse.data.status === 'success') {
const ws = new WebSocket('wss://solidityscan.remixproject.org/solidityscan')
ws.addEventListener('error', console.error);
ws.addEventListener('open', async (event) => {
await props.plugin.call('notification', 'toast', 'Initiating scan...')
})
ws.addEventListener('message', async (event) => {
const data = JSON.parse(event.data)
if (data.type === "auth_token_register" && data.payload.message === "Auth token registered.") {
// Message on Bearer token successful registration
const reqToInitScan = {
"action": "message",
"payload": {
"type": "private_project_scan_initiate",
"body": {
"file_urls": [
urlResponse.data.result.url
],
"project_name": "RemixProject",
"project_type": "new"
}
}
}
ws.send(JSON.stringify(reqToInitScan))
} else if (data.type === "scan_status" && data.payload.scan_status === "download_failed") {
// Message on failed scan
_paq.push(['trackEvent', 'udapp', 'solidityScan', 'scanFailed'])
const modal: AppModal = {
id: 'SolidityScanError',
title: <FormattedMessage id="udapp.solScan.errModalTitle" />,
message: data.payload.scan_status_err_message,
okLabel: 'Close'
}
await props.plugin.call('notification', 'modal', modal)
} else if (data.type === "scan_status" && data.payload.scan_status === "scan_done") {
// Message on successful scan
_paq.push(['trackEvent', 'udapp', 'solidityScan', 'scanSuccess'])
const url = data.payload.scan_details.link
const { data: scanData } = await axios.post('https://solidityscan.remixproject.org/downloadResult', { url })
const scanDetails: Record<string, any>[] = scanData.scan_report.multi_file_scan_details
let modal: AppModal
if (scanDetails && scanDetails.length) {
modal = {
id: 'SolidityScanSuccess',
title: <FormattedMessage id="udapp.solScan.successModalTitle" />,
message: <SolScanTable scanDetails={scanDetails} fileName={fileName}/>,
okLabel: 'Close',
modalParentClass: 'modal-xl'
}
} else {
modal = {
id: 'SolidityScanError',
title: <FormattedMessage id="udapp.solScan.errModalTitle" />,
message: "Some error occurred! Please try again",
okLabel: 'Close'
}
}
await props.plugin.call('notification', 'modal', modal)
}
})
}
}
const askPermissionToScan = async () => {
_paq.push(['trackEvent', 'udapp', 'solidityScan', 'askPermissionToScan'])
const modal: AppModal = {
id: 'SolidityScanPermissionHandler',
title: <FormattedMessage id="udapp.solScan.modalTitle" />,
message: <FormattedMessage id="udapp.solScan.modalMessage" />,
okLabel: <FormattedMessage id="udapp.solScan.modalOkLabel" />,
okFn: handleScanContinue,
cancelLabel: <FormattedMessage id="udapp.solScan.modalCancelLabel" />
}
await props.plugin.call('notification', 'modal', modal)
}
const label = (key: string | number, value: string) => { const label = (key: string | number, value: string) => {
return ( return (
<div className="d-flex mt-2 flex-row label_item"> <div className="d-flex mt-2 flex-row label_item">
@ -293,20 +390,26 @@ export function UniversalDappUI(props: UdappProps) {
</div> </div>
<div className="udapp_cActionsWrapper" data-id="universalDappUiContractActionWrapper"> <div className="udapp_cActionsWrapper" data-id="universalDappUiContractActionWrapper">
<div className="udapp_contractActionsContainer"> <div className="udapp_contractActionsContainer">
<div className="d-flex justify-content-between" data-id="instanceContractBal"> <div className="d-flex flex-row justify-content-between align-items-center pb-2" data-id="instanceContractBal">
<label> <span className="remixui_runtabBalancelabel run-tab">
<b><FormattedMessage id="udapp.balance" />:</b> {instanceBalance} ETH <b><FormattedMessage id="udapp.balance" />:</b> {instanceBalance} ETH
</label> </span>
<div></div>
<div className="d-flex align-self-center">
{props.exEnvironment && props.exEnvironment.startsWith('injected') && ( {props.exEnvironment && props.exEnvironment.startsWith('injected') && (
<CustomTooltip placement="top" tooltipClasses="text-nowrap" tooltipId="udapp_udappEditTooltip" tooltipText={<FormattedMessage id="udapp.tooltipTextEdit" />}> <CustomTooltip placement="top" tooltipClasses="text-nowrap" tooltipId="udapp_udappEditTooltip" tooltipText={<FormattedMessage id="udapp.tooltipTextEdit" />}>
<i <i
className="fas fa-edit btn btn-sm p-0" className="fas fa-edit pr-3"
onClick={() => { onClick={() => {
props.editInstance(props.instance) props.editInstance(props.instance)
}} }}
></i> ></i>
</CustomTooltip> </CustomTooltip>
)} )}
<CustomTooltip placement="top" tooltipClasses="text-nowrap" tooltipId="udapp_udappSolScanTooltip" tooltipText={<FormattedMessage id="udapp.solScan.iconTooltip" />}>
<i className="fas fa-qrcode p-0" onClick={askPermissionToScan}></i>
</CustomTooltip>
</div>
</div> </div>
{ props.isPinnedContract && props.instance.pinnedAt ? ( { props.isPinnedContract && props.instance.pinnedAt ? (
<div className="d-flex" data-id="instanceContractPinnedAt"> <div className="d-flex" data-id="instanceContractPinnedAt">

@ -525,3 +525,8 @@
width: 100%; width: 100%;
} }
.remixui_runtabBalancelabel {
font-size: 0.688rem;
line-height: 0.75rem;
color: var(--runtab);
}

@ -136,10 +136,7 @@ export const initWorkspace = (filePanelPlugin) => async (reducerDispatch: React.
if (!etherscanKey) etherscanKey = '2HKUX5ZVASZIKWJM8MIQVCRUVZ6JAWT531' if (!etherscanKey) etherscanKey = '2HKUX5ZVASZIKWJM8MIQVCRUVZ6JAWT531'
const networks = [ const networks = [
{ id: 1, name: 'mainnet' }, { id: 1, name: 'mainnet' },
{ id: 3, name: 'ropsten' }, { id: 11155111, name: 'sepolia' }
{ id: 4, name: 'rinkeby' },
{ id: 42, name: 'kovan' },
{ id: 5, name: 'goerli' }
] ]
let found = false let found = false
const workspaceName = 'code-sample' const workspaceName = 'code-sample'

Loading…
Cancel
Save