Testing interactions between your contract and MetaMask in a Hardhat project
In the Ethereum ecosystem, interacting with external wallets like MetaMask requires careful consideration of security, usability, and testing. One way to test interactions between your smart contracts and MetaMask is to use a combination of tools from a hardhat project. In this article, we will explore how to achieve this.
The problem:
When you want to interact with an external wallet like Metamask in your contract, you need to:
- Send the private key or user token to your contract.
- Use the
web3
library to send the transaction.
- Verify the response from MetaMask.
This process requires multiple steps and is error-prone if not done correctly. To simplify this process, we will use a hardhat project as a bridge between our contract’s interaction with MetaMask and the browser environment.
Setting up Hard hat
First, install Hardhat by running npx hardhat --run in watch
(or npx hardhat -w
). This will install the dependencies needed to test interactions between your contract and Metamask. You can also use yarn add hardhat
to get started.
Creating a new contract
Create a new Solidity smart contract using Webpack, Ethers.js, or Truffle. For this example, we will use Truffle.
// src/contracts/MyContract.sol
pragma solidity ^0.8.0;
contract MyContract {
mapping(address => uint256) public balances;
function deposit(uint256 amount) public paid {
balances[msg.sender] += amount;
}
function withdrawal(uint256 amount) public {
require(balances[msg.sender] >= amount, "Insufficient balance");
balances[msg.sender] -= amount;
}
}
Writing a Hardhat Test
Create a new file named mycontract.test.js
in the root of your project:
const { expect } = require("chai");
async function testMetamask() {
const myContract = await web3.eth.getContractAt("0x..."); // replace with your contract address
// Send the user's private key to the contract
myContract.sendTransaction({
from: "0x...",
to: "0x...",
value: 1 ether, // replace with the amount of the user's private key
});
const balancesBefore = await web3.eth.getBalance("0x..."); // replace with your user address
expect(balancesBefore).to.equal(0);
// Use Web3 to send the transaction to Metamask
myContract.sendTransaction({
from: "0x...",
to: "0x...",
value: web3.utils.toWei("1", "ether"), // replace with the user's private key amount and token type (e.g., wei for ether)
data: "Hello, MetaMask!",
});
}
Running the test
To run the test in a development environment:
npx hardhat run mycontract.test.js
In this example, we use Web3 to send transactions from our contract’s MyContract
instance to the user’s Ethereum wallet. We then verify that the transaction was successful by checking our user’s balance.
Testing interactions with MetaMask
To test interactions between your contract and Metamask:
- Replace the placeholder values (e.g., contract address, user private key amount) in the
mycontract.test.js
file.
- Update the
balancesBefore
variable to reflect our user’s new balance after interacting with MetaMask.
“`javascript
// Update balances before transaction
const balancesBefore = await web3.eth.getBalance(“0x…”); // replace with your user’s address
expect(balancesBefore).to.equal(1);
// Use Web3 to send the transaction to Metamask
myContract.sendTransaction({
from: “0x…”,
to: “0x…”,
value: web3.utils.toWei(“2”, “ether”), // replace with the user’s private key amount and token type (e.g., wei for ether)
data: “Hello, MetaMask!