Interact With Your Smart Contract

Elan Halpern
DevRel at Alchemy

Part 2: Interact with your Smart Contract

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

Step 1: Create a 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, or your home directory for the Truffle tutorial, create a new file named /interact.js add the following lines of code:

-- CODE language-js line-numbers -- // interact.js const API_KEY = process.env.API_KEY; 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 make sure that the dotenv module is loading 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:

-- CODE language-js line-numbers -- # .env API_URL = "https://eth-goerli.alchemyapi.io/v2/" API_KEY = "" PRIVATE_KEY = "" CONTRACT_ADDRESS = "0x"

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 (and Truffle) automatically generates an ABI for us and saves it in the HelloWorld.json file. In order to use this we'll need to parse out the contents by adding the following lines of code to our contract-interact.js file:

-- CODE language-js line-numbers -- // interact.js // For Truffle const contract = require("./build/contracts/HelloWorld.json"); // 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:

-- CODE language-js line-numbers -- console.log(JSON.stringify(contract.abi));

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

Hardhat:

-- CODE language-js line-numbers -- npx hardhat run scripts/interact.js

Truffle:

-- CODE language-js line-numbers -- node interact.js

Step 4: Create an instance of your contract

In order 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:

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

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

-- CODE language-js line-numbers -- // interact.js // Provider const alchemyProvider = new ethers.providers.AlchemyProvider(network="goerli", API_KEY); // 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 the initMessage = "Hello world!"? We are now going to 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:

-- CODE language-js line-numbers -- // 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:

-- CODE language-js line-numbers -- 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?

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

-- CODE language-js line-numbers -- // 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 and see if you can make the changes necessary to print out that new value!

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

-- CODE language-js line-numbers -- // interact.js const API_KEY = process.env.API_KEY; const PRIVATE_KEY = process.env.PRIVATE_KEY; const CONTRACT_ADDRESS = process.env.CONTRACT_ADDRESS; const contract = require("../artifacts/contracts/HelloWorld.sol/HelloWorld.json"); // provider - Alchemy const alchemyProvider = new ethers.providers.AlchemyProvider(network="goerli", API_KEY); // 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!

-- CODE language-js line-numbers -- npx hardhat run scripts/interact.js --network goerli

-- CODE language-js line-numbers -- 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 set.

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 Goerli Etherscan and search for your transaction hash.

And that's it! You've now deployed AND interacted with an Ethereum smart contract.