$npx -y skills add OpenZeppelin/openzeppelin-skills --skill setup-cairo-contractsSet up a Cairo smart contract project with OpenZeppelin Contracts for Cairo on Starknet. Use when users need to: (1) create a new Scarb/Starknet project, (2) add OpenZeppelin Contracts for Cairo dependencies to Scarb.toml, (3) configure individual or umbrella OpenZeppelin package
| 1 | # Cairo Setup |
| 2 | |
| 3 | ## Project Scaffolding |
| 4 | |
| 5 | Install toolchain and create a project: |
| 6 | |
| 7 | ```bash |
| 8 | curl --proto '=https' --tlsv1.2 -sSf https://sh.starkup.sh | sh |
| 9 | scarb new my_project --test-runner=starknet-foundry |
| 10 | ``` |
| 11 | |
| 12 | This scaffolds a complete Starknet project with `snforge` testing preconfigured. |
| 13 | |
| 14 | ## OpenZeppelin Dependencies |
| 15 | |
| 16 | Look up the current version from https://docs.openzeppelin.com/contracts-cairo before adding. Add to `Scarb.toml`: |
| 17 | |
| 18 | Full library (umbrella package): |
| 19 | |
| 20 | ```toml |
| 21 | [dependencies] |
| 22 | openzeppelin = "<VERSION>" |
| 23 | ``` |
| 24 | |
| 25 | Individual packages (faster builds — only compiles what you use): |
| 26 | |
| 27 | ```toml |
| 28 | [dependencies] |
| 29 | openzeppelin_token = "<VERSION>" |
| 30 | openzeppelin_access = "<VERSION>" |
| 31 | ``` |
| 32 | |
| 33 | Available individual packages: `openzeppelin_access`, `openzeppelin_account`, `openzeppelin_finance`, `openzeppelin_governance`, `openzeppelin_interfaces`, `openzeppelin_introspection`, `openzeppelin_merkle_tree`, `openzeppelin_presets`, `openzeppelin_security`, `openzeppelin_token`, `openzeppelin_upgrades`, `openzeppelin_utils`. |
| 34 | |
| 35 | > `openzeppelin_interfaces` and `openzeppelin_utils` are versioned independently. Check the docs for their specific versions. All other packages share the same version. |
| 36 | |
| 37 | ## Import Conventions |
| 38 | |
| 39 | The import path depends on which dependency is declared: |
| 40 | |
| 41 | - **Umbrella package** (`openzeppelin = "..."`): use `openzeppelin::` as the root |
| 42 | - **Individual packages** (`openzeppelin_token = "..."`): use the package name as the root |
| 43 | |
| 44 | ```cairo |
| 45 | // Individual packages |
| 46 | use openzeppelin_token::erc20::{ERC20Component, ERC20HooksEmptyImpl}; |
| 47 | use openzeppelin_access::ownable::OwnableComponent; |
| 48 | use openzeppelin_upgrades::UpgradeableComponent; |
| 49 | |
| 50 | // Umbrella package equivalents |
| 51 | use openzeppelin::token::erc20::{ERC20Component, ERC20HooksEmptyImpl}; |
| 52 | use openzeppelin::access::ownable::OwnableComponent; |
| 53 | use openzeppelin::upgrades::UpgradeableComponent; |
| 54 | ``` |
| 55 | |
| 56 | Components are integrated via the `component!` macro, embedded impls, and substorage: |
| 57 | |
| 58 | ```cairo |
| 59 | component!(path: ERC20Component, storage: erc20, event: ERC20Event); |
| 60 | |
| 61 | #[abi(embed_v0)] |
| 62 | impl ERC20MixinImpl = ERC20Component::ERC20MixinImpl<ContractState>; |
| 63 | impl ERC20InternalImpl = ERC20Component::InternalImpl<ContractState>; |
| 64 | ``` |