Interacting with a Smart Contract

Step-by-step guide on interacting with a deployed Ethereum smart contract by updating a smart contract variable.

Before starting this tutorial on interacting with a smart contract, you should have completed part 1 — Hello World Smart Contract. In part 3 we'll go over submitting our contract to Etherscan so anyone can understand how to interact with it!

Part 2: Interact with your Smart Contract

Now that we've successfully deployed a smart contract to the Sepolia network, let's test out our web3 skills and interact with it!

Step 1: Create an interact.js file

This is the file where we'll write our interaction script. We'll be using the Ethers.js library that you previously installed in Part 1.
Inside your scripts/ folder for the hardhat tutorial, create a new file named interact.js and add the following lines of code:

// interact.js

const API_URL = process.env.API_URL;
const PRIVATE_KEY = process.env.PRIVATE_KEY;
const CONTRACT_ADDRESS = process.env.CONTRACT_ADDRESS;

Step 2: Update your .env file

We will be using new environment variables, so we need to define them in our .env file and ensure that the .env module loads these variables.

We'll need to add a definition for our Alchemy API_KEY and the CONTRACT_ADDRESS where your smart contract was deployed.

Your .env file should look something like this:

# .env

API_URL = "https://eth-sepolia.g.alchemy.com/v2/<your-api-key>"
API_KEY = "<your-api-key>"
PRIVATE_KEY = "<your-metamask-private-key>"
CONTRACT_ADDRESS = "0x<your contract address>"

Step 3: Grab your contract ABI

Our contract ABI (Application Binary Interface) is the interface to interact with our smart contract. You can learn more about Contract ABIs here. Hardhat automatically generates an ABI for us and saves it in the HelloWorld.json file. To use this, we'll need to parse out the contents by adding the following lines of code to our contract interact.js file:

// For Hardhat 
const contract = require("../artifacts/contracts/HelloWorld.sol/HelloWorld.json");

If you want to see the ABI, you can print it to your console:

console.log(JSON.stringify(contract.abi));

To run interact.js and see your ABI printed to the console, navigate to your terminal and run

Hardat:

npx hardhat run scripts/interact.js

Step 4: Create an instance of your contract

To interact with our contract, we need to create an instance of it in our code. To do so with Ethers.js, we'll need to work with three concepts:

  • Provider - This is a node provider that gives you read and write access to the blockchain.
  • Signer - This represents an Ethereum account that has the ability to sign transactions.
  • Contract - This is an Ethers.js object representing a specific contract deployed on-chain.

We'll use the contract ABI from the previous step to create our instance of the contract:

// interact.js
const ethers = require('ethers');

// Provider
const alchemyProvider = new ethers.providers.JsonRpcProvider(API_URL);

// Signer
const signer = new ethers.Wallet(PRIVATE_KEY, alchemyProvider);

// Contract
const helloWorldContract = new ethers.Contract(CONTRACT_ADDRESS, contract.abi, signer);

You can read more about Providers, Signers, and Contracts in the Ethers.js documentation.

Step 5: Read the init message

Remember when we deployed our contract with theinitMessage = "Hello world!"? We will now read that message stored in our smart contract and print it to the console.

In JavaScript, we use asynchronous functions to interact with networks. Check out this article to learn more about async functions.

Use the code below to call the message function in our smart contract and read the init message:

// interact.js

// ...

async function main() {
  const message = await helloWorldContract.message();
  console.log("The message is: " + message);
}
main();

After running the file using npx hardhat run scripts/interact.js in the terminal, we should see this response:

The message is: Hello world!

Congrats! You've just successfully read smart contract data from the Ethereum blockchain, way to go!

Step 6: Update the message

Now, instead of just reading the message, we can also update the message saved in our smart contract using the update function! Pretty cool, right?

To do so, we can directly call the update function on our instantiated Contract object like so:

// interact.js

// ...

async function main() {
  const message = await helloWorldContract.message();
  console.log("The message is: " + message);
  
  console.log("Updating the message...");
  const tx = await helloWorldContract.update("This is the new message.");
  await tx.wait();
}
main();

Note that we make a call to .wait() on the returned transaction object. This ensures that our script waits for the transaction to be mined on the blockchain before proceeding onwards. If you were to leave this line out, your script may not be able to see the updated message value in your contract.

Step 7: Read the new message

You should be able to repeat Step 5 to read the updated _message_ value. Take a moment to see if you can make the necessary changes to print out that new value!

If you need a hint, here's what your interact.js file should look like at this point:

// interact.js

const API_URL = process.env.API_URL;
const PRIVATE_KEY = process.env.PRIVATE_KEY;
const CONTRACT_ADDRESS = process.env.CONTRACT_ADDRESS;
const ethers = require('ethers');

const contract = require("../artifacts/contracts/HelloWorld.sol/HelloWorld.json");

// provider - Alchemy
const alchemyProvider = new ethers.providers.JsonRpcProvider(API_URL);

// signer - you
const signer = new ethers.Wallet(PRIVATE_KEY, alchemyProvider);

// contract instance
const helloWorldContract = new ethers.Contract(CONTRACT_ADDRESS, contract.abi, signer);

async function main() {
    const message = await helloWorldContract.message();
    console.log("The message is: " + message); 

    console.log("Updating the message...");
    const tx = await helloWorldContract.update("this is the new message");
    await tx.wait();

    const newMessage = await helloWorldContract.message();
    console.log("The new message is: " + newMessage); 
}

main();

Now just run the script and you should be able to see the old message, the updating status, and the new message printed out to your terminal!

npx hardhat run scripts/interact.js --network sepolia
The message is: Hello World!
Updating the message...
The new message is: This is the new message.

While you are running that script, you may notice that the Updating the message... step takes a while to load before the new message is sent. That is due to the mining process! If you are curious about how to track transactions while they are being mined, visit the Alchemy mempool to see the status of your transaction (whether it's pending, mined, or got dropped by the network). If your transaction got dropped, it's also helpful to check Sepolia Etherscan and search for your transaction hash.

And that's it! You've now deployed AND interacted with an Ethereum smart contract. If you'd like to publish your contract to Etherscan so that anyone will know how to interact with it, check out part 3: submitting your smart contract to etherscan!

Once you complete this tutorial, let us know how your experience was or if you have any feedback by tagging us on Twitter @alchemyplatform!


ReadMe