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.getEVMAddress();
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.getAccount();
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", {
args: ["Hello World!"]
});
await hre.midl.execute(); // Deployed by account with index #0
hre.midl.initialize(1);
await hre.midl.deploy("MyContract", {
args: ["Hello world"]
});
await hre.midl.execute(); // Deployed by account with index #1
Retrieving 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.getDeployment("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", {
args: ["Hello World!"],
value: satoshisToWei(value) // attaching 1000 satoshis and multiplying by 10 * 10 ** 10 in msg.value
}, {
deposit: {
satoshis: value
}
});
await hre.midl.callContract("MyContract", "somePayableFunction", {
value: satoshisToWei(value) // attaching 1000 satoshis and multiplying by 10 ** 10 in msg.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 callContract
or deploy
transaction intentions if you 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 getDeployment("ERC20Asset").address;
const myContractAddress = await getDeployment("MyContract").address;
const amount = 1n; // Amount in Rune units according to the Rune's decimals
await hre.midl.callContract("ERC20Asset", "approve", {
args: [myContractAddress, amount]
});
await hre.midl.callContract(
"MyContract",
"functionWithRuneTransfer",
{
args: [amount]
},
{
deposit: {
runes: [
{
id: "1:1", // Rune ID may be attached manually or found by token address using midl-js-executor util
value: 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.