Course lesson

Interact with a Solidity Smart Contract Using Ethers and the Contract ABI in SvetleKit

Now is time to setup the client to talk with the contract, for that you will need to store and access the contract ABI (this is a file generated by the contract compilation) as well as use ethers to set up a connection to the contract.

Duration
5 min
Access
Included
Transcript
Retained from source evidence

Now is time to setup the client to talk with the contract, for that you will need to store and access the contract ABI (this is a file generated by the contract compilation) as well as use ethers to set up a connection to the contract.

Once set up is complete, we will listen to any tip events that come in from the contract and display tip information in the application.

Important

SvelteKit is still in beta. Expect bugs! Read more here, and track progress towards 1.0 here.

This lesson was recorded before the latest breaking changes, the content is still valid but it sometimes references a file that does not exists anymore.

Now: src/routes/index.svelte is called src/routes/+page.svelte

src/routes/__layout.svelte is called src/routes/+layout.svelte

Everything else is 100% valid. This particular content will be updated when Sveltekit reaches 1.0.0 stable.

Setup communication with the contract

Now is time to setup the client to talk with the contract, for that you first need to import the contract ABI, a file generated by the contract compilation under src/artifacts/src/contracts/TipJar.sol/TipJar.json-

import TipJarABI from '../artifacts/src/contracts/TipJar.sol/TipJar.json';

With that in place, you'll need the contract address and setup the "connection" with it. Let's check how to do it

import TipJarABI from '../artifacts/src/contracts/TipJar.sol/TipJar.json';

// Create 2 new variables
const contractAddress = import.meta.env.VITE_CONTRACT_ADDRESS;
let contract =  null;

async function setupContract() {
	if (isConnected && provider) {
		contract = new ethers.Contract(contractAddress, TipJarABI.abi, provider); // Get the contract object
		contract.on('NewTip', async () => { // Listen for events on the contract

			// update balance after a new tip was made
			balance = await provider.getBalance(userAddress);

		});
	}
}


async function setup(accounts) {
	...
	...
	setupContract();
}

The contract address will be stored in an environment variable inside the .env file. Recall the address of the contract on lesson 07? Well, you need that, if you don't recall it, let's deploy the contract again

Terminal
$ npm run hardhat:deploy

And copy the TipJar address into the .env file under the variable VITE_CONTRACT_ADRESS^ (if the .envfile don't exists, just create it).

SvelteKit offers a simple way to retrieve the enviroment variables by using import.meta.env. Every variable named with the VITE_ prefix will be avaible for the frontend to import.

Now in the setupContract function there are two steps.

  • Setup the contract object by calling ethers.Contract that receives the contractAddress, the ABI code and the priovider.
  • Setup a listener for the NewTip event that you know you'll need: The listener callback just update the balance displayed in the screen.

Finally let's create a function to read the tips stored in the contract and render that in the UI

// Read the tips from the contract
async function getTips() {
	if (isConnected) {
		const tips = await contract.getAllTips(); // use the getAllTips function to get all the tips
		allTips = [
			...tips.map((item) => {
				// parse the tips and store them in the allTips array
				return {
					address: item.sender,
					timestamp: new Date(item.timestamp * 1000).toLocaleDateString(),
					message: item.message,
					name: item.name,
					amount: ethers.utils.formatEther(item.amount.toString())
				};
			})
		];
	}
}
<table class="mt-8 border-collapse table-auto w-2/3 mx-auto text-sm h-80 overflow-auto">
	<thead>
		<tr>
			<th class="border-b border-gray-600 font-medium p-4 pl-8 pt-0 pb-3 text-gray-400 text-left"
				>address</th
			>
			<th class="border-b border-gray-600 font-medium p-4 pl-8 pt-0 pb-3 text-gray-400 text-left"
				>Name</th
			>
			<th class="border-b border-gray-600 font-medium p-4 pl-8 pt-0 pb-3 text-gray-400 text-left"
				>Message</th
			>
			<th class="border-b border-gray-600 font-medium p-4 pl-8 pt-0 pb-3 text-gray-400 text-left"
				>Timestamp</th
			>
			<th class="border-b border-gray-600 font-medium p-4 pl-8 pt-0 pb-3 text-gray-400 text-left"
				>Amount</th
			>
		</tr>
	</thead>
	<tbody>
		{#each allTips as item}
			<tr>
				<td class="border-b border-gray-700  p-4 pl-8 text-gray-500">{item.address}</td>
				<td class="border-b border-gray-700  p-4 pl-8 text-gray-500">{item.name}</td>
				<td class="border-b border-gray-700  p-4 pl-8 text-gray-500">{item.message}</td>
				<td class="border-b border-gray-700  p-4 pl-8 text-gray-500">{item.timestamp}</td>
				<td class="border-b border-gray-700  p-4 pl-8 text-gray-500">{item.amount} eth</td>
			</tr>
		{/each}
	</tbody>
</table>