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

pull/3311/head
filip mertens 2 years ago
commit c81c559310
  1. 50
      .circleci/config.yml
  2. 17
      apps/debugger/src/app/debugger-api.ts
  3. 2
      apps/remix-ide-e2e/src/tests/ballot.test.ts
  4. 2
      apps/remix-ide-e2e/src/tests/terminal.test.ts
  5. 16
      apps/remix-ide/project.json
  6. 12
      apps/remix-ide/src/app.js
  7. 5
      apps/remix-ide/src/app/files/fileManager.ts
  8. 2
      apps/remix-ide/src/app/panels/tab-proxy.js
  9. 49
      apps/remix-ide/src/app/plugins/contractFlattener.tsx
  10. 1
      apps/remix-ide/src/app/plugins/remixd-handle.tsx
  11. 159
      apps/remix-ide/src/app/plugins/solidity-umlgen.tsx
  12. 5
      apps/remix-ide/src/app/tabs/locale-module.js
  13. 14
      apps/remix-ide/src/app/tabs/locales/en/home.json
  14. 4
      apps/remix-ide/src/app/tabs/locales/en/solidity.json
  15. 6
      apps/remix-ide/src/app/tabs/locales/zh/home.json
  16. 4
      apps/remix-ide/src/app/tabs/locales/zh/solidity.json
  17. 4
      apps/remix-ide/src/app/tabs/theme-module.js
  18. BIN
      apps/remix-ide/src/assets/img/YouTubeLogo.webp
  19. 6
      apps/remix-ide/src/assets/js/loader.js
  20. 16
      apps/remix-ide/src/remixAppManager.js
  21. 100
      apps/remix-ide/webpack.config.js
  22. 3
      gulpfile.js
  23. 3
      lerna.json
  24. 8
      libs/ghaction-helper/package.json
  25. 3
      libs/ghaction-helper/project.json
  26. 9
      libs/remix-analyzer/package.json
  27. 3
      libs/remix-analyzer/project.json
  28. 7
      libs/remix-astwalker/package.json
  29. 3
      libs/remix-astwalker/project.json
  30. 3
      libs/remix-core-plugin/project.json
  31. 13
      libs/remix-debug/package.json
  32. 1
      libs/remix-debug/project.json
  33. 16
      libs/remix-debug/src/trace/traceAnalyser.ts
  34. 5
      libs/remix-debug/src/trace/traceCache.ts
  35. 5
      libs/remix-debug/src/trace/traceHelper.ts
  36. 18
      libs/remix-debug/src/trace/traceManager.ts
  37. 5
      libs/remix-lib/package.json
  38. 1
      libs/remix-lib/project.json
  39. 2
      libs/remix-lib/src/types/ICompilerApi.ts
  40. 21
      libs/remix-lib/src/util.ts
  41. 27
      libs/remix-simulator/bin/ethsim
  42. 7
      libs/remix-simulator/package.json
  43. 1
      libs/remix-simulator/project.json
  44. 30
      libs/remix-simulator/src/VmProxy.ts
  45. 6
      libs/remix-solidity/package.json
  46. 1
      libs/remix-solidity/project.json
  47. 13
      libs/remix-tests/package.json
  48. 1
      libs/remix-tests/project.json
  49. 1
      libs/remix-ui/app/src/lib/remix-app/remix-app.tsx
  50. 34
      libs/remix-ui/home-tab/src/lib/components/homeTabFeatured.tsx
  51. 17
      libs/remix-ui/home-tab/src/lib/components/homeTabLearn.tsx
  52. 1
      libs/remix-ui/solidity-compiler/src/index.ts
  53. 3
      libs/remix-ui/solidity-compiler/src/lib/compiler-container.tsx
  54. 9
      libs/remix-ui/solidity-compiler/src/lib/contract-selection.tsx
  55. 169
      libs/remix-ui/solidity-compiler/src/lib/logic/flattenerUtilities.ts
  56. 294
      libs/remix-ui/solidity-compiler/src/lib/logic/pdfSaveLogic.ts
  57. 1
      libs/remix-ui/solidity-uml-gen/src/index.ts
  58. 3
      libs/remix-ui/solidity-uml-gen/src/lib/css/solidity-uml-gen.css
  59. 118
      libs/remix-ui/solidity-uml-gen/src/lib/solidity-uml-gen.tsx
  60. 14
      libs/remix-ui/solidity-uml-gen/src/types/index.ts
  61. 2
      libs/remix-ui/theme-module/types/theme-module.ts
  62. 2
      libs/remix-ui/vertical-icons-panel/src/lib/components/Icon.tsx
  63. 1
      libs/remix-ui/workspace/src/lib/components/file-explorer.tsx
  64. 63
      libs/remix-ui/workspace/src/lib/types/index.ts
  65. 2
      libs/remix-ui/workspace/src/lib/utils/index.ts
  66. 4
      libs/remix-url-resolver/package.json
  67. 1
      libs/remix-url-resolver/project.json
  68. 4
      libs/remix-ws-templates/package.json
  69. 1
      libs/remix-ws-templates/project.json
  70. 1
      libs/remixd/project.json
  71. 36
      package.json
  72. 3
      tsconfig.paths.json
  73. 2624
      yarn.lock

@ -5,7 +5,7 @@ parameters:
type: boolean
default: false
orbs:
browser-tools: circleci/browser-tools@1.4.0
browser-tools: circleci/browser-tools@1.4.1
jobs:
build:
docker:
@ -93,14 +93,29 @@ jobs:
type: string
parallelism: 10
steps:
- browser-tools/install-browser-tools
- run:
command: |
google-chrome --version
firefox --version
geckodriver --version
chromedriver --version
rm LICENSE.chromedriver 2> /dev/null
- when:
condition:
equal: [ "chrome", << parameters.browser >> ]
steps:
- browser-tools/install-browser-tools:
install-firefox: false
install-chrome: true
install-geckodriver: false
install-chromedriver: true
- run: google-chrome --version
- run: chromedriver --version
- run: rm LICENSE.chromedriver 2> /dev/null || true
- when:
condition:
equal: [ "firefox", << parameters.browser >> ]
steps:
- browser-tools/install-browser-tools:
install-firefox: true
install-chrome: false
install-geckodriver: true
install-chromedriver: false
- run: firefox --version
- run: geckodriver --version
- checkout
- attach_workspace:
at: .
@ -140,15 +155,14 @@ jobs:
type: string
parallelism: 4
steps:
- browser-tools/install-browser-tools
- run:
command: |
google-chrome --version
firefox --version
geckodriver --version
chromedriver --version
rm LICENSE.chromedriver 2> /dev/null
name: Check install
- browser-tools/install-browser-tools:
install-firefox: false
install-chrome: true
install-geckodriver: false
install-chromedriver: true
- run: google-chrome --version
- run: chromedriver --version
- run: rm LICENSE.chromedriver 2> /dev/null || true
- checkout
- attach_workspace:
at: .

@ -1,7 +1,9 @@
import Web3 from 'web3'
import {init , traceHelper, TransactionDebugger as Debugger } from '@remix-project/remix-debug'
import { init , traceHelper, TransactionDebugger as Debugger } from '@remix-project/remix-debug'
import { CompilerAbstract } from '@remix-project/remix-solidity'
import { lineText } from '@remix-ui/editor'
import { util } from '@remix-project/remix-lib'
const { toHexPaddedString } = util
export const DebuggerApiMixin = (Base) => class extends Base {
@ -137,7 +139,18 @@ export const DebuggerApiMixin = (Base) => class extends Base {
},
debugWithGeneratedSources: false
})
return await debug.debugger.traceManager.getTrace(hash)
const trace = await debug.debugger.traceManager.getTrace(hash)
trace.structLogs = trace.structLogs.map((step) => {
const stack = []
for (const prop in step.stack) {
if (prop !== 'length') {
stack.push(toHexPaddedString(step.stack[prop]))
}
}
step.stack = stack
return step
})
return trace
}
debug (hash, web3?) {

@ -236,7 +236,7 @@ module.exports = {
.waitForElementVisible('select[id="compilierLanguageSelector"]', 10000)
.click('select[id="compilierLanguageSelector"]')
.click('select[id="compilierLanguageSelector"] option[value=Yul]')
.waitForElementContainsText('[data-id="compiledContracts"]', 'Contract', 60000)
.waitForElementContainsText('[data-id="compiledContracts"]', 'Contract', 65000)
.clickLaunchIcon('udapp')
.click('*[data-id="Deploy - transact (not payable)"]')
.waitForElementPresent('*[data-id="universalDappUiContractActionWrapper"]', 60000)

@ -170,7 +170,7 @@ module.exports = {
.waitForElementVisible('[for="autoCompile"]')
.click('[for="autoCompile"]')
.clickLaunchIcon('udapp')
.testContracts('printHardhatlog.sol', { content: hardhatLog }, ['OwnerTest'])
.verifyContracts(['OwnerTest'])
.clickLaunchIcon('udapp')
.click('*[data-id="deployAndRunClearInstances"]')
.selectContract('OwnerTest')

@ -30,14 +30,18 @@
},
"configurations": {
"development": {
"extractLicenses": false,
"sourceMap": true,
"vendorChunk": true,
"optimization": false
},
"production": {
"fileReplacements": [
{
"replace": "apps/remix-ide/src/environments/environment.ts",
"with": "apps/remix-ide/src/environments/environment.prod.ts"
}
]
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"namedChunks": false,
"extractLicenses": false,
"vendorChunk": false
}
}
},

@ -35,6 +35,8 @@ import { Injected0ptimismProvider } from './app/tabs/injected-optimism-provider'
import { InjectedArbitrumOneProvider } from './app/tabs/injected-arbitrum-one-provider'
import { FileDecorator } from './app/plugins/file-decorator'
import { CodeFormat } from './app/plugins/code-format'
import { SolidityUmlGen } from './app/plugins/solidity-umlgen'
import { ContractFlattener } from './app/plugins/contractFlattener'
const isElectron = require('is-electron')
@ -173,6 +175,12 @@ class AppComponent {
//----- search
const search = new SearchPlugin()
//---------------- Solidity UML Generator -------------------------
const solidityumlgen = new SolidityUmlGen(appManager)
// ----------------- ContractFlattener ----------------------------
const contractFlattener = new ContractFlattener()
// ----------------- import content service ------------------------
const contentImport = new CompilerImports()
@ -265,7 +273,9 @@ class AppComponent {
injected0ptimismProvider,
injectedArbitrumOneProvider,
this.walkthroughService,
search
search,
solidityumlgen,
contractFlattener
])
// LAYOUT & SYSTEM VIEWS

@ -5,6 +5,7 @@ import Registry from '../state/registry'
import { EventEmitter } from 'events'
import { fileChangedToastMsg, recursivePasteToastMsg, storageFullMessage } from '@remix-ui/helper'
import helper from '../../lib/helper.js'
import { RemixAppManager } from '../../remixAppManager'
/*
attach to files event (removed renamed)
@ -40,7 +41,7 @@ class FileManager extends Plugin {
events: EventEmitter
editor: any
_components: any
appManager: any
appManager: RemixAppManager
_deps: any
getCurrentFile: () => any
getFile: (path: any) => Promise<unknown>
@ -622,6 +623,7 @@ class FileManager extends Plugin {
file = resolved.file
await this.saveCurrentFile()
if (this.currentFile() === file) return
const provider = resolved.provider
this._deps.config.set('currentFile', file)
this.openedFiles[file] = file
@ -629,6 +631,7 @@ class FileManager extends Plugin {
let content = ''
try {
content = await provider.get(file)
} catch (error) {
console.log(error)
throw error

@ -33,7 +33,7 @@ export class TabProxy extends Plugin {
this.on('fileManager', 'filesAllClosed', () => {
this.call('manager', 'activatePlugin', 'home')
this.tabsApi.activateTab('home')
this.focus('home')
})
this.on('fileManager', 'fileRemoved', (name) => {

@ -0,0 +1,49 @@
import React from 'react'
import { Plugin } from '@remixproject/engine'
import { customAction } from '@remixproject/plugin-api'
import { concatSourceFiles, getDependencyGraph } from '@remix-ui/solidity-compiler'
const profile = {
name: 'contractflattener',
displayName: 'Contract Flattener',
description: 'Flatten solidity contracts',
methods: ['flattenAContract'],
events: [],
}
export class ContractFlattener extends Plugin {
fileName: string
constructor() {
super(profile)
this.fileName = ''
}
onActivation(): void {
this.on('solidity', 'compilationFinished', async (file, source, languageVersion, data, input, version) => {
await this.flattenContract(source, this.fileName, data)
})
}
async flattenAContract(action: customAction) {
this.fileName = action.path[0]
this.call('solidity', 'compile', this.fileName)
}
/**
* Takes currently compiled contract that has a bunch of imports at the top
* and flattens them ready for UML creation. Takes the flattened result
* and assigns to a local property
* @returns {Promise<string>}
*/
async flattenContract (source: any, filePath: string, data: any) {
const ast = data.sources
const dependencyGraph = getDependencyGraph(ast, filePath)
const sorted = dependencyGraph.isEmpty()
? [filePath]
: dependencyGraph.sort().reverse()
const sources = source.sources
const result = concatSourceFiles(sorted, sources)
await this.call('fileManager', 'writeFile', `${filePath}_flattened.sol`, result)
return result
}
}

@ -3,6 +3,7 @@ import React, { useRef, useState, useEffect } from 'react' // eslint-disable-lin
import isElectron from 'is-electron'
import { WebsocketPlugin } from '@remixproject/engine-web'
import * as packageJson from '../../../../../package.json'
// eslint-disable-next-line @nrwl/nx/enforce-module-boundaries
import { version as remixdVersion } from '../../../../../libs/remixd/package.json'
import { PluginManager } from '@remixproject/engine'
import { AppModal, AlertModal } from '@remix-ui/app'

@ -0,0 +1,159 @@
/* eslint-disable @nrwl/nx/enforce-module-boundaries */
import { ViewPlugin } from '@remixproject/engine-web'
import React from 'react'
// eslint-disable-next-line @nrwl/nx/enforce-module-boundaries
import { RemixUiSolidityUmlGen } from '@remix-ui/solidity-uml-gen'
import { ISolidityUmlGen } from 'libs/remix-ui/solidity-uml-gen/src/types'
import { RemixAppManager } from 'libs/remix-ui/plugin-manager/src/types'
import { concatSourceFiles, getDependencyGraph } from 'libs/remix-ui/solidity-compiler/src/lib/logic/flattenerUtilities'
import { convertUmlClasses2Dot } from 'sol2uml/lib/converterClasses2Dot'
import { convertAST2UmlClasses } from 'sol2uml/lib/converterAST2Classes'
import vizRenderStringSync from '@aduh95/viz.js/sync'
import { PluginViewWrapper } from '@remix-ui/helper'
import { customAction } from '@remixproject/plugin-api'
const parser = (window as any).SolidityParser
const profile = {
name: 'solidityumlgen',
displayName: 'Solidity UML Generator',
description: 'Generate UML diagram in svg format from last compiled contract',
location: 'mainPanel',
methods: ['showUmlDiagram', 'generateUml', 'generateCustomAction'],
events: [],
}
export class SolidityUmlGen extends ViewPlugin implements ISolidityUmlGen {
element: HTMLDivElement
currentFile: string
svgPayload: string
updatedSvg: string
currentlySelectedTheme: string
loading: boolean
appManager: RemixAppManager
dispatch: React.Dispatch<any> = () => {}
constructor(appManager: RemixAppManager) {
super(profile)
this.currentFile = ''
this.svgPayload = ''
this.updatedSvg = ''
this.loading = false
this.currentlySelectedTheme = ''
this.appManager = appManager
this.element = document.createElement('div')
this.element.setAttribute('id', 'sol-uml-gen')
}
onActivation(): void {
if (this.currentFile.length < 1)
this.on('solidity', 'compilationFinished', async (file, source, languageVersion, data, input, version) => {
let result = ''
try {
if (data.sources && Object.keys(data.sources).length > 1) { // we should flatten first as there are multiple asts
result = await this.flattenContract(source, this.currentFile, data)
}
const ast = result.length > 1 ? parser.parse(result) : parser.parse(source.sources[this.currentFile].content)
const umlClasses = convertAST2UmlClasses(ast, this.currentFile)
const umlDot = convertUmlClasses2Dot(umlClasses)
const payload = vizRenderStringSync(umlDot)
const currentTheme = await this.call('theme', 'currentTheme')
this.currentlySelectedTheme = currentTheme.quality
this.updatedSvg = payload
this.renderComponent()
} catch (error) {
console.log({ error })
}
})
this.on('theme', 'themeChanged', (theme) => {
this.currentlySelectedTheme = theme.quality
this.renderComponent()
})
}
async mangleSvgPayload(svgPayload: string) : Promise<string> {
const parser = new DOMParser()
const themeQuality = await this.call('theme', 'currentTheme')
const parsedDocument = parser.parseFromString(svgPayload, 'image/svg+xml')
const res = parsedDocument.documentElement
parsedDocument.bgColor = '#cccabc'
res.style.filter = themeQuality.quality === 'dark' ? 'invert(1)' : 'invert(0)'
const stringifiedSvg = new XMLSerializer().serializeToString(parsedDocument)
console.log({ parsedDocument, themeQuality, stringifiedSvg })
return stringifiedSvg
}
onDeactivation(): void {
this.off('solidity', 'compilationFinished')
}
generateCustomAction = async (action: customAction) => {
this.currentFile = action.path[0]
await this.generateUml(action.path[0])
}
async generateUml(currentFile: string) {
await this.call('solidity', 'compile', currentFile)
await this.call('tabs', 'focus', 'solidityumlgen')
this.loading = true
this.renderComponent()
}
/**
* Takes currently compiled contract that has a bunch of imports at the top
* and flattens them ready for UML creation. Takes the flattened result
* and assigns to a local property
* @returns {Promise<string>}
*/
async flattenContract (source: any, filePath: string, data: any) {
const hold = { data, source, filePath }
const ast = data.sources
const dependencyGraph = getDependencyGraph(ast, filePath)
const sorted = dependencyGraph.isEmpty()
? [filePath]
: dependencyGraph.sort().reverse()
const sources = source.sources
const result = concatSourceFiles(sorted, sources)
await this.call('fileManager', 'writeFile', `${filePath}_flattened.sol`, result)
return result
}
async showUmlDiagram(svgPayload: string) {
this.updatedSvg = svgPayload
this.renderComponent()
}
hideSpinner() {
this.loading = false
this.renderComponent()
}
setDispatch (dispatch: React.Dispatch<any>) {
this.dispatch = dispatch
this.renderComponent()
}
render() {
return <div id='sol-uml-gen'>
<PluginViewWrapper plugin={this} />
</div>
}
renderComponent () {
this.dispatch({
...this,
updatedSvg: this.updatedSvg,
loading: this.loading,
themeSelected: this.currentlySelectedTheme
})
}
updateComponent(state: any) {
return <RemixUiSolidityUmlGen
plugin={state}
updatedSvg={state.updatedSvg}
loading={state.loading}
themeSelected={state.currentlySelectedTheme}
/>
}
}

@ -32,7 +32,8 @@ export class LocaleModule extends Plugin {
this.locales[locale.code.toLocaleLowerCase()] = locale
})
this._paq = _paq
let queryLocale = (new QueryParams()).get().locale
this.queryParams = new QueryParams()
let queryLocale = this.queryParams.get().lang
queryLocale = queryLocale && queryLocale.toLocaleLowerCase()
queryLocale = this.locales[queryLocale] ? queryLocale : null
let currentLocale = (this._deps.config && this._deps.config.get('settings/locale')) || null
@ -41,6 +42,7 @@ export class LocaleModule extends Plugin {
this.currentLocaleState = { queryLocale, currentLocale }
this.active = queryLocale || currentLocale || 'en'
this.forced = !!queryLocale
this.queryParams.update({ lang: this.active })
}
/** Return the active locale */
@ -69,6 +71,7 @@ export class LocaleModule extends Plugin {
if (!this.forced) this._deps.config.set('settings/locale', next)
if (localeCode) this.active = localeCode
this.queryParams.update({ lang: localeCode })
this.emit('localeChanged', nextLocale)
this.events.emit('localeChanged', nextLocale)
}

@ -5,16 +5,18 @@
"home.scamAlertText3": "Additional safety tips",
"home.learnMore": "Learn more",
"home.here": "here",
"home.more": "More",
"home.featured": "Featured",
"home.jumpIntoWeb3": "JUMP INTO WEB3",
"home.jumpIntoWeb3Text": "The Remix Project is a rich toolset which can be used for the entire journey of contract development by users of any knowledge level, and as a learning lab for teaching and experimenting with Ethereum.",
"home.remixRewards": "REMIX REWARDS",
"home.remixRewardsText1": "NFTs for our users!",
"home.remixRewardsText2": "Remix Project rewards contributors, beta testers, and UX research participants with NFTs deployed on Optimism.",
"home.jumpIntoWeb3More": "More",
"home.jumpIntoWeb3Text": "Remix IDE is part of the Remix Project, a rich toolset that can be used for the entire journey of contract development by users of any knowledge level. Learn more on the Remix Project website.",
"home.remixYouTube": "WATCH TO LEARN",
"home.remixYouTubeText1": "Video Tips from the Remix Team",
"home.remixYouTubeMore": "Watch",
"home.remixYouTubeText2": "Remix has a growing library of videos containing lots of tips for using the tool. Check them out and subscribe to get our latest uploads.",
"home.betaTesting": "BETA TESTING",
"home.betaTestingText1": "Our community supports us.",
"home.betaTestingText2": "You can join Beta Testing before each release of Remix IDE. Help us test now and get a handle on new features!",
"home.betaTestingText2": "Help us beta test releases now and get a handle on new features!",
"home.betaTestingMore": "Sign up",
"home.featuredPlugins": "Featured Plugins",
"home.solidityPluginDesc": "Compile, test and analyse smart contract.",
"home.starkNetPluginDesc": "Compile and deploy contracts with Cairo, a native language for StarkNet.",

@ -22,6 +22,10 @@
"solidity.noFileSelected": "no file selected",
"solidity.compileAndRunScript": "Compile and Run script",
"solidity.publishOn": "Publish on",
"solidity.flatten": "Flatten contracts before UML generation.",
"solidity.generateUML": "Generate a UML diagram of your contract.",
"solidity.flattenLabel": "Flatten",
"solidity.generateUMLLabel": "Generate UML Diagram",
"solidity.Assembly": "Assembly opcodes describing the contract including corresponding solidity source code",
"solidity.Opcodes": "Assembly opcodes describing the contract",
"solidity.name": "Name of the compiled contract",

@ -9,9 +9,9 @@
"home.featured": "精选",
"home.jumpIntoWeb3": "迎接 WEB3",
"home.jumpIntoWeb3Text": "Remix 项目是一个丰富的工具集,任何知识水平的用户都可以在这上面进行全周期的合约开发,并且可作为以太坊教学和实验的学习实验室。",
"home.remixRewards": "REMIX 奖励",
"home.remixRewardsText1": "给我们的用户提供的 NFT!",
"home.remixRewardsText2": "Remix 会用部署在 Optimism 链上的 NFT 奖励贡献者、beta 测试者和用户体验研究参与者。Remix 奖励的持有者可以铸造第二个“Remixer”用户 NFT 徽章,以赠予他们选择的任何其他用户。",
"home.remixYouTube": "",
"home.remixYouTubeText1": "",
"home.remixYouTubeText2": "",
"home.betaTesting": "BETA 测试",
"home.betaTestingText1": "我们的社区支持我们",
"home.betaTestingText2": "每次 Remix IDE 发布版本之前,你都可以参与 Beta 测试。现在就来帮我们测试并且尝鲜新功能吧!",

@ -22,6 +22,10 @@
"solidity.noFileSelected": "未选中文件",
"solidity.compileAndRunScript": "编译且执行脚本",
"solidity.publishOn": "发布到",
"solidity.flatten": "",
"solidity.generateUML": "",
"solidity.flattenLabel": "",
"solidity.generateUMLLabel": "",
"solidity.Assembly": "合约的汇编操作码,包含对应的solidity源程序",
"solidity.Opcodes": "合约的汇编操作码",
"solidity.name": "已编译合约的名称",

@ -53,7 +53,9 @@ export class ThemeModule extends Plugin {
this.forced = !!queryTheme
}
/** Return the active theme */
/** Return the active theme
* @return {{ name: string, quality: string, url: string }} - The active theme
*/
currentTheme () {
return this.themes[this.active]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

@ -4,6 +4,7 @@ const domains = {
'remix.ethereum.org': 23,
'6fd22d6fe5549ad4c4d8fd3ca0b7816b.mod': 35 // remix desktop
}
if (domains[window.location.hostname]) {
var _paq = window._paq = window._paq || []
/* tracker methods like "setCustomDimension" should be called before "trackPageView" */
@ -11,6 +12,11 @@ if (domains[window.location.hostname]) {
_paq.push(['enableJSErrorTracking']);
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
_paq.push(['enableHeartBeatTimer']);
if (!window.localStorage.getItem('config-v0.8:.remix.config') ||
(window.localStorage.getItem('config-v0.8:.remix.config') && !window.localStorage.getItem('config-v0.8:.remix.config').includes('settings/matomo-analytics'))) {
_paq.push(['optUserOut'])
}
(function () {
var u = "https://matomo.ethereum.org/";
_paq.push(['setTrackerUrl', u + 'matomo.php'])

@ -11,7 +11,7 @@ const requiredModules = [ // services + layout views + system views
'filePanel', 'terminal', 'settings', 'pluginManager', 'tabs', 'udapp', 'dGitProvider', 'solidity', 'solidity-logic', 'gistHandler', 'layout',
'notification', 'permissionhandler', 'walkthrough', 'storage', 'restorebackupzip', 'link-libraries', 'deploy-libraries', 'openzeppelin-proxy',
'hardhat-provider', 'ganache-provider', 'foundry-provider', 'basic-http-provider', 'injected-optimism-provider', 'injected-arbitrum-one-provider',
'compileAndRun', 'search', 'recorder', 'fileDecorator', 'codeParser', 'codeFormatter']
'compileAndRun', 'search', 'recorder', 'fileDecorator', 'codeParser', 'codeFormatter', 'solidityumlgen', 'contractflattener']
// dependentModules shouldn't be manually activated (e.g hardhat is activated by remixd)
const dependentModules = ['foundry', 'hardhat', 'truffle', 'slither']
@ -157,8 +157,8 @@ export class RemixAppManager extends PluginManager {
async registerContextMenuItems() {
await this.call('filePanel', 'registerContextMenuItem', {
id: 'flattener',
name: 'flattenFileCustomAction',
id: 'contractflattener',
name: 'flattenAContract',
label: 'Flatten',
type: [],
extension: ['.sol'],
@ -176,6 +176,16 @@ export class RemixAppManager extends PluginManager {
pattern: [],
sticky: true
})
await this.call('filePanel', 'registerContextMenuItem', {
id: 'solidityumlgen',
name: 'generateCustomAction',
label: 'Generate UML',
type: [],
extension: ['.sol'],
path: [],
pattern: [],
sticky: true
})
}
}

@ -1,9 +1,11 @@
const nxWebpack = require('@nrwl/react/plugins/webpack')
const CopyPlugin = require("copy-webpack-plugin");
const { composePlugins, withNx } = require('@nrwl/webpack')
const { withReact } = require('@nrwl/react')
const webpack = require('webpack')
const CopyPlugin = require("copy-webpack-plugin")
const version = require('../../package.json').version
const fs = require('fs')
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const TerserPlugin = require("terser-webpack-plugin")
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin")
const versionData = {
version: version,
@ -13,14 +15,14 @@ const versionData = {
fs.writeFileSync('./apps/remix-ide/src/assets/version.json', JSON.stringify(versionData))
module.exports = config => {
const nxWebpackConfig = nxWebpack(config)
const webpackConfig = {
...nxWebpackConfig,
resolve: {
...nxWebpackConfig.resolve,
fallback: {
...nxWebpackConfig.resolve.fallback,
// Nx plugins for webpack.
module.exports = composePlugins(withNx(), withReact(), (config) => {
// Update the webpack config as needed here.
// e.g. `config.plugins.push(new MyPlugin())`
// add fallback for node modules
config.resolve.fallback = {
...config.resolve.fallback,
"crypto": require.resolve("crypto-browserify"),
"stream": require.resolve("stream-browserify"),
"path": require.resolve("path-browserify"),
@ -38,24 +40,24 @@ module.exports = config => {
"child_process": false,
"buffer": require.resolve("buffer/"),
"vm": require.resolve('vm-browserify'),
},
},
externals: {
...nxWebpackConfig.externals,
}
// add externals
config.externals = {
...config.externals,
solc: 'solc',
},
}
output: {
...nxWebpackConfig.output,
publicPath: '/',
filename: `[name].${versionData.version}.${versionData.timestamp}.js`,
chunkFilename: `[name].${versionData.version}.${versionData.timestamp}.js`,
},
plugins: [
...nxWebpackConfig.plugins,
//new BundleAnalyzerPlugin({
// analyzerMode: 'static'
//}),
// add public path
config.output.publicPath = '/'
// set filename
config.output.filename = `[name].${versionData.version}.${versionData.timestamp}.js`
config.output.chunkFilename = `[name].${versionData.version}.${versionData.timestamp}.js`
// add copy & provide plugin
config.plugins.push(
new CopyPlugin({
patterns: [
{ from: '../../node_modules/monaco-editor/dev/vs', to: 'assets/js/monaco-editor/dev/vs' }
@ -65,19 +67,35 @@ module.exports = config => {
Buffer: ['buffer', 'Buffer'],
url: ['url', 'URL'],
process: 'process/browser',
}),
]
}
})
)
webpackConfig.output.chunkLoadTimeout = 600000
// souce-map loader
config.module.rules.push({
test: /\.js$/,
use: ["source-map-loader"],
enforce: "pre"
})
if (process.env.NODE_ENV === 'production') {
return {
...webpackConfig,
mode: 'production',
devtool: 'source-map',
}
} else {
return webpackConfig
}
}
config.ignoreWarnings = [/Failed to parse source map/] // ignore source-map-loader warnings
// set minimizer
config.optimization.minimizer = [
new TerserPlugin({
parallel: true,
terserOptions: {
ecma: 2015,
compress: false,
mangle: false,
format: {
comments: false,
},
},
extractComments: false,
}),
new CssMinimizerPlugin(),
];
return config;
});

@ -52,7 +52,8 @@ task('syncLibVersions', async function () {
'remix-tests',
'remix-url-resolver',
'remix-ws-templates',
'remixd'
'remixd',
'ghaction-helper'
]
libs.forEach(lib => {

@ -8,7 +8,8 @@
"dist/libs/remix-solidity",
"dist/libs/remix-tests",
"dist/libs/remix-url-resolver",
"dist/libs/remix-ws-templates"
"dist/libs/remix-ws-templates",
"dist/libs/ghaction-helper"
],
"version": "independent",
"command": {

@ -1,6 +1,6 @@
{
"name": "@remix-project/ghaction-helper",
"version": "0.1.3",
"version": "0.1.5",
"description": "Solidity Tests GitHub Action Helper",
"main": "src/index.js",
"scripts": {
@ -19,7 +19,7 @@
},
"homepage": "https://github.com/ethereum/remix-project#readme",
"devDependencies": {
"@remix-project/remix-solidity": "^0.5.6",
"@remix-project/remix-solidity": "^0.5.9",
"@types/chai": "^4.3.4",
"typescript": "^4.9.3"
},
@ -28,5 +28,7 @@
"chai": "^4.3.7",
"ethers": "^5.7.2",
"ganache": "^7.5.0"
}
},
"types": "./src/index.d.ts",
"gitHead": "69af4eddd1ba47f76a71c78077d453deb572b1a0"
}

@ -14,7 +14,8 @@
"outputPath": "dist/libs/ghaction-helper",
"main": "libs/ghaction-helper/src/index.ts",
"tsConfig": "libs/ghaction-helper/tsconfig.lib.json",
"assets": []
"assets": [],
"updateBuildableProjectDepsInPackageJson": false
}
},
"lint": {

@ -1,6 +1,6 @@
{
"name": "@remix-project/remix-analyzer",
"version": "0.5.30",
"version": "0.5.32",
"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"
@ -24,8 +24,8 @@
"@ethereumjs/block": "^4.0.0",
"@ethereumjs/tx": "^4.0.0",
"@ethereumjs/vm": "^6.0.0",
"@remix-project/remix-astwalker": "^0.0.51",
"@remix-project/remix-lib": "^0.5.21",
"@remix-project/remix-astwalker": "^0.0.53",
"@remix-project/remix-lib": "^0.5.23",
"async": "^2.6.2",
"ethereumjs-util": "^7.0.10",
"ethers": "^5.4.2",
@ -50,5 +50,6 @@
"typescript": "^3.7.5"
},
"typings": "src/index.d.ts",
"gitHead": "b9f8241a57d3083c94d6499efa8e2ea2ac8ef2d1"
"gitHead": "69af4eddd1ba47f76a71c78077d453deb572b1a0",
"main": "./src/index.js"
}

@ -17,7 +17,8 @@
"tsConfig": "libs/remix-analyzer/tsconfig.lib.json",
"assets": [
"libs/remix-analyzer/*.md"
]
],
"updateBuildableProjectDepsInPackageJson": false
}
},
"lint": {

@ -1,6 +1,6 @@
{
"name": "@remix-project/remix-astwalker",
"version": "0.0.51",
"version": "0.0.53",
"description": "Tool to walk through Solidity AST",
"main": "src/index.js",
"scripts": {
@ -36,7 +36,7 @@
"@ethereumjs/block": "^4.0.0",
"@ethereumjs/tx": "^4.0.0",
"@ethereumjs/vm": "^6.0.0",
"@remix-project/remix-lib": "^0.5.21",
"@remix-project/remix-lib": "^0.5.23",
"@types/tape": "^4.2.33",
"async": "^2.6.2",
"ethereumjs-util": "^7.0.10",
@ -53,5 +53,6 @@
"tap-spec": "^5.0.0"
},
"typings": "src/index.d.ts",
"gitHead": "b9f8241a57d3083c94d6499efa8e2ea2ac8ef2d1"
"gitHead": "69af4eddd1ba47f76a71c78077d453deb572b1a0",
"types": "./src/index.d.ts"
}

@ -16,7 +16,8 @@
"tsConfig": "libs/remix-astwalker/tsconfig.lib.json",
"assets": [
"libs/remix-astwalker/*.md"
]
],
"updateBuildableProjectDepsInPackageJson": false
}
},
"lint": {

@ -11,7 +11,8 @@
"outputPath": "dist/libs/remix-core-plugin",
"main": "libs/remix-core-plugin/src/index.ts",
"tsConfig": "libs/remix-core-plugin/tsconfig.lib.json",
"assets": []
"assets": [],
"updateBuildableProjectDepsInPackageJson": false
}
},
"lint": {

@ -1,6 +1,6 @@
{
"name": "@remix-project/remix-debug",
"version": "0.5.21",
"version": "0.5.23",
"description": "Tool to debug Ethereum transactions",
"contributors": [
{
@ -25,10 +25,10 @@
"@ethereumjs/common": "^3.0.0",
"@ethereumjs/tx": "^4.0.0",
"@ethereumjs/vm": "^6.0.0",
"@remix-project/remix-astwalker": "^0.0.51",
"@remix-project/remix-lib": "^0.5.21",
"@remix-project/remix-simulator": "^0.2.21",
"@remix-project/remix-solidity": "^0.5.7",
"@remix-project/remix-astwalker": "^0.0.53",
"@remix-project/remix-lib": "^0.5.23",
"@remix-project/remix-simulator": "^0.2.23",
"@remix-project/remix-solidity": "^0.5.9",
"ansi-gray": "^0.1.1",
"async": "^2.6.2",
"color-support": "^1.1.3",
@ -69,5 +69,6 @@
},
"homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-debug#readme",
"typings": "src/index.d.ts",
"gitHead": "b9f8241a57d3083c94d6499efa8e2ea2ac8ef2d1"
"gitHead": "69af4eddd1ba47f76a71c78077d453deb572b1a0",
"types": "./src/index.d.ts"
}

@ -15,6 +15,7 @@
"outputPath": "dist/libs/remix-debug",
"main": "libs/remix-debug/src/index.ts",
"tsConfig": "libs/remix-debug/tsconfig.lib.json",
"updateBuildableProjectDepsInPackageJson": false,
"assets": [
{
"glob": "rdb",

@ -1,4 +1,6 @@
'use strict'
import { util } from '@remix-project/remix-lib'
const { toHexPaddedString } = util
import * as traceHelper from './traceHelper'
export class TraceAnalyser {
@ -36,8 +38,8 @@ export class TraceAnalyser {
buildReturnValues (index, step) {
if (traceHelper.isReturnInstruction(step)) {
let offset = 2 * parseInt(step.stack[step.stack.length - 1], 16)
const size = 2 * parseInt(step.stack[step.stack.length - 2], 16)
let offset = 2 * parseInt(toHexPaddedString(step.stack[step.stack.length - 1]), 16)
const size = 2 * parseInt(toHexPaddedString(step.stack[step.stack.length - 2]), 16)
const memory = this.trace[this.traceCache.memoryChanges[this.traceCache.memoryChanges.length - 1]].memory
const noOfReturnParams = size / 64
const memoryInString = memory.join('')
@ -77,11 +79,11 @@ export class TraceAnalyser {
let offset = 0
let size = 0
if (callStep.op === 'DELEGATECALL') {
offset = 2 * parseInt(stack[stack.length - 3], 16)
size = 2 * parseInt(stack[stack.length - 4], 16)
offset = 2 * parseInt(toHexPaddedString(stack[stack.length - 3]), 16)
size = 2 * parseInt(toHexPaddedString(stack[stack.length - 4]), 16)
} else {
offset = 2 * parseInt(stack[stack.length - 4], 16)
size = 2 * parseInt(stack[stack.length - 5], 16)
offset = 2 * parseInt(toHexPaddedString(stack[stack.length - 4]), 16)
size = 2 * parseInt(toHexPaddedString(stack[stack.length - 5]), 16)
}
calldata = '0x' + memory.join('').substr(offset, size)
this.traceCache.pushCallDataChanges(index + 1, calldata)
@ -104,7 +106,7 @@ export class TraceAnalyser {
}
this.traceCache.pushStoreChanges(index + 1, context.storageContext[context.storageContext.length - 1])
} else if (traceHelper.isSSTOREInstruction(step)) {
this.traceCache.pushStoreChanges(index + 1, context.storageContext[context.storageContext.length - 1], step.stack[step.stack.length - 1], step.stack[step.stack.length - 2])
this.traceCache.pushStoreChanges(index + 1, context.storageContext[context.storageContext.length - 1], toHexPaddedString(step.stack[step.stack.length - 1]), toHexPaddedString(step.stack[step.stack.length - 2]))
} else if (traceHelper.isReturnInstruction(step) || traceHelper.isStopInstruction(step)) {
context.storageContext.pop()
this.traceCache.pushStoreChanges(index + 1, context.storageContext[context.storageContext.length - 1])

@ -1,5 +1,6 @@
'use strict'
import { util } from '@remix-project/remix-lib'
const { toHexPaddedString } = util
// eslint-disable-next-line camelcase
const { sha3_256 } = util
@ -103,8 +104,8 @@ export class TraceCache {
pushContractCreationFromMemory (index, token, trace, lastMemoryChange) {
const memory = trace[lastMemoryChange].memory
const stack = trace[index].stack
const offset = 2 * parseInt(stack[stack.length - 2], 16)
const size = 2 * parseInt(stack[stack.length - 3], 16)
const offset = 2 * parseInt(toHexPaddedString(stack[stack.length - 2]), 16)
const size = 2 * parseInt(toHexPaddedString(stack[stack.length - 3]), 16)
this.contractCreation[token] = '0x' + memory.join('').substr(offset, size)
}

@ -1,5 +1,6 @@
'use strict'
import { helpers } from '@remix-project/remix-lib'
import { helpers, util } from '@remix-project/remix-lib'
const { toHexPaddedString } = util
const { ui } = helpers
// vmTraceIndex has to point to a CALL, CODECALL, ...
@ -9,7 +10,7 @@ export function resolveCalledAddress (vmTraceIndex, trace) {
return contractCreationToken(vmTraceIndex)
} else if (isCallInstruction(step)) {
const stack = step.stack // callcode, delegatecall, ...
return ui.normalizeHexAddress(stack[stack.length - 2])
return ui.normalizeHexAddress(toHexPaddedString(stack[stack.length - 2]))
}
return undefined
}

@ -1,5 +1,6 @@
'use strict'
import { util, execution } from '@remix-project/remix-lib'
const { toHexPaddedString } = util
import { TraceAnalyser } from './traceAnalyser'
import { TraceCache } from './traceCache'
import { TraceStepManager } from './traceStepManager'
@ -148,9 +149,24 @@ export class TraceManager {
getStackAt (stepIndex) {
this.checkRequestedStep(stepIndex)
if (this.trace[stepIndex] && this.trace[stepIndex].stack) { // there's always a stack
if (Array.isArray(this.trace[stepIndex].stack)) {
const stack = this.trace[stepIndex].stack.slice(0)
stack.reverse()
return stack.map(el => el.startsWith('0x') ? el : '0x' + el)
return stack.map(el => toHexPaddedString(el))
} else {
// it's an object coming from the VM.
// for performance reasons,
// we don't turn the stack coming from the VM into an array when the tx is executed
// but now when the app needs it.
const stack = []
for (const prop in this.trace[stepIndex].stack) {
if (prop !== 'length') {
stack.push(toHexPaddedString(this.trace[stepIndex].stack[prop]))
}
}
stack.reverse()
return stack
}
} else {
throw new Error('no stack found')
}

@ -1,6 +1,6 @@
{
"name": "@remix-project/remix-lib",
"version": "0.5.21",
"version": "0.5.23",
"description": "Library to various Remix tools",
"contributors": [
{
@ -51,5 +51,6 @@
},
"homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-lib#readme",
"typings": "src/index.d.ts",
"gitHead": "b9f8241a57d3083c94d6499efa8e2ea2ac8ef2d1"
"gitHead": "69af4eddd1ba47f76a71c78077d453deb572b1a0",
"types": "./src/index.d.ts"
}

@ -11,6 +11,7 @@
"outputPath": "dist/libs/remix-lib",
"main": "libs/remix-lib/src/index.ts",
"tsConfig": "libs/remix-lib/tsconfig.lib.json",
"updateBuildableProjectDepsInPackageJson": false,
"assets": [
"libs/remix-lib/*.md"
]

@ -34,7 +34,7 @@ export interface ICompilerApi {
resolveContentAndSave: (url: string) => Promise<string>
fileExists: (file: string) => Promise<boolean>
writeFile: (file: string, content: string) => Promise<void>
writeFile: (file: string, content: any) => Promise<void>
readFile: (file: string) => Promise<string>
open: (file: string) => void
saveCurrentFile: () => void

@ -1,5 +1,6 @@
'use strict'
import { BN, bufferToHex, keccak, setLengthLeft, toBuffer, addHexPrefix } from 'ethereumjs-util'
import { bufferToHex, keccak, setLengthLeft, toBuffer, addHexPrefix } from 'ethereumjs-util'
import { bigIntToHex } from '@ethereumjs/util'
import stringSimilarity from 'string-similarity'
/*
@ -35,14 +36,22 @@ export function hexToIntArray (hexString) {
export function hexListFromBNs (bnList) {
const ret = []
for (const k in bnList) {
const v = bnList[k]
if (BN.isBN(v)) {
ret.push('0x' + v.toString('hex', 64))
const v = bnList[k].toString(16)
ret.push('0x' + v.padStart(64, '0'))
}
return ret
}
export function toHexPaddedString(v: bigint | string): string {
if (v) {
if (typeof v === 'string') {
return v.startsWith('0x') ? v : '0x' + v
} else {
ret.push('0x' + (new BN(v)).toString('hex', 64)) // TEMP FIX TO REMOVE ONCE https://github.com/ethereumjs/ethereumjs-vm/pull/293 is released
return '0x' + v.toString(16).padStart(64, '0')
}
}
return ret
else
return '0x' + '0'.padStart(64, '0')
}
/*

@ -20,18 +20,21 @@ program
})
program
.option('-p, --port [port]', 'specify port')
.option('-b, --ip [host]', 'specify host')
.option('-c, --coinbase [coinbase]', 'specify host')
.option('--rpc', 'run rpc server only')
.option('--details', 'display payloads for every requests and their responses')
.parse(process.argv)
const Server = require('../src/server')
const server = new Server({
coinbase: program.coinbase || "0x0000000000000000000000000000000000000000",
.command('start')
.option('-p, --port [port]', 'specify port', 8545)
.option('-b, --ip [host]', 'specify host', '127.0.0.1')
.option('-c, --coinbase [coinbase]', 'specify coinbase', '0x0000000000000000000000000000000000000000')
.option('--rpc', 'run rpc server only', true)
.option('--details', 'display payloads for every requests and their responses', false)
.action(() => {
const Server = require('../src/server')
const server = new Server({
coinbase: program.coinbase,
rpc: program.rpc,
logDetails: program.details
})
server.start(program.host || '127.0.0.1', program.port || 8545)
})
server.start(program.host, program.port)
})
program.parse(process.argv)

@ -1,6 +1,6 @@
{
"name": "@remix-project/remix-simulator",
"version": "0.2.21",
"version": "0.2.23",
"description": "Ethereum IDE and tools for the web",
"contributors": [
{
@ -21,7 +21,7 @@
"@ethereumjs/common": "^3.0.0",
"@ethereumjs/tx": "^4.0.0",
"@ethereumjs/vm": "^6.0.0",
"@remix-project/remix-lib": "^0.5.21",
"@remix-project/remix-lib": "^0.5.23",
"ansi-gray": "^0.1.1",
"async": "^3.1.0",
"body-parser": "^1.18.2",
@ -67,5 +67,6 @@
},
"homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-simulator#readme",
"typings": "src/index.d.ts",
"gitHead": "b9f8241a57d3083c94d6499efa8e2ea2ac8ef2d1"
"gitHead": "69af4eddd1ba47f76a71c78077d453deb572b1a0",
"types": "./src/index.d.ts"
}

@ -14,6 +14,7 @@
"outputPath": "dist/libs/remix-simulator",
"main": "libs/remix-simulator/src/index.ts",
"tsConfig": "libs/remix-simulator/tsconfig.lib.json",
"updateBuildableProjectDepsInPackageJson": false,
"assets": [
{
"glob": "ethsim",

@ -1,5 +1,5 @@
import { util } from '@remix-project/remix-lib'
const { hexListFromBNs, formatMemory } = util
const { toHexPaddedString, formatMemory } = util
import { helpers } from '@remix-project/remix-lib'
const { normalizeHexAddress } = helpers.ui
import { ConsoleLogs } from '@remix-project/remix-lib'
@ -240,7 +240,7 @@ export class VmProxy {
previousOpcode.invalidDepthChange = previousOpcode.op !== 'RETURN' && previousOpcode.op !== 'STOP'
}
const step = {
stack: hexListFromBNs(data.stack),
stack: { ...data.stack },
storage: {},
memory: null,
op: data.opcode.name,
@ -249,6 +249,7 @@ export class VmProxy {
gas: data.gasLeft.toString(),
depth: depth
}
step.stack.length = Object.keys(data.stack).length
if (previousOpcode && (previousOpcode.op === 'CALLDATACOPY' || previousOpcode.op === 'CODECOPY' || previousOpcode.op === 'EXTCODECOPY' || previousOpcode.op === 'RETURNDATACOPY' || previousOpcode.op === 'MSTORE' || previousOpcode.op === 'MSTORE8')) {
step.memory = data.memory
@ -256,9 +257,8 @@ export class VmProxy {
}
this.vmTraces[this.processingHash].structLogs.push(step)
// Track hardhat console.log call
if (step.op === 'STATICCALL' && step.stack[step.stack.length - 2] === '0x000000000000000000000000000000000000000000636f6e736f6c652e6c6f67') {
const stackLength = step.stack.length
const payloadStart = parseInt(step.stack[stackLength - 3], 16)
if (step.op === 'STATICCALL' && toHexPaddedString(step.stack[step.stack.length - 2]) === '0x000000000000000000000000000000000000000000636f6e736f6c652e6c6f67') {
const payloadStart = parseInt(toHexPaddedString(step.stack[step.stack.length - 3]), 16)
const memory = formatMemory(data.memory)
const memoryStr = memory.join('')
let payload = memoryStr.substring(payloadStart * 2, memoryStr.length)
@ -290,7 +290,7 @@ export class VmProxy {
this.processingAddress = '(Contract Creation - Step ' + this.processingIndex + ')'
this.storageCache[this.processingHash][this.processingAddress] = {}
} else {
this.processingAddress = normalizeHexAddress(step.stack[step.stack.length - 2])
this.processingAddress = normalizeHexAddress(toHexPaddedString(step.stack[step.stack.length - 2]))
this.processingAddress = toChecksumAddress(this.processingAddress)
if (!this.storageCache[this.processingHash][this.processingAddress]) {
(async (processingHash, processingAddress, self) => {
@ -307,7 +307,7 @@ export class VmProxy {
}
if (previousOpcode && previousOpcode.op === 'SHA3') {
const preimage = this.getSha3Input(previousOpcode.stack, formatMemory(this.lastMemoryUpdate))
const imageHash = step.stack[step.stack.length - 1].replace('0x', '')
const imageHash = toHexPaddedString(step.stack[step.stack.length - 1]).replace('0x', '')
this.sha3Preimages[imageHash] = {
preimage: preimage
}
@ -421,26 +421,26 @@ export class VmProxy {
}
getSha3Input (stack, memory) {
let memoryStart = stack[stack.length - 1]
let memoryLength = stack[stack.length - 2]
const memoryStart = toHexPaddedString(stack[stack.length - 1])
const memoryLength = toHexPaddedString(stack[stack.length - 2])
const memStartDec = (new BN(memoryStart.replace('0x', ''), 16)).toString(10)
memoryStart = parseInt(memStartDec) * 2
const memoryStartInt = parseInt(memStartDec) * 2
const memLengthDec = (new BN(memoryLength.replace('0x', ''), 16).toString(10))
memoryLength = parseInt(memLengthDec) * 2
const memoryLengthInt = parseInt(memLengthDec) * 2
let i = Math.floor(memoryStart / 32)
const maxIndex = Math.floor(memoryLength / 32) + i
let i = Math.floor(memoryStartInt / 32)
const maxIndex = Math.floor(memoryLengthInt / 32) + i
if (!memory[i]) {
return this.emptyFill(memoryLength)
}
let sha3Input = memory[i].slice(memoryStart - 32 * i)
let sha3Input = memory[i].slice(memoryStartInt - 32 * i)
i++
while (i < maxIndex) {
sha3Input += memory[i] ? memory[i] : this.emptyFill(32)
i++
}
if (sha3Input.length < memoryLength) {
const leftSize = memoryLength - sha3Input.length
const leftSize = memoryLengthInt - sha3Input.length
sha3Input += memory[i] ? memory[i].slice(0, leftSize) : this.emptyFill(leftSize)
}
return sha3Input

@ -1,6 +1,6 @@
{
"name": "@remix-project/remix-solidity",
"version": "0.5.7",
"version": "0.5.9",
"description": "Tool to load and run Solidity compiler",
"main": "src/index.js",
"types": "src/index.d.ts",
@ -18,7 +18,7 @@
"@ethereumjs/block": "^4.0.0",
"@ethereumjs/tx": "^4.0.0",
"@ethereumjs/vm": "^6.0.0",
"@remix-project/remix-lib": "^0.5.21",
"@remix-project/remix-lib": "^0.5.23",
"async": "^2.6.2",
"eslint-scope": "^5.0.0",
"ethereumjs-util": "^7.0.10",
@ -57,5 +57,5 @@
},
"homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-solidity#readme",
"typings": "src/index.d.ts",
"gitHead": "b9f8241a57d3083c94d6499efa8e2ea2ac8ef2d1"
"gitHead": "69af4eddd1ba47f76a71c78077d453deb572b1a0"
}

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

@ -1,6 +1,6 @@
{
"name": "@remix-project/remix-tests",
"version": "0.2.21",
"version": "0.2.23",
"description": "Tool to test Solidity smart contracts",
"main": "src/index.js",
"types": "./src/index.d.ts",
@ -40,9 +40,9 @@
"@ethereumjs/common": "^3.0.0",
"@ethereumjs/tx": "^4.0.0",
"@ethereumjs/vm": "^6.0.0",
"@remix-project/remix-lib": "^0.5.21",
"@remix-project/remix-simulator": "^0.2.21",
"@remix-project/remix-solidity": "^0.5.7",
"@remix-project/remix-lib": "^0.5.23",
"@remix-project/remix-simulator": "^0.2.23",
"@remix-project/remix-solidity": "^0.5.9",
"@remix-project/remix-url-resolver": "^0.0.42",
"ansi-gray": "^0.1.1",
"async": "^2.6.0",
@ -64,9 +64,6 @@
"web3": "^1.5.1",
"winston": "^3.0.0"
},
"peerDependencies": {
"yo-yoify": "^4.3.0"
},
"devDependencies": {
"@babel/preset-env": "^7.4.5",
"@types/async": "^2.4.0",
@ -81,5 +78,5 @@
"typescript": "^3.3.1"
},
"typings": "src/index.d.ts",
"gitHead": "b9f8241a57d3083c94d6499efa8e2ea2ac8ef2d1"
"gitHead": "69af4eddd1ba47f76a71c78077d453deb572b1a0"
}

@ -18,6 +18,7 @@
"outputPath": "dist/libs/remix-tests",
"main": "libs/remix-tests/src/index.ts",
"tsConfig": "libs/remix-tests/tsconfig.lib.json",
"updateBuildableProjectDepsInPackageJson": false,
"assets": [
{
"glob": "remix-tests",

@ -78,6 +78,7 @@ const RemixApp = (props: IRemixAppUi) => {
}
return (
//@ts-ignore
<IntlProvider locale={locale.code} messages={locale.messages}>
<AppProvider value={value}>
<OriginWarning></OriginWarning>

@ -42,16 +42,30 @@ function HomeTabFeatured() {
<h5><FormattedMessage id='home.jumpIntoWeb3' /></h5>
<div><FormattedMessage id='home.jumpIntoWeb3Text'/></div>
<a className="remixui_home_text btn btn-secondary mt-2 text-decoration-none mb-3" onClick={() => _paq.push(['trackEvent', 'hometab', 'featuredSection', 'jumpIntoWeb3'])} target="__blank" href="https://remix-project.org"><FormattedMessage id='home.more' /></a>
<a
className="remixui_home_text btn btn-secondary mt-2 text-decoration-none mb-3"
onClick={() => _paq.push(['trackEvent', 'hometab', 'featuredSection', 'jumpIntoWeb3'])}
target="__blank"
href="https://remix-project.org"><FormattedMessage
id='home.jumpIntoWeb3More'
/></a>
</div>
</div>
<div className="mx-1 px-1 d-flex">
<img src={"/assets/img/remixRewardUser_small.webp"} style={{ flex: "1", height: "170px", maxWidth: "170px" }} alt="" ></img>
<a href="https://www.youtube.com/@EthereumRemix/videos" target="__blank">
<img src={"/assets/img/YouTubeLogo.webp"} style={{ flex: "1", height: "170px", maxWidth: "170px" }} alt="" ></img>
</a>
<div className="h6 w-50 p-4" style={{ flex: "1" }}>
<h5><FormattedMessage id='home.remixRewards' /></h5>
<p style={{ fontStyle: 'italic' }}><FormattedMessage id='home.remixRewardsText1' /></p>
<div><FormattedMessage id='home.remixRewardsText2' /></div>
<a className="remixui_home_text btn btn-secondary mt-2 text-decoration-none mb-3" target="__blank" onClick={() => _paq.push(['trackEvent', 'hometab', 'featuredSection', 'remixRewards'])} href="https://rewards.remix.ethereum.eth.limo"><FormattedMessage id='home.more' /></a>
<h5><FormattedMessage id='home.remixYouTube' /></h5>
<p style={{ fontStyle: 'italic' }}><FormattedMessage id='home.remixYouTubeText1' /></p>
<div><FormattedMessage id='home.remixYouTubeText2' /></div>
<a
className="remixui_home_text btn btn-secondary mt-2 text-decoration-none mb-3"
onClick={() => _paq.push(['trackEvent', 'hometab', 'featuredSection', 'youTubeMore'])}
target="__blank"
href="https://www.youtube.com/@EthereumRemix/videos"><FormattedMessage
id='home.remixYouTubeMore'
/></a>
</div>
</div>
<div className="mx-1 px-1 d-flex">
@ -60,7 +74,13 @@ function HomeTabFeatured() {
<h5><FormattedMessage id='home.betaTesting' /></h5>
<p style={{ fontStyle: 'italic' }}><FormattedMessage id='home.betaTestingText1' /></p>
<div><FormattedMessage id='home.betaTestingText2' /></div>
<a className="remixui_home_text btn btn-secondary mt-2 text-decoration-none mb-3" onClick={() => _paq.push(['trackEvent', 'hometab', 'featuredSection', 'betatesting'])} target="__blank" href="https://docs.google.com/forms/d/e/1FAIpQLSd0WsJnKbeJo-BGrnf7WijxAdmE4PnC_Z4M0IApbBfHLHZdsQ/viewform"><FormattedMessage id='home.more' /></a>
<a
className="remixui_home_text btn btn-secondary mt-2 text-decoration-none mb-3"
onClick={() => _paq.push(['trackEvent', 'hometab', 'featuredSection', 'betatesting'])}
target="__blank"
href="https://docs.google.com/forms/d/e/1FAIpQLSd0WsJnKbeJo-BGrnf7WijxAdmE4PnC_Z4M0IApbBfHLHZdsQ/viewform"><FormattedMessage
id='home.betaTestingMore'
/></a>
</div>
</div>
</Carousel>

@ -31,13 +31,24 @@ 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: 'basics' | 'useofweb3js' | 'deploylibraries') => {
const startLearnEthTutorial = async (tutorial: 'basics' | 'soliditybeginner' | 'deploylibraries') => {
await plugin.appManager.activatePlugin(['solidity', 'LearnEth', 'solidityUnitTesting'])
plugin.verticalIcons.select('LearnEth')
plugin.call('LearnEth', 'startTutorial', 'ethereum/remix-workshops', 'master', tutorial)
_paq.push(['trackEvent', 'hometab', 'startLearnEthTutorial', tutorial])
}
const goToLearnEthHome = async () => {
if(await plugin.appManager.isActive('LearnEth')) {
plugin.verticalIcons.select('LearnEth')
await plugin.call('LearnEth', 'home')
} else {
await plugin.appManager.activatePlugin(['LearnEth', 'solidity', 'solidityUnitTesting'])
plugin.verticalIcons.select('LearnEth')
await plugin.call('LearnEth', 'home')
}
}
return (
<div className="d-flex px-2 pb-2 pt-2 d-flex flex-column" id="hTLearnSection">
<div className="d-flex justify-content-between">
@ -46,7 +57,7 @@ function HomeTabLearn ({plugin}: HomeTabLearnProps) {
</label>
<button
onClick={ async () => {
await startLearnEthTutorial('basics')
await goToLearnEthHome()
}}
className="h-100 px-2 pt-0 btn"
>
@ -74,7 +85,7 @@ function HomeTabLearn ({plugin}: HomeTabLearnProps) {
{(state.visibleTutorial === VisibleTutorial.Intermediate) && <div className="pt-2 d-flex flex-column text-left">
<span>
<FormattedMessage id="home.learnEth2Desc" /></span>
<button className="btn btn-sm btn-secondary mt-2" style={{width: 'fit-content'}} onClick={() => startLearnEthTutorial('useofweb3js')}>
<button className="btn btn-sm btn-secondary mt-2" style={{width: 'fit-content'}} onClick={() => startLearnEthTutorial('soliditybeginner')}>
<FormattedMessage id="home.getStarted" />
</button>
</div>}

@ -1,2 +1,3 @@
export * from './lib/solidity-compiler'
export * from './lib/logic'
export * from './lib/logic/flattenerUtilities'

@ -5,7 +5,6 @@ import { CompilerContainerProps } from './types'
import { ConfigurationSettings } from '@remix-project/remix-lib'
import { checkSpecialChars, CustomTooltip, extractNameFromKey } from '@remix-ui/helper'
import { canUseWorker, baseURLBin, baseURLWasm, urlFromVersion, pathToURL } from '@remix-project/remix-solidity'
import { compilerReducer, compilerInitialState } from './reducers/compiler'
import { resetEditorMode, listenToEvents } from './actions/compiler'
import { getValidLanguage } from '@remix-project/remix-solidity'
@ -22,7 +21,6 @@ declare global {
_paq: any
}
}
const _paq = window._paq = window._paq || [] //eslint-disable-line
export const CompilerContainer = (props: CompilerContainerProps) => {
@ -733,7 +731,6 @@ export const CompilerContainer = (props: CompilerContainerProps) => {
setToggleExpander(!toggleExpander)
}
return (
<section>
<article>

@ -1,4 +1,4 @@
import React, { useState, useEffect, Fragment } from 'react' // eslint-disable-line
import React, { useState, useEffect } from 'react' // eslint-disable-line
import { FormattedMessage, useIntl } from 'react-intl'
import { ContractSelectionProps } from './types'
import { PublishToStorage } from '@remix-ui/publish-to-storage' // eslint-disable-line
@ -25,6 +25,7 @@ export const ContractSelection = (props: ContractSelectionProps) => {
}
}, [contractList])
const resetStorage = () => {
setStorage('')
}
@ -157,10 +158,10 @@ export const ContractSelection = (props: ContractSelectionProps) => {
swarmLocation: 'Swarm url where all metadata information can be found (contract needs to be published first)',
web3Deploy: 'Copy/paste this code to any JavaScript/Web3 console to deploy this contract'
}
let contractProperties = contractsDetails[selectedContract] || {}
contractProperties.compilerInput = compilerInput
let contractProperties:any = {}
// Make 'compilerInput' first field to display it as first item in 'Compilation Details' modal
contractProperties = JSON.parse(JSON.stringify(contractProperties, ["compilerInput", ...Object.keys(contractProperties)], 4))
if (compilerInput) contractProperties.compilerInput = compilerInput
contractProperties = Object.assign(contractProperties, contractsDetails[selectedContract])
const log = <div className="remixui_detailsJSON">
<TreeView>
{

@ -0,0 +1,169 @@
const IMPORT_SOLIDITY_REGEX = /^\s*import(\s+).*$/gm;
const SPDX_SOLIDITY_REGEX = /^\s*\/\/ SPDX-License-Identifier:.*$/gm;
export function getDependencyGraph(ast, target) {
const graph = tsort();
const visited = {};
visited[target] = 1;
_traverse(graph, visited, ast, target);
return graph;
}
export function concatSourceFiles(files, sources) {
let concat = '';
for (const file of files) {
const source = sources[file].content;
const sourceWithoutImport = source.replace(IMPORT_SOLIDITY_REGEX, '');
const sourceWithoutSPDX = sourceWithoutImport.replace(SPDX_SOLIDITY_REGEX, '');
concat += `\n// File: ${file}\n\n`;
concat += sourceWithoutSPDX;
}
return concat;
}
function _traverse(graph, visited, ast, name) {
const currentAst = ast[name].ast;
const dependencies = _getDependencies(currentAst);
for (const dependency of dependencies) {
const path = resolve(name, dependency);
if (path in visited) {
continue;
}
visited[path] = 1;
graph.add(name, path);
_traverse(graph, visited, ast, path);
}
}
function _getDependencies(ast) {
const dependencies = ast.nodes
.filter(node => node.nodeType === 'ImportDirective')
.map(node => node.file);
return dependencies;
}
// TSORT
function tsort(initial?: any) {
const graph = new Graph();
if (initial) {
initial.forEach(function (entry) {
Graph.prototype.add.apply(graph, entry);
});
}
return graph;
}
function Graph() {
this.nodes = {};
}
// Add sorted items to the graph
Graph.prototype.add = function () {
const self = this;
// eslint-disable-next-line prefer-rest-params
let items = [].slice.call(arguments);
if (items.length === 1 && Array.isArray(items[0]))
items = items[0];
items.forEach(function (item) {
if (!self.nodes[item]) {
self.nodes[item] = [];
}
});
for (let i = 1; i < items.length; i++) {
const from = items[i];
const to = items[i - 1];
self.nodes[from].push(to);
}
return self;
};
// Depth first search
// As given in http://en.wikipedia.org/wiki/Topological_sorting
Graph.prototype.sort = function () {
const self = this;
const nodes = Object.keys(this.nodes);
const sorted = [];
const marks = {};
for (let i = 0; i < nodes.length; i++) {
const node = nodes[i];
if (!marks[node]) {
visit(node);
}
}
return sorted;
function visit(node) {
if (marks[node] === 'temp')
throw new Error("There is a cycle in the graph. It is not possible to derive a topological sort.");
else if (marks[node])
return;
marks[node] = 'temp';
self.nodes[node].forEach(visit);
marks[node] = 'perm';
sorted.push(node);
}
};
Graph.prototype.isEmpty = function () {
const nodes = Object.keys(this.nodes);
return nodes.length === 0;
}
// PATH
function resolve(parentPath, childPath) {
if (_isAbsolute(childPath)) {
return childPath;
}
const path = parentPath + '/../' + childPath;
const pathParts = path.split('/');
const resolvedParts = _resolvePathArray(pathParts);
const resolvedPath = resolvedParts
.join('/')
.replace('http:/', 'http://')
.replace('https:/', 'https://');
return resolvedPath;
}
function _isAbsolute(path) {
return path[0] !== '.';
}
function _resolvePathArray(parts) {
const res = [];
for (let i = 0; i < parts.length; i++) {
const p = parts[i];
// ignore empty parts
if (!p || p === '.')
continue;
if (p === '..') {
if (res.length && res[res.length - 1] !== '..') {
res.pop();
}
} else {
res.push(p);
}
}
return res;
}

@ -0,0 +1,294 @@
/* eslint-disable prefer-const */
import domToImage from 'dom-to-image';
import { jsPDF } from 'jspdf';
const _cloneNode = (node, javascriptEnabled) => {
let child = node.firstChild
const clone = node.nodeType === 3 ? document.createTextNode(node.nodeValue) : node.cloneNode(false)
while (child) {
if (javascriptEnabled === true || child.nodeType !== 1 || child.nodeName !== 'SCRIPT') {
clone.appendChild(_cloneNode(child, javascriptEnabled))
}
child = child.nextSibling
}
if (node.nodeType === 1) {
if (node.nodeName === 'CANVAS') {
clone.width = node.width
clone.height = node.height
clone.getContext('2d').drawImage(node, 0, 0)
} else if (node.nodeName === 'TEXTAREA' || node.nodeName === 'SELECT') {
clone.value = node.value
}
clone.addEventListener('load', (() => {
clone.scrollTop = node.scrollTop
clone.scrollLeft = node.scrollLeft
}), true)
}
return clone
}
const _createElement = (tagName, {className, innerHTML, style}) => {
let i
let scripts
const el = document.createElement(tagName)
if (className) {
el.className = className
}
if (innerHTML) {
el.innerHTML = innerHTML
scripts = el.getElementsByTagName('script')
i = scripts.length
while (i-- > 0) {
scripts[i].parentNode.removeChild(scripts[i])
}
}
for (const key in style) {
el.style[key] = style[key];
}
return el;
};
const _isCanvasBlank = canvas => {
const blank = document.createElement('canvas');
blank.width = canvas.width;
blank.height = canvas.height;
const ctx = blank.getContext('2d');
ctx.fillStyle = '#FFFFFF';
ctx.fillRect(0, 0, blank.width, blank.height);
return canvas.toDataURL() === blank.toDataURL();
};
const downloadPdf = (dom, options, cb) => {
const a4Height = 841.89;
const a4Width = 595.28;
let overrideWidth;
let container;
let containerCSS;
let containerWidth;
let elements;
let excludeClassNames;
let excludeTagNames;
let filename;
let filterFn;
let innerRatio;
let overlay;
let overlayCSS;
let pageHeightPx;
let proxyUrl;
let compression = 'NONE';
let scale;
let opts;
let offsetHeight;
let offsetWidth;
let scaleObj;
let style;
const transformOrigin = 'top left';
const pdfOptions: any = {
orientation: 'l',
unit: 'pt',
format: 'a4'
};
({filename, excludeClassNames = [], excludeTagNames = ['button', 'input', 'select'], overrideWidth, proxyUrl, compression, scale} = options);
overlayCSS = {
position: 'fixed',
zIndex: 1000,
opacity: 0,
left: 0,
right: 0,
bottom: 0,
top: 0,
backgroundColor: 'rgba(0,0,0,0.8)'
};
if (overrideWidth) {
overlayCSS.width = `${overrideWidth}px`;
}
containerCSS = {
position: 'absolute',
left: 0,
right: 0,
top: 0,
height: 'auto',
margin: 'auto',
overflow: 'auto',
backgroundColor: 'white'
};
overlay = _createElement('div', {
style: overlayCSS,
className: '',
innerHTML: ''
});
container = _createElement('div', {
style: containerCSS,
className: '',
innerHTML: ''
});
//@ts-ignore
container.appendChild(_cloneNode(dom));
overlay.appendChild(container);
document.body.appendChild(overlay);
innerRatio = a4Height / a4Width;
containerWidth = overrideWidth || container.getBoundingClientRect().width;
pageHeightPx = Math.floor(containerWidth * innerRatio);
elements = container.querySelectorAll('*');
for (let i = 0, len = excludeClassNames.length; i < len; i++) {
const clName = excludeClassNames[i];
container.querySelectorAll(`.${clName}`).forEach(function(a) {
return a.remove();
});
}
for (let j = 0, len1 = excludeTagNames.length; j < len1; j++) {
const tName = excludeTagNames[j];
let els = container.getElementsByTagName(tName);
for (let k = els.length - 1; k >= 0; k--) {
if (!els[k]) {
continue;
}
els[k].parentNode.removeChild(els[k]);
}
}
Array.prototype.forEach.call(elements, el => {
let clientRect;
let endPage;
let nPages;
let pad;
let rules;
let startPage;
rules = {
before: false,
after: false,
avoid: true
};
clientRect = el.getBoundingClientRect();
if (rules.avoid && !rules.before) {
startPage = Math.floor(clientRect.top / pageHeightPx);
endPage = Math.floor(clientRect.bottom / pageHeightPx);
nPages = Math.abs(clientRect.bottom - clientRect.top) / pageHeightPx;
// Turn on rules.before if the el is broken and is at most one page long.
if (endPage !== startPage && nPages <= 1) {
rules.before = true;
}
// Before: Create a padding div to push the element to the next page.
if (rules.before) {
pad = _createElement('div', {
className: '',
innerHTML: '',
style: {
display: 'block',
height: `${pageHeightPx - clientRect.top % pageHeightPx}px`
}
});
return el.parentNode.insertBefore(pad, el);
}
}
});
// Remove unnecessary elements from result pdf
filterFn = ({classList, tagName}) => {
let cName;
let j;
let len;
let ref;
if (classList) {
for (j = 0, len = excludeClassNames.length; j < len; j++) {
cName = excludeClassNames[j];
if (Array.prototype.indexOf.call(classList, cName) >= 0) {
return false;
}
}
}
ref = tagName != null ? tagName.toLowerCase() : undefined;
return excludeTagNames.indexOf(ref) < 0;
};
opts = {
filter: filterFn,
proxy: proxyUrl
};
if (scale) {
offsetWidth = container.offsetWidth;
offsetHeight = container.offsetHeight;
style = {
transform: 'scale(' + scale + ')',
transformOrigin: transformOrigin,
width: offsetWidth + 'px',
height: offsetHeight + 'px'
};
scaleObj = {
width: offsetWidth * scale,
height: offsetHeight * scale,
quality: 1,
style: style
};
opts = Object.assign(opts, scaleObj);
}
return domToImage.toCanvas(container, opts).then(canvas => {
let h;
let imgData;
let nPages;
let page;
let pageCanvas;
let pageCtx;
let pageHeight;
let pdf;
let pxFullHeight;
let w;
// Remove overlay
document.body.removeChild(overlay);
// Initialize the PDF.
pdf = new jsPDF(pdfOptions);
// Calculate the number of pages.
pxFullHeight = canvas.height;
nPages = Math.ceil(pxFullHeight / pageHeightPx);
// Define pageHeight separately so it can be trimmed on the final page.
pageHeight = a4Height;
pageCanvas = document.createElement('canvas');
pageCtx = pageCanvas.getContext('2d');
pageCanvas.width = canvas.width;
pageCanvas.height = pageHeightPx;
page = 0;
while (page < nPages) {
if (page === nPages - 1 && pxFullHeight % pageHeightPx !== 0) {
pageCanvas.height = pxFullHeight % pageHeightPx;
pageHeight = pageCanvas.height * a4Width / pageCanvas.width;
}
w = pageCanvas.width;
h = pageCanvas.height;
pageCtx.fillStyle = 'white';
pageCtx.fillRect(0, 0, w, h);
pageCtx.drawImage(canvas, 0, page * pageHeightPx, w, h, 0, 0, w, h);
// Don't create blank pages
if (_isCanvasBlank(pageCanvas)) {
++page;
continue;
}
// Add the page to the PDF.
if (page) {
pdf.addPage();
}
imgData = pageCanvas.toDataURL('image/PNG');
pdf.addImage(imgData, 'PNG', 0, 0, a4Width, pageHeight, undefined, compression);
++page;
}
if (typeof cb === "function") {
cb(pdf);
}
return pdf.save(filename);
}).catch(error => {
// Remove overlay
document.body.removeChild(overlay);
if (typeof cb === "function") {
cb(null);
}
return console.error(error);
});
};
module.exports = downloadPdf;

@ -0,0 +1 @@
export * from './lib/solidity-uml-gen'

@ -0,0 +1,3 @@
.remixui_default-message {
margin-top: 100px;
}

@ -0,0 +1,118 @@
import { CustomTooltip } from '@remix-ui/helper'
import React, { Fragment, useEffect, useState } from 'react'
import { TransformComponent, TransformWrapper } from 'react-zoom-pan-pinch'
import { ISolidityUmlGen } from '../types'
import './css/solidity-uml-gen.css'
export interface RemixUiSolidityUmlGenProps {
plugin?: ISolidityUmlGen
updatedSvg?: string
loading?: boolean
themeSelected?: string
}
type ButtonAction = {
svgValid: () => boolean
action: () => void
buttonText: string
icon?: string
customcss?: string
}
interface ActionButtonsProps {
buttons: ButtonAction[]
}
const ActionButtons = ({ buttons }: ActionButtonsProps) => (
<>
{buttons.map(btn => (
<CustomTooltip
key={btn.buttonText}
placement="top"
tooltipText={btn.buttonText}
tooltipId={btn.buttonText}
>
<button
key={btn.buttonText}
className={`btn btn-primary btn-sm rounded-circle ${btn.customcss}`}
disabled={!btn.svgValid}
onClick={btn.action}
>
<i className={btn.icon}></i>
</button>
</CustomTooltip>
))}
</>
)
export function RemixUiSolidityUmlGen ({ plugin, updatedSvg, loading, themeSelected }: RemixUiSolidityUmlGenProps) {
const [showViewer, setShowViewer] = useState(false)
const [svgPayload, setSVGPayload] = useState<string>('')
const [validSvg, setValidSvg] = useState(false)
useEffect(() => {
setValidSvg (updatedSvg.startsWith('<?xml') && updatedSvg.includes('<svg'))
setShowViewer(updatedSvg.startsWith('<?xml') && updatedSvg.includes('<svg'))
}
, [updatedSvg])
const buttons: ButtonAction[] = [
{
buttonText: 'Download as PDF',
svgValid: () => validSvg,
action: () => console.log('generated!!'),
icon: 'fa mr-1 pt-1 pb-1 fa-file'
},
{
buttonText: 'Download as PNG',
svgValid: () => validSvg,
action: () => console.log('generated!!'),
icon: 'fa fa-picture-o'
}
]
const DefaultInfo = () => (
<div className="d-flex flex-column justify-content-center align-items-center mt-5">
<h2 className="h2 align-self-start"><p>To view your contract as a Uml Diragram</p></h2>
<h3 className="h4 align-self-start"><p>Right Click on your contract file (Usually ends with .sol)</p></h3>
<h3 className="h4 align-self-start"><p>Click on Generate UML</p></h3>
</div>
)
const Display = () => {
const invert = themeSelected === 'dark' ? 'invert(0.8)' : 'invert(0)'
return (
<div className="d-flex flex-column justify-content-center align-items-center">
<div id="umlImageHolder" className="w-100 px-2 py-2">
{ validSvg && showViewer ? (
<TransformWrapper
initialScale={1}
>
{
({ zoomIn, zoomOut, resetTransform }) => (
<Fragment>
<TransformComponent>
<img
src={`data:image/svg+xml;base64,${btoa(plugin.updatedSvg ?? svgPayload)}`}
width={'100%'}
height={'auto'}
style={{ filter: invert }}
/>
</TransformComponent>
</Fragment>
)
}
</TransformWrapper>
) : loading ? <div className="justify-content-center align-items-center d-flex mx-auto my-auto">
<i className="fas fa-spinner fa-spin fa-4x"></i>
</div> : <DefaultInfo />}
</div>
</div>
)}
return (<>
{ <Display /> }
</>
)
}
export default RemixUiSolidityUmlGen

@ -0,0 +1,14 @@
import { ViewPlugin } from '@remixproject/engine-web'
import React from 'react'
export interface ISolidityUmlGen extends ViewPlugin {
element: HTMLDivElement
currentFile: string
svgPayload: string
updatedSvg: string
showUmlDiagram(path: string, svgPayload: string): void
updateComponent(state: any): JSX.Element
setDispatch(dispatch: React.Dispatch<any>): void
render(): JSX.Element
}

@ -43,4 +43,4 @@ export interface ThemeModule extends Plugin<any, any> {
fixInvert(image?: any): void;
}
interface Theme { name: string, quality: string, url: string }
export interface Theme { name: string, quality: string, url: string }

@ -86,7 +86,7 @@ const Icon = ({
return (
<>
<CustomTooltip
placement={name === 'settings' ? 'right' : name === 'search' ? 'bottom' :
placement={name === 'settings' ? 'right' : name === 'search' ? 'top' :
name === 'udapp' ? 'bottom' : "top"}
tooltipText={title}
delay={{ show: 1000, hide: 0 }}

@ -435,6 +435,7 @@ export const FileExplorer = (props: FileExplorerProps) => {
props.modal('Moving Folder Failed', 'Unexpected error while moving folder: ' + src, 'Close', async () => {})
}
}
return (
<Drag onFileMoved={handleFileMove} onFolderMoved={handleFolderMove}>
<div ref={treeRef} tabIndex={0} style={{ outline: "none" }}>

@ -1,6 +1,9 @@
/* eslint-disable @nrwl/nx/enforce-module-boundaries */
import React from 'react'
import { customAction } from '@remixproject/plugin-api/lib/file-system/file-panel'
import { fileDecoration } from '@remix-ui/file-decorators';
import { fileDecoration } from '@remix-ui/file-decorators'
import { RemixAppManager } from 'libs/remix-ui/plugin-manager/src/types'
import { ViewPlugin } from '@remixproject/engine-web'
export type action = { name: string, type?: Array<'folder' | 'gist' | 'file'>, path?: string[], extension?: string[], pattern?: string[], id: string, multiselect: boolean, label: string, sticky?: boolean }
export interface JSONStandardInput {
@ -16,32 +19,7 @@ export interface JSONStandardInput {
export type MenuItems = action[]
export type WorkspaceTemplate = 'gist-template' | 'code-template' | 'remixDefault' | 'blank' | 'ozerc20' | 'zeroxErc20' | 'ozerc721'
export interface WorkspaceProps {
plugin: {
setWorkspace: ({ name, isLocalhost }, setEvent: boolean) => void,
createWorkspace: (name: string, workspaceTemplateName: string) => void,
renameWorkspace: (oldName: string, newName: string) => void
workspaceRenamed: ({ name }) => void,
workspaceCreated: ({ name }) => void,
workspaceDeleted: ({ name }) => void,
workspace: any // workspace provider,
browser: any // browser provider
localhost: any // localhost provider
fileManager : any
registry: any // registry
request: {
createWorkspace: () => void,
setWorkspace: (workspaceName: string) => void,
createNewFile: () => void,
uploadFile: (target: EventTarget & HTMLInputElement) => void,
getCurrentWorkspace: () => void
} // api request,
workspaces: any,
registeredMenuItems: MenuItems // menu items
removedMenuItems: MenuItems
initialWorkspace: string,
resetNewFile: () => void,
getWorkspaces: () => string[]
}
plugin: FilePanelType
}
export interface WorkspaceState {
hideRemixdExplorer: boolean
@ -67,6 +45,36 @@ export interface FileType {
child?: File[]
}
export interface FilePanelType extends ViewPlugin {
setWorkspace: ({ name, isLocalhost }, setEvent: boolean) => void,
createWorkspace: (name: string, workspaceTemplateName: string) => void,
renameWorkspace: (oldName: string, newName: string) => void
compileContractForUml: (path: string) => void
workspaceRenamed: ({ name }) => void,
workspaceCreated: ({ name }) => void,
workspaceDeleted: ({ name }) => void,
workspace?: any // workspace provider,
browser?: any // browser provider
localhost?: any // localhost provider
fileManager? : any
appManager: RemixAppManager
registry?: any // registry
pluginApi?: any
request: {
createWorkspace: () => void,
setWorkspace: (workspaceName: string) => void,
createNewFile: () => void,
uploadFile: (target: EventTarget & HTMLInputElement) => void,
getCurrentWorkspace: () => void
} // api request,
workspaces: any,
registeredMenuItems: MenuItems // menu items
removedMenuItems: MenuItems
initialWorkspace: string,
resetNewFile: () => void,
getWorkspaces: () => string[]
}
/* eslint-disable-next-line */
export interface FileExplorerProps {
name: string,
@ -136,6 +144,7 @@ export interface FileExplorerContextMenuProps {
paste?: (destination: string, type: string) => void
copyFileName?: (path: string, type: string) => void
copyPath?: (path: string, type: string) => void
generateUml?: (path: string) => Promise<void>
}
export interface FileExplorerState {

@ -30,7 +30,7 @@ export const contextMenuActions: MenuItems = [{
extension: ['.js', '.ts'],
multiselect: false,
label: ''
}, {
},{
id: 'pushChangesToGist',
name: 'Push changes to gist',
type: ['gist'],

@ -1,6 +1,6 @@
{
"name": "@remix-project/remix-url-resolver",
"version": "0.0.43",
"version": "0.0.45",
"description": "Solidity import url resolver engine",
"main": "src/index.js",
"types": "src/index.d.ts",
@ -40,5 +40,5 @@
"typescript": "^3.1.6"
},
"typings": "src/index.d.ts",
"gitHead": "b9f8241a57d3083c94d6499efa8e2ea2ac8ef2d1"
"gitHead": "69af4eddd1ba47f76a71c78077d453deb572b1a0"
}

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

@ -1,6 +1,6 @@
{
"name": "@remix-project/remix-ws-templates",
"version": "1.0.8",
"version": "1.0.10",
"description": "Create a Remix IDE workspace using different templates",
"main": "src/index.js",
"types": "src/index.d.ts",
@ -25,5 +25,5 @@
"ethers": "^5.4.2",
"web3": "^1.5.1"
},
"gitHead": "b9f8241a57d3083c94d6499efa8e2ea2ac8ef2d1"
"gitHead": "69af4eddd1ba47f76a71c78077d453deb572b1a0"
}

@ -13,6 +13,7 @@
"outputPath": "dist/libs/remix-ws-templates",
"main": "libs/remix-ws-templates/src/index.ts",
"tsConfig": "libs/remix-ws-templates/tsconfig.lib.json",
"updateBuildableProjectDepsInPackageJson": false,
"assets": [
{
"glob": "templates/**/*",

@ -13,6 +13,7 @@
"outputPath": "dist/libs/remixd",
"main": "libs/remixd/src/index.ts",
"tsConfig": "libs/remixd/tsconfig.lib.json",
"updateBuildableProjectDepsInPackageJson": false,
"assets": [
"libs/remixd/*.md",
"libs/remixd/origins.json"

@ -1,6 +1,6 @@
{
"name": "remix-project",
"version": "0.30.0-dev",
"version": "0.31.0-dev",
"license": "MIT",
"description": "Ethereum Remix Monorepo",
"keywords": [
@ -49,6 +49,7 @@
"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",
"publishDev:libs": "yarn run build:libs && lerna publish --npm-tag alpha --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",
"babel": "babel",
"watch:e2e": "nodemon",
@ -104,6 +105,7 @@
"nightwatch_local_providers": "yarn run build:e2e && nightwatch --config dist/apps/remix-ide-e2e/nightwatch.js dist/apps/remix-ide-e2e/src/tests/providers.test.js --env=chromeDesktop",
"onchange": "onchange apps/remix-ide/build/app.js -- npm-run-all lint",
"remixd": "nx build remixd && chmod +x dist/libs/remixd/src/bin/remixd.js && dist/libs/remixd/src/bin/remixd.js --remix-ide http://127.0.0.1:8080",
"simulator": "nx build remix-simulator && chmod +x dist/libs/remix-simulator/bin/ethsim && dist/libs/remix-simulator/bin/ethsim start --rpc",
"selenium": "selenium-standalone start",
"selenium-install": "selenium-standalone install",
"sourcemap": "exorcist --root ../ apps/remix-ide/build/app.js.map > apps/remix-ide/build/app.js",
@ -149,6 +151,7 @@
"core-js": "^3.6.5",
"deep-equal": "^1.0.1",
"document-register-element": "1.13.1",
"dom-to-pdf": "^0.3.1",
"eslint-config-prettier": "^8.5.0",
"ethers": "^5.4.2",
"ethjs-util": "^0.1.6",
@ -185,9 +188,11 @@
"react-multi-carousel": "^2.8.2",
"react-router-dom": "^6.3.0",
"react-tabs": "^3.2.2",
"react-zoom-pan-pinch": "^2.2.0",
"regenerator-runtime": "0.13.7",
"rss-parser": "^3.12.0",
"signale": "^1.4.0",
"sol2uml": "^2.4.3",
"string-similarity": "^4.0.4",
"swarmgw": "^0.3.1",
"time-stamp": "^2.2.0",
@ -216,17 +221,18 @@
"@babel/preset-typescript": "^7.18.6",
"@babel/register": "^7.4.4",
"@fortawesome/fontawesome-free": "^5.8.1",
"@nrwl/cli": "^15.0.0",
"@nrwl/eslint-plugin-nx": "^15.0.0",
"@nrwl/jest": "15.0.0",
"@nrwl/js": "15.0.0",
"@nrwl/linter": "15.0.0",
"@nrwl/node": "15.0.0",
"@nrwl/react": "15.0.0",
"@nrwl/tao": "^15.0.0",
"@nrwl/web": "15.0.0",
"@nrwl/webpack": "15.0.0",
"@nrwl/workspace": "^15.0.0",
"@nrwl/cli": "^15.6.3",
"@nrwl/eslint-plugin-nx": "^15.6.3",
"@nrwl/jest": "15.6.3",
"@nrwl/js": "15.6.3",
"@nrwl/linter": "15.6.3",
"@nrwl/node": "15.6.3",
"@nrwl/react": "15.6.3",
"@nrwl/tao": "^15.6.3",
"@nrwl/web": "15.6.3",
"@nrwl/webpack": "15.6.3",
"@nrwl/workspace": "^15.6.3",
"@svgr/webpack": "^6.5.1",
"@testing-library/react": "13.4.0",
"@types/axios": "^0.14.0",
"@types/chai": "^4.3.3",
@ -267,10 +273,10 @@
"browserify-reload": "^1.0.3",
"browserify-zlib": "^0.2.0",
"buffer": "^6.0.3",
"chai": "^4.3.7",
"child_process": "^1.0.2",
"colors": "^1.4.0",
"colors-browserify": "^0.1.1",
"chai": "^4.3.7",
"component-type": "^1.2.1",
"constants-browserify": "^1.0.0",
"copy-to-clipboard": "^3.3.1",
@ -278,6 +284,7 @@
"crypto-browserify": "^3.12.0",
"csjs-inject": "^1.0.1",
"css-loader": "^6.7.1",
"css-minimizer-webpack-plugin": "^4.2.2",
"csslint": "^1.0.2",
"dotenv": "^8.2.0",
"eslint": "^8.26.0",
@ -318,7 +325,7 @@
"npm-link-local": "^1.1.0",
"npm-merge-driver": "^2.3.5",
"npm-run-all": "^4.0.2",
"nx": "15.0.0",
"nx": "15.6.3",
"nyc": "^13.3.0",
"onchange": "^3.2.1",
"os-browserify": "^0.3.0",
@ -334,6 +341,7 @@
"style-loader": "^3.3.1",
"tap-spec": "^5.0.0",
"tape": "^4.13.3",
"terser-webpack-plugin": "^5.3.6",
"timers-browserify": "^2.0.12",
"ts-jest": "^29.0.3",
"ts-node": "10.9.1",

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

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save