Generating and understanding the HelloStarknet
contract
If you encounter an issue while following this tutorial, check out "Hello, Starknet!" quickstart tutorial troubleshooting. |
Introduction
Welcome to the second installment of the "Hello, Starknet!" quickstart series, the official tutorial for starting your journey as a Starknet developer! 🚀
Starknet contracts are a special superset of Cairo programs that are run by the Starknet sequencer, and as such, have access to Starknet’s state. This installment of the series will therefore walk you though generating and understanding Scarb’s default HelloStarknet
contract, which will be used throughout the following installments.
To learn more about Starknet smart contracts, see the Cairo book. |
Generating HelloStarknet
Scarb’s default HelloStarknet
contract can be generated by simply running:
scarb new hello_starknet
and selecting to set up the Starknet Foundry (default)
test runner. If successful, this should create a new hello_starknet
directory with the following structure:
hello_cairo
|- Scarb.lock
|- Scarb.toml
|- snfoundry.toml
|- src
|- lib.cairo
|- tests
|- test_contract.cairo
Understanding HelloStarknet
For the purpose of this tutorial, you can ignore all files in the hello_starknet
directory other than hello_starknet/src/lib.cairo
, which holds the contract’s code:
/// Interface representing `HelloContract`.
/// This interface allows modification and retrieval of the contract balance.
#[starknet::interface](1)
pub trait IHelloStarknet<TContractState> { (2)
/// Increase contract balance.
fn increase_balance(ref self: TContractState, amount: felt252);
/// Retrieve contract balance.
fn get_balance(self: @TContractState) -> felt252;
}
/// Simple contract for managing balance.
#[starknet::contract]
mod HelloStarknet {
use core::starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess};
#[storage] (3)
struct Storage {
balance: felt252,
}
#[abi(embed_v0)] (4)
impl HelloStarknetImpl of super::IHelloStarknet<ContractState> {
fn increase_balance(ref self: ContractState, amount: felt252) {
assert(amount != 0, 'Amount cannot be 0');
self.balance.write(self.balance.read() + amount);
}
fn get_balance(self: @ContractState) -> felt252 {
self.balance.read()
}
}
}
As its comments read, HelloStarknet
is a simple contract for managing balance. Specifically:
1 | The contract is defined by encapsulating state and logic within a module annotated with the #[starknet::contract] attribute. |
2 | The logic that the contract exposes to the outside world is represented by its interface trait, annotated with the #[starknet::interface] attribute. Here, our contract defines and publicly exposes the functions increase_balance and get_balance . |
3 | The state is defined within the Storage struct, which is always initialized empty. Here, our struct contains a single field called balance of type felt252 . |
4 | The logic itself is defined in the implementation block and annotated with the #[abi(embed_v0)] attribute to expose the implementations to the outside world. Here, increase_balance uses the
write method to increase balance by amount and get_balance uses the read method to return the value of balance . |
Once deployed, each value stored in the HelloStarknet
contract’s storage will be recorded in Starknet’s history.
To review examples of more advanced contracts, see Starknet By Example. |