-
Notifications
You must be signed in to change notification settings - Fork 28
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add comments to the upgradeable proxy example
- Loading branch information
Showing
8 changed files
with
87 additions
and
73 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity ^0.8.9; | ||
|
||
// A contrived example of a contract that can be upgraded | ||
contract Demo { | ||
function version() public pure returns (string memory) { | ||
return "1.0.0"; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity ^0.8.9; | ||
|
||
// A contrived example of a contract that can be upgraded | ||
contract DemoV2 { | ||
function version() public pure returns (string memory) { | ||
return "2.0.0"; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,7 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity ^0.8.9; | ||
|
||
// We import these here to force Hardhat to compile them. | ||
// This ensures that their artifacts are available for Hardhat Ignition to use. | ||
import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; | ||
import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,48 +1,85 @@ | ||
// ./ignition/LockModule.js | ||
const { buildModule } = require("@nomicfoundation/hardhat-ignition/modules"); | ||
|
||
/** | ||
* This is the first module that will be run. It deploys the proxy and the | ||
* proxy admin, and returns them so that they can be used by other modules. | ||
*/ | ||
const proxyModule = buildModule("ProxyModule", (m) => { | ||
// This address is the owner of the ProxyAdmin contract, | ||
// so it will be the only account that can upgrade the proxy when needed. | ||
const proxyAdminOwner = m.getAccount(0); | ||
|
||
const box = m.contract("Box"); | ||
// This is our contract that will be proxied. | ||
// We will upgrade this contract with a new version later. | ||
const demo = m.contract("Demo"); | ||
|
||
// The TransparentUpgradeableProxy contract creates the ProxyAdmin within its constructor. | ||
// To read more about how this proxy is implemented, you can view the source code and comments here: | ||
// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.1/contracts/proxy/transparent/TransparentUpgradeableProxy.sol | ||
const proxy = m.contract("TransparentUpgradeableProxy", [ | ||
box, | ||
demo, | ||
proxyAdminOwner, | ||
"0x", | ||
]); | ||
|
||
// We need to get the address of the ProxyAdmin contrac that was created by the TransparentUpgradeableProxy | ||
// so that we can use it to upgrade the proxy later. | ||
const proxyAdminAddress = m.readEventArgument( | ||
proxy, | ||
"AdminChanged", | ||
"newAdmin" | ||
); | ||
|
||
// Here we use m.contractAt(...) to create a contract instance for the ProxyAdmin that we can interact with. | ||
const proxyAdmin = m.contractAt("ProxyAdmin", proxyAdminAddress); | ||
|
||
// Return the proxy and proxy admin so that they can be used by other modules. | ||
return { proxyAdmin, proxy }; | ||
}); | ||
|
||
/** | ||
* This is the second module that will be run. It upgrades the proxy to a new | ||
* version of the Demo contract. | ||
*/ | ||
const upgradeModule = buildModule("UpgradeModule", (m) => { | ||
// Make sure we're account that owns the ProxyAdmin contract. | ||
const proxyAdminOwner = m.getAccount(0); | ||
|
||
// Get the proxy and proxy admin from the previous module. | ||
const { proxyAdmin, proxy } = m.useModule(proxyModule); | ||
|
||
const upgradedBox = m.contract("UpgradedBox"); | ||
// This is the new version of the Demo contract that we want to upgrade to. | ||
const demoV2 = m.contract("DemoV2"); | ||
|
||
m.call(proxyAdmin, "upgradeAndCall", [proxy, upgradedBox, "0x"], { | ||
// Upgrade the proxy to the new version of the Demo contract. | ||
// This function also accepts a data parameter, which can be used to call a function, | ||
// but we don't need it here so we pass an empty hex string ("0x"). | ||
m.call(proxyAdmin, "upgradeAndCall", [proxy, demoV2, "0x"], { | ||
from: proxyAdminOwner, | ||
}); | ||
|
||
// Return the proxy and proxy admin so that they can be used by other modules. | ||
return { proxyAdmin, proxy }; | ||
}); | ||
|
||
/** | ||
* This is the third and final module that will be run. | ||
* | ||
* It takes the proxy from the previous module and uses it to create a local contract instance | ||
* for the DemoV2 contract. This allows us to interact with the DemoV2 contract via the proxy. | ||
*/ | ||
const interactableModule = buildModule("InteractableModule", (m) => { | ||
// Get the proxy from the previous module. | ||
const { proxy } = m.useModule(upgradeModule); | ||
|
||
const box = m.contractAt("UpgradedBox", proxy); | ||
// Create a local contract instance for the DemoV2 contract. | ||
// This line tells Hardhat Ignition to treat the contract at the proxy address as an DemoV2 contract. | ||
// This allows us to call functions on the DemoV2 contract via the proxy. | ||
const demo = m.contractAt("DemoV2", proxy); | ||
|
||
return { box }; | ||
// Return the contract instance so that it can be used by other modules or in tests. | ||
return { demo }; | ||
}); | ||
|
||
module.exports = interactableModule; |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
const { | ||
loadFixture, | ||
} = require("@nomicfoundation/hardhat-toolbox/network-helpers"); | ||
const { expect } = require("chai"); | ||
|
||
const ProxyModule = require("../ignition/modules/ProxyModule"); | ||
|
||
describe("Demo Proxy", function () { | ||
async function deployFixture() { | ||
const [owner, otherAccount] = await ethers.getSigners(); | ||
|
||
const { demo } = await ignition.deploy(ProxyModule); | ||
|
||
return { demo, owner, otherAccount }; | ||
} | ||
|
||
describe("Upgrading", function () { | ||
it("Should have upgraded the proxy to DemoV2", async function () { | ||
const { demo, otherAccount } = await loadFixture(deployFixture); | ||
|
||
expect(await demo.connect(otherAccount).version()).to.equal("2.0.0"); | ||
}); | ||
}); | ||
}); |