Skip to content

Commit 2c34fcd

Browse files
committed
add guide for using ignition with hardhat scripts
1 parent 4290827 commit 2c34fcd

File tree

2 files changed

+242
-0
lines changed

2 files changed

+242
-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,241 @@
1+
# Advanced deployment with 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), but you can follow along in your own project if you prefer.
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 ApolloModule from "../ignition/modules/Apollo";
21+
22+
async function main() {
23+
const { apollo } = await hre.ignition.deploy(ApolloModule);
24+
25+
console.log(`Apollo deployed to: ${apollo.target}`);
26+
}
27+
28+
main().catch(console.error);
29+
```
30+
31+
:::
32+
33+
:::tab{value="JavaScript"}
34+
35+
```javascript
36+
const ApolloModule = require("../ignition/modules/Apollo");
37+
38+
async function main() {
39+
const { apollo } = await hre.ignition.deploy(ApolloModule);
40+
41+
console.log(`Apollo deployed to: ${apollo.target}`);
42+
}
43+
44+
main().catch(console.error);
45+
```
46+
47+
:::
48+
49+
::::
50+
51+
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:
52+
53+
::::tabsgroup{options="TypeScript,JavaScript"}
54+
55+
:::tab{value="TypeScript"}
56+
57+
```sh
58+
npx hardhat run scripts/deploy.ts
59+
```
60+
61+
:::
62+
63+
:::tab{value="JavaScript"}
64+
65+
```sh
66+
npx hardhat run scripts/deploy.js
67+
```
68+
69+
:::
70+
71+
::::
72+
73+
## Asynchronous operations
74+
75+
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:
76+
77+
::::tabsgroup{options="TypeScript,JavaScript"}
78+
79+
:::tab{value="TypeScript"}
80+
81+
```typescript
82+
import { buildModule } from "@nomicfoundation/hardhat-ignition/modules";
83+
84+
export default buildModule("Apollo", (m) => {
85+
const rocketName = m.getParameter("rocketName");
86+
const apollo = m.contract("Rocket", [rocketName]);
87+
88+
m.call(apollo, "launch", []);
89+
90+
return { apollo };
91+
});
92+
```
93+
94+
:::
95+
96+
:::tab{value="JavaScript"}
97+
98+
```javascript
99+
const { buildModule } = require("@nomicfoundation/hardhat-ignition/modules");
100+
101+
module.exports = buildModule("Apollo", (m) => {
102+
const rocketName = m.getParameter("rocketName");
103+
const apollo = m.contract("Rocket", [rocketName]);
104+
105+
m.call(apollo, "launch", []);
106+
107+
return { apollo };
108+
});
109+
```
110+
111+
:::
112+
113+
::::
114+
115+
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:
116+
117+
::::tabsgroup{options="TypeScript,JavaScript"}
118+
119+
:::tab{value="TypeScript"}
120+
121+
```typescript
122+
import ApolloModule from "../ignition/modules/Apollo";
123+
124+
async function getRocketNameFromAPI() {
125+
// Mock function to simulate an asynchronous API call
126+
return "Saturn VI";
127+
}
128+
129+
async function main() {
130+
const rocketName = await getRocketNameFromAPI();
131+
132+
const { apollo } = await hre.ignition.deploy(ApolloModule, {
133+
parameters: { Apollo: { rocketName } },
134+
});
135+
136+
console.log(`Apollo deployed to: ${apollo.target}`);
137+
}
138+
139+
main().catch(console.error);
140+
```
141+
142+
:::
143+
144+
:::tab{value="JavaScript"}
145+
146+
```javascript
147+
const ApolloModule = require("../ignition/modules/Apollo");
148+
149+
async function getRocketNameFromAPI() {
150+
// Mock function to simulate an asynchronous API call
151+
return "Saturn VI";
152+
}
153+
154+
async function main() {
155+
const rocketName = await getRocketNameFromAPI();
156+
157+
const { apollo } = await hre.ignition.deploy(ApolloModule, {
158+
parameters: { Apollo: { rocketName } },
159+
});
160+
161+
console.log(`Apollo deployed to: ${apollo.target}`);
162+
}
163+
164+
main().catch(console.error);
165+
```
166+
167+
:::
168+
169+
::::
170+
171+
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 to the Ignition module when deploying the `Apollo` module. You can run this script using the same command as before.
172+
173+
## Conditional logic
174+
175+
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:
176+
177+
::::tabsgroup{options="TypeScript,JavaScript"}
178+
179+
:::tab{value="TypeScript"}
180+
181+
```typescript
182+
import ApolloModule from "../ignition/modules/Apollo";
183+
184+
async function getRocketNameFromAPI() {
185+
// Mock function to simulate an asynchronous API call
186+
return "Saturn VI";
187+
}
188+
189+
async function main() {
190+
const rocketName = await getRocketNameFromAPI();
191+
192+
if (rocketName !== undefined) {
193+
const { apollo } = await hre.ignition.deploy(ApolloModule, {
194+
parameters: { Apollo: { rocketName } },
195+
});
196+
197+
console.log(`Apollo deployed to: ${apollo.target}`);
198+
} else {
199+
console.log("No name given for Rocket contract, skipping deployment");
200+
}
201+
}
202+
203+
main().catch(console.error);
204+
```
205+
206+
:::
207+
208+
:::tab{value="JavaScript"}
209+
210+
```javascript
211+
const ApolloModule = require("../ignition/modules/Apollo");
212+
213+
async function getRocketNameFromAPI() {
214+
// Mock function to simulate an asynchronous API call
215+
return "Saturn VI";
216+
}
217+
218+
async function main() {
219+
const rocketName = await getRocketNameFromAPI();
220+
221+
if (rocketName !== undefined) {
222+
const { apollo } = await hre.ignition.deploy(ApolloModule, {
223+
parameters: { Apollo: { rocketName } },
224+
});
225+
226+
console.log(`Apollo deployed to: ${apollo.target}`);
227+
} else {
228+
console.log("No name given for Rocket contract, skipping deployment");
229+
}
230+
}
231+
232+
main().catch(console.error);
233+
```
234+
235+
:::
236+
237+
::::
238+
239+
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.
240+
241+
By combining 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)