Merge pull request #4143 from ethereum/ozbackwards

Oz proxy backwards compatible
pull/5370/head
Aniket 1 year ago committed by GitHub
commit 14ac17871a
  1. 345
      apps/remix-ide-e2e/src/tests/proxy_oz_v4.test.ts
  2. 20
      apps/remix-ide-e2e/src/tests/proxy_oz_v5.test.ts
  3. 30
      libs/remix-core-plugin/src/lib/compiler-fetch-and-compile.ts
  4. 21
      libs/remix-core-plugin/src/lib/constants/uups.ts
  5. 102
      libs/remix-core-plugin/src/lib/openzeppelin-proxy.ts

@ -0,0 +1,345 @@
'use strict'
import { NightwatchBrowser } from 'nightwatch'
import init from '../helpers/init'
let firstProxyAddress: string
let lastProxyAddress: string
let shortenedFirstAddress: string
let shortenedLastAddress: string
module.exports = {
'@disabled': true,
before: function (browser: NightwatchBrowser, done: VoidFunction) {
init(browser, done)
},
'@sources': function () {
return sources
},
'Should set the compiler version to 8.19': function(browser: NightwatchBrowser) {
browser.setSolidityCompilerVersion('soljson-v0.8.19+commit.7dd6d404.js')
},
'Should show deploy proxy option for UUPS upgradeable contract #group1': function (browser: NightwatchBrowser) {
browser
.addFile('myTokenV1.sol', sources[0]['myTokenV1.sol'])
.clickLaunchIcon('solidity')
.pause(2000)
// because the compilatiom imports are slow and sometimes stop loading (not sure why, it's bug) we need to recompile and check to see if the files are really in de FS
.click('[data-id="compilerContainerCompileBtn"]')
.clickLaunchIcon('filePanel')
.isVisible({
selector: '*[data-id="treeViewDivtreeViewItem.deps/npm/@openzeppelin/contracts-upgradeable@4.8.3/proxy/beacon/IBeaconUpgradeable.sol"]',
timeout: 120000,
suppressNotFoundErrors: true
})
.clickLaunchIcon('solidity')
.click('[data-id="compilerContainerCompileBtn"]')
.clickLaunchIcon('filePanel')
.isVisible({
selector: '*[data-id="treeViewDivtreeViewItem.deps/npm/@openzeppelin/contracts-upgradeable@4.8.3/proxy/beacon/IBeaconUpgradeable.sol"]',
timeout: 120000,
suppressNotFoundErrors: true
})
.clickLaunchIcon('solidity')
.click('[data-id="compilerContainerCompileBtn"]')
.clickLaunchIcon('filePanel')
.waitForElementVisible({
selector: '*[data-id="treeViewDivtreeViewItem.deps/npm/@openzeppelin/contracts-upgradeable@4.8.3/proxy/beacon/IBeaconUpgradeable.sol"]',
timeout: 120000,
})
.clickLaunchIcon('solidity')
.waitForElementPresent('select[id="compiledContracts"] option[value=MyToken]', 60000)
.clickLaunchIcon('udapp')
.click('select.udapp_contractNames')
.click('select.udapp_contractNames option[value=MyToken]')
.waitForElementPresent('[data-id="contractGUIDeployWithProxyLabel"]')
.waitForElementPresent('[data-id="contractGUIUpgradeImplementationLabel"]')
},
'Should show upgrade proxy option for child contract inheriting UUPS parent contract #group1': function (browser: NightwatchBrowser) {
browser
.addFile('myTokenV2.sol', sources[1]['myTokenV2.sol'])
.clickLaunchIcon('solidity')
.assert.visible('[data-id="compilerContainerCompileBtn"]')
.click('[data-id="compilerContainerCompileBtn"]')
.waitForElementPresent('select[id="compiledContracts"] option[value=MyTokenV2]', 60000)
.clickLaunchIcon('udapp')
.click('select.udapp_contractNames')
.click('select.udapp_contractNames option[value=MyTokenV2]')
.waitForElementPresent('[data-id="contractGUIDeployWithProxyLabel"]')
.waitForElementPresent('[data-id="contractGUIUpgradeImplementationLabel"]')
},
'Should deploy proxy without initialize parameters #group1': function (browser: NightwatchBrowser) {
browser
.openFile('myTokenV1.sol')
.clickLaunchIcon('solidity')
.assert.visible('[data-id="compilerContainerCompileBtn"]')
.click('[data-id="compilerContainerCompileBtn"]')
.waitForElementPresent('select[id="compiledContracts"] option[value=MyToken]', 60000)
.clickLaunchIcon('udapp')
.click('select.udapp_contractNames')
.click('select.udapp_contractNames option[value=MyToken]')
.verify.visible('[data-id="contractGUIDeployWithProxyLabel"]')
.waitForElementPresent('[data-id="contractGUIDeployWithProxyLabel"]')
.click('[data-id="contractGUIDeployWithProxyLabel"]')
.createContract('')
.waitForElementContainsText('[data-id="udappNotifyModalDialogModalTitle-react"]', 'Deploy Implementation & Proxy (ERC1967)')
.waitForElementVisible('[data-id="udappNotify-modal-footer-ok-react"]')
.click('[data-id="udappNotify-modal-footer-ok-react"]')
.waitForElementContainsText('[data-id="confirmProxyDeploymentModalDialogModalTitle-react"]', 'Confirm Deploy Proxy (ERC1967)')
.waitForElementVisible('[data-id="confirmProxyDeployment-modal-footer-ok-react"]')
.click('[data-id="confirmProxyDeployment-modal-footer-ok-react"]')
.waitForElementPresent('[data-id="universalDappUiTitleExpander0"]')
.waitForElementPresent('[data-id="universalDappUiTitleExpander1"]')
.waitForElementContainsText('*[data-id="terminalJournal"]', 'Deploying ERC1967 < 5.0.0 as proxy...', 60000)
},
'Should interact with deployed contract via ERC1967 (proxy) #group1': function (browser: NightwatchBrowser) {
browser
.getAddressAtPosition(1, (address) => {
firstProxyAddress = address
shortenedFirstAddress = address.slice(0, 5) + '...' + address.slice(address.length - 5, address.length)
})
.clickInstance(1)
.perform((done) => {
browser.testConstantFunction(firstProxyAddress, 'name - call', null, '0:\nstring: MyToken').perform(() => {
done()
})
})
.perform((done) => {
browser.testConstantFunction(firstProxyAddress, 'symbol - call', null, '0:\nstring: MTK').perform(() => {
done()
})
})
},
'Should deploy proxy with initialize parameters #group1': function (browser: NightwatchBrowser) {
browser
.waitForElementPresent('[data-id="deployAndRunClearInstances"]')
.click('[data-id="deployAndRunClearInstances"]')
.addFile('initializeProxy.sol', sources[2]['initializeProxy.sol'])
.clickLaunchIcon('solidity')
.assert.visible('[data-id="compilerContainerCompileBtn"]')
.click('[data-id="compilerContainerCompileBtn"]')
.waitForElementPresent('select[id="compiledContracts"] option[value=MyInitializedToken]', 60000)
.clickLaunchIcon('udapp')
.click('select.udapp_contractNames')
.click('select.udapp_contractNames option[value=MyInitializedToken]')
.waitForElementPresent('[data-id="contractGUIDeployWithProxyLabel"]')
.click('[data-id="contractGUIDeployWithProxyLabel"]')
.useXpath()
.waitForElementPresent('//*[@id="runTabView"]/div/div[2]/div[3]/div[1]/div/div[1]/div[4]/div/div[1]/input')
.waitForElementPresent('//*[@id="runTabView"]/div/div[2]/div[3]/div[1]/div/div[1]/div[4]/div/div[2]/input')
.setValue('//*[@id="runTabView"]/div/div[2]/div[3]/div[1]/div/div[1]/div[4]/div/div[1]/input', 'Remix')
.setValue('//*[@id="runTabView"]/div/div[2]/div[3]/div[1]/div/div[1]/div[4]/div/div[2]/input', "R")
.useCss()
.createContract('')
.waitForElementContainsText('[data-id="udappNotifyModalDialogModalTitle-react"]', 'Deploy Implementation & Proxy (ERC1967)')
.waitForElementVisible('[data-id="udappNotify-modal-footer-ok-react"]')
.click('[data-id="udappNotify-modal-footer-ok-react"]')
.waitForElementContainsText('[data-id="confirmProxyDeploymentModalDialogModalTitle-react"]', 'Confirm Deploy Proxy (ERC1967)')
.waitForElementVisible('[data-id="confirmProxyDeployment-modal-footer-ok-react"]')
.click('[data-id="confirmProxyDeployment-modal-footer-ok-react"]')
.waitForElementPresent('[data-id="universalDappUiTitleExpander0"]')
.waitForElementPresent('[data-id="universalDappUiTitleExpander1"]')
.waitForElementContainsText('*[data-id="terminalJournal"]', 'Deploying ERC1967 < 5.0.0 as proxy...', 60000)
},
'Should interact with initialized contract to verify parameters #group1': function (browser: NightwatchBrowser) {
browser
.getAddressAtPosition(1, (address) => {
lastProxyAddress = address
shortenedLastAddress = address.slice(0, 5) + '...' + address.slice(address.length - 5, address.length)
})
.clickInstance(1)
.perform((done) => {
browser.testConstantFunction(lastProxyAddress, 'name - call', null, '0:\nstring: Remix').perform(() => {
done()
})
})
.perform((done) => {
browser.testConstantFunction(lastProxyAddress, 'symbol - call', null, '0:\nstring: R').perform(() => {
done()
})
})
},
'Should upgrade contract by selecting a previously deployed proxy address from dropdown (MyTokenV1 to MyTokenV2) #group1': function (browser: NightwatchBrowser) {
browser
.click('*[data-id="terminalClearConsole"]')
.waitForElementPresent('[data-id="deployAndRunClearInstances"]')
.click('[data-id="deployAndRunClearInstances"]')
.openFile('myTokenV2.sol')
.clickLaunchIcon('solidity')
.assert.visible('[data-id="compilerContainerCompileBtn"]')
.click('[data-id="compilerContainerCompileBtn"]')
.waitForElementPresent('select[id="compiledContracts"] option[value=MyTokenV2]', 60000)
.clickLaunchIcon('udapp')
.click('select.udapp_contractNames')
.click('select.udapp_contractNames option[value=MyTokenV2]')
.waitForElementPresent('[data-id="contractGUIUpgradeImplementationLabel"]')
.click('[data-id="contractGUIUpgradeImplementationLabel"]')
.waitForElementPresent('[data-id="toggleProxyAddressDropdown"]')
.click('[data-id="toggleProxyAddressDropdown"]')
.waitForElementVisible('[data-id="proxy-dropdown-items"]')
.assert.textContains('[data-id="proxy-dropdown-items"]', shortenedFirstAddress)
.assert.textContains('[data-id="proxy-dropdown-items"]', shortenedLastAddress)
.click('[data-id="proxyAddress1"]')
.createContract('')
.waitForElementContainsText('[data-id="udappNotifyModalDialogModalTitle-react"]', 'Deploy Implementation & Update Proxy')
.waitForElementVisible('[data-id="udappNotify-modal-footer-ok-react"]')
.click('[data-id="udappNotify-modal-footer-ok-react"]')
.waitForElementContainsText('[data-id="confirmProxyDeploymentModalDialogModalTitle-react"]', 'Confirm Update Proxy (ERC1967)')
.waitForElementVisible('[data-id="confirmProxyDeployment-modal-footer-ok-react"]')
.click(
{
selector: '[data-id="confirmProxyDeployment-modal-footer-ok-react"]',
})
.waitForElementPresent('[data-id="universalDappUiTitleExpander0"]')
.waitForElementPresent('[data-id="universalDappUiTitleExpander1"]')
.waitForElementContainsText('*[data-id="terminalJournal"]', 'Using ERC1967 < 5.0.0 for the proxy upgrade..', 60000)
},
'Should interact with upgraded function in contract MyTokenV2 #group1': function (browser: NightwatchBrowser) {
browser
.clickInstance(1)
.perform((done) => {
browser.testConstantFunction(lastProxyAddress, 'version - call', null, '0:\nstring: MyTokenV2!').perform(() => {
done()
})
})
},
'Should upgrade contract by providing proxy address in input field (MyTokenV1 to MyTokenV2) #group1': function (browser: NightwatchBrowser) {
browser
.click('*[data-id="terminalClearConsole"]')
.waitForElementPresent('[data-id="deployAndRunClearInstances"]')
.click('[data-id="deployAndRunClearInstances"]')
.openFile('myTokenV2.sol')
.clickLaunchIcon('solidity')
.assert.visible('[data-id="compilerContainerCompileBtn"]')
.click('[data-id="compilerContainerCompileBtn"]')
.waitForElementPresent('select[id="compiledContracts"] option[value=MyTokenV2]', 60000)
.clickLaunchIcon('udapp')
.click('select.udapp_contractNames')
.click('select.udapp_contractNames option[value=MyTokenV2]')
.waitForElementPresent('[data-id="contractGUIUpgradeImplementationLabel"]')
.waitForElementPresent('[data-id="toggleProxyAddressDropdown"]')
.clearValue('[data-id="ERC1967AddressInput"]')
.setValue('[data-id="ERC1967AddressInput"]', firstProxyAddress)
.createContract('')
.waitForElementContainsText('[data-id="udappNotifyModalDialogModalTitle-react"]', 'Deploy Implementation & Update Proxy')
.waitForElementVisible('[data-id="udappNotify-modal-footer-ok-react"]')
.click('[data-id="udappNotify-modal-footer-ok-react"]')
.waitForElementContainsText('[data-id="confirmProxyDeploymentModalDialogModalTitle-react"]', 'Confirm Update Proxy (ERC1967)')
.waitForElementVisible('[data-id="confirmProxyDeployment-modal-footer-ok-react"]')
.click('[data-id="confirmProxyDeployment-modal-footer-ok-react"]')
.waitForElementPresent('[data-id="universalDappUiTitleExpander0"]')
.waitForElementPresent('[data-id="universalDappUiTitleExpander1"]')
.waitForElementContainsText('*[data-id="terminalJournal"]', 'Using ERC1967 < 5.0.0 for the proxy upgrade..', 60000)
},
'Should interact with upgraded contract through provided proxy address #group1': function (browser: NightwatchBrowser) {
browser
.clearConsole()
.clickInstance(1)
.perform((done) => {
browser.testConstantFunction(firstProxyAddress, 'version - call', null, '0:\nstring: MyTokenV2!').perform(() => {
done()
})
})
},
'Should debug the call': function(browser: NightwatchBrowser) {
browser
.debugTransaction(0)
.waitForElementVisible({
locateStrategy: 'xpath',
selector: '//*[@data-id="treeViewLivm trace step" and contains(.,"11")]',
timeout: 60000
})
.goToVMTraceStep(146)
.waitForElementContainsText('*[data-id="functionPanel"]', 'version()', 60000)
.end()
}
}
const sources = [
{
'myTokenV1.sol': {
content: `
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "@openzeppelin/contracts-upgradeable@4.8.3/token/ERC721/ERC721Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable@4.8.3/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable@4.8.3/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable@4.8.3/proxy/utils/UUPSUpgradeable.sol";
contract MyToken is Initializable, ERC721Upgradeable, OwnableUpgradeable, UUPSUpgradeable {
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
function initialize() initializer public {
__ERC721_init("MyToken", "MTK");
__Ownable_init();
__UUPSUpgradeable_init();
}
function _authorizeUpgrade(address newImplementation)
internal
onlyOwner
override
{}
}
`
}
}, {
'myTokenV2.sol': {
content: `
import "./myTokenV1.sol";
contract MyTokenV2 is MyToken {
function version () public view returns (string memory) {
return "MyTokenV2!";
}
}
`
}
}, {
'initializeProxy.sol': {
content: `
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "@openzeppelin/contracts-upgradeable@4.8.3/token/ERC721/ERC721Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable@4.8.3/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable@4.8.3/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable@4.8.3/proxy/utils/UUPSUpgradeable.sol";
contract MyInitializedToken is Initializable, ERC721Upgradeable, OwnableUpgradeable, UUPSUpgradeable {
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
function initialize(string memory tokenName, string memory tokenSymbol) initializer public {
__ERC721_init(tokenName, tokenSymbol);
__Ownable_init();
__UUPSUpgradeable_init();
}
function _authorizeUpgrade(address newImplementation)
internal
onlyOwner
override
{}
}
`
}
}
]

@ -91,6 +91,7 @@ module.exports = {
.click('[data-id="confirmProxyDeployment-modal-footer-ok-react"]')
.waitForElementPresent('[data-id="universalDappUiTitleExpander0"]')
.waitForElementPresent('[data-id="universalDappUiTitleExpander1"]')
.waitForElementContainsText('*[data-id="terminalJournal"]', 'Deploying ERC1967 >= 5.0.0 as proxy...')
},
'Should interact with deployed contract via ERC1967 (proxy) #group1': function (browser: NightwatchBrowser) {
@ -142,6 +143,7 @@ module.exports = {
.click('[data-id="confirmProxyDeployment-modal-footer-ok-react"]')
.waitForElementPresent('[data-id="universalDappUiTitleExpander0"]')
.waitForElementPresent('[data-id="universalDappUiTitleExpander1"]')
.waitForElementContainsText('*[data-id="terminalJournal"]', 'Deploying ERC1967 >= 5.0.0 as proxy...')
},
'Should interact with initialized contract to verify parameters #group1': function (browser: NightwatchBrowser) {
@ -165,6 +167,7 @@ module.exports = {
'Should upgrade contract by selecting a previously deployed proxy address from dropdown (MyTokenV1 to MyTokenV2) #group1': function (browser: NightwatchBrowser) {
browser
.click('*[data-id="terminalClearConsole"]')
.waitForElementPresent('[data-id="deployAndRunClearInstances"]')
.click('[data-id="deployAndRunClearInstances"]')
.openFile('myTokenV2.sol')
@ -196,6 +199,7 @@ module.exports = {
})
.waitForElementPresent('[data-id="universalDappUiTitleExpander0"]')
.waitForElementPresent('[data-id="universalDappUiTitleExpander1"]')
.waitForElementContainsText('*[data-id="terminalJournal"]', 'Using ERC1967 >= 5.0.0 for the proxy upgrade...')
},
'Should interact with upgraded function in contract MyTokenV2 #group1': function (browser: NightwatchBrowser) {
@ -210,6 +214,7 @@ module.exports = {
'Should upgrade contract by providing proxy address in input field (MyTokenV1 to MyTokenV2) #group1': function (browser: NightwatchBrowser) {
browser
.click('*[data-id="terminalClearConsole"]')
.waitForElementPresent('[data-id="deployAndRunClearInstances"]')
.click('[data-id="deployAndRunClearInstances"]')
.openFile('myTokenV2.sol')
@ -233,17 +238,30 @@ module.exports = {
.click('[data-id="confirmProxyDeployment-modal-footer-ok-react"]')
.waitForElementPresent('[data-id="universalDappUiTitleExpander0"]')
.waitForElementPresent('[data-id="universalDappUiTitleExpander1"]')
.waitForElementContainsText('*[data-id="terminalJournal"]', 'Using ERC1967 >= 5.0.0 for the proxy upgrade...')
},
'Should interact with upgraded contract through provided proxy address #group1': function (browser: NightwatchBrowser) {
browser
.clearConsole()
.clickInstance(1)
.perform((done) => {
browser.testConstantFunction(firstProxyAddress, 'version - call', null, '0:\nstring: MyTokenV2!').perform(() => {
done()
})
})
.end()
},
'Should debug the call': function(browser: NightwatchBrowser) {
browser
.debugTransaction(0)
.waitForElementVisible({
locateStrategy: 'xpath',
selector: '//*[@data-id="treeViewLivm trace step" and contains(.,"7")]',
timeout: 60000
})
.goToVMTraceStep(129)
.waitForElementContainsText('*[data-id="functionPanel"]', 'version()', 60000)
.end()
}
}

@ -4,7 +4,7 @@ import { util } from '@remix-project/remix-lib'
import { toChecksumAddress } from '@ethereumjs/util'
import { fetchContractFromEtherscan } from './helpers/fetch-etherscan'
import { fetchContractFromSourcify } from './helpers/fetch-sourcify'
import { UUPSDeployedByteCode, UUPSCompilerVersion, UUPSOptimize, UUPSRuns, UUPSEvmVersion, UUPSLanguage } from './constants/uups'
import { UUPSDeployedByteCode, UUPSCompilerVersion, UUPSOptimize, UUPSRuns, UUPSEvmVersion, UUPSLanguage, UUPSDeployedByteCodeV5, UUPSCompilerVersionV5 } from './constants/uups'
const profile = {
name: 'fetchAndCompile',
@ -84,6 +84,34 @@ export class FetchAndCompile extends Plugin {
return compData
}
if (codeAtAddress === '0x' + UUPSDeployedByteCodeV5) { // proxy
const settings = {
version: UUPSCompilerVersionV5,
language: UUPSLanguage,
evmVersion: UUPSEvmVersion,
optimize: UUPSOptimize,
runs: UUPSRuns
}
const proxyUrl = 'https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.0/contracts/proxy/ERC1967/ERC1967Proxy.sol'
const compilationTargets = {
'proxy.sol': { content: `import "${proxyUrl}";` }
}
const compData = await compile(
compilationTargets,
settings,
async (url, cb) => {
// we first try to resolve the content from the compilation target using a more appropiate path
const path = `${targetPath}/${url}`
if (compilationTargets[path] && compilationTargets[path].content) {
return cb(null, compilationTargets[path].content)
} else {
await this.call('contentImport', 'resolveAndSave', url).then((result) => cb(null, result)).catch((error) => cb(error.message))
}
})
await this.call('compilerArtefacts', 'addResolvedContract', contractAddress, compData)
return compData
}
// sometimes when doing an internal call, the only available artifact is the Solidity interface.
// resolving addresses of internal call would allow to step over the source code, even if the declaration was made using an Interface.

File diff suppressed because one or more lines are too long

@ -1,6 +1,6 @@
import { Plugin } from '@remixproject/engine'
import { ContractAST, ContractSources, DeployOptions } from '../types/contract'
import { EnableProxyURLParam, EnableUpgradeURLParam, GETUUPSProxyVersionAbi, UUPS, UUPSABI, UUPSBytecode, UUPSBytecodeV5, UUPSfunAbi, UUPSupgradeAbi, UUPSupgradeToAndCallAbi } from './constants/uups'
import { EnableProxyURLParam, EnableUpgradeURLParam, GETUUPSProxyVersionAbi, UUPS, UUPSABI, UUPSBytecode, UUPSBytecodeV5, UUPSfunAbi, UUPSfunAbiV5, UUPSupgradeAbi, UUPSupgradeToAndCallAbi } from './constants/uups'
import * as remixLib from '@remix-project/remix-lib'
import * as semver from 'semver'
const txFormat = remixLib.execution.txFormat
@ -37,7 +37,7 @@ export class OpenZeppelinProxy extends Plugin {
const ast = data.sources[file].ast
if (this.kind === 'UUPS') {
const options = await (this.getUUPSContractOptions(contracts, ast, file))
const options = await this.getUUPSContractOptions(contracts, ast, file)
return options
}
@ -88,6 +88,7 @@ export class OpenZeppelinProxy extends Plugin {
}
async deployUUPSProxy(implAddress: string, _data: string, implementationContractObject): Promise<void> {
const args = [implAddress, _data]
const constructorData = await this.blockchain.getEncodedParams(args, UUPSfunAbi)
const proxyName = 'ERC1967Proxy'
@ -95,12 +96,22 @@ export class OpenZeppelinProxy extends Plugin {
contractABI: UUPSABI,
contractByteCode: UUPSBytecodeV5,
contractName: proxyName,
funAbi: UUPSfunAbi,
funAbi: UUPSfunAbiV5,
funArgs: args,
linkReferences: {},
dataHex: UUPSBytecodeV5 + constructorData.replace('0x', '')
dataHex: UUPSBytecodeV5 + constructorData.replace('0x', ''),
}
// check if implementation contract has a function called UPGRADE_INTERFACE_VERSION
// if it hasn't then we use the old bytecode pre 5.0.0
const hasUpgradeVersionCall = implementationContractObject.abi.find((abi) => abi.name === 'UPGRADE_INTERFACE_VERSION')
if (!hasUpgradeVersionCall) {
data.contractByteCode = UUPSBytecode
data.dataHex = UUPSBytecode + constructorData.replace('0x', '')
data.funAbi = UUPSfunAbi
this.call('terminal', 'logHtml', `Deploying ERC1967 < 5.0.0 as proxy...`)
}else{
this.call('terminal', 'logHtml', `Deploying ERC1967 >= 5.0.0 as proxy...`)
}
// re-use implementation contract's ABI for UI display in udapp and change name to proxy name.
implementationContractObject.contractName = implementationContractObject.name
implementationContractObject.implementationAddress = implAddress
@ -118,51 +129,58 @@ export class OpenZeppelinProxy extends Plugin {
dataHex: dataHex,
funAbi: GETUUPSProxyVersionAbi,
contractName: proxyName,
funArgs: []
funArgs: [],
},
useCall: true
useCall: true,
}
// re-use implementation contract's ABI for UI display in udapp and change name to proxy name.
newImplementationContractObject.contractName = newImplementationContractObject.name
newImplementationContractObject.implementationAddress = newImplAddress
newImplementationContractObject.name = proxyName
await this.blockchain.runTx(args, () => { }, () => { }, () => { }, async (error, txResult, _address, returnValue) => {
if (error) {
throw new Error(`error: ${error.message ? error.message : error}`)
}
const response = txFormat.decodeResponse(returnValue, GETUUPSProxyVersionAbi)
const version = response[0].split('string: ')[1]
// check if version is >= 5.0.0
if (semver.gte(version, '5.0.0')) {
const fnData = await this.blockchain.getEncodedFunctionHex([newImplAddress, "0x"], UUPSupgradeToAndCallAbi)
const data = {
contractABI: UUPSABI,
contractName: proxyName,
funAbi: UUPSupgradeToAndCallAbi,
funArgs: [newImplAddress, "0x"],
linkReferences: {},
dataHex: fnData.replace('0x', '')
}
this.blockchain.upgradeProxy(proxyAddress, newImplAddress, data, newImplementationContractObject)
} else {
const fnData = await this.blockchain.getEncodedFunctionHex([newImplAddress], UUPSupgradeAbi)
const proxyName = 'ERC1967Proxy'
const data = {
contractABI: UUPSABI,
contractName: proxyName,
funAbi: UUPSupgradeAbi,
funArgs: [newImplAddress],
linkReferences: {},
dataHex: fnData.replace('0x', '')
await this.blockchain.runTx(
args,
() => {},
() => {},
() => {},
async (error, txResult, _address, returnValue) => {
let version = '4.8.3'
if (error) {
console.log(`error: ${error.message ? error.message : error}`)
} else {
const response = txFormat.decodeResponse(returnValue, GETUUPSProxyVersionAbi)
version = response[0].split('string: ')[1]
// check if version is >= 5.0.0
}
this.blockchain.upgradeProxy(proxyAddress, newImplAddress, data, newImplementationContractObject)
}
})
if (semver.gte(version, '5.0.0')) {
const fnData = await this.blockchain.getEncodedFunctionHex([newImplAddress, '0x'], UUPSupgradeToAndCallAbi)
const data = {
contractABI: UUPSABI,
contractName: proxyName,
funAbi: UUPSupgradeToAndCallAbi,
funArgs: [newImplAddress, '0x'],
linkReferences: {},
dataHex: fnData.replace('0x', ''),
}
this.call('terminal', 'logHtml', `Using ERC1967 >= 5.0.0 for the proxy upgrade...`)
this.blockchain.upgradeProxy(proxyAddress, newImplAddress, data, newImplementationContractObject)
} else {
const fnData = await this.blockchain.getEncodedFunctionHex([newImplAddress], UUPSupgradeAbi)
const proxyName = 'ERC1967Proxy'
const data = {
contractABI: UUPSABI,
contractName: proxyName,
funAbi: UUPSupgradeAbi,
funArgs: [newImplAddress],
linkReferences: {},
dataHex: fnData.replace('0x', ''),
}
this.call('terminal', 'logHtml', `Using ERC1967 < 5.0.0 for the proxy upgrade...`)
this.blockchain.upgradeProxy(proxyAddress, newImplAddress, data, newImplementationContractObject)
}
}
)
}
}
}

Loading…
Cancel
Save