Bonjour,
J'ai découvert que le créateur de ce package avait déjà envisagé d'intégrer hardhat-deploy
avec le plug-in de mise à niveau open zeppelin pour casque, mais aimerait également faire écho au fait que cet ajout serait formidable.
Actuellement, nous utilisons le plugin oz upgrades et bien que nous aimerions également utiliser le plugin hardhat-deploy, nous ne voulons pas sacrifier les choses que le plugin oz nous offre.
Bonjour @Remscar , ce serait vraiment génial.
Pendant ce temps, j'ai développé un plugin "de contournement" pour le faire, j'ai copié du code de la bibliothèque @openzeppelin/upgrade-core.
C'est un peu moche mais ça peut faire le travail (utilisez-le à vos risques et périls).
Importez ce fichier ( après avoir importé hardhat-deploy ) dans le hardhat-config.js :
const { extendEnvironment } = require("hardhat/config")
const AdminUpgradeabilityProxy = require("@openzeppelin/upgrades-core/artifacts/contracts/proxy/AdminUpgradeabilityProxy.sol/AdminUpgradeabilityProxy.json")
const ProxyAdmin = require("@openzeppelin/upgrades-core/artifacts/contracts/proxy/ProxyAdmin.sol/ProxyAdmin.json")
const { assertUpgradeSafe, getVersion, getUnlinkedBytecode } = require("@openzeppelin/upgrades-core")
const { readValidations } = require("@openzeppelin/hardhat-upgrades/dist/validations")
const getSigner = async address => {
const signers = await hre.ethers.getSigners()
return signers.find(signer => signer.address === address)
}
const getInitializerData = (ImplFactory, args = [], initializer) => {
if (initializer === false) {
return "0x"
}
const allowNoInitialization = initializer === undefined && args.length === 0
initializer = initializer ?? "initialize"
try {
const fragment = ImplFactory.interface.getFunction(initializer)
return ImplFactory.interface.encodeFunctionData(fragment, args)
} catch (e) {
if (e instanceof Error) {
if (allowNoInitialization && e.message.includes("no matching function")) {
return "0x"
}
}
throw e
}
}
const deployProxyAdmin = async (owner) => {
const { deployments } = hre
const { deploy } = deployments
return await deploy("ProxyAdmin", {
contract: ProxyAdmin,
from: owner,
log: true,
})
}
const deployOrUpgrade = async (firstImplName, opts, { initializer, postUpgrade, upgrades }) => {
const { deployments } = hre
const { deploy } = deployments
let proxyAdmin
try {
proxyAdmin = await deployments.get("ProxyAdmin")
} catch (error) {
proxyAdmin = await deployProxyAdmin(opts.from)
}
const proxyName = `${firstImplName}Proxy`
const firstImpl = await deploy(firstImplName, opts)
const initData = getInitializerData(
await ethers.getContractFactory(firstImplName),
initializer && initializer.args ? initializer.args : [],
initializer ? initializer.method : false
)
const proxy = await deploy(proxyName, {
contract: AdminUpgradeabilityProxy,
from: opts.from,
log: true,
args: [firstImpl.address, proxyAdmin.address, initData],
})
if (upgrades && upgrades.length > 0) {
let previousImplName, newImplName
if (upgrades.length === 1) {
previousImplName = firstImplName
newImplName = upgrades[0]
} else {
newImplName = upgrades.pop()
previousImplName = upgrades.pop()
for (oldUpgrade in upgrades) {
// unsure previous upgrades exists
await deployments.get(upgrades[oldUpgrade])
}
}
if (previousImplName === newImplName) throw new Error("Same implementation, can't upgrade.")
const newImplFactory = await ethers.getContractFactory(newImplName)
const validations = await readValidations(hre)
const unlinkedBytecode = getUnlinkedBytecode(validations, newImplFactory.bytecode)
const version = getVersion(unlinkedBytecode, newImplFactory.bytecode)
assertUpgradeSafe(validations, version, {
unsafeAllowCustomTypes: false,
unsafeAllowLinkedLibraries: false,
})
const signer = await getSigner(opts.from)
const proxyAdminContract = await ethers.getContractAt(proxyAdmin.abi, proxyAdmin.address, signer)
const previousImpl = await deployments.get(previousImplName)
const actualImpl = await proxyAdminContract.getProxyImplementation(proxy.address)
const newImpl = await deploy(newImplName, {
from: opts.from,
log: true,
})
if (newImpl.newlyDeployed)
if (actualImpl == previousImpl.address) {
console.log(`Upgrading from ${previousImplName} to ${newImplName}`)
if (postUpgrade && postUpgrade.method && postUpgrade.args) {
const upgradeData = getInitializerData(await ethers.getContractFactory(newImplName), postUpgrade.args, postUpgrade.method)
await proxyAdminContract.upgradeAndCall(proxy.address, newImpl.address, upgradeData)
} else await proxyAdminContract.upgrade(proxy.address, newImpl.address)
} else throw new Error(`Proxy is actually pointing on: ${actualImpl}`)
}
return proxy
}
extendEnvironment(hre => {
hre.myPlugin = {
deployOrUpgrade,
}
})
Utilisation :
module.exports = async ({ getNamedAccounts, myPlugin }) => {
const { deployer } = await getNamedAccounts()
// This will deploy the "Contract" with a proxy and a proxyAdmin if it doesn't exist.
const proxy = await myPlugin.deployOrUpgrade(
"Contract",
{ from: deployer, log: true },
{
initializer: { method: "initialize", args: [] },
// bellow attributes for upgrading
postUpgrade: { method: "postUpgrade", args: [] }, // method to exec after upgrade
upgrades: ["ContractV2", "ContractV3"], // you should keep the list of upgrades and add the new one at the last
}
)
}
Il existe maintenant un moyen intégré d'utiliser Openzeppelin Transparent Proxy. je ferme ce sujet
Commentaire le plus utile
Bonjour @Remscar , ce serait vraiment génial.
Pendant ce temps, j'ai développé un plugin "de contournement" pour le faire, j'ai copié du code de la bibliothèque @openzeppelin/upgrade-core.
C'est un peu moche mais ça peut faire le travail (utilisez-le à vos risques et périls).
Importez ce fichier ( après avoir importé hardhat-deploy ) dans le hardhat-config.js :
Utilisation :