Contracts for Cairo

A library for secure smart contract development written in Cairo for Starknet, a decentralized ZK Rollup.

This repo contains highly experimental code. Expect rapid iteration. Use at your own risk.


The library is available as a Scarb package. Follow this guide for installing Cairo and Scarb on your machine before proceeding, and run the following command to check that the installation was successful:

$ scarb --version

scarb 0.8.0-beta.1 (58cc88efb 2023-08-23)
cairo: 2.2.0 (
sierra: 1.3.0

Set up your project

Create an empty directory, and cd into it:

mkdir my_project/ && cd my_project/

Initialize a new Scarb project:

scarb init

The contents of my_project/ should now look like this:

$ ls

Scarb.toml src

Install the library

Install the library by declaring it as a dependency in the project’s Scarb.toml file:

openzeppelin = { git = "", tag = "v0.8.0-beta.1" }
Make sure the tag matches the target release.

Basic usage

This is how it looks to build an account contract using the account module. Copy the code into src/lib.cairo.

mod MyAccount {
    use openzeppelin::account::Account;
    use openzeppelin::account::account::PublicKeyTrait;
    use openzeppelin::account::interface;
    use openzeppelin::introspection::interface::ISRC5;
    use starknet::account::Call;

    // Storage members used by this contract are defined in each imported
    // module whose `unsafe_state` is used. This design will be improved
    // with the addition of components in the future.
    struct Storage {}

    fn constructor(ref self: ContractState, public_key: felt252) {
        let mut unsafe_state = _unsafe_state();
        Account::InternalImpl::initializer(ref unsafe_state, public_key);

    impl SRC6Impl of interface::ISRC6<ContractState> {
        fn __execute__(self: @ContractState, mut calls: Array<Call>) -> Array<Span<felt252>> {
            Account::SRC6Impl::__execute__(@_unsafe_state(), calls)

        fn __validate__(self: @ContractState, mut calls: Array<Call>) -> felt252 {
            Account::SRC6Impl::__validate__(@_unsafe_state(), calls)

        fn is_valid_signature(
            self: @ContractState, hash: felt252, signature: Array<felt252>
        ) -> felt252 {
            Account::SRC6Impl::is_valid_signature(@_unsafe_state(), hash, signature)

    impl SRC5Impl of ISRC5<ContractState> {
        fn supports_interface(self: @ContractState, interface_id: felt252) -> bool {
            Account::SRC5Impl::supports_interface(@_unsafe_state(), interface_id)

    impl PublicKeyImpl of PublicKeyTrait<ContractState> {
        fn get_public_key(self: @ContractState) -> felt252 {

        fn set_public_key(ref self: ContractState, new_public_key: felt252) {
            let mut unsafe_state = _unsafe_state();
            Account::PublicKeyImpl::set_public_key(ref unsafe_state, new_public_key);

    fn __validate_deploy__(
        self: @ContractState,
        class_hash: felt252,
        contract_address_salt: felt252,
        _public_key: felt252
    ) -> felt252 {
            @_unsafe_state(), class_hash, contract_address_salt, _public_key

    fn _unsafe_state() -> Account::ContractState {

You can now compile it:

scarb build