Skip to content
Open
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
3 changes: 3 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
GOERLI_RPC=
PRIVATE_KEY1=
ETHERSCAN=
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
out
artifacts
node_modules
cache
cache
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,12 @@ $ forge t
Bonus: The [DiamondLoupefacet](contracts/facets/DiamondLoupeFacet.sol) uses an updated [LibDiamond](contracts/libraries//LibDiamond.sol) which utilises solidity custom errors to make debugging easier especially when upgrading diamonds. Take it for a spin!!

Need some more clarity? message me [on twitter](https://twitter.com/Timidan_x), Or join the [EIP-2535 Diamonds Discord server](https://discord.gg/kQewPw2)


### Verify

This addition to the template allows you to verify your contracts on deployment.
An example `.env: .env.example` and hardhat config `example.hardhat.config.js` has been provided
To verify, you need to include your etherscan API included.

Enjoy
21 changes: 21 additions & 0 deletions example.hardhat.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
const dotenv = require('dotenv');
dotenv.config();
/**
* @type import('hardhat/config').HardhatUserConfig
*/

require('@nomiclabs/hardhat-ethers');
module.exports = {
solidity: '0.8.18',
defaultNetwork: "goerli",
networks: {
goerli: {
url: process.env.GOERLI_RPC,
accounts: [process.env.PRIVATE_KEY1]
}
},
etherscan: {
apiKey: process.env.ETHERSCAN,
customChains: [],
}
}
7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
"name": "hardhat-project",
"dependencies": {
"@nomiclabs/hardhat-ethers": "^2.0.6",
"ethers": "^5.6.9"
"@nomiclabs/hardhat-etherscan": "^3.1.7",
"dotenv": "^16.0.3",
"ethers": "^5.6.9",
"hardhat": "^2.13.0"
}
}
}
115 changes: 115 additions & 0 deletions scripts/deployAndVerify.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
const { getSelectors, FacetCutAction } = require('./libraries/diamond.js');
const { ethers, network, run } = require('hardhat');
require("@nomiclabs/hardhat-etherscan");


const verify = async (contractAddress, args) => {
console.log("Verifying contract...");
try {
await run("verify:verify", {
address: contractAddress,
constructorArguments: args,
});
} catch (e) {
if (e.message.toLowerCase().includes("already verified")) {
console.log("Already verified!");
} else {
console.log(e);
}
}
};

async function deployAndVerifyDiamond() {
const accounts = await ethers.getSigners();
const contractOwner = accounts[0];
const chainId = network.config.chainId;

// deploy DiamondCutFacet
const DiamondCutFacet = await ethers.getContractFactory('DiamondCutFacet')
const diamondCutFacet = await DiamondCutFacet.deploy()
await diamondCutFacet.deployed()
console.log('DiamondCutFacet deployed:', diamondCutFacet.address);

// verify DiamondCutFacet
console.log(`Waiting for blocks confirmations...`);
await diamondCutFacet.deployTransaction.wait(6);
await verify(diamondCutFacet.address, []);
console.log(`Confirmed!`);



// deploy Diamond
const Diamond = await ethers.getContractFactory('Diamond')
const diamond = await Diamond.deploy(
contractOwner.address,
diamondCutFacet.address,
)
await diamond.deployed()
console.log('Diamond deployed:', diamond.address)

// verify Diamond
console.log(`Waiting for blocks confirmations...`);
await diamond.deployTransaction.wait(6);
await verify(diamond.address, [contractOwner.address,
diamondCutFacet.address,]);
console.log(`Confirmed!`);

// deploy DiamondInit
// DiamondInit provides a function that is called when the diamond is upgraded to initialize state variables
// Read about how the diamondCut function works here: https://eips.ethereum.org/EIPS/eip-2535#addingreplacingremoving-functions
const DiamondInit = await ethers.getContractFactory('DiamondInit');
const diamondInit = await DiamondInit.deploy()
await diamondInit.deployed()
console.log('DiamondInit deployed:', diamondInit.address)

// deploy facets
console.log('')
console.log('Deploying facets')
const FacetNames = ['DiamondLoupeFacet', 'OwnershipFacet']
const cut = []
for (const FacetName of FacetNames) {
const Facet = await ethers.getContractFactory(FacetName)
const facet = await Facet.deploy()
await facet.deployed()
console.log(`${FacetName} deployed: ${facet.address}`)

// verify facet
console.log(`Waiting for blocks confirmations...`);
await facet.deployTransaction.wait(6);
await verify(facet.address, []);
console.log(`Confirmed!`);
cut.push({
facetAddress: facet.address,
action: FacetCutAction.Add,
functionSelectors: getSelectors(facet),
})
}

// upgrade diamond with facets
console.log('')
console.log('Diamond Cut:', cut)
const diamondCut = await ethers.getContractAt('IDiamondCut', diamond.address)
let tx
let receipt
// call to init function
let functionCall = diamondInit.interface.encodeFunctionData('init')
tx = await diamondCut.diamondCut(cut, diamondInit.address, functionCall)
console.log('Diamond cut tx: ', tx.hash)
receipt = await tx.wait()
if (!receipt.status) {
throw Error(`Diamond upgrade failed: ${tx.hash}`)
}
console.log('Completed diamond cut')
return diamond.address
}

if (require.main === module) {
deployAndVerifyDiamond()
.then(() => process.exit(0))
.catch((error) => {
console.error(error)
process.exit(1)
})
}

exports.deployAndVerifyDiamond = deployAndVerifyDiamond