Skip to content

Commit

Permalink
Overall UX improvements (#48)
Browse files Browse the repository at this point in the history
* Returned unused parameter

* Updated README

* Updated version

* Fixed await this._overrideConnectMethod(contract);

* Clarified error

* Optimized network usage

* Improved UX with TruffleReporter

* Improved deployed function

* Deleted redundant _waitForDeployment

* fixes due to Reporter optimizations

* Added new line before summary

* Updated version

* Resolved errors related to verifier

* Add one-second delay before next attempt
  • Loading branch information
KyrylR authored Oct 28, 2023
1 parent b2bad04 commit 2334351
Show file tree
Hide file tree
Showing 10 changed files with 99 additions and 64 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@solarity/hardhat-migrate",
"version": "2.0.0-alpha.5",
"version": "2.0.0-alpha.6",
"description": "Automatic deployment and verification of smart contracts",
"main": "dist/src/index.js",
"types": "dist/src/index.d.ts",
Expand Down
28 changes: 19 additions & 9 deletions src/deployer/Deployer.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Signer } from "ethers";
import { isAddress, Signer } from "ethers";

import { HardhatRuntimeEnvironment } from "hardhat/types";

Expand Down Expand Up @@ -40,21 +40,31 @@ export class Deployer {

public async deployed<T, A = T, I = any>(
contract: Instance<A, I> | (T extends Truffle.Contract<I> ? T : never),
contractAddress?: string,
contractIdentifier?: string,
): Promise<I> {
const adapter = this._resolveAdapter(contract);
const contractName = adapter.getContractName(contract, {});
const defaultContractName = adapter.getContractName(contract, {});

if (contractAddress) {
if (!(await isDeployedContractAddress(contractAddress))) {
throw new MigrateError(`Contract with address '${contractAddress}' is not deployed`);
let contractAddress;

if (contractIdentifier === undefined) {
contractAddress = await TransactionProcessor.tryRestoreContractAddressByName(defaultContractName);

return adapter.toInstance(contract, contractAddress, {});
}

if (isAddress(contractIdentifier)) {
if (!(await isDeployedContractAddress(contractIdentifier))) {
throw new MigrateError(`Contract with address '${contractIdentifier}' is not deployed`);
}

TransactionProcessor.saveDeploymentTransactionWithContractName(contractName, contractAddress);
} else {
contractAddress = await TransactionProcessor.tryRestoreContractAddressByName(contractName);
TransactionProcessor.saveDeploymentTransactionWithContractName(defaultContractName, contractIdentifier);

return adapter.toInstance(contract, contractIdentifier, {});
}

contractAddress = await TransactionProcessor.tryRestoreContractAddressByName(contractIdentifier);

return adapter.toInstance(contract, contractAddress, {});
}

Expand Down
35 changes: 14 additions & 21 deletions src/deployer/MinimalContract.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ethers, Interface, Overrides, Signer, TransactionResponse } from "ethers";
import { ethers, Interface, Overrides, Signer } from "ethers";

import { Linker } from "./Linker";

Expand Down Expand Up @@ -107,34 +107,27 @@ export class MinimalContract {

const txResponse = await signer.sendTransaction(tx);

const [contractAddress] = await Promise.all([
this._waitForDeployment(txResponse),
Reporter.reportTransaction(txResponse, tx.contractName),
]);
await Reporter.reportTransaction(txResponse, tx.contractName);

const contractAddress = (await txResponse.wait(0))!.contractAddress;

if (typeof contractAddress !== "string") {
throw new MigrateError("Contract deployment failed. Invalid contract address conversion.");
}

TransactionProcessor.saveDeploymentTransaction(tx, tx.contractName, contractAddress);

VerificationProcessor.saveVerificationFunction({
contractAddress,
contractName: tx.contractName,
constructorArguments: args,
chainId: Number(await getChainId()),
});

return contractAddress;
}

private async _waitForDeployment(tx: TransactionResponse): Promise<string> {
const receipt = await tx.wait(this._config.wait);

if (receipt) {
return receipt.contractAddress!;
try {
VerificationProcessor.saveVerificationFunction({
contractAddress,
contractName: ArtifactProcessor.tryGetContractName(this._bytecode),
constructorArguments: args,
chainId: Number(await getChainId()),
});
} catch {
Reporter.reportVerificationFailedToSave(tx.contractName);
}

throw new MigrateError("Contract deployment failed.");
return contractAddress;
}
}
2 changes: 2 additions & 0 deletions src/deployer/adapters/TruffleAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,8 @@ export class TruffleAdapter extends Adapter {

const methodString = getMethodString(contractName, methodName);

TruffleReporter.notifyTransactionSending(methodString);

if (this._config.continue) {
return this._recoverTransaction(methodString, onlyToSaveTx, oldMethod, args);
}
Expand Down
5 changes: 3 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { Provider } from "./tools/Provider";
import { Verifier } from "./verifier/Verifier";

export { Deployer } from "./deployer/Deployer";
export { Reporter } from "./tools/reporters/Reporter";
export { DefaultStorage } from "./tools/storage/MigrateStorage";

extendConfig(migrateConfigExtender);
Expand All @@ -33,7 +34,7 @@ const migrate: ActionType<MigrateConfig> = async (taskArgs, env) => {
env.config.migrate = mergeConfigs(taskArgs, env.config.migrate);

Linker.setConfig(env.config.migrate);
Reporter.init(env.config.migrate);
await Reporter.init(env.config.migrate);

// Make sure that contract artifacts are up-to-date.
await env.run(TASK_COMPILE, {
Expand All @@ -57,7 +58,7 @@ const migrate: ActionType<MigrateConfig> = async (taskArgs, env) => {
const migrateVerify: ActionType<MigrateVerifyConfig> = async (taskArgs, env) => {
const config = extendVerifyConfigs(taskArgs);

Reporter.init(env.config.migrate);
await Reporter.init(env.config.migrate);

await new Verifier(env, config).verifyBatch(
VerificationProcessor.restoreSavedVerificationFunctions(config.inputFile),
Expand Down
60 changes: 38 additions & 22 deletions src/tools/reporters/Reporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,26 @@ import { ChainRecord, predefinedChains } from "../../types/verifier";
@catchError
export class Reporter {
private static _config: MigrateConfig;
private static _network: Network;
private static _nativeSymbol: string;
private static _explorerUrl: string;

private static totalCost: bigint = 0n;
private static totalTransactions: number = 0;

public static init(config: MigrateConfig) {
public static async init(config: MigrateConfig) {
this._config = config;

this._network = await this._getNetwork();

this._nativeSymbol = await this._getNativeSymbol();
this._explorerUrl = (await this._getExplorerUrl()) + "/tx/";
}

public static async reportMigrationBegin(files: string[]) {
public static reportMigrationBegin(files: string[]) {
this._reportMigrationFiles(files);

await this._reportChainInfo();
this._reportChainInfo();

console.log("\nStarting migration...\n");
}
Expand All @@ -36,12 +44,12 @@ export class Reporter {
console.log(`\n${underline(`Running ${file}...`)}`);
}

public static async summary() {
public static summary() {
const output =
`> ${"Total transactions:".padEnd(20)} ${this.totalTransactions}\n` +
`> ${"Final cost:".padEnd(20)} ${this.castAmount(this.totalCost, await this._getNativeSymbol())}\n`;
`> ${"Final cost:".padEnd(20)} ${this.castAmount(this.totalCost, this._nativeSymbol)}\n`;

console.log(output);
console.log(`\n${output}`);
}

public static async reportTransactionByHash(txHash: string, instanceName: string) {
Expand All @@ -66,6 +74,7 @@ export class Reporter {

const spinner = ora(await formatPendingTimeTask()).start();

// TODO: make 1000 configurable
const spinnerInterval = setInterval(async () => (spinner.text = await formatPendingTimeTask()), 1000);

let receipt: TransactionReceipt;
Expand Down Expand Up @@ -138,6 +147,21 @@ export class Reporter {
console.log(output);
}

public static reportVerificationFailedToSave(contractName: string) {
const output = `\nFailed to save verification arguments for contract: ${contractName}\n`;

console.log(output);
}

public static reportContracts(...contracts: [string, string][]): void {
const table: { Contract: string; Address: string }[] = contracts.map(([contract, address]) => ({
Contract: contract,
Address: address,
}));
console.table(table);
console.log();
}

private static _parseTransactionTitle(tx: TransactionResponse, instanceName: string): string {
if (tx.to === null) {
if (instanceName.split(":").length == 1) {
Expand All @@ -160,8 +184,8 @@ export class Reporter {
}; Seconds: ${((Date.now() - startTime) / 1000).toFixed(0)}`;
}

private static async _getExplorerLink(txHash: string): Promise<string> {
return (await this._getExplorerUrl()) + "/tx/" + txHash;
private static _getExplorerLink(txHash: string): string {
return this._explorerUrl + txHash;
}

private static async _printTransaction(tx: TransactionReceipt) {
Expand All @@ -171,7 +195,7 @@ export class Reporter {
output += `> contractAddress: ${tx.contractAddress}\n`;
}

const nativeSymbol = await this._getNativeSymbol();
const nativeSymbol = this._nativeSymbol;

output += `> blockNumber: ${tx.blockNumber}\n`;

Expand Down Expand Up @@ -214,10 +238,10 @@ export class Reporter {
console.log("");
}

private static async _reportChainInfo() {
console.log(`> ${"Network:".padEnd(20)} ${(await this._getNetwork()).name}`);
private static _reportChainInfo() {
console.log(`> ${"Network:".padEnd(20)} ${this._network.name}`);

console.log(`> ${"Network id:".padEnd(20)} ${await this._getChainId()}`);
console.log(`> ${"Network id:".padEnd(20)} ${this._network.chainId}`);
}

private static async _getNetwork(): Promise<Network> {
Expand All @@ -228,16 +252,8 @@ export class Reporter {
}
}

private static async _getChainId(): Promise<number> {
try {
return Number((await this._getNetwork()).chainId);
} catch {
return 1337;
}
}

private static async _getExplorerUrl(): Promise<string> {
const chainId = await this._getChainId();
const chainId = Number(this._network.chainId);

if (predefinedChains[chainId]) {
const explorers = predefinedChains[chainId].explorers;
Expand All @@ -251,7 +267,7 @@ export class Reporter {
}

private static async _getNativeSymbol(): Promise<string> {
const chainId = await this._getChainId();
const chainId = Number(this._network.chainId);

if (predefinedChains[chainId]) {
return predefinedChains[chainId].nativeCurrency.symbol;
Expand Down
5 changes: 5 additions & 0 deletions src/tools/reporters/TruffleReporter.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable no-console */
import { Reporter } from "./Reporter";

import { TruffleTransactionResponse } from "../../types/deployer";
Expand All @@ -8,4 +9,8 @@ export class TruffleReporter {

await Reporter.reportTransactionByHash(hash, instanceName);
}

public static notifyTransactionSending(methodString: string) {
console.log(`> ${methodString} is being sent...`);
}
}
8 changes: 7 additions & 1 deletion src/tools/storage/TransactionProcessor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { validateKeyDeploymentFields, validateKeyTxFields } from "../../types/ty
export class TransactionProcessor {
private static _deployedContracts: Map<string, boolean> = new Map();

@catchError
@validateKeyDeploymentFields
public static saveDeploymentTransaction(args: ContractDeployTransaction, contractName: string, address: string) {
this._saveContract(args, address);
Expand All @@ -44,6 +45,7 @@ export class TransactionProcessor {
);
}

@catchError
@validateKeyDeploymentFields
public static async tryRestoreContractAddressByKeyFields(key: ContractDeployTransaction): Promise<string> {
const contractAddress = this._tryGetDataFromStorage(
Expand All @@ -62,6 +64,7 @@ export class TransactionProcessor {
return contractAddress;
}

@catchError
public static async tryRestoreContractAddressByName(contractName: string): Promise<string> {
const contractAddress = this._tryGetDataFromStorage(contractName);

Expand All @@ -72,6 +75,7 @@ export class TransactionProcessor {
return contractAddress;
}

@catchError
@validateKeyTxFields
public static tryRestoreSavedTransaction(key: KeyTransactionFields): ContractTransactionResponse {
if (this._deployedContracts.has(key.to)) {
Expand All @@ -89,6 +93,7 @@ export class TransactionProcessor {
);
}

@catchError
@validateKeyTxFields
private static _saveTransaction(args: KeyTransactionFields, transaction: KeyTransactionFields) {
TransactionStorage.set(
Expand All @@ -104,6 +109,7 @@ export class TransactionProcessor {
);
}

@catchError
@validateKeyDeploymentFields
private static _saveContract(args: ContractDeployTransaction, contractAddress: string) {
this._deployedContracts.set(contractAddress, true);
Expand All @@ -128,7 +134,7 @@ export class TransactionProcessor {
const value = TransactionStorage.get(key);

if (!value) {
throw new MigrateError(`Transaction not found in storage`);
throw new MigrateError(`Requested data not found in storage`);
}

return value;
Expand Down
12 changes: 7 additions & 5 deletions src/verifier/Verifier.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,19 +32,21 @@ export class Verifier {

const instance = await this._getEtherscanInstance(this._hre);

if (await instance.isVerified(contractAddress)) {
Reporter.reportAlreadyVerified(contractAddress, contractName);
for (let attempts = 0; attempts < this._config.attempts; attempts++) {
if (await instance.isVerified(contractAddress)) {
Reporter.reportAlreadyVerified(contractAddress, contractName);

return;
}
break;
}

for (let attempts = 0; attempts < this._config.attempts; attempts++) {
try {
await this._tryVerify(instance, contractAddress, contractName, constructorArguments);
break;
} catch (e: any) {
this._handleVerificationError(contractAddress, contractName, e);
}

await new Promise((resolve) => setTimeout(resolve, 1000));
}
}

Expand Down
Loading

0 comments on commit 2334351

Please sign in to comment.