Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: upgradeables #154

Merged
merged 3 commits into from
Mar 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions src/upgradeables/DocumentStoreUpgradeable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// SPDX-License-Identifier: Apache-2.0

pragma solidity >=0.8.23 <0.9.0;

import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import "../base/BaseDocumentStore.sol";

/**
* @title DocumentStore
* @notice A contract for storing and revoking documents with access control
*/
contract DocumentStoreUpgradeable is UUPSUpgradeable, BaseDocumentStore {
/**
* @notice Initialises the contract with a name and initial admin
* @param name The name of the contract
* @param initAdmin The initial admin of the contract
*/
constructor(string memory name, address initAdmin) {
initialize(name, initAdmin);
}

/**
* @notice Internally initialises the contract with a name and owner
* @param _name The name of the contract
* @param initAdmin The owner of the contract
*/
function initialize(string memory _name, address initAdmin) public initializer {
__BaseDocumentStore_init(_name, initAdmin);
}

function _authorizeUpgrade(address) internal view virtual override onlyRole(DEFAULT_ADMIN_ROLE) {}
}
18 changes: 18 additions & 0 deletions src/upgradeables/OwnableDocumentStoreUpgradeable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// SPDX-License-Identifier: Apache-2.0

pragma solidity >=0.8.23 <0.9.0;

import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import "../base/BaseOwnableDocumentStore.sol";

contract OwnableDocumentStoreUpgradeable is UUPSUpgradeable, BaseOwnableDocumentStore {
constructor(string memory name_, string memory symbol_, address initAdmin) {
initialize(name_, symbol_, initAdmin);
}

function initialize(string memory name_, string memory symbol_, address initAdmin) public initializer {
__OwnableDocumentStore_init(name_, symbol_, initAdmin);
}

function _authorizeUpgrade(address) internal view virtual override onlyRole(DEFAULT_ADMIN_ROLE) {}
}
83 changes: 83 additions & 0 deletions test/DocumentStoreUpgradeable.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity >=0.8.23 <0.9.0;

import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
import {CommonTest} from "./CommonTest.t.sol";
import "../src/upgradeables/DocumentStoreUpgradeable.sol";

contract DocumentStoreUpgradeable_Test is CommonTest {
DocumentStoreUpgradeable public dsProxy;
DocumentStoreUpgradeable public documentStore;

string public implName = "ImplDocumentStore";
address public implOwner = vm.addr(99);

string public initialName = "DocumentStore";

function setUp() public override {
super.setUp();

bytes memory initData = abi.encodeCall(DocumentStoreUpgradeable.initialize, (initialName, owner));

documentStore = new DocumentStoreUpgradeable(implName, implOwner);
ERC1967Proxy proxy = new ERC1967Proxy(address(documentStore), initData);
dsProxy = DocumentStoreUpgradeable(address(proxy));
}

function testImplInitializedValues() public {
assertEq(documentStore.name(), implName);
assertTrue(documentStore.hasRole(documentStore.DEFAULT_ADMIN_ROLE(), implOwner));
}

function testImplReinitialiseFail() public {
vm.expectRevert(abi.encodeWithSelector(Initializable.InvalidInitialization.selector));

documentStore.initialize("NewName", owner);
}

function testInitializeValues() public {
assertEq(dsProxy.name(), initialName);
assertTrue(dsProxy.hasRole(documentStore.DEFAULT_ADMIN_ROLE(), owner));
}

function testFailReinitialize() public {
dsProxy.initialize("NewName", owner);
}

function testUpgradeToAndCallAsNonAdmin() public {
address nonAdmin = vm.addr(69);
address newImplementation = address(new DocumentStoreUpgradeable("NewImplDocumentStore", owner));

vm.expectRevert(
abi.encodeWithSelector(
IAccessControl.AccessControlUnauthorizedAccount.selector,
nonAdmin,
documentStore.DEFAULT_ADMIN_ROLE()
)
);

vm.prank(nonAdmin);
dsProxy.upgradeToAndCall(newImplementation, "");
}

function testUpgradeToAndCallAsAdmin() public {
address newImplementation = address(new DocumentStoreUpgradeable("TestName", owner));

vm.prank(owner);
dsProxy.upgradeToAndCall(newImplementation, "");

bytes32 proxyImpl = vm.load(address(dsProxy), 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc);

assertEq(newImplementation, address(uint160(uint256(proxyImpl))));
}

function testUpgradeToAndCallReinitialiseFail() public {
address newImplementation = address(new DocumentStoreUpgradeable("TestName", owner));
bytes memory initData = abi.encodeCall(DocumentStoreUpgradeable.initialize, (initialName, owner));

vm.expectRevert(abi.encodeWithSelector(Initializable.InvalidInitialization.selector));

vm.prank(owner);
dsProxy.upgradeToAndCall(newImplementation, initData);
}
}
93 changes: 93 additions & 0 deletions test/OwnableDocumentStoreUpgradeable.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity >=0.8.23 <0.9.0;

import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
import {CommonTest} from "./CommonTest.t.sol";
import "../src/upgradeables/OwnableDocumentStoreUpgradeable.sol";

contract OwnableDocumentStoreUpgradeable_Test is CommonTest {
OwnableDocumentStoreUpgradeable public dsProxy;
OwnableDocumentStoreUpgradeable public documentStore;

string public implName = "ImplOwnableDocumentStore";
string public implSymbol = "ImplTEST";
address public implOwner = vm.addr(99);

string public initialName = "OwnableDocumentStore";
string public initialSymbol = "TEST";

function setUp() public override {
super.setUp();

bytes memory initData = abi.encodeCall(
OwnableDocumentStoreUpgradeable.initialize,
(initialName, initialSymbol, owner)
);

documentStore = new OwnableDocumentStoreUpgradeable(implName, implSymbol, implOwner);
ERC1967Proxy proxy = new ERC1967Proxy(address(documentStore), initData);
dsProxy = OwnableDocumentStoreUpgradeable(address(proxy));
}

function testImplInitializedValues() public {
assertEq(documentStore.name(), implName);
assertEq(documentStore.symbol(), implSymbol);
assertTrue(documentStore.hasRole(documentStore.DEFAULT_ADMIN_ROLE(), implOwner));
}

function testImplReinitialiseFail() public {
vm.expectRevert(abi.encodeWithSelector(Initializable.InvalidInitialization.selector));

documentStore.initialize("NewName", "TEST2", owner);
}

function testInitializeValues() public {
assertEq(dsProxy.name(), initialName);
assertEq(dsProxy.symbol(), initialSymbol);
assertTrue(dsProxy.hasRole(documentStore.DEFAULT_ADMIN_ROLE(), owner));
}

function testFailReinitialize() public {
dsProxy.initialize("NewName", "TEST2", owner);
}

function testUpgradeToAndCallAsNonAdmin() public {
address nonAdmin = vm.addr(69);
address newImplementation = address(new OwnableDocumentStoreUpgradeable("NewImplDocumentStore", "TEST2", owner));

vm.expectRevert(
abi.encodeWithSelector(
IAccessControl.AccessControlUnauthorizedAccount.selector,
nonAdmin,
documentStore.DEFAULT_ADMIN_ROLE()
)
);

vm.prank(nonAdmin);
dsProxy.upgradeToAndCall(newImplementation, "");
}

function testUpgradeToAndCallAsAdmin() public {
address newImplementation = address(new OwnableDocumentStoreUpgradeable("TestName", implSymbol, owner));

vm.prank(owner);
dsProxy.upgradeToAndCall(newImplementation, "");

bytes32 proxyImpl = vm.load(address(dsProxy), 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc);

assertEq(newImplementation, address(uint160(uint256(proxyImpl))));
}

function testUpgradeToAndCallReinitialiseFail() public {
address newImplementation = address(new OwnableDocumentStoreUpgradeable("TestName", implSymbol, owner));
bytes memory initData = abi.encodeCall(
OwnableDocumentStoreUpgradeable.initialize,
(initialName, initialSymbol, owner)
);

vm.expectRevert(abi.encodeWithSelector(Initializable.InvalidInitialization.selector));

vm.prank(owner);
dsProxy.upgradeToAndCall(newImplementation, initData);
}
}
Loading