erc20.test.ts.md•68.2 kB
# Snapshot report for `src/erc20.test.ts`
The actual snapshot is saved in `erc20.test.ts.snap`.
Generated by [AVA](https://avajs.dev).
## basic erc20, non-upgradeable
> Snapshot 1
`// SPDX-License-Identifier: MIT␊
// Compatible with OpenZeppelin Contracts for Cairo ^2.0.0␊
␊
#[starknet::contract]␊
mod MyToken {␊
use openzeppelin::token::erc20::{␊
DefaultConfig as ERC20DefaultConfig, ERC20Component, ERC20HooksEmptyImpl␊
};␊
␊
component!(path: ERC20Component, storage: erc20, event: ERC20Event);␊
␊
// External␊
#[abi(embed_v0)]␊
impl ERC20MixinImpl = ERC20Component::ERC20MixinImpl<ContractState>;␊
␊
// Internal␊
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) {␊
self.erc20.initializer("MyToken", "MTK");␊
}␊
}␊
`
## basic erc20
> Snapshot 1
`// SPDX-License-Identifier: MIT␊
// Compatible with OpenZeppelin Contracts for Cairo ^2.0.0␊
␊
#[starknet::contract]␊
mod MyToken {␊
use openzeppelin::access::ownable::OwnableComponent;␊
use openzeppelin::token::erc20::{␊
DefaultConfig as ERC20DefaultConfig, ERC20Component, ERC20HooksEmptyImpl␊
};␊
use openzeppelin::upgrades::interface::IUpgradeable;␊
use openzeppelin::upgrades::UpgradeableComponent;␊
use starknet::{ClassHash, ContractAddress};␊
␊
component!(path: ERC20Component, storage: erc20, event: ERC20Event);␊
component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊
component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);␊
␊
// External␊
#[abi(embed_v0)]␊
impl ERC20MixinImpl = ERC20Component::ERC20MixinImpl<ContractState>;␊
#[abi(embed_v0)]␊
impl OwnableMixinImpl = OwnableComponent::OwnableMixinImpl<ContractState>;␊
␊
// Internal␊
impl ERC20InternalImpl = ERC20Component::InternalImpl<ContractState>;␊
impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl<ContractState>;␊
impl OwnableInternalImpl = OwnableComponent::InternalImpl<ContractState>;␊
␊
#[storage]␊
struct Storage {␊
#[substorage(v0)]␊
erc20: ERC20Component::Storage,␊
#[substorage(v0)]␊
upgradeable: UpgradeableComponent::Storage,␊
#[substorage(v0)]␊
ownable: OwnableComponent::Storage,␊
}␊
␊
#[event]␊
#[derive(Drop, starknet::Event)]␊
enum Event {␊
#[flat]␊
ERC20Event: ERC20Component::Event,␊
#[flat]␊
UpgradeableEvent: UpgradeableComponent::Event,␊
#[flat]␊
OwnableEvent: OwnableComponent::Event,␊
}␊
␊
#[constructor]␊
fn constructor(ref self: ContractState, owner: ContractAddress) {␊
self.erc20.initializer("MyToken", "MTK");␊
self.ownable.initializer(owner);␊
}␊
␊
//␊
// Upgradeable␊
//␊
␊
#[abi(embed_v0)]␊
impl UpgradeableImpl of IUpgradeable<ContractState> {␊
fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊
self.ownable.assert_only_owner();␊
self.upgradeable.upgrade(new_class_hash);␊
}␊
}␊
}␊
`
## erc20 burnable
> Snapshot 1
`// SPDX-License-Identifier: MIT␊
// Compatible with OpenZeppelin Contracts for Cairo ^2.0.0␊
␊
#[starknet::contract]␊
mod MyToken {␊
use openzeppelin::access::ownable::OwnableComponent;␊
use openzeppelin::token::erc20::{␊
DefaultConfig as ERC20DefaultConfig, ERC20Component, ERC20HooksEmptyImpl␊
};␊
use openzeppelin::upgrades::interface::IUpgradeable;␊
use openzeppelin::upgrades::UpgradeableComponent;␊
use starknet::{ClassHash, ContractAddress, get_caller_address};␊
␊
component!(path: ERC20Component, storage: erc20, event: ERC20Event);␊
component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊
component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);␊
␊
// External␊
#[abi(embed_v0)]␊
impl ERC20MixinImpl = ERC20Component::ERC20MixinImpl<ContractState>;␊
#[abi(embed_v0)]␊
impl OwnableMixinImpl = OwnableComponent::OwnableMixinImpl<ContractState>;␊
␊
// Internal␊
impl ERC20InternalImpl = ERC20Component::InternalImpl<ContractState>;␊
impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl<ContractState>;␊
impl OwnableInternalImpl = OwnableComponent::InternalImpl<ContractState>;␊
␊
#[storage]␊
struct Storage {␊
#[substorage(v0)]␊
erc20: ERC20Component::Storage,␊
#[substorage(v0)]␊
upgradeable: UpgradeableComponent::Storage,␊
#[substorage(v0)]␊
ownable: OwnableComponent::Storage,␊
}␊
␊
#[event]␊
#[derive(Drop, starknet::Event)]␊
enum Event {␊
#[flat]␊
ERC20Event: ERC20Component::Event,␊
#[flat]␊
UpgradeableEvent: UpgradeableComponent::Event,␊
#[flat]␊
OwnableEvent: OwnableComponent::Event,␊
}␊
␊
#[constructor]␊
fn constructor(ref self: ContractState, owner: ContractAddress) {␊
self.erc20.initializer("MyToken", "MTK");␊
self.ownable.initializer(owner);␊
}␊
␊
#[generate_trait]␊
#[abi(per_item)]␊
impl ExternalImpl of ExternalTrait {␊
#[external(v0)]␊
fn burn(ref self: ContractState, value: u256) {␊
self.erc20.burn(get_caller_address(), value);␊
}␊
}␊
␊
//␊
// Upgradeable␊
//␊
␊
#[abi(embed_v0)]␊
impl UpgradeableImpl of IUpgradeable<ContractState> {␊
fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊
self.ownable.assert_only_owner();␊
self.upgradeable.upgrade(new_class_hash);␊
}␊
}␊
}␊
`
## erc20 pausable
> Snapshot 1
`// SPDX-License-Identifier: MIT␊
// Compatible with OpenZeppelin Contracts for Cairo ^2.0.0␊
␊
#[starknet::contract]␊
mod MyToken {␊
use openzeppelin::access::ownable::OwnableComponent;␊
use openzeppelin::security::pausable::PausableComponent;␊
use openzeppelin::token::erc20::{DefaultConfig as ERC20DefaultConfig, ERC20Component};␊
use openzeppelin::upgrades::interface::IUpgradeable;␊
use openzeppelin::upgrades::UpgradeableComponent;␊
use starknet::{ClassHash, ContractAddress};␊
␊
component!(path: ERC20Component, storage: erc20, event: ERC20Event);␊
component!(path: PausableComponent, storage: pausable, event: PausableEvent);␊
component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);␊
component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊
␊
// External␊
#[abi(embed_v0)]␊
impl ERC20MixinImpl = ERC20Component::ERC20MixinImpl<ContractState>;␊
#[abi(embed_v0)]␊
impl PausableImpl = PausableComponent::PausableImpl<ContractState>;␊
#[abi(embed_v0)]␊
impl OwnableMixinImpl = OwnableComponent::OwnableMixinImpl<ContractState>;␊
␊
// Internal␊
impl ERC20InternalImpl = ERC20Component::InternalImpl<ContractState>;␊
impl PausableInternalImpl = PausableComponent::InternalImpl<ContractState>;␊
impl OwnableInternalImpl = OwnableComponent::InternalImpl<ContractState>;␊
impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl<ContractState>;␊
␊
#[storage]␊
struct Storage {␊
#[substorage(v0)]␊
erc20: ERC20Component::Storage,␊
#[substorage(v0)]␊
pausable: PausableComponent::Storage,␊
#[substorage(v0)]␊
ownable: OwnableComponent::Storage,␊
#[substorage(v0)]␊
upgradeable: UpgradeableComponent::Storage,␊
}␊
␊
#[event]␊
#[derive(Drop, starknet::Event)]␊
enum Event {␊
#[flat]␊
ERC20Event: ERC20Component::Event,␊
#[flat]␊
PausableEvent: PausableComponent::Event,␊
#[flat]␊
OwnableEvent: OwnableComponent::Event,␊
#[flat]␊
UpgradeableEvent: UpgradeableComponent::Event,␊
}␊
␊
#[constructor]␊
fn constructor(ref self: ContractState, owner: ContractAddress) {␊
self.erc20.initializer("MyToken", "MTK");␊
self.ownable.initializer(owner);␊
}␊
␊
impl ERC20HooksImpl of ERC20Component::ERC20HooksTrait<ContractState> {␊
fn before_update(␊
ref self: ERC20Component::ComponentState<ContractState>,␊
from: ContractAddress,␊
recipient: ContractAddress,␊
amount: u256,␊
) {␊
let contract_state = self.get_contract();␊
contract_state.pausable.assert_not_paused();␊
}␊
}␊
␊
#[generate_trait]␊
#[abi(per_item)]␊
impl ExternalImpl of ExternalTrait {␊
#[external(v0)]␊
fn pause(ref self: ContractState) {␊
self.ownable.assert_only_owner();␊
self.pausable.pause();␊
}␊
␊
#[external(v0)]␊
fn unpause(ref self: ContractState) {␊
self.ownable.assert_only_owner();␊
self.pausable.unpause();␊
}␊
}␊
␊
//␊
// Upgradeable␊
//␊
␊
#[abi(embed_v0)]␊
impl UpgradeableImpl of IUpgradeable<ContractState> {␊
fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊
self.ownable.assert_only_owner();␊
self.upgradeable.upgrade(new_class_hash);␊
}␊
}␊
}␊
`
## erc20 pausable with roles
> Snapshot 1
`// SPDX-License-Identifier: MIT␊
// Compatible with OpenZeppelin Contracts for Cairo ^2.0.0␊
␊
const PAUSER_ROLE: felt252 = selector!("PAUSER_ROLE");␊
const UPGRADER_ROLE: felt252 = selector!("UPGRADER_ROLE");␊
␊
#[starknet::contract]␊
mod MyToken {␊
use openzeppelin::access::accesscontrol::{AccessControlComponent, DEFAULT_ADMIN_ROLE};␊
use openzeppelin::introspection::src5::SRC5Component;␊
use openzeppelin::security::pausable::PausableComponent;␊
use openzeppelin::token::erc20::{DefaultConfig as ERC20DefaultConfig, ERC20Component};␊
use openzeppelin::upgrades::interface::IUpgradeable;␊
use openzeppelin::upgrades::UpgradeableComponent;␊
use starknet::{ClassHash, ContractAddress};␊
use super::{PAUSER_ROLE, UPGRADER_ROLE};␊
␊
component!(path: ERC20Component, storage: erc20, event: ERC20Event);␊
component!(path: PausableComponent, storage: pausable, event: PausableEvent);␊
component!(path: AccessControlComponent, storage: accesscontrol, event: AccessControlEvent);␊
component!(path: SRC5Component, storage: src5, event: SRC5Event);␊
component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊
␊
// External␊
#[abi(embed_v0)]␊
impl ERC20MixinImpl = ERC20Component::ERC20MixinImpl<ContractState>;␊
#[abi(embed_v0)]␊
impl PausableImpl = PausableComponent::PausableImpl<ContractState>;␊
#[abi(embed_v0)]␊
impl AccessControlMixinImpl = AccessControlComponent::AccessControlMixinImpl<ContractState>;␊
␊
// Internal␊
impl ERC20InternalImpl = ERC20Component::InternalImpl<ContractState>;␊
impl PausableInternalImpl = PausableComponent::InternalImpl<ContractState>;␊
impl AccessControlInternalImpl = AccessControlComponent::InternalImpl<ContractState>;␊
impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl<ContractState>;␊
␊
#[storage]␊
struct Storage {␊
#[substorage(v0)]␊
erc20: ERC20Component::Storage,␊
#[substorage(v0)]␊
pausable: PausableComponent::Storage,␊
#[substorage(v0)]␊
accesscontrol: AccessControlComponent::Storage,␊
#[substorage(v0)]␊
src5: SRC5Component::Storage,␊
#[substorage(v0)]␊
upgradeable: UpgradeableComponent::Storage,␊
}␊
␊
#[event]␊
#[derive(Drop, starknet::Event)]␊
enum Event {␊
#[flat]␊
ERC20Event: ERC20Component::Event,␊
#[flat]␊
PausableEvent: PausableComponent::Event,␊
#[flat]␊
AccessControlEvent: AccessControlComponent::Event,␊
#[flat]␊
SRC5Event: SRC5Component::Event,␊
#[flat]␊
UpgradeableEvent: UpgradeableComponent::Event,␊
}␊
␊
#[constructor]␊
fn constructor(␊
ref self: ContractState,␊
default_admin: ContractAddress,␊
pauser: ContractAddress,␊
upgrader: ContractAddress,␊
) {␊
self.erc20.initializer("MyToken", "MTK");␊
self.accesscontrol.initializer();␊
␊
self.accesscontrol._grant_role(DEFAULT_ADMIN_ROLE, default_admin);␊
self.accesscontrol._grant_role(PAUSER_ROLE, pauser);␊
self.accesscontrol._grant_role(UPGRADER_ROLE, upgrader);␊
}␊
␊
impl ERC20HooksImpl of ERC20Component::ERC20HooksTrait<ContractState> {␊
fn before_update(␊
ref self: ERC20Component::ComponentState<ContractState>,␊
from: ContractAddress,␊
recipient: ContractAddress,␊
amount: u256,␊
) {␊
let contract_state = self.get_contract();␊
contract_state.pausable.assert_not_paused();␊
}␊
}␊
␊
#[generate_trait]␊
#[abi(per_item)]␊
impl ExternalImpl of ExternalTrait {␊
#[external(v0)]␊
fn pause(ref self: ContractState) {␊
self.accesscontrol.assert_only_role(PAUSER_ROLE);␊
self.pausable.pause();␊
}␊
␊
#[external(v0)]␊
fn unpause(ref self: ContractState) {␊
self.accesscontrol.assert_only_role(PAUSER_ROLE);␊
self.pausable.unpause();␊
}␊
}␊
␊
//␊
// Upgradeable␊
//␊
␊
#[abi(embed_v0)]␊
impl UpgradeableImpl of IUpgradeable<ContractState> {␊
fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊
self.accesscontrol.assert_only_role(UPGRADER_ROLE);␊
self.upgradeable.upgrade(new_class_hash);␊
}␊
}␊
}␊
`
## erc20 burnable pausable
> Snapshot 1
`// SPDX-License-Identifier: MIT␊
// Compatible with OpenZeppelin Contracts for Cairo ^2.0.0␊
␊
#[starknet::contract]␊
mod MyToken {␊
use openzeppelin::access::ownable::OwnableComponent;␊
use openzeppelin::security::pausable::PausableComponent;␊
use openzeppelin::token::erc20::{DefaultConfig as ERC20DefaultConfig, ERC20Component};␊
use openzeppelin::upgrades::interface::IUpgradeable;␊
use openzeppelin::upgrades::UpgradeableComponent;␊
use starknet::{ClassHash, ContractAddress, get_caller_address};␊
␊
component!(path: ERC20Component, storage: erc20, event: ERC20Event);␊
component!(path: PausableComponent, storage: pausable, event: PausableEvent);␊
component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);␊
component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊
␊
// External␊
#[abi(embed_v0)]␊
impl ERC20MixinImpl = ERC20Component::ERC20MixinImpl<ContractState>;␊
#[abi(embed_v0)]␊
impl PausableImpl = PausableComponent::PausableImpl<ContractState>;␊
#[abi(embed_v0)]␊
impl OwnableMixinImpl = OwnableComponent::OwnableMixinImpl<ContractState>;␊
␊
// Internal␊
impl ERC20InternalImpl = ERC20Component::InternalImpl<ContractState>;␊
impl PausableInternalImpl = PausableComponent::InternalImpl<ContractState>;␊
impl OwnableInternalImpl = OwnableComponent::InternalImpl<ContractState>;␊
impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl<ContractState>;␊
␊
#[storage]␊
struct Storage {␊
#[substorage(v0)]␊
erc20: ERC20Component::Storage,␊
#[substorage(v0)]␊
pausable: PausableComponent::Storage,␊
#[substorage(v0)]␊
ownable: OwnableComponent::Storage,␊
#[substorage(v0)]␊
upgradeable: UpgradeableComponent::Storage,␊
}␊
␊
#[event]␊
#[derive(Drop, starknet::Event)]␊
enum Event {␊
#[flat]␊
ERC20Event: ERC20Component::Event,␊
#[flat]␊
PausableEvent: PausableComponent::Event,␊
#[flat]␊
OwnableEvent: OwnableComponent::Event,␊
#[flat]␊
UpgradeableEvent: UpgradeableComponent::Event,␊
}␊
␊
#[constructor]␊
fn constructor(ref self: ContractState, owner: ContractAddress) {␊
self.erc20.initializer("MyToken", "MTK");␊
self.ownable.initializer(owner);␊
}␊
␊
impl ERC20HooksImpl of ERC20Component::ERC20HooksTrait<ContractState> {␊
fn before_update(␊
ref self: ERC20Component::ComponentState<ContractState>,␊
from: ContractAddress,␊
recipient: ContractAddress,␊
amount: u256,␊
) {␊
let contract_state = self.get_contract();␊
contract_state.pausable.assert_not_paused();␊
}␊
}␊
␊
#[generate_trait]␊
#[abi(per_item)]␊
impl ExternalImpl of ExternalTrait {␊
#[external(v0)]␊
fn pause(ref self: ContractState) {␊
self.ownable.assert_only_owner();␊
self.pausable.pause();␊
}␊
␊
#[external(v0)]␊
fn unpause(ref self: ContractState) {␊
self.ownable.assert_only_owner();␊
self.pausable.unpause();␊
}␊
␊
#[external(v0)]␊
fn burn(ref self: ContractState, value: u256) {␊
self.erc20.burn(get_caller_address(), value);␊
}␊
}␊
␊
//␊
// Upgradeable␊
//␊
␊
#[abi(embed_v0)]␊
impl UpgradeableImpl of IUpgradeable<ContractState> {␊
fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊
self.ownable.assert_only_owner();␊
self.upgradeable.upgrade(new_class_hash);␊
}␊
}␊
}␊
`
## erc20 preminted
> Snapshot 1
`// SPDX-License-Identifier: MIT␊
// Compatible with OpenZeppelin Contracts for Cairo ^2.0.0␊
␊
#[starknet::contract]␊
mod MyToken {␊
use openzeppelin::access::ownable::OwnableComponent;␊
use openzeppelin::token::erc20::{␊
DefaultConfig as ERC20DefaultConfig, ERC20Component, ERC20HooksEmptyImpl␊
};␊
use openzeppelin::upgrades::interface::IUpgradeable;␊
use openzeppelin::upgrades::UpgradeableComponent;␊
use starknet::{ClassHash, ContractAddress};␊
␊
component!(path: ERC20Component, storage: erc20, event: ERC20Event);␊
component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊
component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);␊
␊
// External␊
#[abi(embed_v0)]␊
impl ERC20MixinImpl = ERC20Component::ERC20MixinImpl<ContractState>;␊
#[abi(embed_v0)]␊
impl OwnableMixinImpl = OwnableComponent::OwnableMixinImpl<ContractState>;␊
␊
// Internal␊
impl ERC20InternalImpl = ERC20Component::InternalImpl<ContractState>;␊
impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl<ContractState>;␊
impl OwnableInternalImpl = OwnableComponent::InternalImpl<ContractState>;␊
␊
#[storage]␊
struct Storage {␊
#[substorage(v0)]␊
erc20: ERC20Component::Storage,␊
#[substorage(v0)]␊
upgradeable: UpgradeableComponent::Storage,␊
#[substorage(v0)]␊
ownable: OwnableComponent::Storage,␊
}␊
␊
#[event]␊
#[derive(Drop, starknet::Event)]␊
enum Event {␊
#[flat]␊
ERC20Event: ERC20Component::Event,␊
#[flat]␊
UpgradeableEvent: UpgradeableComponent::Event,␊
#[flat]␊
OwnableEvent: OwnableComponent::Event,␊
}␊
␊
#[constructor]␊
fn constructor(ref self: ContractState, recipient: ContractAddress, owner: ContractAddress) {␊
self.erc20.initializer("MyToken", "MTK");␊
self.ownable.initializer(owner);␊
␊
self.erc20.mint(recipient, 1000000000000000000000);␊
}␊
␊
//␊
// Upgradeable␊
//␊
␊
#[abi(embed_v0)]␊
impl UpgradeableImpl of IUpgradeable<ContractState> {␊
fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊
self.ownable.assert_only_owner();␊
self.upgradeable.upgrade(new_class_hash);␊
}␊
}␊
}␊
`
## erc20 premint of 0
> Snapshot 1
`// SPDX-License-Identifier: MIT␊
// Compatible with OpenZeppelin Contracts for Cairo ^2.0.0␊
␊
#[starknet::contract]␊
mod MyToken {␊
use openzeppelin::access::ownable::OwnableComponent;␊
use openzeppelin::token::erc20::{␊
DefaultConfig as ERC20DefaultConfig, ERC20Component, ERC20HooksEmptyImpl␊
};␊
use openzeppelin::upgrades::interface::IUpgradeable;␊
use openzeppelin::upgrades::UpgradeableComponent;␊
use starknet::{ClassHash, ContractAddress};␊
␊
component!(path: ERC20Component, storage: erc20, event: ERC20Event);␊
component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊
component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);␊
␊
// External␊
#[abi(embed_v0)]␊
impl ERC20MixinImpl = ERC20Component::ERC20MixinImpl<ContractState>;␊
#[abi(embed_v0)]␊
impl OwnableMixinImpl = OwnableComponent::OwnableMixinImpl<ContractState>;␊
␊
// Internal␊
impl ERC20InternalImpl = ERC20Component::InternalImpl<ContractState>;␊
impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl<ContractState>;␊
impl OwnableInternalImpl = OwnableComponent::InternalImpl<ContractState>;␊
␊
#[storage]␊
struct Storage {␊
#[substorage(v0)]␊
erc20: ERC20Component::Storage,␊
#[substorage(v0)]␊
upgradeable: UpgradeableComponent::Storage,␊
#[substorage(v0)]␊
ownable: OwnableComponent::Storage,␊
}␊
␊
#[event]␊
#[derive(Drop, starknet::Event)]␊
enum Event {␊
#[flat]␊
ERC20Event: ERC20Component::Event,␊
#[flat]␊
UpgradeableEvent: UpgradeableComponent::Event,␊
#[flat]␊
OwnableEvent: OwnableComponent::Event,␊
}␊
␊
#[constructor]␊
fn constructor(ref self: ContractState, owner: ContractAddress) {␊
self.erc20.initializer("MyToken", "MTK");␊
self.ownable.initializer(owner);␊
}␊
␊
//␊
// Upgradeable␊
//␊
␊
#[abi(embed_v0)]␊
impl UpgradeableImpl of IUpgradeable<ContractState> {␊
fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊
self.ownable.assert_only_owner();␊
self.upgradeable.upgrade(new_class_hash);␊
}␊
}␊
}␊
`
## erc20 votes, custom decimals
> Snapshot 1
`// SPDX-License-Identifier: MIT␊
// Compatible with OpenZeppelin Contracts for Cairo ^2.0.0␊
␊
#[starknet::contract]␊
mod MyToken {␊
use openzeppelin::access::ownable::OwnableComponent;␊
use openzeppelin::token::erc20::{ERC20Component, ERC20HooksEmptyImpl};␊
use openzeppelin::upgrades::interface::IUpgradeable;␊
use openzeppelin::upgrades::UpgradeableComponent;␊
use starknet::{ClassHash, ContractAddress};␊
␊
component!(path: ERC20Component, storage: erc20, event: ERC20Event);␊
component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊
component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);␊
␊
// External␊
#[abi(embed_v0)]␊
impl ERC20MixinImpl = ERC20Component::ERC20MixinImpl<ContractState>;␊
#[abi(embed_v0)]␊
impl OwnableMixinImpl = OwnableComponent::OwnableMixinImpl<ContractState>;␊
␊
// Internal␊
impl ERC20InternalImpl = ERC20Component::InternalImpl<ContractState>;␊
impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl<ContractState>;␊
impl OwnableInternalImpl = OwnableComponent::InternalImpl<ContractState>;␊
␊
#[storage]␊
struct Storage {␊
#[substorage(v0)]␊
erc20: ERC20Component::Storage,␊
#[substorage(v0)]␊
upgradeable: UpgradeableComponent::Storage,␊
#[substorage(v0)]␊
ownable: OwnableComponent::Storage,␊
}␊
␊
#[event]␊
#[derive(Drop, starknet::Event)]␊
enum Event {␊
#[flat]␊
ERC20Event: ERC20Component::Event,␊
#[flat]␊
UpgradeableEvent: UpgradeableComponent::Event,␊
#[flat]␊
OwnableEvent: OwnableComponent::Event,␊
}␊
␊
#[constructor]␊
fn constructor(ref self: ContractState, owner: ContractAddress) {␊
self.erc20.initializer("MyToken", "MTK");␊
self.ownable.initializer(owner);␊
}␊
␊
impl ERC20ImmutableConfig of ERC20Component::ImmutableConfig {␊
const DECIMALS: u8 = 6;␊
}␊
␊
//␊
// Upgradeable␊
//␊
␊
#[abi(embed_v0)]␊
impl UpgradeableImpl of IUpgradeable<ContractState> {␊
fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊
self.ownable.assert_only_owner();␊
self.upgradeable.upgrade(new_class_hash);␊
}␊
}␊
}␊
`
## erc20 mintable
> Snapshot 1
`// SPDX-License-Identifier: MIT␊
// Compatible with OpenZeppelin Contracts for Cairo ^2.0.0␊
␊
#[starknet::contract]␊
mod MyToken {␊
use openzeppelin::access::ownable::OwnableComponent;␊
use openzeppelin::token::erc20::{␊
DefaultConfig as ERC20DefaultConfig, ERC20Component, ERC20HooksEmptyImpl␊
};␊
use openzeppelin::upgrades::interface::IUpgradeable;␊
use openzeppelin::upgrades::UpgradeableComponent;␊
use starknet::{ClassHash, ContractAddress};␊
␊
component!(path: ERC20Component, storage: erc20, event: ERC20Event);␊
component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);␊
component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊
␊
// External␊
#[abi(embed_v0)]␊
impl ERC20MixinImpl = ERC20Component::ERC20MixinImpl<ContractState>;␊
#[abi(embed_v0)]␊
impl OwnableMixinImpl = OwnableComponent::OwnableMixinImpl<ContractState>;␊
␊
// Internal␊
impl ERC20InternalImpl = ERC20Component::InternalImpl<ContractState>;␊
impl OwnableInternalImpl = OwnableComponent::InternalImpl<ContractState>;␊
impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl<ContractState>;␊
␊
#[storage]␊
struct Storage {␊
#[substorage(v0)]␊
erc20: ERC20Component::Storage,␊
#[substorage(v0)]␊
ownable: OwnableComponent::Storage,␊
#[substorage(v0)]␊
upgradeable: UpgradeableComponent::Storage,␊
}␊
␊
#[event]␊
#[derive(Drop, starknet::Event)]␊
enum Event {␊
#[flat]␊
ERC20Event: ERC20Component::Event,␊
#[flat]␊
OwnableEvent: OwnableComponent::Event,␊
#[flat]␊
UpgradeableEvent: UpgradeableComponent::Event,␊
}␊
␊
#[constructor]␊
fn constructor(ref self: ContractState, owner: ContractAddress) {␊
self.erc20.initializer("MyToken", "MTK");␊
self.ownable.initializer(owner);␊
}␊
␊
#[generate_trait]␊
#[abi(per_item)]␊
impl ExternalImpl of ExternalTrait {␊
#[external(v0)]␊
fn mint(ref self: ContractState, recipient: ContractAddress, amount: u256) {␊
self.ownable.assert_only_owner();␊
self.erc20.mint(recipient, amount);␊
}␊
}␊
␊
//␊
// Upgradeable␊
//␊
␊
#[abi(embed_v0)]␊
impl UpgradeableImpl of IUpgradeable<ContractState> {␊
fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊
self.ownable.assert_only_owner();␊
self.upgradeable.upgrade(new_class_hash);␊
}␊
}␊
}␊
`
## erc20 mintable with roles
> Snapshot 1
`// SPDX-License-Identifier: MIT␊
// Compatible with OpenZeppelin Contracts for Cairo ^2.0.0␊
␊
const MINTER_ROLE: felt252 = selector!("MINTER_ROLE");␊
const UPGRADER_ROLE: felt252 = selector!("UPGRADER_ROLE");␊
␊
#[starknet::contract]␊
mod MyToken {␊
use openzeppelin::access::accesscontrol::{AccessControlComponent, DEFAULT_ADMIN_ROLE};␊
use openzeppelin::introspection::src5::SRC5Component;␊
use openzeppelin::token::erc20::{␊
DefaultConfig as ERC20DefaultConfig, ERC20Component, ERC20HooksEmptyImpl␊
};␊
use openzeppelin::upgrades::interface::IUpgradeable;␊
use openzeppelin::upgrades::UpgradeableComponent;␊
use starknet::{ClassHash, ContractAddress};␊
use super::{MINTER_ROLE, UPGRADER_ROLE};␊
␊
component!(path: ERC20Component, storage: erc20, event: ERC20Event);␊
component!(path: AccessControlComponent, storage: accesscontrol, event: AccessControlEvent);␊
component!(path: SRC5Component, storage: src5, event: SRC5Event);␊
component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊
␊
// External␊
#[abi(embed_v0)]␊
impl ERC20MixinImpl = ERC20Component::ERC20MixinImpl<ContractState>;␊
#[abi(embed_v0)]␊
impl AccessControlMixinImpl = AccessControlComponent::AccessControlMixinImpl<ContractState>;␊
␊
// Internal␊
impl ERC20InternalImpl = ERC20Component::InternalImpl<ContractState>;␊
impl AccessControlInternalImpl = AccessControlComponent::InternalImpl<ContractState>;␊
impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl<ContractState>;␊
␊
#[storage]␊
struct Storage {␊
#[substorage(v0)]␊
erc20: ERC20Component::Storage,␊
#[substorage(v0)]␊
accesscontrol: AccessControlComponent::Storage,␊
#[substorage(v0)]␊
src5: SRC5Component::Storage,␊
#[substorage(v0)]␊
upgradeable: UpgradeableComponent::Storage,␊
}␊
␊
#[event]␊
#[derive(Drop, starknet::Event)]␊
enum Event {␊
#[flat]␊
ERC20Event: ERC20Component::Event,␊
#[flat]␊
AccessControlEvent: AccessControlComponent::Event,␊
#[flat]␊
SRC5Event: SRC5Component::Event,␊
#[flat]␊
UpgradeableEvent: UpgradeableComponent::Event,␊
}␊
␊
#[constructor]␊
fn constructor(␊
ref self: ContractState,␊
default_admin: ContractAddress,␊
minter: ContractAddress,␊
upgrader: ContractAddress,␊
) {␊
self.erc20.initializer("MyToken", "MTK");␊
self.accesscontrol.initializer();␊
␊
self.accesscontrol._grant_role(DEFAULT_ADMIN_ROLE, default_admin);␊
self.accesscontrol._grant_role(MINTER_ROLE, minter);␊
self.accesscontrol._grant_role(UPGRADER_ROLE, upgrader);␊
}␊
␊
#[generate_trait]␊
#[abi(per_item)]␊
impl ExternalImpl of ExternalTrait {␊
#[external(v0)]␊
fn mint(ref self: ContractState, recipient: ContractAddress, amount: u256) {␊
self.accesscontrol.assert_only_role(MINTER_ROLE);␊
self.erc20.mint(recipient, amount);␊
}␊
}␊
␊
//␊
// Upgradeable␊
//␊
␊
#[abi(embed_v0)]␊
impl UpgradeableImpl of IUpgradeable<ContractState> {␊
fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊
self.accesscontrol.assert_only_role(UPGRADER_ROLE);␊
self.upgradeable.upgrade(new_class_hash);␊
}␊
}␊
}␊
`
## erc20 votes
> Snapshot 1
`// SPDX-License-Identifier: MIT␊
// Compatible with OpenZeppelin Contracts for Cairo ^2.0.0␊
␊
#[starknet::contract]␊
mod MyToken {␊
use openzeppelin::access::ownable::OwnableComponent;␊
use openzeppelin::governance::votes::VotesComponent;␊
use openzeppelin::token::erc20::{DefaultConfig as ERC20DefaultConfig, ERC20Component};␊
use openzeppelin::upgrades::interface::IUpgradeable;␊
use openzeppelin::upgrades::UpgradeableComponent;␊
use openzeppelin::utils::cryptography::nonces::NoncesComponent;␊
use openzeppelin::utils::cryptography::snip12::SNIP12Metadata;␊
use starknet::{ClassHash, ContractAddress};␊
␊
component!(path: ERC20Component, storage: erc20, event: ERC20Event);␊
component!(path: NoncesComponent, storage: nonces, event: NoncesEvent);␊
component!(path: VotesComponent, storage: votes, event: VotesEvent);␊
component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊
component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);␊
␊
// External␊
#[abi(embed_v0)]␊
impl ERC20MixinImpl = ERC20Component::ERC20MixinImpl<ContractState>;␊
#[abi(embed_v0)]␊
impl NoncesImpl = NoncesComponent::NoncesImpl<ContractState>;␊
#[abi(embed_v0)]␊
impl VotesImpl = VotesComponent::VotesImpl<ContractState>;␊
#[abi(embed_v0)]␊
impl OwnableMixinImpl = OwnableComponent::OwnableMixinImpl<ContractState>;␊
␊
// Internal␊
impl ERC20InternalImpl = ERC20Component::InternalImpl<ContractState>;␊
impl VotesInternalImpl = VotesComponent::InternalImpl<ContractState>;␊
impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl<ContractState>;␊
impl OwnableInternalImpl = OwnableComponent::InternalImpl<ContractState>;␊
␊
#[storage]␊
struct Storage {␊
#[substorage(v0)]␊
erc20: ERC20Component::Storage,␊
#[substorage(v0)]␊
nonces: NoncesComponent::Storage,␊
#[substorage(v0)]␊
votes: VotesComponent::Storage,␊
#[substorage(v0)]␊
upgradeable: UpgradeableComponent::Storage,␊
#[substorage(v0)]␊
ownable: OwnableComponent::Storage,␊
}␊
␊
#[event]␊
#[derive(Drop, starknet::Event)]␊
enum Event {␊
#[flat]␊
ERC20Event: ERC20Component::Event,␊
#[flat]␊
NoncesEvent: NoncesComponent::Event,␊
#[flat]␊
VotesEvent: VotesComponent::Event,␊
#[flat]␊
UpgradeableEvent: UpgradeableComponent::Event,␊
#[flat]␊
OwnableEvent: OwnableComponent::Event,␊
}␊
␊
#[constructor]␊
fn constructor(ref self: ContractState, owner: ContractAddress) {␊
self.erc20.initializer("MyToken", "MTK");␊
self.ownable.initializer(owner);␊
}␊
␊
impl ERC20HooksImpl of ERC20Component::ERC20HooksTrait<ContractState> {␊
fn after_update(␊
ref self: ERC20Component::ComponentState<ContractState>,␊
from: ContractAddress,␊
recipient: ContractAddress,␊
amount: u256,␊
) {␊
let mut contract_state = self.get_contract_mut();␊
contract_state.votes.transfer_voting_units(from, recipient, amount);␊
}␊
}␊
␊
//␊
// SNIP12 Metadata␊
//␊
␊
impl SNIP12MetadataImpl of SNIP12Metadata {␊
fn name() -> felt252 {␊
'MY_DAPP_NAME'␊
}␊
␊
fn version() -> felt252 {␊
'v1'␊
}␊
}␊
␊
//␊
// Upgradeable␊
//␊
␊
#[abi(embed_v0)]␊
impl UpgradeableImpl of IUpgradeable<ContractState> {␊
fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊
self.ownable.assert_only_owner();␊
self.upgradeable.upgrade(new_class_hash);␊
}␊
}␊
}␊
`
## erc20 votes, version
> Snapshot 1
`// SPDX-License-Identifier: MIT␊
// Compatible with OpenZeppelin Contracts for Cairo ^2.0.0␊
␊
#[starknet::contract]␊
mod MyToken {␊
use openzeppelin::access::ownable::OwnableComponent;␊
use openzeppelin::governance::votes::VotesComponent;␊
use openzeppelin::token::erc20::{DefaultConfig as ERC20DefaultConfig, ERC20Component};␊
use openzeppelin::upgrades::interface::IUpgradeable;␊
use openzeppelin::upgrades::UpgradeableComponent;␊
use openzeppelin::utils::cryptography::nonces::NoncesComponent;␊
use openzeppelin::utils::cryptography::snip12::SNIP12Metadata;␊
use starknet::{ClassHash, ContractAddress};␊
␊
component!(path: ERC20Component, storage: erc20, event: ERC20Event);␊
component!(path: NoncesComponent, storage: nonces, event: NoncesEvent);␊
component!(path: VotesComponent, storage: votes, event: VotesEvent);␊
component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊
component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);␊
␊
// External␊
#[abi(embed_v0)]␊
impl ERC20MixinImpl = ERC20Component::ERC20MixinImpl<ContractState>;␊
#[abi(embed_v0)]␊
impl NoncesImpl = NoncesComponent::NoncesImpl<ContractState>;␊
#[abi(embed_v0)]␊
impl VotesImpl = VotesComponent::VotesImpl<ContractState>;␊
#[abi(embed_v0)]␊
impl OwnableMixinImpl = OwnableComponent::OwnableMixinImpl<ContractState>;␊
␊
// Internal␊
impl ERC20InternalImpl = ERC20Component::InternalImpl<ContractState>;␊
impl VotesInternalImpl = VotesComponent::InternalImpl<ContractState>;␊
impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl<ContractState>;␊
impl OwnableInternalImpl = OwnableComponent::InternalImpl<ContractState>;␊
␊
#[storage]␊
struct Storage {␊
#[substorage(v0)]␊
erc20: ERC20Component::Storage,␊
#[substorage(v0)]␊
nonces: NoncesComponent::Storage,␊
#[substorage(v0)]␊
votes: VotesComponent::Storage,␊
#[substorage(v0)]␊
upgradeable: UpgradeableComponent::Storage,␊
#[substorage(v0)]␊
ownable: OwnableComponent::Storage,␊
}␊
␊
#[event]␊
#[derive(Drop, starknet::Event)]␊
enum Event {␊
#[flat]␊
ERC20Event: ERC20Component::Event,␊
#[flat]␊
NoncesEvent: NoncesComponent::Event,␊
#[flat]␊
VotesEvent: VotesComponent::Event,␊
#[flat]␊
UpgradeableEvent: UpgradeableComponent::Event,␊
#[flat]␊
OwnableEvent: OwnableComponent::Event,␊
}␊
␊
#[constructor]␊
fn constructor(ref self: ContractState, owner: ContractAddress) {␊
self.erc20.initializer("MyToken", "MTK");␊
self.ownable.initializer(owner);␊
}␊
␊
impl ERC20HooksImpl of ERC20Component::ERC20HooksTrait<ContractState> {␊
fn after_update(␊
ref self: ERC20Component::ComponentState<ContractState>,␊
from: ContractAddress,␊
recipient: ContractAddress,␊
amount: u256,␊
) {␊
let mut contract_state = self.get_contract_mut();␊
contract_state.votes.transfer_voting_units(from, recipient, amount);␊
}␊
}␊
␊
//␊
// SNIP12 Metadata␊
//␊
␊
impl SNIP12MetadataImpl of SNIP12Metadata {␊
fn name() -> felt252 {␊
'MY_DAPP_NAME'␊
}␊
␊
fn version() -> felt252 {␊
'MY_DAPP_VERSION'␊
}␊
}␊
␊
//␊
// Upgradeable␊
//␊
␊
#[abi(embed_v0)]␊
impl UpgradeableImpl of IUpgradeable<ContractState> {␊
fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊
self.ownable.assert_only_owner();␊
self.upgradeable.upgrade(new_class_hash);␊
}␊
}␊
}␊
`
## erc20 votes, non-upgradeable
> Snapshot 1
`// SPDX-License-Identifier: MIT␊
// Compatible with OpenZeppelin Contracts for Cairo ^2.0.0␊
␊
#[starknet::contract]␊
mod MyToken {␊
use openzeppelin::governance::votes::VotesComponent;␊
use openzeppelin::token::erc20::{DefaultConfig as ERC20DefaultConfig, ERC20Component};␊
use openzeppelin::utils::cryptography::nonces::NoncesComponent;␊
use openzeppelin::utils::cryptography::snip12::SNIP12Metadata;␊
use starknet::ContractAddress;␊
␊
component!(path: ERC20Component, storage: erc20, event: ERC20Event);␊
component!(path: NoncesComponent, storage: nonces, event: NoncesEvent);␊
component!(path: VotesComponent, storage: votes, event: VotesEvent);␊
␊
// External␊
#[abi(embed_v0)]␊
impl ERC20MixinImpl = ERC20Component::ERC20MixinImpl<ContractState>;␊
#[abi(embed_v0)]␊
impl NoncesImpl = NoncesComponent::NoncesImpl<ContractState>;␊
#[abi(embed_v0)]␊
impl VotesImpl = VotesComponent::VotesImpl<ContractState>;␊
␊
// Internal␊
impl ERC20InternalImpl = ERC20Component::InternalImpl<ContractState>;␊
impl VotesInternalImpl = VotesComponent::InternalImpl<ContractState>;␊
␊
#[storage]␊
struct Storage {␊
#[substorage(v0)]␊
erc20: ERC20Component::Storage,␊
#[substorage(v0)]␊
nonces: NoncesComponent::Storage,␊
#[substorage(v0)]␊
votes: VotesComponent::Storage,␊
}␊
␊
#[event]␊
#[derive(Drop, starknet::Event)]␊
enum Event {␊
#[flat]␊
ERC20Event: ERC20Component::Event,␊
#[flat]␊
NoncesEvent: NoncesComponent::Event,␊
#[flat]␊
VotesEvent: VotesComponent::Event,␊
}␊
␊
#[constructor]␊
fn constructor(ref self: ContractState) {␊
self.erc20.initializer("MyToken", "MTK");␊
}␊
␊
impl ERC20HooksImpl of ERC20Component::ERC20HooksTrait<ContractState> {␊
fn after_update(␊
ref self: ERC20Component::ComponentState<ContractState>,␊
from: ContractAddress,␊
recipient: ContractAddress,␊
amount: u256,␊
) {␊
let mut contract_state = self.get_contract_mut();␊
contract_state.votes.transfer_voting_units(from, recipient, amount);␊
}␊
}␊
␊
//␊
// SNIP12 Metadata␊
//␊
␊
impl SNIP12MetadataImpl of SNIP12Metadata {␊
fn name() -> felt252 {␊
'MY_DAPP_NAME'␊
}␊
␊
fn version() -> felt252 {␊
'v1'␊
}␊
}␊
}␊
`
## erc20 full, non-upgradeable
> Snapshot 1
`// SPDX-License-Identifier: MIT␊
// Compatible with OpenZeppelin Contracts for Cairo ^2.0.0␊
␊
#[starknet::contract]␊
mod MyToken {␊
use openzeppelin::access::ownable::OwnableComponent;␊
use openzeppelin::governance::votes::VotesComponent;␊
use openzeppelin::security::pausable::PausableComponent;␊
use openzeppelin::token::erc20::{DefaultConfig as ERC20DefaultConfig, ERC20Component};␊
use openzeppelin::utils::cryptography::nonces::NoncesComponent;␊
use openzeppelin::utils::cryptography::snip12::SNIP12Metadata;␊
use starknet::{ContractAddress, get_caller_address};␊
␊
component!(path: ERC20Component, storage: erc20, event: ERC20Event);␊
component!(path: PausableComponent, storage: pausable, event: PausableEvent);␊
component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);␊
component!(path: NoncesComponent, storage: nonces, event: NoncesEvent);␊
component!(path: VotesComponent, storage: votes, event: VotesEvent);␊
␊
// External␊
#[abi(embed_v0)]␊
impl ERC20MixinImpl = ERC20Component::ERC20MixinImpl<ContractState>;␊
#[abi(embed_v0)]␊
impl PausableImpl = PausableComponent::PausableImpl<ContractState>;␊
#[abi(embed_v0)]␊
impl OwnableMixinImpl = OwnableComponent::OwnableMixinImpl<ContractState>;␊
#[abi(embed_v0)]␊
impl NoncesImpl = NoncesComponent::NoncesImpl<ContractState>;␊
#[abi(embed_v0)]␊
impl VotesImpl = VotesComponent::VotesImpl<ContractState>;␊
␊
// Internal␊
impl ERC20InternalImpl = ERC20Component::InternalImpl<ContractState>;␊
impl PausableInternalImpl = PausableComponent::InternalImpl<ContractState>;␊
impl OwnableInternalImpl = OwnableComponent::InternalImpl<ContractState>;␊
impl VotesInternalImpl = VotesComponent::InternalImpl<ContractState>;␊
␊
#[storage]␊
struct Storage {␊
#[substorage(v0)]␊
erc20: ERC20Component::Storage,␊
#[substorage(v0)]␊
pausable: PausableComponent::Storage,␊
#[substorage(v0)]␊
ownable: OwnableComponent::Storage,␊
#[substorage(v0)]␊
nonces: NoncesComponent::Storage,␊
#[substorage(v0)]␊
votes: VotesComponent::Storage,␊
}␊
␊
#[event]␊
#[derive(Drop, starknet::Event)]␊
enum Event {␊
#[flat]␊
ERC20Event: ERC20Component::Event,␊
#[flat]␊
PausableEvent: PausableComponent::Event,␊
#[flat]␊
OwnableEvent: OwnableComponent::Event,␊
#[flat]␊
NoncesEvent: NoncesComponent::Event,␊
#[flat]␊
VotesEvent: VotesComponent::Event,␊
}␊
␊
#[constructor]␊
fn constructor(ref self: ContractState, recipient: ContractAddress, owner: ContractAddress) {␊
self.erc20.initializer("MyToken", "MTK");␊
self.ownable.initializer(owner);␊
␊
self.erc20.mint(recipient, 2000000000000000000000);␊
}␊
␊
impl ERC20HooksImpl of ERC20Component::ERC20HooksTrait<ContractState> {␊
fn before_update(␊
ref self: ERC20Component::ComponentState<ContractState>,␊
from: ContractAddress,␊
recipient: ContractAddress,␊
amount: u256,␊
) {␊
let contract_state = self.get_contract();␊
contract_state.pausable.assert_not_paused();␊
}␊
␊
fn after_update(␊
ref self: ERC20Component::ComponentState<ContractState>,␊
from: ContractAddress,␊
recipient: ContractAddress,␊
amount: u256,␊
) {␊
let mut contract_state = self.get_contract_mut();␊
contract_state.votes.transfer_voting_units(from, recipient, amount);␊
}␊
}␊
␊
#[generate_trait]␊
#[abi(per_item)]␊
impl ExternalImpl of ExternalTrait {␊
#[external(v0)]␊
fn pause(ref self: ContractState) {␊
self.ownable.assert_only_owner();␊
self.pausable.pause();␊
}␊
␊
#[external(v0)]␊
fn unpause(ref self: ContractState) {␊
self.ownable.assert_only_owner();␊
self.pausable.unpause();␊
}␊
␊
#[external(v0)]␊
fn burn(ref self: ContractState, value: u256) {␊
self.erc20.burn(get_caller_address(), value);␊
}␊
␊
#[external(v0)]␊
fn mint(ref self: ContractState, recipient: ContractAddress, amount: u256) {␊
self.ownable.assert_only_owner();␊
self.erc20.mint(recipient, amount);␊
}␊
}␊
␊
//␊
// SNIP12 Metadata␊
//␊
␊
impl SNIP12MetadataImpl of SNIP12Metadata {␊
fn name() -> felt252 {␊
'MY_DAPP_NAME'␊
}␊
␊
fn version() -> felt252 {␊
'MY_DAPP_VERSION'␊
}␊
}␊
}␊
`
## erc20 full upgradeable
> Snapshot 1
`// SPDX-License-Identifier: MIT␊
// Compatible with OpenZeppelin Contracts for Cairo ^2.0.0␊
␊
#[starknet::contract]␊
mod MyToken {␊
use openzeppelin::access::ownable::OwnableComponent;␊
use openzeppelin::governance::votes::VotesComponent;␊
use openzeppelin::security::pausable::PausableComponent;␊
use openzeppelin::token::erc20::{DefaultConfig as ERC20DefaultConfig, ERC20Component};␊
use openzeppelin::upgrades::interface::IUpgradeable;␊
use openzeppelin::upgrades::UpgradeableComponent;␊
use openzeppelin::utils::cryptography::nonces::NoncesComponent;␊
use openzeppelin::utils::cryptography::snip12::SNIP12Metadata;␊
use starknet::{ClassHash, ContractAddress, get_caller_address};␊
␊
component!(path: ERC20Component, storage: erc20, event: ERC20Event);␊
component!(path: PausableComponent, storage: pausable, event: PausableEvent);␊
component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);␊
component!(path: NoncesComponent, storage: nonces, event: NoncesEvent);␊
component!(path: VotesComponent, storage: votes, event: VotesEvent);␊
component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊
␊
// External␊
#[abi(embed_v0)]␊
impl ERC20MixinImpl = ERC20Component::ERC20MixinImpl<ContractState>;␊
#[abi(embed_v0)]␊
impl PausableImpl = PausableComponent::PausableImpl<ContractState>;␊
#[abi(embed_v0)]␊
impl OwnableMixinImpl = OwnableComponent::OwnableMixinImpl<ContractState>;␊
#[abi(embed_v0)]␊
impl NoncesImpl = NoncesComponent::NoncesImpl<ContractState>;␊
#[abi(embed_v0)]␊
impl VotesImpl = VotesComponent::VotesImpl<ContractState>;␊
␊
// Internal␊
impl ERC20InternalImpl = ERC20Component::InternalImpl<ContractState>;␊
impl PausableInternalImpl = PausableComponent::InternalImpl<ContractState>;␊
impl OwnableInternalImpl = OwnableComponent::InternalImpl<ContractState>;␊
impl VotesInternalImpl = VotesComponent::InternalImpl<ContractState>;␊
impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl<ContractState>;␊
␊
#[storage]␊
struct Storage {␊
#[substorage(v0)]␊
erc20: ERC20Component::Storage,␊
#[substorage(v0)]␊
pausable: PausableComponent::Storage,␊
#[substorage(v0)]␊
ownable: OwnableComponent::Storage,␊
#[substorage(v0)]␊
nonces: NoncesComponent::Storage,␊
#[substorage(v0)]␊
votes: VotesComponent::Storage,␊
#[substorage(v0)]␊
upgradeable: UpgradeableComponent::Storage,␊
}␊
␊
#[event]␊
#[derive(Drop, starknet::Event)]␊
enum Event {␊
#[flat]␊
ERC20Event: ERC20Component::Event,␊
#[flat]␊
PausableEvent: PausableComponent::Event,␊
#[flat]␊
OwnableEvent: OwnableComponent::Event,␊
#[flat]␊
NoncesEvent: NoncesComponent::Event,␊
#[flat]␊
VotesEvent: VotesComponent::Event,␊
#[flat]␊
UpgradeableEvent: UpgradeableComponent::Event,␊
}␊
␊
#[constructor]␊
fn constructor(ref self: ContractState, recipient: ContractAddress, owner: ContractAddress) {␊
self.erc20.initializer("MyToken", "MTK");␊
self.ownable.initializer(owner);␊
␊
self.erc20.mint(recipient, 2000000000000000000000);␊
}␊
␊
impl ERC20HooksImpl of ERC20Component::ERC20HooksTrait<ContractState> {␊
fn before_update(␊
ref self: ERC20Component::ComponentState<ContractState>,␊
from: ContractAddress,␊
recipient: ContractAddress,␊
amount: u256,␊
) {␊
let contract_state = self.get_contract();␊
contract_state.pausable.assert_not_paused();␊
}␊
␊
fn after_update(␊
ref self: ERC20Component::ComponentState<ContractState>,␊
from: ContractAddress,␊
recipient: ContractAddress,␊
amount: u256,␊
) {␊
let mut contract_state = self.get_contract_mut();␊
contract_state.votes.transfer_voting_units(from, recipient, amount);␊
}␊
}␊
␊
#[generate_trait]␊
#[abi(per_item)]␊
impl ExternalImpl of ExternalTrait {␊
#[external(v0)]␊
fn pause(ref self: ContractState) {␊
self.ownable.assert_only_owner();␊
self.pausable.pause();␊
}␊
␊
#[external(v0)]␊
fn unpause(ref self: ContractState) {␊
self.ownable.assert_only_owner();␊
self.pausable.unpause();␊
}␊
␊
#[external(v0)]␊
fn burn(ref self: ContractState, value: u256) {␊
self.erc20.burn(get_caller_address(), value);␊
}␊
␊
#[external(v0)]␊
fn mint(ref self: ContractState, recipient: ContractAddress, amount: u256) {␊
self.ownable.assert_only_owner();␊
self.erc20.mint(recipient, amount);␊
}␊
}␊
␊
//␊
// SNIP12 Metadata␊
//␊
␊
impl SNIP12MetadataImpl of SNIP12Metadata {␊
fn name() -> felt252 {␊
'MY_DAPP_NAME'␊
}␊
␊
fn version() -> felt252 {␊
'MY_DAPP_VERSION'␊
}␊
}␊
␊
//␊
// Upgradeable␊
//␊
␊
#[abi(embed_v0)]␊
impl UpgradeableImpl of IUpgradeable<ContractState> {␊
fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊
self.ownable.assert_only_owner();␊
self.upgradeable.upgrade(new_class_hash);␊
}␊
}␊
}␊
`
## erc20 full upgradeable with roles
> Snapshot 1
`// SPDX-License-Identifier: MIT␊
// Compatible with OpenZeppelin Contracts for Cairo ^2.0.0␊
␊
const PAUSER_ROLE: felt252 = selector!("PAUSER_ROLE");␊
const MINTER_ROLE: felt252 = selector!("MINTER_ROLE");␊
const UPGRADER_ROLE: felt252 = selector!("UPGRADER_ROLE");␊
␊
#[starknet::contract]␊
mod MyToken {␊
use openzeppelin::access::accesscontrol::{AccessControlComponent, DEFAULT_ADMIN_ROLE};␊
use openzeppelin::governance::votes::VotesComponent;␊
use openzeppelin::introspection::src5::SRC5Component;␊
use openzeppelin::security::pausable::PausableComponent;␊
use openzeppelin::token::erc20::{DefaultConfig as ERC20DefaultConfig, ERC20Component};␊
use openzeppelin::upgrades::interface::IUpgradeable;␊
use openzeppelin::upgrades::UpgradeableComponent;␊
use openzeppelin::utils::cryptography::nonces::NoncesComponent;␊
use openzeppelin::utils::cryptography::snip12::SNIP12Metadata;␊
use starknet::{ClassHash, ContractAddress, get_caller_address};␊
use super::{MINTER_ROLE, PAUSER_ROLE, UPGRADER_ROLE};␊
␊
component!(path: ERC20Component, storage: erc20, event: ERC20Event);␊
component!(path: PausableComponent, storage: pausable, event: PausableEvent);␊
component!(path: AccessControlComponent, storage: accesscontrol, event: AccessControlEvent);␊
component!(path: SRC5Component, storage: src5, event: SRC5Event);␊
component!(path: NoncesComponent, storage: nonces, event: NoncesEvent);␊
component!(path: VotesComponent, storage: votes, event: VotesEvent);␊
component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊
␊
// External␊
#[abi(embed_v0)]␊
impl ERC20MixinImpl = ERC20Component::ERC20MixinImpl<ContractState>;␊
#[abi(embed_v0)]␊
impl PausableImpl = PausableComponent::PausableImpl<ContractState>;␊
#[abi(embed_v0)]␊
impl AccessControlMixinImpl = AccessControlComponent::AccessControlMixinImpl<ContractState>;␊
#[abi(embed_v0)]␊
impl NoncesImpl = NoncesComponent::NoncesImpl<ContractState>;␊
#[abi(embed_v0)]␊
impl VotesImpl = VotesComponent::VotesImpl<ContractState>;␊
␊
// Internal␊
impl ERC20InternalImpl = ERC20Component::InternalImpl<ContractState>;␊
impl PausableInternalImpl = PausableComponent::InternalImpl<ContractState>;␊
impl AccessControlInternalImpl = AccessControlComponent::InternalImpl<ContractState>;␊
impl VotesInternalImpl = VotesComponent::InternalImpl<ContractState>;␊
impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl<ContractState>;␊
␊
#[storage]␊
struct Storage {␊
#[substorage(v0)]␊
erc20: ERC20Component::Storage,␊
#[substorage(v0)]␊
pausable: PausableComponent::Storage,␊
#[substorage(v0)]␊
accesscontrol: AccessControlComponent::Storage,␊
#[substorage(v0)]␊
src5: SRC5Component::Storage,␊
#[substorage(v0)]␊
nonces: NoncesComponent::Storage,␊
#[substorage(v0)]␊
votes: VotesComponent::Storage,␊
#[substorage(v0)]␊
upgradeable: UpgradeableComponent::Storage,␊
}␊
␊
#[event]␊
#[derive(Drop, starknet::Event)]␊
enum Event {␊
#[flat]␊
ERC20Event: ERC20Component::Event,␊
#[flat]␊
PausableEvent: PausableComponent::Event,␊
#[flat]␊
AccessControlEvent: AccessControlComponent::Event,␊
#[flat]␊
SRC5Event: SRC5Component::Event,␊
#[flat]␊
NoncesEvent: NoncesComponent::Event,␊
#[flat]␊
VotesEvent: VotesComponent::Event,␊
#[flat]␊
UpgradeableEvent: UpgradeableComponent::Event,␊
}␊
␊
#[constructor]␊
fn constructor(␊
ref self: ContractState,␊
recipient: ContractAddress,␊
default_admin: ContractAddress,␊
pauser: ContractAddress,␊
minter: ContractAddress,␊
upgrader: ContractAddress,␊
) {␊
self.erc20.initializer("MyToken", "MTK");␊
self.accesscontrol.initializer();␊
␊
self.erc20.mint(recipient, 2000000000000000000000);␊
self.accesscontrol._grant_role(DEFAULT_ADMIN_ROLE, default_admin);␊
self.accesscontrol._grant_role(PAUSER_ROLE, pauser);␊
self.accesscontrol._grant_role(MINTER_ROLE, minter);␊
self.accesscontrol._grant_role(UPGRADER_ROLE, upgrader);␊
}␊
␊
impl ERC20HooksImpl of ERC20Component::ERC20HooksTrait<ContractState> {␊
fn before_update(␊
ref self: ERC20Component::ComponentState<ContractState>,␊
from: ContractAddress,␊
recipient: ContractAddress,␊
amount: u256,␊
) {␊
let contract_state = self.get_contract();␊
contract_state.pausable.assert_not_paused();␊
}␊
␊
fn after_update(␊
ref self: ERC20Component::ComponentState<ContractState>,␊
from: ContractAddress,␊
recipient: ContractAddress,␊
amount: u256,␊
) {␊
let mut contract_state = self.get_contract_mut();␊
contract_state.votes.transfer_voting_units(from, recipient, amount);␊
}␊
}␊
␊
#[generate_trait]␊
#[abi(per_item)]␊
impl ExternalImpl of ExternalTrait {␊
#[external(v0)]␊
fn pause(ref self: ContractState) {␊
self.accesscontrol.assert_only_role(PAUSER_ROLE);␊
self.pausable.pause();␊
}␊
␊
#[external(v0)]␊
fn unpause(ref self: ContractState) {␊
self.accesscontrol.assert_only_role(PAUSER_ROLE);␊
self.pausable.unpause();␊
}␊
␊
#[external(v0)]␊
fn burn(ref self: ContractState, value: u256) {␊
self.erc20.burn(get_caller_address(), value);␊
}␊
␊
#[external(v0)]␊
fn mint(ref self: ContractState, recipient: ContractAddress, amount: u256) {␊
self.accesscontrol.assert_only_role(MINTER_ROLE);␊
self.erc20.mint(recipient, amount);␊
}␊
}␊
␊
//␊
// SNIP12 Metadata␊
//␊
␊
impl SNIP12MetadataImpl of SNIP12Metadata {␊
fn name() -> felt252 {␊
'MY_DAPP_NAME'␊
}␊
␊
fn version() -> felt252 {␊
'MY_DAPP_VERSION'␊
}␊
}␊
␊
//␊
// Upgradeable␊
//␊
␊
#[abi(embed_v0)]␊
impl UpgradeableImpl of IUpgradeable<ContractState> {␊
fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊
self.accesscontrol.assert_only_role(UPGRADER_ROLE);␊
self.upgradeable.upgrade(new_class_hash);␊
}␊
}␊
}␊
`