Skip to content

Commit 13333d9

Browse files
authored
Merge pull request #5174 from NomicFoundation/ignition/scripts-guide
Guide for using ignition with hardhat scripts
2 parents 4290827 + 9442c76 commit 13333d9

File tree

2 files changed

+251
-0
lines changed

2 files changed

+251
-0
lines changed

docs/src/content/ignition/docs/guides/_dirinfo.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ order:
1111
- /viem
1212
- /create2
1313
- /ledger
14+
- /scripts
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
# Deploying within Hardhat scripts
2+
3+
Hardhat Ignition is a powerful deployment engine, but you may find there are some programming concepts that are not allowed within an Ignition module. Conditional logic, `async/await`, and `console.log` of deployment variables are some examples of operations that cannot be performed within an Ignition module. However, this guide will show you how you can perform all of these operations by pairing Ignition with Hardhat scripts.
4+
5+
:::tip
6+
7+
This guide will be using the contracts and Ignition module from the [quick start guide](/ignition/docs/getting-started#quick-start).
8+
9+
:::
10+
11+
## Logging a contract's address to the console
12+
13+
We will begin by creating a `scripts` directory within our Hardhat project. Within this directory, create a new file called `deploy.js` (or `deploy.ts` if you're using TypeScript) and add the following code:
14+
15+
::::tabsgroup{options="TypeScript,JavaScript"}
16+
17+
:::tab{value="TypeScript"}
18+
19+
```typescript
20+
import hre from "hardhat";
21+
import ApolloModule from "../ignition/modules/Apollo";
22+
23+
async function main() {
24+
const { apollo } = await hre.ignition.deploy(ApolloModule);
25+
26+
console.log(`Apollo deployed to: ${await apollo.getAddress()}`);
27+
}
28+
29+
main().catch(console.error);
30+
```
31+
32+
:::
33+
34+
:::tab{value="JavaScript"}
35+
36+
```javascript
37+
const ApolloModule = require("../ignition/modules/Apollo");
38+
39+
async function main() {
40+
const { apollo } = await hre.ignition.deploy(ApolloModule);
41+
42+
console.log(`Apollo deployed to: ${await apollo.getAddress()}`);
43+
}
44+
45+
main().catch(console.error);
46+
```
47+
48+
:::
49+
50+
::::
51+
52+
This script imports the `Apollo` module and deploys it using `hre.ignition.deploy`. The `apollo` object in this example is an [ethers.js](https://docs.ethers.org) contract instance, which contains the deployed contract's address in the `target` property. We then log this address to the console. To run the script, execute the following command:
53+
54+
::::tabsgroup{options="TypeScript,JavaScript"}
55+
56+
:::tab{value="TypeScript"}
57+
58+
```sh
59+
npx hardhat run scripts/deploy.ts
60+
```
61+
62+
:::
63+
64+
:::tab{value="JavaScript"}
65+
66+
```sh
67+
npx hardhat run scripts/deploy.js
68+
```
69+
70+
:::
71+
72+
::::
73+
74+
## Asynchronous operations
75+
76+
For this example, let's say we want to dynamically change the name of the `Rocket` contract according to some external data. We need to make an asynchronous call to an API to retrieve this data, and we also need to adjust our Ignition module to accept this data as a parameter. First, let's update our Ignition module:
77+
78+
::::tabsgroup{options="TypeScript,JavaScript"}
79+
80+
:::tab{value="TypeScript"}
81+
82+
```typescript{4}
83+
import hre from "hardhat";
84+
import { buildModule } from "@nomicfoundation/hardhat-ignition/modules";
85+
86+
export default buildModule("Apollo", (m) => {
87+
const rocketName = m.getParameter("rocketName");
88+
const apollo = m.contract("Rocket", [rocketName]);
89+
90+
m.call(apollo, "launch", []);
91+
92+
return { apollo };
93+
});
94+
```
95+
96+
:::
97+
98+
:::tab{value="JavaScript"}
99+
100+
```javascript{4}
101+
const { buildModule } = require("@nomicfoundation/hardhat-ignition/modules");
102+
103+
module.exports = buildModule("Apollo", (m) => {
104+
const rocketName = m.getParameter("rocketName");
105+
const apollo = m.contract("Rocket", [rocketName]);
106+
107+
m.call(apollo, "launch", []);
108+
109+
return { apollo };
110+
});
111+
```
112+
113+
:::
114+
115+
::::
116+
117+
We've added a new parameter to the Ignition module called `rocketName`. This parameter will be passed to the `Rocket` contract when it is deployed. Next, let's update our deployment script to make an asynchronous call to an API:
118+
119+
::::tabsgroup{options="TypeScript,JavaScript"}
120+
121+
:::tab{value="TypeScript"}
122+
123+
```typescript
124+
import hre from "hardhat";
125+
import ApolloModule from "../ignition/modules/Apollo";
126+
127+
async function getRocketNameFromAPI() {
128+
// Mock function to simulate an asynchronous API call
129+
return "Saturn VI";
130+
}
131+
132+
async function main() {
133+
const rocketName = await getRocketNameFromAPI();
134+
135+
const { apollo } = await hre.ignition.deploy(ApolloModule, {
136+
parameters: { Apollo: { rocketName } },
137+
});
138+
139+
console.log(`Apollo deployed to: ${apollo.target}`);
140+
}
141+
142+
main().catch(console.error);
143+
```
144+
145+
:::
146+
147+
:::tab{value="JavaScript"}
148+
149+
```javascript
150+
const ApolloModule = require("../ignition/modules/Apollo");
151+
152+
async function getRocketNameFromAPI() {
153+
// Mock function to simulate an asynchronous API call
154+
return "Saturn VI";
155+
}
156+
157+
async function main() {
158+
const rocketName = await getRocketNameFromAPI();
159+
160+
const { apollo } = await hre.ignition.deploy(ApolloModule, {
161+
parameters: { Apollo: { rocketName } },
162+
});
163+
164+
console.log(`Apollo deployed to: ${apollo.target}`);
165+
}
166+
167+
main().catch(console.error);
168+
```
169+
170+
:::
171+
172+
::::
173+
174+
In this script, we've added a new function called `getRocketNameFromAPI`, which simulates an asynchronous API call. We then call this function to retrieve the rocket name and pass it as a parameter under the named Ignition module when deploying the `Apollo` module. You can run this script using the same command as before.
175+
176+
:::tip
177+
178+
You can read more about defining and using parameters in Ignition modules in the [deployment guide](/ignition/docs/guides/deploy#defining-parameters-during-deployment).
179+
180+
:::
181+
182+
## Conditional logic
183+
184+
Lastly, let's add some conditional logic to our deployment script. Suppose we want to deploy the `Apollo` module only if the rocket name is not empty. We can achieve this by adding a simple `if` statement to our script:
185+
186+
::::tabsgroup{options="TypeScript,JavaScript"}
187+
188+
:::tab{value="TypeScript"}
189+
190+
```typescript
191+
import ApolloModule from "../ignition/modules/Apollo";
192+
193+
async function getRocketNameFromAPI() {
194+
// Mock function to simulate an asynchronous API call
195+
return "Saturn VI";
196+
}
197+
198+
async function main() {
199+
const rocketName = await getRocketNameFromAPI();
200+
201+
if (rocketName !== undefined) {
202+
const { apollo } = await hre.ignition.deploy(ApolloModule, {
203+
parameters: { Apollo: { rocketName } },
204+
});
205+
206+
console.log(`Apollo deployed to: ${await apollo.getAddress()}`);
207+
} else {
208+
console.log("No name given for Rocket contract, skipping deployment");
209+
}
210+
}
211+
212+
main().catch(console.error);
213+
```
214+
215+
:::
216+
217+
:::tab{value="JavaScript"}
218+
219+
```javascript
220+
const ApolloModule = require("../ignition/modules/Apollo");
221+
222+
async function getRocketNameFromAPI() {
223+
// Mock function to simulate an asynchronous API call
224+
return "Saturn VI";
225+
}
226+
227+
async function main() {
228+
const rocketName = await getRocketNameFromAPI();
229+
230+
if (rocketName !== undefined) {
231+
const { apollo } = await hre.ignition.deploy(ApolloModule, {
232+
parameters: { Apollo: { rocketName } },
233+
});
234+
235+
console.log(`Apollo deployed to: ${await apollo.getAddress()}`);
236+
} else {
237+
console.log("No name given for Rocket contract, skipping deployment");
238+
}
239+
}
240+
241+
main().catch(console.error);
242+
```
243+
244+
:::
245+
246+
::::
247+
248+
In this script, we've added an `if` statement to check if the `rocketName` is not `undefined`. If it is not `undefined`, we proceed with deploying the `Apollo` module; otherwise, we log a message to the console indicating that the deployment has been skipped. You can run this script using the same command as before.
249+
250+
By combining Hardhat Ignition with Hardhat scripts, you can perform advanced deployment operations that are not possible within an Ignition module alone. These are just a few examples of what you can achieve with this powerful combination. Feel free to experiment further and explore the possibilities!

0 commit comments

Comments
 (0)