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

[WIP] Feat: Upgrade Functionality #2

Open
wants to merge 38 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
171fd7a
refactor clearDBForVersion
Whytecrowe Feb 6, 2024
faaeba3
rename current db getter and add another one for deployed version
Whytecrowe Feb 6, 2024
bb93140
draft the BaseUpgradeMission for needed method placeholders and place…
Whytecrowe Feb 6, 2024
8e870b1
add an enum for all the possible operations for upgrade
Whytecrowe Feb 7, 2024
816e1eb
make version an optional field on IContractDbData
Whytecrowe Feb 7, 2024
0a47a31
fix wrongly named DB getters on base mission
Whytecrowe Feb 7, 2024
0b1cb3d
use the new enum in upgrade mission and add dbCopy method
Whytecrowe Feb 7, 2024
a6db753
refactor and make new deployer types for the upgradeProxy calls
Whytecrowe Feb 8, 2024
2690082
add upgradeProxy method that uses hardhat-upgrades under the hood
Whytecrowe Feb 8, 2024
a06fd5e
implement upgrade() method along with implementing other placeholders…
Whytecrowe Feb 8, 2024
e2c4954
extract tx awaiting logic on HardhatDeployer into it's own method and…
Whytecrowe Feb 8, 2024
f7aefa0
remove redundant bytecode comparison and try to rely on upgrades for …
Whytecrowe Feb 8, 2024
ae765c0
install HH related packages as devDeps
Whytecrowe Feb 10, 2024
b005b4d
add include field in tsconfig to only compile src folder
Whytecrowe Feb 10, 2024
deadf03
start refatoring types on HardhatDeployer
Whytecrowe Feb 10, 2024
b87f933
finish retyping HardhatDeployer
Whytecrowe Feb 12, 2024
e27d0c5
remove usage of IHardhatBase and ISignerBase from the main classes an…
Whytecrowe Feb 12, 2024
846c55b
remove IHardhatBase type and fix types in all existing classes
Whytecrowe Feb 12, 2024
04d0467
remove src and test folders from the package
Whytecrowe Feb 12, 2024
17cf776
start fixing tests
Whytecrowe Feb 12, 2024
b39a9cf
specify what goes into the module's package in package.json
Whytecrowe Feb 13, 2024
10aacd8
fix some base types
Whytecrowe Feb 13, 2024
eb1460c
Merge branch 'type-refactor' into feat/upgrade-logic
Whytecrowe Feb 13, 2024
cbe8bd9
add "clean" script and add that to the build
Whytecrowe Feb 13, 2024
a2437ac
fix types and patch holes, remove redundant type args everywhere
Whytecrowe Feb 13, 2024
43782b8
fix incorrect db getter calls
Whytecrowe Feb 16, 2024
f62d9b1
add methods to read all version docs from db
Whytecrowe Feb 16, 2024
af0b4a9
add source maps to tsconfig
Whytecrowe Feb 20, 2024
848cb5f
fix a bug in execute of Upgrade mission
Whytecrowe Feb 20, 2024
d72003a
Merge branch 'master' into feat/upgrade-logic
Whytecrowe Sep 12, 2024
9cab7a0
fix errors after update from master
Whytecrowe Sep 12, 2024
d3f5405
update hardhat and ethers packages
Whytecrowe Sep 12, 2024
b15d55f
fix versioner to archive only at the end of campaign run
Whytecrowe Sep 26, 2024
fdf798f
update eslint config
Whytecrowe Oct 1, 2024
3b03537
add bytecode comparison func draft
Whytecrowe Oct 1, 2024
b184460
start reworking upgrade determination logic after all the testing:
Whytecrowe Oct 1, 2024
5b14e5d
remove redundant deploy await method from deployer
Whytecrowe Oct 3, 2024
8356ca4
refactoring and new logic:
Whytecrowe Oct 3, 2024
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
4 changes: 2 additions & 2 deletions .npmignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
.idea
src
.eslintrc
tsconfig.json
test
src/
test/
.circleci
```
9 changes: 7 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
"npm": ">=9"
},
"scripts": {
"build": "tsc",
"clean": "rm -rf dist",
"build": "yarn clean && tsc",
"prepare": "yarn build",
"lint": "yarn eslint .",
"test": "mocha --require ts-node/register ./test/cases/*.ts"
Expand All @@ -31,7 +32,11 @@
"devDependencies": {
"@types/mocha": "^10.0.6",
"@types/node": "^18.15.11",
"@zero-tech/eslint-config-cpt": "0.2.7",
"ethers": "^6.13.2",
"hardhat": "^2.22.10",
"@openzeppelin/hardhat-upgrades": "^3.2.1",
"@nomicfoundation/hardhat-ethers": "^3.0.8",
"@zero-tech/eslint-config-cpt": "0.2.8",
"eslint": "^8.56.0",
"mocha": "^10.2.0",
"ts-node": "10.9.1",
Expand Down
292 changes: 145 additions & 147 deletions src/campaign/deploy-campaign.ts
Original file line number Diff line number Diff line change
@@ -1,147 +1,145 @@
import {
ICampaignArgs,
ICampaignState,
TLogger,
IMissionInstances,
IContractV6, IDeployCampaignConfig, IContractState,
} from "./types";
import { HardhatDeployer } from "../deployer/hardhat-deployer";
import { ITenderlyContractData, TDeployMissionCtor } from "../missions/types";
import { BaseDeployMission } from "../missions/base-deploy-mission";
import { MongoDBAdapter } from "../db/mongo-adapter/mongo-adapter";
import { IHardhatBase, ISignerBase } from "../deployer/types";
import { makeCampaignProxy } from "./proxy";


export class DeployCampaign <
H extends IHardhatBase,
S extends ISignerBase,
C extends IDeployCampaignConfig<S>,
St extends IContractState<IContractV6>,
> {
state : ICampaignState<H, S, C, St>;
deployer : HardhatDeployer<H, S>;
dbAdapter : MongoDBAdapter;
logger : TLogger;
config : C;

// TODO dep: improve typing here so that methods of each contract type are resolved in Mission classes!
// eslint-disable-next-line @typescript-eslint/no-explicit-any
[name : string | symbol] : any;

constructor ({
missions,
deployer,
dbAdapter,
logger,
config,
} : ICampaignArgs<H, S, C, St>) {
this.state = {
missions,
instances: {},
contracts: {} as St,
};
this.deployer = deployer;
this.dbAdapter = dbAdapter;
this.logger = logger;
this.config = config;

const campaignProxy = makeCampaignProxy(this);

// instantiate all missions
this.state.instances = missions.reduce(
(acc : IMissionInstances<H, S, C, St>, mission : TDeployMissionCtor<H, S, C, St>) => {
const instance = new mission({
campaign: campaignProxy,
logger,
config,
});

acc[instance.instanceName] = instance;
return acc;
},
{}
);

this.logger.info("Deploy Campaign initialized.");

return campaignProxy;
}

async execute () {
this.logger.info("Deploy Campaign execution started.");

await this.dbAdapter.configureVersioning();

await Object.values(this.state.instances).reduce(
async (
acc : Promise<void>,
missionInstance : BaseDeployMission<H, S, C, St>,
) : Promise<void> => {
await acc;
return missionInstance.execute();
},
Promise.resolve()
);

if (this.config.postDeploy.verifyContracts) {
await this.verify();
}

if (this.config.postDeploy.monitorContracts) {
await this.monitor();
}

// eslint-disable-next-line max-len
this.logger.info(`Deploy Campaign execution finished successfully under DB Version: ${this.dbAdapter.versioner.curDbVersion}.`);
}

updateStateContract (instanceName : string, contractName : string, contract : IContractV6) {
// TODO: can we improve this?
(this.state.contracts as IContractState)[instanceName] = contract;
this.logger.debug(`Data of deployed contract '${contractName}' is added to Campaign state at '${instanceName}'.`);
}

async verify () {
return Object.values(this.state.instances).reduce(
async (
acc : Promise<void>,
missionInstance : BaseDeployMission<H, S, C, St>,
) => {
await acc;
return missionInstance.verify();
},
Promise.resolve()
);
}

async monitor () {
this.logger.info("Pushing contracts to Tenderly...");

const contracts = await Object.values(this.state.instances).reduce(
async (
acc : Promise<Array<ITenderlyContractData>>,
missionInstance : BaseDeployMission<H, S, C, St>,
) : Promise<Array<ITenderlyContractData>> => {
const newAcc = await acc;
const data = await missionInstance.getMonitoringData();

return [...newAcc, ...data];
},
Promise.resolve([])
);

try {
const response = await this.deployer.tenderlyPush(contracts);
this.logger.info(
`Tenderly push finished successfully for Project ${this.config.postDeploy.tenderlyProjectSlug}
with data: ${JSON.stringify(response, null, "\t")}`
);
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
} catch (e : any) {
this.logger.error("Tenderly push failed.");
this.logger.error(e.message);
this.logger.debug("Continuing...");
}
}
}
import {
ICampaignArgs,
ICampaignState,
TLogger,
IMissionInstances,
IDeployCampaignConfig, IContractState,
} from "./types";
import { HardhatDeployer } from "../deployer/hardhat-deployer";
import { ITenderlyContractData, TDeployMissionCtor } from "../missions/types";
import { BaseDeployMission } from "../missions/base-deploy-mission";
import { MongoDBAdapter } from "../db/mongo-adapter/mongo-adapter";
import { makeCampaignProxy } from "./proxy";
import { Contract } from "ethers";


export class DeployCampaign <
C extends IDeployCampaignConfig,
St extends IContractState,
> {
state : ICampaignState<C, St>;
deployer : HardhatDeployer;
dbAdapter : MongoDBAdapter;
logger : TLogger;
config : C;

// TODO dep: improve typing here so that methods of each contract type are resolved in Mission classes!
// eslint-disable-next-line @typescript-eslint/no-explicit-any
[name : string | symbol] : any;

constructor ({
missions,
deployer,
dbAdapter,
logger,
config,
} : ICampaignArgs<C, St>) {
this.state = {
missions,
instances: {},
contracts: {} as St,
};
this.deployer = deployer;
this.dbAdapter = dbAdapter;
this.logger = logger;
this.config = config;

const campaignProxy = makeCampaignProxy(this);

// instantiate all missions
this.state.instances = missions.reduce(
(acc : IMissionInstances<C, St>, mission : TDeployMissionCtor<C, St>) => {
const instance = new mission({
campaign: campaignProxy,
logger,
config,
});

acc[instance.instanceName] = instance;
return acc;
},
{}
);

this.logger.info("Deploy Campaign initialized.");

return campaignProxy;
}

async execute () {
this.logger.info("Deploy Campaign execution started.");

await this.dbAdapter.configureVersioning();

await Object.values(this.state.instances).reduce(
async (
acc : Promise<void>,
missionInstance : BaseDeployMission<C, St>,
) : Promise<void> => {
await acc;
return missionInstance.execute();
},
Promise.resolve()
);

if (this.config.postDeploy.verifyContracts) {
await this.verify();
}

if (this.config.postDeploy.monitorContracts) {
await this.monitor();
}

// eslint-disable-next-line max-len
this.logger.info(`Deploy Campaign execution finished successfully under DB Version: ${this.dbAdapter.versioner.curDbVersion}.`);
}

updateStateContract (instanceName : string, contractName : string, contract : Contract) {
// TODO: can we improve this?
(this.state.contracts as IContractState)[instanceName] = contract;
this.logger.debug(`Data of deployed contract '${contractName}' is added to Campaign state at '${instanceName}'.`);
}

async verify () {
return Object.values(this.state.instances).reduce(
async (
acc : Promise<void>,
missionInstance : BaseDeployMission<C, St>,
) => {
await acc;
return missionInstance.verify();
},
Promise.resolve()
);
}

async monitor () {
this.logger.info("Pushing contracts to Tenderly...");

const contracts = await Object.values(this.state.instances).reduce(
async (
acc : Promise<Array<ITenderlyContractData>>,
missionInstance : BaseDeployMission<C, St>,
) : Promise<Array<ITenderlyContractData>> => {
const newAcc = await acc;
const data = await missionInstance.getMonitoringData();

return [...newAcc, ...data];
},
Promise.resolve([])
);

try {
const response = await this.deployer.tenderlyPush(contracts);
this.logger.info(
`Tenderly push finished successfully for Project ${this.config.postDeploy.tenderlyProjectSlug}
with data: ${JSON.stringify(response, null, "\t")}`
);
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
} catch (e : any) {
this.logger.error("Tenderly push failed.");
this.logger.error(e.message);
this.logger.debug("Continuing...");
}
}
}
41 changes: 19 additions & 22 deletions src/campaign/proxy.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,19 @@
import { IHardhatBase, ISignerBase } from "../deployer/types";
import { DeployCampaign } from "./deploy-campaign";
import { IContractState, IDeployCampaignConfig } from "./types";

export const makeCampaignProxy = <
H extends IHardhatBase,
S extends ISignerBase,
C extends IDeployCampaignConfig<S>,
St extends IContractState,
> (campaign : DeployCampaign<H, S, C, St>) => new Proxy(campaign, {
get : (target, prop) => {
if (typeof prop === "string") {
if (!!target.state.contracts[prop]) {
return target.state.contracts[prop];
}

if (!!target[prop]) {
return target[prop];
}
}
},
});
import { DeployCampaign } from "./deploy-campaign";
import { IContractState, IDeployCampaignConfig } from "./types";

export const makeCampaignProxy = <
C extends IDeployCampaignConfig,
St extends IContractState,
> (campaign : DeployCampaign<C, St>) => new Proxy(campaign, {
get : (target, prop) => {
if (typeof prop === "string") {
if (!!target.state.contracts[prop]) {
return target.state.contracts[prop];
}

if (!!target[prop]) {
return target[prop];
}
}
},
});
Loading