Skip to content

Commit

Permalink
⭐️ init commit
Browse files Browse the repository at this point in the history
  • Loading branch information
PatrickAlphaC committed Apr 18, 2023
1 parent 1b78dc8 commit 5c03f4f
Show file tree
Hide file tree
Showing 17 changed files with 437 additions and 50 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ out/
!/broadcast
/broadcast/*/31337/
/broadcast/**/dry-run/
/broadcast/

# Docs
docs/
Expand Down
9 changes: 9 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
[submodule "lib/forge-std"]
path = lib/forge-std
url = https://github.com/foundry-rs/forge-std
[submodule "lib/openzeppelin-contracts"]
path = lib/openzeppelin-contracts
url = https://github.com/openzeppelin/openzeppelin-contracts
[submodule "lib/openzeppelin-contracts-upgradeable"]
path = lib/openzeppelin-contracts-upgradeable
url = https://github.com/openzeppelin/openzeppelin-contracts-upgradeable
[submodule "lib/foundry-devops"]
path = lib/foundry-devops
url = https://github.com/chainaccelorg/foundry-devops
138 changes: 138 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
# Foundry UUPS Upgradeable Contracts

This is a section of the Cyfrin Foundry Solidity Course.

*This is for demo purposes only. Upgradeable contracts are a menance and in general should be avoided for


- [Foundry UUPS Upgradeable Contracts](#foundry-uups-upgradeable-contracts)
- [Getting Started](#getting-started)
- [Requirements](#requirements)
- [Quickstart](#quickstart)
- [Optional Gitpod](#optional-gitpod)
- [Usage](#usage)
- [Start a local node](#start-a-local-node)
- [Deploy](#deploy)
- [Deploy - Other Network](#deploy---other-network)
- [Testing](#testing)
- [Test Coverage](#test-coverage)
- [Deployment to a testnet or mainnet](#deployment-to-a-testnet-or-mainnet)
- [Estimate gas](#estimate-gas)
- [Formatting](#formatting)
- [Thank you!](#thank-you)

# Getting Started

## Requirements

- [git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)
- You'll know you did it right if you can run `git --version` and you see a response like `git version x.x.x`
- [foundry](https://getfoundry.sh/)
- You'll know you did it right if you can run `forge --version` and you see a response like `forge 0.2.0 (816e00b 2023-03-16T00:05:26.396218Z)`

## Quickstart

```
git clone https://github.com/PatrickAlphaC/foundry-upgrades-f23
cd foundry-upgrades-f23
forge build
```

### Optional Gitpod

If you can't or don't want to run and install locally, you can work with this repo in Gitpod. If you do this, you can skip the `clone this repo` part.

[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#github.com/PatrickAlphaC/foundry-upgrades-f23)

# Usage

## Start a local node

```
make anvil
```

## Deploy

This will default to your local node. You need to have it running in another terminal in order for it to deploy.

```
make deploy
```

## Deploy - Other Network

[See below](#deployment-to-a-testnet-or-mainnet)

## Testing

```
forge test
```

### Test Coverage

```
forge coverage
```

and for coverage based testing:

```
forge coverage --report debug
```


# Deployment to a testnet or mainnet

1. Setup environment variables

You'll want to set your `SEPOLIA_RPC_URL` and `PRIVATE_KEY` as environment variables. You can add them to a `.env` file, similar to what you see in `.env.example`.

- `PRIVATE_KEY`: The private key of your account (like from [metamask](https://metamask.io/)). **NOTE:** FOR DEVELOPMENT, PLEASE USE A KEY THAT DOESN'T HAVE ANY REAL FUNDS ASSOCIATED WITH IT.
- You can [learn how to export it here](https://metamask.zendesk.com/hc/en-us/articles/360015289632-How-to-Export-an-Account-Private-Key).
- `SEPOLIA_RPC_URL`: This is url of the goerli testnet node you're working with. You can get setup with one for free from [Alchemy](https://alchemy.com/?a=673c802981)

Optionally, add your `ETHERSCAN_API_KEY` if you want to verify your contract on [Etherscan](https://etherscan.io/).

1. Get testnet ETH

Head over to [faucets.chain.link](https://faucets.chain.link/) and get some tesnet ETH. You should see the ETH show up in your metamask.

2. Deploy

```
make deploy ARGS="--network sepolia"
```


## Estimate gas

You can estimate how much gas things cost by running:

```
forge snapshot
```

And you'll see and output file called `.gas-snapshot`


# Formatting


To run code formatting:
```
forge fmt
```


# Thank you!

If you appreciated this, feel free to follow me or donate!

ETH/Polygon/Avalanche/etc Address: 0x9680201d9c93d65a3603d2088d125e955c73BD65

[![Patrick Collins Twitter](https://img.shields.io/badge/Twitter-1DA1F2?style=for-the-badge&logo=twitter&logoColor=white)](https://twitter.com/PatrickAlphaC)
[![Patrick Collins YouTube](https://img.shields.io/badge/YouTube-FF0000?style=for-the-badge&logo=youtube&logoColor=white)](https://www.youtube.com/channel/UCn-3f8tw_E1jZvhuHatROwA)
[![Patrick Collins Linkedin](https://img.shields.io/badge/LinkedIn-0077B5?style=for-the-badge&logo=linkedin&logoColor=white)](https://www.linkedin.com/in/patrickalphac/)
[![Patrick Collins Medium](https://img.shields.io/badge/Medium-000000?style=for-the-badge&logo=medium&logoColor=white)](https://medium.com/@patrick.collins_58673/)
10 changes: 10 additions & 0 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,15 @@
src = "src"
out = "out"
libs = ["lib"]
ffi = true

remappings = ['@openzeppelin/contracts=lib/openzeppelin-contracts/contracts', '@openzeppelin/contracts-upgradeable@4.8.3=lib/openzeppelin-contracts-upgradeable/contracts']

[etherscan]
mainnet = { key = "${ETHERSCAN_API_KEY}" }
sepolia = {key = "${ETHERSCAN_API_KEY}"}

[rpc_endpoints]
sepolia = "${SEPOLIA_RPC_URL}"

# See more config options https://github.com/foundry-rs/foundry/tree/master/config
1 change: 1 addition & 0 deletions lib/foundry-devops
Submodule foundry-devops added at d4a3bb
1 change: 1 addition & 0 deletions lib/openzeppelin-contracts
Submodule openzeppelin-contracts added at 0a25c1
1 change: 1 addition & 0 deletions lib/openzeppelin-contracts-upgradeable
12 changes: 0 additions & 12 deletions script/Counter.s.sol

This file was deleted.

19 changes: 19 additions & 0 deletions script/DepolyBox.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import {Script} from "forge-std/Script.sol";
import {BoxV1} from "../src/BoxV1.sol";
import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";

contract DeployBox is Script {
function run() external returns (address) {
address proxy = deployBox();
return proxy;
}

function deployBox() public returns (address) {
BoxV1 box = new BoxV1();
ERC1967Proxy proxy = new ERC1967Proxy(address(box), "");
return address(proxy);
}
}
32 changes: 32 additions & 0 deletions script/UpgradeBox.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import {Script} from "forge-std/Script.sol";
import {BoxV1} from "../src/BoxV1.sol";
import {BoxV2} from "../src/BoxV2.sol";
import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
import {DevOpsTools} from "lib/foundry-devops/src/DevOpsTools.sol";

contract UpgradeBox is Script {
function run() external returns (address) {
address mostRecentlyDeployedProxy = DevOpsTools
.get_most_recent_deployment("ERC1967Proxy", block.chainid);

vm.startBroadcast();
BoxV2 newBox = new BoxV2();
vm.stopBroadcast();
address proxy = upgradeBox(mostRecentlyDeployedProxy, address(newBox));
return proxy;
}

function upgradeBox(
address proxyAddress,
address newBox
) public returns (address) {
vm.startBroadcast();
BoxV1 proxy = BoxV1(payable(proxyAddress));
proxy.upgradeTo(address(newBox));
vm.stopBroadcast();
return address(proxy);
}
}
32 changes: 32 additions & 0 deletions src/BoxV1.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import "@openzeppelin/contracts-upgradeable@4.8.3/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable@4.8.3/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable@4.8.3/proxy/utils/UUPSUpgradeable.sol";

contract BoxV1 is Initializable, OwnableUpgradeable, UUPSUpgradeable {
uint256 internal value;

/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}

function initialize() public initializer {
__Ownable_init();
__UUPSUpgradeable_init();
}

function getValue() public view returns (uint256) {
return value;
}

function version() public pure returns (uint256) {
return 1;
}

function _authorizeUpgrade(
address newImplementation
) internal override onlyOwner {}
}
36 changes: 36 additions & 0 deletions src/BoxV2.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import "@openzeppelin/contracts-upgradeable@4.8.3/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable@4.8.3/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable@4.8.3/proxy/utils/UUPSUpgradeable.sol";

contract BoxV2 is Initializable, OwnableUpgradeable, UUPSUpgradeable {
uint256 internal value;

/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}

function initialize() public initializer {
__Ownable_init();
__UUPSUpgradeable_init();
}

function setValue(uint256 newValue) public {
value = newValue;
}

function getValue() public view returns (uint256) {
return value;
}

function version() public pure returns (uint256) {
return 2;
}

function _authorizeUpgrade(
address newImplementation
) internal override onlyOwner {}
}
14 changes: 0 additions & 14 deletions src/Counter.sol

This file was deleted.

37 changes: 37 additions & 0 deletions src/sublesson/DelegateCallExample.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// SPDX-License-Identifier: MIT

// Be sure to check out solidity-by-example
// https://solidity-by-example.org/delegatecall

pragma solidity ^0.8.19;

// NOTE: Deploy this contract first
contract B {
// NOTE: storage layout must be the same as contract A
uint256 public num;
address public sender;
uint256 public value;

function setVars(uint256 _num) public payable {
num = _num;
sender = msg.sender;
value = msg.value;
}
}

contract A {
uint256 public num;
address public sender;
uint256 public value;

function setVars(address _contract, uint256 _num) public payable {
// A's storage is set, B is not modified.
// (bool success, bytes memory data) = _contract.delegatecall(
(bool success, ) = _contract.delegatecall(
abi.encodeWithSignature("setVars(uint256)", _num)
);
if (!success) {
revert("delegatecall failed");
}
}
}
Loading

0 comments on commit 5c03f4f

Please sign in to comment.