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

Add an ability to change signer during the migration #79

Merged
merged 4 commits into from
Jun 21, 2024
Merged
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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## Version 2.1.10

* Added an ability to change signer during the migration

## Version 2.1.9

* Updated dependencies
Expand Down
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,14 @@ Facilitates sending native assets to a specified address, primarily for the reco

---

- **setSigner(from <- optional)**:

Sets the signer for the following transactions and deployments.

If the `from` parameter is not specified, the signer is reset to the default.

---

- **getSigner(from <- optional)**:

Retrieves an ethers signer for use in migrations.
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

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.1.9",
"version": "2.1.10",
"description": "Automatic deployment and verification of smart contracts",
"main": "dist/src/index.js",
"types": "dist/src/index.d.ts",
Expand Down
13 changes: 9 additions & 4 deletions src/deployer/Deployer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { isAddress, Signer } from "ethers";

import { HardhatRuntimeEnvironment } from "hardhat/types";

import { catchError, getChainId, getSignerHelper, isDeployedContractAddress } from "../utils";
import { catchError, getChainId, isDeployedContractAddress } from "../utils";

import { MigrateError } from "../errors";

Expand All @@ -21,6 +21,7 @@ import { isContractFactory, isEthersContract, isBytecodeFactory, isTruffleFactor

import { Stats } from "../tools/Stats";
import { Reporter } from "../tools/reporters/Reporter";
import { networkManager } from "../tools/network/NetworkManager";
import { TransactionRunner } from "../tools/runners/TransactionRunner";
import { TransactionProcessor } from "../tools/storage/TransactionProcessor";

Expand Down Expand Up @@ -103,7 +104,7 @@ export class Deployer {
value: bigint,
name: string = SEND_NATIVE_TX_NAME,
): Promise<TransactionFieldsToSave> {
const signer = await getSignerHelper();
const signer = await networkManager!.getSigner();

const tx = await this._buildSendTransaction(to, value, name);

Expand Down Expand Up @@ -138,8 +139,12 @@ export class Deployer {
return savedTx!;
}

public async setSigner(from?: string) {
await networkManager!.setSigner(from);
}

public async getSigner(from?: string): Promise<Signer> {
return getSignerHelper(from);
return networkManager!.getSigner(from);
}

public async getChainId(): Promise<bigint> {
Expand All @@ -152,7 +157,7 @@ export class Deployer {
value,
chainId: await getChainId(),
data: "0x",
from: (await getSignerHelper()).address,
from: (await networkManager!.getSigner()).address,
name,
};
}
Expand Down
7 changes: 4 additions & 3 deletions src/deployer/MinimalContract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { isFullyQualifiedName } from "hardhat/utils/contract-names";

import { Linker } from "./Linker";

import { catchError, fillParameters, getChainId, getInterfaceOnlyWithConstructor, getSignerHelper } from "../utils";
import { catchError, fillParameters, getChainId, getInterfaceOnlyWithConstructor } from "../utils";

import { MigrateError } from "../errors";

Expand All @@ -15,6 +15,7 @@ import { ContractDeployTxWithName, OverridesAndLibs } from "../types/deployer";

import { Stats } from "../tools/Stats";
import { Reporter } from "../tools/reporters/Reporter";
import { networkManager } from "../tools/network/NetworkManager";
import { TransactionRunner } from "../tools/runners/TransactionRunner";
import { ArtifactProcessor } from "../tools/storage/ArtifactProcessor";
import { TransactionProcessor } from "../tools/storage/TransactionProcessor";
Expand Down Expand Up @@ -77,7 +78,7 @@ export class MinimalContract {
return {
contractName: this._contractName,
chainId: await getChainId(),
from: (await getSignerHelper(txOverrides.from)).address,
from: (await networkManager!.getSigner(txOverrides.from)).address,
...(await factory.getDeployTransaction(...args, txOverrides)),
};
}
Expand All @@ -101,7 +102,7 @@ export class MinimalContract {
}

private async _processContractDeploymentTransaction(tx: ContractDeployTxWithName, args: any[]): Promise<string> {
const signer: Signer = await getSignerHelper(tx.from);
const signer: Signer = await networkManager!.getSigner(tx.from);

const txResponse = await signer.sendTransaction(tx);

Expand Down
7 changes: 4 additions & 3 deletions src/deployer/adapters/AbstractEthersAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,15 @@ import "../../type-extensions";

import { UNKNOWN_TRANSACTION_NAME } from "../../constants";

import { bytecodeToString, fillParameters, getMethodString, getSignerHelper } from "../../utils";
import { bytecodeToString, fillParameters, getMethodString } from "../../utils";

import { OverridesAndLibs, OverridesAndName } from "../../types/deployer";
import { EthersContract, BytecodeFactory } from "../../types/adapter";
import { KeyTransactionFields, MigrationMetadata, TransactionFieldsToSave } from "../../types/tools";

import { Stats } from "../../tools/Stats";
import { Reporter } from "../../tools/reporters/Reporter";
import { networkManager } from "../../tools/network/NetworkManager";
import { TransactionRunner } from "../../tools/runners/TransactionRunner";
import { TransactionProcessor } from "../../tools/storage/TransactionProcessor";

Expand All @@ -46,7 +47,7 @@ export abstract class AbstractEthersAdapter extends Adapter {
}

public async toInstance<A, I>(instance: Factory<A, I>, address: string, parameters: OverridesAndLibs): Promise<I> {
const signer = await getSignerHelper(parameters.from);
const signer = await networkManager!.getSigner(parameters.from);
const contractName = this.getContractName(instance, parameters);

let contract = new BaseContract(address, this.getInterface(instance), signer);
Expand Down Expand Up @@ -102,7 +103,7 @@ export abstract class AbstractEthersAdapter extends Adapter {
contractInterface: Interface,
contractName: string,
): Promise<BaseContract> {
const defaultRunner = await getSignerHelper();
const defaultRunner = await networkManager!.getSigner();

contract.connect = (runner: ContractRunner | null): BaseContract => {
const newContract = new BaseContract(contract.target, contractInterface, runner ?? defaultRunner);
Expand Down
14 changes: 4 additions & 10 deletions src/deployer/adapters/TruffleAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,7 @@ import { Adapter } from "./Adapter";

import { MinimalContract } from "../MinimalContract";

import {
bytecodeToString,
catchError,
fillParameters,
getInstanceNameFromClass,
getMethodString,
getSignerHelper,
} from "../../utils";
import { bytecodeToString, catchError, fillParameters, getInstanceNameFromClass, getMethodString } from "../../utils";

import { UNKNOWN_TRANSACTION_NAME } from "../../constants";

Expand All @@ -31,6 +24,7 @@ import { OverridesAndName, TruffleTransactionResponse } from "../../types/deploy

import { Stats } from "../../tools/Stats";
import { Reporter } from "../../tools/reporters/Reporter";
import { networkManager } from "../../tools/network/NetworkManager";
import { TransactionRunner } from "../../tools/runners/TransactionRunner";
import { ArtifactProcessor } from "../../tools/storage/ArtifactProcessor";
import { TransactionProcessor } from "../../tools/storage/TransactionProcessor";
Expand Down Expand Up @@ -133,14 +127,14 @@ export class TruffleAdapter extends Adapter {
const tx = await contractMethod.populateTransaction(...args);

// In case if the `from` field is not specified, it should be filled with the default signer.
tx.from = tx.from ?? (await getSignerHelper()).address;
tx.from = tx.from ?? (await networkManager!.getSigner()).address;

await fillParameters(tx);

const keyFields = this._getKeyFieldsFromTransaction(tx, contractMethod, args);

// Connect to signer and get method again with signer
contractMethod = ethersBaseContract.connect(await getSignerHelper(tx.from)).getFunction(methodName);
contractMethod = ethersBaseContract.connect(await networkManager!.getSigner(tx.from)).getFunction(methodName);

const methodString = getMethodString(contractName, methodName, contractMethod.fragment, args);

Expand Down
18 changes: 18 additions & 0 deletions src/tools/network/NetworkManager.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import axios, { Axios } from "axios";
import { AddressLike, ethers } from "ethers";

import { HardhatEthersSigner } from "@nomicfoundation/hardhat-ethers/signers";
import type { HardhatEthersProvider as HardhatEthersProviderT } from "@nomicfoundation/hardhat-ethers/internal/hardhat-ethers-provider";

import { HardhatRuntimeEnvironment } from "hardhat/types";
Expand Down Expand Up @@ -61,11 +63,27 @@ class NetworkManager {
public axios: Axios;
public provider: HardhatEthersProviderT;

private currentFrom: string | undefined = undefined;

constructor() {
this.axios = this.withRetry(axios);
this.provider = this.withRetry(ethersProvider!);
}

public async getSigner(from?: null | AddressLike): Promise<HardhatEthersSigner> {
if (!from) {
return this.provider.getSigner(this.currentFrom);
}

const address = await ethers.resolveAddress(from, this.provider);

return this.provider.getSigner(address);
}

public async setSigner(from?: AddressLike): Promise<void> {
this.currentFrom = from ? await ethers.resolveAddress(from, this.provider) : undefined;
}

public withRetry<T extends { [key: string]: any }>(instance: T): T {
return new Proxy(instance, {
get(target, propKey, receiver) {
Expand Down
14 changes: 1 addition & 13 deletions src/utils/network.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { AddressLike, ethers, toBigInt } from "ethers";

import { HardhatEthersSigner } from "@nomicfoundation/hardhat-ethers/signers";
import { toBigInt } from "ethers";

import { networkManager } from "../tools/network/NetworkManager";

Expand All @@ -11,13 +9,3 @@ export async function getChainId(): Promise<bigint> {
export async function isDeployedContractAddress(address: string): Promise<boolean> {
return (await networkManager!.provider.getCode(address)) !== "0x";
}

export async function getSignerHelper(from?: null | AddressLike): Promise<HardhatEthersSigner> {
if (!from) {
return networkManager!.provider.getSigner();
}

const address = await ethers.resolveAddress(from, networkManager!.provider);

return networkManager!.provider.getSigner(address);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Deployer } from "../../../../src/deployer/Deployer";

import { GovToken__factory } from "../typechain-types";

export = async (deployer: Deployer) => {
await deployer.setSigner("0x70997970C51812dc3A010C7d01b50e0d17dc79C8");

await deployer.deploy(GovToken__factory, ["Token", "TKN"], { name: "Governance Token #12" });

const govToken5 = await deployer.deployed(GovToken__factory, "Governance Token #12");

if ((await govToken5.owner()) !== "0x70997970C51812dc3A010C7d01b50e0d17dc79C8") {
console.error("Owner is not set correctly");
process.exit(1);
}

await deployer.setSigner();

const newToken = await deployer.deploy(GovToken__factory, ["Token", "TKN"], { name: "Governance Token #13" });

if ((await newToken.owner()) !== "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266") {
console.error("Owner is not set correctly");
process.exit(1);
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Deployer } from "../../../../src/deployer/Deployer";

export = async (deployer: Deployer) => {
// Moved here for testing reasons, before it was initialized globally once and failed on the second test on the .link function.
// Because Truffle throws an error if attempting to link the same object twice to the same library.
const GovToken = artifacts.require("GovToken");

await deployer.setSigner("0x70997970C51812dc3A010C7d01b50e0d17dc79C8");

await deployer.deploy(GovToken, ["Token", "TKN"], { name: "Governance Token #12" });

const govToken5 = await deployer.deployed(GovToken, "Governance Token #12");

if ((await govToken5.owner()) !== "0x70997970C51812dc3A010C7d01b50e0d17dc79C8") {
console.error("Owner is not set correctly");
process.exit(1);
}

await deployer.setSigner();

const newToken = await deployer.deploy(GovToken, ["Token", "TKN"], { name: "Governance Token #13" });

if ((await newToken.owner()) !== "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266") {
console.error("Owner is not set correctly");
process.exit(1);
}
};
10 changes: 10 additions & 0 deletions test/integration/migration/typechain-ethers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,14 @@ describe("typechain-ethers", () => {
await runWithContinue(hre, 3);
});
});

describe("migration flow for edge cases", () => {
it("should run migration successfully", async function () {
await runWithoutContinue(hre, 4);
});

it("should recover migration successfully", async function () {
await runWithContinue(hre, 4);
});
});
});
10 changes: 10 additions & 0 deletions test/integration/migration/typechain-truffle.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,14 @@ describe("typechain-truffle", () => {
await runWithContinue(hre, 3);
});
});

describe("migration flow for different signers", () => {
it("should run migration successfully", async function () {
await runWithoutContinue(hre, 4);
});

it("should recover migration successfully", async function () {
await runWithContinue(hre, 4);
});
});
});
Loading