From b522b2a85395ac1b4561a3fcb2645307707a70f8 Mon Sep 17 00:00:00 2001 From: David Disu Date: Mon, 11 Jul 2022 13:12:23 +0100 Subject: [PATCH] Track inherited contracts using exported symbols --- .../src/lib/openzeppelin-proxy.ts | 34 ++-- libs/remix-core-plugin/src/types/contract.ts | 185 ++++++++++-------- .../run-tab/src/lib/actions/events.ts | 5 +- 3 files changed, 130 insertions(+), 94 deletions(-) diff --git a/libs/remix-core-plugin/src/lib/openzeppelin-proxy.ts b/libs/remix-core-plugin/src/lib/openzeppelin-proxy.ts index 55abe4e443..bf3302f625 100644 --- a/libs/remix-core-plugin/src/lib/openzeppelin-proxy.ts +++ b/libs/remix-core-plugin/src/lib/openzeppelin-proxy.ts @@ -1,6 +1,6 @@ -import { Plugin } from '@remixproject/engine'; -import { ContractABI, ContractAST, DeployOptions } from '../types/contract'; -import { UUPS, UUPSABI, UUPSBytecode, UUPSfunAbi, UUPSupgradeAbi } from './constants/uups'; +import { Plugin } from '@remixproject/engine' +import { ContractABI, ContractAST, ContractSources, DeployOptions } from '../types/contract' +import { UUPS, UUPSABI, UUPSBytecode, UUPSfunAbi, UUPSupgradeAbi } from './constants/uups' const proxyProfile = { name: 'openzeppelin-proxy', @@ -28,20 +28,30 @@ export class OpenZeppelinProxy extends Plugin { return false } - async getProxyOptions (contracts: ContractABI): Promise<{ [name: string]: DeployOptions }> { + async getProxyOptions (data: ContractSources, file: string): Promise<{ [name: string]: DeployOptions }> { + const contracts = data.contracts[file] + const ast = data.sources[file].ast const inputs = {} if (this.kind === 'UUPS') { Object.keys(contracts).map(name => { - const abi = contracts[name].abi - const initializeInput = abi.find(node => node.name === 'initialize') + if (ast) { + const UUPSSymbol = ast.exportedSymbols['UUPSUpgradeable'] ? ast.exportedSymbols['UUPSUpgradeable'][0] : null - inputs[name] = { - options: [{ title: 'Deploy with Proxy', active: false }, { title: 'Upgrade with Proxy', active: false }], - initializeOptions: { - inputs: initializeInput, - initializeInputs: initializeInput ? this.blockchain.getInputs(initializeInput) : null - } + ast.absolutePath === file && ast.nodes.map((node) => { + if (node.name === name && node.linearizedBaseContracts.includes(UUPSSymbol)) { + const abi = contracts[name].abi + const initializeInput = abi.find(node => node.name === 'initialize') + + inputs[name] = { + options: [{ title: 'Deploy with Proxy', active: false }, { title: 'Upgrade with Proxy', active: false }], + initializeOptions: { + inputs: initializeInput, + initializeInputs: initializeInput ? this.blockchain.getInputs(initializeInput) : null + } + } + } + }) } }) } diff --git a/libs/remix-core-plugin/src/types/contract.ts b/libs/remix-core-plugin/src/types/contract.ts index b6d2aa513a..a327539a60 100644 --- a/libs/remix-core-plugin/src/types/contract.ts +++ b/libs/remix-core-plugin/src/types/contract.ts @@ -54,86 +54,40 @@ export interface ContractAST { }[] } -export interface ContractABI { - [key: string]: { - abi: ({ - inputs: never[]; - stateMutability: string; - type: string; - anonymous?: undefined; - name?: undefined; - outputs?: undefined; - } | { - anonymous: boolean; - inputs: { - indexed: boolean; - internalType: string; - name: string; - type: string; - }[]; - name: string; - type: string; - stateMutability?: undefined; - outputs?: undefined; - } | { - inputs: { - internalType: string; - name: string; - type: string; - }[]; - name: string; - outputs: { - internalType: string; - name: string; - type: string; - }[]; - stateMutability: string; - type: string; - anonymous?: undefined; - })[]; - devdoc: { - kind: string; - methods: { - [key: string]: { - [key: string]: string - } - }; - version: number; - }; - evm: any - metadata: string; - storageLayout: { - storage: { - astId: number; - contract: string; - label: string; - offset: number; - slot: string; - type: string; - }[]; - types: { - [key: string]: { - base: string; - encoding: string; - label: string; - numberOfBytes: string; - members?: { - astId: number; - contract: string; - label: string; - offset: number; - slot: string; - type: string; - }[]; - }; - }; - }; - userdoc: { - kind: string; - methods: any; - version: number; - }; - }; +export type ContractABI = { + inputs: []; + stateMutability: string; + type: string; + anonymous?: undefined; + name?: string; + outputs?: undefined; +} | { + anonymous: boolean; + inputs: { + indexed: boolean; + internalType: string; + name: string; + type: string; + }[]; + name: string; + type: string; + stateMutability?: undefined; + outputs?: undefined; +} | { + inputs: { + internalType: string; + name: string; + type: string; + }[]; + name: string; + outputs: { + internalType: string; + name: string; + type: string; + }[]; + stateMutability: string; + type: string; + anonymous?: undefined; } export type DeployMode = 'Deploy with Proxy' | 'Upgrade with Proxy' @@ -158,3 +112,74 @@ export interface DeployOptions { initializeOptions: DeployOption, options: { title: DeployMode, active: boolean }[] } + +export interface ContractSources { + contracts: { + [path: string]: { + [contractName: string]: { + abi: ContractABI[], + devdoc: { + kind: string + methods: { + [key: string]: { + [key: string]: string + } + }; + version: number + } + evm: any + metadata: string + storageLayout: { + storage: { + astId: number + contract: string + label: string + offset: number + slot: string + type: string + }[] + types: { + [key: string]: { + base: string + encoding: string + label: string + numberOfBytes: string + members?: { + astId: number + contract: string + label: string + offset: number + slot: string + type: string + }[] + } + } + } + userdoc: { + kind: string + methods: any + version: number + } + } + } + }, + error: { + component: string, + errorCode: string, + formattedMessage: string, + message: string, + severity: string, + sourceLocation: { + end: number, + file: string, + start: number + }, + type: string + }[], + sources: { + [path: string]: { + ast: ContractAST, + id: number + } + } + } diff --git a/libs/remix-ui/run-tab/src/lib/actions/events.ts b/libs/remix-ui/run-tab/src/lib/actions/events.ts index 447da599fc..0156ef8432 100644 --- a/libs/remix-ui/run-tab/src/lib/actions/events.ts +++ b/libs/remix-ui/run-tab/src/lib/actions/events.ts @@ -6,6 +6,7 @@ import { addDeployOption, clearAllInstances, clearRecorderCount, fetchContractLi import { CompilerAbstract } from '@remix-project/remix-solidity' import * as ethJSUtil from 'ethereumjs-util' import Web3 from 'web3' +import { ContractSources } from "../types" export const setupEvents = (plugin: RunTab, dispatch: React.Dispatch) => { plugin.blockchain.events.on('newTransaction', (tx, receipt) => { @@ -92,7 +93,7 @@ export const setupEvents = (plugin: RunTab, dispatch: React.Dispatch) => { }) } -const broadcastCompilationResult = async (plugin: RunTab, dispatch: React.Dispatch, file, source, languageVersion, data, input?) => { +const broadcastCompilationResult = async (plugin: RunTab, dispatch: React.Dispatch, file, source, languageVersion, data: ContractSources, input?) => { // TODO check whether the tab is configured const compiler = new CompilerAbstract(languageVersion, data, source, input) @@ -108,7 +109,7 @@ const broadcastCompilationResult = async (plugin: RunTab, dispatch: React.Dispat const isUpgradeable = await plugin.call('openzeppelin-proxy', 'isConcerned', data.sources[file] ? data.sources[file].ast : {}) if (isUpgradeable) { - const options = await plugin.call('openzeppelin-proxy', 'getProxyOptions', data.contracts[file]) + const options = await plugin.call('openzeppelin-proxy', 'getProxyOptions', data, file) dispatch(addDeployOption({ [file]: options })) } else {