This repository has been archived by the owner on Apr 27, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 45
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Closes #167 This PR introduces minor changes to the `AllowListAuthenticator` making it upgradable and includes tests verifying upgradability. In particular: - removing `customInitiallyOwnable` as it is no longer used: Not yet sure how this will affect the `deployments` directory which still includes it. - Updating authenticator deployment script to deploy as proxy. - rename authenticator `owner` to `manager` because of name collision with proxy owner - introduce proxy.ts with helper methods to fetch implementation and owner address. - Include two unit tests: one verifying that upgrade is possible and the other to ensure preservation of storage. Note that the unit tests involving Authenticator's non-upgrade related functionality do not use the proxy deployment as specified in the migration scripts, so that manager must be set immediately after deployment. We had originally planned/hoped to use the `hardhat-upgrades` plugin and opened the following two PRs to `openzeppelin-upgrades`, but this plugin turned out to be unnecessary. - Custom Deployments: OpenZeppelin/openzeppelin-upgrades#273 - Manual Safety Override: OpenZeppelin/openzeppelin-upgrades#280 ### Test Plan Old + new unit and e2e tests.
- Loading branch information
Showing
12 changed files
with
178 additions
and
48 deletions.
There are no files selected for viewing
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
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,10 @@ | ||
// SPDX-License-Identifier: LGPL-3.0-or-later | ||
pragma solidity ^0.7.6; | ||
|
||
import "../GPv2AllowListAuthentication.sol"; | ||
|
||
contract GPv2AllowListAuthenticationV2 is GPv2AllowListAuthentication { | ||
function newMethod() external pure returns (uint256) { | ||
return 1337; | ||
} | ||
} |
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
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
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
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,45 @@ | ||
// defined in https://eips.ethereum.org/EIPS/eip-1967 | ||
|
||
import { BigNumber } from "ethers"; | ||
import { ethers } from "hardhat"; | ||
|
||
// The proxy contract used by hardhat-deploy implements EIP-1967 (Standard Proxy | ||
// Storage Slot). See <https://eips.ethereum.org/EIPS/eip-1967>. | ||
function slot(string: string) { | ||
return ethers.utils.defaultAbiCoder.encode( | ||
["bytes32"], | ||
[BigNumber.from(ethers.utils.id(string)).sub(1)], | ||
); | ||
} | ||
const IMPLEMENTATION_STORAGE_SLOT = slot("eip1967.proxy.implementation"); | ||
const OWNER_STORAGE_SLOT = slot("eip1967.proxy.admin"); | ||
|
||
/** | ||
* Returns the address of the implementation of an EIP-1967-compatible proxy | ||
* from its address. | ||
* | ||
* @param proxy Address of the proxy contract. | ||
* @returns The address of the contract storing the proxy implementation. | ||
*/ | ||
export async function implementationAddress(proxy: string): Promise<string> { | ||
const [implementation] = await ethers.utils.defaultAbiCoder.decode( | ||
["address"], | ||
await ethers.provider.getStorageAt(proxy, IMPLEMENTATION_STORAGE_SLOT), | ||
); | ||
return implementation; | ||
} | ||
|
||
/** | ||
* Returns the address of the implementation of an EIP-1967-compatible proxy | ||
* from its address. | ||
* | ||
* @param proxy Address of the proxy contract. | ||
* @returns The address of the administrator of the proxy. | ||
*/ | ||
export async function ownerAddress(proxy: string): Promise<string> { | ||
const [owner] = await ethers.utils.defaultAbiCoder.decode( | ||
["address"], | ||
await ethers.provider.getStorageAt(proxy, OWNER_STORAGE_SLOT), | ||
); | ||
return owner; | ||
} |
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
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
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
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
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,72 @@ | ||
import { expect } from "chai"; | ||
import { Contract, Wallet } from "ethers"; | ||
import { deployments, ethers } from "hardhat"; | ||
|
||
import { deployTestContracts } from "./fixture"; | ||
|
||
describe("Upgrade Authenticator", () => { | ||
let authenticator: Contract; | ||
let deployer: Wallet; | ||
let owner: Wallet; | ||
let solver: Wallet; | ||
|
||
beforeEach(async () => { | ||
({ | ||
authenticator, | ||
deployer, | ||
owner, | ||
wallets: [solver], | ||
} = await deployTestContracts()); | ||
}); | ||
|
||
it("should upgrade authenticator", async () => { | ||
const GPv2AllowListAuthenticationV2 = await ethers.getContractFactory( | ||
"GPv2AllowListAuthenticationV2", | ||
deployer, | ||
); | ||
// Note that, before the upgrade this is actually the old instance | ||
const authenticatorV2 = GPv2AllowListAuthenticationV2.attach( | ||
authenticator.address, | ||
); | ||
// This method doesn't exist before upgrade | ||
await expect(authenticatorV2.newMethod()).to.be.reverted; | ||
|
||
await upgrade( | ||
"GPv2AllowListAuthentication", | ||
"GPv2AllowListAuthenticationV2", | ||
); | ||
// This method should exist on after upgrade | ||
expect(await authenticatorV2.newMethod()).to.equal(1337); | ||
}); | ||
|
||
it("should preserve storage", async () => { | ||
await authenticator.connect(owner).addSolver(solver.address); | ||
|
||
// Upgrade after storage is set. | ||
await upgrade( | ||
"GPv2AllowListAuthentication", | ||
"GPv2AllowListAuthenticationV2", | ||
); | ||
|
||
const GPv2AllowListAuthenticationV2 = await ethers.getContractFactory( | ||
"GPv2AllowListAuthenticationV2", | ||
deployer, | ||
); | ||
const authenticatorV2 = GPv2AllowListAuthenticationV2.attach( | ||
authenticator.address, | ||
); | ||
// Both, the listed solvers and original manager are still set | ||
expect(await authenticatorV2.isSolver(solver.address)).to.equal(true); | ||
expect(await authenticatorV2.manager()).to.equal(owner.address); | ||
}); | ||
|
||
async function upgrade(contractName: string, newContractName: string) { | ||
// Note that deterministic deployment and gasLimit are not needed/used here as deployment args. | ||
await deployments.deploy(contractName, { | ||
contract: newContractName, | ||
// From differs from initial deployment here since the proxy owner is the Authenticator manager. | ||
from: owner.address, | ||
proxy: true, | ||
}); | ||
} | ||
}); |