|
| 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