Contracts for Cairo

A library for secure smart contract development written in Cairo for Starknet. This library consists of a set of reusable components to build custom smart contracts, as well as ready-to-deploy presets. You can also find other utilities including interfaces and dispatchers and test utilities that facilitate testing with Starknet Foundry.

This repo contains highly experimental code. Expect rapid iteration. Use at your own risk.
You can track our roadmap and future milestones in our Github Project.

Installation

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 2.9.4 (d3be9ebe1 2025-02-19)
cairo: 2.9.4 (https://crates.io/crates/cairo-lang-compiler/2.9.4)
sierra: 1.6.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:

[dependencies]
openzeppelin = "1.0.0"

The previous example would import the entire library. We can also add each package as a separate dependency to improve the building time by not including modules that won’t be used:

[dependencies]
openzeppelin_access = "1.0.0"
openzeppelin_token = "1.0.0"

Basic usage

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

If you added the entire library as a dependency, use openzeppelin::token instead of openzeppelin_token for the imports.
#[starknet::contract]
mod MyERC20Token {
    use openzeppelin_token::erc20::{ERC20Component, ERC20HooksEmptyImpl};
    use starknet::ContractAddress;

    component!(path: ERC20Component, storage: erc20, event: ERC20Event);

    // ERC20 Mixin
    #[abi(embed_v0)]
    impl ERC20MixinImpl = ERC20Component::ERC20MixinImpl<ContractState>;
    impl ERC20InternalImpl = ERC20Component::InternalImpl<ContractState>;

    #[storage]
    struct Storage {
        #[substorage(v0)]
        erc20: ERC20Component::Storage
    }

    #[event]
    #[derive(Drop, starknet::Event)]
    enum Event {
        #[flat]
        ERC20Event: ERC20Component::Event
    }

    #[constructor]
    fn constructor(
        ref self: ContractState,
        name: ByteArray,
        symbol: ByteArray,
        fixed_supply: u256,
        recipient: ContractAddress
    ) {
        self.erc20.initializer(name, symbol);
        self.erc20.mint(recipient, fixed_supply);
    }
}

You can now compile it:

scarb build