Skip to content

Commit 3bd80a0

Browse files
committed
add encodeFunctionCall to upgradeable proxy guide
1 parent 99c738b commit 3bd80a0

File tree

1 file changed

+33
-5
lines changed

1 file changed

+33
-5
lines changed

docs/src/content/ignition/docs/guides/upgradeable-proxies.md

+33-5
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,19 @@ pragma solidity ^0.8.9;
3838
3939
// A contrived example of a contract that can be upgraded
4040
contract DemoV2 {
41+
string public name;
42+
4143
function version() public pure returns (string memory) {
4244
return "2.0.0";
4345
}
46+
47+
function setName(string memory _name) public {
48+
name = _name;
49+
}
4450
}
4551
```
4652

47-
This contract is identical to the first one, except that it returns an updated version string.
53+
In addition to updating the version string, this contract also adds a `name` state variable and a `setName` function that allows us to set the value of `name`. We'll use this function later when we upgrade our proxy.
4854

4955
Finally, we'll create a file called `Proxies.sol` to import our proxy contracts. This file will look a little different than the others:
5056

@@ -184,7 +190,7 @@ module.exports = demoModule;
184190

185191
::::
186192

187-
### Part 3: Upgrading our proxy
193+
### Part 3: Upgrading our proxy with an initialization function
188194

189195
Next it's time to upgrade our proxy to a new version. To do this, we'll create a new file within our `ignition/modules` directory called `UpgradeModule.js` (or `UpgradeModule.ts` if you're using TypeScript). Inside this file, we'll again break up our module into two parts. To start, we'll write our `UpgradeModule`:
190196

@@ -196,7 +202,11 @@ const upgradeModule = buildModule("UpgradeModule", (m) => {
196202

197203
const demoV2 = m.contract("DemoV2");
198204

199-
m.call(proxyAdmin, "upgradeAndCall", [proxy, demoV2, "0x"], {
205+
const encodedFunctionCall = m.encodeFunctionCall(demoV2, "setName", [
206+
"Example Name",
207+
]);
208+
209+
m.call(proxyAdmin, "upgradeAndCall", [proxy, demoV2, encodedFunctionCall], {
200210
from: proxyAdminOwner,
201211
});
202212

@@ -210,7 +220,9 @@ Next, we use the `m.useModule(...)` method to get the `ProxyAdmin` and proxy con
210220

211221
Then, we deploy our `DemoV2` contract. This will be the contract that we'll upgrade our proxy to.
212222

213-
Finally, we call the `upgradeAndCall` method on the `ProxyAdmin` contract. This method takes three arguments: the proxy contract, the new implementation contract, and a data parameter that can be used to call an additional function. We don't need it right now, so we'll leave it blank by setting it to an empty hex string (`"0x"`). We also provide the `from` option to ensure that the upgrade is called from the owner of the `ProxyAdmin` contract.
223+
Next, we encode a call to the `setName` function in the `DemoV2` contract. This function takes a single argument, a string, which we'll set to `"Example Name"`. This encoded function call will be used to call the `setName` function on the `DemoV2` contract when we upgrade the proxy.
224+
225+
Finally, we call the `upgradeAndCall` method on the `ProxyAdmin` contract. This method takes three arguments: the proxy contract, the new implementation contract, and a data parameter that can be used to call an additional function on the target contract. In this case, we're calling the `setName` function on the `DemoV2` contract with the encoded function call we created earlier. We also provide the `from` option to ensure that the upgrade is called from the owner of the `ProxyAdmin` contract.
214226

215227
Lastly, we again return the `ProxyAdmin` and proxy contracts so that we can use them in our next module.
216228

@@ -289,6 +301,14 @@ describe("Demo Proxy", function () {
289301

290302
expect(await demo.connect(otherAccount).version()).to.equal("2.0.0");
291303
});
304+
305+
it("Should have set the name during upgrade", async function () {
306+
const [owner, otherAccount] = await ethers.getSigners();
307+
308+
const { demo } = await ignition.deploy(UpgradeModule);
309+
310+
expect(await demo.connect(otherAccount).name()).to.equal("Example Name");
311+
});
292312
});
293313
});
294314
```
@@ -322,6 +342,14 @@ describe("Demo Proxy", function () {
322342

323343
expect(await demo.connect(otherAccount).version()).to.equal("2.0.0");
324344
});
345+
346+
it("Should have set the name during upgrade", async function () {
347+
const [owner, otherAccount] = await ethers.getSigners();
348+
349+
const { demo } = await ignition.deploy(UpgradeModule);
350+
351+
expect(await demo.connect(otherAccount).name()).to.equal("Example Name");
352+
});
325353
});
326354
});
327355
```
@@ -330,7 +358,7 @@ describe("Demo Proxy", function () {
330358

331359
::::
332360

333-
Here we use Hardhat Ignition to deploy our imported modules. First, we deploy our base `ProxyModule` that returns the first version of our `Demo` contract and test it to ensure the proxy worked and retrieves the appropriate version string. Then, we deploy our `UpgradeModule` that returns the second version of our `Demo` contract and test it to ensure the proxy now returns the updated version string.
361+
Here we use Hardhat Ignition to deploy our imported modules. First, we deploy our base `ProxyModule` that returns the first version of our `Demo` contract and test it to ensure the proxy worked and retrieves the appropriate version string. Then, we deploy our `UpgradeModule` that returns the second version of our `Demo` contract and test it to ensure the proxy now returns the updated version string. We also test that our initialization function was called and set the `name` state variable to `"Example Name"`.
334362

335363
## Further reading
336364

0 commit comments

Comments
 (0)