Getting Started with Cairo

In this tutorial we will set up the environment and write our first Cairo program.

Scarb: the Cairo build tool and package manager

We recommend installing Scarb via the asdf version manager. Each Scarb version is associated with a specific Cairo version, and using asdf will allow you to switch between different compiler versions conveniently. Run the commands below after installing asdf (make sure to add asdf to your ~/.bashrc or ~/.zshrc files as detailed in the installing instructions).

asdf plugin add scarb 
asdf install scarb latest 
asdf global scarb latest

To verify that Scarb was installed successfully, run the following in your terminal of choice:

scarb --version

You can learn more about Scarb in the official documentation.

Creating a new Cairo project

You can create a new Scarb package by running:

scarb new hello_cairo

The above will create the following directory package:

hello_cairo 
|- Scarb.toml 
|- src 
   |- lib.cairo

Scarb.toml is the manifest file for Cairo. It’s where you keep your project metadata and dependencies.

lib.cairo is where you write your code, scarb new creates a default template for us with a main function that calculates the 16’th Fibonacci number:

fn main() -> felt252 { 
    fib(16) 
}

fn fib(mut n: felt252) -> felt252 { 
    let mut a: felt252 = 0; 
    let mut b: felt252 = 1;
    while n != 0 { 
        n = n - 1; 
        let temp = b; 
        b = a + b; 
        a = temp; 
    }; 
    a  
}

#[cfg(test)] 
mod tests { 
    use super::fib; 

    #[test] 
    fn it_works() { 
        assert(fib(16) == 987, 'it works!'); 
     } 
}

We can see that the above code has a function called fib for calculating the n’th Fibonnaci number, and a main function that returns fib(16). Additionally, we have a test module with a single test function that asserts that the value return by fib(16) is 987. For those familiar with Rust, the similarity between the languages is evident. If you’re unfamiliar with Rust, don’t let it discourage you, you can read all about the language’s internals in the cairo-book.

Usually, lib.cairo contains your main function or declaration of other modules.

To build your Cairo package, you should run:

scarb build

To execute main you can use the cairo-run command:

scarb cairo-run

If the template project is not changed, this should print:

Run completed successfully, returning [987]

To run all the test functions (functions annotated with #[test] inside modules annotated with #[cfg(test)]) you can use the scarb test command:

scarb test

If the template project is not changed, this should print:

testing hello_cairo ... 
running 1 tests 
test hello_cairo::tests::it_works ... ok (gas usage est.: 33260) 
test result: ok. 1 passed; 0 failed; 0 ignored; 0 filtered out;

Creating a Starknet smart-contract package

Cairo is a programming language for writing provable programs, but it is more widely known as the smart-contract language of Starknet. A smart contract does not have a main function but rather a list of entry points, each callable from other contracts. While their high-level structure differs, smart contracts have the same syntax as “regular” Cairo programs.

To build a smart contract package, you need to add the following to your Scarb.toml:

[dependencies] 
starknet = ">=2.6.0" 

[[target.starknet-contract]]

We can add a new cairo file to our project, simple_storage.cairo with simple smart contract that externalizes a setter and getter functions for a single u128 storage variable:

#[starknet::interface] 
trait ISimpleStorage<TContractState> { 
     fn set(ref self: TContractState, x: u128);
     fn get(self: @TContractState) -> u128; 
} 

#[starknet::contract] 
mod simple_storage { 
    use starknet::get_caller_address; 
    use starknet::ContractAddress; 

    #[storage] 
    struct Storage { 
        stored_data: u128 
    } 

    #[abi(embed_v0)] 
    impl SimpleStorage of super::ISimpleStorage<ContractState> { 
        fn set(ref self: ContractState, x: u128) { 
            self.stored_data.write(x); 
        } 
        fn get(self: @ContractState) -> u128 { 
            self.stored_data.read() 
        } 
    } 
}

You can learn more about the anatomy of this contract in the Cairo book.

Our project hierarchy now looks like this:

hello_cairo 
|- Scarb.toml 
|- src 
   |- lib.cairo 
   |- simple_storage.cairo

To add the new simple_storage module to our project, we need to add the following line to the lib.cairo file:

mod simple_storage;

This line will cause the compiler to build the contents of simple_storage.cairo.

Now, running scarb build will create a smart-contract artifact hello_cairo_simple_storage.contract_class.json inside ./target/dev. The name of the artifact is <package_name>_<contract_module_name>. These artifacts are known in Starknet as contract classes, and you can learn more about them in the Starknet documentation.

To interact with Starknet and deploy your new contract, you’ll need a Starknet account with enough funds to pay the transaction fees. To this end, we recommend using Starkli, the Starknet-CLI that will allow you to create accounts and interact with the blockchain.