Merge branch 'master' into workspace_completion

workspace_completion
STetsing 1 week ago committed by GitHub
commit abef01655e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 2
      .env.local
  2. 1
      .gitignore
  3. 13
      apps/remix-dapp/src/locales/en/udapp.json
  4. 2
      apps/remix-ide-e2e/src/tests/remixd.test.ts
  5. 3
      apps/remix-ide-e2e/src/tests/terminal.test.ts
  6. 8
      apps/remix-ide-e2e/src/tests/vm_state.test.ts
  7. 2
      apps/remix-ide/src/app/files/fileManager.ts
  8. 64
      apps/remix-ide/src/app/plugins/remixAIPlugin.tsx
  9. 16
      apps/remix-ide/src/app/providers/environment-explorer.tsx
  10. 4
      apps/remix-ide/src/app/providers/style/environment-explorer.css
  11. 1
      apps/remix-ide/src/app/tabs/locale-module.js
  12. 1
      apps/remix-ide/src/app/tabs/locales/en/editor.json
  13. 13
      apps/remix-ide/src/app/tabs/locales/en/udapp.json
  14. 6
      apps/remix-ide/src/app/tabs/script-runner-ui.tsx
  15. 2
      apps/remix-ide/src/app/tabs/theme-module.js
  16. 3
      apps/remix-ide/src/blockchain/blockchain.tsx
  17. 4
      apps/remixdesktop/src/lib/InferenceServerManager.ts
  18. 2
      apps/remixdesktop/test/tests/app/foundry.test.ts
  19. 2
      apps/walletconnect/webpack.config.js
  20. 8
      libs/ghaction-helper/package.json
  21. 185
      libs/remix-ai-core/src/agents/securityAgent.ts
  22. 3
      libs/remix-ai-core/src/helpers/streamHandler.ts
  23. 7
      libs/remix-ai-core/src/index.ts
  24. 4
      libs/remix-ai-core/src/inferencers/remote/remoteInference.ts
  25. 2
      libs/remix-ai-core/src/prompts/promptBuilder.ts
  26. 8
      libs/remix-analyzer/package.json
  27. 2
      libs/remix-api/src/lib/plugins/remixAIDesktop-api.ts
  28. 6
      libs/remix-astwalker/package.json
  29. 12
      libs/remix-debug/package.json
  30. 4
      libs/remix-lib/package.json
  31. 10
      libs/remix-lib/src/execution/txRunner.ts
  32. 4
      libs/remix-lib/src/execution/txRunnerVM.ts
  33. 6
      libs/remix-simulator/package.json
  34. 1
      libs/remix-simulator/src/provider.ts
  35. 6
      libs/remix-solidity/package.json
  36. 10
      libs/remix-tests/package.json
  37. 9
      libs/remix-ui/editor/src/lib/providers/inlineCompletionProvider.ts
  38. 28
      libs/remix-ui/editor/src/lib/remix-ui-editor.tsx
  39. 2
      libs/remix-ui/editor/src/lib/syntaxes/solidity.ts
  40. 13
      libs/remix-ui/environment-explorer/src/lib/components/environment-explorer-ui.tsx
  41. 1
      libs/remix-ui/environment-explorer/src/lib/types/index.ts
  42. 3
      libs/remix-ui/grid-view/src/lib/remix-ui-grid-cell.css
  43. 25
      libs/remix-ui/grid-view/src/lib/remix-ui-grid-cell.tsx
  44. 6
      libs/remix-ui/home-tab/src/lib/components/homeTabFeatured.tsx
  45. 2
      libs/remix-ui/home-tab/src/lib/components/types/carouselTypes.ts
  46. 2
      libs/remix-ui/run-tab/src/lib/actions/deploy.ts
  47. 41
      libs/remix-ui/run-tab/src/lib/components/environment.tsx
  48. 10
      libs/remix-ui/run-tab/src/lib/run-tab.tsx
  49. 1
      libs/remix-ui/run-tab/src/lib/types/blockchain.d.ts
  50. 19
      libs/remix-ui/scriptrunner/src/lib/script-runner-ui.tsx
  51. 1
      libs/remix-ui/solidity-compiler/src/lib/compiler-container.tsx
  52. 7
      libs/remix-ui/terminal/src/lib/remix-ui-terminal.tsx
  53. 4
      libs/remix-url-resolver/package.json
  54. 4
      libs/remix-ws-templates/package.json
  55. 2
      libs/remixd/package.json
  56. 11
      releaseDetails.json

@ -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>

1
.gitignore vendored

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

@ -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",

@ -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()

@ -195,7 +195,7 @@ module.exports = {
.journalChildIncludes('inside getOwner', { shouldHaveOnlyOneOccurrence: true })
},
'Emit 2 similar events and check the filtering is done properly #group4': function (browser: NightwatchBrowser) {
'Emit 2 similar events and check the filtering is done properly #group11': function (browser: NightwatchBrowser) {
let addressRef: string
browser
.addFile('contracts/contract_with_event.sol', { content: contract_with_event })
@ -204,7 +204,6 @@ module.exports = {
.clickLaunchIcon('solidity')
.click('*[data-id="compilerContainerCompileBtn"]')
.clickLaunchIcon('udapp')
.click('*[data-id="deployAndRunClearInstances"]')
.selectContract('Example')
.createContract('')
.getAddressAtPosition(0, (address) => {

@ -33,7 +33,7 @@ const tests = {
.click('*[data-id="delete-state-icon"]')
.waitForElementVisible(
{
selector: "//*[@data-shared='tooltipPopup' and contains(.,'State not available to delete')]",
selector: "//*[@data-shared='tooltipPopup' and contains(.,'State not available to reset')]",
locateStrategy: 'xpath'
}
)
@ -65,7 +65,7 @@ const tests = {
// check toaster for forked state
.waitForElementVisible(
{
selector: '//*[@data-shared="tooltipPopup" and contains(.,"VM state \'forkedState_1\' forked")]',
selector: '//*[@data-shared="tooltipPopup" and contains(.,"New environment \'forkedState_1\' created with forked state.")]',
locateStrategy: 'xpath'
}
)
@ -105,7 +105,7 @@ const tests = {
.setValue('input[data-id="modalDialogForkState"]', 'forkedState_2')
.modalFooterOKClick('udappNotify')
.waitForElementVisible('*[data-shared="tooltipPopup"]', 10000)
.assert.textContains('*[data-shared="tooltipPopup"]', `VM state 'forkedState_2' forked and selected as current environment.`)
.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
@ -140,7 +140,7 @@ const tests = {
.modalFooterOKClick('udappNotify')
.waitForElementVisible('*[data-shared="tooltipPopup"]', 10000)
// check if toaster is shown
.assert.textContains('*[data-shared="tooltipPopup"]', `VM state deleted successfully.`)
.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

@ -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'
}

@ -3,7 +3,7 @@ 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'
import { CodeCompletionAgent } from '@remix/remix-ai-core';
@ -18,9 +18,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.',
@ -39,7 +38,8 @@ 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
completionAgent: CodeCompletionAgent
@ -47,8 +47,8 @@ export class RemixAIPlugin extends ViewPlugin {
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 {
@ -70,6 +70,9 @@ export class RemixAIPlugin extends ViewPlugin {
console.log('Indexing workspace')
this.completionAgent.indexWorkspace()
}, 60000)
this.securityAgent = new SecurityAgent(this)
}
async initialize(model1?:IModel, model2?:IModel, remoteModel?:IRemoteModel, useRemote?:boolean){
@ -105,11 +108,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 {
@ -130,17 +128,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)
@ -154,11 +143,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)
@ -171,11 +155,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)
@ -186,6 +165,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.completionAgent.indexer == null || this.completionAgent.indexer == undefined) await this.completionAgent.indexWorkspace()
@ -210,11 +205,12 @@ 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'])
}

@ -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;
}

@ -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)

@ -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",

@ -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",

@ -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() {

@ -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

@ -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 environment.`)
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')
}

@ -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 {
@ -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()

@ -46,7 +46,7 @@ module.exports = composePlugins(withNx(), (config) => {
process: 'process/browser'
})
)
console.log(process.env.WALLET_CONNECT_PROJECT_ID)
// set the define plugin to load the WALLET_CONNECT_PROJECT_ID
config.plugins.push(
new webpack.DefinePlugin({

@ -1,6 +1,6 @@
{
"name": "@remix-project/ghaction-helper",
"version": "0.1.42",
"version": "0.1.43",
"description": "Solidity Tests GitHub Action Helper",
"main": "src/index.js",
"scripts": {
@ -19,17 +19,17 @@
},
"homepage": "https://github.com/ethereum/remix-project#readme",
"devDependencies": {
"@remix-project/remix-solidity": "^0.5.48",
"@remix-project/remix-solidity": "^0.5.49",
"@types/chai": "^4.3.4",
"typescript": "^4.9.3"
},
"dependencies": {
"@ethereum-waffle/chai": "^3.4.4",
"@remix-project/remix-simulator": "^0.2.62",
"@remix-project/remix-simulator": "^0.2.63",
"chai": "^4.3.7",
"ethers": "^5.7.2",
"web3": "^4.1.1"
},
"types": "./src/index.d.ts",
"gitHead": "baa8abc9b912288b7a2546bedc717a9229f652c4"
"gitHead": "a92b8aa830067f879c96b41e301bc3174b87e551"
}

@ -1,28 +1,189 @@
// security checks
import * as fs from 'fs';
class SecurityAgent {
private codebase: string[]; // list of codebase files
interface SecurityReport {
compiled: boolean;
vulnerabilities: string[];
isNotSafe: string;
fileName: string;
reportTimestamp: string;
recommendations: string[];
fileModifiedSinceLastReport: boolean;
hasPastedCode: boolean;
}
class WorkspaceWatcher {
private intervalId: NodeJS.Timeout | null = null;
public interval: number;
private task: () => void;
constructor(task: () => void, interval: number) {
this.task = task;
this.interval = interval;
}
start(): void {
if (this.intervalId === null) {
this.intervalId = setInterval(() => {
this.task();
}, this.interval);
}
}
stop(): void {
if (this.intervalId !== null) {
clearInterval(this.intervalId);
this.intervalId = null;
}
}
isRunning(): boolean {
return this.intervalId !== null;
}
}
export class SecurityAgent {
public currentFile: string;
public openedFiles: any;
private basePlugin: any;
private watcher: WorkspaceWatcher;
public reports: SecurityReport[] = [];
constructor(plugin) {
this.basePlugin = plugin;
this.basePlugin.on('fileManager', 'fileAdded', (path) => { });
this.basePlugin.on('fileManager', 'fileChanged', (path) => { //this.modifiedFile(path)
});
this.basePlugin.on('fileManager', 'fileRemoved', (path) => { this.removeFileFromReport(path) });
this.basePlugin.on('fileManager', 'fileRenamed', (oldName, newName) => {
this.removeFileFromReport(oldName);
this.addFileToReport(newName);
});
// disable for now the compilationFinished event
// this.basePlugin.on('solidity', 'compilationFinished', async (fileName, source, languageVersion, data) => { this.onCompilationFinished(fileName) });
// this.basePlugin.on('vyper', 'compilationFinished', async (fileName, source, languageVersion, data) => { this.onCompilationFinished(fileName) });
// this.basePlugin.on('hardhat', 'compilationFinished', async (fileName, source, languageVersion, data) => { this.onCompilationFinished(fileName) });
// this.basePlugin.on('foundry', 'compilationFinished', async (fileName, source, languageVersion, data) => { this.onCompilationFinished(fileName) });
this.watcher = new WorkspaceWatcher(async () => {
try {
this.currentFile = await this.basePlugin.call('fileManager', 'getCurrentFile');
this.openedFiles = await this.basePlugin.call('fileManager', 'getOpenedFiles');
Object.keys(this.openedFiles).forEach(key => {
this.addFileToReport(this.openedFiles[key]);
});
} catch (error) {
// no file selected or opened currently
}
}, 10000);
this.watcher.start();
}
addFileToReport(file: string): void {
const report = this.reports.find((r) => r.fileName === file);
if (report) {
// nothing to do
} else {
this.reports.push({
compiled: false,
isNotSafe: 'No',
vulnerabilities: [],
fileName: file,
reportTimestamp: null,
recommendations: [],
fileModifiedSinceLastReport: false,
hasPastedCode: false
});
}
constructor(codebasePath: string) {
// git or fs
this.codebase = this.loadCodebase(codebasePath);
}
private loadCodebase(path: string): string[] {
const files = fs.readdirSync(path);
return files
.filter(file => file.endsWith('.ts'))
.flatMap(file => fs.readFileSync(`${path}/${file}`, 'utf-8').split('\n'));
async onCompilationFinished(file: string) {
let report = this.reports.find((r) => r.fileName === file);
if (report) {
report.compiled = true;
report.fileModifiedSinceLastReport = false;
} else {
report = {
compiled: true,
isNotSafe: 'No',
vulnerabilities: [],
fileName: file,
reportTimestamp: null,
recommendations: [],
fileModifiedSinceLastReport: false,
hasPastedCode: false
}
this.reports.push(report);
}
try {
this.processFile(file);
console.log('Checking for vulnerabilities after compilation', this.reports);
} catch (error) {
console.error('Error checking for vulnerabilities after compilation: ', error);
}
// check for security vulnerabilities
}
public update(currentFile, lineNumber){
removeFileFromReport(file: string): void {
const index = this.reports.findIndex((r) => r.fileName === file);
if (index !== -1) {
this.reports.splice(index, 1);
}
}
modifiedFile(file: string): void {
const report = this.reports.find((r) => r.fileName === file);
if (report) {
report.fileModifiedSinceLastReport = true;
}
}
async processFile(file: string) {
try {
const report = this.reports.find((r) => r.fileName === file);
if (report) { }
else {
this.reports.push({
compiled: false,
isNotSafe: 'No',
vulnerabilities: [],
fileName: file,
reportTimestamp: null,
recommendations: [],
fileModifiedSinceLastReport: false,
hasPastedCode: false
});
}
if (!report.reportTimestamp || report.fileModifiedSinceLastReport) {
const content = await this.basePlugin.call('fileManager', 'getFile', file);
const prompt = "```\n" + content + "\n```\n\nReply in a short manner: Does this code contain major security vulnerabilities leading to a scam or loss of funds?"
let result = await this.basePlugin.call('remixAI', 'vulnerability_check', prompt)
result = JSON.parse(result);
report.vulnerabilities = result.Reason;
report.recommendations = result.Suggestion;
report.isNotSafe = result.Answer;
report.reportTimestamp = new Date().toISOString();
}
} catch (error) {
console.error('Error processing file: ', error);
}
}
getReport(file: string): SecurityReport {
return this.reports.find((r) => r.fileName === file);
}
public getRecommendations(currentLine: string, numSuggestions: number = 3): string[] {
// process the codebase highlighting security vulnerabilities and deliver recommendations
const suggestions: string[] = [];
return suggestions;
}

@ -46,6 +46,7 @@ export const HandleStreamResponse = async (streamResponse,
}
catch (error) {
console.error('Error parsing JSON:', error);
return { 'generateText': 'Try again!', 'isGenerating': false }
}
}
if (done_cb) {
@ -54,7 +55,7 @@ export const HandleStreamResponse = async (streamResponse,
}
catch (error) {
console.error('Error parsing JSON:', error);
return { 'generateText': '', 'isGenerating': false }
return { 'generateText': 'Try again!', 'isGenerating': false }
}
}

@ -6,7 +6,7 @@ import { IModel, IModelResponse, IModelRequest, InferenceModel, ICompletions,
import { ModelType } from './types/constants'
import { DefaultModels, InsertionParams, CompletionParams, GenerationParams } from './types/models'
import { getCompletionPrompt, getInsertionPrompt } from './prompts/completionPrompts'
import { buildSolgptPromt, PromptBuilder } from './prompts/promptBuilder'
import { buildSolgptPrompt, PromptBuilder } from './prompts/promptBuilder'
import { RemoteInferencer } from './inferencers/remote/remoteInference'
import { ChatHistory } from './prompts/chat'
import { downloadLatestReleaseExecutable } from './helpers/inferenceServerReleases'
@ -14,7 +14,7 @@ import { downloadLatestReleaseExecutable } from './helpers/inferenceServerReleas
export {
IModel, IModelResponse, IModelRequest, InferenceModel,
ModelType, DefaultModels, ICompletions, IParams, IRemoteModel,
getCompletionPrompt, getInsertionPrompt, IStreamResponse, buildSolgptPromt,
getCompletionPrompt, getInsertionPrompt, IStreamResponse, buildSolgptPrompt,
RemoteInferencer, InsertionParams, CompletionParams, GenerationParams,
ChatEntry, AIRequestType, RemoteBackendOPModel, ChatHistory, downloadLatestReleaseExecutable
}
@ -22,4 +22,5 @@ export {
export * from './types/types'
export * from './helpers/streamHandler'
export * from './agents/codeExplainAgent'
export * from './agents/completionAgent'
export * from './agents/completionAgent'
export * from './agents/securityAgent'

@ -1,6 +1,6 @@
import { ICompletions, IParams, AIRequestType, RemoteBackendOPModel, JsonStreamParser } from "../../types/types";
import { GenerationParams, CompletionParams, InsertionParams } from "../../types/models";
import { buildSolgptPromt } from "../../prompts/promptBuilder";
import { buildSolgptPrompt } from "../../prompts/promptBuilder";
import EventEmitter from "events";
import { ChatHistory } from "../../prompts/chat";
import axios from 'axios';
@ -129,7 +129,7 @@ export class RemoteInferencer implements ICompletions {
}
async solidity_answer(prompt, options:IParams=GenerationParams): Promise<any> {
const main_prompt = buildSolgptPromt(prompt, this.model_op)
const main_prompt = buildSolgptPrompt(prompt, this.model_op)
const payload = { 'prompt': main_prompt, "endpoint":"solidity_answer", ...options }
if (options.stream_result) return this._streamInferenceRequest(payload, AIRequestType.GENERAL)
else return this._makeRequest(payload, AIRequestType.GENERAL)

@ -7,7 +7,7 @@ export const PromptBuilder = (inst, answr, modelop) => {
if (modelop === RemoteBackendOPModel.MISTRAL) return ""
}
export const buildSolgptPromt = (userPrompt:string, modelOP:RemoteBackendOPModel) => {
export const buildSolgptPrompt = (userPrompt:string, modelOP:RemoteBackendOPModel) => {
if (modelOP === undefined) {
console.log('WARNING: modelOP is undefined. Provide a valid model OP for chat history')
return userPrompt

@ -1,6 +1,6 @@
{
"name": "@remix-project/remix-analyzer",
"version": "0.5.71",
"version": "0.5.72",
"description": "Tool to perform static analysis on Solidity smart contracts",
"scripts": {
"test": "./../../node_modules/.bin/ts-node --project ../../tsconfig.base.json --require tsconfig-paths/register ./../../node_modules/.bin/tape ./test/tests.ts"
@ -25,8 +25,8 @@
"@ethereumjs/tx": "5.4.0",
"@ethereumjs/util": "9.1.0",
"@ethereumjs/vm": "8.1.1",
"@remix-project/remix-astwalker": "^0.0.92",
"@remix-project/remix-lib": "^0.5.69",
"@remix-project/remix-astwalker": "^0.0.93",
"@remix-project/remix-lib": "^0.5.70",
"async": "^2.6.2",
"ethers": "^5.4.2",
"ethjs-util": "^0.1.6",
@ -50,6 +50,6 @@
"typescript": "^3.7.5"
},
"typings": "src/index.d.ts",
"gitHead": "baa8abc9b912288b7a2546bedc717a9229f652c4",
"gitHead": "a92b8aa830067f879c96b41e301bc3174b87e551",
"main": "./src/index.js"
}

@ -10,7 +10,7 @@ export interface IRemixAID {
} & StatusEvents,
methods: {
code_completion(context: string): Promise<string>
code_completion(context: string): Promise<string>
code_insertion(msg_pfx: string, msg_sfx: string): Promise<string>,
code_generation(prompt: string): Promise<string | null>,
code_explaining(code: string, context?: string): Promise<string | null>,

@ -1,6 +1,6 @@
{
"name": "@remix-project/remix-astwalker",
"version": "0.0.92",
"version": "0.0.93",
"description": "Tool to walk through Solidity AST",
"main": "src/index.js",
"scripts": {
@ -37,7 +37,7 @@
"@ethereumjs/tx": "5.4.0",
"@ethereumjs/util": "9.1.0",
"@ethereumjs/vm": "8.1.1",
"@remix-project/remix-lib": "^0.5.69",
"@remix-project/remix-lib": "^0.5.70",
"@types/tape": "^4.2.33",
"async": "^2.6.2",
"ethers": "^5.4.2",
@ -53,6 +53,6 @@
"tap-spec": "^5.0.0"
},
"typings": "src/index.d.ts",
"gitHead": "baa8abc9b912288b7a2546bedc717a9229f652c4",
"gitHead": "a92b8aa830067f879c96b41e301bc3174b87e551",
"types": "./src/index.d.ts"
}

@ -1,6 +1,6 @@
{
"name": "@remix-project/remix-debug",
"version": "0.5.62",
"version": "0.5.63",
"description": "Tool to debug Ethereum transactions",
"contributors": [
{
@ -26,10 +26,10 @@
"@ethereumjs/tx": "5.4.0",
"@ethereumjs/util": "9.1.0",
"@ethereumjs/vm": "8.1.1",
"@remix-project/remix-astwalker": "^0.0.92",
"@remix-project/remix-lib": "^0.5.69",
"@remix-project/remix-simulator": "^0.2.62",
"@remix-project/remix-solidity": "^0.5.48",
"@remix-project/remix-astwalker": "^0.0.93",
"@remix-project/remix-lib": "^0.5.70",
"@remix-project/remix-simulator": "^0.2.63",
"@remix-project/remix-solidity": "^0.5.49",
"ansi-gray": "^0.1.1",
"async": "^2.6.2",
"color-support": "^1.1.3",
@ -69,6 +69,6 @@
},
"homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-debug#readme",
"typings": "src/index.d.ts",
"gitHead": "baa8abc9b912288b7a2546bedc717a9229f652c4",
"gitHead": "a92b8aa830067f879c96b41e301bc3174b87e551",
"types": "./src/index.d.ts"
}

@ -1,6 +1,6 @@
{
"name": "@remix-project/remix-lib",
"version": "0.5.69",
"version": "0.5.70",
"description": "Library to various Remix tools",
"contributors": [
{
@ -55,6 +55,6 @@
},
"homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-lib#readme",
"typings": "src/index.d.ts",
"gitHead": "baa8abc9b912288b7a2546bedc717a9229f652c4",
"gitHead": "a92b8aa830067f879c96b41e301bc3174b87e551",
"types": "./src/index.d.ts"
}

@ -16,7 +16,7 @@ export type Transaction = {
export class TxRunner {
event
pendingTxs
queusTxs
queueTxs
opt
internalRunner
constructor (internalRunner, opt) {
@ -25,7 +25,7 @@ export class TxRunner {
this.event = new EventManager()
this.pendingTxs = {}
this.queusTxs = []
this.queueTxs = []
}
rawRun (args: Transaction, confirmationCb, gasEstimationForceSend, promptCb, cb) {
@ -42,14 +42,14 @@ export class TxRunner {
function run (self, tx: Transaction, stamp, confirmationCb, gasEstimationForceSend = null, promptCb = null, callback = null) {
if (Object.keys(self.pendingTxs).length) {
return self.queusTxs.push({ tx, stamp, confirmationCb, gasEstimationForceSend, promptCb, callback })
return self.queueTxs.push({ tx, stamp, confirmationCb, gasEstimationForceSend, promptCb, callback })
}
self.pendingTxs[stamp] = tx
self.execute(tx, confirmationCb, gasEstimationForceSend, promptCb, function (error, result) {
delete self.pendingTxs[stamp]
if (callback && typeof callback === 'function') callback(error, result)
if (self.queusTxs.length) {
const next = self.queusTxs.pop()
if (self.queueTxs.length) {
const next = self.queueTxs.pop()
run(self, next.tx, next.stamp, next.confirmationCb, next.gasEstimationForceSend, next.promptCb, next.callback)
}
})

@ -24,7 +24,7 @@ export class TxRunnerVM {
blockNumber
pendingTxs
vmaccounts
queusTxs
queueTxs
blocks: Uint8Array[]
logsManager
commonContext
@ -41,7 +41,7 @@ export class TxRunnerVM {
this.commonContext = this.getVMObject().common
this.pendingTxs = {}
this.vmaccounts = vmaccounts
this.queusTxs = []
this.queueTxs = []
/*
txHash is generated using the nonce,
in order to have unique transaction hash, we need to keep using different nonce (in case of a call)

@ -1,6 +1,6 @@
{
"name": "@remix-project/remix-simulator",
"version": "0.2.62",
"version": "0.2.63",
"description": "Ethereum IDE and tools for the web",
"contributors": [
{
@ -23,7 +23,7 @@
"@ethereumjs/util": "9.1.0",
"@ethereumjs/vm": "8.1.1",
"@metamask/eth-sig-util": "^7.0.2",
"@remix-project/remix-lib": "^0.5.69",
"@remix-project/remix-lib": "^0.5.70",
"ansi-gray": "^0.1.1",
"async": "^3.1.0",
"body-parser": "^1.18.2",
@ -71,6 +71,6 @@
},
"homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-simulator#readme",
"typings": "src/index.d.ts",
"gitHead": "baa8abc9b912288b7a2546bedc717a9229f652c4",
"gitHead": "a92b8aa830067f879c96b41e301bc3174b87e551",
"types": "./src/index.d.ts"
}

@ -54,7 +54,6 @@ export class Provider {
pendingRequests: Array<any>
constructor (options: ProviderOptions = {} as ProviderOptions) {
console.log(options)
this.options = options
this.connected = true
this.vmContext = new VMContext(options['fork'], options['nodeUrl'], options['blockNumber'], options['stateDb'], options['blocks'])

@ -1,6 +1,6 @@
{
"name": "@remix-project/remix-solidity",
"version": "0.5.48",
"version": "0.5.49",
"description": "Tool to load and run Solidity compiler",
"main": "src/index.js",
"types": "src/index.d.ts",
@ -19,7 +19,7 @@
"@ethereumjs/tx": "5.4.0",
"@ethereumjs/util": "9.1.0",
"@ethereumjs/vm": "8.1.1",
"@remix-project/remix-lib": "^0.5.69",
"@remix-project/remix-lib": "^0.5.70",
"async": "^2.6.2",
"eslint-scope": "^5.0.0",
"ethers": "^5.4.2",
@ -57,5 +57,5 @@
},
"homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-solidity#readme",
"typings": "src/index.d.ts",
"gitHead": "baa8abc9b912288b7a2546bedc717a9229f652c4"
"gitHead": "a92b8aa830067f879c96b41e301bc3174b87e551"
}

@ -1,6 +1,6 @@
{
"name": "@remix-project/remix-tests",
"version": "0.2.62",
"version": "0.2.63",
"description": "Tool to test Solidity smart contracts",
"main": "src/index.js",
"types": "./src/index.d.ts",
@ -41,9 +41,9 @@
"@ethereumjs/tx": "5.4.0",
"@ethereumjs/util": "9.1.0",
"@ethereumjs/vm": "8.1.1",
"@remix-project/remix-lib": "^0.5.69",
"@remix-project/remix-simulator": "^0.2.62",
"@remix-project/remix-solidity": "^0.5.48",
"@remix-project/remix-lib": "^0.5.70",
"@remix-project/remix-simulator": "^0.2.63",
"@remix-project/remix-solidity": "^0.5.49",
"@remix-project/remix-url-resolver": "^0.0.42",
"ansi-gray": "^0.1.1",
"async": "^2.6.0",
@ -89,5 +89,5 @@
"@ethereumjs/trie": "6.2.1"
},
"typings": "src/index.d.ts",
"gitHead": "baa8abc9b912288b7a2546bedc717a9229f652c4"
"gitHead": "a92b8aa830067f879c96b41e301bc3174b87e551"
}

@ -9,7 +9,7 @@ export class RemixInLineCompletionProvider implements monacoTypes.languages.Inli
props: EditorUIProps
monaco: any
completionEnabled: boolean
task: string
task: string = 'code_completion'
currentCompletion: any
private lastRequestTime: number = 0;
private readonly minRequestInterval: number = 200;
@ -60,13 +60,6 @@ export class RemixInLineCompletionProvider implements monacoTypes.languages.Inli
endColumn: getTextAtLine(model.getLineCount()).length + 1,
});
if (!word.endsWith(' ') &&
!word.endsWith('.') &&
!word.endsWith('"') &&
!word.endsWith('(')) {
return;
}
try {
const split = word.split('\n')
if (split.length < 2) return

@ -2,7 +2,7 @@ import React, { useState, useRef, useEffect, useReducer } from 'react' // eslint
import { FormattedMessage, useIntl } from 'react-intl'
import { isArray } from 'lodash'
import Editor, { DiffEditor, loader, Monaco } from '@monaco-editor/react'
import { AlertModal } from '@remix-ui/app'
import { AppModal } from '@remix-ui/app'
import { ConsoleLogs, QueryParams } from '@remix-project/remix-lib'
import { reducerActions, reducerListener, initialState } from './actions/editor'
import { solidityTokensProvider, solidityLanguageConfig } from './syntaxes/solidity'
@ -664,11 +664,26 @@ export const EditorUI = (props: EditorUIProps) => {
}
})
editor.onDidPaste((e) => {
editor.onDidPaste(async (e) => {
if (!pasteCodeRef.current && e && e.range && e.range.startLineNumber >= 0 && e.range.endLineNumber >= 0 && e.range.endLineNumber - e.range.startLineNumber > 10) {
const modalContent: AlertModal = {
// get the file name
const pastedCode = editor.getModel().getValueInRange(e.range)
const pastedCodePrompt = intl.formatMessage({ id: 'editor.PastedCodeSafety' }, { content:pastedCode })
const modalContent: AppModal = {
id: 'newCodePasted',
title: intl.formatMessage({ id: 'editor.title1' }),
title: "New code pasted",
okLabel: 'Ask RemixAI',
cancelLabel: 'Close',
cancelFn: () => {},
okFn: async () => {
await props.plugin.call('popupPanel', 'showPopupPanel', true)
setTimeout(async () => {
props.plugin.call('remixAI', 'chatPipe', 'vulnerability_check', pastedCodePrompt)
}, 500)
// add matamo event
_paq.push(['trackEvent', 'ai', 'remixAI', 'vulnerability_check_pasted_code'])
},
message: (
<div>
{' '}
@ -699,10 +714,9 @@ export const EditorUI = (props: EditorUIProps) => {
</div>
</div>
</div>
),
)
}
props.plugin.call('notification', 'alert', modalContent)
pasteCodeRef.current = true
props.plugin.call('notification', 'modal', modalContent)
_paq.push(['trackEvent', 'editor', 'onDidPaste', 'more_than_10_lines'])
}
})

@ -1236,7 +1236,7 @@ export const solidityTokensProvider = {
'abstract',
'payable',
'nonpayable',
'constants',
'constant',
'immutable',
'assert',
'require',

@ -102,6 +102,19 @@ export const EnvironmentExplorerUI = (props: environmentExplorerUIProps) => {
}}
>
<div data-id={`${provider.name}desc`}>{(section.descriptionFn && section.descriptionFn(provider)) || provider.description}</div>
{ provider.isForkedState && <CustomTooltip
placement="auto"
tooltipId={`overlay-tooltip-${provider.name}`}
tooltipText="Delete Environment Immediately"
>
<span
onClick={async () => props.deleteForkedState(provider)}
className="btn btn-sm mt-1 border border-danger"
>
Delete Environment
</span>
</CustomTooltip>
}
</RemixUIGridCell>
))}
</RemixUIGridSection>

@ -8,6 +8,7 @@ export type environmentExplorerUIProps = {
providersFlat: { [key: string]: Provider }
pinnedProviders: string[]
}
deleteForkedState (provider: Provider): Promise<void>
pinStateCallback (provider: Provider, pinned: boolean): Promise<void>
profile: Profile
}

@ -27,9 +27,6 @@
.remixui_grid_cell_pin {
width: 1rem;
height: 1rem;
position: relative;
right: 0.9rem;
top: -0.7rem;
background: transparent;
z-index: 1000;
}

@ -86,8 +86,8 @@ export const RemixUIGridCell = (props: RemixUIGridCellProps) => {
{ anyEnabled && <div className='mr-2 mt-3 pb-1 d-flex flex-column'>
<div className='d-flex flex-grid'>
<div className={ `${pinned ? "" : "border-dark "}` + "d-flex mx-0 p-2 bg-light border border-secondary remixui_grid_cell_container " + props.classList || ''} data-id={"remixUIGS" + props.title}>
<div className="d-flex remixui_grid_cell w-100 flex-column">
{ !props.hideTitle && <div className='d-flex flex-row pb-1 mb-1 align-items-end' style={{ minWidth: '8rem', height: '1rem' }}>
<div className="d-flex remixui_grid_cell w-100 space-between justify-content-between flex-column">
{ !props.hideTitle && <div className='d-flex flex-row pb-1 my-1 align-items-end' style={{ minWidth: '8rem', height: '1rem' }}>
{ props.logo ? props.logoURL !== '' ?
<a href={props.logoURL} target="__blank">
<img className='remixui_grid_view_logo mr-1' src={props.logo} style={{ width: '1rem', height: '1rem' }}/>
@ -103,24 +103,25 @@ export const RemixUIGridCell = (props: RemixUIGridCellProps) => {
tooltipText={ props.titleTooltip ? props.titleTooltip : props.title }
>
<label
className='m-0 p-0 text-uppercase align-items-left font-weight-bold text-truncate overflow-hidden whitespace-nowra'
className='m-0 p-0 text-uppercase align-items-left font-weight-bold text-truncate overflow-hidden whitespace-nowrap'
>{ props.title }
</label>
</CustomTooltip>
}
</div> }
{ props.children }
{ filterCon.showPin && <button
className={`${pinned ? 'fas fa-toggle-on fa-lg text-dark' : 'fas fa-toggle-off fa-lg text-secondary'}` + ` fa-regular border-0 p-0 mt-2 align-self-end mr-1 remixui_grid_cell_pin`}
style={{ fontSize: 'large' }}
data-id={`${pinned ? `${props.id}-pinned` : `${props.id}-unpinned`}`}
onClick={async () => {
if (!props.pinStateCallback) setPinned(!pinned)
if (await props.pinStateCallback(!pinned)) setPinned(!pinned)
}}
></button>}
</div>
</div>
{ filterCon.showPin && <button
className={`${pinned ? 'fa-circle-check text-dark' : 'fa-circle text-secondary'}` + ` fa-regular border-0 mb-0 remixui_grid_cell_pin`}
style={{ fontSize: 'large' }}
data-id={`${pinned ? `${props.id}-pinned` : `${props.id}-unpinned`}`}
onClick={async () => {
if (!props.pinStateCallback) setPinned(!pinned)
if (await props.pinStateCallback(!pinned)) setPinned(!pinned)
}}
></button>}
{ props.tagList && <div className={`d-flex flex-column align-items-begin ` +`${filterCon.showPin ? 'remixui_grid_cell_tags' : 'remixui_grid_cell_tags_no_pin'}`}>
{ Object.keys(props.tagList).map((key) => (
filterCon.keyValueMap[props.tagList[key]]?.enabled && (

@ -50,8 +50,8 @@ function HomeTabFeatured(props:HomeTabFeaturedProps) {
autoPlaySpeed={10000}
dotListClass="position-relative mt-2"
>
<div
className="mx-1 px-1 d-flex" // Please do not delete. just comment this out. To be used every year.
{false && <div // no this is not a mistake. keep it false until next year ;)
className="mx-1 px-1 d-flex d-none" // Please do not delete. just comment this out or keep hidden. To be used every year.
>
<a href="https://cryptpad.fr/form/#/2/form/view/pV-DdryeJoYUWvW+gXsFaMNynEY7t5mUsgeD1urgwSE/" target="__blank">
<img className="remixui_carouselImage" src={'/assets/img/solSurvey2024.webp'} alt=""></img>
@ -83,7 +83,7 @@ function HomeTabFeatured(props:HomeTabFeaturedProps) {
</a>
</p>
</div>
</div>
</div> }
<div className="mr-1 pr-1 d-flex align-items-center justify-content-center h-100">
<a href={releaseDetails.moreLink} target="__blank">
<img src={'assets/img/remi_drums_whatsnew.webp'} className="remixui_carouselImage" alt=""></img>

@ -34,7 +34,7 @@ export interface CarouselProps {
beforeChange?: (nextSlide: number, state: StateCallBack) => void; // Change callback before sliding every time. `(previousSlide, currentState) => ...`
sliderClass?: string; // Use this to style your own track list.
itemClass?: string; // Use this to style your own Carousel item. For example add padding-left and padding-right
itemAriaLabel?: string; // Use this to add your own Carousel item aria-label.if it is not defined the child aria label will be applied if the child dont have one than a default empty string will be applied
itemAriaLabel?: string; // Use this to add your own Carousel item aria-label.if it is not defined the child aria label will be applied if the child doesn't have one, then a default empty string will be applied
containerClass?: string; // Use this to style the whole container. For example add padding to allow the "dots" or "arrows" to go to other places without being overflown.
className?: string; // Use this to style the whole container with styled-components
dotListClass?: string; // Use this to style the dot list.

@ -22,7 +22,7 @@ const txHelper = remixLib.execution.txHelper
const txFormat = remixLib.execution.txFormat
const loadContractFromAddress = (plugin: RunTab, address, confirmCb, cb) => {
if (/.(.abi)$/.exec(plugin.config.get('currentFile'))) {
if (/\.(abi)$/.exec(plugin.config.get('currentFile'))) {
confirmCb(() => {
let abi
try {

@ -31,6 +31,10 @@ export function EnvironmentUI(props: EnvironmentProps) {
const forkStatePrompt = (defaultName: string) => {
return (
<div data-id="forkVmStateModal">
<ul className='ml-3'>
<li><FormattedMessage id="udapp.forkVmStateDesc1"/></li>
<li><FormattedMessage id="udapp.forkVmStateDesc2"/></li>
</ul>
<label id="stateName" className="form-check-label" style={{ fontWeight: 'bolder' }}>
<FormattedMessage id="udapp.forkStateLabel" />
</label>
@ -49,10 +53,10 @@ export function EnvironmentUI(props: EnvironmentProps) {
return (
<div data-id="deleteVmStateModal">
<ul className='ml-3'>
<li><FormattedMessage id="udapp.deleteVmStateDesc1"/></li>
<li><FormattedMessage id="udapp.deleteVmStateDesc2"/></li>
<li><FormattedMessage id="udapp.resetVmStateDesc1"/></li>
<li><FormattedMessage id="udapp.resetVmStateDesc2"/></li>
</ul>
<FormattedMessage id="udapp.deleteVmStateDesc3"/>
<FormattedMessage id="udapp.resetVmStateDesc3"/>
</div>
)
}
@ -83,15 +87,15 @@ export function EnvironmentUI(props: EnvironmentProps) {
} else props.runTabPlugin.call('notification', 'toast', `State not available to fork, as no transactions have been made for selected environment & selected workspace.`)
}
const deleteVmState = async() => {
const resetVmState = async() => {
_paq.push(['trackEvent', 'udapp', 'deleteState', `deleteState clicked`])
const context = currentProvider.name
const contextExists = await props.runTabPlugin.call('fileManager', 'exists', `.states/${context}/state.json`)
if (contextExists) {
props.modal(
intl.formatMessage({ id: 'udapp.deleteVmStateTitle' }),
intl.formatMessage({ id: 'udapp.resetVmStateTitle' }),
deleteVmStatePrompt(),
intl.formatMessage({ id: 'udapp.delete' }),
intl.formatMessage({ id: 'udapp.reset' }),
async () => {
const currentProvider = await props.runTabPlugin.call('blockchain', 'getCurrentProvider')
// Reset environment blocks and account data
@ -103,35 +107,28 @@ export function EnvironmentUI(props: EnvironmentProps) {
// If there are pinned contracts, delete pinned contracts folder
const isPinnedContracts = await props.runTabPlugin.call('fileManager', 'exists', `.deploys/pinned-contracts/${context}`)
if (isPinnedContracts) await props.runTabPlugin.call('fileManager', 'remove', `.deploys/pinned-contracts/${context}`)
props.runTabPlugin.call('notification', 'toast', `VM state deleted successfully.`)
_paq.push(['trackEvent', 'udapp', 'deleteState', `VM state deleted`])
props.runTabPlugin.call('notification', 'toast', `VM state reset successfully.`)
_paq.push(['trackEvent', 'udapp', 'deleteState', `VM state reset`])
},
intl.formatMessage({ id: 'udapp.cancel' }),
null
)
} else props.runTabPlugin.call('notification', 'toast', `State not available to delete, as no transactions have been made for selected environment & selected workspace.`)
} else props.runTabPlugin.call('notification', 'toast', `State not available to reset, as no transactions have been made for selected environment & selected workspace.`)
}
const isL2 = (providerDisplayName: string) => providerDisplayName && (providerDisplayName.startsWith('L2 - Optimism') || providerDisplayName.startsWith('L2 - Arbitrum'))
return (
<div className="udapp_crow">
<label id="selectExEnv" className="udapp_settingsLabel">
<label id="selectExEnv" className="udapp_settingsLabel w-100">
<FormattedMessage id="udapp.environment" />
<CustomTooltip placement={'auto-end'} tooltipClasses="text-nowrap" tooltipId="info-recorder" tooltipText={<FormattedMessage id="udapp.tooltipText2" />}>
<a href="https://chainlist.org/" target="_blank">
<i className={'ml-2 fas fa-plug'} aria-hidden="true"></i>
</a>
</CustomTooltip>
<CustomTooltip placement={'auto-end'} tooltipClasses="text-wrap" tooltipId="runAndDeployAddresstooltip" tooltipText={<FormattedMessage id="udapp.environmentDocs" />}>
<a href="https://remix-ide.readthedocs.io/en/latest/run.html#environment" target="_blank" rel="noreferrer">
<i className="udapp_infoDeployAction ml-2 fas fa-info"></i>
</a>
</CustomTooltip>
{ currentProvider && currentProvider.isVM && isSaveEvmStateChecked && <CustomTooltip placement={'auto-end'} tooltipClasses="text-wrap" tooltipId="forkStatetooltip" tooltipText={<FormattedMessage id="udapp.forkStateTitle" />}>
<i className="udapp_infoDeployAction ml-2 fas fa-code-branch" style={{ cursor: 'pointer' }} onClick={forkState} data-id="fork-state-icon"></i>
</CustomTooltip> }
{ currentProvider && currentProvider.isVM && isSaveEvmStateChecked && <CustomTooltip placement={'auto-end'} tooltipClasses="text-wrap" tooltipId="deleteVMStatetooltip" tooltipText={<FormattedMessage id="udapp.deleteVmStateTitle" />}>
<i className="udapp_infoDeployAction ml-2 fas fa-trash" style={{ cursor: 'pointer' }} onClick={deleteVmState} data-id="delete-state-icon"></i>
{ currentProvider && currentProvider.isVM && isSaveEvmStateChecked && <CustomTooltip placement={'auto-end'} tooltipClasses="text-wrap" tooltipId="deleteVMStatetooltip" tooltipText={<FormattedMessage id="udapp.resetVmStateTitle" />}>
<span onClick={resetVmState} style={{ cursor: 'pointer', float: 'right', textTransform: 'none' }}>
<i className="udapp_infoDeployAction ml-2 fas fa-refresh" data-id="delete-state-icon"></i>
<span className="ml-1" style = {{ textTransform: 'none', fontSize: '13px' }}>Reset State</span>
</span>
</CustomTooltip> }
</label>
<div className="udapp_environment" data-id={`selected-provider-${currentProvider && currentProvider.name}`}>

@ -235,6 +235,16 @@ export function RunTabUI(props: RunTabProps) {
}
}, [runTab.popup])
useEffect(() => {
if (runTab.selectExEnv.includes('injected') &&
Object.entries(runTab.accounts.loadedAccounts).length === 0 &&
runTab.accounts.selectedAccount.length > 0) {
// switch to vm-cancum because no account is loaded from injected provider
const context = plugin.blockchain.defaultPinnedProviders[0] // vm-cancun
setExecutionEnvironment({ context, fork: '' })
}
}, [runTab.accounts.loadedAccounts])
const setCheckIpfs = (value: boolean) => {
dispatch(setIpfsCheckedState(value))
}

@ -25,6 +25,7 @@ export class Blockchain extends Plugin<any, any> {
};
setupProviders(): void;
providers: any;
defaultPinnedProviders: string[];
getCurrentProvider(): any;
/** Return the list of accounts */
getAccounts(cb?: any): any;

@ -5,6 +5,7 @@ import { faCaretDown, faCaretRight, faCheck, faExclamationCircle, faRedoAlt, faT
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { CustomScriptRunner } from "./custom-script-runner";
import { CustomTooltip } from "@remix-ui/helper";
const _paq = (window._paq = window._paq || []) // eslint-disable-line
export interface ScriptRunnerUIProps {
loadScriptRunner: (config: ProjectConfiguration) => void;
@ -62,12 +63,18 @@ export const ScriptRunnerUI = (props: ScriptRunnerUIProps) => {
</div>}
{!config.isLoading && config.errorStatus && config.error &&
<div onClick={() => loadScriptRunner(config)} className="pointer px-2">
<div
onClick={() => {
loadScriptRunner(config)
_paq.push(['trackEvent', 'scriptRunnerPlugin', 'loadScriptRunnerConfig', config.name])
}}
className="pointer px-2"
>
<FontAwesomeIcon data-id={`sr-reload-${config.name}`} icon={faRedoAlt}></FontAwesomeIcon>
</div>}
{!config.isLoading && !config.errorStatus && !config.error &&
<div onClick={() => loadScriptRunner(config)} className="pointer px-2">
{activeConfig && activeConfig.name !== config.name ?
{ activeConfig && activeConfig.name !== config.name ?
<FontAwesomeIcon data-id={`sr-toggle-${config.name}`} icon={faToggleOn}></FontAwesomeIcon> :
<FontAwesomeIcon data-id={`sr-loaded-${config.name}`} className="text-success" icon={faCheck}></FontAwesomeIcon>
}
@ -87,7 +94,9 @@ export const ScriptRunnerUI = (props: ScriptRunnerUIProps) => {
</li>
))}
</ul></>
</Accordion.Collapse></div>))}
</Accordion.Collapse>
</div>))
}
</Accordion>
{enableCustomScriptRunner &&
<CustomScriptRunner
@ -98,6 +107,6 @@ export const ScriptRunnerUI = (props: ScriptRunnerUIProps) => {
publishedConfigurations={configurations.filter((config) => config.publish)}
/>}
</div>
);
};
)
}

@ -486,6 +486,7 @@ export const CompilerContainer = (props: CompilerContainerProps) => {
compileIcon.current.classList.remove('remixui_spinningIcon')
compileIcon.current.classList.remove('remixui_bouncingIcon')
if (!state.autoCompile || (state.autoCompile && state.matomoAutocompileOnce)) {
_paq.push(['trackEvent', 'compiler', 'compiled', 'solCompilationFinishedTriggeredByUser'])
_paq.push(['trackEvent', 'compiler', 'compiled', 'with_config_file_' + state.useFileConfiguration])
_paq.push(['trackEvent', 'compiler', 'compiled', 'with_version_' + _retrieveVersion()])
if (state.autoCompile && state.matomoAutocompileOnce) {

@ -235,12 +235,7 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
try {
if (script.trim().startsWith('git')) {
// await this.call('git', 'execute', script) code might be used in the future
// TODO: rm gpt or redirect gpt to sol-pgt
} else if (script.trim().startsWith('gpt')) {
call('terminal', 'log',{ type: 'warn', value: `> ${script}` })
await call('remixAI', 'solidity_answer', script) // No streaming supported in terminal
_paq.push(['trackEvent', 'ai', 'remixAI', 'askFromTerminal'])
} else if (script.trim().startsWith('sol-gpt')) {
} else if (script.trim().startsWith('gpt') || script.trim().startsWith('sol-gpt')) {
call('terminal', 'log',{ type: 'warn', value: `> ${script}` })
await call('remixAI', 'solidity_answer', script) // No streaming supported in terminal
_paq.push(['trackEvent', 'ai', 'remixAI', 'askFromTerminal'])

@ -1,6 +1,6 @@
{
"name": "@remix-project/remix-url-resolver",
"version": "0.0.91",
"version": "0.0.92",
"description": "Solidity import url resolver engine",
"main": "src/index.js",
"types": "src/index.d.ts",
@ -41,5 +41,5 @@
"typescript": "^3.1.6"
},
"typings": "src/index.d.ts",
"gitHead": "baa8abc9b912288b7a2546bedc717a9229f652c4"
"gitHead": "a92b8aa830067f879c96b41e301bc3174b87e551"
}

@ -1,6 +1,6 @@
{
"name": "@remix-project/remix-ws-templates",
"version": "1.0.56",
"version": "1.0.57",
"description": "Create a Remix IDE workspace using different templates",
"main": "src/index.js",
"types": "src/index.d.ts",
@ -24,5 +24,5 @@
"ethers": "^5.4.2",
"web3": "^4.1.1"
},
"gitHead": "baa8abc9b912288b7a2546bedc717a9229f652c4"
"gitHead": "a92b8aa830067f879c96b41e301bc3174b87e551"
}

@ -1,6 +1,6 @@
{
"name": "@remix-project/remixd",
"version": "0.6.42",
"version": "0.6.43",
"description": "remix server: allow accessing file system from remix.ethereum.org and start a dev environment (see help section)",
"main": "index.js",
"types": "./index.d.ts",

@ -1,11 +1,10 @@
{
"version": "v0.59.0",
"version": "v0.60.0",
"title": "RELEASE HIGHLIGHTS",
"highlight1": "Fork & delete VM state",
"highlight2": "Syntax highlighting for Noir(.nr) files",
"highlight3": "",
"highlight1": "Delete forked state environments",
"highlight2": "Scan code pasted into editor using AI",
"highlight3": "Added Linea chain deployment environment",
"highlight4": "",
"more": "Read More",
"moreLink": "https://medium.com/remix-ide/remix-release-v0-59-0-306881e41984?source=friends_link&sk=be2390827519bf2d7530f013021160b9"
"moreLink": "https://medium.com/remix-ide/remix-release-v0-60-0-a86fb7649d62?source=friends_link&sk=63c8c24be0b818dbd855947f2804aad2"
}
Loading…
Cancel
Save