|
| 1 | +# Using Viem |
| 2 | + |
| 3 | +Hardhat Ignition provides a variant based on using [Viem](https://viem.sh) as your connection library. Viem is a lightweight alternative to [ethers](https://docs.ethers.org) with a focus on type safety. |
| 4 | + |
| 5 | +The Viem support in Hardhat Ignition includes a helper function, for use in Hardhat tests and scripts, that allows you to deploy Ignition modules and get back the deployed contracts as fully typed Viem contract instances. |
| 6 | + |
| 7 | +## Installation |
| 8 | + |
| 9 | +To install Hardhat Ignition with Viem support in an existing Hardhat project, you will need: |
| 10 | + |
| 11 | +- Hardhat version 2.18.0 or higher |
| 12 | +- Viem version 1.18.0 or higher |
| 13 | + |
| 14 | +You can also follow [Hardhat's Viem Quick Start](../../../hardhat-runner/docs/advanced/using-viem#quick-start) to create a new Hardhat Viem project from scratch. |
| 15 | + |
| 16 | +From the root directory of your Hardhat project run: |
| 17 | + |
| 18 | +::::tabsgroup{options="npm 7+,npm 6,yarn"} |
| 19 | + |
| 20 | +:::tab{value="npm 7+"} |
| 21 | + |
| 22 | +```shell |
| 23 | +npm install --save-dev @nomicfoundation/hardhat-ignition-viem |
| 24 | +``` |
| 25 | + |
| 26 | +::: |
| 27 | + |
| 28 | +:::tab{value="npm 6"} |
| 29 | + |
| 30 | +```shell |
| 31 | +npm install --save-dev @nomicfoundation/hardhat-ignition-viem @nomicfoundation/hardhat-ignition @nomicfoundation/hardhat-verify @nomicfoundation/hardhat-viem @nomicfoundation/ignition-core typescript viem |
| 32 | +``` |
| 33 | + |
| 34 | +::: |
| 35 | + |
| 36 | +:::tab{value=yarn} |
| 37 | + |
| 38 | +```shell |
| 39 | +yarn add --dev @nomicfoundation/hardhat-ignition-viem @nomicfoundation/hardhat-ignition @nomicfoundation/hardhat-verify @nomicfoundation/hardhat-viem @nomicfoundation/ignition-core typescript viem |
| 40 | +``` |
| 41 | + |
| 42 | +::: |
| 43 | + |
| 44 | +:::: |
| 45 | + |
| 46 | +Then [enable the plugin](../../../hardhat-runner/docs/guides/project-setup.md#plugins-and-dependencies) in your config file: |
| 47 | + |
| 48 | +::::tabsgroup{options="TypeScript,JavaScript"} |
| 49 | + |
| 50 | +:::tab{value="TypeScript"} |
| 51 | + |
| 52 | +```typescript |
| 53 | +import "@nomicfoundation/hardhat-ignition-viem"; |
| 54 | +``` |
| 55 | + |
| 56 | +::: |
| 57 | + |
| 58 | +:::tab{value="JavaScript"} |
| 59 | + |
| 60 | +```javascript |
| 61 | +require("@nomicfoundation/hardhat-ignition-viem"); |
| 62 | +``` |
| 63 | + |
| 64 | +::: |
| 65 | + |
| 66 | +:::: |
| 67 | + |
| 68 | +:::tip |
| 69 | + |
| 70 | +Only **one** Hardhat Ignition package should be imported within your Hardhat config file. Viem and ethers support cannot both be enabled at the same time. |
| 71 | + |
| 72 | +::: |
| 73 | + |
| 74 | +## The Ignition object |
| 75 | + |
| 76 | +The `@nomicfoundation/hardhat-plugin-viem` plugin adds an `ignition` object to the [Hardhat Runtime Environment](../../../hardhat-runner/docs/advanced/hardhat-runtime-environment.md). |
| 77 | + |
| 78 | +The `ignition` object exposes a `deploy` method, which takes an Ignition module, deploys it against the current network, like Hardhat Network, and returns the results of the module as typed Viem contract instances. |
| 79 | + |
| 80 | +The `deploy` method takes the Module as its first argument: |
| 81 | + |
| 82 | +```typescript |
| 83 | +const ApolloModule = buildModule("Apollo", (m) => { |
| 84 | + const apollo = m.contract("Rocket", ["Saturn V"]); |
| 85 | + |
| 86 | + return { apollo }; |
| 87 | +}); |
| 88 | + |
| 89 | +it("should have named the rocket Saturn V", async function () { |
| 90 | + const { apollo } = await hre.ignition.deploy(ApolloModule); |
| 91 | + |
| 92 | + assert.equal(await apollo.read.name(), "Saturn V"); |
| 93 | +}); |
| 94 | +``` |
| 95 | + |
| 96 | +The `ignition.deploy` method returns an object with a Viem contract instance per `Future` returned as a result in the module. |
| 97 | + |
| 98 | +## Usage with Artifacts |
| 99 | + |
| 100 | +To infer the type of a Viem contract instance, the full type of the ABI must be available when initializing a `Future` within a module. |
| 101 | + |
| 102 | +For named Hardhat contracts, the ABI and type information will be retrieved automatically using [hardhat-viem's type generation](https://hardhat.org/hardhat-runner/docs/advanced/using-viem#contract-type-generation). |
| 103 | + |
| 104 | +If you are passing an artifact object to initialize a `Future` within a module, you will need to ensure the artifact's ABI is either declared with [const assertions](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-4.html#const-assertions) or defined inline: |
| 105 | + |
| 106 | +```typescript |
| 107 | +const counterArtifact = { |
| 108 | + // ... |
| 109 | + abi: [...] as const, // <--- const assertion |
| 110 | +} |
| 111 | + |
| 112 | +const CounterModule = buildModule("Counter", (m) => { |
| 113 | + const counter = m.contract("Counter", CounterArtifact, [42]); |
| 114 | + |
| 115 | + return { counter }; |
| 116 | +}); |
| 117 | +``` |
| 118 | + |
| 119 | +If type inference isn't working for the returned contract, it is likely that the ABI type needs a `const` assertion or to be defined inline. |
| 120 | + |
| 121 | +This is because the ABI type must be as narrow as possible for Viem to infer the correct type for the contract, and by default Typescript will broaden the types within object literals. |
| 122 | + |
| 123 | +:::tip |
| 124 | + |
| 125 | +Typescript doesn't support importing JSON as const, it will instead automatically broaden the type, breaking Viem's inference. The artifact must be defined inline within Typescript. |
| 126 | + |
| 127 | +::: |
| 128 | + |
| 129 | +See [Viem's type inference requirements](https://viem.sh/docs/typescript.html#type-inference) for more details. |
| 130 | + |
| 131 | +## Sending transactions with a different account |
| 132 | + |
| 133 | +The `ignition.deploy` method will default to using the first account in Hardhat network's `accounts` array as the sender for all transactions. |
| 134 | + |
| 135 | +You can change this by passing a `defaultSender` within the options object as a second argument to the `deploy` method: |
| 136 | + |
| 137 | +```typescript |
| 138 | +const [first, second] = await hre.viem.getWalletClients(); |
| 139 | + |
| 140 | +const result = await hre.ignition.deploy(ApolloModule, { |
| 141 | + defaultSender: second.account.address, |
| 142 | +}); |
| 143 | +``` |
| 144 | + |
| 145 | +## Hardhat Ignition and Hardhat Viem |
| 146 | + |
| 147 | +Hardhat Ignition leverages the [hardhat-viem](https://hardhat.org/hardhat-runner/plugins/nomicfoundation-hardhat-viem) plugin for its type generation support, and inherits the same approach to [managing types and version stability](https://hardhat.org/hardhat-runner/docs/advanced/using-viem#managing-types-and-version-stability). |
| 148 | + |
| 149 | +Read the documentation on [hardhat-viem](https://hardhat.org/hardhat-runner/plugins/nomicfoundation-hardhat-viem) to learn more about Hardhat's Viem capabilities. |
0 commit comments