Skip to content

Commit

Permalink
Add Advanced Sample Project with TypeScript
Browse files Browse the repository at this point in the history
  • Loading branch information
feuGeneA committed Aug 10, 2021
1 parent 130a0c1 commit d15141f
Show file tree
Hide file tree
Showing 10 changed files with 278 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "advanced-typescript-project",
"version": "1.0.0",
"license": "MIT",
"dependencies": {}
}
33 changes: 33 additions & 0 deletions packages/e2e/test/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,5 +113,38 @@ describe("e2e tests", function () {
});
}
});

describe("advanced TypeScript sample project", function () {
useFixture("advanced-ts-sample-project");

before(function () {
shell.exec(`${hardhatBinary}`, {
env: {
...process.env,
HARDHAT_CREATE_ADVANCED_TYPESCRIPT_SAMPLE_PROJECT_WITH_DEFAULTS: "true",
},
});
});

for (const suggestedCommand of [
// This list should be kept reasonably in sync with
// hardhat-core/sample-projects/advanced-ts/README.txt
`${hardhatBinary} compile`,
`${hardhatBinary} test`,
`${hardhatBinary} run scripts/deploy.ts`,
"ts-node scripts/deploy.ts",
"REPORT_GAS=true npx hardhat test",
`${hardhatBinary} coverage`,
"npx eslint '**/*.{ts,js}'",
"npx eslint '**/*.{ts,js}' --fix",
"npx prettier '**/*.{json,sol,md}' --check",
"npx solhint 'contracts/**/*.sol'",
"npx solhint 'contracts/**/*.sol' --fix",
]) {
it(`should permit successful execution of the suggested command "${suggestedCommand}"`, async function () {
shell.exec(suggestedCommand);
});
}
});
});
});
38 changes: 38 additions & 0 deletions packages/hardhat-core/sample-projects/advanced-ts/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
module.exports = {
env: {
browser: false,
es2021: true,
mocha: true,
node: true,
},
plugins: ["@typescript-eslint"],
extends: [
"standard",
"plugin:prettier/recommended",
"plugin:node/recommended",
],
parser: "@typescript-eslint/parser",
parserOptions: {
ecmaVersion: 12,
},
overrides: [
{
files: ["scripts/**"],
rules: { "no-process-exit": "off" },
},
{
files: ["hardhat.config.ts", "scripts/**", "test/**"],
globals: { hre: true },
rules: {
"node/no-unpublished-import": "off",
"node/no-unpublished-require": "off",
},
},
],
rules: {
"node/no-unsupported-features/es-syntax": [
"error",
{ ignores: ["modules"] },
],
},
};
42 changes: 42 additions & 0 deletions packages/hardhat-core/sample-projects/advanced-ts/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Advanced Sample Hardhat Project

This project demonstrates an advanced Hardhat use case, integrating other tools commonly used alongside Hardhat in the ecosystem.

The project comes with a sample contract, a test for that contract, a sample script that deploys that contract, and an example of a task implementation, which simply lists the available accounts. It also comes with a variety of other tools, preconfigured to work with the project code.

Try running some of the following tasks:

```shell
npx hardhat accounts
npx hardhat compile
npx hardhat clean
npx hardhat test
npx hardhat node
npx hardhat help
REPORT_GAS=true npx hardhat test
npx hardhat coverage
npx hardhat run scripts/deploy.js
npx ts-node scripts/deploy.js
npx eslint '**/*.{js,ts}'
npx eslint '**/*.{js,ts}' --fix
npx prettier '**/*.{json,sol,md}' --check
npx prettier '**/*.{json,sol,md}' --write
npx solhint 'contracts/**/*.sol'
npx solhint 'contracts/**/*.sol' --fix
```

# Etherscan verification

To try out Etherscan verification, you first need to deploy a contract to an Ethereum network that's supported by Etherscan, such as Ropsten.

In this project, copy the .env.template file to a file named .env, and then edit it to fill in the details. Enter your Etherscan API key, your Ropsten node URL (eg from Alchemy), and the private key of the account which will send the deployment transaction. With a valid .env file in place, first deploy your contract:

```shell
hardhat run --network ropsten scripts/sample-script.js
```

Then, copy the deployment address and paste it in to replace `DEPLOYED_CONTRACT_ADDRESS` in this command:

```shell
npx hardhat verify --network ropsten DEPLOYED_CONTRACT_ADDRESS "Hello, Hardhat!"
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import * as dotenv from "dotenv";

import { HardhatUserConfig, task } from "hardhat/config";
import "@nomiclabs/hardhat-etherscan";
import "@nomiclabs/hardhat-waffle";
import "@typechain/hardhat";
import "hardhat-gas-reporter";
import "solidity-coverage";

dotenv.config();

// This is a sample Hardhat task. To learn how to create your own go to
// https://hardhat.org/guides/create-task.html
task("accounts", "Prints the list of accounts", async (taskArgs, hre) => {
const accounts = await hre.ethers.getSigners();

for (const account of accounts) {
console.log(account.address);
}
});

// You need to export an object to set up your config
// Go to https://hardhat.org/config/ to learn more

const config: HardhatUserConfig = {
solidity: "0.8.4",
networks: {
ropsten: {
url: process.env.ROPSTEN_URL || "",
accounts: [process.env.PRIVATE_KEY || `0x${"0".repeat(40)}`],
},
},
gasReporter: {
enabled: process.env.REPORT_GAS !== undefined,
currency: "USD",
},
etherscan: {
apiKey: process.env.ETHERSCAN_API_KEY,
},
};

export default config;
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// We require the Hardhat Runtime Environment explicitly here. This is optional
// but useful for running the script in a standalone fashion through `node <script>`.
//
// When running the script with `npx hardhat run <script>` you'll find the Hardhat
// Runtime Environment's members available in the global scope.
import { hre } from "hardhat";

async function main() {
// Hardhat always runs the compile task when running scripts with its command
// line interface.
//
// If this script is run directly using `node` you may want to call compile
// manually to make sure everything is compiled
// await hre.run('compile');

// We get the contract to deploy
const Greeter = await hre.ethers.getContractFactory("Greeter");
const greeter = await Greeter.deploy("Hello, Hardhat!");

await greeter.deployed();

console.log("Greeter deployed to:", greeter.address);
}

// We recommend this pattern to be able to use async/await everywhere
// and properly handle errors.
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});
19 changes: 19 additions & 0 deletions packages/hardhat-core/sample-projects/advanced-ts/test/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { expect } from "chai";
import { ethers } from "hardhat";

describe("Greeter", function () {
it("Should return the new greeting once it's changed", async function () {
const Greeter = await ethers.getContractFactory("Greeter");
const greeter = await Greeter.deploy("Hello, world!");
await greeter.deployed();

expect(await greeter.greet()).to.equal("Hello, world!");

const setGreetingTx = await greeter.setGreeting("Hola, mundo!");

// wait until the transaction is mined
await setGreetingTx.wait();

expect(await greeter.greet()).to.equal("Hola, mundo!");
});
});
12 changes: 12 additions & 0 deletions packages/hardhat-core/sample-projects/advanced-ts/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"compilerOptions": {
"target": "es2018",
"module": "commonjs",
"strict": true,
"esModuleInterop": true,
"outDir": "dist",
"declaration": true
},
"include": ["./scripts", "./test", "./typechain"],
"files": ["./hardhat.config.ts"]
}
3 changes: 3 additions & 0 deletions packages/hardhat-core/src/internal/cli/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@ async function main() {
process.env.HARDHAT_CREATE_BASIC_SAMPLE_PROJECT_WITH_DEFAULTS !==
undefined ||
process.env.HARDHAT_CREATE_ADVANCED_SAMPLE_PROJECT_WITH_DEFAULTS !==
undefined ||
process.env
.HARDHAT_CREATE_ADVANCED_TYPESCRIPT_SAMPLE_PROJECT_WITH_DEFAULTS !==
undefined)
) {
await createProject();
Expand Down
55 changes: 51 additions & 4 deletions packages/hardhat-core/src/internal/cli/project-creation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,15 @@ import { emoji } from "./emoji";
enum Action {
CREATE_BASIC_SAMPLE_PROJECT_ACTION = "Create a basic sample project",
CREATE_ADVANCED_SAMPLE_PROJECT_ACTION = "Create an advanced sample project",
CREATE_ADVANCED_TYPESCRIPT_SAMPLE_PROJECT_ACTION = "Create an advanced sample project that uses TypeScript",
CREATE_EMPTY_HARDHAT_CONFIG_ACTION = "Create an empty hardhat.config.js",
QUIT_ACTION = "Quit",
}

type SampleProjectTypeCreationAction =
| Action.CREATE_BASIC_SAMPLE_PROJECT_ACTION
| Action.CREATE_ADVANCED_SAMPLE_PROJECT_ACTION;
| Action.CREATE_ADVANCED_SAMPLE_PROJECT_ACTION
| Action.CREATE_ADVANCED_TYPESCRIPT_SAMPLE_PROJECT_ACTION;

interface Dependencies {
[name: string]: string;
Expand Down Expand Up @@ -60,11 +62,26 @@ const ADVANCED_SAMPLE_PROJECT_DEPENDENCIES: Dependencies = {
"solidity-coverage": "^0.7.16",
};

const ADVANCED_TYPESCRIPT_SAMPLE_PROJECT_DEPENDENCIES: Dependencies = {
...ADVANCED_SAMPLE_PROJECT_DEPENDENCIES,
"@typechain/ethers-v5": "^7.0.1",
"@typechain/hardhat": "^2.3.0",
"@typescript-eslint/eslint-plugin": "^4.29.1",
"@typescript-eslint/parser": "^4.29.1",
"@types/chai": "^4.2.21",
"@types/node": "^16.4.13",
"@types/mocha": "^9.0.0",
"ts-node": "^10.1.0",
typechain: "^5.1.2", // a workaround. see https://github.com/nomiclabs/hardhat/issues/1672#issuecomment-894497156
typescript: "^4.3.5",
};

const SAMPLE_PROJECT_DEPENDENCIES: {
[K in SampleProjectTypeCreationAction]: Dependencies;
} = {
[Action.CREATE_BASIC_SAMPLE_PROJECT_ACTION]: BASIC_SAMPLE_PROJECT_DEPENDENCIES,
[Action.CREATE_ADVANCED_SAMPLE_PROJECT_ACTION]: ADVANCED_SAMPLE_PROJECT_DEPENDENCIES,
[Action.CREATE_ADVANCED_TYPESCRIPT_SAMPLE_PROJECT_ACTION]: ADVANCED_TYPESCRIPT_SAMPLE_PROJECT_DEPENDENCIES,
};

const TELEMETRY_CONSENT_TIMEOUT = 10000;
Expand Down Expand Up @@ -128,20 +145,40 @@ async function copySampleProject(
) {
const packageRoot = getPackageRoot();

// first copy the basic project, then, if the advanced project is what was
// requested, overlay the advanced files on top of the basic ones.
// first copy the basic project, then, if an advanced project is what was
// requested, overlay the advanced files on top of the basic ones. then, if
// the advanced TypeScript project is what was requested, overlay those files
// on top of the advanced ones.

await fsExtra.ensureDir(projectRoot);
await fsExtra.copy(
path.join(packageRoot, "sample-projects", "basic"),
projectRoot
);

if (projectType === Action.CREATE_ADVANCED_SAMPLE_PROJECT_ACTION) {
if (
projectType === Action.CREATE_ADVANCED_SAMPLE_PROJECT_ACTION ||
projectType === Action.CREATE_ADVANCED_TYPESCRIPT_SAMPLE_PROJECT_ACTION
) {
await fsExtra.copy(
path.join(packageRoot, "sample-projects", "advanced"),
projectRoot
);
await fsExtra.remove(path.join(projectRoot, "scripts", "sample-script.js"));
}

if (projectType === Action.CREATE_ADVANCED_TYPESCRIPT_SAMPLE_PROJECT_ACTION) {
await fsExtra.copy(
path.join(packageRoot, "sample-projects", "advanced-ts"),
projectRoot
);
for (const jsFile of [
"hardhat.config.js",
path.join("scripts", "deploy.js"),
path.join("test", "sample-test.js"),
]) {
await fsExtra.remove(jsFile);
}
}

// This is just in case we have been using the sample project for dev/testing
Expand Down Expand Up @@ -202,7 +239,14 @@ async function getAction(): Promise<Action> {
undefined
) {
return Action.CREATE_ADVANCED_SAMPLE_PROJECT_ACTION;
} else if (
process.env
.HARDHAT_CREATE_ADVANCED_TYPESCRIPT_SAMPLE_PROJECT_WITH_DEFAULTS !==
undefined
) {
return Action.CREATE_ADVANCED_TYPESCRIPT_SAMPLE_PROJECT_ACTION;
}

const { default: enquirer } = await import("enquirer");
try {
const actionResponse = await enquirer.prompt<{ action: string }>([
Expand Down Expand Up @@ -290,6 +334,9 @@ export async function createProject() {
process.env.HARDHAT_CREATE_BASIC_SAMPLE_PROJECT_WITH_DEFAULTS !==
undefined ||
process.env.HARDHAT_CREATE_ADVANCED_SAMPLE_PROJECT_WITH_DEFAULTS !==
undefined ||
process.env
.HARDHAT_CREATE_ADVANCED_TYPESCRIPT_SAMPLE_PROJECT_WITH_DEFAULTS !==
undefined;

if (useDefaultPromptResponses) {
Expand Down

0 comments on commit d15141f

Please sign in to comment.