Advanced Usage
Midl's hardhat-deploy offers more functionality than just deploying or writing to contracts.
Common requests from developers include retrieving deployed smart contract addresses, adding rune deposits to function executions, rewriting deployment files, and more.
Below are some of the most common use cases.
Additionally, you can find the complete API here and more advanced examples in this repository.
If you find any missing functionality that would be useful, please open an issue on GitHub.
Retrieving an EVM Address
The EVM address is generated from the default BTC account derived from the mnemonic in hardhat-config.
In a hardhat-deploy function, you can retrieve it as follows:
const evmAddress = hre.midl.evm.address;Retrieving a Bitcoin Address
The Bitcoin address is derived from the mnemonic in hardhat-config.
In a hardhat-deploy function, you can retrieve it as follows:
await hre.midl.initialize(); // retrieves account with index #0
const { address } = hre.midl.account;Using Multiple Accounts During Deployment
Accounts are derived from the mnemonic in hardhat-config. You can change the account directly within deploy functions.
await hre.midl.initialize();
await hre.midl.deploy("MyContract", ["Hello World!"]);
await hre.midl.execute(); // Deployed by account with index #0
await hre.midl.initialize(1);
await hre.midl.deploy("MyContract", ["Hello world"]);
await hre.midl.execute(); // Deployed by account with index #1Retrieving Deployed Contract Address & ABI
Deployed contract addresses and ABIs are stored by default in the deployments of your hardhat project folder as JSON files.
In a hardhat-deploy function, you can retrieve them as follows:
const { address, abi } = await hre.midl.get("MyContract");Passing BTC as Value to Deploy or Write Functions
You can pass the native token as a value to payable functions.
In a hardhat-deploy function, this can be done as follows:
const value = 1000; // Amount in satoshis
await hre.midl.deploy(
"MyContract",
["Hello World!"],
{
value: satoshisToWei(value), // attaching 1000 sats as msg.value (10^10 wei per sat)
},
{
deposit: {
satoshis: value,
},
},
);
await hre.midl.write(
"MyContract",
"somePayableFunction",
[],
{
value: satoshisToWei(value),
},
{
deposit: {
satoshis: value,
},
},
);Calling CompleteTx
CompleteTx allows you to withdraw your assets back to Bitcoin L1. A complete transaction retrieves native BTC and Runes on request.
TIP
Calling execute({ withdraw: true }) will automatically call completeTx and withdraw only native BTC.
WARNING
Only add withdraw to the write or deploy transaction intentions if the contract you are calling calls the Executor contract's completeTx function. Otherwise, if you want to withdraw assets, you must call completeTx directly.
In a hardhat-deploy function, you can invoke this as follows:
await hre.midl.execute({ withdraw: {
runes: [{ id: runeId, value: amount, address: runeAddress }],
}});Using a Rune with Your hardhat-deploy Function
You can use Runes in Midl functions and seamlessly utilize them with hardhat-deploy. Doing so will create a transfer of a Rune in the BTC transaction.
In a hardhat-deploy function, this can be done as follows:
const assetAddress = (await hre.midl.get("ERC20Asset"))?.address;
const myContractAddress = (await hre.midl.get("MyContract"))?.address;
const amount = 1n; // Amount in Rune units according to the Rune's decimals
await hre.midl.write("ERC20Asset", "approve", [myContractAddress, amount]);
await hre.midl.write(
"MyContract",
"functionWithRuneTransfer",
[amount],
{},
{
deposit: {
runes: [
{
id: "1:1", // Rune ID may be attached manually or found by token address using midl-js-executor util
amount,
address: assetAddress, // Mirrored ERC20 asset
},
],
},
},
);Skip Estimate Gas
WARNING
This is a dangerous feature—please use it at your own risk. If your transaction reverts, transaction fees will still be charged.
This option allows you to bypass gas estimation before executing a transaction. It’s particularly helpful when transactions are failing silently and you need deeper insight into what’s going wrong - for example, by inspecting the raw transaction trace through an RPC call or block explorer.
In a hardhat-deploy function, this can be done as follows:
await hre.midl.initialize();
// some deployment functions
hre.midl.execute({
skipEstimateGas: true, // Skips gas estimation
});Deploying a Proxy
You can deploy proxy contracts in the same way as with the standard hardhat-deploy library.
Please see a complete example here.