Merge branch 'ethereum:master' into links-fix

pull/5715/head
0x 1 week ago committed by GitHub
commit 7d4f61b056
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 2
      .env.local
  2. 4
      .github/ISSUE_TEMPLATE/bug_report.md
  3. 1
      .gitignore
  4. 4
      CONTRIBUTING.md
  5. 4
      apps/circuit-compiler/src/app/services/circomPluginClient.ts
  6. 2
      apps/circuit-compiler/webpack.config.js
  7. 19
      apps/contract-verification/README.md
  8. 27
      apps/contract-verification/src/app/app.tsx
  9. 40
      apps/contract-verification/src/app/components/AccordionReceipt.tsx
  10. 8
      apps/contract-verification/src/app/components/ConfigInput.tsx
  11. 10
      apps/contract-verification/src/app/components/ConstructorArguments.tsx
  12. 4
      apps/contract-verification/src/app/components/ContractAddressInput.tsx
  13. 5
      apps/contract-verification/src/app/components/ContractDropdown.tsx
  14. 14
      apps/contract-verification/src/app/components/NavMenu.tsx
  15. 6
      apps/contract-verification/src/app/components/SearchableChainDropdown.tsx
  16. 4
      apps/contract-verification/src/app/layouts/Default.tsx
  17. 9
      apps/contract-verification/src/app/routes.tsx
  18. 7
      apps/contract-verification/src/app/views/LookupView.tsx
  19. 5
      apps/contract-verification/src/app/views/ReceiptsView.tsx
  20. 3
      apps/contract-verification/src/app/views/SettingsView.tsx
  21. 30
      apps/contract-verification/src/app/views/VerifyView.tsx
  22. 2
      apps/contract-verification/src/profile.json
  23. 2
      apps/contract-verification/webpack.config.js
  24. 2
      apps/debugger/webpack.config.js
  25. 2
      apps/doc-gen/webpack.config.js
  26. 2
      apps/doc-viewer/webpack.config.js
  27. 2
      apps/learneth/src/pages/StepDetail/index.tsx
  28. 4
      apps/learneth/src/redux/models/remixide.ts
  29. 2
      apps/learneth/webpack.config.js
  30. 2
      apps/noir-compiler/webpack.config.js
  31. 2
      apps/quick-dapp/webpack.config.js
  32. 17
      apps/remix-dapp/src/locales/en/udapp.json
  33. 2
      apps/remix-dapp/src/locales/zh/udapp.json
  34. 2
      apps/remix-dapp/webpack.config.js
  35. 6
      apps/remix-ide-e2e/src/commands/addAtAddressInstance.ts
  36. 17
      apps/remix-ide-e2e/src/commands/selectContract.ts
  37. 2
      apps/remix-ide-e2e/src/local-plugin/webpack.config.js
  38. 2
      apps/remix-ide-e2e/src/tests/layout.test.ts
  39. 4
      apps/remix-ide-e2e/src/tests/migrateFileSystem.test.ts
  40. 10
      apps/remix-ide-e2e/src/tests/quickDapp.test.ts
  41. 2
      apps/remix-ide-e2e/src/tests/remixd.test.ts
  42. 2
      apps/remix-ide-e2e/src/tests/solidityImport.test.ts
  43. 2
      apps/remix-ide-e2e/src/tests/specialFunctions.test.ts
  44. 82
      apps/remix-ide-e2e/src/tests/terminal.test.ts
  45. 154
      apps/remix-ide-e2e/src/tests/vm_state.test.ts
  46. 6
      apps/remix-ide-e2e/src/tests/workspace_git.test.ts
  47. 4
      apps/remix-ide-e2e/src/types/index.d.ts
  48. 2
      apps/remix-ide/contracts/node_modules/openzeppelin-solidity/contracts/sample.sol
  49. 12
      apps/remix-ide/release-process.md
  50. 122
      apps/remix-ide/src/app.ts
  51. 2
      apps/remix-ide/src/app/components/main-panel.tsx
  52. 2
      apps/remix-ide/src/app/components/plugin-manager-component.js
  53. 2
      apps/remix-ide/src/app/components/popup-panel.tsx
  54. 13
      apps/remix-ide/src/app/editor/editor.js
  55. 2
      apps/remix-ide/src/app/files/dgitProvider.ts
  56. 4
      apps/remix-ide/src/app/files/fileManager.ts
  57. 2
      apps/remix-ide/src/app/files/remixDProvider.js
  58. 6
      apps/remix-ide/src/app/files/workspaceFileProvider.js
  59. 2
      apps/remix-ide/src/app/panels/file-panel.js
  60. 2
      apps/remix-ide/src/app/panels/layout.ts
  61. 2
      apps/remix-ide/src/app/panels/tab-proxy.js
  62. 3
      apps/remix-ide/src/app/panels/terminal.tsx
  63. 3
      apps/remix-ide/src/app/plugins/git.tsx
  64. 65
      apps/remix-ide/src/app/plugins/remixAIPlugin.tsx
  65. 16
      apps/remix-ide/src/app/providers/environment-explorer.tsx
  66. 4
      apps/remix-ide/src/app/providers/style/environment-explorer.css
  67. 2
      apps/remix-ide/src/app/tabs/analysis-tab.js
  68. 2
      apps/remix-ide/src/app/tabs/compile-tab.js
  69. 2
      apps/remix-ide/src/app/tabs/debugger-tab.js
  70. 1
      apps/remix-ide/src/app/tabs/locale-module.js
  71. 30
      apps/remix-ide/src/app/tabs/locales/en/contractverification.json
  72. 1
      apps/remix-ide/src/app/tabs/locales/en/editor.json
  73. 1
      apps/remix-ide/src/app/tabs/locales/en/home.json
  74. 4
      apps/remix-ide/src/app/tabs/locales/en/pluginManager.json
  75. 13
      apps/remix-ide/src/app/tabs/locales/en/udapp.json
  76. 1
      apps/remix-ide/src/app/tabs/locales/es/panel.json
  77. 1
      apps/remix-ide/src/app/tabs/locales/fr/panel.json
  78. 1
      apps/remix-ide/src/app/tabs/locales/it/panel.json
  79. 1
      apps/remix-ide/src/app/tabs/locales/ko/panel.json
  80. 1
      apps/remix-ide/src/app/tabs/locales/ru/panel.json
  81. 1
      apps/remix-ide/src/app/tabs/locales/zh/panel.json
  82. 6
      apps/remix-ide/src/app/tabs/script-runner-ui.tsx
  83. 2
      apps/remix-ide/src/app/tabs/settings-tab.tsx
  84. 2
      apps/remix-ide/src/app/tabs/test-tab.js
  85. 2
      apps/remix-ide/src/app/tabs/theme-module.js
  86. 5
      apps/remix-ide/src/app/udapp/run-tab.tsx
  87. BIN
      apps/remix-ide/src/assets/img/contractVerification.webp
  88. BIN
      apps/remix-ide/src/assets/img/linea_chain.png
  89. BIN
      apps/remix-ide/src/assets/img/solSurvey2024.webp
  90. BIN
      apps/remix-ide/src/assets/img/soliditySurvey2023.webp
  91. 3
      apps/remix-ide/src/blockchain/blockchain.tsx
  92. 3
      apps/remix-ide/src/remixAppManager.js
  93. 2
      apps/remix-ide/team-best-practices.md
  94. 2
      apps/remix-ide/webpack.config.js
  95. 23
      apps/remixdesktop/README.md
  96. 10
      apps/remixdesktop/src/lib/InferenceServerManager.ts
  97. 2
      apps/remixdesktop/test/tests/app/foundry.test.ts
  98. 4
      apps/vyper/.browserslistrc
  99. 194
      apps/vyper/src/app/app.tsx
  100. 6
      apps/vyper/src/app/utils/compiler.tsx
  101. Some files were not shown because too many files have changed in this diff Show More

@ -2,4 +2,4 @@ gist_token=<token>
account_passphrase=<passphrase>
account_password=<password>
NODE_OPTIONS=--max-old-space-size=2048
# WALLET_CONNECT_PROJECT_ID=<walletconnect cloud PROJECT_ID>
WALLET_CONNECT_PROJECT_ID=<project_id>

@ -25,8 +25,8 @@ If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. Windows, Linux or MacOS]
- Browser [e.g. chrome, firefox]
- Version [e.g. 22]
- Browser: [e.g. chrome, firefox]
- Version: [e.g. 22]
**Additional context**
Add any other context about the problem here.

1
.gitignore vendored

@ -16,6 +16,7 @@ soljson.js
*_group*.ts
stats.json
release
.env
# compiled output

@ -1,6 +1,6 @@
# Contributing
Everyone is welcome to contribute to Remix's codebase and please join our [Discord](https://discord.gg/mh9hFCKkEq).
Everyone is welcome to contribute to Remix's codebase and please join our [Discord](https://discord.com/invite/nfv6ZYjAeP).
## Development
Remix libraries work closely with [Remix IDE](https://remix.ethereum.org). Each library has a README to explain its application.
@ -72,7 +72,7 @@ import panelJson from './panel.json';
import enJson from '../en';
// There may have some untranslated content. Always fill in the gaps with EN JSON.
// No need for a defaultMessage prop when render a FormattedMessage component.
// No need for a defaultMessage prop when rendering a FormattedMessage component.
export default Object.assign({}, enJson, {
...panelJson,
})

@ -502,9 +502,9 @@ export class CircomPluginClient extends PluginClient {
const exists = await this.call('fileManager', 'exists', path)
if (exists) return path
else throw new Error(`Report path ${path} do no exist in the Remix FileSystem`)
else throw new Error(`Report path ${path} does not exist in the Remix FileSystem`)
} else {
throw new Error(`Report path ${path} do no exist in the Remix FileSystem`)
throw new Error(`Report path ${path} does not exist in the Remix FileSystem`)
}
}
}

@ -55,7 +55,7 @@ module.exports = composePlugins(withNx(), (config) => {
})
)
// souce-map loader
// source-map loader
config.module.rules.push({
test: /\.js$/,
use: ["source-map-loader"],

@ -0,0 +1,19 @@
# Contract Verification Plugin
With this plugin, contracts written and compiled in Remix can be verified at Sourcify, Etherscan, Blockscout and Routescan at the same time. Besides that, the source code of any address can be fetched from the verifiers and added to the file editor.
## Adding a new verification service
Currently, the plugin supports Sourcify, Etherscan, Blockscout and Routescan. To add a new verifier, you need to make the following changes:
In `./src/app/types/VerificationTypes.ts`, add the new verifier to the `VerifierIdentifier` type and the`VERIFIERS` array.
In order to interact with the API of the verification service, you need to create a new class that extends the `AbstractVerifier` class. If your API is based on the Etherscan API, you can simply extend the `EtherscanVerifier` class. In this case, see the `RoutescanVerifier` and the `BlockscoutVerifier` for reference. All related classes are located in the `./src/app/Verifiers` directory.
In `./src/app/Verifiers/index.ts`, add your new verifier to the `getVerifier` function. Validate any settings properties that are required by your verifier.
In `./src/app/utils/default-apis.json`, you need to add default settings for your new verifier. If you can, simply add your defaults in the form of `{ [VerifierIdentifier]: { [chainId]: { apiUrl: [value], explorerUrl: [value] } } }`. If you need more flexibility, you might also want to change the `src/app/utils/default-settings.ts` file. See Routescan there for reference.
Your new verifier will automatically be shown in the `VerifyView` and the `LookupView` since we added it to the `VERIFIERS` array. You only need to make a change to the `SettingsView` because the required settings depend on the verifier. There, add a new div block in the same format as the other verifiers. Only add the `ConfigInput` elements for the settings that your verifier needs to the div block.
That's it! Your verification service should be able to verify contracts through Remix now.

@ -13,6 +13,7 @@ import { CompilerAbstract } from '@remix-project/remix-solidity'
import { useLocalStorage } from './hooks/useLocalStorage'
import { getVerifier } from './Verifiers'
import { ContractDropdownSelection } from './components/ContractDropdown'
import { IntlProvider } from 'react-intl'
const plugin = new ContractVerificationPluginClient()
@ -32,11 +33,25 @@ const App = () => {
const [proxyAddressError, setProxyAddressError] = useState('')
const [abiEncodedConstructorArgs, setAbiEncodedConstructorArgs] = useState<string>('')
const [abiEncodingError, setAbiEncodingError] = useState<string>('')
const [locale, setLocale] = useState<{ code: string; messages: any }>({
code: 'en',
messages: {}
})
const timer = useRef(null)
useEffect(() => {
plugin.internalEvents.on('verification_activated', () => {
// @ts-ignore
plugin.call('locale', 'currentLocale').then((locale: any) => {
setLocale(locale)
})
// @ts-ignore
plugin.on('locale', 'localeChanged', (locale: any) => {
setLocale(locale)
})
// Fetch compiler artefacts initially
plugin.call('compilerArtefacts' as any, 'getAllCompilerAbstracts').then((obj: any) => {
setCompilationOutput(obj)
@ -143,11 +158,13 @@ const App = () => {
}, [submittedContracts])
return (
<AppContext.Provider value={{ themeType, setThemeType, clientInstance: plugin, settings, setSettings, chains, compilationOutput, submittedContracts, setSubmittedContracts }}>
<VerifyFormContext.Provider value={{ selectedChain, setSelectedChain, contractAddress, setContractAddress, contractAddressError, setContractAddressError, selectedContract, setSelectedContract, proxyAddress, setProxyAddress, proxyAddressError, setProxyAddressError, abiEncodedConstructorArgs, setAbiEncodedConstructorArgs, abiEncodingError, setAbiEncodingError }}>
<DisplayRoutes />
</VerifyFormContext.Provider>
</AppContext.Provider>
<IntlProvider locale={locale.code} messages={locale.messages}>
<AppContext.Provider value={{ themeType, setThemeType, clientInstance: plugin, settings, setSettings, chains, compilationOutput, submittedContracts, setSubmittedContracts }}>
<VerifyFormContext.Provider value={{ selectedChain, setSelectedChain, contractAddress, setContractAddress, contractAddressError, setContractAddressError, selectedContract, setSelectedContract, proxyAddress, setProxyAddress, proxyAddressError, setProxyAddressError, abiEncodedConstructorArgs, setAbiEncodedConstructorArgs, abiEncodingError, setAbiEncodingError }}>
<DisplayRoutes />
</VerifyFormContext.Provider>
</AppContext.Provider>
</IntlProvider>
)
}

@ -97,32 +97,32 @@ const ReceiptsBody = ({ receipts }: { receipts: VerificationReceipt[] }) => {
className="list-group-item d-flex flex-row align-items-center"
>
<CustomTooltip
placement="top"
tooltipClasses=" text-break"
tooltipTextClasses="text-capitalize"
tooltipText={`Status: ${receipt.status}${receipt.message ? `, Message: ${receipt.message}` : ''}`}
>
<span className="mr-2">
{['verified', 'partially verified', 'already verified'].includes(receipt.status) ?
<i className="fas fa-check text-success px-1"></i> :
receipt.status === 'fully verified' ?
<i className="fas fa-check-double text-success px-1"></i> :
receipt.status === 'failed' ?
<i className="fas fa-xmark text-warning px-1"></i> :
['pending', 'awaiting implementation verification'].includes(receipt.status) ?
<i className="fas fa-spinner fa-spin"></i> :
<i className="fas fa-question"></i>
}
</span>
</CustomTooltip>
<div className="d-flex flex-row w-100 justify-content-between">
placement="top"
tooltipClasses=" text-break"
tooltipTextClasses="text-capitalize"
tooltipText={`Status: ${receipt.status}${receipt.message ? `, Message: ${receipt.message}` : ''}`}
>
<span className="mr-2">
{['verified', 'partially verified', 'already verified'].includes(receipt.status) ?
<i className="fas fa-check text-success px-1"></i> :
receipt.status === 'fully verified' ?
<i className="fas fa-check-double text-success px-1"></i> :
receipt.status === 'failed' ?
<i className="fas fa-xmark text-warning px-1"></i> :
['pending', 'awaiting implementation verification'].includes(receipt.status) ?
<i className="fas fa-spinner fa-spin"></i> :
<i className="fas fa-question"></i>
}
</span>
</CustomTooltip>
<div className="d-flex flex-row w-100 justify-content-between">
<CustomTooltip placement="top" tooltipClasses=" text-break" tooltipText={`API: ${receipt.verifierInfo.apiUrl}`}>
<span className="font-weight-bold pr-2">{receipt.verifierInfo.name}</span>
</CustomTooltip>
<div className="ml-1">
{!!receipt.lookupUrl && receipt.verifierInfo.name === 'Blockscout' ?
<CopyToClipboard classList="pr-0 py-0" tip="Copy code URL" content={receipt.lookupUrl} direction="top" /> :
!!receipt.lookupUrl && <a href={receipt.lookupUrl} target="_blank" className="fa fas fa-arrow-up-right-from-square"></a>
!!receipt.lookupUrl && <a href={receipt.lookupUrl} target="_blank" className="fa fas fa-arrow-up-right-from-square" rel="noreferrer"></a>
}
</div>
</div>

@ -1,5 +1,6 @@
import React, { useEffect, useState } from 'react'
import { CustomTooltip } from '@remix-ui/helper'
import { FormattedMessage, useIntl } from 'react-intl'
interface ConfigInputProps {
label: string
@ -13,6 +14,7 @@ interface ConfigInputProps {
export const ConfigInput: React.FC<ConfigInputProps> = ({ label, id, secret, initialValue, saveResult }) => {
const [value, setValue] = useState(initialValue)
const [enabled, setEnabled] = useState(false)
const intl = useIntl()
// Reset state when initialValue changes
useEffect(() => {
@ -42,7 +44,7 @@ export const ConfigInput: React.FC<ConfigInputProps> = ({ label, id, secret, ini
type={secret ? 'password' : 'text'}
className={`form-control small w-100 ${!enabled ? 'bg-transparent pl-0 border-0' : ''}`}
id={id}
placeholder={`Add ${label}`}
placeholder={intl.formatMessage({ id: "contract-verification.configInputPlaceholder" }, { label })}
value={value}
onChange={(e) => setValue(e.target.value)}
disabled={!enabled}
@ -51,10 +53,10 @@ export const ConfigInput: React.FC<ConfigInputProps> = ({ label, id, secret, ini
{ enabled ? (
<>
<button type="button" className="btn btn-primary btn-sm ml-2" onClick={handleSave}>
Save
<FormattedMessage id="contract-verification.configInputSaveButton" />
</button>
<button type="button" className="btn btn-secondary btn-sm ml-2" onClick={handleCancel}>
Cancel
<FormattedMessage id="contract-verification.configInputCancelButton" />
</button>
</>
) : (

@ -3,6 +3,7 @@ import { ethers } from 'ethers'
import { AppContext } from '../AppContext'
import { ContractDropdownSelection } from './ContractDropdown'
import { FormattedMessage } from 'react-intl'
interface ConstructorArgumentsProps {
abiEncodedConstructorArgs: string
@ -102,7 +103,9 @@ export const ConstructorArguments: React.FC<ConstructorArgumentsProps> = ({ abiE
<div className="d-flex py-1 align-items-center custom-control custom-checkbox">
<input className="form-check-input custom-control-input" type="checkbox" id="toggleRawInputSwitch" checked={toggleRawInput} onChange={() => setToggleRawInput(!toggleRawInput)} />
<label className="m-0 form-check-label custom-control-label" style={{ paddingTop: '2px' }} htmlFor="toggleRawInputSwitch">
Enter raw ABI-encoded constructor arguments
<FormattedMessage
id="contract-verification.constructorArgumentsToggleRawInput"
/>
</label>
</div>
{toggleRawInput ? (
@ -122,7 +125,10 @@ export const ConstructorArguments: React.FC<ConstructorArgumentsProps> = ({ abiE
{abiEncodedConstructorArgs && (
<div>
<label className="form-check-label" htmlFor="rawAbiEncodingResult">
ABI-encoded constructor arguments:
<FormattedMessage
id="contract-verification.constructorArgumentsRawAbiEncodingResult"
defaultMessage="ABI-encoded constructor arguments"
/> :
</label>
<textarea className="form-control" rows={5} disabled value={abiEncodedConstructorArgs} id="rawAbiEncodingResult" style={{ opacity: 0.5 }} />
</div>

@ -2,11 +2,11 @@ import React, { useEffect, useState, useContext } from 'react'
import { ethers } from 'ethers/'
interface ContractAddressInputProps {
label: string
label: string | any
id: string
contractAddress: string
setContractAddress: (address: string) => void
contractAddressError: string
contractAddressError: string | any
setContractAddressError: (error: string) => void
}

@ -1,6 +1,7 @@
import React, { useEffect, useState, useContext, Fragment } from 'react'
import './ContractDropdown.css'
import { AppContext } from '../AppContext'
import { FormattedMessage } from 'react-intl'
export interface ContractDropdownSelection {
triggerFilePath: string
@ -42,7 +43,7 @@ export const ContractDropdown: React.FC<ContractDropdownProps> = ({ label, id, s
return (
<div className="form-group">
<label htmlFor={id}>{label}</label>
<label htmlFor={id}><FormattedMessage id="contract-verification.contractDropdownLabel" defaultMessage={label} values={{ label }} /></label>
<select value={selectedContract ? JSON.stringify(selectedContract) : ''}
className={`form-control custom-select pr-4 ${!hasContracts ? 'disabled-cursor text-warning' : ''}`}
id={id}
@ -65,7 +66,7 @@ export const ContractDropdown: React.FC<ContractDropdownProps> = ({ label, id, s
</optgroup>
))
) : (
<option>Compiled contract required</option>
<option value={''}><FormattedMessage id="contract-verification.contractDropDownDefaultText" defaultMessage={'Compiled contract required'} /></option>
)}
</select>
</div>

@ -1,13 +1,15 @@
import React from 'react'
import { NavLink } from 'react-router-dom'
import { useIntl, FormattedMessage } from 'react-intl'
interface NavItemProps {
to: string
icon: JSX.Element
title: string
title: string | any
}
const NavItem: React.FC<NavItemProps> = ({ to, icon, title }) => {
const intl = useIntl()
return (
<NavLink
data-id={`${title}Tab`}
@ -24,11 +26,11 @@ const NavItem: React.FC<NavItemProps> = ({ to, icon, title }) => {
export const NavMenu = () => {
return (
<nav className="d-flex medium flex-row w-100" style={{backgroundColor: 'var(--body-bg)!important'}}>
<NavItem to="/" icon={<i className="fas fa-home"></i>} title="Verify" />
<NavItem to="/receipts" icon={<i className="fas fa-receipt"></i>} title="Receipts" />
<NavItem to="/lookup" icon={<i className="fas fa-search"></i>} title="Lookup" />
<NavItem to="/settings" icon={<i className="fas fa-cog"></i>} title="Settings" />
<nav className="d-flex medium flex-row w-100" style={{ backgroundColor: 'var(--body-bg)!important' }}>
<NavItem to="/" icon={<i className="fas fa-home"></i>} title={ <FormattedMessage id="contract-verification.verifyNavTitle" defaultMessage={'Verify'} /> } />
<NavItem to="/receipts" icon={<i className="fas fa-receipt"></i>} title={ <FormattedMessage id="contract-verification.receiptsNavTitle" defaultMessage={'Receipts'} /> } />
<NavItem to="/lookup" icon={<i className="fas fa-search"></i>} title={ <FormattedMessage id="contract-verification.lookupNavTitle" defaultMessage={'Lookup'} /> } />
<NavItem to="/settings" icon={<i className="fas fa-cog"></i>} title={ <FormattedMessage id="contract-verification.settingsNavTitle" defaultMessage={'Settings'} /> } />
</nav>
)
}

@ -2,6 +2,7 @@ import React, { useState, useEffect, useRef, useMemo } from 'react'
import Fuse from 'fuse.js'
import type { Chain } from '../types'
import { AppContext } from '../AppContext'
import { useIntl } from 'react-intl'
function getChainDescriptor(chain: Chain): string {
if (!chain) return ''
@ -9,7 +10,7 @@ function getChainDescriptor(chain: Chain): string {
}
interface DropdownProps {
label: string
label: string | any
id: string
setSelectedChain: (chain: Chain) => void
selectedChain: Chain
@ -18,6 +19,7 @@ interface DropdownProps {
export const SearchableChainDropdown: React.FC<DropdownProps> = ({ label, id, setSelectedChain, selectedChain }) => {
const { chains } = React.useContext(AppContext)
const ethereumChainIds = [1, 11155111, 17000]
const intl = useIntl()
// Add Ethereum chains to the head of the chains list. Sort the rest alphabetically
const dropdownChains = useMemo(
@ -90,7 +92,7 @@ export const SearchableChainDropdown: React.FC<DropdownProps> = ({ label, id, se
{' '}
{/* Add ref here */}
<label htmlFor={id}>{label}</label>
<input type="text" value={searchTerm} onChange={handleInputChange} onClick={openDropdown} data-id="chainDropdownbox" placeholder="Select a chain" className="form-control" />
<input type="text" value={searchTerm} onChange={handleInputChange} onClick={openDropdown} data-id="chainDropdownbox" placeholder={intl.formatMessage({ id: "contract-verification.searchableChainDropdown", defaultMessage: "Select a chain" })} className="form-control" />
<ul className="dropdown-menu show w-100 bg-light" style={{ maxHeight: '400px', overflowY: 'auto', display: isOpen ? 'initial' : 'none' }}>
{filteredOptions.map((chain) => (
<li key={chain.chainId} onClick={() => handleOptionClick(chain)} data-id={chain.chainId} className={`dropdown-item text-dark ${selectedChain?.chainId === chain.chainId ? 'active' : ''}`} style={{ cursor: 'pointer', whiteSpace: 'normal' }}>

@ -4,8 +4,8 @@ import { NavMenu } from '../components/NavMenu'
interface Props {
from: string
title?: string
description?: string
title?: string | any
description?: string | any
}
export const DefaultLayout = ({ children, title, description }: PropsWithChildren<Props>) => {

@ -3,6 +3,7 @@ import { HashRouter as Router, Route, Routes } from 'react-router-dom'
import { VerifyView, ReceiptsView, LookupView, SettingsView } from './views'
import { DefaultLayout } from './layouts'
import { FormattedMessage } from 'react-intl'
const DisplayRoutes = () => (
<Router>
@ -10,7 +11,7 @@ const DisplayRoutes = () => (
<Route
path="/"
element={
<DefaultLayout from="/" title="Verify" description="Verify compiled contracts on different verification services">
<DefaultLayout from="/" title="Verify" description={<FormattedMessage id="contract-verification.verifyDefaultLayout.description" defaultMessage="Verify compiled contracts on different verification services" />}>
<VerifyView />
</DefaultLayout>
}
@ -19,7 +20,7 @@ const DisplayRoutes = () => (
<Route
path="/receipts"
element={
<DefaultLayout from="/" title="Receipts" description="Check the verification statuses of contracts submitted for verification">
<DefaultLayout from="/" title="Receipts" description={<FormattedMessage id="contract-verification.receiptsDefaultLayout.description" defaultMessage="Check the verification statuses of contracts submitted for verification" />}>
<ReceiptsView />
</DefaultLayout>
}
@ -28,7 +29,7 @@ const DisplayRoutes = () => (
<Route
path="/lookup"
element={
<DefaultLayout from="/" title="Lookup" description="Search for verified contracts and download them to Remix">
<DefaultLayout from="/" title="Lookup" description={<FormattedMessage id="contract-verification.lookupDefaultLayout.description" defaultMessage="Lookup the verification status of a contract by its address" />}>
<LookupView />
</DefaultLayout>
}
@ -37,7 +38,7 @@ const DisplayRoutes = () => (
<Route
path="/settings"
element={
<DefaultLayout from="/" title="Settings" description="Customize settings for each verification service and chain">
<DefaultLayout from="/" title="Settings" description={<FormattedMessage id="contract-verification.settingsDefaultLayout.description" defaultMessage="Configure the settings for the contract verification plugin" />}>
<SettingsView />
</DefaultLayout>
}

@ -9,6 +9,7 @@ import { useNavigate } from 'react-router-dom'
import { VerifyFormContext } from '../VerifyFormContext'
import { useSourcifySupported } from '../hooks/useSourcifySupported'
import { CopyToClipboard } from '@remix-ui/clipboard'
import { FormattedMessage } from 'react-intl'
export const LookupView = () => {
const { settings, clientInstance } = useContext(AppContext)
@ -74,10 +75,10 @@ export const LookupView = () => {
return (
<>
<form onSubmit={handleLookup}>
<SearchableChainDropdown label="Chain" id="network-dropdown" selectedChain={selectedChain} setSelectedChain={setSelectedChain} />
<ContractAddressInput label="Contract Address" id="contract-address" contractAddress={contractAddress} setContractAddress={setContractAddress} contractAddressError={contractAddressError} setContractAddressError={setContractAddressError} />
<SearchableChainDropdown label={<FormattedMessage id="contract-verification.searchableChainDropdownLabel" defaultMessage="Chain" />} id="network-dropdown" selectedChain={selectedChain} setSelectedChain={setSelectedChain} />
<ContractAddressInput label={<FormattedMessage id="contract-verification.contractAddressInput" defaultMessage="Contract Address" />} id="contract-address" contractAddress={contractAddress} setContractAddress={setContractAddress} contractAddressError={contractAddressError} setContractAddressError={setContractAddressError} />
<button type="submit" className="btn w-100 btn-primary" disabled={submitDisabled}>
Lookup
<FormattedMessage id="contract-verification.lookupButton" defaultMessage="Lookup" />
</button>
</form>
<div className="pt-3">

@ -1,6 +1,7 @@
import { useContext } from 'react'
import { AccordionReceipt } from '../components/AccordionReceipt'
import { AppContext } from '../AppContext'
import { FormattedMessage } from 'react-intl'
export const ReceiptsView = () => {
const { submittedContracts } = useContext(AppContext)
@ -10,7 +11,9 @@ export const ReceiptsView = () => {
<div>
{contracts.length > 0 ? contracts.map((contract, index) => (
<AccordionReceipt key={contract.id} contract={contract} index={index} />
)) : <div className="text-center mt-5" data-id="noContractsSubmitted">No contracts submitted for verification</div>}
)) : <div className="text-center mt-5" data-id="noContractsSubmitted">
<FormattedMessage id="contract-verification.receipts.noContractsSubmitted" defaultMessage="No contracts submitted for verification" />
</div>}
</div>
)
}

@ -4,6 +4,7 @@ import type { VerifierIdentifier, VerifierSettings, ContractVerificationSettings
import { mergeChainSettingsWithDefaults } from '../utils'
import { AppContext } from '../AppContext'
import { VerifyFormContext } from '../VerifyFormContext'
import { FormattedMessage } from 'react-intl'
export const SettingsView = () => {
const { settings, setSettings } = useContext(AppContext)
@ -28,7 +29,7 @@ export const SettingsView = () => {
return (
<>
<SearchableChainDropdown label="Chain" id="network-dropdown" setSelectedChain={setSelectedChain} selectedChain={selectedChain} />
<SearchableChainDropdown label={<FormattedMessage id="contract-verification.searchableChainDropdownLabel" defaultMessage="Chain" />} id="network-dropdown" setSelectedChain={setSelectedChain} selectedChain={selectedChain} />
{selectedChain && (
<div>

@ -5,12 +5,13 @@ import { SearchableChainDropdown, ContractDropdown, ContractAddressInput } from
import type { VerifierIdentifier, SubmittedContract, VerificationReceipt, VerifierInfo, VerificationResponse } from '../types'
import { VERIFIERS } from '../types'
import { mergeChainSettingsWithDefaults, validConfiguration } from '../utils'
import { useNavigate } from 'react-router-dom'
import { Form, useNavigate } from 'react-router-dom'
import { ConstructorArguments } from '../components/ConstructorArguments'
import { CustomTooltip } from '@remix-ui/helper'
import { AbstractVerifier, getVerifier } from '../Verifiers'
import { VerifyFormContext } from '../VerifyFormContext'
import { useSourcifySupported } from '../hooks/useSourcifySupported'
import { FormattedMessage } from 'react-intl'
export const VerifyView = () => {
const { compilationOutput, setSubmittedContracts, settings, clientInstance } = useContext(AppContext)
@ -177,9 +178,14 @@ export const VerifyView = () => {
return (
<form onSubmit={handleVerify}>
<SearchableChainDropdown label="Chain" id="network-dropdown" selectedChain={selectedChain} setSelectedChain={setSelectedChain} />
<SearchableChainDropdown
label={<FormattedMessage id="contract-verification.searchableChainDropdown" defaultMessage={"Chain"} />}
id="network-dropdown"
selectedChain={selectedChain}
setSelectedChain={setSelectedChain}
/>
<ContractAddressInput
label="Contract Address"
label={<FormattedMessage id="contract-verification.contractAddressInput" defaultMessage={"Contract Address"}/>}
id="contract-address"
contractAddress={contractAddress}
setContractAddress={setContractAddress}
@ -200,11 +206,11 @@ export const VerifyView = () => {
<div className="d-flex py-1 align-items-center custom-control custom-checkbox">
<input id="has-proxy" className="form-check-input custom-control-input" type="checkbox" checked={!!hasProxy} onChange={(e) => setHasProxy(e.target.checked)} />
<label htmlFor="has-proxy" className="m-0 form-check-label custom-control-label" style={{ paddingTop: '2px' }}>
The deployed contract is behind a proxy
<FormattedMessage id="contract-verification.proxyInputLabel" defaultMessage={'The deployed contract is behind a proxy'} />
</label>
</div>
{hasProxy && <ContractAddressInput
label="Proxy Address"
label={<FormattedMessage id="contract-verification.proxyContractAddressInput" defaultMessage={'Proxy Address'} />}
id="proxy-address"
contractAddress={proxyAddress}
setContractAddress={setProxyAddress}
@ -261,14 +267,14 @@ export const VerifyView = () => {
})}
</div>
<CustomTooltip tooltipText={submitDisabled ? (
(!!contractAddressError || !contractAddress) ? "Please provide a valid contract address." :
!selectedChain ? "Please select the chain." :
!selectedContract ? "Please select the contract (compile if needed)." :
((hasProxy && !!proxyAddressError) || (hasProxy && !proxyAddress)) ? "Please provide a valid proxy contract address." :
"Please provide all necessary data to verify") // Is not expected to be a case
: "Verify with selected tools"}>
(!!contractAddressError || !contractAddress) ? <FormattedMessage id="contract-verification.contractAddressError" defaultMessage="Please provide a valid contract address." /> :
!selectedChain ? <FormattedMessage id="contract-verification.chainError" defaultMessage="Please select the chain." /> :
!selectedContract ? <FormattedMessage id="contract-verification.selectedContractError" defaultMessage="Please select the contract." /> :
((hasProxy && !!proxyAddressError) || (hasProxy && !proxyAddress)) ? <FormattedMessage id="contract-verification.proxyAddressError" defaultMessage="Please provide a valid proxy address." /> :
<FormattedMessage id="contract-verification.generalVerifyError" defaultMessage={"Please provide all necessary data to verify"} />) // Is not expected to be a case
: <FormattedMessage id="contract-verification.verifyButtonTooltip" defaultMessage="Verify the contract on the selected chains with the selected verifiers." />}>
<button type="submit" className="w-100 btn btn-primary mt-3" disabled={submitDisabled}>
Verify
<FormattedMessage id="contract-verification.verifyButton" defaultMessage="Verify" />
</button>
</CustomTooltip>
</form>

File diff suppressed because one or more lines are too long

@ -56,7 +56,7 @@ module.exports = composePlugins(withNx(), (config) => {
})
)
// souce-map loader
// source-map loader
config.module.rules.push({
test: /\.js$/,
use: ['source-map-loader'],

@ -48,7 +48,7 @@ module.exports = composePlugins(withNx(), (config) => {
})
)
// souce-map loader
// source-map loader
config.module.rules.push({
test: /\.js$/,
use: ['source-map-loader'],

@ -40,7 +40,7 @@ module.exports = composePlugins(withNx(), withReact(), config => {
new webpack.DefinePlugin({}),
)
// souce-map loader
// source-map loader
config.module.rules.push({
test: /\.js$/,
use: ['source-map-loader'],

@ -28,7 +28,7 @@ module.exports = composePlugins(withNx(), withReact(), (config) => {
new webpack.DefinePlugin({})
)
// souce-map loader
// source-map loader
config.module.rules.push({
test: /\.js$/,
use: ['source-map-loader'],

@ -85,7 +85,7 @@ function StepDetailPage() {
<div className="errorloadingspacer"></div>
<h1 className="pl-3 pr-3 pt-3 pb-1">{clonedStep.name}</h1>
<button
className="w-100nav-item rounded-0 nav-link btn btn-success test"
className="w-100 nav-item rounded-0 nav-link btn btn-success test"
onClick={() => {
dispatch({
type: 'remixide/displayFile',

@ -33,7 +33,9 @@ const Model: ModelType = {
},
})
yield remixClient.onload()
yield remixClient.onload(() => {
remixClient.call('manager', 'activatePlugin', 'solidityUnitTesting')
})
toast.dismiss()

@ -54,7 +54,7 @@ module.exports = composePlugins(withNx(), (config) => {
})
)
// souce-map loader
// source-map loader
config.module.rules.push({
test: /\.js$/,
use: ['source-map-loader'],

@ -55,7 +55,7 @@ module.exports = composePlugins(withNx(), (config) => {
})
)
// souce-map loader
// source-map loader
config.module.rules.push({
test: /\.js$/,
use: ["source-map-loader"],

@ -54,7 +54,7 @@ module.exports = composePlugins(withNx(), (config) => {
})
)
// souce-map loader
// source-map loader
config.module.rules.push({
test: /\.js$/,
use: ['source-map-loader'],

@ -26,7 +26,7 @@
"udapp.contractOptionsTitle2": "Select a compiled contract to deploy or to use with At Address.",
"udapp.contractOptionsTitle3": "Select and compile *.sol file to deploy or access a contract.",
"udapp.contractOptionsTitle4": "When there is a compiled .sol file, choose the contract to deploy or to use with At Address.",
"udapp.checkSumWarning": "It seems you are not using a checksumed address.A checksummed address is an address that contains uppercase letters, as specified in {a}.Checksummed addresses are meant to help prevent users from sending transactions to the wrong address.",
"udapp.checkSumWarning": "It seems you are not using a checksummed address.A checksummed address is an address that contains uppercase letters, as specified in {a}.Checksummed addresses are meant to help prevent users from sending transactions to the wrong address.",
"udapp.isOverSizePromptEip170": "Contract creation initialization returns data with length of more than 24576 bytes. The deployment will likely fail if the current network has activated the eip 170. More info: {a}",
"udapp.isOverSizePromptEip3860": "Contract creation init code exceeds the allowed max code size of 49152 bytes. The deployment will likely fail if the current network has activated the eip 3860. More info: {a}",
"udapp.thisContractMayBeAbstract": "This contract may be abstract, it may not implement an abstract parent's methods completely or it may not invoke an inherited contract's constructor correctly.",
@ -50,12 +50,15 @@
"udapp.hash": "hash",
"udapp.signature": "signature",
"udapp.forkStateTitle": "Fork VM state",
"udapp.forkStateLabel": "State Name",
"udapp.forkStateLabel": "New environment name",
"udapp.forkVmStateDesc1":"Forking state will create a new environment with same state as selected environment",
"udapp.forkVmStateDesc2":"New environment will be pinned, which can be unpinned or deleted using Envionment Explorer",
"udapp.fork": "Fork",
"udapp.deleteVmStateTitle": "Delete VM state",
"udapp.deleteVmStateDesc1": "Deleting the state of this VM will delete the associated transaction details in this Workspace.",
"udapp.deleteVmStateDesc2": "It will also delete the data of contracts deployed and pinned in this Workspace.",
"udapp.deleteVmStateDesc3": "Do you want to continue?",
"udapp.resetVmStateTitle": "Reset VM state",
"udapp.resetVmStateDesc1": "Resetting the state of this VM will delete the associated transaction details in this Workspace.",
"udapp.resetVmStateDesc2": "It will also delete the data of contracts deployed and pinned in this Workspace.",
"udapp.resetVmStateDesc3": "Do you want to continue?",
"udapp.reset": "Reset",
"udapp.delete": "Delete",
"udapp.injectedTitle": "Unfortunately it's not possible to create an account using injected provider. Please create the account directly from your provider (i.e metamask or other of the same type).",
"udapp.createNewAccount": "Create a new account",
@ -133,7 +136,7 @@
"udapp.contractCreation": "Contract Creation",
"udapp.transactionFee": "Transaction is invalid. Max fee should not be less than Base fee",
"udapp.title1": "Represents the part of the tx fee that goes to the miner.",
"udapp.title2": "Represents the maximum amount of fee that you will pay for this transaction. The minimun needs to be set to base fee.",
"udapp.title2": "Represents the maximum amount of fee that you will pay for this transaction. The minimum needs to be set to base fee.",
"udapp.gasPrice": "Gas price",
"udapp.gweiText": "visit {a} for current gas price info.",
"udapp.maxTransactionFee": "Max transaction fee",

@ -23,7 +23,7 @@
"udapp.contractOptionsTitle2": "选择要部署或与 At Address 一起使用的已编译合约。",
"udapp.contractOptionsTitle3": "选择并编译 *.sol 文件以部署或访问合约。",
"udapp.contractOptionsTitle4": "当有编译的 .sol 文件时,选择 {br} 合约进行部署或与 AtAddress 一起使用。",
"udapp.checkSumWarning": "您似乎没有使用 checksumed address 。{br} checksumed address 是包含大写字母的地址,如 {a} 中所指定。{br} checksumed address 旨在帮助防止用户将交易发送到错误地址。",
"udapp.checkSumWarning": "您似乎没有使用 checksummed address 。{br} checksummed address 是包含大写字母的地址,如 {a} 中所指定。{br} checksummed address 旨在帮助防止用户将交易发送到错误地址。",
"udapp.isOverSizePromptEip170": "合约创建初始化返回长度超过24576字节的数据。部署可能会失败。 {br}更多信息:{a}",
"udapp.isOverSizePromptEip3860": "合约创建初始化代码超出了允许的最大代码大小 49152 字节。如果当前网络已激活 eip 3860,则部署可能会失败。更多信息:{a}",
"udapp.thisContractMayBeAbstract": "这个合约可能是抽象的,它可能没有完全实现抽象父类的方法,或者它可能没有正确调用继承合约的构造函数。",

@ -72,7 +72,7 @@ module.exports = composePlugins(withNx(), (config) => {
})
)
// souce-map loader
// source-map loader
config.module.rules.push({
test: /\.js$/,
use: ['source-map-loader'],

@ -19,11 +19,11 @@ function addInstance (browser: NightwatchBrowser, address: string, isValidFormat
.waitForElementVisible('.ataddressinput')
.click('.ataddressinput')
.setValue('.ataddressinput', address, function () {
if (!isValidFormat || !isValidChecksum) browser.assert.elementPresent('button[id^="runAndDeployAtAdressButton"]:disabled')
if (!isValidFormat || !isValidChecksum) browser.assert.elementPresent('button[id^="runAndDeployAtAddressButton"]:disabled')
else if (isAbi) {
browser
.click({
selector: '//*[@id="runAndDeployAtAdressButtonContainer"]',
selector: '//*[@id="runAndDeployAtAddressButtonContainer"]',
locateStrategy: 'xpath'
})
.waitForElementPresent('[data-id="udappNotify-modal-footer-ok-react"]', 5000)
@ -34,7 +34,7 @@ function addInstance (browser: NightwatchBrowser, address: string, isValidFormat
})
} else {
browser.click({
selector: '//*[@id="runAndDeployAtAdressButtonContainer"]',
selector: '//*[@id="runAndDeployAtAddressButtonContainer"]',
locateStrategy: 'xpath'
})
}

@ -4,19 +4,14 @@ import EventEmitter from 'events'
const selector = '.udapp_contractNames'
class SelectContract extends EventEmitter {
command (this: NightwatchBrowser, contractName: string): NightwatchBrowser {
this.api.waitForElementVisible(selector).perform((done) => {
selectContract(this.api, contractName, () => {
done()
this.emit('complete')
})
})
command(this: NightwatchBrowser, contractName: string): NightwatchBrowser {
this.api
.waitForElementVisible(selector)
.waitForElementPresent(`${selector} option[value="${contractName}"]`)
.click(`${selector} option[value="${contractName}"]`)
.perform(() => this.emit('complete'))
return this
}
}
function selectContract (browser: NightwatchBrowser, contractName: string, callback: VoidFunction) {
browser.click(`${selector} option[value="${contractName}"]`).perform(() => callback())
}
module.exports = SelectContract

@ -8,7 +8,7 @@ module.exports = composePlugins(withNx(), (config) => {
// add public path
config.output.publicPath = '/'
// souce-map loader
// source-map loader
config.module.rules.push({
test: /\.js$/,
use: ["source-map-loader"],

@ -26,7 +26,7 @@ module.exports = {
.assert.containsText('.sidepanel h6[data-id="sidePanelSwapitTitle"]', 'SOLIDITY COMPILER')
.waitForElementNotVisible('.pinned-panel h6[data-id="sidePanelSwapitTitle"]')
},
'Should pin a plugin while a another plugin is already pinned': function (browser: NightwatchBrowser) {
'Should pin a plugin while an another plugin is already pinned': function (browser: NightwatchBrowser) {
browser.waitForElementVisible('[data-id="movePluginToRight"]')
.click('[data-id="movePluginToRight"]')
.waitForElementVisible('[data-id="movePluginToLeft"]')

@ -101,7 +101,7 @@ module.exports = {
browser.assert.equal(content, 'testing')
})
},
'Should have a artifacts file with JSON test data #group1 #group3 #group5 #group7': function (browser: NightwatchBrowser) {
'Should have an artifacts file with JSON test data #group1 #group3 #group5 #group7': function (browser: NightwatchBrowser) {
browser.waitForElementVisible('*[data-id="remixIdeSidePanel"]', 5000)
.click('*[data-id="treeViewLitreeViewItemtest_contracts/artifacts"]')
.openFile('test_contracts/artifacts/Storage_metadata.json')
@ -111,7 +111,7 @@ module.exports = {
browser.assert.equal(metadata.test, 'data')
})
},
'Should have a empty workspace #group1 #group3 #group5 #group7': function (browser: NightwatchBrowser) {
'Should have an empty workspace #group1 #group3 #group5 #group7': function (browser: NightwatchBrowser) {
browser.waitForElementVisible('*[data-id="remixIdeSidePanel"]', 5000)
.switchWorkspace('emptyspace')
},

@ -90,7 +90,7 @@ const tests = {
.setValue('input[data-id="surgePassword"]', surgePassword)
.setValue('input[data-id="surgeSubdomain"]', surgeSubdomain)
.setValue('input[data-id="functionTitle0x6057361d"]', 'Function Store Title')
.setValue('input[data-id="functionTitle0x2e64cec1"]', 'Function Retrive Title')
.setValue('input[data-id="functionTitle0x2e64cec1"]', 'Function Retrieve Title')
.execute((function() {
document.querySelector('input[data-id="uploadLogo"]').classList.remove('d-none');
}))
@ -176,7 +176,7 @@ const tests = {
})
})
.assert.containsText('*[data-id="functionTitle0x6057361d"]', 'Function Store Title')
.assert.containsText('*[data-id="functionTitle0x2e64cec1"]', 'Function Retrive Title')
.assert.containsText('*[data-id="functionTitle0x2e64cec1"]', 'Function Retrieve Title')
.assert.containsText('*[data-id="dappTitle"]', 'Storage')
.assert.containsText('*[data-id="dappInstructions"]', 'Store & retrieve value in a variable')
.assert.elementPresent('.fa-twitter.btn', 'Twitter icon should be present')
@ -191,9 +191,9 @@ const tests = {
.getLocation('*[data-id="function0x6057361d"]', function (result: any) {
const funcStoreLocation = result.value
browser.getLocation('*[data-id="function0x2e64cec1"]', function (result: any) {
const funcRetriveLocation = result.value
browser.assert.strictEqual(funcStoreLocation.y, funcRetriveLocation.y, 'Both functions should be on the same horizontal line')
browser.assert.ok(funcStoreLocation.x > funcRetriveLocation.x, 'Function Store should be on the right of Function Retrive')
const funcRetrieveLocation = result.value
browser.assert.strictEqual(funcStoreLocation.y, funcRetrieveLocation.y, 'Both functions should be on the same horizontal line')
browser.assert.ok(funcStoreLocation.x > funcRetrieveLocation.x, 'Function Store should be on the right of Function Retrieve')
})
})
.getAttribute('a[data-id="viewSourceCode"]', 'href', function (result) {

@ -527,7 +527,7 @@ async function installFoundry(): Promise<void> {
server.stdout.on('data', function (data) {
console.log(data.toString())
if (
data.toString().includes("foundryup: done!")
data.toString().includes("foundryup: use - chisel 0.3.0")
) {
console.log('resolving')
resolve()

@ -158,7 +158,7 @@ const sources = [
'Untitled5.sol': { content: 'import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v2.3.0/contracts/token/ERC20/ERC20.sol"; contract test8 {}' }
},
{
'Untitled6.sol': { content: 'import "https://github.com/OpenZeppelin/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol"; contract test10 {}' }
'Untitled6.sol': { content: 'import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol"; contract test10 {}' }
},
{
'Untitled7.sol': { content: 'import "https://raw.githubusercontent.com/OpenZeppelin/openzeppelin-contracts/master/contracts/token/ERC20/ERC20.sol"; contract test11 {}' }

@ -7,7 +7,7 @@ module.exports = {
before: function (browser: NightwatchBrowser, done: VoidFunction) {
// this test suite also contribute testing https://github.com/ethereum/remix/pull/1497 and https://github.com/ethereum/remix-ide/pull/2898
// quick explanation:
// the goal of https://github.com/ethereum/remix-ide/pull/2898 is to keep track of all the compiled contracts an not only the last one.
// the goal of https://github.com/ethereum/remix-ide/pull/2898 is to keep track of all the compiled contracts a not only the last one.
// this introduce an issue: if 2 compiled contracts have the same name, the second one override the first which is not wanted.
// fix's delivered by https://github.com/ethereum/remix/pull/1497: instead of getting contract by name,
// which result in name clashing we process the whole contract object (which contain bytecode, deployedbytecode, ...)

File diff suppressed because one or more lines are too long

@ -0,0 +1,154 @@
'use strict'
import { NightwatchBrowser } from 'nightwatch'
import init from '../helpers/init'
declare global {
interface Window { testplugin: { name: string, url: string }; }
}
const tests = {
'@disabled': true,
before: function (browser: NightwatchBrowser, done: VoidFunction) {
init(browser, done, null)
},
'Should show fork and delete VM state icons #group1': function (browser: NightwatchBrowser) {
browser
.clickLaunchIcon('udapp')
.waitForElementVisible('*[data-id="selected-provider-vm-cancun"]')
.waitForElementVisible('*[data-id="fork-state-icon"]')
.waitForElementVisible('*[data-id="delete-state-icon"]')
},
'Should show toaster while trying fork and delete VM state without state #group1': function (browser: NightwatchBrowser) {
browser
.waitForElementVisible('*[data-id="fork-state-icon"]')
.click('*[data-id="fork-state-icon"]')
.waitForElementVisible(
{
selector: "//*[@data-shared='tooltipPopup' and contains(.,'State not available to fork')]",
locateStrategy: 'xpath'
}
)
.waitForElementVisible('*[data-id="delete-state-icon"]')
.click('*[data-id="delete-state-icon"]')
.waitForElementVisible(
{
selector: "//*[@data-shared='tooltipPopup' and contains(.,'State not available to reset')]",
locateStrategy: 'xpath'
}
)
},
'Should fork state successfully #group1': function (browser: NightwatchBrowser) {
browser
.openFile('contracts')
.openFile('contracts/1_Storage.sol')
.verifyContracts(['Storage'])
.clickLaunchIcon('udapp')
.click('[data-id="Deploy - transact (not payable)"]')
.clickInstance(0)
.clickFunction('store - transact (not payable)', { types: 'uint256 num', values: '"55"' })
.testFunction('last',
{
status: '0x1 Transaction mined and execution succeed',
'decoded input': { 'uint256 num': '55' }
})
.clickFunction('retrieve - call')
.testFunction('last',
{
'decoded output': { '0': 'uint256: 55' }
})
.click('*[data-id="fork-state-icon"]')
.waitForElementVisible('*[data-id="udappNotifyModalDialogModalTitle-react"]')
.click('input[data-id="modalDialogForkState"]')
.setValue('input[data-id="modalDialogForkState"]', 'forkedState_1')
.modalFooterOKClick('udappNotify')
// check toaster for forked state
.waitForElementVisible(
{
selector: '//*[@data-shared="tooltipPopup" and contains(.,"New environment \'forkedState_1\' created with forked state.")]',
locateStrategy: 'xpath'
}
)
// check if forked state is selected as current environment
.assert.elementPresent('*[data-id="selected-provider-vm-fs-forkedState_1"]')
// check if forked state file is created with expected details
.openFile('.states/forked_states/forkedState_1.json')
.getEditorValue((content) => {
browser.assert.ok(content.indexOf(`"latestBlockNumber": "0x2"`) !== -1)
browser.assert.ok(content.indexOf(`"stateName": "forkedState_1"`) !== -1)
browser.assert.ok(content.indexOf(`"forkName": "cancun"`) !== -1)
browser.assert.ok(content.indexOf(`"savingTimestamp":`) !== -1)
browser.assert.ok(content.indexOf(`"db":`) !== -1)
browser.assert.ok(content.indexOf(`"blocks":`) !== -1)
})
},
'Should show fork states provider in environment explorer & make txs using forked state #group1': function (browser: NightwatchBrowser) {
browser
.clickLaunchIcon('udapp')
.waitForElementVisible('[data-id="settingsSelectEnvOptions"]')
.click('[data-id="settingsSelectEnvOptions"] button')
.waitForElementVisible(`[data-id="dropdown-item-another-chain"]`)
.click(`[data-id="dropdown-item-another-chain"]`)
.assert.visible('[data-id="remixUIGSDeploy to an In-browser Forked State."]')
.assert.elementPresent('[data-id="remixUIGSforkedState_1"]')
.assert.elementPresent('[data-id="vm-fs-forkedState_1-pinned"]')
.assert.textContains('[data-id="vm-fs-forkedState_1desc"]', 'Latest Block: 2')
.assert.not.elementPresent('[data-id="remixUIGSforkedState_2"]')
.switchEnvironment('vm-cancun')
.openFile('contracts/1_Storage.sol')
.verifyContracts(['Storage'])
.clickLaunchIcon('udapp')
.click('*[data-id="Deploy - transact (not payable)"]')
.click('*[data-id="fork-state-icon"]')
.waitForElementVisible('*[data-id="udappNotifyModalDialogModalTitle-react"]')
.click('input[data-id="modalDialogForkState"]')
.setValue('input[data-id="modalDialogForkState"]', 'forkedState_2')
.modalFooterOKClick('udappNotify')
.waitForElementVisible('*[data-shared="tooltipPopup"]', 10000)
.assert.textContains('*[data-shared="tooltipPopup"]', `New environment 'forkedState_2' created with forked state.`)
// check if 'forkedState_2' is selected as current environment
.assert.elementPresent('*[data-id="selected-provider-vm-fs-forkedState_2"]')
// check if 'forkedState_2' is present in environment explorer
.assert.elementPresent('[data-id="remixUIGSforkedState_2"]')
// check if 'forkedState_2' is pinned in environment explorer
.assert.elementPresent('[data-id="vm-fs-forkedState_2-pinned"]')
// 'forkedState_2' should have 3 blocks
.assert.textContains('[data-id="vm-fs-forkedState_2desc"]', 'Latest Block: 3')
.click('*[data-id="Deploy - transact (not payable)"]')
.clickInstance(0)
.clickFunction('store - transact (not payable)', { types: 'uint256 num', values: '"555"' })
// block number should be 5 after 2 txs
.testFunction('last',
{
status: '0x1 Transaction mined and execution succeed',
'block number': '5',
'decoded input': { 'uint256 num': '555' }
})
},
'Should delete state successfully #group1': function (browser: NightwatchBrowser) {
browser
.switchEnvironment('vm-cancun')
.openFile('contracts/1_Storage.sol')
.verifyContracts(['Storage'])
.clickLaunchIcon('udapp')
.click('*[data-id="Deploy - transact (not payable)"]')
.pause(10000)
.assert.textContains('*[data-id="deployedContractsBadge"]', '1')
.click(('*[data-id="delete-state-icon"]'))
.waitForElementVisible('*[data-id="udappNotifyModalDialogModalTitle-react"]')
.waitForElementVisible('*[data-id="deleteVmStateModal"]')
.modalFooterOKClick('udappNotify')
.waitForElementVisible('*[data-shared="tooltipPopup"]', 10000)
// check if toaster is shown
.assert.textContains('*[data-shared="tooltipPopup"]', `VM state reset successfully.`)
// check that there are no instances
.assert.textContains('*[data-id="deployedContractsBadge"]', '0')
// check if state file is deleted
.openFile('.states/vm-cancun')
.assert.not.elementPresent('*[data-id="treeViewDivDraggableItem.states/vm-cancun/state.json"]')
}
}
module.exports = {
...tests
};

@ -434,7 +434,7 @@ module.exports = {
.click('*[data-id="saveGitHubCredentials"]')
.modalFooterOKClick('github-credentials-error')
},
'check source controle panel #group5': function (browser: NightwatchBrowser) {
'check source control panel #group5': function (browser: NightwatchBrowser) {
browser
.waitForElementVisible('*[data-id="sourcecontrol-panel"]')
.click('*[data-id="sourcecontrol-panel"]')
@ -448,7 +448,7 @@ module.exports = {
.clickLaunchIcon('filePanel')
.switchWorkspace('default_workspace')
},
'check source controle panel again #group5': function (browser: NightwatchBrowser) {
'check source control panel again #group5': function (browser: NightwatchBrowser) {
browser
.pause(1000)
.clickLaunchIcon('dgit')
@ -485,7 +485,7 @@ module.exports = {
'Incorrect content')
})
},
'check source controle panel for uniswap #group5': function (browser: NightwatchBrowser) {
'check source control panel for uniswap #group5': function (browser: NightwatchBrowser) {
browser
.pause(5000)
.clickLaunchIcon('dgit')

@ -25,7 +25,7 @@ declare module 'nightwatch' {
journalLastChildIncludes(val: string): NightwatchBrowser
executeScriptInTerminal(script: string): NightwatchBrowser
clearEditableContent(cssSelector: string): NightwatchBrowser
journalChildIncludes(val: string, opts = {shouldHaveOnlyOneOccurence: boolean}): NightwatchBrowser
journalChildIncludes(val: string, opts = {shouldHaveOnlyOneOccurrence: boolean}): NightwatchBrowser
debugTransaction(index: number): NightwatchBrowser
checkElementStyle(cssSelector: string, styleProperty: string, expectedResult: string): NightwatchBrowser
openFile(name: string): NightwatchBrowser
@ -57,7 +57,7 @@ declare module 'nightwatch' {
journalLastChild(val: string): NightwatchBrowser
checkTerminalFilter(filter: string, test: string, notContain: boolean): NightwatchBrowser
noWorkerErrorFor(version: string): NightwatchBrowser
validateValueInput(selector: string, valueTosSet: string[], expectedValue: string): NightwatchBrowser
validateValueInput(selector: string, valueToSet: string[], expectedValue: string): NightwatchBrowser
checkAnnotations(type: string): NightwatchBrowser
checkAnnotationsNotPresent(type: string): NightwatchBrowser
getLastTransactionHash(callback: (hash: string) => void)

@ -1 +1 @@
import "https://github.com/OpenZeppelin/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol"; contract test11 {}
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol"; contract test11 {}

@ -1,9 +1,9 @@
This document includes:
This document describes:
- how to update remix.ethereum.org.
- how to update remix-alpha.ethereum.org.
- how to release remix IDE.
# remix IDE release
# Remix IDE Release
- git fetch origin master
- git checkout origin/master
@ -12,7 +12,7 @@ This document includes:
- merge PR
- git fetch origin master
- git checkout origin/master
- git tag v(version-number)
- git tag v<version-number>
- git push --tags
- github-changes -o ethereum -r remix-ide -a --only-pulls --use-commit-body --only-merges --between-tags previous_version...next_version
- publish a release in github using the changelog
@ -23,7 +23,7 @@ This document includes:
- npm publish
- after remix_live is updated, drop the zip (from https://github.com/ethereum/remix-live/) to the release.
# remix-ide beta release
# Remix IDE Beta Release
- git fetch origin master
- git checkout origin/master
- git checkout -b bumpVersion
@ -31,7 +31,7 @@ This document includes:
- merge PR
- git fetch origin master
- git checkout origin/master
- git tag v(version-number) (with "vx.x.x-beta.1")
- git tag v<version-number> (with "vx.x.x-beta.1")
- git push --tags
- github-changes -o ethereum -r remix-ide -a --only-pulls --use-commit-body --only-merges --between-tags previous_version...next_version
- publish a beta release in github using the changelog
@ -41,7 +41,7 @@ This document includes:
This is not strictly speaking a release. Updating the remix site is done through the Travis build:
- git co -b remix_live origin/remix_live
- git checkout -b remix_live origin/remix_live
- git reset --hard -master-commit-hash-
- git push -f origin remix_live

@ -26,21 +26,21 @@ import { WalkthroughService } from './walkthroughService'
import { OffsetToLineColumnConverter, CompilerMetadata, CompilerArtefacts, FetchAndCompile, CompilerImports, GistHandler } from '@remix-project/core-plugin'
import {Registry} from '@remix-project/remix-lib'
import {ConfigPlugin} from './app/plugins/config'
import {StoragePlugin} from './app/plugins/storage'
import {Layout} from './app/panels/layout'
import {NotificationPlugin} from './app/plugins/notification'
import {Blockchain} from './blockchain/blockchain'
import {MergeVMProvider, LondonVMProvider, BerlinVMProvider, ShanghaiVMProvider, CancunVMProvider} from './app/providers/vm-provider'
import {MainnetForkVMProvider} from './app/providers/mainnet-vm-fork-provider'
import {SepoliaForkVMProvider} from './app/providers/sepolia-vm-fork-provider'
import {GoerliForkVMProvider} from './app/providers/goerli-vm-fork-provider'
import {CustomForkVMProvider} from './app/providers/custom-vm-fork-provider'
import {HardhatProvider} from './app/providers/hardhat-provider'
import {GanacheProvider} from './app/providers/ganache-provider'
import {FoundryProvider} from './app/providers/foundry-provider'
import {ExternalHttpProvider} from './app/providers/external-http-provider'
import { Registry } from '@remix-project/remix-lib'
import { ConfigPlugin } from './app/plugins/config'
import { StoragePlugin } from './app/plugins/storage'
import { Layout } from './app/panels/layout'
import { NotificationPlugin } from './app/plugins/notification'
import { Blockchain } from './blockchain/blockchain'
import { MergeVMProvider, LondonVMProvider, BerlinVMProvider, ShanghaiVMProvider, CancunVMProvider } from './app/providers/vm-provider'
import { MainnetForkVMProvider } from './app/providers/mainnet-vm-fork-provider'
import { SepoliaForkVMProvider } from './app/providers/sepolia-vm-fork-provider'
import { GoerliForkVMProvider } from './app/providers/goerli-vm-fork-provider'
import { CustomForkVMProvider } from './app/providers/custom-vm-fork-provider'
import { HardhatProvider } from './app/providers/hardhat-provider'
import { GanacheProvider } from './app/providers/ganache-provider'
import { FoundryProvider } from './app/providers/foundry-provider'
import { ExternalHttpProvider } from './app/providers/external-http-provider'
import { EnvironmentExplorer } from './app/providers/environment-explorer'
import { FileDecorator } from './app/plugins/file-decorator'
import { CodeFormat } from './app/plugins/code-format'
@ -58,7 +58,7 @@ import { xtermPlugin } from './app/plugins/electron/xtermPlugin'
import { ripgrepPlugin } from './app/plugins/electron/ripgrepPlugin'
import { compilerLoaderPlugin, compilerLoaderPluginDesktop } from './app/plugins/electron/compilerLoaderPlugin'
import { appUpdaterPlugin } from './app/plugins/electron/appUpdaterPlugin'
import { remixAIDesktopPlugin } from './app/plugins/electron/remixAIDesktopPlugin'
import { remixAIDesktopPlugin } from './app/plugins/electron/remixAIDesktopPlugin'
import { RemixAIPlugin } from './app/plugins/remixAIPlugin'
import { SlitherHandleDesktop } from './app/plugins/electron/slitherPlugin'
import { SlitherHandle } from './app/files/slither-handle'
@ -72,9 +72,9 @@ import { Matomo } from './app/plugins/matomo'
import { TemplatesSelectionPlugin } from './app/plugins/templates-selection/templates-selection-plugin'
const isElectron = require('is-electron')
import isElectron from 'is-electron'
const remixLib = require('@remix-project/remix-lib')
import * as remixLib from '@remix-project/remix-lib'
import { QueryParams } from '@remix-project/remix-lib'
import { SearchPlugin } from './app/tabs/search'
@ -82,27 +82,27 @@ import { ScriptRunnerUIPlugin } from './app/tabs/script-runner-ui'
import { ElectronProvider } from './app/files/electronProvider'
const Storage = remixLib.Storage
const RemixDProvider = require('./app/files/remixDProvider')
const Config = require('./config')
import RemixDProvider from './app/files/remixDProvider'
import Config from './config'
const FileManager = require('./app/files/fileManager')
import FileManager from './app/files/fileManager'
import FileProvider from "./app/files/fileProvider"
import { appPlatformTypes } from '@remix-ui/app'
const DGitProvider = require('./app/files/dgitProvider')
const WorkspaceFileProvider = require('./app/files/workspaceFileProvider')
import DGitProvider from './app/files/dgitProvider'
import WorkspaceFileProvider from './app/files/workspaceFileProvider'
const PluginManagerComponent = require('./app/components/plugin-manager-component')
import PluginManagerComponent from './app/components/plugin-manager-component'
const CompileTab = require('./app/tabs/compile-tab')
const SettingsTab = require('./app/tabs/settings-tab')
const AnalysisTab = require('./app/tabs/analysis-tab')
const { DebuggerTab } = require('./app/tabs/debugger-tab')
const TestTab = require('./app/tabs/test-tab')
const FilePanel = require('./app/panels/file-panel')
const Editor = require('./app/editor/editor')
const Terminal = require('./app/panels/terminal')
const { TabProxy } = require('./app/panels/tab-proxy.js')
import CompileTab from './app/tabs/compile-tab'
import SettingsTab from './app/tabs/settings-tab'
import AnalysisTab from './app/tabs/analysis-tab'
import DebuggerTab from './app/tabs/debugger-tab'
import TestTab from './app/tabs/test-tab'
import Filepanel from './app/panels/file-panel'
import Editor from './app/editor/editor'
import Terminal from './app/panels/terminal'
import TabProxy from './app/panels/tab-proxy.js'
const _paq = (window._paq = window._paq || [])
@ -115,16 +115,49 @@ export class platformApi {
}
}
type Components = {
filesProviders: {
browser?: any
localhost?: any
workspace?: any
electron?: any
}
}
class AppComponent {
appManager: RemixAppManager
queryParams: QueryParams
private _components: Components
panels: any
workspace: any
engine: RemixEngine
matomoConfAlreadySet: any
matomoCurrentSetting: any
showMatomo: boolean
walkthroughService: WalkthroughService
platform: 'desktop' | 'web'
gistHandler: GistHandler
themeModule: ThemeModule
localeModule: LocaleModule
notification: NotificationPlugin
layout: Layout
mainview: any
menuicons: VerticalIcons
sidePanel: SidePanel
hiddenPanel: HiddenPanel
pinnedPanel: PinnedPanel
popupPanel: PopupPanel
statusBar: StatusBar
settings: SettingsTab
constructor() {
const PlatFormAPi = new platformApi()
Registry.getInstance().put({
api: PlatFormAPi,
name: 'platform'
})
this.appManager = new RemixAppManager({})
this.appManager = new RemixAppManager()
this.queryParams = new QueryParams()
this._components = {}
this._components = {} as Components
// setup storage
const configStorage = new Storage('config-v0.8:')
@ -161,7 +194,6 @@ class AppComponent {
name: 'fileproviders'
})
}
async run() {
@ -184,7 +216,7 @@ class AppComponent {
this.matomoConfAlreadySet = Registry.getInstance().get('config').api.exists('settings/matomo-analytics')
this.matomoCurrentSetting = Registry.getInstance().get('config').api.get('settings/matomo-analytics')
let electronTracking = window.electronAPI ? await window.electronAPI.canTrackMatomo() : false
const electronTracking = (window as any).electronAPI ? await (window as any).electronAPI.canTrackMatomo() : false
const lastMatomoCheck = window.localStorage.getItem('matomo-analytics-consent')
const sixMonthsAgo = new Date();
@ -193,11 +225,11 @@ class AppComponent {
const e2eforceMatomoToShow = window.localStorage.getItem('showMatomo') && window.localStorage.getItem('showMatomo') === 'true'
const contextShouldShowMatomo = matomoDomains[window.location.hostname] || e2eforceMatomoToShow || electronTracking
const shouldRenewConsent = this.matomoCurrentSetting === false && (!lastMatomoCheck || new Date(Number(lastMatomoCheck)) < sixMonthsAgo) // it is set to false for more than 6 months.
this.showMatomo = contextShouldShowMatomo && (!this.matomoConfAlreadySet || shouldRenewConsent)
this.showMatomo = contextShouldShowMatomo && (!this.matomoConfAlreadySet || shouldRenewConsent)
if (this.showMatomo && shouldRenewConsent) {
_paq.push(['trackEvent', 'Matomo', 'refreshMatomoPermissions']);
}
}
this.walkthroughService = new WalkthroughService(appManager)
@ -387,7 +419,7 @@ class AppComponent {
ganacheProvider,
foundryProvider,
externalHttpProvider,
environmentExplorer,
environmentExplorer,
this.walkthroughService,
search,
solidityumlgen,
@ -456,10 +488,10 @@ class AppComponent {
this.popupPanel = new PopupPanel()
const pluginManagerComponent = new PluginManagerComponent(appManager, this.engine)
const filePanel = new FilePanel(appManager, contentImport)
const filePanel = new Filepanel(appManager, contentImport)
this.statusBar = new StatusBar(filePanel, this.menuicons)
const landingPage = new LandingPage(appManager, this.menuicons, fileManager, filePanel, contentImport)
this.settings = new SettingsTab(Registry.getInstance().get('config').api, editor, appManager)
this.settings = new SettingsTab(Registry.getInstance().get('config').api, editor)//, appManager)
this.engine.register([this.menuicons, landingPage, this.hiddenPanel, this.sidePanel, this.statusBar, filePanel, pluginManagerComponent, this.settings, this.pinnedPanel, this.popupPanel])
@ -514,7 +546,7 @@ class AppComponent {
async activate() {
const queryParams = new QueryParams()
const params = queryParams.get()
const params: any = queryParams.get()
try {
this.engine.register(await this.appManager.registeredPlugins())
@ -610,10 +642,11 @@ class AppComponent {
}
if (params.call) {
const callDetails = params.call.split('//')
const callDetails: any = params.call.split('//')
if (callDetails.length > 1) {
this.appManager.call('notification', 'toast', `initiating ${callDetails[0]} and calling "${callDetails[1]}" ...`)
// @todo(remove the timeout when activatePlugin is on 0.3.0)
//@ts-ignore
await this.appManager.call(...callDetails).catch(console.error)
}
}
@ -629,6 +662,7 @@ class AppComponent {
// @todo(remove the timeout when activatePlugin is on 0.3.0)
try {
//@ts-ignore
await this.appManager.call(...callDetails)
} catch (e) {
console.error(e)

@ -15,7 +15,7 @@ const profile = {
export class MainPanel extends AbstractPanel {
element: HTMLDivElement
dispatch: React.Dispatch<any> = () => {}
constructor(config) {
constructor(config = null) {
super(profile)
this.element = document.createElement('div')
this.element.setAttribute('data-id', 'mainPanelPluginsContainer')

@ -19,7 +19,7 @@ const profile = {
maintainedBy: "Remix"
}
class PluginManagerComponent extends ViewPlugin {
export default class PluginManagerComponent extends ViewPlugin {
constructor (appManager, engine) {
super(profile)
this.appManager = appManager

@ -24,7 +24,7 @@ export class PopupPanel extends AbstractPanel {
dispatch: React.Dispatch<any> = () => { }
appStateDispatch: React.Dispatch<AppAction> = () => { }
constructor(config) {
constructor(config = null) {
super(profile)
this.event = new EventEmitter()
}

@ -5,7 +5,6 @@ import { EditorUI } from '@remix-ui/editor' // eslint-disable-line
import { Plugin } from '@remixproject/engine'
import * as packageJson from '../../../../../package.json'
import { PluginViewWrapper } from '@remix-ui/helper'
import { commitChange } from '@remix-ui/git'
const EventManager = require('../../lib/events')
@ -17,7 +16,7 @@ const profile = {
methods: ['highlight', 'discardHighlight', 'clearAnnotations', 'addLineText', 'discardLineTexts', 'addAnnotation', 'gotoLine', 'revealRange', 'getCursorPosition', 'open', 'addModel','addErrorMarker', 'clearErrorMarkers', 'getText', 'getPositionAt', 'openReadOnly'],
}
class Editor extends Plugin {
export default class Editor extends Plugin {
constructor () {
super(profile)
@ -91,7 +90,7 @@ class Editor extends Plugin {
}
render () {
return <div ref={(element)=>{
return <div ref={(element)=>{
this.ref = element
this.ref.currentContent = () => this.currentContent() // used by e2e test
this.ref.setCurrentContent = (value) => {
@ -103,7 +102,7 @@ class Editor extends Plugin {
this.ref.gotoLine = (line, column) => this.gotoLine(line, column || 0)
this.ref.getCursorPosition = () => this.getCursorPosition()
this.ref.addDecoration = (marker, filePath, typeOfDecoration) => this.addDecoration(marker, filePath, typeOfDecoration)
this.ref.clearDecorationsByPlugin = (filePath, plugin, typeOfDecoration) => this.clearDecorationsByPlugin(filePath, plugin, typeOfDecoration)
this.ref.clearDecorationsByPlugin = (filePath, plugin, typeOfDecoration) => this.clearDecorationsByPlugin(filePath, plugin, typeOfDecoration)
this.ref.keepDecorationsFor = (name, typeOfDecoration) => this.keepDecorationsFor(name, typeOfDecoration)
}} id='editorView'>
<PluginViewWrapper plugin={this} />
@ -250,7 +249,7 @@ class Editor extends Plugin {
*/
async _createSession (path, content, mode, readOnly) {
if (!this.activated) return
this.emit('addModel', content, mode, path, readOnly || this.readOnlySessions[path])
return {
path,
@ -549,7 +548,7 @@ class Editor extends Plugin {
decoration.from = from
const { currentDecorations, registeredDecorations } = this.api.addDecoration(decoration, path, typeOfDecoration)
if (!this.registeredDecorations[typeOfDecoration][filePath]) this.registeredDecorations[typeOfDecoration][filePath] = []
if (!this.registeredDecorations[typeOfDecoration][filePath]) this.registeredDecorations[typeOfDecoration][filePath] = []
this.registeredDecorations[typeOfDecoration][filePath].push(...registeredDecorations)
if (!this.currentDecorations[typeOfDecoration][filePath]) this.currentDecorations[typeOfDecoration][filePath] = []
this.currentDecorations[typeOfDecoration][filePath].push(...currentDecorations)
@ -602,5 +601,3 @@ class Editor extends Plugin {
return this.api.getPositionAt(offset)
}
}
module.exports = Editor

@ -28,7 +28,7 @@ const profile: LibraryProfile = {
, 'getGitHubUser', 'remotebranches', 'remotecommits', 'repositories', 'getCommitChanges', 'compareBranches'],
kind: 'file-system'
}
class DGitProvider extends Plugin<any, CustomRemixApi> {
export default class DGitProvider extends Plugin<any, CustomRemixApi> {
constructor() {
super(profile)
}

@ -26,7 +26,7 @@ const profile = {
'readFile', 'copyFile', 'copyDir', 'rename', 'mkdir', 'readdir', 'dirList', 'fileList', 'remove', 'getCurrentFile', 'getFile',
'getFolder', 'setFile', 'switchFile', 'refresh', 'getProviderOf', 'getProviderByName', 'getPathFromUrl', 'getUrlFromPath',
'saveCurrentFile', 'setBatchFiles', 'isGitRepo', 'isFile', 'isDirectory', 'hasGitSubmodule', 'copyFolderToJson', 'diff',
'hasGitSubmodules'
'hasGitSubmodules', 'getOpenedFiles'
],
kind: 'file-system'
}
@ -40,7 +40,7 @@ const errorMsg = {
const createError = (err) => {
return new Error(`${errorMsg[err.code]} ${err.message || ''}`)
}
class FileManager extends Plugin {
export default class FileManager extends Plugin {
mode: string
openedFiles: any
editor: any

@ -1,7 +1,7 @@
'use strict'
import FileProvider from "./fileProvider"
module.exports = class RemixDProvider extends FileProvider {
export default class RemixDProvider extends FileProvider {
constructor (appManager) {
super('localhost')
this._appManager = appManager

@ -3,7 +3,7 @@
const EventManager = require('events')
import FileProvider from "./fileProvider"
class WorkspaceFileProvider extends FileProvider {
export default class WorkspaceFileProvider extends FileProvider {
constructor () {
super('')
this.workspacesPath = '.workspaces'
@ -18,10 +18,10 @@ class WorkspaceFileProvider extends FileProvider {
})
}).catch((e) => {
console.log(e)
})
})
} catch (e) {
// we don't need to log error if this throws an error
}
}
}
setWorkspace (workspace) {

@ -55,7 +55,7 @@ const profile = {
version: packageJson.version,
maintainedBy: 'Remix'
}
module.exports = class Filepanel extends ViewPlugin {
export default class Filepanel extends ViewPlugin {
constructor(appManager, contentImport) {
super(profile)
this.registry = Registry.getInstance()

@ -12,7 +12,7 @@ const profile: Profile = {
interface panelState {
active: boolean
plugin: Plugin
minimized: boolean
minimized?: boolean
}
interface panels {
tabs: panelState

@ -10,7 +10,7 @@ const profile = {
kind: 'other'
}
export class TabProxy extends Plugin {
export default class TabProxy extends Plugin {
constructor (fileManager, editor) {
super(profile)
this.event = new EventEmitter()

@ -24,7 +24,7 @@ const profile = {
version: packageJson.version
}
class Terminal extends Plugin {
export default class Terminal extends Plugin {
fileImport: CompilerImports
event: any
globalRegistry: Registry
@ -163,4 +163,3 @@ class Terminal extends Plugin {
}
}
module.exports = Terminal

@ -7,13 +7,12 @@ import * as packageJson from '../../../../../package.json'
const profile = {
name: 'dgit',
displayName: 'Git',
desciption: 'Git plugin for Remix',
description: 'Git plugin for Remix',
methods: ['open', 'init'],
events: [''],
version: packageJson.version,
maintainedBy: 'Remix',
permission: true,
description: 'Use this plugin to interact with your git repositories',
location: 'sidePanel',
icon: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTIxLjAwNyA4LjIyMTY4QzIxLjAxMDUgNy41Mjc5MiAyMC44MjA3IDYuODQ2ODkgMjAuNDU5MSA2LjI1NDg1QzIwLjA5NzQgNS42NjI4MSAxOS41NzggNS4xODMxNSAxOC45NTkyIDQuODY5NTdDMTguMzQwMyA0LjU1NiAxNy42NDYzIDQuNDIwOTEgMTYuOTU1MSA0LjQ3OTQxQzE2LjI2MzcgNC41Mzc5MyAxNS42MDI1IDQuNzg3NzMgMTUuMDQ1IDUuMjAwODVDMTQuNDg3NyA1LjYxMzk3IDE0LjA1NjMgNi4xNzQwOSAxMy43OTkzIDYuODE4NUMxMy41NDI0IDcuNDYyOSAxMy40Njk3IDguMTY2MTMgMTMuNTg5OCA4Ljg0OTQ0QzEzLjcwOTkgOS41MzI3NCAxNC4wMTc3IDEwLjE2OTIgMTQuNDc4OSAxMC42ODc0QzE0Ljk0MDIgMTEuMjA1NiAxNS41MzY3IDExLjU4NTIgMTYuMjAxNSAxMS43ODM2QzE1Ljk1NiAxMi4yODI0IDE1LjU3NjMgMTIuNzAzIDE1LjEwNDkgMTIuOTk3OUMxNC42MzM2IDEzLjI5MjkgMTQuMDg5NCAxMy40NTA1IDEzLjUzMzQgMTMuNDUzMkgxMC41NDRDOS40MzcyNiAxMy40NTcxIDguMzcxNjMgMTMuODcyNyA3LjU1NDUxIDE0LjYxOTFWNy4zOTgwOUM4LjQ2MTg0IDcuMjEyODggOS4yNjgwOCA2LjY5NzM3IDkuODE2OTIgNS45NTE1MUMxMC4zNjU4IDUuMjA1NjUgMTAuNjE4MSA0LjI4MjU2IDEwLjUyNSAzLjM2MTIxQzEwLjQzMTkgMi40Mzk4NyAxMC4wMDAxIDEuNTg1OSA5LjMxMzE2IDAuOTY0ODczQzguNjI2MjQgMC4zNDM4NDUgNy43MzMxOSAwIDYuODA3MTYgMEM1Ljg4MTEyIDAgNC45ODgwNyAwLjM0Mzg0NSA0LjMwMTE0IDAuOTY0ODczQzMuNjE0MjIgMS41ODU5IDMuMTgyMzYgMi40Mzk4NyAzLjA4OTI4IDMuMzYxMjFDMi45OTYyIDQuMjgyNTYgMy4yNDg1NSA1LjIwNTY1IDMuNzk3MzkgNS45NTE1MUM0LjM0NjIzIDYuNjk3MzcgNS4xNTI0NyA3LjIxMjg4IDYuMDU5OCA3LjM5ODA5VjE2LjUxNTlDNS4xNTQxOCAxNi42ODkxIDQuMzQzMjMgMTcuMTg3NyAzLjc3OTkzIDE3LjkxNzZDMy4yMTY2MyAxOC42NDc2IDIuOTM5OTIgMTkuNTU4NSAzLjAwMTk3IDIwLjQ3ODVDMy4wNjQwMyAyMS4zOTg0IDMuNDYwNTcgMjIuMjYzOSA0LjExNjggMjIuOTExNUM0Ljc3MzAzIDIzLjU1OTIgNS42NDM2IDIzLjk0NDQgNi41NjQyNyAyMy45OTQ0QzcuNDg0OTYgMjQuMDQ0NSA4LjM5MjExIDIzLjc1NTggOS4xMTQ2NCAyMy4xODNDOS44MzcxOCAyMi42MTAyIDEwLjMyNTEgMjEuNzkyOCAxMC40ODY1IDIwLjg4NUMxMC42NDc4IDE5Ljk3NzEgMTAuNDcxNCAxOS4wNDE3IDkuOTkwNDggMTguMjU1QzkuNTA5NTcgMTcuNDY4MyA4Ljc1NzQxIDE2Ljg4NDggNy44NzU4OCAxNi42MTQ1QzguMTIxNzYgMTYuMTE2MiA4LjUwMTY3IDE1LjY5NjMgOC45NzI5NiAxNS40MDE5QzkuNDQ0MjYgMTUuMTA3NCA5Ljk4ODI3IDE0Ljk1MDMgMTAuNTQ0IDE0Ljk0NzlIMTMuNTMzNEMxNC40NjYxIDE0Ljk0MzYgMTUuMzc0MiAxNC42NDg2IDE2LjEzMTMgMTQuMTAzOUMxNi44ODg0IDEzLjU1OTIgMTcuNDU2OCAxMi43OTIgMTcuNzU3NSAxMS45MDkxQzE4LjY1MzQgMTEuNzkxNCAxOS40NzYzIDExLjM1MjggMjAuMDczOCAxMC42NzQ4QzIwLjY3MTMgOS45OTY4IDIxLjAwMjggOS4xMjUzMyAyMS4wMDcgOC4yMjE2OFpNNC41NjUwOCAzLjczNzUyQzQuNTY1MDggMy4yOTQwOCA0LjY5NjU3IDIuODYwNiA0Ljk0MjkzIDIuNDkxOUM1LjE4OTMgMi4xMjMxOSA1LjUzOTQ3IDEuODM1ODEgNS45NDkxNSAxLjY2NjExQzYuMzU4ODQgMS40OTY0MiA2LjgwOTY1IDEuNDUyMDIgNy4yNDQ1NiAxLjUzODU0QzcuNjc5NDggMS42MjUwNCA4LjA3ODk4IDEuODM4NTcgOC4zOTI1NCAyLjE1MjE0QzguNzA2MTEgMi40NjU3IDguOTE5NjQgMi44NjUyIDkuMDA2MTUgMy4zMDAxMkM5LjA5MjY2IDMuNzM1MDQgOS4wNDgyNyA0LjE4NTg1IDguODc4NTcgNC41OTU1M0M4LjcwODg3IDUuMDA1MjEgOC40MjE0OSA1LjM1NTM5IDguMDUyNzggNS42MDE3NUM3LjY4NDA4IDUuODQ4MTEgNy4yNTA2IDUuOTc5NiA2LjgwNzE2IDUuOTc5NkM2LjIxMjUyIDUuOTc5NiA1LjY0MjI0IDUuNzQzMzkgNS4yMjE3NyA1LjMyMjkxQzQuODAxMjkgNC45MDI0NSA0LjU2NTA4IDQuMzMyMTYgNC41NjUwOCAzLjczNzUyWk05LjA0OTIzIDIwLjE3OTRDOS4wNDkyMyAyMC42MjI5IDguOTE3NzQgMjEuMDU2MyA4LjY3MTM4IDIxLjQyNUM4LjQyNTAxIDIxLjc5MzcgOC4wNzQ4NSAyMi4wODExIDcuNjY1MTYgMjIuMjUwOEM3LjI1NTQ3IDIyLjQyMDUgNi44MDQ2NiAyMi40NjQ5IDYuMzY5NzUgMjIuMzc4NEM1LjkzNDgzIDIyLjI5MiA1LjUzNTMzIDIyLjA3ODQgNS4yMjE3NyAyMS43NjQ4QzQuOTA4MjEgMjEuNDUxMiA0LjY5NDY3IDIxLjA1MTcgNC42MDgxNiAyMC42MTY5QzQuNTIxNjUgMjAuMTgxOSA0LjU2NjA1IDE5LjczMTEgNC43MzU3NSAxOS4zMjE0QzQuOTA1NDUgMTguOTExNyA1LjE5MjgyIDE4LjU2MTUgNS41NjE1MyAxOC4zMTUyQzUuOTMwMjMgMTguMDY4OSA2LjM2MzcxIDE3LjkzNzMgNi44MDcxNiAxNy45MzczQzcuNDAxNzkgMTcuOTM3MyA3Ljk3MjA3IDE4LjE3MzYgOC4zOTI1NCAxOC41OTRDOC44MTMwMiAxOS4wMTQ1IDkuMDQ5MjMgMTkuNTg0OCA5LjA0OTIzIDIwLjE3OTRaTTE3LjI3MDIgMTAuNDYzOEMxNi44MjY3IDEwLjQ2MzggMTYuMzkzMyAxMC4zMzIyIDE2LjAyNDYgMTAuMDg1OUMxNS42NTU5IDkuODM5NTQgMTUuMzY4NSA5LjQ4OTM3IDE1LjE5ODggOS4wNzk2OUMxNS4wMjkxIDguNjcgMTQuOTg0NyA4LjIxOTIgMTUuMDcxMiA3Ljc4NDI3QzE1LjE1NzYgNy4zNDkzNSAxNS4zNzEyIDYuOTQ5ODUgMTUuNjg0OCA2LjYzNjI5QzE1Ljk5ODQgNi4zMjI3MyAxNi4zOTc5IDYuMTA5MTkgMTYuODMyNyA2LjAyMjY4QzE3LjI2NzcgNS45MzYxNyAxNy43MTg1IDUuOTgwNTggMTguMTI4MSA2LjE1MDI3QzE4LjUzNzkgNi4zMTk5NyAxOC44ODgxIDYuNjA3MzQgMTkuMTM0NCA2Ljk3NjA1QzE5LjM4MDcgNy4zNDQ3NiAxOS41MTIzIDcuNzc4MjMgMTkuNTEyMyA4LjIyMTY4QzE5LjUxMjMgOC44MTYzMiAxOS4yNzYgOS4zODY2IDE4Ljg1NTYgOS44MDcwNkMxOC40MzUxIDEwLjIyNzUgMTcuODY0OCAxMC40NjM4IDE3LjI3MDIgMTAuNDYzOFoiIGZpbGw9IiM0MjQyNDIiLz4KPC9zdmc+Cg=="
}

@ -3,9 +3,10 @@ import { ViewPlugin } from '@remixproject/engine-web'
import { Plugin } from '@remixproject/engine';
import { RemixAITab, ChatApi } from '@remix-ui/remix-ai'
import React, { useCallback } from 'react';
import { ICompletions, IModel, RemoteInferencer, IRemoteModel, IParams, GenerationParams, CodeExplainAgent } from '@remix/remix-ai-core';
import { ICompletions, IModel, RemoteInferencer, IRemoteModel, IParams, GenerationParams, CodeExplainAgent, SecurityAgent } from '@remix/remix-ai-core';
import { CustomRemixApi } from '@remix-api'
import { PluginViewWrapper } from '@remix-ui/helper'
const _paq = (window._paq = window._paq || [])
type chatRequestBufferT<T> = {
[key in keyof T]: T[key]
@ -16,9 +17,8 @@ const profile = {
displayName: 'RemixAI',
methods: ['code_generation', 'code_completion',
"solidity_answer", "code_explaining",
"code_insertion", "error_explaining",
"initialize", 'chatPipe', 'ProcessChatRequestBuffer',
'isChatRequestPending'],
"code_insertion", "error_explaining", "vulnerability_check",
"initialize", 'chatPipe', 'ProcessChatRequestBuffer', 'isChatRequestPending'],
events: [],
icon: 'assets/img/remix-logo-blue.png',
description: 'RemixAI provides AI services to Remix IDE.',
@ -37,15 +37,16 @@ export class RemixAIPlugin extends ViewPlugin {
remoteInferencer:RemoteInferencer = null
isInferencing: boolean = false
chatRequestBuffer: chatRequestBufferT<any> = null
agent: CodeExplainAgent
codeExpAgent: CodeExplainAgent
securityAgent: SecurityAgent
useRemoteInferencer:boolean = false
dispatch: any
constructor(inDesktop:boolean) {
super(profile)
this.isOnDesktop = inDesktop
this.agent = new CodeExplainAgent(this)
// user machine dont use resource for remote inferencing
this.codeExpAgent = new CodeExplainAgent(this)
// user machine dont use ressource for remote inferencing
}
onActivation(): void {
@ -61,6 +62,8 @@ export class RemixAIPlugin extends ViewPlugin {
this.useRemoteInferencer = true
this.initialize()
}
this.securityAgent = new SecurityAgent(this)
}
async initialize(model1?:IModel, model2?:IModel, remoteModel?:IRemoteModel, useRemote?:boolean){
@ -96,11 +99,6 @@ export class RemixAIPlugin extends ViewPlugin {
}
async code_generation(prompt: string): Promise<any> {
if (this.isInferencing) {
this.call('terminal', 'log', { type: 'aitypewriterwarning', value: "RemixAI is already busy!" })
return
}
if (this.isOnDesktop && !this.useRemoteInferencer) {
return await this.call(this.remixDesktopPluginName, 'code_generation', prompt)
} else {
@ -117,17 +115,8 @@ export class RemixAIPlugin extends ViewPlugin {
}
async solidity_answer(prompt: string, params: IParams=GenerationParams): Promise<any> {
if (this.isInferencing) {
this.call('terminal', 'log', { type: 'aitypewriterwarning', value: "RemixAI is already busy!" })
return
}
if (prompt.trimStart().startsWith('gpt') || prompt.trimStart().startsWith('sol-gpt')) {
params.terminal_output = true
params.stream_result = false
params.return_stream_response = false
}
const newPrompt = await this.codeExpAgent.chatCommand(prompt)
const newPrompt = await this.agent.chatCommand(prompt)
let result
if (this.isOnDesktop && !this.useRemoteInferencer) {
result = await this.call(this.remixDesktopPluginName, 'solidity_answer', newPrompt)
@ -141,11 +130,6 @@ export class RemixAIPlugin extends ViewPlugin {
}
async code_explaining(prompt: string, context: string, params: IParams=GenerationParams): Promise<any> {
if (this.isInferencing) {
this.call('terminal', 'log', { type: 'aitypewriterwarning', value: "RemixAI is already busy!" })
return
}
let result
if (this.isOnDesktop && !this.useRemoteInferencer) {
result = await this.call(this.remixDesktopPluginName, 'code_explaining', prompt, context, params)
@ -158,11 +142,6 @@ export class RemixAIPlugin extends ViewPlugin {
}
async error_explaining(prompt: string, context: string="", params: IParams=GenerationParams): Promise<any> {
if (this.isInferencing) {
this.call('terminal', 'log', { type: 'aitypewriterwarning', value: "RemixAI is already busy!" })
return
}
let result
if (this.isOnDesktop && !this.useRemoteInferencer) {
result = await this.call(this.remixDesktopPluginName, 'error_explaining', prompt)
@ -173,6 +152,22 @@ export class RemixAIPlugin extends ViewPlugin {
return result
}
async vulnerability_check(prompt: string, params: IParams=GenerationParams): Promise<any> {
let result
if (this.isOnDesktop && !this.useRemoteInferencer) {
result = await this.call(this.remixDesktopPluginName, 'vulnerability_check', prompt)
} else {
result = await this.remoteInferencer.vulnerability_check(prompt, params)
}
if (result && params.terminal_output) this.call('terminal', 'log', { type: 'aitypewriterwarning', value: result })
return result
}
getVulnerabilityReport(file: string): any {
return this.securityAgent.getReport(file)
}
async code_insertion(msg_pfx: string, msg_sfx: string): Promise<any> {
if (this.isOnDesktop && !this.useRemoteInferencer) {
return await this.call(this.remixDesktopPluginName, 'code_insertion', msg_pfx, msg_sfx)
@ -193,12 +188,14 @@ export class RemixAIPlugin extends ViewPlugin {
if (fn === "code_explaining") ChatApi.composer.send("Explain the current code")
else if (fn === "error_explaining") ChatApi.composer.send("Explain the error")
else if (fn === "solidity_answer") ChatApi.composer.send("Answer the following question")
else console.log("chatRequestBuffer is not empty. First process the last request.")
else if (fn === "vulnerability_check") ChatApi.composer.send("Is there any vulnerability in the pasted code?")
else console.log("chatRequestBuffer function name not recognized.")
}
}
else {
console.log("chatRequestBuffer is not empty. First process the last request.")
console.log("chatRequestBuffer is not empty. First process the last request.", this.chatRequestBuffer)
}
_paq.push(['trackEvent', 'ai', 'remixAI_chat', 'askFromTerminal'])
}
async ProcessChatRequestBuffer(params:IParams=GenerationParams){

@ -78,6 +78,15 @@ export class EnvironmentExplorer extends ViewPlugin {
}
}
async deleteForkedState (provider) {
const providerName = await this.call('blockchain', 'getProvider')
if (providerName !== provider.name) {
await this.call('fileManager', 'remove', `.states/forked_states/${provider.displayName}.json`)
await this.call('blockchain', 'removeProvider', provider.name)
this.call('notification', 'toast', `Environment "${provider.displayName}" deleted successfully.`)
} else this.call('notification', 'toast', 'Cannot delete the current selected environment')
}
renderComponent() {
this.dispatch({
...this.state
@ -86,7 +95,12 @@ export class EnvironmentExplorer extends ViewPlugin {
updateComponent(state: EnvironmentExplorerState) {
return (<>
<EnvironmentExplorerUI pinStateCallback={this.pinStateCallback.bind(this)} profile={profile} state={state} />
<EnvironmentExplorerUI
pinStateCallback={this.pinStateCallback.bind(this)}
deleteForkedState={this.deleteForkedState.bind(this)}
profile={profile}
state={state}
/>
</>)
}
}

@ -1,5 +1,5 @@
.EECellStyle {
min-height: 6rem;
min-height: 8rem;
max-width: 12rem;
min-width: 10rem;
min-width: 12rem;
}

@ -22,7 +22,7 @@ const profile = {
maintainedBy: 'Remix'
}
class AnalysisTab extends ViewPlugin {
export default class AnalysisTab extends ViewPlugin {
constructor () {
super(profile)
this.event = new EventManager()

@ -28,7 +28,7 @@ const profile = {
// - events: ['compilationFinished'],
// - methods: ['getCompilationResult']
class CompileTab extends CompilerApiMixin(ViewPlugin) { // implements ICompilerApi
export default class CompileTab extends CompilerApiMixin(ViewPlugin) { // implements ICompilerApi
constructor (config, fileManager) {
super(profile)
this.fileManager = fileManager

@ -22,7 +22,7 @@ const profile = {
maintainedBy: 'Remix'
}
export class DebuggerTab extends DebuggerApiMixin(ViewPlugin) {
export default class DebuggerTab extends DebuggerApiMixin(ViewPlugin) {
constructor () {
super(profile)
this.el = document.createElement('div')

@ -77,6 +77,7 @@ export class LocaleModule extends Plugin {
const next = localeCode || this.active // Name
if (next === this.active) return // --> exit out of this method
_paq.push(['trackEvent', 'localeModule', 'switchTo', next])
const nextLocale = this.locales[next] // Locale
if (!this.forced) this._deps.config.set('settings/locale', next)

@ -0,0 +1,30 @@
{
"contract-verification.verifyNavTitle": "Verify",
"contract-verification.receiptsNavTitle": "Receipts",
"contract-verification.lookupNavTitle": "Lookup",
"contract-verification.settingsNavTitle": "Settings",
"contract-verification.contractAddressInput": "Contract Address",
"contract-verification.proxyContractAddressInput": "Proxy Address",
"contract-verification.proxyInputLabel": "The deployed contract is behind a proxy",
"contract-verification.panelDisplayName": "Contract Verification",
"contract-verification.searchableChainDropdownLabel": "Chain",
"contract-verification.contractAddressError": "Please enter a valid contract address",
"contract-verification.chainError": "Please select the chain.",
"contract-verification.proxyAddressError": "Please provide a valid proxy contract address.",
"contract-verification.verifyButton": "Verify",
"contract-verification.lookupButton": "Lookup",
"contract-verification.receipts.noContractsSubmitted": "No contracts submitted for verification",
"contract-verification.receiptsDefaultLayout.description": "Check the verification statuses of contracts submitted for verification",
"contract-verification.verifyDefaultLayout.description": "Verify compiled contracts on different verification services",
"contract-verification.lookupDefaultLayout.description": "Search for verified contracts and download them to Remix",
"contract-verification.settingsDefaultLayout.description": "Customize settings for each verification service and chain",
"contract-verification.configInputPlaceholderText": "Add {label}",
"contract-verification.configInputSaveButton": "Save",
"contract-verification.configInputCancelButton": "Cancel",
"contract-verification.constructorArgumentsToggleRawInput": "Enter raw ABI-encoded constructor arguments",
"contract-verification.constructorArgumentsRawAbiEncodingResult": "ABI-encoded constructor arguments",
"contract-verification.contractDropdownLabel": "{label}",
"contract-verification.contractDropDownDefaultText": "Compiled contract required"
}

@ -28,6 +28,7 @@
"editor.explainFunctionByAI": "```\n{content}\n```\nExplain the function {currentFunction}",
"editor.explainFunctionByAISol": "```\n{content}\n```\nExplain the function {currentFunction}",
"editor.ExplainPipeMessage": "```\n {content}\n```\nExplain the snipped above",
"editor.PastedCodeSafety": "```\n {content}\n```\n\nReply in a short manner: Does this code contain major security vulnerabilities leading to a scam or loss of funds?",
"editor.executeFreeFunction": "Run a free function",
"editor.executeFreeFunction2": "Run the free function \"{name}\"",
"editor.toastText1": "This can only execute free function",

@ -26,6 +26,7 @@
"home.solhintPluginDesc": "Solhint is an open source project for linting Solidity code.",
"home.sourcifyPluginDesc": "Solidity contract and metadata verification service.",
"home.unitTestPluginDesc": "Write and run unit tests for your contracts in Solidity.",
"home.contractVerificationDesc": "Verify contracts on multiple services at the same time.",
"home.dgitPluginDesc": "Add source control to your projects.",
"home.oneClickDappDesc": "Quickly generate smart contract interfaces",
"home.getStarted": "Get Started",

@ -2,8 +2,8 @@
"pluginManager.displayName": "Plugin manager",
"pluginManager.activate": "Activate",
"pluginManager.deactivate": "Deactivate",
"pluginManager.activeModules": "Active Modules",
"pluginManager.inactiveModules": "Inactive Modules",
"pluginManager.activeModules": "Active Plugins",
"pluginManager.inactiveModules": "Inactive Plugins",
"pluginManager.connectLocal": "Connect to a Local Plugin",
"pluginManager.localForm.title": "Local Plugin",
"pluginManager.localForm.pluginName": "Plugin Name",

@ -50,12 +50,15 @@
"udapp.hash": "hash",
"udapp.signature": "signature",
"udapp.forkStateTitle": "Fork VM state",
"udapp.forkStateLabel": "State Name",
"udapp.forkStateLabel": "New environment name",
"udapp.forkVmStateDesc1":"Forking state will create a new environment with same state as selected environment",
"udapp.forkVmStateDesc2":"After forking, new environment will be pinned and selected automatically. It can be unpinned or deleted using Envionment Explorer",
"udapp.fork": "Fork",
"udapp.deleteVmStateTitle": "Delete VM state",
"udapp.deleteVmStateDesc1": "Deleting the state of this VM will delete the associated transaction details in this Workspace.",
"udapp.deleteVmStateDesc2": "It will also delete the data of contracts deployed and pinned in this Workspace.",
"udapp.deleteVmStateDesc3": "Do you want to continue?",
"udapp.resetVmStateTitle": "Reset VM state",
"udapp.resetVmStateDesc1": "Resetting the state of this VM will delete the associated transaction details in this Workspace.",
"udapp.resetVmStateDesc2": "It will also delete the data of contracts deployed and pinned in this Workspace.",
"udapp.resetVmStateDesc3": "Do you want to continue?",
"udapp.reset": "Reset",
"udapp.delete": "Delete",
"udapp.injectedTitle": "Unfortunately it's not possible to create an account using injected provider. Please create the account directly from your provider (i.e metamask or other of the same type).",
"udapp.createNewAccount": "Create new account",

@ -3,6 +3,7 @@
"panel.maintainedBy": "Mantenido por",
"panel.documentation": "Documentación",
"panel.description": "Descripción",
"panel.displayName": "Nombre para mostrar",
"panel.maintainedByRemix": "Mantenido por Remix",
"panel.pluginInfo": "Información del Complemento",
"panel.linkToDoc": "Enlace a la documentación",

@ -3,6 +3,7 @@
"panel.maintainedBy": "Maintenu par :",
"panel.documentation": "Documentation",
"panel.description": "Description",
"panel.displayName": "Nom d'affichage",
"panel.maintainedByRemix": "Maintenu par Remix",
"panel.pluginInfo": "Informations sur l'extension",
"panel.linkToDoc": "Lien vers la documentation",

@ -3,6 +3,7 @@
"panel.maintainedBy": "Mantenuto Da",
"panel.documentation": "Documentazione",
"panel.description": "Descrizione",
"panel.displayName": "Nome visualizzato",
"panel.maintainedByRemix": "Mantenuto da Remix",
"panel.pluginInfo": "Informazioni sul plugin",
"panel.linkToDoc": "Link alla documentazione",

@ -3,6 +3,7 @@
"panel.maintainedBy": "유지 관리:",
"panel.documentation": "문서",
"panel.description": "상세정보",
"panel.displayName": "표시 이름",
"panel.maintainedByRemix": "리믹스에 의한 유지 관리",
"panel.pluginInfo": "플러그인 정보",
"panel.linkToDoc": "문서 링크",

@ -3,6 +3,7 @@
"panel.maintainedBy": "Поддерживается",
"panel.documentation": "Документация",
"panel.description": "Описание",
"panel.displayName": "Отображаемое имя",
"panel.maintainedByRemix": "Поддерживается Remix",
"panel.pluginInfo": "Информация о плагине",
"panel.linkToDoc": "Ссылка на документацию",

@ -3,6 +3,7 @@
"panel.maintainedBy": "维护者",
"panel.documentation": "文档",
"panel.description": "描述",
"panel.displayName": "显示名称",
"panel.maintainedByRemix": "由 Remix 维护",
"panel.pluginInfo": "插件信息",
"panel.linkToDoc": "文档链接",

@ -71,7 +71,6 @@ export class ScriptRunnerUIPlugin extends ViewPlugin {
})
this.plugin.on('fileManager', 'fileSaved', async (file: string) => {
if (file === configFileName && this.enableCustomScriptRunner) {
await this.loadCustomConfig()
this.renderComponent()
@ -114,7 +113,8 @@ export class ScriptRunnerUIPlugin extends ViewPlugin {
activateCustomScriptRunner={this.activateCustomScriptRunner.bind(this)}
saveCustomConfig={this.saveCustomConfig.bind(this)}
openCustomConfig={this.openCustomConfig.bind(this)}
loadScriptRunner={this.selectScriptRunner.bind(this)} />
loadScriptRunner={this.selectScriptRunner.bind(this)}
/>
)
}
@ -184,7 +184,6 @@ export class ScriptRunnerUIPlugin extends ViewPlugin {
this.setIsLoading(config.name, false)
this.renderComponent()
return result
}
async execute(script: string, filePath: string) {
@ -289,7 +288,6 @@ export class ScriptRunnerUIPlugin extends ViewPlugin {
}
}
}
}
async openCustomConfig() {

@ -27,7 +27,7 @@ const profile = {
maintainedBy: 'Remix'
}
module.exports = class SettingsTab extends ViewPlugin {
export default class SettingsTab extends ViewPlugin {
config: any = {}
editor: any
private _deps: {

@ -22,7 +22,7 @@ const profile = {
maintainedBy: 'Remix'
}
module.exports = class TestTab extends ViewPlugin {
export default class TestTab extends ViewPlugin {
constructor (fileManager, offsetToLineColumnConverter, filePanel, compileTab, appManager, contentImport) {
super(profile)
this.compileTab = compileTab

@ -118,7 +118,7 @@ export class ThemeModule extends Plugin {
}
const next = themeName || this.active // Name
if (next === this.active) return // --> exit out of this method
_paq.push(['trackEvent', 'themeModule', 'switchTo', next])
_paq.push(['trackEvent', 'themeModule', 'switchThemeTo', next])
const nextTheme = this.themes[next] // Theme
if (!this.forced) this._deps.config.set('settings/theme', next)
document.getElementById('theme-link') ? document.getElementById('theme-link').remove() : null

@ -160,13 +160,15 @@ export class RunTab extends ViewPlugin {
'injected-metamask-gnosis': 'Deploy to Gnosis through the Metamask browser extension.',
'injected-metamask-arbitrum': 'Deploy to Arbitrum through the Metamask browser extension.',
'injected-metamask-sepolia': 'Deploy to the Sepolia testnet through the Metamask browser extension.',
'injected-metamask-ephemery': 'Deploy to the Ephemery testnet through the Metamask browser extension.'
'injected-metamask-ephemery': 'Deploy to the Ephemery testnet through the Metamask browser extension.',
'injected-metamask-linea': 'Deploy to Linea through the Metamask browser extension.'
}
const logos = {
'injected-metamask-optimism': ['assets/img/optimism-ethereum-op-logo.png', 'assets/img/metamask.png'],
'injected-metamask-arbitrum': ['assets/img/arbitrum-arb-logo.png', 'assets/img/metamask.png'],
'injected-metamask-gnosis': ['assets/img/gnosis_chain.png', 'assets/img/metamask.png'],
'injected-metamask-linea': ['assets/img/linea_chain.png', 'assets/img/metamask.png'],
'injected-metamask-sepolia': ['assets/img/metamask.png'],
'injected-metamask-ephemery': ['assets/img/metamask.png'],
'injected-MetaMask': ['assets/img/metamask.png'],
@ -243,6 +245,7 @@ export class RunTab extends ViewPlugin {
"decimals": 18
})
*/
await addCustomInjectedProvider(11, event, 'injected-metamask-linea', 'L2 - Linea', '0xe708', ['https://rpc.linea.build'])
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

@ -157,7 +157,7 @@ export class Blockchain extends Plugin {
_paq.push(['trackEvent', 'blockchain', 'providerPinned', name])
this.emit('providersChanged')
this.changeExecutionContext({ context: name }, null, null, null)
this.call('notification', 'toast', `VM state '${providerName}' forked and selected as current envionment.`)
this.call('notification', 'toast', `New environment '${providerName}' created with forked state.`)
})
this.on('environmentExplorer', 'providerUnpinned', (name, provider) => {
@ -687,6 +687,7 @@ export class Blockchain extends Plugin {
}
removeProvider(name) {
if (this.pinnedProviders.includes(name)) this.emit('shouldRemoveProviderFromUdapp', name, this.getProviderObjByName(name))
this.executionContext.removeProvider(name)
this.emit('providersChanged')
}

@ -149,7 +149,8 @@ export function isNative(name) {
'templateSelection',
'walletconnect',
'contract-verification',
'popupPanel'
'popupPanel',
'LearnEth',
]
return nativePlugins.includes(name) || requiredModules.includes(name) || isInjectedProvider(name) || isVM(name) || isScriptRunner(name)
}

@ -158,7 +158,7 @@ Before starting to coding, we should ensure all devs / contributors are aware of
### 1) Bugs:
- A critical bug should get the label `Blocker`, and every effort should be put to fix it.
- Addressing a non critical and non planned bug can be done:
- After having notified in the `remix-dev` channel if the bug does not involves UX or public API changes.
- After having notified in the `remix-dev` channel if the bug does not involve UX or public API changes.
- After a dev meeting (e.g the regular standup) if the bug involves any UX or public API changes.
### 2) Support:

@ -128,7 +128,7 @@ module.exports = composePlugins(withNx(), withReact(), (config) => {
})
)
// souce-map loader
// source-map loader
config.module.rules.push({
test: /\.js$/,
use: ['source-map-loader'],

@ -4,13 +4,13 @@
### Running the app locally
In the main repo yarn, then run yarn serve
In the main repo run yarn, then run yarn serve
In this directory apps/remixdesktop, yarn, then run: yarn start:dev to boot the electron app
Then, the app will be started in live reload mode, and anything you do in Remix IDE will be reloaded.
It will not however reload electron code. You need to rerun yarn start:dev every time.
If you run into issues with yarn when native node modules are being rebuilt you need
If you run into issues with yarn when native node modules are being rebuilt, you need
- Windows: install Visual Studio Tools with Desktop Development C++ enabled in the Workloads
- MacOS: install Xcode or Xcode Command Line Tools. Also make sure the compilers (clang++ | g++) target the right sdk includes, ```export SDKROOT="xcrun --show-sdk-path"```
- Linux: unknown, probably a C++ compiler
@ -44,7 +44,7 @@ const clientProfile: Profile = {
As you can see in the clientProfile you define the methods which are exposed to the Remix plugin system.
5. add a base plugin and a plugin client
4. add a base plugin and a plugin client
```
export class CompilerLoaderPlugin extends ElectronBasePlugin {
clients: CompilerLoaderPluginClient[] = []
@ -71,7 +71,7 @@ The ElectronBasePluginClient is the specific instance which will be connected to
Any instance specific code is set as functions on the ElectronBasePluginClient class.
6. If you need fs access you need to track the workingdir like we do here:
5. If you need fs access you need to track the workingdir like we do here:
This ensures you know where the user is working
```
@ -92,7 +92,7 @@ class IsoGitPluginClient extends ElectronBasePluginClient {
```
7. If you need to call methods on the BASE which holds all the clients you can add methods there, for example this iterates over clients
6. If you need to call methods on the BASE which holds all the clients you can add methods there, for example this iterates over clients
and finds the one with the webContentsId. This ID passed on ie by menu items. Look at menu.ts to see how that works.
```
@ -104,21 +104,21 @@ and finds the one with the webContentsId. This ID passed on ie by menu items. Lo
}
```
8. Add your plugin to engine.ts
7. Add your plugin to engine.ts
```
const compilerLoaderPlugin = new CompilerLoaderPlugin()
```
9. Register the plugin in engine.ts
8. Register the plugin in engine.ts
```
engine.register(compilerLoaderPlugin)
```
10. activation of plugins is done when the clients connect to the engine. No need to activate it.
9. activation of plugins is done when the clients connect to the engine. No need to activate it.
11. Add the plugin to the preload.ts. Add it to this list:
10. Add the plugin to the preload.ts. Add it to this list:
```
const exposedPLugins = ['fs', 'git', 'xterm', 'isogit', 'electronconfig', 'electronTemplates', 'ripgrep', 'compilerloader', 'appUpdater']
@ -126,7 +126,7 @@ const exposedPLugins = ['fs', 'git', 'xterm', 'isogit', 'electronconfig', 'elect
If you don't do this, it won't work.
12. In Remix IDE create a plugin in src/app/plugins/electron. If everything works correctly the methods will be loaded from the electron side, no need to specify them here.
11. In Remix IDE create a plugin in src/app/plugins/electron. If everything works correctly the methods will be loaded from the electron side, no need to specify them here.
This plugin is only a passthrough.
```
@ -150,11 +150,10 @@ export class compilerLoaderPluginDesktop extends ElectronPlugin {
}
```
13. if you need to activate that on load you need to add it to the app.js where other plugins are activated.
12. if you need to activate that on load you need to add it to the app.js where other plugins are activated.
## CI
CI will only run the builds if the branch is master or contains the word: desktop

@ -6,7 +6,7 @@ import { EventEmitter } from 'events';
import { ICompletions, IModel, IParams, InsertionParams,
CompletionParams, GenerationParams, ModelType, AIRequestType,
IStreamResponse, ChatHistory, downloadLatestReleaseExecutable,
buildSolgptPromt } from "@remix/remix-ai-core"
buildSolgptPrompt } from "@remix/remix-ai-core"
import { platform } from 'os';
class ServerStatusTimer {
@ -149,8 +149,8 @@ export class InferenceManager implements ICompletions {
} else {
// Server is running with successful request
// console.log('Inference server is running')
// console.log('completion is runnig', state.data?.completion)
// console.log('general is runnig', state.data?.general)
// console.log('completion is running', state.data?.completion)
// console.log('general is running', state.data?.general)
}
// this._handleResources()
}
@ -176,7 +176,7 @@ export class InferenceManager implements ICompletions {
}
if (model.modelReqs.GPURequired) {
if (gpu_available.length < 1) {
if (logger)console.warn('GPU requiredfor desktop inference but not available')
if (logger)console.warn('GPU required for desktop inference but not available')
}
}
}
@ -517,7 +517,7 @@ export class InferenceManager implements ICompletions {
modelOP = model.modelOP
}
}
const prompt = buildSolgptPromt(userPrompt, modelOP)
const prompt = buildSolgptPrompt(userPrompt, modelOP)
if (params.stream_result) {
return this._streamInferenceRequest('solidity_answer', { prompt, ...params })

@ -89,7 +89,7 @@ async function installFoundry(): Promise<void> {
server.stdout.on('data', function (data) {
console.log(data.toString())
if (
data.toString().includes("foundryup: done!")
data.toString().includes("foundryup: use - chisel 0.3.0")
) {
console.log('resolving')
resolve()

@ -10,7 +10,7 @@
last 1 Chrome version
last 1 Firefox version
last 2 Edge major versions
last 2 Safari major version
last 2 Safari major versions
last 2 iOS major versions
Firefox ESR
not IE 9-11 # For IE 9-11 support, remove 'not'.
not IE 9-11 # For IE 9-11 support, remove 'not'.

@ -56,8 +56,8 @@ const App = () => {
try {
remixClient.call('locale' as any, 'currentLocale').then((currentLocale) => {
setLocale(currentLocale)
})
})
remixClient.on('locale' as any, 'localeChanged', (locale: any) => {
setLocale(locale)
})
@ -118,113 +118,113 @@ const App = () => {
return (
<IntlProvider locale={locale.code} messages={locale.messages}>
<main id="vyper-plugin">
<section>
<div className="px-3 pt-3 mb-3 w-100">
<CustomTooltip placement="bottom" tooltipText="Clone a repo of Vyper examples. Switch to the File Explorer to see the examples.">
<button data-id="add-repository" className="w-100 text-dark btn border" onClick={() => {
{cloneCount === 0 ? remixClient.cloneVyperRepo() : remixClient.cloneVyperRepo(cloneCount)}
setCloneCount((prev) => {
return ++prev
})
}}>
<main id="vyper-plugin">
<section>
<div className="px-3 pt-3 mb-3 w-100">
<CustomTooltip placement="bottom" tooltipText="Clone a repo of Vyper examples. Switch to the File Explorer to see the examples.">
<button data-id="add-repository" className="w-100 text-dark btn border" onClick={() => {
{cloneCount === 0 ? remixClient.cloneVyperRepo() : remixClient.cloneVyperRepo(cloneCount)}
setCloneCount((prev) => {
return ++prev
})
}}>
Clone a repo of Vyper examples
</button>
</CustomTooltip>
</div>
<Accordion className="border-0 w-100 accordion-background">
<div className="border-0">
<div className="">
<CustomAccordionToggle eventKey="0">
<label style={{fontSize: "1REM"}}>Configurations</label>
</CustomAccordionToggle>
</div>
<Accordion.Collapse eventKey="0">
<div className="pb-2 border-bottom">
<Form>
<div className="d-flex flex-row justify-content-around mb-1 mt-2">
<div className={`custom-control custom-radio ${state.environment === 'remote' ? 'd-flex' : 'd-flex cursor-status'}`}>
<input
type="radio"
id="remote-compiler"
data-id="remote-compiler"
name="remote"
value={state.environment}
checked={state.environment === 'remote'}
onChange={() => setEnvironment('remote')}
className={`custom-control-input ${state.environment === 'remote' ? 'd-flex mr-1' : 'd-flex mr-1 cursor-status'}`}
/>
<label
htmlFor="remote-compiler"
className="form-check-label custom-control-label"
style={{ paddingTop: '0.19rem' }}
>Remote Compiler</label>
</div>
<div className={`custom-control custom-radio ${state.environment === 'local' ? 'mr-2' : `cursor-status`}`}>
<input
id="local-compiler"
data-id="local-compiler"
checked={state.environment === 'local'}
type="radio"
name="local"
value={state.environment}
onChange={() => setEnvironment('local')}
className={`custom-control-input ${state.environment === 'local' ? '' : `cursor-status`}`}
/>
<label
htmlFor="local-compiler"
className="form-check-label custom-control-label"
style={{ paddingTop: '0.19rem' }}
>Local Compiler</label>
</div>
</div>
</Form>
<LocalUrlInput url={state.localUrl} setUrl={setLocalUrl} environment={state.environment} />
</div>
</Accordion.Collapse>
</button>
</CustomTooltip>
</div>
</Accordion>
<span className="w-100 px-3 mt-3 mb-1 small text-warning">
<Accordion className="border-0 w-100 accordion-background">
<div className="border-0">
<div className="">
<CustomAccordionToggle eventKey="0">
<label style={{ fontSize: "1REM" }}>Configurations</label>
</CustomAccordionToggle>
</div>
<Accordion.Collapse eventKey="0">
<div className="pb-2 border-bottom">
<Form>
<div className="d-flex flex-row justify-content-around mb-1 mt-2">
<div className={`custom-control custom-radio ${state.environment === 'remote' ? 'd-flex' : 'd-flex cursor-status'}`}>
<input
type="radio"
id="remote-compiler"
data-id="remote-compiler"
name="remote"
value={state.environment}
checked={state.environment === 'remote'}
onChange={() => setEnvironment('remote')}
className={`custom-control-input ${state.environment === 'remote' ? 'd-flex mr-1' : 'd-flex mr-1 cursor-status'}`}
/>
<label
htmlFor="remote-compiler"
className="form-check-label custom-control-label"
style={{ paddingTop: '0.19rem' }}
>Remote Compiler</label>
</div>
<div className={`custom-control custom-radio ${state.environment === 'local' ? 'mr-2' : `cursor-status`}`}>
<input
id="local-compiler"
data-id="local-compiler"
checked={state.environment === 'local'}
type="radio"
name="local"
value={state.environment}
onChange={() => setEnvironment('local')}
className={`custom-control-input ${state.environment === 'local' ? '' : `cursor-status`}`}
/>
<label
htmlFor="local-compiler"
className="form-check-label custom-control-label"
style={{ paddingTop: '0.19rem' }}
>Local Compiler</label>
</div>
</div>
</Form>
<LocalUrlInput url={state.localUrl} setUrl={setLocalUrl} environment={state.environment} />
</div>
</Accordion.Collapse>
</div>
</Accordion>
<span className="w-100 px-3 mt-3 mb-1 small text-warning">
Specify the{' '}
<a className="text-warning" target="_blank" href="https://remix-ide.readthedocs.io/en/latest/vyper.html#specify-vyper-version">
<a className="text-warning" target="_blank" href="https://remix-ide.readthedocs.io/en/latest/vyper.html#specify-vyper-version">
compiler version
</a>{' '}
</a>{' '}
&{' '}
<a className="text-warning" href="https://remix-ide.readthedocs.io/en/latest/vyper.html#evm-version" target="_blank" rel="noopener noreferrer">
<a className="text-warning" href="https://remix-ide.readthedocs.io/en/latest/vyper.html#evm-version" target="_blank" rel="noopener noreferrer">
EVM version
</a>{' '}
</a>{' '}
in the .vy file.
</span>
<div className="px-3 w-100 mb-3 mt-1" id="compile-btn">
<CompilerButton compilerUrl={compilerUrl()} contract={contract} setOutput={(name, update) => setOutput({ ...output, [name]: update })} resetCompilerState={resetCompilerResultState} output={output} remixClient={remixClient}/>
</div>
<article id="result" className="px-3 p-2 w-100 border-top mt-2 vyper-errorBlobs">
{output && output.status === 'success' &&
</span>
<div className="px-3 w-100 mb-3 mt-1" id="compile-btn">
<CompilerButton compilerUrl={compilerUrl()} contract={contract} setOutput={(name, update) => setOutput({ ...output, [name]: update })} resetCompilerState={resetCompilerResultState} output={output} remixClient={remixClient}/>
</div>
<article id="result" className="px-3 p-2 w-100 border-top mt-2 vyper-errorBlobs">
{output && output.status === 'success' &&
<>
<VyperResult output={output} plugin={remixClient} />
</>
}
{output && output.status === 'failed' &&
}
{output && output.status === 'failed' &&
output.errors && output.errors.map((error: VyperCompilationError, index: number) => {
return <Renderer key={index}
message={extractRelativePath(error.message, contract)}
plugin={remixClient}
context='vyper'
opt={{
useSpan: false,
type: 'error',
errorType: error.error_type,
errCol: error.column,
errLine: error.line ? error.line - 1 : null,
errFile: contract
}}
/>
})
}
</article>
</section>
</main>
message={extractRelativePath(error.message, contract)}
plugin={remixClient}
context='vyper'
opt={{
useSpan: false,
type: 'error',
errorType: error.error_type,
errCol: error.column,
errLine: error.line ? error.line - 1 : null,
errFile: contract
}}
/>
})
}
</article>
</section>
</main>
</IntlProvider>
)
}

@ -31,8 +31,6 @@ const compileReturnType = (output, contract): VyperCompilationResult => {
const normal = normalizeContractPath(contract)[2]
const abi = temp[normal]['abi']
const evm = _.merge(temp[normal]['evm'])
const depByteCode = evm.deployedBytecode
const runtimeBytecode = evm.bytecode
const methodIdentifiers = evm.methodIdentifiers
// TODO: verify this is correct
const version = output.version || '0.4.0'
@ -52,8 +50,8 @@ const compileReturnType = (output, contract): VyperCompilationResult => {
} = {
contractName: normal,
abi,
bytecode: depByteCode,
runtimeBytecode,
bytecode: evm.bytecode,
runtimeBytecode: evm.deployedBytecode,
ir: '',
methodIdentifiers,
version,

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save