28.10.2022

Getting started with Starknet Hardhat Plugin (Part 1: “Hello world”)

First part of a series of tutorials on how to use the StarkNet Hardhat Plugin for Cairo smart contract development.

Hello frens! 👋

Welcome to the first part of a series of tutorials on how to use the StarkNet Hardhat Plugin for Cairo smart contract development!

If you plan to use JavaScript as your language of choice in the StarkNet ecosystem, you came to the right place.

In this tutorial we will deliberately use links to other resources, because StarkNet is in alpha version at the time of writing, so expect things will change and break… And the resources linked will likely change as well to reflect the evolution 🧬

Installation

First things first, so please refer to the project's repository for instructions on how to install and set up everything:

  1. Install Hardhat itself
  2. Include Hardhat plugin inside the hardhat project you created, per instructions
  3. Create a new project (in our case, we called it hardhat-tutorial) 
  4. Navigate to the newly created project
  5. Be sure to run

 npm i @shardlabs/starknet-hardhat-plugin --save-dev

Note: After installing hardhat, and running npx hardhat - setting up a project should look something like this:

Note: After successfully installing everything, make sure you have docker running as well, or if you have cairo-lang installed locally, set up venv in your hardhat config file - like so!

Hello World

Now we have arrived to the fun part! 👻 First, copy the contract found here, and paste it in your project under the contracts folder inside your hardhat project. 

Note: you can delete the Solidity (.sol) contract if it was generated with your project.

You can call the contract hello.cairo ! At the time of writing, the contract looks like this:


 
// Declare this file as a StarkNet contract.
%lang starknet
 
from starkware.cairo.common.cairo_builtins import HashBuiltin
 
// Define a storage variable.
@storage_var
func balance() -> (res: felt) {
}
 
// Increases the balance by the given amount.
@external
func increase_balance{
   syscall_ptr: felt*,
   pedersen_ptr: HashBuiltin*,
   range_check_ptr,
}(amount: felt) {
   let (res) = balance.read();
   balance.write(res + amount);
   return ();
}
 
// Returns the current balance.
@view
func get_balance{
   syscall_ptr: felt*,
   pedersen_ptr: HashBuiltin*,
   range_check_ptr,
}() -> (res: felt) {
   let (res) = balance.read();
   return (res=res);
}

Commands

We are going to show you how to compile, deploy and interact with your contract by using the Hardhat StarkNet commands. But first, let’s configure our hardhat.config.ts file, find it or place it at the root of our project and follow the instructions below.


import "@shardlabs/starknet-hardhat-plugin";
 
module.exports = {
   starknet: {
       dockerizedVersion: "0.10.3",
       network: "alpha-goerli"
   },
   networks: {
   }
};

Compile contract

In the console, write this command:


> npx hardhat starknet-compile contracts/hello.cairo

After successful compilation you should see these .json files in your project:

Deployment of Account

Now we would like to deploy our contract! 

But, unlike the previous StarkNet versions, to do so, we will use an account that is already deployed and funded.

  1. Pre-calculate the address of the account which we will deploy later
  2. Fund the pre-calculated address
  3. Perform the actual deployment

You can learn more about this here.

That’s what we’ll be doing on the next few steps.

1. Let’s add a new file to our project, under the /scripts folder and name it deploy-account.ts. 

2. To create an account on testnet, we could run the following script in our project. Copy the following code to deploy-account.ts


import { starknet } from "hardhat";
 
async function keypress() {
    process.stdin.setRawMode(true);
    return new Promise((resolve) =>
        process.stdin.once("data", () => {
            process.stdin.setRawMode(false);
            resolve();
        })
    );
}
 
(async () => {
    const account = await starknet.OpenZeppelinAccount.createAccount();
    console.log(
        `Account created at ${account.address} with private key=${account.privateKey} and public key=${account.publicKey}`
    );
    console.log(
        "Please fund the address. Even after you get a confirmation that the funds were transferred, you may want to wait for a couple of minutes."
    );
    console.log("Press any key to continue...");
    await keypress();
    console.log("Deploying...");
    await account.deployAccount({ maxFee: 1e18 });
    console.log("Deployed");
})()
    .then(() => process.exit(0))
    .catch((err) => {
        console.error(err);
        process.exit(1);
    });

3. Run the following command in the console:


> npx hardhat run scripts/deploy-account.ts

Note: make sure you save your address, private and public keys shown in the console 

4. Funding the account

When the script pauses execution, you should add funds to the generated address - the command createAccount(), will output an account address which we then will use to fund through a faucet!

You should give it a few minutes for the transaction to be accepted. 

Note: The account is not yet deployed, so you will not be able to see it on Starkscan!

5. Deploying the account.

Once we make sure funding is successful (by checking if tokens were transferred), we can proceed - hit enter!.

After deploying the account, the transaction hash of the account will be output. To verify that the contract is accepted on the network, copy the address and paste it into the search field of Voyager or Starkscan

Note that due to high network traffic, there may be no result at first, so it is best to wait a few minutes before checking again.

Contract deployment and interaction

Ok. Now, we've deployed an account that will deploy our contract. We can proceed to deploying the hello.cairo contract.

Create a new script, call it deploy-contract.ts and place it in the /scripts folder.

Note: Be sure to add the address and private key from previous steps in the getOZAccount() function.


import hardhat from "hardhat";
import { starknet } from "hardhat";
 
async function main() {
    const account = await getOZAccount();
    const contractFactory = await hardhat.starknet.getContractFactory("hello");
    await account.declare(contractFactory, { maxFee: 1e18 });
    const contract = await account.deploy(contractFactory);
    console.log("Deployed to:", contract.address);
 
    const { res: balanceBefore } = await contract.call("get_balance");
    console.log("Balance before invoke: ", balanceBefore);
 
    await account.invoke(contract, "increase_balance", { amount: 10 });
    const { res: balanceAfter } = await contract.call("get_balance");
    console.log("Balance after invoke:", balanceAfter);
}
 
main()
    .then(() => process.exit(0))
    .catch((error) => {
        console.error(error);
        process.exit(1);
    });
 
/**
 * Returns an instance of OZAccount. Expected to be deployed
 */
 export async function getOZAccount() {
    return await starknet.OpenZeppelinAccount.getAccountFromAddress(
        // address from previous step
        "0x5b34912eb729c73edccc8380488177b9fed2868f431dd693d0a715306a5c37e",
        // private key from previous step
        "0x2cb7362c74f2e2ed432779eeacca7f0d"
    );
}

Note: The getContractFactory() method fetches a compiled contract by name. 

Now in the console, run:


> npx hardhat run scripts/deploy-contract.ts 

Note: You will have to wait for some time for the contract to actually get deployed on testnet. This can vary depending on the traffic. You can check the status of the transaction on: https://testnet.starkscan.co/ . Also be sure you are checking the testnet, and not the mainnet!

Final result in the console:

And that’s it!

Congratulations! :)

More information

Also be sure to check out the hardhat-example repository for more examples on features and usage!

Up Next

You may have noticed that doing this on the testnet can be slow 😞 But don't worry - in the next tutorial, we will see how to do the same operations, but on a local instance of the starknet network, called the devnet. Therefore make sure you follow our blog and Twitter

Happy coding!🚀🚀🚀

‍‍*This article is also available on SpaceShard Medium.

Downlaod all images