Skip to content

Commit

Permalink
fix upgradeable
Browse files Browse the repository at this point in the history
  • Loading branch information
ryanio committed Apr 19, 2024
1 parent 40b22f6 commit f0bb777
Show file tree
Hide file tree
Showing 11 changed files with 782 additions and 121 deletions.
5 changes: 3 additions & 2 deletions package.json
Expand Up @@ -37,9 +37,10 @@
"hardhat": "^2.11.1"
},
"devDependencies": {
"@nomiclabs/hardhat-ethers": "^2.1.1",
"@nomiclabs/hardhat-ethers": "^2.2.3",
"@nomiclabs/hardhat-etherscan": "^3.1.0",
"@nomiclabs/hardhat-waffle": "^2.0.3",
"@openzeppelin/hardhat-upgrades": "^1.28.0",
"@typechain/ethers-v5": "^10.1.0",
"@typechain/hardhat": "^6.1.2",
"@types/chai": "^4.3.3",
Expand Down Expand Up @@ -74,7 +75,7 @@
"async": ">=2.6.4",
"cross-fetch": ">=3.1.5",
"lodash": ">=4.17.21",
"node-fetch": ">=2.6.7",
"node-fetch": "^2.6.7",
"underscore": ">=1.12.1",
"yargs-parser": ">=5.0.1",
"web3": ">=1.8.0",
Expand Down
16 changes: 6 additions & 10 deletions src-upgradeable/README.md
Expand Up @@ -13,17 +13,13 @@ Constructors are replaced by internal initializer functions following the naming

These functions are internal, and you must define your own public initializer function that calls the parent class' initializer.

If using with another upgradeable library, please do use their respective initializer modifier on the `initialize()` function, in addition to the `initializerERC721A` modifier.
If using with another upgradeable library, please do use their respective initializer modifier on the `initialize()` function, in addition to the `onlyInitializing` modifier.

## Deployment

If you are using hardhat, you can deploy it using
[OpenZeppelin Upgrade Plugins](https://docs.openzeppelin.com/upgrades-plugins/1.x/).

```
npm install --save-dev @openzeppelin/hardhat-upgrades
```

**Deploy Script**

Located at [`scripts/deploy.ts`](./scripts/deploy.ts)
Expand All @@ -34,14 +30,14 @@ Located at [`scripts/upgrade.ts`](./scripts/upgrade.ts)

### Testnet / Mainnet

We will use the Goerli testnet as an example.
We will use the Sepolia testnet as an example.

Add the following to your environment file `.env`:

```
export ETHERSCAN_KEY="Your Etherscan API Key"
export PRIVATE_KEY="Your Wallet Private Key"
export RPC_URL_GOERLI="https://Infura Or Alchemy URL With API Key"
export SEPOLIA_RPC_URL="https://Infura Or Alchemy URL With API Key"
export ETHERSCAN_API_KEY="Your Etherscan API Key"
```

Hardhat config located at [`hardhat.config.ts`](./hardhat.config.ts)
Expand All @@ -51,13 +47,13 @@ Hardhat config located at [`hardhat.config.ts`](./hardhat.config.ts)
In this directory (`src-upgradeable`) run:

```
npx hardhat run --config hardhat.config.ts --network goerli scripts/deploy.ts
npx hardhat run --config hardhat.config.ts --network sepolia scripts/deploy.ts
```

**Upgrade**

In this directory (`src-upgradeable`) run:

```
npx hardhat run --config hardhat.config.ts --network goerli scripts/upgrade.ts
npx hardhat run --config hardhat.config.ts --network sepolia scripts/upgrade.ts
```
8 changes: 4 additions & 4 deletions src-upgradeable/hardhat.config.ts
Expand Up @@ -11,22 +11,22 @@ module.exports = {
viaIR: true,
optimizer: {
enabled: true,
runs: 200,
runs: 1000,
},
},
},
],
},
networks: {
goerli: {
url: process.env.RPC_URL_GOERLI,
sepolia: {
url: process.env.SEPOLIA_RPC_URL,
accounts: [process.env.PRIVATE_KEY],
},
},
etherscan: {
// Your API key for Etherscan
// Obtain one at https://etherscan.io/
apiKey: process.env.ETHERSCAN_KEY,
apiKey: process.env.ETHERSCAN_API_KEY,
},
paths: { sources: "./src" },
};
29 changes: 18 additions & 11 deletions src-upgradeable/scripts/deploy.ts
Expand Up @@ -2,24 +2,31 @@ import fs from "fs";
import { ethers, upgrades } from "hardhat";

async function mainDeploy() {
const ExampleToken = await ethers.getContractFactory("ExampleToken");
const ERC721SeaDropUpgradeable = await ethers.getContractFactory("ERC721SeaDropUpgradeable");

console.log("Deploying...");
const exampleToken = await upgrades.deployProxy(
ExampleToken,

const tokenName = "ERC721SeaDropUpgradeable"
const tokenSymbol = "SD"
const allowedSeaDrop = ["0x00005EA00Ac477B1030CE78506496e8C2dE24bf5"]

const token = await upgrades.deployProxy(
ERC721SeaDropUpgradeable,
[
"ExampleToken",
"ExTkn",
"0x4468A5B725E2C63056131121cD33b66848E1dd87",
["0x00005EA00Ac477B1030CE78506496e8C2dE24bf5"],
tokenName,
tokenSymbol,
allowedSeaDrop,
],
{ initializer: "initialize" }
);
await exampleToken.deployed();

await token.deployed();

const addresses = {
proxy: exampleToken.address,
admin: await upgrades.erc1967.getAdminAddress(exampleToken.address),
proxy: token.address,
admin: await upgrades.erc1967.getAdminAddress(token.address),
implementation: await upgrades.erc1967.getImplementationAddress(
exampleToken.address
token.address
),
};
console.log("Addresses: ", addresses);
Expand Down
8 changes: 6 additions & 2 deletions src-upgradeable/scripts/upgrade.ts
Expand Up @@ -2,13 +2,17 @@ import fs from "fs";
import { ethers, upgrades } from "hardhat";

async function main() {
const ExampleToken = await ethers.getContractFactory("ExampleToken");
const ERC721SeaDropUpgradeable = await ethers.getContractFactory("ERC721SeaDropUpgradeable");

console.log("Upgrading...");

let addresses = JSON.parse(
fs.readFileSync("deployment-addresses.json").toString()
);
const result = await upgrades.upgradeProxy(addresses.proxy, ExampleToken);

const result = await upgrades.upgradeProxy(addresses.proxy, ERC721SeaDropUpgradeable);
await result.deployTransaction.wait();

console.log("Upgraded");

addresses = {
Expand Down
2 changes: 1 addition & 1 deletion src-upgradeable/src/ERC721ContractMetadataUpgradeable.sol
Expand Up @@ -50,6 +50,7 @@ import {
*/
contract ERC721ContractMetadataUpgradeable is
ERC721AConduitPreapprovedUpgradeable,
ERC721TransferValidatorUpgradeable,
TwoStepOwnableUpgradeable,
ISeaDropTokenContractMetadataUpgradeable
{
Expand Down Expand Up @@ -77,7 +78,6 @@ contract ERC721ContractMetadataUpgradeable is
string memory symbol
) internal onlyInitializing {
__ERC721AConduitPreapprovedUpgradeable_init_unchained(name, symbol);
__ConstructorInitializable_init_unchained();
__TwoStepOwnable_init_unchained();
}

Expand Down
23 changes: 16 additions & 7 deletions src-upgradeable/src/ERC721SeaDropUpgradeable.sol
Expand Up @@ -71,20 +71,29 @@ contract ERC721SeaDropUpgradeable is
}

/**
* @notice Deploy the token contract with its name, symbol,
* @notice Initialize the token contract with its name, symbol,
* and allowed SeaDrop addresses.
*/
function initialize(
string memory name,
string memory symbol,
address[] memory allowedSeaDrop
) external initializer initializerERC721A {
__ERC721SeaDrop_init(
name,
symbol,
allowedSeaDrop
);
}

function __ERC721SeaDrop_init(
string memory name,
string memory symbol,
address[] memory allowedSeaDrop
) internal onlyInitializing {
__ERC721A_init_unchained(name, symbol);
__ConstructorInitializable_init_unchained();
__TwoStepOwnable_init_unchained();
__ERC721ContractMetadata_init_unchained(name, symbol);
__ReentrancyGuard_init_unchained();
__ERC721ContractMetadata_init(name, symbol);
__ERC721SeaDrop_init_unchained(name, symbol, allowedSeaDrop);
__ReentrancyGuard_init_unchained();
}

function __ERC721SeaDrop_init_unchained(
Expand Down Expand Up @@ -182,7 +191,7 @@ contract ERC721SeaDropUpgradeable is
* @param tokenId The token id to burn.
*/
// solhint-disable-next-line comprehensive-interface
function burn(uint256 tokenId) external {
function burn(uint256 tokenId) external virtual {
_burn(tokenId, true);
}

Expand Down
18 changes: 1 addition & 17 deletions src-upgradeable/src/ExampleToken.sol
Expand Up @@ -33,22 +33,6 @@ contract ExampleToken is ERC721SeaDropUpgradeable {
*/
error BurnIncorrectSender();

/**
* @notice Initialize the token contract with its name, symbol,
* and allowed SeaDrop addresses.
*/
function initialize(
string memory name,
string memory symbol,
address[] memory allowedSeaDrop
) external initializer initializerERC721A {
ERC721SeaDropUpgradeable.__ERC721SeaDrop_init(
name,
symbol,
allowedSeaDrop
);
}

function setBurnAddress(address newBurnAddress) external onlyOwner {
ExampleTokenStorage.layout().burnAddress = newBurnAddress;
}
Expand All @@ -62,7 +46,7 @@ contract ExampleToken is ERC721SeaDropUpgradeable {
*
* @param tokenId The token id to burn.
*/
function burn(uint256 tokenId) external {
function burn(uint256 tokenId) external override {
if (msg.sender != ExampleTokenStorage.layout().burnAddress) {
revert BurnIncorrectSender();
}
Expand Down
Expand Up @@ -38,27 +38,9 @@ contract ERC721SeaDropRandomOffsetUpgradeable is ERC721SeaDropUpgradeable {
string memory symbol,
address[] memory allowedSeaDrop
) internal onlyInitializing {
__ERC721A_init_unchained(name, symbol);
__ConstructorInitializable_init_unchained();
__TwoStepOwnable_init_unchained();
__ERC721ContractMetadata_init_unchained(name, symbol);
__ReentrancyGuard_init_unchained();
__ERC721SeaDrop_init_unchained(name, symbol, allowedSeaDrop);
__ERC721SeaDrop_init_unchained(name, symbol, allowedSeaDrop);
__ERC721SeaDropRandomOffset_init_unchained(
name,
symbol,
allowedSeaDrop
);
}

function __ERC721SeaDropRandomOffset_init_unchained(
string memory,
string memory,
address,
address[] memory
) internal onlyInitializing {}

/**
* @notice Set the random offset, for a fair metadata reveal. Only callable
* by the owner one time when the total number of minted tokens
Expand Down
Expand Up @@ -16,7 +16,7 @@ abstract contract ERC721AConduitPreapprovedUpgradeable is ERC721AUpgradeable {
*/
function __ERC721AConduitPreapprovedUpgradeable_init_unchained(
string memory name, string memory symbol
) internal onlyInitializing {
) internal onlyInitializingERC721A {
__ERC721A_init_unchained(name, symbol);
}

Expand All @@ -28,6 +28,6 @@ abstract contract ERC721AConduitPreapprovedUpgradeable is ERC721AUpgradeable {
if (operator == _CONDUIT) {
return true;
}
return ERC721A.isApprovedForAll(owner, operator);
return ERC721AUpgradeable.isApprovedForAll(owner, operator);
}
}

0 comments on commit f0bb777

Please sign in to comment.