Merge branch 'master' into foundry

pull/3285/head
bunsenstraat 2 years ago committed by GitHub
commit 9f19ba5457
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 8
      apps/remix-ide/src/app/tabs/locales/en/filePanel.json
  2. 16
      apps/remix-ide/src/app/tabs/locales/en/home.json
  3. 8
      apps/remix-ide/src/app/tabs/locales/zh/filePanel.json
  4. 3
      apps/remix-ide/src/app/tabs/locales/zh/home.json
  5. 14
      apps/remix-ide/src/app/tabs/web3-provider.js
  6. BIN
      apps/remix-ide/src/assets/img/dgit.webp
  7. BIN
      apps/remix-ide/src/assets/img/oneclickdapp.webp
  8. 15
      libs/ghaction-helper/.eslintrc
  9. 1
      libs/ghaction-helper/.npmignore
  10. 7
      libs/ghaction-helper/README.md
  11. 32
      libs/ghaction-helper/package.json
  12. 30
      libs/ghaction-helper/project.json
  13. 21
      libs/ghaction-helper/src/artifacts-helper.ts
  14. 9
      libs/ghaction-helper/src/chai.ts
  15. 8
      libs/ghaction-helper/src/ethers.ts
  16. 2
      libs/ghaction-helper/src/index.ts
  17. 265
      libs/ghaction-helper/src/methods.ts
  18. 53
      libs/ghaction-helper/src/signer.ts
  19. 7
      libs/ghaction-helper/tsconfig.json
  20. 15
      libs/ghaction-helper/tsconfig.lib.json
  21. 4
      libs/remix-analyzer/project.json
  22. 4
      libs/remix-astwalker/project.json
  23. 13
      libs/remix-debug/project.json
  24. 4
      libs/remix-lib/project.json
  25. 13
      libs/remix-simulator/project.json
  26. 4
      libs/remix-solidity/project.json
  27. 6
      libs/remix-ui/debugger-ui/src/lib/debugger-ui.tsx
  28. 22
      libs/remix-ui/debugger-ui/src/lib/vm-debugger/global-variables.tsx
  29. 37
      libs/remix-ui/home-tab/src/lib/components/homeTabFeaturedPlugins.tsx
  30. 41
      libs/remix-ui/home-tab/src/lib/components/homeTabGetStarted.tsx
  31. 16
      libs/remix-ui/home-tab/src/lib/components/homeTabLearn.tsx
  32. 36
      libs/remix-ui/workspace/src/lib/actions/workspace.ts
  33. 322
      libs/remix-ui/workspace/src/lib/components/workspace-hamburger.tsx
  34. 4
      libs/remix-ui/workspace/src/lib/contexts/index.ts
  35. 14
      libs/remix-ui/workspace/src/lib/providers/FileSystemProvider.tsx
  36. 249
      libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx
  37. 52
      libs/remix-ui/workspace/src/lib/utils/constants.ts
  38. 4
      libs/remix-url-resolver/project.json
  39. 21
      libs/remix-ws-templates/project.json
  40. 4
      package.json
  41. 3
      tsconfig.paths.json
  42. 21
      yarn.lock

@ -15,8 +15,12 @@
"filePanel.workspace.restore": "Restore Workspace Backup",
"filePanel.workspace.clone": "Clone Git Repository",
"filePanel.workspace.enterGitUrl": "Enter git repository url",
"filePanel.workspace.solghaction": "Add the Solidity GitHub Action file. Push to a repository to start running it in the GitHub CI.",
"filePanel.solghaction": "Add Solidity GitHub Action",
"filePanel.workspace.solghaction": "Adds a preset yml file to run solidity unit tests on github actions CI.",
"filePanel.solghaction": "Solidity Test Workflow",
"filePanel.workspace.tssoltestghaction": "Adds a preset yml file to run mocha and chai tests for solidity on github actions CI",
"filePanel.tssoltestghaction": "Mocha Chai Test Workflow",
"filePanel.workspace.slitherghaction": "Adds a preset yml file to run slither analysis on github actions CI",
"filePanel.slitherghaction": "Slither Workflow",
"filePanel.newFile": "New File",
"filePanel.newFolder": "New Folder",
"filePanel.rename": "Rename",

@ -21,20 +21,24 @@
"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.dgitPluginDesc": "Add source control to your projects.",
"home.oneClickDappDesc": "Quickly generate smart contract interfaces",
"home.getStarted": "Get Started",
"home.projectTemplates": "Project Templates",
"home.blankTemplateDesc": "Create an empty workspace.",
"home.remixDefaultTemplateDesc": "Create a workspace with sample files.",
"home.ozerc20TemplateDesc": "Create an ERC20 token by importing OpenZeppelin library.",
"home.ozerc721TemplateDesc": "Create an NFT token by importing OpenZeppelin library.",
"home.ozerc1155TemplateDesc": "Create an ERC1155 token by importing OpenZeppelin library.",
"home.gnosisSafeMultisigTemplateDesc": "Create Multi-Signature wallets using this template.",
"home.zeroxErc20TemplateDesc": "Create an ERC20 token by importing 0xProject contract.",
"home.learn": "Learn",
"home.remixBasics": "Remix Basics",
"home.remixBasicsDesc":"Introduction to Remix's interface and concepts used in Ethereum, as well as the basics of Solidity.",
"home.remixIntermediate": "Remix Intermediate",
"home.remixIntermediateDesc": "Using the web3.js to interact with a contract. Using Recorder tool.",
"home.remixAdvanced": "Remix Advanced",
"home.remixAdvancedDesc": "Learn the Proxy Pattern and working with Libraries in Remix. Learn to use the Debugger.",
"home.learnEth1": "Remix Basics",
"home.learnEth1Desc":"An introduction to Remix's interface and basic operations.",
"home.learnEth2": "Intro to Solidity",
"home.learnEth2Desc": "Interactively learn Solidity beginner concepts.",
"home.remixAdvanced": "Deploying with Libraries",
"home.remixAdvancedDesc": "Learn to deploy with libraries in Remix",
"home.remixYoutubePlaylist": "Remix Youtube Playlist",
"home.remixTwitterProfile": "Remix Twitter Profile",
"home.remixLinkedinProfile": "Remix Linkedin Profile",

@ -15,8 +15,12 @@
"filePanel.workspace.restore": "恢复工作空间",
"filePanel.workspace.clone": "克隆 Git 仓库",
"filePanel.workspace.enterGitUrl": "输入 Git 仓库地址",
"filePanel.workspace.solghaction": "添加 Solidity GitHub Action 文件。推送到一个代码仓库,然后在 GitHub CI 中运行它。",
"filePanel.solghaction": "添加 Solidity GitHub Action",
"filePanel.workspace.solghaction": "添加预设 yml 文件以在 github 操作 CI 上运行 solidity 单元测试。",
"filePanel.solghaction": "Solidity Test Workflow",
"filePanel.workspace.tssoltestghaction": "添加一个预设的 yml 文件以在 github 操作 CI 上运行 mocha 和 chai 测试以确保可靠性",
"filePanel.tssoltestghaction": "Mocha Chai Test Workflow",
"filePanel.workspace.slitherghaction": "添加一个预设的 yml 文件以在 github actions CI 上运行 slither 分析",
"filePanel.slitherghaction": "Slither Workflow",
"filePanel.newFile": "新建文件",
"filePanel.newFolder": "新建文件夹",
"filePanel.rename": "重命名",

@ -21,12 +21,15 @@
"home.solhintPluginDesc": "Solhint 是一个用于检查 Solidity 代码的开源项目",
"home.sourcifyPluginDesc": "Solidity 合约和元数据验证服务。",
"home.unitTestPluginDesc": "在 Solidity 中为你的合约编写和运行单元测试。",
"home.dgitPluginDesc": "",
"home.getStarted": "开始使用",
"home.projectTemplates": "项目模板",
"home.blankTemplateDesc": "创建一个空的工作空间。",
"home.remixDefaultTemplateDesc": "创建一个带有样本文件的工作空间",
"home.ozerc20TemplateDesc": "通过引入 OpenZeppelin 库来创建一个 ERC20 代币。",
"home.ozerc721TemplateDesc": "通过引入 OpenZeppelin 库来创建一个 NFT 代币。",
"home.ozerc1155TemplateDesc": "",
"home.gnosisSafeMultisigTemplateDesc": "",
"home.zeroxErc20TemplateDesc": "通过引入 0xProject 合约来创建一个 ERC20 代币。",
"home.learn": "学习",
"home.remixBasics": "Remix 基础",

@ -30,10 +30,16 @@ export class Web3ProviderModule extends Plugin {
// see https://github.com/ethereum/web3.js/pull/1018/files#diff-d25786686c1053b786cc2626dc6e048675050593c0ebaafbf0814e1996f22022R129
provider[provider.sendAsync ? 'sendAsync' : 'send'](payload, async (error, message) => {
if (error) {
const errorData = error.data ? error.data : error.message ? error.message : error
// See: https://github.com/ethers-io/ethers.js/issues/901
if (!(typeof errorData === 'string' && errorData.includes("unknown method eth_chainId"))) this.call('terminal', 'log', { value: error.data ? error.data : error.message, type: 'error' } )
return reject(errorData)
// Handle 'The method "debug_traceTransaction" does not exist / is not available.' error
if(error.message && error.code && error.code === -32601) {
this.call('terminal', 'log', { value: error.message, type: 'error' } )
return reject(error.message)
} else {
const errorData = error.data || error.message || error
// See: https://github.com/ethers-io/ethers.js/issues/901
if (!(typeof errorData === 'string' && errorData.includes("unknown method eth_chainId"))) this.call('terminal', 'log', { value: error.data || error.message, type: 'error' } )
return reject(errorData)
}
}
if (payload.method === 'eth_sendTransaction') {
if (payload.params.length && !payload.params[0].to && message.result) {

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

@ -0,0 +1,15 @@
{
"extends": "../../.eslintrc",
"rules": {
"dot-notation": "off",
"no-unused-vars": "off",
"no-use-before-define": "off"
},
"env": {
"browser": true,
"amd": true,
"node": true,
"es6": true
},
"ignorePatterns": ["!**/*"]
}

@ -0,0 +1,7 @@
# ghaction
This library was generated with [Nx](https://nx.dev).
## Running unit tests
Run `nx test ghaction` to execute the unit tests via [Jest](https://jestjs.io).

@ -0,0 +1,32 @@
{
"name": "@remix-project/ghaction-helper",
"version": "0.1.3",
"description": "Solidity Tests GitHub Action Helper",
"main": "src/index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "tsc"
},
"repository": {
"type": "git",
"url": "git+https://github.com/ethereum/remix-project.git"
},
"keywords": [],
"author": "@ioedeveloper",
"license": "ISC",
"bugs": {
"url": "https://github.com/ethereum/remix-project/issues"
},
"homepage": "https://github.com/ethereum/remix-project#readme",
"devDependencies": {
"@remix-project/remix-solidity": "^0.5.6",
"@types/chai": "^4.3.4",
"typescript": "^4.9.3"
},
"dependencies": {
"@ethereum-waffle/chai": "^3.4.4",
"chai": "^4.3.7",
"ethers": "^5.7.2",
"ganache": "^7.5.0"
}
}

@ -0,0 +1,30 @@
{
"name": "ghaction-helper",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "libs/ghaction-helper/src",
"projectType": "library",
"implicitDependencies": [
"remix-solidity"
],
"targets": {
"build": {
"executor": "@nrwl/js:tsc",
"outputs": ["{options.outputPath}"],
"options": {
"outputPath": "dist/libs/ghaction-helper",
"main": "libs/ghaction-helper/src/index.ts",
"tsConfig": "libs/ghaction-helper/tsconfig.lib.json",
"assets": []
}
},
"lint": {
"executor": "@nrwl/linter:eslint",
"outputs": ["{options.outputFile}"],
"options": {
"lintFilePatterns": ["libs/ghaction-helper/**/*.ts"]
}
}
},
"tags": []
}

@ -0,0 +1,21 @@
import { CompilationResult } from '@remix-project/remix-solidity'
//@ts-ignore
import * as fs from 'fs/promises'
import * as path from 'path'
export async function getArtifactsByContractName (contractIdentifier: string) {
//@ts-ignore
const contractArtifacts = await fs.readdir(global.remixContractArtifactsPath)
let contract
for (const artifactFile of contractArtifacts) {
//@ts-ignore
const artifact = await fs.readFile(path.join(global.remixContractArtifactsPath, artifactFile), 'utf-8')
const artifactJSON: CompilationResult = JSON.parse(artifact)
const contractFullPath = (Object.keys(artifactJSON.contracts!)).find((contractName) => artifactJSON.contracts![contractName] && artifactJSON.contracts![contractName][contractIdentifier])
contract = contractFullPath ? artifactJSON.contracts![contractFullPath!][contractIdentifier] : undefined
if (contract) break
}
return contract
}

@ -0,0 +1,9 @@
import * as chai from 'chai'
// @ts-ignore
import { waffleChai } from '@ethereum-waffle/chai'
chai.use(waffleChai)
// @ts-ignore
export * from 'chai'
export { chai }

@ -0,0 +1,8 @@
// @ts-nocheck
import { ethers } from 'ethers'
import * as hhEtherMethods from './methods'
for(const method in hhEtherMethods) Object.defineProperty(ethers, method, { value: hhEtherMethods[method]})
export * from 'ethers'
export { ethers }

@ -0,0 +1,2 @@
export * from './chai'
export * from './ethers'

@ -0,0 +1,265 @@
// @ts-ignore
import { ethers } from "ethers"
//@ts-ignore
import * as ganache from "ganache"
import { getArtifactsByContractName } from './artifacts-helper'
import { SignerWithAddress } from './signer'
const initializeProvider = () => {
//@ts-ignore
global.ganacheProvider = ganache.provider({ logging: { quiet: true } })
}
const isFactoryOptions = (signerOrOptions: any) => {
if (!signerOrOptions || signerOrOptions === undefined || signerOrOptions instanceof ethers.Signer) return false
return true
}
const isArtifact = (artifact: any) => {
const {
contractName,
sourceName,
abi,
bytecode,
deployedBytecode,
linkReferences,
deployedLinkReferences,
} = artifact
return (
typeof contractName === "string" &&
typeof sourceName === "string" &&
Array.isArray(abi) &&
typeof bytecode === "string" &&
typeof deployedBytecode === "string" &&
linkReferences !== undefined &&
deployedLinkReferences !== undefined
)
}
function linkBytecode(artifact: any, libraries: any) {
let bytecode = artifact.bytecode
for (const { sourceName, libraryName, address } of libraries) {
const linkReferences = artifact.linkReferences[sourceName][libraryName]
for (const { start, length } of linkReferences) {
bytecode =
bytecode.substr(0, 2 + start * 2) +
address.substr(2) +
bytecode.substr(2 + (start + length) * 2)
}
}
return bytecode
}
const collectLibrariesAndLink = async (artifact: any, libraries: any) => {
const neededLibraries = []
for (const [sourceName, sourceLibraries] of Object.entries(artifact.linkReferences)) {
// @ts-ignore
for (const libName of Object.keys(sourceLibraries)) {
neededLibraries.push({ sourceName, libName })
}
}
const linksToApply = new Map()
for (const [linkedLibraryName, linkedLibraryAddress] of Object.entries(libraries)) {
// @ts-ignore
if (!ethers.utils.isAddress(linkedLibraryAddress)) {
throw new Error(
`You tried to link the contract ${artifact.contractName} with the library ${linkedLibraryName}, but provided this invalid address: ${linkedLibraryAddress}`
)
}
const matchingNeededLibraries = neededLibraries.filter((lib) => {
return (
lib.libName === linkedLibraryName ||
`${lib.sourceName}:${lib.libName}` === linkedLibraryName
)
})
if (matchingNeededLibraries.length === 0) {
let detailedMessage
if (neededLibraries.length > 0) {
const libraryFQNames = neededLibraries
.map((lib) => `${lib.sourceName}:${lib.libName}`)
.map((x) => `* ${x}`)
.join("\n")
detailedMessage = `The libraries needed are:
${libraryFQNames}`
} else {
detailedMessage = "This contract doesn't need linking any libraries."
}
throw new Error(
`You tried to link the contract ${artifact.contractName} with ${linkedLibraryName}, which is not one of its libraries.
${detailedMessage}`
)
}
if (matchingNeededLibraries.length > 1) {
const matchingNeededLibrariesFQNs = matchingNeededLibraries
.map(({ sourceName, libName }) => `${sourceName}:${libName}`)
.map((x) => `* ${x}`)
.join("\n")
throw new Error(
`The library name ${linkedLibraryName} is ambiguous for the contract ${artifact.contractName}.
It may resolve to one of the following libraries:
${matchingNeededLibrariesFQNs}
To fix this, choose one of these fully qualified library names and replace where appropriate.`
)
}
const [neededLibrary] = matchingNeededLibraries
const neededLibraryFQN = `${neededLibrary.sourceName}:${neededLibrary.libName}`
// The only way for this library to be already mapped is
// for it to be given twice in the libraries user input:
// once as a library name and another as a fully qualified library name.
if (linksToApply.has(neededLibraryFQN)) {
throw new Error(
`The library names ${neededLibrary.libName} and ${neededLibraryFQN} refer to the same library and were given as two separate library links.
Remove one of them and review your library links before proceeding.`
)
}
linksToApply.set(neededLibraryFQN, {
sourceName: neededLibrary.sourceName,
libraryName: neededLibrary.libName,
address: linkedLibraryAddress,
})
}
if (linksToApply.size < neededLibraries.length) {
const missingLibraries = neededLibraries
.map((lib) => `${lib.sourceName}:${lib.libName}`)
.filter((libFQName) => !linksToApply.has(libFQName))
.map((x) => `* ${x}`)
.join("\n")
throw new Error(
`The contract ${artifact.contractName} is missing links for the following libraries:
${missingLibraries}`
)
}
// @ts-ignore
return linkBytecode(artifact, [...linksToApply.values()])
}
// Convert output.contracts.<filename>.<contractName> in Artifact object compatible form
const resultToArtifact = (result: any) => {
const { fullyQualifiedName, artefact } = result
return {
contractName: fullyQualifiedName.split(':')[1],
sourceName: fullyQualifiedName.split(':')[0],
abi: artefact.abi,
bytecode: artefact.evm.bytecode.object,
deployedBytecode: artefact.evm.deployedBytecode.object,
linkReferences: artefact.evm.bytecode.linkReferences,
deployedLinkReferences: artefact.evm.deployedBytecode.linkReferences
}
}
const getContractFactory = async (contractNameOrABI: ethers.ContractInterface, bytecode?: string, signerOrOptions = null) => {
//@ts-ignore
if (!global.ganacheProvider) initializeProvider()
if (bytecode && contractNameOrABI) {
//@ts-ignore
return new ethers.ContractFactory(contractNameOrABI, bytecode, signerOrOptions || (new ethers.providers.Web3Provider(ganacheProvider)).getSigner())
} else if (typeof contractNameOrABI === 'string') {
const contract = await getArtifactsByContractName(contractNameOrABI)
if (contract) {
//@ts-ignore
return new ethers.ContractFactory(contract.abi, contract.evm.bytecode.object, signerOrOptions || (new ethers.providers.Web3Provider(ganacheProvider)).getSigner())
} else {
throw new Error('Contract artifacts not found')
}
} else {
throw new Error('Invalid contract name or ABI provided')
}
}
const getContractAt = async (contractNameOrABI: ethers.ContractInterface, address: string, signer = null) => {
//@ts-ignore
if (!global.ganacheProvider) initializeProvider()
//@ts-ignore
const provider = new ethers.providers.Web3Provider(ganacheProvider)
if(typeof contractNameOrABI === 'string') {
const result = await getArtifactsByContractName(contractNameOrABI)
if (result) {
return new ethers.Contract(address, result.abi, signer || provider.getSigner())
} else {
throw new Error('Contract artifacts not found')
}
} else {
return new ethers.Contract(address, contractNameOrABI, signer || provider.getSigner())
}
}
const getSigner = async (address: string) => {
//@ts-ignore
if (!global.ganacheProvider) initializeProvider()
//@ts-ignore
const provider = new ethers.providers.Web3Provider(ganacheProvider)
const signer = provider.getSigner(address)
return SignerWithAddress.create(signer)
}
const getSigners = async () => {
//@ts-ignore
if (!global.ganacheProvider) initializeProvider()
//@ts-ignore
const provider = new ethers.providers.Web3Provider(ganacheProvider)
const accounts = await provider.listAccounts()
return await Promise.all( accounts.map((account: any) => getSigner(account)))
}
const getContractFactoryFromArtifact = async (artifact: any, signerOrOptions: { signer: any, libraries: any }) => {
//@ts-ignore
if (!global.ganacheProvider) initializeProvider()
let libraries = {}
let signer
if (!isArtifact(artifact)) {
throw new Error(
`You are trying to create a contract factory from an artifact, but you have not passed a valid artifact parameter.`
)
}
if (isFactoryOptions(signerOrOptions)) {
signer = signerOrOptions.signer;
libraries = signerOrOptions.libraries ?? {};
} else {
signer = signerOrOptions;
}
if (artifact.bytecode === "0x") {
throw new Error(
`You are trying to create a contract factory for the contract ${artifact.contractName}, which is abstract and can't be deployed.
If you want to call a contract using ${artifact.contractName} as its interface use the "getContractAt" function instead.`
)
}
const linkedBytecode = await collectLibrariesAndLink(artifact, libraries)
//@ts-ignore
return new ethers.ContractFactory(artifact.abi, linkedBytecode || artifact.bytecode, signer || (new ethers.providers.Web3Provider(ganacheProvider)).getSigner())
}
const getContractAtFromArtifact = async (artifact: any, address: string, signerOrOptions = null) => {
if (!isArtifact(artifact)) {
throw new Error(
`You are trying to create a contract factory from an artifact, but you have not passed a valid artifact parameter.`
)
}
return await getContractAt(artifact.abi, address, signerOrOptions)
}
export { getContractAtFromArtifact, getContractFactoryFromArtifact, getSigners, getSigner, getContractAt, getContractFactory }

@ -0,0 +1,53 @@
// @ts-ignore
import { ethers } from "ethers"
export class SignerWithAddress extends ethers.Signer {
address: string
_signer: {
provider: any
signTransaction: (transaction: any) => any,
signMessage: (message: string) => any,
sendTransaction: (transaction: any) => any,
connect: (provider: any) => any,
_signTypedData: (...params: any) => any
}
provider: any
static async create(signer: any) {
return new SignerWithAddress(await signer.getAddress(), signer)
}
constructor(address: string, _signer: any) {
super()
this.address = address
this._signer = _signer
this.provider = _signer.provider
}
async getAddress() {
return this.address
}
signMessage(message: string){
return this._signer.signMessage(message)
}
signTransaction(transaction: any) {
return this._signer.signTransaction(transaction)
}
sendTransaction(transaction: any) {
return this._signer.sendTransaction(transaction)
}
connect(provider: any) {
return new SignerWithAddress(this.address, this._signer.connect(provider))
}
_signTypedData(...params: any) {
return this._signer._signTypedData(...params)
}
toJSON() {
return `<SignerWithAddress ${this.address}>`
}
}

@ -0,0 +1,7 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"types": ["jest", "node"]
},
"include": ["**/*.ts"]
}

@ -0,0 +1,15 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"module": "commonjs",
"outDir": "../../dist/out-tsc",
"declaration": true,
"rootDir": "./src",
"types": ["node"]
},
"exclude": [
"**/*.spec.ts"
],
"include": ["**/*.ts"]
}

@ -15,7 +15,9 @@
"outputPath": "dist/libs/remix-analyzer",
"main": "libs/remix-analyzer/src/index.ts",
"tsConfig": "libs/remix-analyzer/tsconfig.lib.json",
"assets": []
"assets": [
"libs/remix-analyzer/*.md"
]
}
},
"lint": {

@ -14,7 +14,9 @@
"outputPath": "dist/libs/remix-astwalker",
"main": "libs/remix-astwalker/src/index.ts",
"tsConfig": "libs/remix-astwalker/tsconfig.lib.json",
"assets": []
"assets": [
"libs/remix-astwalker/*.md"
]
}
},
"lint": {

@ -15,7 +15,18 @@
"outputPath": "dist/libs/remix-debug",
"main": "libs/remix-debug/src/index.ts",
"tsConfig": "libs/remix-debug/tsconfig.lib.json",
"assets": []
"assets": [
{
"glob": "rdb",
"input": "libs/remix-debug/bin/",
"output": "bin/"
},
{
"glob": "*.md",
"input": "libs/remix-debug/",
"output": "/"
}
]
}
},
"lint": {

@ -11,7 +11,9 @@
"outputPath": "dist/libs/remix-lib",
"main": "libs/remix-lib/src/index.ts",
"tsConfig": "libs/remix-lib/tsconfig.lib.json",
"assets": []
"assets": [
"libs/remix-lib/*.md"
]
}
},
"lint": {

@ -14,7 +14,18 @@
"outputPath": "dist/libs/remix-simulator",
"main": "libs/remix-simulator/src/index.ts",
"tsConfig": "libs/remix-simulator/tsconfig.lib.json",
"assets": []
"assets": [
{
"glob": "ethsim",
"input": "libs/remix-simulator/bin/",
"output": "bin/"
},
{
"glob": "*.md",
"input": "libs/remix-simulator/",
"output": "/"
}
]
}
},
"lint": {

@ -14,7 +14,9 @@
"outputPath": "dist/libs/remix-solidity",
"main": "libs/remix-solidity/src/index.ts",
"tsConfig": "libs/remix-solidity/tsconfig.lib.json",
"assets": []
"assets": [
"libs/remix-solidity/*.md"
]
}
},
"lint": {

@ -321,9 +321,13 @@ export const DebuggerUI = (props: DebuggerUIProps) => {
} catch (error) {
unLoad()
setState(prevState => {
let errorMsg = error.message || error
if (typeof errorMsg !== 'string') {
errorMsg = JSON.stringify(errorMsg) + '. Possible error: the current endpoint does not support retrieving the trace of a transaction.'
}
return {
...prevState,
validationError: error.message || error
validationError: errorMsg
}
})
}

@ -6,18 +6,18 @@ import Web3 from 'web3'
export const GlobalVariables = ({ block, receipt, tx, className }) => {
// see https://docs.soliditylang.org/en/latest/units-and-global-variables.html#block-and-transaction-properties
const globals = {
'block.chainid': tx.chainId,
'block.coinbase': block.miner,
'block.difficulty': block.difficulty,
'block.gaslimit': block.gasLimit,
'block.number': block.number,
'block.timestamp': block.timestamp,
'msg.sender': tx.from,
'msg.sig': tx.input.substring(0, 10),
'msg.value': tx.value + ' Wei',
'tx.origin': tx.from
'block.chainid': tx && tx.chainId,
'block.coinbase': block && block.miner,
'block.difficulty': block && block.difficulty,
'block.gaslimit': block && block.gasLimit,
'block.number': block && block.number,
'block.timestamp': block && block.timestamp,
'msg.sender': tx && tx.from,
'msg.sig': tx && tx.input && tx.input.substring(0, 10),
'msg.value': tx && (tx.value + ' Wei'),
'tx.origin': tx && tx.from
}
if (block.baseFeePerGas) {
if (block && block.baseFeePerGas) {
globals['block.basefee'] = Web3.utils.toBN(block.baseFeePerGas).toString(10) + ` Wei (${block.baseFeePerGas})`
}

@ -63,10 +63,10 @@ function HomeTabFeaturedPlugins ({plugin}: HomeTabFeaturedPluginsProps) {
plugin.verticalIcons.select('solidity')
_paq.push(['trackEvent', 'hometabActivate', 'userActivate', 'solidity'])
}
const startStarkNet = async () => {
await plugin.appManager.activatePlugin('starkNet_compiler')
plugin.verticalIcons.select('starkNet_compiler')
_paq.push(['trackEvent', 'hometabActivate', 'userActivate', 'starkNet_compiler'])
const startOneClickDapp = async () => {
await plugin.appManager.activatePlugin('oneClickDapp')
plugin.verticalIcons.select('oneClickDapp')
_paq.push(['trackEvent', 'hometabActivate', 'userActivate', 'oneClickDapp'])
}
const startSolhint = async () => {
await plugin.appManager.activatePlugin(['solidity', 'solhint'])
@ -84,6 +84,12 @@ function HomeTabFeaturedPlugins ({plugin}: HomeTabFeaturedPluginsProps) {
_paq.push(['trackEvent', 'hometabActivate', 'userActivate', 'solidityUnitTesting'])
}
const startDgit = async () => {
await plugin.appManager.activatePlugin('dgit')
plugin.verticalIcons.select('dgit')
_paq.push(['tracEvent', 'hometabActivate', 'userActivate', 'dgit'])
}
return (
<div className="pl-2 w-100" id="hTFeaturedPlugins">
<label className="" style={{fontSize: "1.2rem"}}><FormattedMessage id='home.featuredPlugins' /></label>
@ -126,14 +132,6 @@ function HomeTabFeaturedPlugins ({plugin}: HomeTabFeaturedPluginsProps) {
remixMaintained={true}
callback={() => startSolidity()}
/>
<PluginButton
imgPath="assets/img/starkNetLogo.webp"
envID="starkNetLogo"
envText="StarkNet"
description={intl.formatMessage({ id: 'home.starkNetPluginDesc' })}
l2={true}
callback={() => startStarkNet()}
/>
<PluginButton
imgPath="assets/img/solhintLogo.webp"
envID="solhintLogo" envText="Solhint linter"
@ -147,6 +145,21 @@ function HomeTabFeaturedPlugins ({plugin}: HomeTabFeaturedPluginsProps) {
description={intl.formatMessage({ id: 'home.sourcifyPluginDesc' })}
callback={() => startSourceVerify()}
/>
<PluginButton
imgPath="assets/img/dgit.webp"
envID="dgitLogo"
envText="Dgit"
description={intl.formatMessage({ id: 'home.dgitPluginDesc' })}
remixMaintained={true}
callback={() => startDgit()}
/>
<PluginButton
imgPath="assets/img/oneclickdapp.webp"
envID="oneClickDappLogo"
envText="OneClickDapp"
description={intl.formatMessage({ id: 'home.oneClickDappDesc' })}
callback={() => startOneClickDapp()}
/>
<PluginButton
imgPath="assets/img/unitTesting.webp"
envID="sUTLogo"

@ -105,31 +105,36 @@ function HomeTabGetStarted ({plugin}: HomeTabGetStartedProps) {
deviceType={"desktop"}
itemClass="w-100"
>
<WorkspaceTemplate
gsID="starkNetLogo"
workspaceTitle="Blank"
description={intl.formatMessage({ id: 'home.blankTemplateDesc' })}
callback={() => createWorkspace("blank")} />
<WorkspaceTemplate
gsID="solhintLogo"
workspaceTitle="Remix Default"
description={intl.formatMessage({ id: 'home.remixDefaultTemplateDesc' })}
callback={() => createWorkspace("remixDefault")} />
<WorkspaceTemplate
gsID="sourcifyLogo"
workspaceTitle="OpenZeppelin ERC20"
description={intl.formatMessage({ id: 'home.ozerc20TemplateDesc' })}
callback={() => createWorkspace("ozerc20")} />
<WorkspaceTemplate
gsID="sUTLogo"
workspaceTitle="OpenZeppelin ERC721"
description={intl.formatMessage({ id: 'home.ozerc721TemplateDesc' })}
callback={() => createWorkspace("ozerc721")} />
workspaceTitle="Gnosis Safe MultiSig"
description={intl.formatMessage({ id: 'home.gnosisSafeMultisigTemplateDesc' })}
callback={() => createWorkspace("gnosisSafeMultisig")} />
<WorkspaceTemplate
gsID="sUTLogo"
workspaceTitle="0xProject ERC20"
description={intl.formatMessage({ id: 'home.zeroxErc20TemplateDesc' })}
callback={() => createWorkspace("zeroxErc20")} />
<WorkspaceTemplate
gsID="sourcifyLogo"
workspaceTitle="OpenZeppelin ERC20"
description={intl.formatMessage({ id: 'home.ozerc20TemplateDesc' })}
callback={() => createWorkspace("ozerc20")} />
<WorkspaceTemplate
gsID="sUTLogo"
workspaceTitle="OpenZeppelin ERC721"
description={intl.formatMessage({ id: 'home.ozerc721TemplateDesc' })}
callback={() => createWorkspace("ozerc721")} />
<WorkspaceTemplate
gsID="sUTLogo"
workspaceTitle="OpenZeppelin ERC1155"
description={intl.formatMessage({ id: 'home.ozerc1155TemplateDesc' })}
callback={() => createWorkspace("ozerc1155")} />
<WorkspaceTemplate
gsID="solhintLogo"
workspaceTitle="Remix Default"
description={intl.formatMessage({ id: 'home.remixDefaultTemplateDesc' })}
callback={() => createWorkspace("remixDefault")} />
</Carousel>
</ThemeContext.Provider>
</div>

@ -31,10 +31,10 @@ function HomeTabLearn ({plugin}: HomeTabLearnProps) {
window.open("https://remix-ide.readthedocs.io/en/latest/remix_tutorials_learneth.html?highlight=learneth#learneth-tutorial-repos", '_blank')
}
const startLearnEthTutorial = async (tutorial) => {
const startLearnEthTutorial = async (tutorial: 'basics' | 'useofweb3js' | 'deploylibraries') => {
await plugin.appManager.activatePlugin(['solidity', 'LearnEth', 'solidityUnitTesting'])
plugin.call('LearnEth', 'startTutorial', 'ethereum/remix-workshops', 'master', tutorial)
plugin.verticalIcons.select('LearnEth')
plugin.call('LearnEth', 'startTutorial', 'ethereum/remix-workshops', 'master', tutorial)
_paq.push(['trackEvent', 'hometab', 'startLearnEthTutorial', tutorial])
}
@ -45,7 +45,9 @@ function HomeTabLearn ({plugin}: HomeTabLearnProps) {
<FormattedMessage id="home.learn" />
</label>
<button
onClick={ ()=> openLink()}
onClick={ async () => {
await startLearnEthTutorial('basics')
}}
className="h-100 px-2 pt-0 btn"
>
<img className="align-self-center" src="assets/img/learnEthLogo.webp" alt="" style={ { filter: themeFilter.filter, width: "1rem", height: "1ren" } } />
@ -54,11 +56,11 @@ function HomeTabLearn ({plugin}: HomeTabLearnProps) {
<div className="d-flex flex-column">
<label className="d-flex flex-column btn border" onClick={() => setState((prevState) => {return { ...prevState, visibleTutorial: VisibleTutorial.Basics }})}>
<label className="card-title align-self-start m-0 float-left" style={{fontSize: "1rem"}}>
<FormattedMessage id="home.remixBasics" />
<FormattedMessage id="home.learnEth1" />
</label>
{(state.visibleTutorial === VisibleTutorial.Basics) && <div className="pt-2 d-flex flex-column text-left">
<span>
<FormattedMessage id="home.remixBasicsDesc" />
<FormattedMessage id="home.learnEth1Desc" />
</span>
<button className="btn btn-sm btn-secondary mt-2" style={{width: 'fit-content'}} onClick={() => startLearnEthTutorial('basics')}>
<FormattedMessage id="home.getStarted" />
@ -67,11 +69,11 @@ function HomeTabLearn ({plugin}: HomeTabLearnProps) {
</label>
<label className="d-flex flex-column btn border" onClick={() => setState((prevState) => {return { ...prevState, visibleTutorial: VisibleTutorial.Intermediate }})}>
<label className="card-title align-self-start m-0 float-left" style={{fontSize: "1rem"}}>
<FormattedMessage id="home.remixIntermediate" />
<FormattedMessage id="home.learnEth2" />
</label>
{(state.visibleTutorial === VisibleTutorial.Intermediate) && <div className="pt-2 d-flex flex-column text-left">
<span>
<FormattedMessage id="home.remixIntermediateDesc" /></span>
<FormattedMessage id="home.learnEth2Desc" /></span>
<button className="btn btn-sm btn-secondary mt-2" style={{width: 'fit-content'}} onClick={() => startLearnEthTutorial('useofweb3js')}>
<FormattedMessage id="home.getStarted" />
</button>

@ -7,7 +7,7 @@ import { addSlash, checkSlash, checkSpecialChars } from '@remix-ui/helper'
import { JSONStandardInput, WorkspaceTemplate } from '../types'
import { QueryParams } from '@remix-project/remix-lib'
import * as templateWithContent from '@remix-project/remix-ws-templates'
import { ROOT_PATH } from '../utils/constants'
import { ROOT_PATH, slitherYml, solTestYml, tsSolTestYml } from '../utils/constants'
// eslint-disable-next-line @nrwl/nx/enforce-module-boundaries
import { IndexedDBStorage } from '../../../../../../apps/remix-ide/src/app/files/filesystems/indexedDB'
import { getUncommittedFiles } from '../utils/gitStatusFilter'
@ -612,25 +612,23 @@ export const createNewBranch = async (branch: string) => {
}
export const createSolidityGithubAction = async () => {
const actionYml = `
name: Running Solidity Unit Tests
on: [push]
jobs:
run_sol_contracts_job:
runs-on: ubuntu-latest
name: A job to run solidity unit tests on github actions CI
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Run SUT Action
uses: EthereumRemix/sol-test@v1
with:
test-path: 'tests'
compiler-version: '0.8.15'
`
const path = '.github/workflows/run-solidity-unittesting.yml'
await plugin.call('fileManager', 'writeFile', path , actionYml)
await plugin.call('fileManager', 'writeFile', path , solTestYml)
plugin.call('fileManager', 'open', path)
}
export const createTsSolGithubAction = async () => {
const path = '.github/workflows/run-js-test.yml'
await plugin.call('fileManager', 'writeFile', path , tsSolTestYml)
plugin.call('fileManager', 'open', path)
}
export const createSlitherGithubAction = async () => {
const path = '.github/workflows/run-slither-action.yml'
await plugin.call('fileManager', 'writeFile', path , slitherYml)
plugin.call('fileManager', 'open', path)
}

@ -0,0 +1,322 @@
import React from 'react'
import { CustomTooltip } from '@remix-ui/helper'
import { Dropdown } from 'react-bootstrap'
import { FormattedMessage } from 'react-intl'
const _paq = window._paq = window._paq || []
export interface HamburgerMenuProps {
createWorkspace: () => void,
deleteCurrentWorkspace: () => void,
renameCurrentWorkspace: () => void,
cloneGitRepository: () => void,
downloadWorkspaces: () => void,
restoreBackup: () => void,
hideIconsMenu: (showMenu: boolean) => void,
addGithubAction: () => void,
addTsSolTestGithubAction: () => void,
addSlitherGithubAction: () => void,
showIconsMenu: boolean,
hideWorkspaceOptions: boolean,
hideLocalhostOptions: boolean
}
export function HamburgerMenu (props: HamburgerMenuProps) {
const { showIconsMenu, hideWorkspaceOptions, hideLocalhostOptions } = props
return (
<>
<Dropdown.Item>
<CustomTooltip
placement="right"
tooltipId="createWorkspaceTooltip"
tooltipClasses="text-nowrap"
tooltipText={<FormattedMessage id='filePanel.workspace.create' />}
>
<div
data-id='workspaceCreate'
onClick={() => {
props.createWorkspace()
_paq.push(['trackEvent', 'fileExplorer', 'workspaceMenu', 'workspaceCreate'])
props.hideIconsMenu(!showIconsMenu)
}}
key={`workspacesCreate-fe-ws`}
>
<span
hidden={hideWorkspaceOptions}
id='workspaceCreate'
data-id='workspaceCreate'
onClick={() => {
props.createWorkspace()
_paq.push(['trackEvent', 'fileExplorer', 'workspaceMenu', 'workspaceCreate'])
props.hideIconsMenu(!showIconsMenu)
}}
className='far fa-plus pl-2'
>
</span>
<span className="pl-3"><FormattedMessage id='filePanel.create' /></span>
</div>
</CustomTooltip>
</Dropdown.Item>
<Dropdown.Item>
<CustomTooltip
placement="right-start"
tooltipId="createWorkspaceTooltip"
tooltipClasses="text-nowrap"
tooltipText={<FormattedMessage id='filePanel.workspace.delete' />}
>
<div
data-id='workspaceDelete'
onClick={() => {
props.deleteCurrentWorkspace()
_paq.push(['trackEvent', 'fileExplorer', 'workspaceMenu', 'workspaceDelete'])
props.hideIconsMenu(!showIconsMenu)
}}
key={`workspacesDelete-fe-ws`}
>
<span
hidden={ hideWorkspaceOptions || hideLocalhostOptions }
id='workspaceDelete'
data-id='workspaceDelete'
onClick={() => {
props.deleteCurrentWorkspace()
_paq.push(['trackEvent', 'fileExplorer', 'workspaceMenu', 'workspaceDelete'])
props.hideIconsMenu(!showIconsMenu)
}}
className='far fa-trash pl-2'
>
</span>
<span className="pl-3"><FormattedMessage id='filePanel.delete' /></span>
</div>
</CustomTooltip>
</Dropdown.Item>
<Dropdown.Item>
<CustomTooltip
placement='right-start'
tooltipClasses="text-nowrap"
tooltipId="workspaceRenametooltip"
tooltipText={<FormattedMessage id='filePanel.workspace.rename' />}
>
<div onClick={() => {
props.renameCurrentWorkspace()
_paq.push(['trackEvent', 'fileExplorer', 'workspaceMenu', 'workspaceRename'])
props.hideIconsMenu(!showIconsMenu)
}}
data-id='workspaceRename'
key={`workspacesRename-fe-ws`}
>
<span
hidden={ hideWorkspaceOptions || hideLocalhostOptions }
id='workspaceRename'
data-id='workspaceRename'
onClick={() => {
props.renameCurrentWorkspace()
_paq.push(['trackEvent', 'fileExplorer', 'workspaceMenu', 'workspaceRename'])
props.hideIconsMenu(!showIconsMenu)
}}
className='far fa-edit pl-2'>
</span>
<span className="pl-3"><FormattedMessage id='filePanel.rename' /></span>
</div>
</CustomTooltip>
</Dropdown.Item>
<Dropdown.Item><Dropdown.Divider className="border mb-0 mt-0" /></Dropdown.Item>
<Dropdown.Item>
<CustomTooltip
placement="right-start"
tooltipId="cloneWorkspaceTooltip"
tooltipClasses="text-nowrap"
tooltipText={<FormattedMessage id='filePanel.workspace.clone' />}
>
<div
data-id='cloneGitRepository'
onClick={() => {
props.cloneGitRepository()
_paq.push(['trackEvent', 'fileExplorer', 'workspaceMenu', 'cloneGitRepository'])
props.hideIconsMenu(!showIconsMenu)
}}
key={`cloneGitRepository-fe-ws`}
>
<span
hidden={ hideWorkspaceOptions }
id='cloneGitRepository'
data-id='cloneGitRepository'
onClick={() => {
props.cloneGitRepository()
_paq.push(['trackEvent', 'fileExplorer', 'workspaceMenu', 'cloneGitRepository'])
props.hideIconsMenu(!showIconsMenu)
}}
className='fab fa-github pl-2'
>
</span>
<span className="pl-3"><FormattedMessage id='filePanel.clone' /></span>
</div>
</CustomTooltip>
</Dropdown.Item>
<Dropdown.Item><Dropdown.Divider className="border mt-0 mb-0 remixui_menuhr" style={{ pointerEvents: 'none' }}/></Dropdown.Item>
<Dropdown.Item>
<CustomTooltip
placement="right-start"
tooltipId="createWorkspaceTooltip"
tooltipClasses="text-nowrap"
tooltipText={<FormattedMessage id='filePanel.workspace.download' />}
>
<div
data-id='workspacesDownload'
onClick={() => {
props.downloadWorkspaces()
_paq.push(['trackEvent', 'fileExplorer', 'workspaceMenu', 'workspacesDownload'])
props.hideIconsMenu(!showIconsMenu)
}}
key={`workspacesDownload-fe-ws`}
>
<span
hidden={ hideWorkspaceOptions || hideLocalhostOptions }
id='workspacesDownload'
data-id='workspacesDownload'
onClick={() => {
props.downloadWorkspaces()
_paq.push(['trackEvent', 'fileExplorer', 'workspaceMenu', 'workspacesDownload'])
props.hideIconsMenu(!showIconsMenu)
}}
className='far fa-download pl-2 '
>
</span>
<span className="pl-3"><FormattedMessage id='filePanel.download' /></span>
</div>
</CustomTooltip>
</Dropdown.Item>
<Dropdown.Item>
<CustomTooltip
placement="right-start"
tooltipId="createWorkspaceTooltip"
tooltipClasses="text-nowrap"
tooltipText={<FormattedMessage id='filePanel.workspace.restore' />}
>
<div
data-id='workspacesRestore'
onClick={() => {
props.restoreBackup()
_paq.push(['trackEvent', 'fileExplorer', 'workspaceMenu', 'workspacesRestore'])
props.hideIconsMenu(!showIconsMenu)
}}
key={`workspacesRestore-fe-ws`}
>
<span
hidden={ hideWorkspaceOptions }
id='workspacesRestore'
data-id='workspacesRestore'
onClick={() => {
props.restoreBackup()
_paq.push(['trackEvent', 'fileExplorer', 'workspaceMenu', 'workspacesRestore'])
props.hideIconsMenu(!showIconsMenu)
}}
className='far fa-upload pl-2'
>
</span>
<span className="pl-3"><FormattedMessage id='filePanel.restore' /></span>
</div>
</CustomTooltip>
</Dropdown.Item>
<Dropdown.Item><Dropdown.Divider className="border mt-0 mb-0 remixui_menuhr" style={{ pointerEvents: 'none' }}/></Dropdown.Item>
<Dropdown.Item>
<CustomTooltip
placement="right-start"
tooltipId="createSolGHActionTooltip"
tooltipClasses="text-nowrap"
tooltipText={<FormattedMessage id='filePanel.workspace.solghaction' />}
>
<div
data-id='soliditygithubaction'
onClick={(e) => {
e.stopPropagation()
props.addGithubAction()
_paq.push(['trackEvent', 'fileExplorer', 'workspaceMenu', 'addSolidityTesting'])
props.hideIconsMenu(!showIconsMenu)
}}
>
<span
hidden={ hideWorkspaceOptions }
id='soliditygithubaction'
data-id='soliditygithubaction'
onClick={(e) => {
e.stopPropagation()
props.addGithubAction()
_paq.push(['trackEvent', 'fileExplorer', 'workspaceMenu', 'addSolidityTesting'])
props.hideIconsMenu(!showIconsMenu)
}}
className='fak fa-solidity-mono pl-2'
>
</span>
<span className="pl-3">{<FormattedMessage id='filePanel.solghaction' />}</span>
</div>
</CustomTooltip>
</Dropdown.Item>
<Dropdown.Item>
<CustomTooltip
placement="right-start"
tooltipId="createTsSolTestGHActionTooltip"
tooltipClasses="text-nowrap"
tooltipText={<FormattedMessage id='filePanel.workspace.tssoltestghaction' />}
>
<div
data-id='typescriptsoliditygithubtestaction'
onClick={(e) => {
e.stopPropagation()
props.addTsSolTestGithubAction()
_paq.push(['trackEvent', 'fileExplorer', 'workspaceMenu', 'addTsSolTestingAction'])
props.hideIconsMenu(!showIconsMenu)
}}
>
<span
hidden={ hideWorkspaceOptions }
id='tssoliditygithubaction'
data-id='tssoliditygithubaction'
onClick={(e) => {
e.stopPropagation()
props.addTsSolTestGithubAction()
_paq.push(['trackEvent', 'fileExplorer', 'workspaceMenu', 'addTsSolTestingAction'])
props.hideIconsMenu(!showIconsMenu)
}}
className='fab fa-js pl-2'
>
</span>
<span className="pl-3">{<FormattedMessage id='filePanel.tssoltestghaction' />}</span>
</div>
</CustomTooltip>
</Dropdown.Item>
<Dropdown.Item>
<CustomTooltip
placement="right-start"
tooltipId="createSlitherGHActionTooltip"
tooltipClasses="text-nowrap"
tooltipText={<FormattedMessage id='filePanel.workspace.slitherghaction' />}
>
<div
data-id='slithergithubtestaction'
onClick={(e) => {
e.stopPropagation()
props.addSlitherGithubAction()
_paq.push(['trackEvent', 'fileExplorer', 'workspaceMenu', 'addSlitherAction'])
props.hideIconsMenu(!showIconsMenu)
}}
>
<span
hidden={ hideWorkspaceOptions }
id='slithergithubaction'
data-id='slithergithubaction'
onClick={(e) => {
e.stopPropagation()
props.addSlitherGithubAction()
_paq.push(['trackEvent', 'fileExplorer', 'workspaceMenu', 'addSlitherAction'])
props.hideIconsMenu(!showIconsMenu)
}}
className='far fa-shield pl-2'
>
</span>
<span className="pl-3">{<FormattedMessage id='filePanel.slitherghaction' />}</span>
</div>
</CustomTooltip>
</Dropdown.Item>
</>
)
}

@ -37,7 +37,9 @@ export const FileSystemContext = createContext<{
dispatchSwitchToBranch: (branch: string) => Promise<void>,
dispatchCreateNewBranch: (branch: string) => Promise<void>,
dispatchCheckoutRemoteBranch: (branch: string, remote: string) => Promise<void>,
dispatchCreateSolidityGithubAction: () => Promise<void>
dispatchCreateSolidityGithubAction: () => Promise<void>,
dispatchCreateTsSolGithubAction: () => Promise<void>,
dispatchCreateSlitherGithubAction: () => Promise<void>
}>(null)

@ -8,7 +8,7 @@ import { browserReducer, browserInitialState } from '../reducers/workspace'
import { initWorkspace, fetchDirectory, removeInputField, deleteWorkspace, clearPopUp, publishToGist, createNewFile, setFocusElement, createNewFolder,
deletePath, renamePath, copyFile, copyFolder, runScript, emitContextMenuEvent, handleClickFile, handleExpandPath, addInputField, createWorkspace,
fetchWorkspaceDirectory, renameWorkspace, switchToWorkspace, uploadFile, handleDownloadFiles, restoreBackupZip, cloneRepository, moveFile, moveFolder,
showAllBranches, switchBranch, createNewBranch, checkoutRemoteBranch, createSolidityGithubAction
showAllBranches, switchBranch, createNewBranch, checkoutRemoteBranch, createSolidityGithubAction, createTsSolGithubAction, createSlitherGithubAction
} from '../actions'
import { Modal, WorkspaceProps, WorkspaceTemplate } from '../types'
// eslint-disable-next-line @typescript-eslint/no-unused-vars
@ -159,6 +159,14 @@ export const FileSystemProvider = (props: WorkspaceProps) => {
await createSolidityGithubAction()
}
const dispatchCreateTsSolGithubAction = async () => {
await createTsSolGithubAction()
}
const dispatchCreateSlitherGithubAction = async () => {
await createSlitherGithubAction()
}
useEffect(() => {
dispatchInitWorkspace()
}, [])
@ -268,7 +276,9 @@ export const FileSystemProvider = (props: WorkspaceProps) => {
dispatchSwitchToBranch,
dispatchCreateNewBranch,
dispatchCheckoutRemoteBranch,
dispatchCreateSolidityGithubAction
dispatchCreateSolidityGithubAction,
dispatchCreateTsSolGithubAction,
dispatchCreateSlitherGithubAction
}
return (
<FileSystemContext.Provider value={value}>

@ -6,6 +6,7 @@ import { FileExplorer } from './components/file-explorer' // eslint-disable-line
import { FileSystemContext } from './contexts'
import './css/remix-ui-workspace.css'
import { ROOT_PATH } from './utils/constants'
import { HamburgerMenu } from './components/workspace-hamburger'
const _paq = window._paq = window._paq || []
const canUpload = window.File || window.FileReader || window.FileList || window.Blob
@ -103,6 +104,14 @@ export function Workspace () {
global.dispatchCreateSolidityGithubAction()
}
const addTsSolTestGithubAction = () => {
global.dispatchCreateTsSolGithubAction()
}
const addSlitherGithubAction = () => {
global.dispatchCreateSlitherGithubAction()
}
const downloadWorkspaces = async () => {
try {
await global.dispatchHandleDownloadFiles()
@ -372,222 +381,6 @@ export function Workspace () {
)
}
const workspaceMenuIcons = [
<CustomTooltip
placement="right"
tooltipId="createWorkspaceTooltip"
tooltipClasses="text-nowrap"
tooltipText={<FormattedMessage id='filePanel.workspace.create' />}
>
<div
data-id='workspaceCreate'
onClick={() => {
createWorkspace()
_paq.push(['trackEvent', 'fileExplorer', 'workspaceMenu', 'workspaceCreate'])
hideIconsMenu(!showIconsMenu)
}}
key={`workspacesCreate-fe-ws`}
>
<span
hidden={currentWorkspace === LOCALHOST}
id='workspaceCreate'
data-id='workspaceCreate'
onClick={() => {
createWorkspace()
_paq.push(['trackEvent', 'fileExplorer', 'workspaceMenu', 'workspaceCreate'])
hideIconsMenu(!showIconsMenu)
}}
className='far fa-plus pl-2'
>
</span>
<span className="pl-3"><FormattedMessage id='filePanel.create' /></span>
</div>
</CustomTooltip>,
<CustomTooltip
placement="right-start"
tooltipId="createWorkspaceTooltip"
tooltipClasses="text-nowrap"
tooltipText={<FormattedMessage id='filePanel.workspace.delete' />}
>
<div
data-id='workspaceDelete'
onClick={() => {
deleteCurrentWorkspace()
_paq.push(['trackEvent', 'fileExplorer', 'workspaceMenu', 'workspaceDelete'])
hideIconsMenu(!showIconsMenu)
}}
key={`workspacesDelete-fe-ws`}
>
<span
hidden={currentWorkspace === LOCALHOST || currentWorkspace === NO_WORKSPACE}
id='workspaceDelete'
data-id='workspaceDelete'
onClick={() => {
deleteCurrentWorkspace()
_paq.push(['trackEvent', 'fileExplorer', 'workspaceMenu', 'workspaceDelete'])
hideIconsMenu(!showIconsMenu)
}}
className='far fa-trash pl-2'
>
</span>
<span className="pl-3"><FormattedMessage id='filePanel.delete' /></span>
</div>
</CustomTooltip>,
<CustomTooltip
placement='right-start'
tooltipClasses="text-nowrap"
tooltipId="workspaceRenametooltip"
tooltipText={<FormattedMessage id='filePanel.workspace.rename' />}
>
<div onClick={() => {
renameCurrentWorkspace()
_paq.push(['trackEvent', 'fileExplorer', 'workspaceMenu', 'workspaceRename'])
hideIconsMenu(!showIconsMenu)
}}
data-id='workspaceRename'
key={`workspacesRename-fe-ws`}
>
<span
hidden={currentWorkspace === LOCALHOST || currentWorkspace === NO_WORKSPACE}
id='workspaceRename'
data-id='workspaceRename'
onClick={() => {
renameCurrentWorkspace()
_paq.push(['trackEvent', 'fileExplorer', 'workspaceMenu', 'workspaceRename'])
hideIconsMenu(!showIconsMenu)
}}
className='far fa-edit pl-2'>
</span>
<span className="pl-3"><FormattedMessage id='filePanel.rename' /></span>
</div>
</CustomTooltip>,
<Dropdown.Divider className="border mb-0 mt-0" />,
<CustomTooltip
placement="right-start"
tooltipId="cloneWorkspaceTooltip"
tooltipClasses="text-nowrap"
tooltipText={<FormattedMessage id='filePanel.workspace.clone' />}
>
<div
data-id='cloneGitRepository'
onClick={() => {
cloneGitRepository()
_paq.push(['trackEvent', 'fileExplorer', 'workspaceMenu', 'cloneGitRepository'])
hideIconsMenu(!showIconsMenu)
}}
key={`cloneGitRepository-fe-ws`}
>
<span
hidden={currentWorkspace === LOCALHOST}
id='cloneGitRepository'
data-id='cloneGitRepository'
onClick={() => {
cloneGitRepository()
_paq.push(['trackEvent', 'fileExplorer', 'workspaceMenu', 'cloneGitRepository'])
hideIconsMenu(!showIconsMenu)
}}
className='fab fa-github pl-2'
>
</span>
<span className="pl-3"><FormattedMessage id='filePanel.clone' /></span>
</div>
</CustomTooltip>,
<Dropdown.Divider className="border mt-0 mb-0 remixui_menuhr" style={{ pointerEvents: 'none' }}/>,
<CustomTooltip
placement="right-start"
tooltipId="createWorkspaceTooltip"
tooltipClasses="text-nowrap"
tooltipText={<FormattedMessage id='filePanel.workspace.download' />}
>
<div
data-id='workspacesDownload'
onClick={() => {
downloadWorkspaces()
_paq.push(['trackEvent', 'fileExplorer', 'workspaceMenu', 'workspacesDownload'])
hideIconsMenu(!showIconsMenu)
}}
key={`workspacesDownload-fe-ws`}
>
<span
hidden={currentWorkspace === LOCALHOST || currentWorkspace === NO_WORKSPACE}
id='workspacesDownload'
data-id='workspacesDownload'
onClick={() => {
downloadWorkspaces()
_paq.push(['trackEvent', 'fileExplorer', 'workspaceMenu', 'workspacesDownload'])
hideIconsMenu(!showIconsMenu)
}}
className='far fa-download pl-2 '
>
</span>
<span className="pl-3"><FormattedMessage id='filePanel.download' /></span>
</div>
</CustomTooltip>,
<CustomTooltip
placement="right-start"
tooltipId="createWorkspaceTooltip"
tooltipClasses="text-nowrap"
tooltipText={<FormattedMessage id='filePanel.workspace.restore' />}
>
<div
data-id='workspacesRestore'
onClick={() => {
restoreBackup()
_paq.push(['trackEvent', 'fileExplorer', 'workspaceMenu', 'workspacesRestore'])
hideIconsMenu(!showIconsMenu)
}}
key={`workspacesRestore-fe-ws`}
>
<span
hidden={currentWorkspace === LOCALHOST}
id='workspacesRestore'
data-id='workspacesRestore'
onClick={() => {
restoreBackup()
_paq.push(['trackEvent', 'fileExplorer', 'workspaceMenu', 'workspacesRestore'])
hideIconsMenu(!showIconsMenu)
}}
className='far fa-upload pl-2'
>
</span>
<span className="pl-3"><FormattedMessage id='filePanel.restore' /></span>
</div>
</CustomTooltip>,
<Dropdown.Divider className="border mt-0 mb-0 remixui_menuhr" style={{ pointerEvents: 'none' }}/>,
<CustomTooltip
placement="right-start"
tooltipId="createSolGHActionTooltip"
tooltipClasses="text-nowrap"
tooltipText={<FormattedMessage id='filePanel.workspace.solghaction' />}
>
<div
data-id='soliditygithubaction'
onClick={(e) => {
e.stopPropagation()
addGithubAction()
_paq.push(['trackEvent', 'fileExplorer', 'workspaceMenu', 'addSolidityTesting'])
hideIconsMenu(!showIconsMenu)
}}
>
<span
hidden={currentWorkspace === LOCALHOST}
id='soliditygithubaction'
data-id='soliditygithubaction'
onClick={(e) => {
e.stopPropagation()
addGithubAction()
_paq.push(['trackEvent', 'fileExplorer', 'workspaceMenu', 'addSolidityTesting'])
hideIconsMenu(!showIconsMenu)
}}
className='fab fa-github pl-2'
>
</span>
<span className="pl-3">{<FormattedMessage id='filePanel.solghaction' />}</span>
</div>
</CustomTooltip>
]
const menuLength = workspaceMenuIcons.length
let count = 0
return (
<div className='d-flex flex-column justify-content-between h-100'>
<div className='remixui_container overflow-auto' style={{ maxHeight: selectedWorkspace && selectedWorkspace.isGitRepo ? '95%' : '100%' }}>
@ -631,15 +424,21 @@ export function Workspace () {
icon={'fas fa-bars'}
></Dropdown.Toggle>
<Dropdown.Menu as={CustomMenu} data-id="wsdropdownMenu" className='custom-dropdown-items remixui_menuwidth' rootCloseEvent="click">
{
workspaceMenuIcons.map(m => {
return (
<Dropdown.Item key={`wsdropdownMenu-${count !== menuLength ? count++ : count }`}>
{m}
</Dropdown.Item>
)
})
}
<HamburgerMenu
createWorkspace={createWorkspace}
deleteCurrentWorkspace={deleteCurrentWorkspace}
renameCurrentWorkspace={renameCurrentWorkspace}
cloneGitRepository={cloneGitRepository}
downloadWorkspaces={downloadWorkspaces}
restoreBackup={restoreBackup}
hideIconsMenu={hideIconsMenu}
addGithubAction={addGithubAction}
addSlitherGithubAction={addSlitherGithubAction}
addTsSolTestGithubAction={addTsSolTestGithubAction}
showIconsMenu={showIconsMenu}
hideWorkspaceOptions={ currentWorkspace === LOCALHOST }
hideLocalhostOptions={ currentWorkspace === NO_WORKSPACE }
/>
</Dropdown.Menu>
</Dropdown>
</span>) : null}

@ -1 +1,53 @@
export const ROOT_PATH = '/'
export const solTestYml = `
name: Running Solidity Unit Tests
on: [push]
jobs:
run_sol_contracts_job:
runs-on: ubuntu-latest
name: A job to run solidity unit tests on github actions CI
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Run SUT Action
uses: EthereumRemix/sol-test@v1
with:
test-path: 'tests'
compiler-version: '0.8.15'
`
export const tsSolTestYml = `
name: Running Mocha Chai Solidity Unit Tests
on: [push]
jobs:
run_sample_test_job:
runs-on: ubuntu-latest
name: A job to run mocha and chai tests for solidity on github actions CI
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Run Mocha Chai Unit Test Action
uses: EthereumRemix/ts-sol-test@v1.2
with:
test-path: 'tests'
contract-path: 'contracts'
compiler-version: '0.8.7'
`
export const slitherYml = `
name: Slither Analysis
on: [push]
jobs:
analyze:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- run: npm install
- uses: crytic/slither-action@v0.2.0
with:
target: 'contracts'
slither-args: '--solc-remaps "@openzeppelin/contracts=./node_modules/@openzeppelin/contracts hardhat=./node_modules/hardhat"'
fail-on: 'low'
solc-version: '0.8.2'
`

@ -13,7 +13,9 @@
"outputPath": "dist/libs/remix-url-resolver",
"main": "libs/remix-url-resolver/src/index.ts",
"tsConfig": "libs/remix-url-resolver/tsconfig.lib.json",
"assets": []
"assets": [
"libs/remix-url-resolver/*.md"
]
}
},
"lint": {

@ -13,7 +13,26 @@
"outputPath": "dist/libs/remix-ws-templates",
"main": "libs/remix-ws-templates/src/index.ts",
"tsConfig": "libs/remix-ws-templates/tsconfig.lib.json",
"assets": []
"assets": [
{
"glob": "templates/**/*",
"ignore": [
"templates/**/*/index.ts"
],
"input": "libs/remix-ws-templates/src/",
"output": "src/"
},
{
"glob": "*.md",
"input": "libs/remix-ws-templates/",
"output": "/"
},
{
"glob": "templates/**/.prettierrc",
"input": "libs/remix-ws-templates/src/",
"output": "src/"
}
]
}
},
"lint": {

@ -45,8 +45,8 @@
"workspace-schematic": "nx workspace-schematic",
"dep-graph": "nx dep-graph",
"help": "nx help",
"lint:libs": "nx run-many --target=lint --projects=remix-analyzer,remix-astwalker,remix-debug,remix-lib,remix-simulator,remix-solidity,remix-tests,remix-url-resolver,remix-ws-templates,remixd,remix-ui-tree-view,remix-ui-modal-dialog,remix-ui-toaster,remix-ui-helper,remix-ui-debugger-ui,remix-ui-workspace,remix-ui-static-analyser,remix-ui-checkbox,remix-ui-settings,remix-core-plugin,remix-ui-renderer,remix-ui-publish-to-storage,remix-ui-solidity-compiler,solidity-unit-testing,remix-ui-plugin-manager,remix-ui-terminal,remix-ui-editor,remix-ui-app,remix-ui-tabs,remix-ui-panel,remix-ui-run-tab,remix-ui-permission-handler,remix-ui-search,remix-ui-file-decorators,remix-ui-tooltip-popup",
"build:libs": "nx run-many --target=build --parallel=false --with-deps=true --projects=remix-analyzer,remix-astwalker,remix-debug,remix-lib,remix-simulator,remix-solidity,remix-tests,remix-url-resolver,remix-ws-templates,remixd",
"lint:libs": "nx run-many --target=lint --projects=remix-analyzer,remix-astwalker,remix-debug,remix-lib,remix-simulator,remix-solidity,remix-tests,remix-url-resolver,remix-ws-templates,remixd,remix-ui-tree-view,remix-ui-modal-dialog,remix-ui-toaster,remix-ui-helper,remix-ui-debugger-ui,remix-ui-workspace,remix-ui-static-analyser,remix-ui-checkbox,remix-ui-settings,remix-core-plugin,remix-ui-renderer,remix-ui-publish-to-storage,remix-ui-solidity-compiler,solidity-unit-testing,remix-ui-plugin-manager,remix-ui-terminal,remix-ui-editor,remix-ui-app,remix-ui-tabs,remix-ui-panel,remix-ui-run-tab,remix-ui-permission-handler,remix-ui-search,remix-ui-file-decorators,remix-ui-tooltip-popup,ghaction-helper",
"build:libs": "nx run-many --target=build --parallel=false --with-deps=true --projects=remix-analyzer,remix-astwalker,remix-debug,remix-lib,remix-simulator,remix-solidity,remix-tests,remix-url-resolver,remix-ws-templates,remixd,ghaction-helper",
"test:libs": "nx run-many --target=test --projects=remix-analyzer,remix-astwalker,remix-debug,remix-lib,remix-simulator,remix-tests,remix-url-resolver,remixd",
"publish:libs": "yarn run build:libs && lerna publish --skip-git && yarn run bumpVersion:libs",
"build:e2e": "node apps/remix-ide-e2e/src/buildGroupTests.js && tsc -p apps/remix-ide-e2e/tsconfig.e2e.json",

@ -145,6 +145,9 @@
"@remix-ui/locale-module": [
"libs/remix-ui/locale-module/src/index.ts"
],
"@remix-project/ghaction-helper": [
"libs/ghaction-helper/src/index.ts"
]
}
}
}

@ -10958,9 +10958,9 @@ decimal.js@^10.3.1:
integrity sha512-ic1yEvwT6GuvaYwBLLY6/aFFgjZdySKTE8en/fkU3QICTmRtgtSlFn0u0BXN06InZwtfCelR7j8LRiDI/02iGA==
decode-uri-component@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545"
integrity sha512-hjf+xovcEn31w/EUYdTXQh/8smFL/dzYjohQGEIgjyNavaJfBY2p5F527Bo1VPATxv0VYTUC2bOcXvqFwk78Og==
version "0.2.2"
resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.2.tgz#e69dbe25d37941171dd540e024c444cd5188e1e9"
integrity sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==
decompress-response@^3.2.0, decompress-response@^3.3.0:
version "3.3.0"
@ -21816,7 +21816,7 @@ qs@6.10.3:
dependencies:
side-channel "^1.0.4"
qs@6.11.0, qs@^6.9.4:
qs@6.11.0, qs@^6.4.0, qs@^6.9.4:
version "6.11.0"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a"
integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==
@ -21828,17 +21828,10 @@ qs@6.7.0:
resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc"
integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==
qs@^6.4.0:
version "6.10.1"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.10.1.tgz#4931482fa8d647a5aab799c5271d2133b981fb6a"
integrity sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg==
dependencies:
side-channel "^1.0.4"
qs@~6.4.0:
version "6.4.0"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233"
integrity sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=
version "6.4.1"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.1.tgz#2bad97710a5b661c366b378b1e3a44a592ff45e6"
integrity sha512-LQy1Q1fcva/UsnP/6Iaa4lVeM49WiOitu2T4hZCyA/elLKu37L99qcBJk4VCCk+rdLvnMzfKyiN3SZTqdAZGSQ==
qs@~6.5.2:
version "6.5.2"

Loading…
Cancel
Save