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.
Before installing Cairo on your machine, you need to install gmp
:
sudo apt install -y libgmp3-dev # linux
brew install gmp # mac
If you have any troubles installing gmp on your Apple M1 computer, here’s a list of potential solutions.
Create a directory for your project, then cd
into it and create a Python virtual environment.
mkdir my-project
cd my-project
python3 -m venv env
source env/bin/activate
Install the Nile development environment and then run init
to kickstart a new project. Nile will create the project directory structure and install the Cairo language, a local network, and a testing framework.
pip install cairo-nile
nile init
pip install openzeppelin-cairo-contracts
⚠️ Warning!⚠️
Installing directly themain
branch may contain incomplete or breaking implementations, download official releases only.
Presets are ready-to-use contracts that you can deploy right away. They also serve as examples of how to use library modules. Read more about presets.
// contracts/MyToken.cairo
%lang starknet
from openzeppelin.token.erc20.presets.ERC20 import (
constructor,
name,
symbol,
totalSupply,
decimals,
balanceOf,
allowance,
transfer,
transferFrom,
approve,
increaseAllowance,
decreaseAllowance
)
Compile and deploy it right away:
nile compile
nile deploy MyToken <name> <symbol> <decimals> <initial_supply> <recipient> --alias my_token
Note that
<initial_supply>
is expected to be two integers i.e.1
0
. See Uint256 for more information.
%lang starknet
from starkware.cairo.common.cairo_builtins import HashBuiltin
from starkware.cairo.common.uint256 import Uint256
from openzeppelin.security.pausable.library import Pausable
from openzeppelin.token.erc20.library import ERC20
(...)
@external
func transfer{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
recipient: felt, amount: Uint256
) -> (success: felt) {
Pausable.assert_not_paused();
return ERC20.transfer(recipient, amount);
}
Check out the full documentation site! Featuring:
- Accounts
- ERC20
- ERC721
- ERC1155
- Contract extensibility pattern
- Proxies and upgrades
- Security
- Utilities
- StarkNet official documentation
- Cairo language documentation
- Perama's Cairo by example
- Cairo 101 workshops
Clone the repository
git clone git@github.com:OpenZeppelin/cairo-contracts.git
cd
into it and create a Python virtual environment:
cd cairo-contracts
python3 -m venv env
source env/bin/activate
Install dependencies:
python -m pip install .
nile compile --directory src
🤖 Compiling all Cairo contracts in the src directory
🔨 Compiling src/openzeppelin/token/erc20/library.cairo
🔨 Compiling src/openzeppelin/token/erc20/presets/ERC20Mintable.cairo
🔨 Compiling src/openzeppelin/token/erc20/presets/ERC20Pausable.cairo
🔨 Compiling src/openzeppelin/token/erc20/presets/ERC20Upgradeable.cairo
🔨 Compiling src/openzeppelin/token/erc20/presets/ERC20.cairo
🔨 Compiling src/openzeppelin/token/erc20/IERC20.cairo
🔨 Compiling src/openzeppelin/token/erc721/enumerable/library.cairo
🔨 Compiling src/openzeppelin/token/erc721/library.cairo
🔨 Compiling src/openzeppelin/token/erc721/utils/ERC721Holder.cairo
🔨 Compiling src/openzeppelin/token/erc721/presets/ERC721MintablePausable.cairo
🔨 Compiling src/openzeppelin/token/erc721/presets/ERC721MintableBurnable.cairo
🔨 Compiling src/openzeppelin/token/erc721/presets/ERC721EnumerableMintableBurnable.cairo
🔨 Compiling src/openzeppelin/token/erc721/IERC721.cairo
🔨 Compiling src/openzeppelin/token/erc721/IERC721Metadata.cairo
🔨 Compiling src/openzeppelin/token/erc721/IERC721Receiver.cairo
🔨 Compiling src/openzeppelin/token/erc721/enumerable/IERC721Enumerable.cairo
🔨 Compiling src/openzeppelin/access/ownable/library.cairo
🔨 Compiling src/openzeppelin/security/reentrancyguard/library.cairo
🔨 Compiling src/openzeppelin/security/safemath/library.cairo
🔨 Compiling src/openzeppelin/security/pausable/library.cairo
🔨 Compiling src/openzeppelin/security/initializable/library.cairo
🔨 Compiling src/openzeppelin/utils/constants/library.cairo
🔨 Compiling src/openzeppelin/introspection/erc165/library.cairo
🔨 Compiling src/openzeppelin/introspection/erc165/IERC165.cairo
🔨 Compiling src/openzeppelin/upgrades/library.cairo
🔨 Compiling src/openzeppelin/upgrades/presets/Proxy.cairo
🔨 Compiling src/openzeppelin/account/library.cairo
🔨 Compiling src/openzeppelin/account/presets/EthAccount.cairo
🔨 Compiling src/openzeppelin/account/presets/Account.cairo
🔨 Compiling src/openzeppelin/account/presets/AddressRegistry.cairo
🔨 Compiling src/openzeppelin/account/IAccount.cairo
✅ Done
Run tests using tox, tox automatically creates an isolated testing environment:
tox
====================== test session starts ======================
platform linux -- Python 3.7.2, pytest-7.1.2, py-1.11.0, pluggy-1.0.0
rootdir: /home/readme/cairo-contracts, configfile: tox.ini
plugins: asyncio-0.18.3, xdist-2.5.0, forked-1.4.0, web3-5.29.0, typeguard-2.13.3
asyncio: mode=auto
gw0 [185] / gw1 [185]
......................................................................................
......................................................................................
............ [100%]
For M1 users or those who are having trouble with library/python versions you can alternatively run the tests within a docker container. Using the following as a Dockerfile placed in the root directory of the project:
FROM python:3.7
RUN pip install tox
RUN mkdir cairo-contracts
COPY . cairo-contracts
WORKDIR cairo-contracts
ENTRYPOINT tox
After its placed there run:
docker build -t cairo-tests .
docker run cairo-tests
This repo utilizes the pytest-xdist plugin which runs tests in parallel. This feature increases testing speed; however, conflicts with a shared state can occur since tests do not run in order. To overcome this, independent cached versions of contracts being tested should be provisioned to each test case. Here's a simple fixture example:
from utils import get_contract_class, cached_contract
@pytest.fixture
def foo_factory():
# get contract class
foo_cls = get_contract_class('Foo')
# deploy contract
starknet = await Starknet.empty()
foo = await starknet.deploy(contract_class=foo_cls)
# copy the state and cache contract
state = starknet.state.copy()
cached_foo = cached_contract(state, foo_cls, foo)
return cached_foo
See Memoization in the Utilities documentation for a more thorough example on caching contracts.
Note that this does not apply for stateless libraries such as SafeMath.
⚠️ Warning!⚠️ This project is still in a very early and experimental phase. It has never been audited nor thoroughly reviewed for security vulnerabilities. Do not use in production.
Refer to SECURITY.md for more details.
OpenZeppelin Contracts for Cairo exists thanks to its contributors. There are many ways you can participate and help build high quality software. Check out the contribution guide!
To keep the markdown files neat and easy to edit, we utilize DavidAnson's markdownlint linter. You can find the listed rules here. Note that the following rules are disabled:
-
MD013: line length
- to enable paragraphs without internal line breaks
-
MD033: inline HTML
- to enable .md files to have duplicate headers and separate them by identifiers
Before creating a PR, check that documentation changes are compliant with our markdown rules by running:
tox -e lint
OpenZeppelin Contracts for Cairo is released under the MIT License.