Skip to content

Commit

Permalink
Merge pull request #1132 from privacy-scaling-explorations/docs/contr…
Browse files Browse the repository at this point in the history
…act-deployment

docs(contracts): add documentation for deployment workflow
  • Loading branch information
0xmad authored Jan 30, 2024
2 parents ea7a3f3 + 243690e commit ef8af2a
Show file tree
Hide file tree
Showing 18 changed files with 245 additions and 2 deletions.
1 change: 1 addition & 0 deletions contracts/hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import "solidity-docgen";

import type { HardhatUserConfig } from "hardhat/config";

// Don't forget to import new tasks here
import "./tasks/deploy";
import { EChainId, ESupportedChains, NETWORKS_DEFAULT_GAS, getNetworkRpcUrls } from "./tasks/helpers/constants";
import "./tasks/runner/deployFull";
Expand Down
3 changes: 3 additions & 0 deletions contracts/tasks/deploy/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import fs from "fs";
import path from "path";

/**
* The same as individual imports but doesn't require to add new import line everytime
*/
["maci"].forEach((folder) => {
const tasksPath = path.resolve(__dirname, folder);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ const DEFAULT_INITIAL_VOICE_CREDITS = 99;
const deployment = Deployment.getInstance();
const storage = ContractStorage.getInstance();

/**
* Deploy step registration and task itself
*/
deployment
.deployTask("full:deploy-constant-initial-voice-credit-proxy", "Deploy constant initial voice credit proxy")
.setAction(
Expand Down
3 changes: 3 additions & 0 deletions contracts/tasks/deploy/maci/02-freeForAllSignUpGatekeeper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import { EContracts, IDeployParams } from "../../helpers/types";
const deployment = Deployment.getInstance();
const storage = ContractStorage.getInstance();

/**
* Deploy step registration and task itself
*/
deployment
.deployTask("full:deploy-free-for-all-signup-gatekeeper", "Deploy constant initial voice credit proxy")
.setAction(async ({ incremental }: IDeployParams, hre) => {
Expand Down
3 changes: 3 additions & 0 deletions contracts/tasks/deploy/maci/03-verifier.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import { EContracts, IDeployParams } from "../../helpers/types";
const deployment = Deployment.getInstance();
const storage = ContractStorage.getInstance();

/**
* Deploy step registration and task itself
*/
deployment
.deployTask("full:deploy-verifier", "Deploy verifier")
.setAction(async ({ incremental }: IDeployParams, hre) => {
Expand Down
3 changes: 3 additions & 0 deletions contracts/tasks/deploy/maci/04-topupCredit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import { EContracts, IDeployParams } from "../../helpers/types";
const deployment = Deployment.getInstance();
const storage = ContractStorage.getInstance();

/**
* Deploy step registration and task itself
*/
deployment
.deployTask("full:deploy-topup-credit", "Deploy topup credit")
.setAction(async ({ incremental }: IDeployParams, hre) => {
Expand Down
3 changes: 3 additions & 0 deletions contracts/tasks/deploy/maci/05-poseidon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import { EContracts, IDeployParams } from "../../helpers/types";
const deployment = Deployment.getInstance();
const storage = ContractStorage.getInstance();

/**
* Deploy step registration and task itself
*/
deployment
.deployTask("full:deploy-poseidon", "Deploy poseidon contracts")
.setAction(async ({ incremental }: IDeployParams, hre) => {
Expand Down
3 changes: 3 additions & 0 deletions contracts/tasks/deploy/maci/06-pollFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import { EContracts, IDeployParams } from "../../helpers/types";
const deployment = Deployment.getInstance();
const storage = ContractStorage.getInstance();

/**
* Deploy step registration and task itself
*/
deployment
.deployTask("full:deploy-poll-factory", "Deploy poll factory")
.setAction(async ({ incremental }: IDeployParams, hre) => {
Expand Down
3 changes: 3 additions & 0 deletions contracts/tasks/deploy/maci/07-messageProcessorFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import { EContracts, IDeployParams } from "../../helpers/types";
const deployment = Deployment.getInstance();
const storage = ContractStorage.getInstance();

/**
* Deploy step registration and task itself
*/
deployment
.deployTask("full:deploy-message-processor-factory", "Deploy message processor factory")
.setAction(async ({ incremental }: IDeployParams, hre) => {
Expand Down
3 changes: 3 additions & 0 deletions contracts/tasks/deploy/maci/08-tallyFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import { EContracts, IDeployParams } from "../../helpers/types";
const deployment = Deployment.getInstance();
const storage = ContractStorage.getInstance();

/**
* Deploy step registration and task itself
*/
deployment
.deployTask("full:deploy-tally-factory", "Deploy tally factory")
.setAction(async ({ incremental }: IDeployParams, hre) => {
Expand Down
3 changes: 3 additions & 0 deletions contracts/tasks/deploy/maci/09-subsidyFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import { EContracts, IDeployParams } from "../../helpers/types";
const deployment = Deployment.getInstance();
const storage = ContractStorage.getInstance();

/**
* Deploy step registration and task itself
*/
deployment
.deployTask("full:deploy-subsidy-factory", "Deploy subsidy factory")
.setAction(async ({ incremental }: IDeployParams, hre) => {
Expand Down
3 changes: 3 additions & 0 deletions contracts/tasks/deploy/maci/10-maci.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import { EContracts, IDeployParams } from "../../helpers/types";
const deployment = Deployment.getInstance();
const storage = ContractStorage.getInstance();

/**
* Deploy step registration and task itself
*/
deployment
.deployTask("full:deploy-maci", "Deploy MACI contract")
.setAction(async ({ incremental, stateTreeDepth }: IDeployParams, hre) => {
Expand Down
79 changes: 77 additions & 2 deletions contracts/tasks/helpers/ContractStorage.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
/* eslint-disable import/no-extraneous-dependencies */
/* eslint-disable no-console */
/* eslint-disable import/no-extraneous-dependencies, no-console */
import low from "lowdb";
import FileSync from "lowdb/adapters/FileSync";

import type { EContracts, IRegisterContract, IStorageInstanceEntry, IStorageNamedEntry } from "./types";

/**
* Internal storage structure type.
* named: contracts can be queried by name
* instance: contract can be queried by address
* verified: mark contracts which are already verified
*/
type TStorage = Record<
string,
Partial<{
Expand All @@ -14,15 +19,33 @@ type TStorage = Record<
}>
>;

/**
* @notice Contract storage keeps all deployed contracts with addresses, arguments in the json file.
* This class is using for incremental deployment and verification.
*/
export class ContractStorage {
/**
* Singleton instance for class
*/
private static INSTANCE?: ContractStorage;

/**
* Json file database instance
*/
private db: low.LowdbSync<TStorage>;

/**
* Initialize class properties only once
*/
private constructor() {
this.db = low(new FileSync<TStorage>("./deployed-contracts.json"));
}

/**
* Get singleton object
*
* @returns {ContractStorage} singleton object
*/
static getInstance(): ContractStorage {
if (!ContractStorage.INSTANCE) {
ContractStorage.INSTANCE = new ContractStorage();
Expand All @@ -31,6 +54,11 @@ export class ContractStorage {
return ContractStorage.INSTANCE;
}

/**
* Register contract and save contract address, constructor args in the json file
*
* @param {IRegisterContract} args - register arguments
*/
async register({ id, contract, network, args }: IRegisterContract): Promise<void> {
const contractAddress = await contract.getAddress();

Expand Down Expand Up @@ -72,28 +100,63 @@ export class ContractStorage {
.write();
}

/**
* Get contract instances from the json file
*
* @param network - selected network
* @returns {[string, IStorageInstanceEntry][]} storage instance entries
*/
getInstances(network: string): [string, IStorageInstanceEntry][] {
const collection = this.db.get(`${network}.instance`);
const value = collection.value() as IStorageInstanceEntry[] | undefined;

return Object.entries<IStorageInstanceEntry>(value || []);
}

/**
* Check if contract is verified or not locally
*
* @param address - contract address
* @param network - selected network
* @returns contract verified or not
*/
getVerified(address: string, network: string): boolean {
return this.db.get(`${network}.verified.${address}`).value() as unknown as boolean;
}

/**
* Set contract verification in the json file
*
* @param address - contract address
* @param network - selected network
* @param verified - verified or not
*/
setVerified = (address: string, network: string, verified: boolean): void => {
this.db.set(`${network}.verified.${address}`, verified).write();
};

/**
* Get contract address by name from the json file
*
* @param id - contract name
* @param network - selected network
* @returns contract address
*/
getAddress(id: EContracts, network: string): string | undefined {
const collection = this.db.get(`${network}.named.${id}`);
const namedEntry = collection.value() as IStorageNamedEntry | undefined;

return namedEntry?.address;
}

/**
* Get contract address by name from the json file
*
* @param id - contract name
* @param network - selected network
* @throws {Error} if there is no address the error will be thrown
* @returns contract address
*/
mustGetAddress(id: EContracts, network: string): string {
const address = this.getAddress(id, network);

Expand All @@ -104,6 +167,13 @@ export class ContractStorage {
return address;
}

/**
* Get contract from the json file with sizes and multi count
*
* @param deployer - deployer address
* @param network - selected network
* @returns {[entries: Map<string, string>, length: number, multiCount: number]}
*/
printContracts(deployer: string, network: string): [Map<string, string>, number, number] {
console.log("Contracts deployed at", network, "by", deployer);
console.log("---------------------------------");
Expand Down Expand Up @@ -135,6 +205,11 @@ export class ContractStorage {
return [entryMap, instanceEntries.length, multiCount];
}

/**
* Clean json file for selected network
*
* @param network - selected network
*/
cleanup(network: string): void {
this.db.set(network, {}).write();
}
Expand Down
19 changes: 19 additions & 0 deletions contracts/tasks/helpers/ContractVerifier.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,32 @@
import type { IVerificationSubtaskArgs } from "./types";
import type { HardhatRuntimeEnvironment, Libraries } from "hardhat/types";

/**
* @notice Contract verifier allows to verify contract using hardhat-etherscan plugin.
*/
export class ContractVerifier {
/**
* Hardhat runtime environment
*/
private hre: HardhatRuntimeEnvironment;

/**
* Initialize class properties
*
* @param hre - Hardhat runtime environment
*/
constructor(hre: HardhatRuntimeEnvironment) {
this.hre = hre;
}

/**
* Verify contract through etherscan
*
* @param address - contract address
* @param constructorArguments - stringified constructor arguments
* @param libraries - stringified libraries which can't be detected automatically
* @returns
*/
async verify(address: string, constructorArguments: string, libraries?: string): Promise<[boolean, string]> {
const params: IVerificationSubtaskArgs = {
address,
Expand Down
Loading

0 comments on commit ef8af2a

Please sign in to comment.