ΠΡΠΈΠ²Π΅Ρ,
Π― ΠΎΠ±Π½Π°ΡΡΠΆΠΈΠ», ΡΡΠΎ ΡΠΎΠ·Π΄Π°ΡΠ΅Π»Ρ ΡΡΠΎΠ³ΠΎ ΠΏΠ°ΠΊΠ΅ΡΠ° ΡΠΆΠ΅ ΡΠ°ΡΡΠΌΠ°ΡΡΠΈΠ²Π°Π» Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡΡ ΠΈΠ½ΡΠ΅Π³ΡΠ°ΡΠΈΠΈ hardhat-deploy
Ρ ΠΏΠ»Π°Π³ΠΈΠ½ΠΎΠΌ open zeppelin upgrades Π΄Π»Ρ ΠΊΠ°ΡΠΊΠΈ, Π½ΠΎ ΡΠ°ΠΊΠΆΠ΅ Ρ
ΠΎΡΠ΅Π» Π±Ρ ΠΏΠΎΠ²ΡΠΎΡΠΈΡΡ, ΡΡΠΎ ΡΡΠΎ Π΄ΠΎΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ Π±ΡΠ»ΠΎ Π±Ρ ΠΎΡΠ»ΠΈΡΠ½ΡΠΌ.
Π Π½Π°ΡΡΠΎΡΡΠ΅Π΅ Π²ΡΠ΅ΠΌΡ ΠΌΡ ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠ΅ΠΌ ΠΏΠ»Π°Π³ΠΈΠ½ oz upgrades, ΠΈ Ρ ΠΎΡΡ ΠΌΡ Ρ ΠΎΡΠ΅Π»ΠΈ Π±Ρ ΡΠ°ΠΊΠΆΠ΅ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡ ΠΏΠ»Π°Π³ΠΈΠ½ hardhat-deploy, ΠΌΡ Π½Π΅ Ρ ΠΎΡΠΈΠΌ ΠΆΠ΅ΡΡΠ²ΠΎΠ²Π°ΡΡ ΡΠ΅ΠΌ, ΡΡΠΎ ΠΏΡΠ΅Π΄Π»Π°Π³Π°Π΅Ρ Π½Π°ΠΌ ΠΏΠ»Π°Π³ΠΈΠ½ oz.
ΠΡΠΈΠ²Π΅Ρ @Remscar , ΡΡΠΎ ΠΎΠΏΡΠ΅Π΄Π΅Π»Π΅Π½Π½ΠΎ Π±ΡΠ»ΠΎ Π±Ρ Π·Π΄ΠΎΡΠΎΠ²ΠΎ.
Π’Π΅ΠΌ Π²ΡΠ΅ΠΌΠ΅Π½Π΅ΠΌ Ρ ΡΠ°Π·ΡΠ°Π±ΠΎΡΠ°Π» Π΄Π»Ρ ΡΡΠΎΠ³ΠΎ ΠΎΠ±Ρ
ΠΎΠ΄Π½ΠΎΠΉ ΠΏΠ»Π°Π³ΠΈΠ½, ΡΠΊΠΎΠΏΠΈΡΠΎΠ²Π°Π² Π½Π΅ΠΊΠΎΡΠΎΡΡΠΉ ΠΊΠΎΠ΄ ΠΈΠ· Π±ΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΠΈ @openzeppelin/upgrade-core.
ΠΡΠΎ Π½Π΅ΠΌΠ½ΠΎΠ³ΠΎ ΡΡΠΎΠ΄Π»ΠΈΠ²ΠΎ, Π½ΠΎ ΠΎΠ½ΠΎ ΠΌΠΎΠΆΠ΅Ρ ΡΠ°Π±ΠΎΡΠ°ΡΡ (ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠΉΡΠ΅ Π΅Π³ΠΎ Π½Π° ΡΠ²ΠΎΠΉ ΡΡΡΠ°Ρ
ΠΈ ΡΠΈΡΠΊ).
ΠΠΌΠΏΠΎΡΡΠΈΡΡΠΉΡΠ΅ ΡΡΠΎΡ ΡΠ°ΠΉΠ» (ΠΏΠΎΡΠ»Π΅ ΠΈΠΌΠΏΠΎΡΡΠ° hardhat-deploy) Π² 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,
}
})
ΠΡΠΈΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ :
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
}
)
}
Π’Π΅ΠΏΠ΅ΡΡ Π΅ΡΡΡ Π²ΡΡΡΠΎΠ΅Π½Π½ΡΠΉ ΡΠΏΠΎΡΠΎΠ± ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΡ Openzeppelin Transparent Proxy. Ρ Π·Π°ΠΊΡΠΎΡ ΡΡΠΎΡ Π²ΠΎΠΏΡΠΎΡ
Π‘Π°ΠΌΡΠΉ ΠΏΠΎΠ»Π΅Π·Π½ΡΠΉ ΠΊΠΎΠΌΠΌΠ΅Π½ΡΠ°ΡΠΈΠΉ
ΠΡΠΈΠ²Π΅Ρ @Remscar , ΡΡΠΎ ΠΎΠΏΡΠ΅Π΄Π΅Π»Π΅Π½Π½ΠΎ Π±ΡΠ»ΠΎ Π±Ρ Π·Π΄ΠΎΡΠΎΠ²ΠΎ.
Π’Π΅ΠΌ Π²ΡΠ΅ΠΌΠ΅Π½Π΅ΠΌ Ρ ΡΠ°Π·ΡΠ°Π±ΠΎΡΠ°Π» Π΄Π»Ρ ΡΡΠΎΠ³ΠΎ ΠΎΠ±Ρ ΠΎΠ΄Π½ΠΎΠΉ ΠΏΠ»Π°Π³ΠΈΠ½, ΡΠΊΠΎΠΏΠΈΡΠΎΠ²Π°Π² Π½Π΅ΠΊΠΎΡΠΎΡΡΠΉ ΠΊΠΎΠ΄ ΠΈΠ· Π±ΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΠΈ @openzeppelin/upgrade-core.
ΠΡΠΎ Π½Π΅ΠΌΠ½ΠΎΠ³ΠΎ ΡΡΠΎΠ΄Π»ΠΈΠ²ΠΎ, Π½ΠΎ ΠΎΠ½ΠΎ ΠΌΠΎΠΆΠ΅Ρ ΡΠ°Π±ΠΎΡΠ°ΡΡ (ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠΉΡΠ΅ Π΅Π³ΠΎ Π½Π° ΡΠ²ΠΎΠΉ ΡΡΡΠ°Ρ ΠΈ ΡΠΈΡΠΊ).
ΠΠΌΠΏΠΎΡΡΠΈΡΡΠΉΡΠ΅ ΡΡΠΎΡ ΡΠ°ΠΉΠ» (ΠΏΠΎΡΠ»Π΅ ΠΈΠΌΠΏΠΎΡΡΠ° hardhat-deploy) Π² hardhat-config.js:
ΠΡΠΈΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ :