-
Notifications
You must be signed in to change notification settings - Fork 358
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'cairo-2' of github.com:OpenZeppelin/cairo-contracts int…
…o feat/update-introspection-docs-#567
- Loading branch information
Showing
5 changed files
with
311 additions
and
91 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,115 +1,149 @@ | ||
= Contracts for Cairo | ||
:starknet: https://starkware.co/product/starknet/[Starknet] | ||
:scarb: https://docs.swmansion.com/scarb[Scarb] | ||
:installation: https://docs.swmansion.com/scarb/download.html[this guide] | ||
|
||
*A library for secure smart contract development* written in Cairo for https://starkware.co/product/starknet/[StarkNet], a decentralized ZK Rollup. | ||
= Contracts for Cairo | ||
|
||
== Usage | ||
*A library for secure smart contract development* written in Cairo for {starknet}, a decentralized ZK Rollup. | ||
|
||
WARNING: This repo contains highly experimental code. Expect rapid iteration. *Use at your own risk.* | ||
|
||
=== First time? | ||
== Installation | ||
|
||
Before installing Cairo on your machine, you need to install `gmp`: | ||
The library is available as a {scarb} package. Follow {installation} for installing Cairo and Scarb on your machine | ||
before proceeding, and run the following command to check that the installation was successful: | ||
|
||
[,bash] | ||
---- | ||
sudo apt install -y libgmp3-dev # linux | ||
brew install gmp # mac | ||
---- | ||
$ scarb --version | ||
TIP: If you have any trouble installing gmp on your Apple M1 computer, https://github.com/OpenZeppelin/nile/issues/22[here's a list of potential solutions]. | ||
scarb 0.7.0 (58cc88efb 2023-08-23) | ||
cairo: 2.2.0 (https://crates.io/crates/cairo-lang-compiler/2.2.0) | ||
sierra: 1.3.0 | ||
---- | ||
|
||
=== Set up your project | ||
|
||
Create a directory for your project, then `cd` into it and create a Python virtual environment. | ||
Create an empty directory, and `cd` into it: | ||
|
||
[,bash] | ||
---- | ||
mkdir my-project | ||
cd my-project | ||
python3 -m venv env | ||
source env/bin/activate | ||
mkdir my_project/ && cd my_project/ | ||
---- | ||
|
||
Install the https://github.com/OpenZeppelin/nile[Nile] development environment and then run `init` to kickstart a new project. | ||
Nile will create the project directory structure and install https://www.cairo-lang.org/docs/quickstart.html[the Cairo language], a https://github.com/Shard-Labs/starknet-devnet/[local network], and a https://docs.pytest.org/en/6.2.x/[testing framework]. | ||
Initialize a new Scarb project: | ||
|
||
[,bash] | ||
---- | ||
pip install cairo-nile | ||
nile init | ||
scarb init | ||
---- | ||
|
||
=== Install the library | ||
The contents of `my_project/` should now look like this: | ||
|
||
[,bash] | ||
---- | ||
pip install openzeppelin-cairo-contracts | ||
---- | ||
|
||
WARNING: Installing directly through GitHub may contain incomplete or breaking implementations. | ||
While we aim not to introduce such changes, we still strongly recommend installing through https://github.com/OpenZeppelin/cairo-contracts/releases/[official releases]. | ||
|
||
=== Use a basic preset | ||
$ ls | ||
Presets are ready-to-use contracts that you can deploy right away. | ||
They also serve as examples of how to use library modules. | ||
xref:extensibility.adoc#presets[Read more about presets]. | ||
|
||
[,cairo] | ||
---- | ||
// contracts/MyToken.cairo | ||
%lang starknet | ||
from openzeppelin.token.erc20.presets.ERC20 import ( | ||
constructor, | ||
name, | ||
symbol, | ||
totalSupply, | ||
decimals, | ||
balanceOf, | ||
allowance, | ||
transfer, | ||
transferFrom, | ||
approve, | ||
increaseAllowance, | ||
decreaseAllowance | ||
) | ||
Scarb.toml src | ||
---- | ||
|
||
Compile and deploy it right away: | ||
=== Install the library | ||
|
||
[,bash] | ||
---- | ||
nile compile | ||
Install the library by declaring it as a dependency in the project's `Scarb.toml` file: | ||
|
||
nile deploy MyToken <name> <symbol> <decimals> <initial_supply> <recipient> --alias my_token | ||
[,text] | ||
---- | ||
[dependencies] | ||
openzeppelin = { git = "https://github.com/OpenZeppelin/cairo-contracts.git", tag = "v0.7.0" } | ||
---- | ||
|
||
NOTE: `<initial_supply>` is expected to be two integers i.e. | ||
`1` `0`. | ||
See xref:utilities.adoc#uint256[uint256] for more information. | ||
WARNING: Make sure the tag matches the target release. | ||
|
||
=== Write a custom contract using library modules | ||
== Basic usage | ||
|
||
xref:extensibility.adoc#libraries[Read more about libraries]. | ||
This is how it looks to build an account contract using the xref:accounts.adoc[account module]. | ||
Copy the code into `src/lib.cairo`. | ||
|
||
[,cairo] | ||
[,javascript] | ||
---- | ||
#[starknet::contract] | ||
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. | ||
#[storage] | ||
struct Storage {} | ||
#[constructor] | ||
fn constructor(ref self: ContractState, public_key: felt252) { | ||
let mut unsafe_state = _unsafe_state(); | ||
Account::InternalImpl::initializer(ref unsafe_state, public_key); | ||
} | ||
#[external(v0)] | ||
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) | ||
} | ||
} | ||
#[external(v0)] | ||
impl SRC5Impl of ISRC5<ContractState> { | ||
fn supports_interface(self: @ContractState, interface_id: felt252) -> bool { | ||
Account::SRC5Impl::supports_interface(@_unsafe_state(), interface_id) | ||
} | ||
} | ||
#[external(v0)] | ||
impl PublicKeyImpl of PublicKeyTrait<ContractState> { | ||
fn get_public_key(self: @ContractState) -> felt252 { | ||
Account::PublicKeyImpl::get_public_key(@_unsafe_state()) | ||
} | ||
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); | ||
} | ||
} | ||
#[external(v0)] | ||
fn __validate_deploy__( | ||
self: @ContractState, | ||
class_hash: felt252, | ||
contract_address_salt: felt252, | ||
_public_key: felt252 | ||
) -> felt252 { | ||
Account::__validate_deploy__( | ||
@_unsafe_state(), class_hash, contract_address_salt, _public_key | ||
) | ||
} | ||
#[inline(always)] | ||
fn _unsafe_state() -> Account::ContractState { | ||
Account::unsafe_new_contract_state() | ||
} | ||
} | ||
---- | ||
%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 | ||
|
||
(...) | ||
You can now compile it: | ||
|
||
@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); | ||
} | ||
[,bash] | ||
---- | ||
scarb build | ||
---- |
Oops, something went wrong.