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

Integrating hardhat-ledger support #731

Merged
merged 6 commits into from
Apr 30, 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
68 changes: 65 additions & 3 deletions packages/hardhat-plugin/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ import {
StatusResult,
} from "@nomicfoundation/ignition-core";
import {
ensureDir,
pathExists,
readFile,
readdirSync,
rm,
pathExists,
writeJSON,
ensureDir,
readFile,
} from "fs-extra";
import { extendConfig, extendEnvironment, scope } from "hardhat/config";
import { NomicLabsHardhatPluginError } from "hardhat/plugins";
Expand Down Expand Up @@ -257,6 +257,37 @@ ignitionScope
const strategyConfig = hre.config.ignition.strategyConfig?.[strategyName];

try {
try {
await hre.network.provider.send("hardhat_setLedgerOutputEnabled", [
false,
]);

hre.network.provider.once(
"connection_start",
executionEventListener.ledgerConnectionStart
);
hre.network.provider.once(
"connection_success",
executionEventListener.ledgerConnectionSuccess
);
hre.network.provider.once(
"connection_failure",
executionEventListener.ledgerConnectionFailure
);
hre.network.provider.on(
"confirmation_start",
executionEventListener.ledgerConfirmationStart
);
hre.network.provider.on(
"confirmation_success",
executionEventListener.ledgerConfirmationSuccess
);
hre.network.provider.on(
"confirmation_failure",
executionEventListener.ledgerConfirmationFailure
);
} catch {}

const result = await deploy({
config: hre.config.ignition,
provider: hre.network.provider,
Expand All @@ -273,6 +304,37 @@ ignitionScope
hre.config.networks[hre.network.name]?.ignition.maxFeePerGasLimit,
});

try {
await hre.network.provider.send("hardhat_setLedgerOutputEnabled", [
true,
]);

hre.network.provider.off(
"connection_start",
executionEventListener.ledgerConnectionStart
);
zoeyTM marked this conversation as resolved.
Show resolved Hide resolved
hre.network.provider.off(
"connection_success",
executionEventListener.ledgerConnectionSuccess
);
hre.network.provider.off(
"connection_failure",
executionEventListener.ledgerConnectionFailure
);
hre.network.provider.off(
"confirmation_start",
executionEventListener.ledgerConfirmationStart
);
hre.network.provider.off(
"confirmation_success",
executionEventListener.ledgerConfirmationSuccess
);
hre.network.provider.off(
"confirmation_failure",
executionEventListener.ledgerConfirmationFailure
);
} catch {}

if (result.type === "SUCCESSFUL_DEPLOYMENT" && verify) {
console.log("");
console.log(chalk.bold("Verifying deployed contracts"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export function calculateBatchDisplay(state: UiState): {
height: number;
} {
const batch = state.batches[state.currentBatch - 1];
const height = batch.length + 2;
const height = batch.length + (state.ledgerMessageIsDisplayed ? 4 : 2);

let text = `Batch #${state.currentBatch}\n`;

Expand All @@ -16,6 +16,10 @@ export function calculateBatchDisplay(state: UiState): {

text += "\n";

if (state.ledger) {
text += `\n Ledger: ${state.ledgerMessage}\n`;
}

return { text, height };
}

Expand Down
92 changes: 88 additions & 4 deletions packages/hardhat-plugin/src/ui/pretty-event-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,15 @@ export class PrettyEventHandler implements ExecutionEventListener {
maxFeeBumps: 0,
gasBumps: {},
strategy: null,
ledger: false,
ledgerMessage: "",
ledgerMessageIsDisplayed: false,
};

constructor(private _deploymentParams: DeploymentParameters = {}) {}
constructor(
private _deploymentParams: DeploymentParameters = {},
private _disableOutput = false
) {}

public get state(): UiState {
return this._uiState;
Expand Down Expand Up @@ -309,6 +315,77 @@ export class PrettyEventHandler implements ExecutionEventListener {
};
}

public ledgerConnectionStart(): void {
this.state = {
...this.state,
ledger: true,
ledgerMessage: "Connecting wallet",
};

this._redisplayCurrentBatch();

this.state = {
...this.state,
ledgerMessageIsDisplayed: true,
kanej marked this conversation as resolved.
Show resolved Hide resolved
};
}

public ledgerConnectionSuccess(): void {
this.state = {
...this.state,
ledgerMessage: "Wallet connected",
};

this._redisplayCurrentBatch();
}

public ledgerConnectionFailure(): void {
this.state = {
...this.state,
ledgerMessage: "Wallet connection failed",
};

this._redisplayCurrentBatch();
}

public ledgerConfirmationStart(): void {
this.state = {
...this.state,
ledger: true,
ledgerMessage: "Waiting for confirmation on device",
};

this._redisplayCurrentBatch();

this.state = {
...this.state,
ledgerMessageIsDisplayed: true,
};
}

public ledgerConfirmationSuccess(): void {
this.state = {
...this.state,
ledgerMessage: "Transaction approved by device",
};

this._redisplayCurrentBatch();

this.state = {
...this.state,
ledger: false,
};
}

public ledgerConfirmationFailure(): void {
this.state = {
...this.state,
ledgerMessage: "Transaction confirmation failed",
};

this._redisplayCurrentBatch();
}

private _setFutureStatusInitializedAndRedisplayBatch({
futureId,
}: {
Expand All @@ -330,6 +407,11 @@ export class PrettyEventHandler implements ExecutionEventListener {
futureId,
this._getFutureStatusFromEventResult(result)
);

this.state = {
...this.state,
ledgerMessageIsDisplayed: false,
};
}

private _setFutureStatusAndRedisplayBatch(
Expand Down Expand Up @@ -454,11 +536,13 @@ export class PrettyEventHandler implements ExecutionEventListener {
}

private _redisplayCurrentBatch() {
const { height, text: batch } = calculateBatchDisplay(this.state);
if (!this._disableOutput) {
const { height, text: batch } = calculateBatchDisplay(this.state);

this._clearUpToHeight(height);
this._clearUpToHeight(height);

console.log(batch);
console.log(batch);
}
}

private _clearCurrentLine(): void {
Expand Down
3 changes: 3 additions & 0 deletions packages/hardhat-plugin/src/ui/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ export interface UiState {
maxFeeBumps: number;
gasBumps: Record<string, number>;
strategy: string | null;
ledger: boolean;
ledgerMessage: string;
ledgerMessageIsDisplayed: boolean;
}

export interface AddressMap {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ const exampleState: UiState = {
maxFeeBumps: 0,
gasBumps: {},
strategy: null,
ledger: false,
ledgerMessage: "",
ledgerMessageIsDisplayed: false,
};

describe("ui - calculate batch display", () => {
Expand Down Expand Up @@ -179,16 +182,44 @@ describe("ui - calculate batch display", () => {
expectedText
);
});

it("should render a batch when using a ledger device", () => {
const expectedText = testFormat(`
Batch #1
Executing ExampleModule#Token...

Ledger: Waiting for confirmation on device
zoeyTM marked this conversation as resolved.
Show resolved Hide resolved
`);

assertBatchText(
[
{
status: {
type: UiFutureStatusType.UNSTARTED,
},
futureId: "ExampleModule#Token",
},
],
3,
expectedText,
{
ledger: true,
ledgerMessage: "Waiting for confirmation on device",
}
);
});
});

function assertBatchText(
batch: UiFuture[],
expectedHeight: number,
expectedText: string
expectedText: string,
extraState?: Partial<UiState>
) {
const { text: actualText, height } = calculateBatchDisplay({
...exampleState,
batches: [batch],
...extraState,
});

assert.equal(height, expectedHeight);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ describe("ui - calculate starting message display", () => {
maxFeeBumps: 0,
gasBumps: {},
strategy: "basic",
ledger: false,
ledgerMessage: "",
ledgerMessageIsDisplayed: false,
kanej marked this conversation as resolved.
Show resolved Hide resolved
};

it("should display the deploying module message", () => {
Expand Down
72 changes: 72 additions & 0 deletions packages/hardhat-plugin/test/ui/pretty-event-handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { assert } from "chai";

import { PrettyEventHandler } from "../../src/ui/pretty-event-handler";

describe("ui - pretty event handler", () => {
describe("ledger", () => {
it("should set a message on connection start", () => {
const eventHandler = new PrettyEventHandler(undefined, true);

eventHandler.ledgerConnectionStart();

assert.equal(eventHandler.state.ledgerMessage, "Connecting wallet");
assert.isTrue(eventHandler.state.ledger);
assert.isTrue(eventHandler.state.ledgerMessageIsDisplayed);
});

it("should set a message on connection success", () => {
const eventHandler = new PrettyEventHandler(undefined, true);

eventHandler.ledgerConnectionSuccess();

assert.equal(eventHandler.state.ledgerMessage, "Wallet connected");
});

it("should set a message on connection failure", () => {
const eventHandler = new PrettyEventHandler(undefined, true);

eventHandler.ledgerConnectionFailure();

assert.equal(
eventHandler.state.ledgerMessage,
"Wallet connection failed"
);
});

it("should set a message on confirmation start", () => {
const eventHandler = new PrettyEventHandler(undefined, true);

eventHandler.ledgerConfirmationStart();

assert.equal(
eventHandler.state.ledgerMessage,
"Waiting for confirmation on device"
);
assert.isTrue(eventHandler.state.ledger);
assert.isTrue(eventHandler.state.ledgerMessageIsDisplayed);
});

it("should set a message on confirmation success", () => {
const eventHandler = new PrettyEventHandler(undefined, true);

eventHandler.ledgerConfirmationSuccess();

assert.equal(
eventHandler.state.ledgerMessage,
"Transaction approved by device"
);
assert.isFalse(eventHandler.state.ledger);
});

it("should set a message on confirmation failure", () => {
const eventHandler = new PrettyEventHandler(undefined, true);

eventHandler.ledgerConfirmationFailure();

assert.equal(
eventHandler.state.ledgerMessage,
"Transaction confirmation failed"
);
});
});
});
Loading