Launching
Gas optimisation
Every transaction on the blockchain costs gas and our goal is to make every transaction cost as little as possible.
The smart contract code that we've written uses as little storage as possible, which plays a big part in reducing gas costs, however we still have one more step to take that is often forgotten.
Gas Reporter
Before we optimize further, let's start by measuring our current gas costs. We'll need to first install and configure hardhat-gas-reporter plugin.
- Install it by running
npm install hardhat-gas-reporter. - In your hardhat config file import the plugin at the top of the file by adding
require("hardhat-gas-reporter") - Add the following block to the settings in that file:
gasReporter: {
outputFile: "gas-report.txt",
enabled: process.env.REPORT_GAS !== undefined,
currency: "USD",
noColors: true,
coinmarketcap: process.env.COIN_MARKETCAP_API_KEY || "",
token: "ETH"
}
We need to first update our .env file with a CoinMarketCap API key, which can be acquired for free from their website.
Your .env file should have the following lines in it, if not, go ahead and add them:
REPORT_GAS=true
COIN_MARKETCAP_API_KEY=[YOUR-API-KEY]
Let's run our tests again via npx hardhat test. The gas reporter plugin will take over and will log the gas used in every function call and will output the results to the gas-report-txt file.

This report is really useful in estimating how much your contract will cost to deploy to production, and how much each transaction will cost once deployed.
It also gives us a benchmark that we can use to measure our gas optimization efforts!
Solidity Optimizer
Let's configure the solidity compiler to optimize our code for us by adjusting the solidity line in our hardhat configuration in hardhat.config.js:
solidity: {
version: "0.8.9",
settings: {
optimizer: {
// Toggles whether the optimizer is on or off.
// It's good to keep it off for development
// and turn on for when getting ready to launch.
enabled: true,
// The number of runs specifies roughly how often
// the deployed code will be executed across the
// life-time of the contract.
runs: 300,
}
},
}
Apart from turning the optimizer on, the only configuration option we have is the runs parameter.
From the solidity documentation:
The number of runs specifies roughly how often each opcode of the deployed code will be executed across the life-time of the contract. This means it is a trade-off parameter between code size (deploy cost) and code execution cost (cost after deployment).
200 or 300 runs is a sensible default, but I encourage you to experiment with different values to see how it effects deployment and transaction costs, and pick the most appropriate value for your project.
Here's the same report again, but with the optimizer turned on. Notice the reduction in gas prices:

OpenZeppelin Defender
Defender is a smart contract management tool built by OpenZeppelin, and I've found it to be useful to set up and pass on to the client so that they can perform certain smart contract functions.
It allows you to connect a smart contract, and create "proposals" - aka function calls - that can be executed and re-executed at later times.
Bear in mind that proposals must be created by the wallet that will later execute them (annoying! I would rather create the proposals myself for the client to execute) so my workflow is usually the following:
- Ask the client to create an account on Defener and share the credentials with me
- Add the contract to Defender
- Create and execute a proposal to pass ownership of the contract to the client
- Guide the client to create proposals for common actions, usually on a video call
- Allow the client to test these actions out on a test contract so that they are comfortable with the process once we go live
Creating a launch plan
I've found that the way to plan for a smooth launch is to use a checklist, and to run through the entire checklist on a test environment before executing it in production.
Steps in the checklist should be automated to reduce the risk of manual error. For example, I added in a step to "Shuffle NFTs" so that the final order of the NFTs is not the same as the order used for testing - this means that I've built a script (included in my Hashlips Fork) that I can run reliably with a single command.
Here's a checklist that I've used in the past. I like to run through each item in the list and add a little ✅ checkmark near completed steps.
PREP
- Create new wallet for deployment + coupon generation: “Deployment wallet”
- Generate coupons and upload to Coupon API
- Shuffle NFTs (optional)
- Run script to make any changes to the metadata (optional)
- Regenerate Provenance hash
- Upload images to IPFS
PRE-DEPLOYMENT
- Client to prepare wallet that contract ownership should be transferred to: “Owner wallet”
DEPLOYMENT
- Run
npx hardhat deploy -–network mainnetto run deployment procedure
POST DEPLOYMENT
- Configure OpenZeppelin Defender with deployed contract
- Transfer ownership of contract to Owner wallet
- Transfer remaining funds from Deployment wallet to Owner wallet