A secure, modular smart contract library for Arbitrum Stylus, written in Rust and inspired by OpenZeppelin Contracts.
Stylus enables high-performance smart contracts in Rust, compiled to WebAssembly (Wasm), for deployment on Arbitrum chains.
- Security-first contracts, ported from the
openzeppelin-contracts
library. - Full support for
no_std
Rust environments. - Ready-to-use unit and integration testing helpers, used in our own tests.
- Familiar, well-documented contract APIs.
Add the crate to your Cargo.toml:
[dependencies]
# We recommend pinning to a specific version.
openzeppelin-stylus = "=0.2.0"
If you want to use the latest features before they are fully stabilized or audited, try the most recent alpha. We release a new alpha version every ~3 weeks.
[dependencies]
openzeppelin-stylus = "=0.3.0-alpha.1"
Enable ABI export support:
[features]
# stylus-sdk/export-abi will be enabled automatically.
export-abi = ["openzeppelin-stylus/export-abi"]
This library is designed for no_std
environments to reduce Wasm size.
Ensure your dependencies also avoid the standard library:
[dependencies] alloy-primitives = { version = "=0.8.20", default-features = false } stylus-sdk = "=0.9.0"
This library requires the Rust nightly toolchain, due to unstable flags used during compilation to reduce the Wasm size of Stylus contracts.
β οΈ Note: While nightly is pinned in this repository viarust-toolchain.toml
, this only affects local development within this repo.
We also include aconfig.toml
to define platform-specific compiler flags.
End-users of the crate must set their own nightly toolchain when compiling projects that use openzeppelin-stylus
.
To compile contracts for Arbitrum Stylus, run:
cargo build --release --target wasm32-unknown-unknown \
-Z build-std=std,panic_abort \
-Z build-std-features=panic_immediate_abort
Once defined as a dependency, use one of our pre-defined implementations by importing them:
use openzeppelin_stylus::token::erc20::{self, Erc20, IErc20};
use stylus_sdk::{
alloy_primitives::{Address, U256},
prelude::*,
};
#[entrypoint]
#[storage]
struct Erc20Example {
erc20: Erc20,
}
#[public]
#[implements(IErc20<Error = erc20::Error>)]
impl Erc20Example {}
#[public]
impl IErc20 for Erc20Example {
type Error = erc20::Error;
fn total_supply(&self) -> U256 {
self.erc20.total_supply()
}
fn balance_of(&self, account: Address) -> U256 {
self.erc20.balance_of(account)
}
fn transfer(
&mut self,
to: Address,
value: U256,
) -> Result<bool, Self::Error> {
self.erc20.transfer(to, value)
}
fn allowance(&self, owner: Address, spender: Address) -> U256 {
self.erc20.allowance(owner, spender)
}
fn approve(
&mut self,
spender: Address,
value: U256,
) -> Result<bool, Self::Error> {
self.erc20.approve(spender, value)
}
fn transfer_from(
&mut self,
from: Address,
to: Address,
value: U256,
) -> Result<bool, Self::Error> {
self.erc20.transfer_from(from, to, value)
}
}
For a working demo with deployment and queries, check out the basic example.
- Examples: Browse our examples folder for full project templates.
- Test helpers: See unit and integration testing utilities.
- Roadmap: Follow planned features and modules in our roadmap.
OpenZeppelin Contracts for Stylus exists thanks to its contributors. There are many ways you can participate and help build high-quality software. Check out the contribution guide!
- Past audits: See the
audits
folder. - Refer to our Security Policy for guidelines on reporting vulnerabilities.
OpenZeppelin Contracts for Stylus is released under the MIT License.