Skip to content

Commit d06a2f7

Browse files
Test and Upgrade functions tested
1 parent aa80a1a commit d06a2f7

11 files changed

Lines changed: 239 additions & 1 deletion

.gitmodules

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
11
[submodule "lib/forge-std"]
22
path = lib/forge-std
33
url = https://github.com/foundry-rs/forge-std
4+
[submodule "lib/openzeppelin-contracts-upgradeable"]
5+
path = lib/openzeppelin-contracts-upgradeable
6+
url = https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable
7+
[submodule "lib/openzeppelin-contracts"]
8+
path = lib/openzeppelin-contracts
9+
url = https://github.com/OpenZeppelin/openzeppelin-contracts
10+
[submodule "lib/foundry-devops"]
11+
path = lib/foundry-devops
12+
url = https://github.com/Cyfrin/foundry-devops

README.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,48 @@
11
Upgradable smart-contracts
2+
# Upgradable Smart Contracts
3+
4+
This repository demonstrates the use of upgradable smart contracts using [OpenZeppelin Contracts Upgradeable](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable) and [Foundry](https://github.com/foundry-rs/foundry). It provides example contracts, deployment scripts, and tests to help you get started with secure and maintainable upgradeable contract development.
5+
6+
## Features
7+
8+
- Example implementation of upgradeable contracts (`BoxV1`, `BoxV2`)
9+
- Deployment and upgrade scripts using Foundry
10+
- Automated tests for deployment and upgrade flows
11+
- Integration with OpenZeppelin's upgradeable libraries
12+
13+
## Getting Started
14+
15+
### Prerequisites
16+
17+
- [Foundry](https://getfoundry.sh/) (for `forge` and `cast`)
18+
- [Git](https://git-scm.com/)
19+
20+
### Installation
21+
22+
Clone the repository and install dependencies:
23+
24+
```sh
25+
git clone https://github.com/your-username/upgradable_contract.git
26+
cd upgradable_contract
27+
forge install
28+
* Compile Contracts
29+
forge build
30+
* Run Tests
31+
forge test
32+
** Deploy and Upgrade
33+
* Deployment and upgrade scripts are located in the script/ directory:
34+
* DeployBox.s.sol: Deploys the initial version of the contract.
35+
* UpgradeBox.sol: Upgrades the contract to a new version.
36+
* You can run these scripts using Foundry's forge script command.
37+
38+
src/ # Solidity contract sources
39+
script/ # Deployment and upgrade scripts
40+
test/ # Test contracts
41+
lib/ # External dependencies (OpenZeppelin, Forge Std, etc.)
42+
43+
*References
44+
** OpenZeppelin Contracts Upgradeable Documentation
45+
** Foundry Book
46+
** License
47+
** This project is licensed under the MIT License.
48+

foundry.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,8 @@
22
src = "src"
33
out = "out"
44
libs = ["lib"]
5-
5+
remappings = [
6+
"@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts",
7+
"@openzeppelin/contracts=lib/openzeppelin-contracts/contracts"
8+
]
69
# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options

lib/foundry-devops

Submodule foundry-devops added at efff097

lib/openzeppelin-contracts

Submodule openzeppelin-contracts added at c64a1ed

script/DeployBox.s.sol

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
//SPDX-License-Identifier:MIT
2+
pragma solidity ^0.8.18;
3+
4+
import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
5+
import {Script} from "forge-std/Script.sol";
6+
import {BoxV1} from "../src/BoxV1.sol";
7+
8+
/*
9+
Steps of deployment:
10+
Deploy BoxV1
11+
Get an address
12+
Deploy Proxy with BoxV1 address
13+
Verify that everything works
14+
Deploy BoxV2
15+
Point Proxy to BoxV2
16+
*/
17+
contract DeployBox is Script {
18+
function run() external returns (address) {
19+
address proxy = deployBox();
20+
return proxy;
21+
}
22+
23+
/**
24+
* @notice deploys the proxy contract
25+
* @return address : address of the proxy contract
26+
*/
27+
function deployBox() public returns (address) {
28+
vm.startBroadcast();
29+
BoxV1 box = new BoxV1(); // Implementation
30+
ERC1967Proxy proxy = new ERC1967Proxy(address(box), "");
31+
BoxV1(address(proxy)).initialize();
32+
vm.stopBroadcast();
33+
return address(proxy);
34+
}
35+
}

script/UpgradeBox.sol

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
pragma solidity ^0.8.18;
4+
5+
import {Script} from "forge-std/Script.sol";
6+
import {DevOpsTools} from "lib/foundry-devops/src/DevOpsTools.sol";
7+
import {BoxV2} from "../src/BoxV2.sol";
8+
import {BoxV1} from "../src/BoxV1.sol";
9+
10+
contract UpgradeBox is Script {
11+
function run() external returns (address) {
12+
address mostRecentDeployment = DevOpsTools.get_most_recent_deployment("ERC1967Proxy", block.chainid);
13+
vm.startBroadcast();
14+
BoxV2 newBox = new BoxV2();
15+
vm.stopBroadcast();
16+
17+
address proxy = upgradeBox(mostRecentDeployment, address(newBox));
18+
return proxy;
19+
}
20+
21+
function upgradeBox(address proxyAddress, address newBox) public returns (address) {
22+
vm.startBroadcast();
23+
BoxV1 proxy = BoxV1(proxyAddress);
24+
proxy.upgradeTo(address(newBox));
25+
vm.stopBroadcast();
26+
return address(proxy);
27+
}
28+
}

src/BoxV1.sol

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//SPDX-License-Identifier:MIT
2+
pragma solidity ^0.8.18;
3+
4+
import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
5+
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
6+
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
7+
8+
contract BoxV1 is Initializable, UUPSUpgradeable, OwnableUpgradeable {
9+
uint256 internal number;
10+
11+
constructor() {
12+
// do not allow constructor initialisation/reinitialisation
13+
_disableInitializers();
14+
}
15+
16+
/**
17+
* @param newImplementation: new implementation to upgradet to
18+
* @notice specification of the new implementation to upgrade to and how
19+
*/
20+
function _authorizeUpgrade(address newImplementation) internal override {}
21+
22+
/**
23+
* @notice defining how our V1 should be initialised
24+
* caller of this function is the one authorised perform criticall functions relating to upgrades
25+
*/
26+
function initialize() public initializer {
27+
__Ownable_init();
28+
__UUPSUpgradeable_init();
29+
}
30+
31+
function getNumber() external view returns (uint256) {
32+
return number;
33+
}
34+
35+
function version() external pure returns (uint256) {
36+
return 1;
37+
}
38+
}

src/BoxV2.sol

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.18;
3+
4+
import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
5+
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
6+
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
7+
8+
contract BoxV2 is Initializable, UUPSUpgradeable, OwnableUpgradeable {
9+
uint256 internal number;
10+
11+
/// @custom:oz-upgrades-unsafe-allow constructor
12+
constructor() {
13+
_disableInitializers();
14+
}
15+
16+
function initialize() public initializer {
17+
__Ownable_init();
18+
__UUPSUpgradeable_init();
19+
}
20+
21+
// new function added that's not in BOXV1.sol
22+
function setNumber(uint256 _number) external {
23+
number = _number;
24+
}
25+
26+
function getNumber() external view returns (uint256) {
27+
return number;
28+
}
29+
30+
function version() external pure returns (uint256) {
31+
return 2;
32+
}
33+
34+
function _authorizeUpgrade(address newImplementation) internal override {}
35+
}

0 commit comments

Comments
 (0)