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

Use ethers and add machine-readable output for contract deployment #303

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
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
29 changes: 27 additions & 2 deletions hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { NetworkUserConfig } from 'hardhat/types';

import 'dotenv/config';

import '@nomicfoundation/hardhat-toolbox-viem';
import '@nomicfoundation/hardhat-chai-matchers';
import '@openzeppelin/hardhat-upgrades';

Expand Down Expand Up @@ -54,7 +53,10 @@ const config: HardhatUserConfig = {
},
},
etherscan: {
apiKey: process.env.ETHERSCAN_KEY,
apiKey: {
'holesky': process.env.ETHERSCAN_KEY,
'devnet': 'x',
},
customChains: [
{
network: 'holesky',
Expand All @@ -64,6 +66,14 @@ const config: HardhatUserConfig = {
browserURL: 'https://holesky.etherscan.io',
},
},
{
network: 'devnet',
chainId: 3151908,
urls: {
apiURL: `${process.env.BLOCKSCOUT_URL}/api`,
browserURL: process.env.BLOCKSCOUT_URL,
},
}
],
},
contractSizer: {
Expand All @@ -86,6 +96,7 @@ const config: HardhatUserConfig = {
},
};


if (process.env.HOLESKY_ETH_NODE_URL && process.env.HOLESKY_OWNER_PRIVATE_KEY) {
const sharedConfig = {
url: `${process.env.HOLESKY_ETH_NODE_URL}${process.env.NODE_PROVIDER_KEY}`,
Expand Down Expand Up @@ -135,4 +146,18 @@ if (process.env.FORK_TESTING_ENABLED) {
};
}

if (process.env.DEVNET_ETH_NODE_URL) {
config.networks = {
devnet: {
chainId: 3151908,
url: `${process.env.DEVNET_ETH_NODE_URL}`,
accounts: [
"39725efee3fb28614de3bacaffe4cc4bd8c436257e2c8bb887c4b5c4be45e76d",
],
gasPrice: +(process.env.GAS_PRICE || ''),
gas: +(process.env.GAS || ''),
} as NetworkUserConfig,
};
}

export default config;
119 changes: 84 additions & 35 deletions tasks/deploy.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { task, subtask, types } from 'hardhat/config';
import { SSVModules } from './config';


/**
@title Hardhat task to deploy all required contracts for SSVNetwork.
This task deploys the main SSVNetwork and SSVNetworkViews contracts, along with their associated modules.
Expand All @@ -15,30 +16,51 @@ The deployer account used will be the first one returned by ethers.getSigners().
Therefore, it should be appropriately configured in your Hardhat network configuration.
This task assumes that the SSVModules enum and deployment tasks for individual contracts have been properly defined.
*/
task('deploy:all', 'Deploy SSVNetwork, SSVNetworkViews and module contracts').setAction(async ({}, hre) => {
// Triggering compilation
await hre.run('compile');
task('deploy:all', 'Deploy SSVNetwork, SSVNetworkViews and module contracts')
.addOptionalParam('machine', 'outputs the machine readable output', false, types.boolean)
.setAction(async (args, hre) => {
if (!args.machine) {
// Triggering compilation if this is manual
await hre.run('compile');
}

const [deployer] = await ethers.getSigners();
console.log(`Deploying contracts with the account:${deployer.address}`);
if (!args.machine){
const [deployer] = await ethers.getSigners();
deployer.address = deployer.address.toLowerCase();
console.log(`Deploying contracts with the account:${deployer.address}`);
}

const ssvTokenAddress = await hre.run('deploy:mock-token');
const operatorsModAddress = await hre.run('deploy:module', { module: SSVModules[SSVModules.SSVOperators] });
const clustersModAddress = await hre.run('deploy:module', { module: SSVModules[SSVModules.SSVClusters] });
const daoModAddress = await hre.run('deploy:module', { module: SSVModules[SSVModules.SSVDAO] });
const viewsModAddress = await hre.run('deploy:module', { module: SSVModules[SSVModules.SSVViews] });
const ssvTokenAddress = await hre.run('deploy:token', { machine: args.machine });
const operatorsModAddress = await hre.run('deploy:module', { module: SSVModules[SSVModules.SSVOperators], machine: args.machine });
const clustersModAddress = await hre.run('deploy:module', { module: SSVModules[SSVModules.SSVClusters], machine: args.machine });
const daoModAddress = await hre.run('deploy:module', { module: SSVModules[SSVModules.SSVDAO], machine: args.machine });
const viewsModAddress = await hre.run('deploy:module', { module: SSVModules[SSVModules.SSVViews], machine: args.machine });

const { ssvNetworkProxyAddress: ssvNetworkAddress } = await hre.run('deploy:ssv-network', {
operatorsModAddress,
clustersModAddress,
daoModAddress,
viewsModAddress,
ssvTokenAddress,
machine: args.machine,
});

await hre.run('deploy:ssv-network-views', {
ssvNetworkAddress,
machine: args.machine,
});

if (args.machine) {
const jsonData = {
ssvTokenAddress,
operatorsModAddress,
clustersModAddress,
daoModAddress,
viewsModAddress,
ssvNetworkAddress,
}
console.log(JSON.stringify(jsonData));
}
});

/**
Expand Down Expand Up @@ -92,27 +114,35 @@ This subtask uses the "deploy:impl" subtask for the actual deployment.
*/
subtask('deploy:module', 'Deploys a new module contract')
.addParam('module', 'SSV Module', null, types.string)
.setAction(async ({ module }, hre) => {
.addOptionalParam('machine', 'outputs the machine readable output', false, types.boolean)
.setAction(async ({ module, machine }, hre) => {
const moduleValues = Object.values(SSVModules);
if (!moduleValues.includes(module)) {
throw new Error(`Invalid SSVModule: ${module}. Expected one of: ${moduleValues.join(', ')}`);
}

const moduleAddress = await hre.run('deploy:impl', { contract: module });
const moduleAddress = await hre.run('deploy:impl', { contract: module, machine: machine });
return moduleAddress;
});

task('deploy:token', 'Deploys SSV Token').setAction(async ({}, hre) => {
// Triggering compilation
await hre.run('compile');

console.log('Deploying SSV Network Token');
task('deploy:token', 'Deploys SSV Token')
.addOptionalParam('machine', 'outputs the machine readable output', false, types.boolean)
.setAction(async (args, hre) => {
if (!args.machine){
// Triggering compilation if this is manual
await hre.run('compile');
console.log('Deploying SSV Network Token');
}

const ssvTokenFactory = await ethers.getContractFactory('SSVToken');
const ssvToken = await ssvTokenFactory.deploy();
await ssvToken.deployed();
await ssvToken.waitForDeployment();

console.log(`SSV Network Token deployed to: ${ssvToken.address}`);
if (!args.machine){
console.log(`SSV Network Token deployed to: ${ssvToken.address}`);
}

return await ssvToken.getAddress()
});

/**
Expand All @@ -126,9 +156,12 @@ subtask('deploy:mock-token', 'Deploys / fetch SSV Token').setAction(async ({}, h
if (tokenAddress) return tokenAddress;

// Local networks, deploy mock token
const ssvToken = await hre.viem.deployContract('SSVToken');
// const ssvToken = await hre.viem.deployContract('SSVToken');
const ssvTokenFactory = await ethers.getContractFactory('SSVToken');
const ssvToken = await ssvTokenFactory.deployContract();
await ssvToken.waitForDeployment();

return ssvToken.address;
return await ssvToken.getAddress();
});

/**
Expand All @@ -144,15 +177,22 @@ The contract specified should be already compiled and exist in the 'artifacts' d
*/
subtask('deploy:impl', 'Deploys an implementation contract')
.addParam('contract', 'New contract implemetation', null, types.string)
.setAction(async ({ contract }, hre) => {
// Triggering compilation
await hre.run('compile');

.addOptionalParam('machine', 'outputs the machine readable output', false, types.boolean)
.setAction(async (args, hre) => {
if (!args.machine){
// Triggering compilation if this is manual
await hre.run('compile');
}
// Deploy implemetation contract
const contractImpl = await hre.viem.deployContract(contract);
console.log(`${contract} implementation deployed to: ${contractImpl.address}`);
const contractFactory = await ethers.getContractFactory(args.contract);
const contractImpl = await contractFactory.deploy();
await contractImpl.waitForDeployment();

return contractImpl.address;
if (!args.machine){
console.log(`${args.contract} implementation deployed to: ${await contractImpl.getAddress()}`);
}

return await contractImpl.getAddress();
});

/**
Expand All @@ -178,11 +218,15 @@ subtask('deploy:ssv-network', 'Deploys SSVNetwork contract')
.addPositionalParam('daoModAddress', 'DAO module address', null, types.string)
.addPositionalParam('viewsModAddress', 'Views module address', null, types.string)
.addPositionalParam('ssvTokenAddress', 'SSV Token address', null, types.string)
.setAction(async ({ operatorsModAddress, clustersModAddress, daoModAddress, viewsModAddress, ssvTokenAddress }) => {
.addOptionalParam('machine', 'outputs the machine readable output', false, types.boolean)
.setAction(async ({ operatorsModAddress, clustersModAddress, daoModAddress, viewsModAddress, ssvTokenAddress, machine }) => {
const ssvNetworkFactory = await ethers.getContractFactory('SSVNetwork');

// deploy SSVNetwork
console.log(`Deploying SSVNetwork with ssvToken ${ssvTokenAddress}`);
if (!machine){
console.log(`Deploying SSVNetwork with ssvToken ${ssvTokenAddress}`);
}

const ssvNetwork = await upgrades.deployProxy(
ssvNetworkFactory,
[
Expand All @@ -207,8 +251,10 @@ subtask('deploy:ssv-network', 'Deploys SSVNetwork contract')
const ssvNetworkProxyAddress = await ssvNetwork.getAddress();
const ssvNetworkImplAddress = await upgrades.erc1967.getImplementationAddress(ssvNetworkProxyAddress);

console.log(`SSVNetwork proxy deployed to: ${ssvNetworkProxyAddress}`);
console.log(`SSVNetwork implementation deployed to: ${ssvNetworkImplAddress}`);
if (!machine) {
console.log(`SSVNetwork proxy deployed to: ${ssvNetworkProxyAddress}`);
console.log(`SSVNetwork implementation deployed to: ${ssvNetworkImplAddress}`);
}

return { ssvNetworkProxyAddress, ssvNetworkImplAddress };
});
Expand All @@ -226,7 +272,8 @@ The 'SSVNetworkViews' contract specified should be already compiled and exist in
*/
subtask('deploy:ssv-network-views', 'Deploys SSVNetworkViews contract')
.addParam('ssvNetworkAddress', 'SSVNetwork address', null, types.string)
.setAction(async ({ ssvNetworkAddress }) => {
.addOptionalParam('machine', 'outputs the machine readable output', false, types.boolean)
.setAction(async ({ ssvNetworkAddress, machine }) => {
const ssvNetworkViewsFactory = await ethers.getContractFactory('SSVNetworkViews');

// deploy SSVNetwork
Expand All @@ -238,8 +285,10 @@ subtask('deploy:ssv-network-views', 'Deploys SSVNetworkViews contract')
const ssvNetworkViewsProxyAddress = await ssvNetworkViews.getAddress();
const ssvNetworkViewsImplAddress = await upgrades.erc1967.getImplementationAddress(ssvNetworkViewsProxyAddress);

console.log(`SSVNetworkViews proxy deployed to: ${ssvNetworkViewsProxyAddress}`);
console.log(`SSVNetworkViews implementation deployed to: ${ssvNetworkViewsImplAddress}`);
if (!machine){
console.log(`SSVNetworkViews proxy deployed to: ${ssvNetworkViewsProxyAddress}`);
console.log(`SSVNetworkViews implementation deployed to: ${ssvNetworkViewsImplAddress}`);
}

return { ssvNetworkViewsProxyAddress, ssvNetworkViewsImplAddress };
});
Loading