diff --git a/packages/core-cairo/CHANGELOG.md b/packages/core-cairo/CHANGELOG.md index 55228c65..5690a838 100644 --- a/packages/core-cairo/CHANGELOG.md +++ b/packages/core-cairo/CHANGELOG.md @@ -2,6 +2,8 @@ ## 0.20.0 (2024-12-10) +- Add Governor tab. ([#417](https://github.com/OpenZeppelin/contracts-wizard/pull/417)) + - **Breaking changes**: - Use OpenZeppelin Contracts for Cairo v0.20.0. ([#419](https://github.com/OpenZeppelin/contracts-wizard/pull/419)) diff --git a/packages/core-cairo/src/account.test.ts.md b/packages/core-cairo/src/account.test.ts.md index 1b152814..3896b7e2 100644 --- a/packages/core-cairo/src/account.test.ts.md +++ b/packages/core-cairo/src/account.test.ts.md @@ -15,17 +15,19 @@ Generated by [AVA](https://avajs.dev). mod MyAccount {␊ use openzeppelin::account::AccountComponent;␊ use openzeppelin::introspection::src5::SRC5Component;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ use starknet::ClassHash;␊ ␊ component!(path: AccountComponent, storage: account, event: AccountEvent);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl AccountMixinImpl = AccountComponent::AccountMixinImpl;␊ ␊ + // Internal␊ impl AccountInternalImpl = AccountComponent::InternalImpl;␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ ␊ @@ -55,6 +57,10 @@ Generated by [AVA](https://avajs.dev). self.account.initializer(public_key);␊ }␊ ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ #[abi(embed_v0)]␊ impl UpgradeableImpl of IUpgradeable {␊ fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ @@ -80,9 +86,11 @@ Generated by [AVA](https://avajs.dev). component!(path: AccountComponent, storage: account, event: AccountEvent);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl AccountMixinImpl = AccountComponent::AccountMixinImpl;␊ ␊ + // Internal␊ impl AccountInternalImpl = AccountComponent::InternalImpl;␊ ␊ #[storage]␊ @@ -120,17 +128,19 @@ Generated by [AVA](https://avajs.dev). mod MyAccount {␊ use openzeppelin::account::AccountComponent;␊ use openzeppelin::introspection::src5::SRC5Component;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ use starknet::ClassHash;␊ ␊ component!(path: AccountComponent, storage: account, event: AccountEvent);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl AccountMixinImpl = AccountComponent::AccountMixinImpl;␊ ␊ + // Internal␊ impl AccountInternalImpl = AccountComponent::InternalImpl;␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ ␊ @@ -160,6 +170,10 @@ Generated by [AVA](https://avajs.dev). self.account.initializer(public_key);␊ }␊ ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ #[abi(embed_v0)]␊ impl UpgradeableImpl of IUpgradeable {␊ fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ @@ -185,9 +199,11 @@ Generated by [AVA](https://avajs.dev). component!(path: AccountComponent, storage: account, event: AccountEvent);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl AccountMixinImpl = AccountComponent::AccountMixinImpl;␊ ␊ + // Internal␊ impl AccountInternalImpl = AccountComponent::InternalImpl;␊ ␊ #[storage]␊ @@ -225,14 +241,15 @@ Generated by [AVA](https://avajs.dev). mod MyAccount {␊ use openzeppelin::account::AccountComponent;␊ use openzeppelin::introspection::src5::SRC5Component;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ use starknet::ClassHash;␊ ␊ component!(path: AccountComponent, storage: account, event: AccountEvent);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl SRC6Impl = AccountComponent::SRC6Impl;␊ #[abi(embed_v0)]␊ @@ -240,6 +257,7 @@ Generated by [AVA](https://avajs.dev). #[abi(embed_v0)]␊ impl SRC5Impl = SRC5Component::SRC5Impl;␊ ␊ + // Internal␊ impl AccountInternalImpl = AccountComponent::InternalImpl;␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ ␊ @@ -269,6 +287,10 @@ Generated by [AVA](https://avajs.dev). self.account.initializer(public_key);␊ }␊ ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ #[abi(embed_v0)]␊ impl UpgradeableImpl of IUpgradeable {␊ fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ @@ -294,6 +316,7 @@ Generated by [AVA](https://avajs.dev). component!(path: AccountComponent, storage: account, event: AccountEvent);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl SRC6Impl = AccountComponent::SRC6Impl;␊ #[abi(embed_v0)]␊ @@ -301,6 +324,7 @@ Generated by [AVA](https://avajs.dev). #[abi(embed_v0)]␊ impl SRC5Impl = SRC5Component::SRC5Impl;␊ ␊ + // Internal␊ impl AccountInternalImpl = AccountComponent::InternalImpl;␊ ␊ #[storage]␊ @@ -338,14 +362,15 @@ Generated by [AVA](https://avajs.dev). mod MyAccount {␊ use openzeppelin::account::AccountComponent;␊ use openzeppelin::introspection::src5::SRC5Component;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ use starknet::ClassHash;␊ ␊ component!(path: AccountComponent, storage: account, event: AccountEvent);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl SRC6Impl = AccountComponent::SRC6Impl;␊ #[abi(embed_v0)]␊ @@ -355,6 +380,7 @@ Generated by [AVA](https://avajs.dev). #[abi(embed_v0)]␊ impl SRC5Impl = SRC5Component::SRC5Impl;␊ ␊ + // Internal␊ impl AccountInternalImpl = AccountComponent::InternalImpl;␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ ␊ @@ -384,6 +410,10 @@ Generated by [AVA](https://avajs.dev). self.account.initializer(public_key);␊ }␊ ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ #[abi(embed_v0)]␊ impl UpgradeableImpl of IUpgradeable {␊ fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ @@ -405,14 +435,15 @@ Generated by [AVA](https://avajs.dev). mod MyAccount {␊ use openzeppelin::account::AccountComponent;␊ use openzeppelin::introspection::src5::SRC5Component;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ use starknet::ClassHash;␊ ␊ component!(path: AccountComponent, storage: account, event: AccountEvent);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl SRC6Impl = AccountComponent::SRC6Impl;␊ #[abi(embed_v0)]␊ @@ -422,6 +453,7 @@ Generated by [AVA](https://avajs.dev). #[abi(embed_v0)]␊ impl SRC5Impl = SRC5Component::SRC5Impl;␊ ␊ + // Internal␊ impl AccountInternalImpl = AccountComponent::InternalImpl;␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ ␊ @@ -451,6 +483,10 @@ Generated by [AVA](https://avajs.dev). self.account.initializer(public_key);␊ }␊ ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ #[abi(embed_v0)]␊ impl UpgradeableImpl of IUpgradeable {␊ fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ @@ -472,14 +508,15 @@ Generated by [AVA](https://avajs.dev). mod MyAccount {␊ use openzeppelin::account::AccountComponent;␊ use openzeppelin::introspection::src5::SRC5Component;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ use starknet::ClassHash;␊ ␊ component!(path: AccountComponent, storage: account, event: AccountEvent);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl SRC6Impl = AccountComponent::SRC6Impl;␊ #[abi(embed_v0)]␊ @@ -491,6 +528,7 @@ Generated by [AVA](https://avajs.dev). #[abi(embed_v0)]␊ impl SRC5Impl = SRC5Component::SRC5Impl;␊ ␊ + // Internal␊ impl AccountInternalImpl = AccountComponent::InternalImpl;␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ ␊ @@ -520,6 +558,10 @@ Generated by [AVA](https://avajs.dev). self.account.initializer(public_key);␊ }␊ ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ #[abi(embed_v0)]␊ impl UpgradeableImpl of IUpgradeable {␊ fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ @@ -541,14 +583,15 @@ Generated by [AVA](https://avajs.dev). mod MyAccount {␊ use openzeppelin::account::AccountComponent;␊ use openzeppelin::introspection::src5::SRC5Component;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ use starknet::ClassHash;␊ ␊ component!(path: AccountComponent, storage: account, event: AccountEvent);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl SRC6Impl = AccountComponent::SRC6Impl;␊ #[abi(embed_v0)]␊ @@ -560,6 +603,7 @@ Generated by [AVA](https://avajs.dev). #[abi(embed_v0)]␊ impl SRC5Impl = SRC5Component::SRC5Impl;␊ ␊ + // Internal␊ impl AccountInternalImpl = AccountComponent::InternalImpl;␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ ␊ @@ -589,6 +633,10 @@ Generated by [AVA](https://avajs.dev). self.account.initializer(public_key);␊ }␊ ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ #[abi(embed_v0)]␊ impl UpgradeableImpl of IUpgradeable {␊ fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ @@ -610,14 +658,15 @@ Generated by [AVA](https://avajs.dev). mod MyAccount {␊ use openzeppelin::account::AccountComponent;␊ use openzeppelin::introspection::src5::SRC5Component;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ use starknet::ClassHash;␊ ␊ component!(path: AccountComponent, storage: account, event: AccountEvent);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl SRC6Impl = AccountComponent::SRC6Impl;␊ #[abi(embed_v0)]␊ @@ -631,6 +680,7 @@ Generated by [AVA](https://avajs.dev). #[abi(embed_v0)]␊ impl SRC5Impl = SRC5Component::SRC5Impl;␊ ␊ + // Internal␊ impl AccountInternalImpl = AccountComponent::InternalImpl;␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ ␊ @@ -660,6 +710,10 @@ Generated by [AVA](https://avajs.dev). self.account.initializer(public_key);␊ }␊ ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ #[abi(embed_v0)]␊ impl UpgradeableImpl of IUpgradeable {␊ fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ @@ -681,14 +735,15 @@ Generated by [AVA](https://avajs.dev). mod MyAccount {␊ use openzeppelin::account::AccountComponent;␊ use openzeppelin::introspection::src5::SRC5Component;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ use starknet::ClassHash;␊ ␊ component!(path: AccountComponent, storage: account, event: AccountEvent);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl SRC6Impl = AccountComponent::SRC6Impl;␊ #[abi(embed_v0)]␊ @@ -702,6 +757,7 @@ Generated by [AVA](https://avajs.dev). #[abi(embed_v0)]␊ impl SRC5Impl = SRC5Component::SRC5Impl;␊ ␊ + // Internal␊ impl AccountInternalImpl = AccountComponent::InternalImpl;␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ ␊ @@ -731,6 +787,10 @@ Generated by [AVA](https://avajs.dev). self.account.initializer(public_key);␊ }␊ ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ #[abi(embed_v0)]␊ impl UpgradeableImpl of IUpgradeable {␊ fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ @@ -753,17 +813,19 @@ Generated by [AVA](https://avajs.dev). use openzeppelin::account::eth_account::EthAccountComponent;␊ use openzeppelin::account::interface::EthPublicKey;␊ use openzeppelin::introspection::src5::SRC5Component;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ use starknet::ClassHash;␊ ␊ component!(path: EthAccountComponent, storage: eth_account, event: EthAccountEvent);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl EthAccountMixinImpl = EthAccountComponent::EthAccountMixinImpl;␊ ␊ + // Internal␊ impl EthAccountInternalImpl = EthAccountComponent::InternalImpl;␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ ␊ @@ -793,6 +855,10 @@ Generated by [AVA](https://avajs.dev). self.eth_account.initializer(public_key);␊ }␊ ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ #[abi(embed_v0)]␊ impl UpgradeableImpl of IUpgradeable {␊ fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ @@ -819,9 +885,11 @@ Generated by [AVA](https://avajs.dev). component!(path: EthAccountComponent, storage: eth_account, event: EthAccountEvent);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl EthAccountMixinImpl = EthAccountComponent::EthAccountMixinImpl;␊ ␊ + // Internal␊ impl EthAccountInternalImpl = EthAccountComponent::InternalImpl;␊ ␊ #[storage]␊ @@ -860,17 +928,19 @@ Generated by [AVA](https://avajs.dev). use openzeppelin::account::eth_account::EthAccountComponent;␊ use openzeppelin::account::interface::EthPublicKey;␊ use openzeppelin::introspection::src5::SRC5Component;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ use starknet::ClassHash;␊ ␊ component!(path: EthAccountComponent, storage: eth_account, event: EthAccountEvent);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl EthAccountMixinImpl = EthAccountComponent::EthAccountMixinImpl;␊ ␊ + // Internal␊ impl EthAccountInternalImpl = EthAccountComponent::InternalImpl;␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ ␊ @@ -900,6 +970,10 @@ Generated by [AVA](https://avajs.dev). self.eth_account.initializer(public_key);␊ }␊ ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ #[abi(embed_v0)]␊ impl UpgradeableImpl of IUpgradeable {␊ fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ @@ -926,9 +1000,11 @@ Generated by [AVA](https://avajs.dev). component!(path: EthAccountComponent, storage: eth_account, event: EthAccountEvent);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl EthAccountMixinImpl = EthAccountComponent::EthAccountMixinImpl;␊ ␊ + // Internal␊ impl EthAccountInternalImpl = EthAccountComponent::InternalImpl;␊ ␊ #[storage]␊ @@ -967,14 +1043,15 @@ Generated by [AVA](https://avajs.dev). use openzeppelin::account::eth_account::EthAccountComponent;␊ use openzeppelin::account::interface::EthPublicKey;␊ use openzeppelin::introspection::src5::SRC5Component;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ use starknet::ClassHash;␊ ␊ component!(path: EthAccountComponent, storage: eth_account, event: EthAccountEvent);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl SRC6Impl = EthAccountComponent::SRC6Impl;␊ #[abi(embed_v0)]␊ @@ -982,6 +1059,7 @@ Generated by [AVA](https://avajs.dev). #[abi(embed_v0)]␊ impl SRC5Impl = SRC5Component::SRC5Impl;␊ ␊ + // Internal␊ impl EthAccountInternalImpl = EthAccountComponent::InternalImpl;␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ ␊ @@ -1011,6 +1089,10 @@ Generated by [AVA](https://avajs.dev). self.eth_account.initializer(public_key);␊ }␊ ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ #[abi(embed_v0)]␊ impl UpgradeableImpl of IUpgradeable {␊ fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ @@ -1037,6 +1119,7 @@ Generated by [AVA](https://avajs.dev). component!(path: EthAccountComponent, storage: eth_account, event: EthAccountEvent);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl SRC6Impl = EthAccountComponent::SRC6Impl;␊ #[abi(embed_v0)]␊ @@ -1044,6 +1127,7 @@ Generated by [AVA](https://avajs.dev). #[abi(embed_v0)]␊ impl SRC5Impl = SRC5Component::SRC5Impl;␊ ␊ + // Internal␊ impl EthAccountInternalImpl = EthAccountComponent::InternalImpl;␊ ␊ #[storage]␊ @@ -1082,14 +1166,15 @@ Generated by [AVA](https://avajs.dev). use openzeppelin::account::eth_account::EthAccountComponent;␊ use openzeppelin::account::interface::EthPublicKey;␊ use openzeppelin::introspection::src5::SRC5Component;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ use starknet::ClassHash;␊ ␊ component!(path: EthAccountComponent, storage: eth_account, event: EthAccountEvent);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl SRC6Impl = EthAccountComponent::SRC6Impl;␊ #[abi(embed_v0)]␊ @@ -1099,6 +1184,7 @@ Generated by [AVA](https://avajs.dev). #[abi(embed_v0)]␊ impl SRC5Impl = SRC5Component::SRC5Impl;␊ ␊ + // Internal␊ impl EthAccountInternalImpl = EthAccountComponent::InternalImpl;␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ ␊ @@ -1128,6 +1214,10 @@ Generated by [AVA](https://avajs.dev). self.eth_account.initializer(public_key);␊ }␊ ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ #[abi(embed_v0)]␊ impl UpgradeableImpl of IUpgradeable {␊ fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ @@ -1150,14 +1240,15 @@ Generated by [AVA](https://avajs.dev). use openzeppelin::account::eth_account::EthAccountComponent;␊ use openzeppelin::account::interface::EthPublicKey;␊ use openzeppelin::introspection::src5::SRC5Component;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ use starknet::ClassHash;␊ ␊ component!(path: EthAccountComponent, storage: eth_account, event: EthAccountEvent);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl SRC6Impl = EthAccountComponent::SRC6Impl;␊ #[abi(embed_v0)]␊ @@ -1167,6 +1258,7 @@ Generated by [AVA](https://avajs.dev). #[abi(embed_v0)]␊ impl SRC5Impl = SRC5Component::SRC5Impl;␊ ␊ + // Internal␊ impl EthAccountInternalImpl = EthAccountComponent::InternalImpl;␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ ␊ @@ -1196,6 +1288,10 @@ Generated by [AVA](https://avajs.dev). self.eth_account.initializer(public_key);␊ }␊ ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ #[abi(embed_v0)]␊ impl UpgradeableImpl of IUpgradeable {␊ fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ @@ -1218,14 +1314,15 @@ Generated by [AVA](https://avajs.dev). use openzeppelin::account::eth_account::EthAccountComponent;␊ use openzeppelin::account::interface::EthPublicKey;␊ use openzeppelin::introspection::src5::SRC5Component;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ use starknet::ClassHash;␊ ␊ component!(path: EthAccountComponent, storage: eth_account, event: EthAccountEvent);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl SRC6Impl = EthAccountComponent::SRC6Impl;␊ #[abi(embed_v0)]␊ @@ -1237,6 +1334,7 @@ Generated by [AVA](https://avajs.dev). #[abi(embed_v0)]␊ impl SRC5Impl = SRC5Component::SRC5Impl;␊ ␊ + // Internal␊ impl EthAccountInternalImpl = EthAccountComponent::InternalImpl;␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ ␊ @@ -1266,6 +1364,10 @@ Generated by [AVA](https://avajs.dev). self.eth_account.initializer(public_key);␊ }␊ ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ #[abi(embed_v0)]␊ impl UpgradeableImpl of IUpgradeable {␊ fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ @@ -1288,14 +1390,15 @@ Generated by [AVA](https://avajs.dev). use openzeppelin::account::eth_account::EthAccountComponent;␊ use openzeppelin::account::interface::EthPublicKey;␊ use openzeppelin::introspection::src5::SRC5Component;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ use starknet::ClassHash;␊ ␊ component!(path: EthAccountComponent, storage: eth_account, event: EthAccountEvent);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl SRC6Impl = EthAccountComponent::SRC6Impl;␊ #[abi(embed_v0)]␊ @@ -1307,6 +1410,7 @@ Generated by [AVA](https://avajs.dev). #[abi(embed_v0)]␊ impl SRC5Impl = SRC5Component::SRC5Impl;␊ ␊ + // Internal␊ impl EthAccountInternalImpl = EthAccountComponent::InternalImpl;␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ ␊ @@ -1336,6 +1440,10 @@ Generated by [AVA](https://avajs.dev). self.eth_account.initializer(public_key);␊ }␊ ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ #[abi(embed_v0)]␊ impl UpgradeableImpl of IUpgradeable {␊ fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ @@ -1358,14 +1466,15 @@ Generated by [AVA](https://avajs.dev). use openzeppelin::account::eth_account::EthAccountComponent;␊ use openzeppelin::account::interface::EthPublicKey;␊ use openzeppelin::introspection::src5::SRC5Component;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ use starknet::ClassHash;␊ ␊ component!(path: EthAccountComponent, storage: eth_account, event: EthAccountEvent);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl SRC6Impl = EthAccountComponent::SRC6Impl;␊ #[abi(embed_v0)]␊ @@ -1379,6 +1488,7 @@ Generated by [AVA](https://avajs.dev). #[abi(embed_v0)]␊ impl SRC5Impl = SRC5Component::SRC5Impl;␊ ␊ + // Internal␊ impl EthAccountInternalImpl = EthAccountComponent::InternalImpl;␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ ␊ @@ -1408,6 +1518,10 @@ Generated by [AVA](https://avajs.dev). self.eth_account.initializer(public_key);␊ }␊ ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ #[abi(embed_v0)]␊ impl UpgradeableImpl of IUpgradeable {␊ fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ @@ -1430,14 +1544,15 @@ Generated by [AVA](https://avajs.dev). use openzeppelin::account::eth_account::EthAccountComponent;␊ use openzeppelin::account::interface::EthPublicKey;␊ use openzeppelin::introspection::src5::SRC5Component;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ use starknet::ClassHash;␊ ␊ component!(path: EthAccountComponent, storage: eth_account, event: EthAccountEvent);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl SRC6Impl = EthAccountComponent::SRC6Impl;␊ #[abi(embed_v0)]␊ @@ -1451,6 +1566,7 @@ Generated by [AVA](https://avajs.dev). #[abi(embed_v0)]␊ impl SRC5Impl = SRC5Component::SRC5Impl;␊ ␊ + // Internal␊ impl EthAccountInternalImpl = EthAccountComponent::InternalImpl;␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ ␊ @@ -1480,6 +1596,10 @@ Generated by [AVA](https://avajs.dev). self.eth_account.initializer(public_key);␊ }␊ ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ #[abi(embed_v0)]␊ impl UpgradeableImpl of IUpgradeable {␊ fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ diff --git a/packages/core-cairo/src/account.test.ts.snap b/packages/core-cairo/src/account.test.ts.snap index 0c6195e8..a013fa64 100644 Binary files a/packages/core-cairo/src/account.test.ts.snap and b/packages/core-cairo/src/account.test.ts.snap differ diff --git a/packages/core-cairo/src/account.ts b/packages/core-cairo/src/account.ts index b5768bcd..bfbeaca2 100644 --- a/packages/core-cairo/src/account.ts +++ b/packages/core-cairo/src/account.ts @@ -55,7 +55,7 @@ export function buildAccount(opts: AccountOptions): Contract { c.addComponent(components.AccountComponent, [{ lit: 'public_key' }], true); break; case 'eth': - c.addStandaloneImport('openzeppelin::account::interface::EthPublicKey;'); + c.addUseClause('openzeppelin::account::interface', 'EthPublicKey'); c.addConstructorArgument({ name: 'public_key', type: 'EthPublicKey' }); c.addComponent(components.EthAccountComponent, [{ lit: 'public_key' }], true); break; @@ -160,11 +160,11 @@ const components = defineComponents( { name: 'AccountEvent', type: 'AccountComponent::Event', }, - impls: [], - internalImpl: { + impls: [{ name: 'AccountInternalImpl', + embed: false, value: 'AccountComponent::InternalImpl', - }, + }], }, EthAccountComponent: { path: 'openzeppelin::account::eth_account', @@ -176,10 +176,10 @@ const components = defineComponents( { name: 'EthAccountEvent', type: 'EthAccountComponent::Event', }, - impls: [], - internalImpl: { + impls: [{ name: 'EthAccountInternalImpl', + embed: false, value: 'EthAccountComponent::InternalImpl', - }, + }] }, }); diff --git a/packages/core-cairo/src/add-pausable.ts b/packages/core-cairo/src/add-pausable.ts index a98fe91f..1e950f98 100644 --- a/packages/core-cairo/src/add-pausable.ts +++ b/packages/core-cairo/src/add-pausable.ts @@ -25,16 +25,15 @@ const components = defineComponents( { name: 'PausableEvent', type: 'PausableComponent::Event', }, - impls: [ - { + impls: [{ name: 'PausableImpl', value: 'PausableComponent::PausableImpl', - }, + }, { + name: 'PausableInternalImpl', + embed: false, + value: 'PausableComponent::InternalImpl', + } ], - internalImpl: { - name: 'PausableInternalImpl', - value: 'PausableComponent::InternalImpl', - }, }, }); diff --git a/packages/core-cairo/src/api.ts b/packages/core-cairo/src/api.ts index f8b41962..d5634fb5 100644 --- a/packages/core-cairo/src/api.ts +++ b/packages/core-cairo/src/api.ts @@ -3,6 +3,7 @@ import { printERC20, defaults as erc20defaults, isAccessControlRequired as erc20 import { printERC721, defaults as erc721defaults, isAccessControlRequired as erc721IsAccessControlRequired, ERC721Options } from './erc721'; import { printERC1155, defaults as erc1155defaults, isAccessControlRequired as erc1155IsAccessControlRequired, ERC1155Options } from './erc1155'; import { printAccount, defaults as accountDefaults, AccountOptions } from './account'; +import { printGovernor, defaults as governorDefaults, isAccessControlRequired as governorIsAccessControlRequired, GovernorOptions } from './governor'; import { printCustom, defaults as customDefaults, isAccessControlRequired as customIsAccessControlRequired, CustomOptions } from './custom'; export interface WizardAccountAPI{ @@ -39,6 +40,7 @@ export type ERC20 = WizardContractAPI; export type ERC721 = WizardContractAPI; export type ERC1155 = WizardContractAPI; export type Account = WizardAccountAPI; +export type Governor = WizardContractAPI; export type Custom = WizardContractAPI; export const erc20: ERC20 = { @@ -60,6 +62,11 @@ export const account: Account = { print: printAccount, defaults: accountDefaults, } +export const governor: Governor = { + print: printGovernor, + defaults: governorDefaults, + isAccessControlRequired: governorIsAccessControlRequired +} export const custom: Custom = { print: printCustom, defaults: customDefaults, diff --git a/packages/core-cairo/src/build-generic.ts b/packages/core-cairo/src/build-generic.ts index ef2e485b..27fec9d2 100644 --- a/packages/core-cairo/src/build-generic.ts +++ b/packages/core-cairo/src/build-generic.ts @@ -3,12 +3,13 @@ import { ERC721Options, buildERC721 } from './erc721'; import { ERC1155Options, buildERC1155 } from './erc1155'; import { CustomOptions, buildCustom } from './custom'; import { AccountOptions, buildAccount } from './account'; - +import { GovernorOptions, buildGovernor } from './governor'; export interface KindedOptions { ERC20: { kind: 'ERC20' } & ERC20Options; ERC721: { kind: 'ERC721' } & ERC721Options; ERC1155: { kind: 'ERC1155' } & ERC1155Options; Account: { kind: 'Account' } & AccountOptions; + Governor: { kind: 'Governor' } & GovernorOptions; Custom: { kind: 'Custom' } & CustomOptions; } @@ -28,6 +29,9 @@ export function buildGeneric(opts: GenericOptions) { case 'Account': return buildAccount(opts); + case 'Governor': + return buildGovernor(opts); + case 'Custom': return buildCustom(opts); diff --git a/packages/core-cairo/src/common-components.ts b/packages/core-cairo/src/common-components.ts index 207e6212..a05776fd 100644 --- a/packages/core-cairo/src/common-components.ts +++ b/packages/core-cairo/src/common-components.ts @@ -28,11 +28,11 @@ const components = defineComponents( { name: 'VotesEvent', type: 'VotesComponent::Event', }, - impls: [], - internalImpl: { + impls: [{ name: 'VotesInternalImpl', + embed: false, value: 'VotesComponent::InternalImpl', - }, + }], }, NoncesComponent: { @@ -54,32 +54,38 @@ const components = defineComponents( { }, }) -export function addSRC5Component(c: ContractBuilder) { +export function addSRC5Component(c: ContractBuilder, section?: string) { c.addComponent(components.SRC5Component, [], false); if (!c.interfaceFlags.has('ISRC5')) { c.addImplToComponent(components.SRC5Component, { name: 'SRC5Impl', value: 'SRC5Component::SRC5Impl', + section, }); c.addInterfaceFlag('ISRC5'); } } -export function addVotesComponent(c: ContractBuilder, name: string, version: string) { - c.addStandaloneImport('openzeppelin::utils::cryptography::snip12::SNIP12Metadata'); +export function addVotesComponent(c: ContractBuilder, name: string, version: string, section?: string) { + addSNIP12Metadata(c, name, version, section); c.addComponent(components.NoncesComponent, [], false); c.addComponent(components.VotesComponent, [], false); c.addImplToComponent(components.VotesComponent, { name: 'VotesImpl', value: `VotesComponent::VotesImpl`, }); +} + +export function addSNIP12Metadata(c: ContractBuilder, name: string, version: string, section?: string) { + c.addUseClause('openzeppelin::utils::cryptography::snip12', 'SNIP12Metadata'); const SNIP12Metadata: BaseImplementedTrait = { name: 'SNIP12MetadataImpl', of: 'SNIP12Metadata', tags: [], priority: 0, + section, }; c.addImplementedTrait(SNIP12Metadata); diff --git a/packages/core-cairo/src/contract.test.ts b/packages/core-cairo/src/contract.test.ts index 1cc88ba8..b7d040ee 100644 --- a/packages/core-cairo/src/contract.test.ts +++ b/packages/core-cairo/src/contract.test.ts @@ -14,16 +14,15 @@ const FOO_COMPONENT: Component = { name: 'FooEvent', type: 'FooComponent::Event', }, - impls: [ - { + impls: [{ name: 'FooImpl', value: 'FooComponent::FooImpl', - }, + }, { + name: 'FooInternalImpl', + embed: false, + value: 'FooComponent::InternalImpl', + } ], - internalImpl: { - name: 'FooInternalImpl', - value: 'FooComponent::InternalImpl', - }, }; test('contract basics', t => { @@ -107,6 +106,7 @@ test('contract with standalone import', t => { Foo.addComponent( FOO_COMPONENT, ); - Foo.addStandaloneImport('some::library::SomeLibrary'); + Foo.addUseClause('some::library', 'SomeLibrary'); t.snapshot(printContract(Foo)); }); + diff --git a/packages/core-cairo/src/contract.test.ts.md b/packages/core-cairo/src/contract.test.ts.md index b6d52b23..83f0b0ad 100644 --- a/packages/core-cairo/src/contract.test.ts.md +++ b/packages/core-cairo/src/contract.test.ts.md @@ -122,9 +122,11 @@ Generated by [AVA](https://avajs.dev). ␊ component!(path: FooComponent, storage: foo, event: FooEvent);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl FooImpl = FooComponent::FooImpl;␊ ␊ + // Internal␊ impl FooInternalImpl = FooComponent::InternalImpl;␊ ␊ #[storage]␊ @@ -161,9 +163,11 @@ Generated by [AVA](https://avajs.dev). ␊ component!(path: FooComponent, storage: foo, event: FooEvent);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl FooImpl = FooComponent::FooImpl;␊ ␊ + // Internal␊ impl FooInternalImpl = FooComponent::InternalImpl;␊ ␊ #[storage]␊ @@ -178,5 +182,10 @@ Generated by [AVA](https://avajs.dev). #[flat]␊ FooEvent: FooComponent::Event,␊ }␊ + ␊ + #[constructor]␊ + fn constructor(ref self: ContractState) {␊ + self.foo.initializer();␊ + }␊ }␊ ` diff --git a/packages/core-cairo/src/contract.test.ts.snap b/packages/core-cairo/src/contract.test.ts.snap index 86a5513b..f18abae3 100644 Binary files a/packages/core-cairo/src/contract.test.ts.snap and b/packages/core-cairo/src/contract.test.ts.snap differ diff --git a/packages/core-cairo/src/contract.ts b/packages/core-cairo/src/contract.ts index 431b3f32..b7f77d6a 100644 --- a/packages/core-cairo/src/contract.ts +++ b/packages/core-cairo/src/contract.ts @@ -4,8 +4,9 @@ export interface Contract { license: string; name: string; account: boolean; - standaloneImports: string[]; + useClauses: UseClause[]; components: Component[]; + constants: Variable[]; constructorCode: string[]; constructorArgs: Argument[]; upgradeable: boolean; @@ -15,13 +16,19 @@ export interface Contract { export type Value = string | number | bigint | { lit: string } | { note: string, value: Value }; +export interface UseClause { + containerPath: string; + name: string; + groupable?: boolean; + alias?: string; +} + export interface Component { name: string; path: string; substorage: Substorage; event: Event; impls: Impl[]; - internalImpl?: Impl; initializer?: Initializer; } @@ -38,6 +45,8 @@ export interface Event { export interface Impl { name: string; value: string; + embed?: boolean; + section?: string; } export interface Initializer { @@ -49,6 +58,7 @@ export interface BaseImplementedTrait { of: string; tags: string[]; perItemTag?: string; + section?: string; /** * Priority for which trait to print first. * Lower numbers are higher priority, undefined is lowest priority. @@ -59,6 +69,7 @@ export interface BaseImplementedTrait { export interface ImplementedTrait extends BaseImplementedTrait { superVariables: Variable[]; functions: ContractFunction[]; + section?: string; } export interface BaseFunction { @@ -77,6 +88,8 @@ export interface Variable { name: string; type: string; value: string; + comment?: string; + inlineComment?: boolean; } export interface Argument { @@ -96,7 +109,8 @@ export class ContractBuilder implements Contract { private componentsMap: Map = new Map(); private implementedTraitsMap: Map = new Map(); private superVariablesMap: Map = new Map(); - private standaloneImportsSet: Set = new Set(); + private constantsMap: Map = new Map(); + private useClausesMap: Map = new Map(); private interfaceFlagsSet: Set = new Set(); constructor(name: string, account: boolean = false) { @@ -116,8 +130,12 @@ export class ContractBuilder implements Contract { return [...this.superVariablesMap.values()]; } - get standaloneImports(): string[] { - return [...this.standaloneImportsSet]; + get constants(): Variable[] { + return [...this.constantsMap.values()]; + } + + get useClauses(): UseClause[] { + return [...this.useClausesMap.values()]; } /** @@ -127,11 +145,19 @@ export class ContractBuilder implements Contract { return this.interfaceFlagsSet; } - addStandaloneImport(fullyQualified: string): void { - this.standaloneImportsSet.add(fullyQualified); + addUseClause(containerPath: string, name: string, options?: { groupable?: boolean, alias?: string }): void { + // groupable defaults to true + const groupable = options?.groupable ?? true; + const alias = options?.alias ?? ''; + const uniqueName = alias.length > 0 ? alias : name; + const present = this.useClausesMap.has(uniqueName); + if (!present) { + this.useClausesMap.set(uniqueName, { containerPath, name, groupable, alias }); + } } addComponent(component: Component, params: Value[] = [], initializable: boolean = true): boolean { + this.addUseClause(component.path, component.name); const key = component.name; const present = this.componentsMap.has(key); if (!present) { @@ -144,7 +170,7 @@ export class ContractBuilder implements Contract { addImplToComponent(component: Component, impl: Impl): void { this.addComponent(component); - let c = this.componentsMap.get(component.name); + const c = this.componentsMap.get(component.name); if (c == undefined) { throw new Error(`Component ${component.name} has not been added yet`); } @@ -154,11 +180,21 @@ export class ContractBuilder implements Contract { } } + addConstant(constant: Variable): boolean { + if (this.constantsMap.has(constant.name)) { + return false; + } else { + this.constantsMap.set(constant.name, constant); + return true; + } + } + addSuperVariable(variable: Variable): boolean { if (this.superVariablesMap.has(variable.name)) { return false; } else { this.superVariablesMap.set(variable.name, variable); + this.addUseClause('super', variable.name); return true; } } @@ -169,12 +205,13 @@ export class ContractBuilder implements Contract { if (existingTrait !== undefined) { return existingTrait; } else { - const t: ImplementedTrait = { + const t: ImplementedTrait = { name: baseTrait.name, of: baseTrait.of, tags: [ ...baseTrait.tags ], superVariables: [], functions: [], + section: baseTrait.section, priority: baseTrait.priority, }; this.implementedTraitsMap.set(key, t); diff --git a/packages/core-cairo/src/custom.test.ts.md b/packages/core-cairo/src/custom.test.ts.md index e7882a3f..6be7095f 100644 --- a/packages/core-cairo/src/custom.test.ts.md +++ b/packages/core-cairo/src/custom.test.ts.md @@ -29,17 +29,18 @@ Generated by [AVA](https://avajs.dev). #[starknet::contract]␊ mod MyContract {␊ use openzeppelin::access::ownable::OwnableComponent;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ - use starknet::ClassHash;␊ - use starknet::ContractAddress;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ + use starknet::{ClassHash, ContractAddress};␊ ␊ component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl OwnableMixinImpl = OwnableComponent::OwnableMixinImpl;␊ ␊ + // Internal␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ impl OwnableInternalImpl = OwnableComponent::InternalImpl;␊ ␊ @@ -65,6 +66,10 @@ Generated by [AVA](https://avajs.dev). self.ownable.initializer(owner);␊ }␊ ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ #[abi(embed_v0)]␊ impl UpgradeableImpl of IUpgradeable {␊ fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ @@ -86,20 +91,21 @@ Generated by [AVA](https://avajs.dev). mod MyContract {␊ use openzeppelin::access::ownable::OwnableComponent;␊ use openzeppelin::security::pausable::PausableComponent;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ - use starknet::ClassHash;␊ - use starknet::ContractAddress;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ + use starknet::{ClassHash, ContractAddress};␊ ␊ 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 PausableImpl = PausableComponent::PausableImpl;␊ #[abi(embed_v0)]␊ impl OwnableMixinImpl = OwnableComponent::OwnableMixinImpl;␊ ␊ + // Internal␊ impl PausableInternalImpl = PausableComponent::InternalImpl;␊ impl OwnableInternalImpl = OwnableComponent::InternalImpl;␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ @@ -129,14 +135,6 @@ Generated by [AVA](https://avajs.dev). fn constructor(ref self: ContractState, owner: ContractAddress) {␊ self.ownable.initializer(owner);␊ }␊ - ␊ - #[abi(embed_v0)]␊ - impl UpgradeableImpl of IUpgradeable {␊ - fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ - self.ownable.assert_only_owner();␊ - self.upgradeable.upgrade(new_class_hash);␊ - }␊ - }␊ ␊ #[generate_trait]␊ #[abi(per_item)]␊ @@ -153,6 +151,18 @@ Generated by [AVA](https://avajs.dev). self.pausable.unpause();␊ }␊ }␊ + ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ + #[abi(embed_v0)]␊ + impl UpgradeableImpl of IUpgradeable {␊ + fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ + self.ownable.assert_only_owner();␊ + self.upgradeable.upgrade(new_class_hash);␊ + }␊ + }␊ }␊ ` @@ -166,17 +176,18 @@ Generated by [AVA](https://avajs.dev). #[starknet::contract]␊ mod MyContract {␊ use openzeppelin::access::ownable::OwnableComponent;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ - use starknet::ClassHash;␊ - use starknet::ContractAddress;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ + use starknet::{ClassHash, ContractAddress};␊ ␊ component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl OwnableMixinImpl = OwnableComponent::OwnableMixinImpl;␊ ␊ + // Internal␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ impl OwnableInternalImpl = OwnableComponent::InternalImpl;␊ ␊ @@ -202,6 +213,10 @@ Generated by [AVA](https://avajs.dev). self.ownable.initializer(owner);␊ }␊ ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ #[abi(embed_v0)]␊ impl UpgradeableImpl of IUpgradeable {␊ fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ @@ -237,17 +252,18 @@ Generated by [AVA](https://avajs.dev). #[starknet::contract]␊ mod MyContract {␊ use openzeppelin::access::ownable::OwnableComponent;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ - use starknet::ClassHash;␊ - use starknet::ContractAddress;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ + use starknet::{ClassHash, ContractAddress};␊ ␊ component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);␊ component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl OwnableMixinImpl = OwnableComponent::OwnableMixinImpl;␊ ␊ + // Internal␊ impl OwnableInternalImpl = OwnableComponent::InternalImpl;␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ ␊ @@ -273,6 +289,10 @@ Generated by [AVA](https://avajs.dev). self.ownable.initializer(owner);␊ }␊ ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ #[abi(embed_v0)]␊ impl UpgradeableImpl of IUpgradeable {␊ fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ @@ -294,22 +314,22 @@ Generated by [AVA](https://avajs.dev). ␊ #[starknet::contract]␊ mod MyContract {␊ - use openzeppelin::access::accesscontrol::AccessControlComponent;␊ - use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE;␊ + use openzeppelin::access::accesscontrol::{AccessControlComponent, DEFAULT_ADMIN_ROLE};␊ use openzeppelin::introspection::src5::SRC5Component;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ - use starknet::ClassHash;␊ - use starknet::ContractAddress;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ + use starknet::{ClassHash, ContractAddress};␊ use super::UPGRADER_ROLE;␊ ␊ 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 AccessControlMixinImpl = AccessControlComponent::AccessControlMixinImpl;␊ ␊ + // Internal␊ impl AccessControlInternalImpl = AccessControlComponent::InternalImpl;␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ ␊ @@ -346,6 +366,10 @@ Generated by [AVA](https://avajs.dev). self.accesscontrol._grant_role(UPGRADER_ROLE, upgrader);␊ }␊ ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ #[abi(embed_v0)]␊ impl UpgradeableImpl of IUpgradeable {␊ fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ @@ -372,11 +396,13 @@ Generated by [AVA](https://avajs.dev). component!(path: PausableComponent, storage: pausable, event: PausableEvent);␊ component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl PausableImpl = PausableComponent::PausableImpl;␊ #[abi(embed_v0)]␊ impl OwnableMixinImpl = OwnableComponent::OwnableMixinImpl;␊ ␊ + // Internal␊ impl PausableInternalImpl = PausableComponent::InternalImpl;␊ impl OwnableInternalImpl = OwnableComponent::InternalImpl;␊ ␊ diff --git a/packages/core-cairo/src/custom.test.ts.snap b/packages/core-cairo/src/custom.test.ts.snap index 10ce3638..fb2302b7 100644 Binary files a/packages/core-cairo/src/custom.test.ts.snap and b/packages/core-cairo/src/custom.test.ts.snap differ diff --git a/packages/core-cairo/src/erc1155.test.ts.md b/packages/core-cairo/src/erc1155.test.ts.md index 52cf75df..51892028 100644 --- a/packages/core-cairo/src/erc1155.test.ts.md +++ b/packages/core-cairo/src/erc1155.test.ts.md @@ -15,19 +15,20 @@ Generated by [AVA](https://avajs.dev). mod MyToken {␊ use openzeppelin::access::ownable::OwnableComponent;␊ use openzeppelin::introspection::src5::SRC5Component;␊ - use openzeppelin::token::erc1155::ERC1155Component;␊ - use openzeppelin::token::erc1155::ERC1155HooksEmptyImpl;␊ + use openzeppelin::token::erc1155::{ERC1155Component, ERC1155HooksEmptyImpl};␊ use starknet::ContractAddress;␊ ␊ component!(path: ERC1155Component, storage: erc1155, event: ERC1155Event);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl ERC1155MixinImpl = ERC1155Component::ERC1155MixinImpl;␊ #[abi(embed_v0)]␊ impl OwnableMixinImpl = OwnableComponent::OwnableMixinImpl;␊ ␊ + // Internal␊ impl ERC1155InternalImpl = ERC1155Component::InternalImpl;␊ impl OwnableInternalImpl = OwnableComponent::InternalImpl;␊ ␊ @@ -86,23 +87,23 @@ Generated by [AVA](https://avajs.dev). mod MyToken {␊ use openzeppelin::access::ownable::OwnableComponent;␊ use openzeppelin::introspection::src5::SRC5Component;␊ - use openzeppelin::token::erc1155::ERC1155Component;␊ - use openzeppelin::token::erc1155::ERC1155HooksEmptyImpl;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ + use openzeppelin::token::erc1155::{ERC1155Component, ERC1155HooksEmptyImpl};␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ - use starknet::ClassHash;␊ - use starknet::ContractAddress;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ + use starknet::{ClassHash, ContractAddress};␊ ␊ component!(path: ERC1155Component, storage: erc1155, event: ERC1155Event);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);␊ component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl ERC1155MixinImpl = ERC1155Component::ERC1155MixinImpl;␊ #[abi(embed_v0)]␊ impl OwnableMixinImpl = OwnableComponent::OwnableMixinImpl;␊ ␊ + // Internal␊ impl ERC1155InternalImpl = ERC1155Component::InternalImpl;␊ impl OwnableInternalImpl = OwnableComponent::InternalImpl;␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ @@ -137,14 +138,6 @@ Generated by [AVA](https://avajs.dev). self.erc1155.initializer("https://gateway.pinata.cloud/ipfs/QmcP9hxrnC1T5ATPmq2saFeAM1ypFX9BnAswCdHB9JCjLA/");␊ self.ownable.initializer(owner);␊ }␊ - ␊ - #[abi(embed_v0)]␊ - impl UpgradeableImpl of IUpgradeable {␊ - fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ - self.ownable.assert_only_owner();␊ - self.upgradeable.upgrade(new_class_hash);␊ - }␊ - }␊ ␊ #[generate_trait]␊ #[abi(per_item)]␊ @@ -160,6 +153,18 @@ Generated by [AVA](https://avajs.dev). self.set_base_uri(baseUri);␊ }␊ }␊ + ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ + #[abi(embed_v0)]␊ + impl UpgradeableImpl of IUpgradeable {␊ + fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ + self.ownable.assert_only_owner();␊ + self.upgradeable.upgrade(new_class_hash);␊ + }␊ + }␊ }␊ ` @@ -175,22 +180,20 @@ Generated by [AVA](https://avajs.dev). ␊ #[starknet::contract]␊ mod MyToken {␊ - use openzeppelin::access::accesscontrol::AccessControlComponent;␊ - use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE;␊ + use openzeppelin::access::accesscontrol::{AccessControlComponent, DEFAULT_ADMIN_ROLE};␊ use openzeppelin::introspection::src5::SRC5Component;␊ - use openzeppelin::token::erc1155::ERC1155Component;␊ - use openzeppelin::token::erc1155::ERC1155HooksEmptyImpl;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ + use openzeppelin::token::erc1155::{ERC1155Component, ERC1155HooksEmptyImpl};␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ - use starknet::ClassHash;␊ - use starknet::ContractAddress;␊ - use super::{URI_SETTER_ROLE, UPGRADER_ROLE};␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ + use starknet::{ClassHash, ContractAddress};␊ + use super::{UPGRADER_ROLE, URI_SETTER_ROLE};␊ ␊ component!(path: ERC1155Component, storage: erc1155, event: ERC1155Event);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ component!(path: AccessControlComponent, storage: accesscontrol, event: AccessControlEvent);␊ component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl ERC1155MixinImpl = ERC1155Component::ERC1155MixinImpl;␊ #[abi(embed_v0)]␊ @@ -198,6 +201,7 @@ Generated by [AVA](https://avajs.dev). #[abi(embed_v0)]␊ impl AccessControlCamelImpl = AccessControlComponent::AccessControlCamelImpl;␊ ␊ + // Internal␊ impl ERC1155InternalImpl = ERC1155Component::InternalImpl;␊ impl AccessControlInternalImpl = AccessControlComponent::InternalImpl;␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ @@ -241,14 +245,6 @@ Generated by [AVA](https://avajs.dev). self.accesscontrol._grant_role(URI_SETTER_ROLE, uri_setter);␊ self.accesscontrol._grant_role(UPGRADER_ROLE, upgrader);␊ }␊ - ␊ - #[abi(embed_v0)]␊ - impl UpgradeableImpl of IUpgradeable {␊ - fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ - self.accesscontrol.assert_only_role(UPGRADER_ROLE);␊ - self.upgradeable.upgrade(new_class_hash);␊ - }␊ - }␊ ␊ #[generate_trait]␊ #[abi(per_item)]␊ @@ -264,6 +260,18 @@ Generated by [AVA](https://avajs.dev). self.set_base_uri(baseUri);␊ }␊ }␊ + ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ + #[abi(embed_v0)]␊ + impl UpgradeableImpl of IUpgradeable {␊ + fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ + self.accesscontrol.assert_only_role(UPGRADER_ROLE);␊ + self.upgradeable.upgrade(new_class_hash);␊ + }␊ + }␊ }␊ ` @@ -278,23 +286,23 @@ Generated by [AVA](https://avajs.dev). mod MyToken {␊ use openzeppelin::access::ownable::OwnableComponent;␊ use openzeppelin::introspection::src5::SRC5Component;␊ - use openzeppelin::token::erc1155::ERC1155Component;␊ - use openzeppelin::token::erc1155::ERC1155HooksEmptyImpl;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ + use openzeppelin::token::erc1155::{ERC1155Component, ERC1155HooksEmptyImpl};␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ - use starknet::ClassHash;␊ - use starknet::ContractAddress;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ + use starknet::{ClassHash, ContractAddress};␊ ␊ component!(path: ERC1155Component, storage: erc1155, event: ERC1155Event);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl ERC1155MixinImpl = ERC1155Component::ERC1155MixinImpl;␊ #[abi(embed_v0)]␊ impl OwnableMixinImpl = OwnableComponent::OwnableMixinImpl;␊ ␊ + // Internal␊ impl ERC1155InternalImpl = ERC1155Component::InternalImpl;␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ impl OwnableInternalImpl = OwnableComponent::InternalImpl;␊ @@ -330,6 +338,10 @@ Generated by [AVA](https://avajs.dev). self.ownable.initializer(owner);␊ }␊ ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ #[abi(embed_v0)]␊ impl UpgradeableImpl of IUpgradeable {␊ fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ @@ -351,24 +363,23 @@ Generated by [AVA](https://avajs.dev). mod MyToken {␊ use openzeppelin::access::ownable::OwnableComponent;␊ use openzeppelin::introspection::src5::SRC5Component;␊ - use openzeppelin::token::erc1155::ERC1155Component;␊ - use openzeppelin::token::erc1155::ERC1155HooksEmptyImpl;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ + use openzeppelin::token::erc1155::{ERC1155Component, ERC1155HooksEmptyImpl};␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ - use starknet::ClassHash;␊ - use starknet::ContractAddress;␊ - use starknet::get_caller_address;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ + use starknet::{ClassHash, ContractAddress, get_caller_address};␊ ␊ component!(path: ERC1155Component, storage: erc1155, event: ERC1155Event);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);␊ component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl ERC1155MixinImpl = ERC1155Component::ERC1155MixinImpl;␊ #[abi(embed_v0)]␊ impl OwnableMixinImpl = OwnableComponent::OwnableMixinImpl;␊ ␊ + // Internal␊ impl ERC1155InternalImpl = ERC1155Component::InternalImpl;␊ impl OwnableInternalImpl = OwnableComponent::InternalImpl;␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ @@ -403,14 +414,6 @@ Generated by [AVA](https://avajs.dev). self.erc1155.initializer("https://gateway.pinata.cloud/ipfs/QmcP9hxrnC1T5ATPmq2saFeAM1ypFX9BnAswCdHB9JCjLA/");␊ self.ownable.initializer(owner);␊ }␊ - ␊ - #[abi(embed_v0)]␊ - impl UpgradeableImpl of IUpgradeable {␊ - fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ - self.ownable.assert_only_owner();␊ - self.upgradeable.upgrade(new_class_hash);␊ - }␊ - }␊ ␊ #[generate_trait]␊ #[abi(per_item)]␊ @@ -459,6 +462,18 @@ Generated by [AVA](https://avajs.dev). self.set_base_uri(baseUri);␊ }␊ }␊ + ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ + #[abi(embed_v0)]␊ + impl UpgradeableImpl of IUpgradeable {␊ + fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ + self.ownable.assert_only_owner();␊ + self.upgradeable.upgrade(new_class_hash);␊ + }␊ + }␊ }␊ ` @@ -475,10 +490,9 @@ Generated by [AVA](https://avajs.dev). use openzeppelin::introspection::src5::SRC5Component;␊ use openzeppelin::security::pausable::PausableComponent;␊ use openzeppelin::token::erc1155::ERC1155Component;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ - use starknet::ClassHash;␊ - use starknet::ContractAddress;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ + use starknet::{ClassHash, ContractAddress};␊ ␊ component!(path: ERC1155Component, storage: erc1155, event: ERC1155Event);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ @@ -486,6 +500,7 @@ Generated by [AVA](https://avajs.dev). component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);␊ component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl ERC1155MixinImpl = ERC1155Component::ERC1155MixinImpl;␊ #[abi(embed_v0)]␊ @@ -493,6 +508,7 @@ Generated by [AVA](https://avajs.dev). #[abi(embed_v0)]␊ impl OwnableMixinImpl = OwnableComponent::OwnableMixinImpl;␊ ␊ + // Internal␊ impl ERC1155InternalImpl = ERC1155Component::InternalImpl;␊ impl PausableInternalImpl = PausableComponent::InternalImpl;␊ impl OwnableInternalImpl = OwnableComponent::InternalImpl;␊ @@ -545,15 +561,7 @@ Generated by [AVA](https://avajs.dev). contract_state.pausable.assert_not_paused();␊ }␊ }␊ - ␊ - #[abi(embed_v0)]␊ - impl UpgradeableImpl of IUpgradeable {␊ - fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ - self.ownable.assert_only_owner();␊ - self.upgradeable.upgrade(new_class_hash);␊ - }␊ - }␊ - ␊ + ␊ #[generate_trait]␊ #[abi(per_item)]␊ impl ExternalImpl of ExternalTrait {␊ @@ -580,6 +588,18 @@ Generated by [AVA](https://avajs.dev). self.set_base_uri(baseUri);␊ }␊ }␊ + ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ + #[abi(embed_v0)]␊ + impl UpgradeableImpl of IUpgradeable {␊ + fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ + self.ownable.assert_only_owner();␊ + self.upgradeable.upgrade(new_class_hash);␊ + }␊ + }␊ }␊ ` @@ -594,23 +614,23 @@ Generated by [AVA](https://avajs.dev). mod MyToken {␊ use openzeppelin::access::ownable::OwnableComponent;␊ use openzeppelin::introspection::src5::SRC5Component;␊ - use openzeppelin::token::erc1155::ERC1155Component;␊ - use openzeppelin::token::erc1155::ERC1155HooksEmptyImpl;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ + use openzeppelin::token::erc1155::{ERC1155Component, ERC1155HooksEmptyImpl};␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ - use starknet::ClassHash;␊ - use starknet::ContractAddress;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ + use starknet::{ClassHash, ContractAddress};␊ ␊ component!(path: ERC1155Component, storage: erc1155, event: ERC1155Event);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);␊ component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl ERC1155MixinImpl = ERC1155Component::ERC1155MixinImpl;␊ #[abi(embed_v0)]␊ impl OwnableMixinImpl = OwnableComponent::OwnableMixinImpl;␊ ␊ + // Internal␊ impl ERC1155InternalImpl = ERC1155Component::InternalImpl;␊ impl OwnableInternalImpl = OwnableComponent::InternalImpl;␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ @@ -645,14 +665,6 @@ Generated by [AVA](https://avajs.dev). self.erc1155.initializer("https://gateway.pinata.cloud/ipfs/QmcP9hxrnC1T5ATPmq2saFeAM1ypFX9BnAswCdHB9JCjLA/");␊ self.ownable.initializer(owner);␊ }␊ - ␊ - #[abi(embed_v0)]␊ - impl UpgradeableImpl of IUpgradeable {␊ - fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ - self.ownable.assert_only_owner();␊ - self.upgradeable.upgrade(new_class_hash);␊ - }␊ - }␊ ␊ #[generate_trait]␊ #[abi(per_item)]␊ @@ -703,6 +715,18 @@ Generated by [AVA](https://avajs.dev). self.set_base_uri(baseUri);␊ }␊ }␊ + ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ + #[abi(embed_v0)]␊ + impl UpgradeableImpl of IUpgradeable {␊ + fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ + self.ownable.assert_only_owner();␊ + self.upgradeable.upgrade(new_class_hash);␊ + }␊ + }␊ }␊ ` @@ -719,22 +743,20 @@ Generated by [AVA](https://avajs.dev). ␊ #[starknet::contract]␊ mod MyToken {␊ - use openzeppelin::access::accesscontrol::AccessControlComponent;␊ - use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE;␊ + use openzeppelin::access::accesscontrol::{AccessControlComponent, DEFAULT_ADMIN_ROLE};␊ use openzeppelin::introspection::src5::SRC5Component;␊ - use openzeppelin::token::erc1155::ERC1155Component;␊ - use openzeppelin::token::erc1155::ERC1155HooksEmptyImpl;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ + use openzeppelin::token::erc1155::{ERC1155Component, ERC1155HooksEmptyImpl};␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ - use starknet::ClassHash;␊ - use starknet::ContractAddress;␊ - use super::{MINTER_ROLE, URI_SETTER_ROLE, UPGRADER_ROLE};␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ + use starknet::{ClassHash, ContractAddress};␊ + use super::{MINTER_ROLE, UPGRADER_ROLE, URI_SETTER_ROLE};␊ ␊ component!(path: ERC1155Component, storage: erc1155, event: ERC1155Event);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ component!(path: AccessControlComponent, storage: accesscontrol, event: AccessControlEvent);␊ component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl ERC1155MixinImpl = ERC1155Component::ERC1155MixinImpl;␊ #[abi(embed_v0)]␊ @@ -742,6 +764,7 @@ Generated by [AVA](https://avajs.dev). #[abi(embed_v0)]␊ impl AccessControlCamelImpl = AccessControlComponent::AccessControlCamelImpl;␊ ␊ + // Internal␊ impl ERC1155InternalImpl = ERC1155Component::InternalImpl;␊ impl AccessControlInternalImpl = AccessControlComponent::InternalImpl;␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ @@ -787,14 +810,6 @@ Generated by [AVA](https://avajs.dev). self.accesscontrol._grant_role(URI_SETTER_ROLE, uri_setter);␊ self.accesscontrol._grant_role(UPGRADER_ROLE, upgrader);␊ }␊ - ␊ - #[abi(embed_v0)]␊ - impl UpgradeableImpl of IUpgradeable {␊ - fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ - self.accesscontrol.assert_only_role(UPGRADER_ROLE);␊ - self.upgradeable.upgrade(new_class_hash);␊ - }␊ - }␊ ␊ #[generate_trait]␊ #[abi(per_item)]␊ @@ -845,6 +860,18 @@ Generated by [AVA](https://avajs.dev). self.set_base_uri(baseUri);␊ }␊ }␊ + ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ + #[abi(embed_v0)]␊ + impl UpgradeableImpl of IUpgradeable {␊ + fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ + self.accesscontrol.assert_only_role(UPGRADER_ROLE);␊ + self.upgradeable.upgrade(new_class_hash);␊ + }␊ + }␊ }␊ ` @@ -859,23 +886,23 @@ Generated by [AVA](https://avajs.dev). mod MyToken {␊ use openzeppelin::access::ownable::OwnableComponent;␊ use openzeppelin::introspection::src5::SRC5Component;␊ - use openzeppelin::token::erc1155::ERC1155Component;␊ - use openzeppelin::token::erc1155::ERC1155HooksEmptyImpl;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ + use openzeppelin::token::erc1155::{ERC1155Component, ERC1155HooksEmptyImpl};␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ - use starknet::ClassHash;␊ - use starknet::ContractAddress;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ + use starknet::{ClassHash, ContractAddress};␊ ␊ component!(path: ERC1155Component, storage: erc1155, event: ERC1155Event);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);␊ component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl ERC1155MixinImpl = ERC1155Component::ERC1155MixinImpl;␊ #[abi(embed_v0)]␊ impl OwnableMixinImpl = OwnableComponent::OwnableMixinImpl;␊ ␊ + // Internal␊ impl ERC1155InternalImpl = ERC1155Component::InternalImpl;␊ impl OwnableInternalImpl = OwnableComponent::InternalImpl;␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ @@ -910,14 +937,6 @@ Generated by [AVA](https://avajs.dev). self.erc1155.initializer("https://gateway.pinata.cloud/ipfs/QmcP9hxrnC1T5ATPmq2saFeAM1ypFX9BnAswCdHB9JCjLA/");␊ self.ownable.initializer(owner);␊ }␊ - ␊ - #[abi(embed_v0)]␊ - impl UpgradeableImpl of IUpgradeable {␊ - fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ - self.ownable.assert_only_owner();␊ - self.upgradeable.upgrade(new_class_hash);␊ - }␊ - }␊ ␊ #[generate_trait]␊ #[abi(per_item)]␊ @@ -933,6 +952,18 @@ Generated by [AVA](https://avajs.dev). self.set_base_uri(baseUri);␊ }␊ }␊ + ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ + #[abi(embed_v0)]␊ + impl UpgradeableImpl of IUpgradeable {␊ + fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ + self.ownable.assert_only_owner();␊ + self.upgradeable.upgrade(new_class_hash);␊ + }␊ + }␊ }␊ ` @@ -947,14 +978,11 @@ Generated by [AVA](https://avajs.dev). mod MyToken {␊ use openzeppelin::access::ownable::OwnableComponent;␊ use openzeppelin::introspection::src5::SRC5Component;␊ - use openzeppelin::token::common::erc2981::DefaultConfig;␊ - use openzeppelin::token::common::erc2981::ERC2981Component;␊ - use openzeppelin::token::erc1155::ERC1155Component;␊ - use openzeppelin::token::erc1155::ERC1155HooksEmptyImpl;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ + use openzeppelin::token::common::erc2981::{DefaultConfig, ERC2981Component};␊ + use openzeppelin::token::erc1155::{ERC1155Component, ERC1155HooksEmptyImpl};␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ - use starknet::ClassHash;␊ - use starknet::ContractAddress;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ + use starknet::{ClassHash, ContractAddress};␊ ␊ component!(path: ERC1155Component, storage: erc1155, event: ERC1155Event);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ @@ -962,6 +990,7 @@ Generated by [AVA](https://avajs.dev). component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ component!(path: ERC2981Component, storage: erc2981, event: ERC2981Event);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl ERC1155MixinImpl = ERC1155Component::ERC1155MixinImpl;␊ #[abi(embed_v0)]␊ @@ -973,6 +1002,7 @@ Generated by [AVA](https://avajs.dev). #[abi(embed_v0)]␊ impl ERC2981AdminOwnableImpl = ERC2981Component::ERC2981AdminOwnableImpl;␊ ␊ + // Internal␊ impl ERC1155InternalImpl = ERC1155Component::InternalImpl;␊ impl OwnableInternalImpl = OwnableComponent::InternalImpl;␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ @@ -1017,14 +1047,6 @@ Generated by [AVA](https://avajs.dev). self.ownable.initializer(owner);␊ self.erc2981.initializer(default_royalty_receiver, 500);␊ }␊ - ␊ - #[abi(embed_v0)]␊ - impl UpgradeableImpl of IUpgradeable {␊ - fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ - self.ownable.assert_only_owner();␊ - self.upgradeable.upgrade(new_class_hash);␊ - }␊ - }␊ ␊ #[generate_trait]␊ #[abi(per_item)]␊ @@ -1040,6 +1062,18 @@ Generated by [AVA](https://avajs.dev). self.set_base_uri(baseUri);␊ }␊ }␊ + ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ + #[abi(embed_v0)]␊ + impl UpgradeableImpl of IUpgradeable {␊ + fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ + self.ownable.assert_only_owner();␊ + self.upgradeable.upgrade(new_class_hash);␊ + }␊ + }␊ }␊ ` @@ -1055,18 +1089,14 @@ Generated by [AVA](https://avajs.dev). ␊ #[starknet::contract]␊ mod MyToken {␊ - use openzeppelin::access::accesscontrol::AccessControlComponent;␊ - use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE;␊ + use openzeppelin::access::accesscontrol::{AccessControlComponent, DEFAULT_ADMIN_ROLE};␊ use openzeppelin::introspection::src5::SRC5Component;␊ - use openzeppelin::token::common::erc2981::DefaultConfig;␊ - use openzeppelin::token::common::erc2981::ERC2981Component;␊ - use openzeppelin::token::erc1155::ERC1155Component;␊ - use openzeppelin::token::erc1155::ERC1155HooksEmptyImpl;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ + use openzeppelin::token::common::erc2981::{DefaultConfig, ERC2981Component};␊ + use openzeppelin::token::erc1155::{ERC1155Component, ERC1155HooksEmptyImpl};␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ - use starknet::ClassHash;␊ - use starknet::ContractAddress;␊ - use super::{URI_SETTER_ROLE, UPGRADER_ROLE};␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ + use starknet::{ClassHash, ContractAddress};␊ + use super::{UPGRADER_ROLE, URI_SETTER_ROLE};␊ ␊ component!(path: ERC1155Component, storage: erc1155, event: ERC1155Event);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ @@ -1074,6 +1104,7 @@ Generated by [AVA](https://avajs.dev). component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ component!(path: ERC2981Component, storage: erc2981, event: ERC2981Event);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl ERC1155MixinImpl = ERC1155Component::ERC1155MixinImpl;␊ #[abi(embed_v0)]␊ @@ -1087,6 +1118,7 @@ Generated by [AVA](https://avajs.dev). #[abi(embed_v0)]␊ impl ERC2981AdminAccessControlImpl = ERC2981Component::ERC2981AdminAccessControlImpl;␊ ␊ + // Internal␊ impl ERC1155InternalImpl = ERC1155Component::InternalImpl;␊ impl AccessControlInternalImpl = AccessControlComponent::InternalImpl;␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ @@ -1139,14 +1171,6 @@ Generated by [AVA](https://avajs.dev). self.accesscontrol._grant_role(UPGRADER_ROLE, upgrader);␊ self.accesscontrol._grant_role(ERC2981Component::ROYALTY_ADMIN_ROLE, royalty_admin);␊ }␊ - ␊ - #[abi(embed_v0)]␊ - impl UpgradeableImpl of IUpgradeable {␊ - fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ - self.accesscontrol.assert_only_role(UPGRADER_ROLE);␊ - self.upgradeable.upgrade(new_class_hash);␊ - }␊ - }␊ ␊ #[generate_trait]␊ #[abi(per_item)]␊ @@ -1162,6 +1186,18 @@ Generated by [AVA](https://avajs.dev). self.set_base_uri(baseUri);␊ }␊ }␊ + ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ + #[abi(embed_v0)]␊ + impl UpgradeableImpl of IUpgradeable {␊ + fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ + self.accesscontrol.assert_only_role(UPGRADER_ROLE);␊ + self.upgradeable.upgrade(new_class_hash);␊ + }␊ + }␊ }␊ ` @@ -1177,12 +1213,10 @@ Generated by [AVA](https://avajs.dev). use openzeppelin::access::ownable::OwnableComponent;␊ use openzeppelin::introspection::src5::SRC5Component;␊ use openzeppelin::token::common::erc2981::ERC2981Component;␊ - use openzeppelin::token::erc1155::ERC1155Component;␊ - use openzeppelin::token::erc1155::ERC1155HooksEmptyImpl;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ + use openzeppelin::token::erc1155::{ERC1155Component, ERC1155HooksEmptyImpl};␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ - use starknet::ClassHash;␊ - use starknet::ContractAddress;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ + use starknet::{ClassHash, ContractAddress};␊ ␊ component!(path: ERC1155Component, storage: erc1155, event: ERC1155Event);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ @@ -1190,6 +1224,7 @@ Generated by [AVA](https://avajs.dev). component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ component!(path: ERC2981Component, storage: erc2981, event: ERC2981Event);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl ERC1155MixinImpl = ERC1155Component::ERC1155MixinImpl;␊ #[abi(embed_v0)]␊ @@ -1201,6 +1236,7 @@ Generated by [AVA](https://avajs.dev). #[abi(embed_v0)]␊ impl ERC2981AdminOwnableImpl = ERC2981Component::ERC2981AdminOwnableImpl;␊ ␊ + // Internal␊ impl ERC1155InternalImpl = ERC1155Component::InternalImpl;␊ impl OwnableInternalImpl = OwnableComponent::InternalImpl;␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ @@ -1249,15 +1285,7 @@ Generated by [AVA](https://avajs.dev). impl ERC2981ImmutableConfig of ERC2981Component::ImmutableConfig {␊ const FEE_DENOMINATOR: u128 = 100000;␊ }␊ - ␊ - #[abi(embed_v0)]␊ - impl UpgradeableImpl of IUpgradeable {␊ - fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ - self.ownable.assert_only_owner();␊ - self.upgradeable.upgrade(new_class_hash);␊ - }␊ - }␊ - ␊ + ␊ #[generate_trait]␊ #[abi(per_item)]␊ impl ExternalImpl of ExternalTrait {␊ @@ -1272,6 +1300,18 @@ Generated by [AVA](https://avajs.dev). self.set_base_uri(baseUri);␊ }␊ }␊ + ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ + #[abi(embed_v0)]␊ + impl UpgradeableImpl of IUpgradeable {␊ + fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ + self.ownable.assert_only_owner();␊ + self.upgradeable.upgrade(new_class_hash);␊ + }␊ + }␊ }␊ ` @@ -1287,17 +1327,14 @@ Generated by [AVA](https://avajs.dev). ␊ #[starknet::contract]␊ mod MyToken {␊ - use openzeppelin::access::accesscontrol::AccessControlComponent;␊ - use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE;␊ + use openzeppelin::access::accesscontrol::{AccessControlComponent, DEFAULT_ADMIN_ROLE};␊ use openzeppelin::introspection::src5::SRC5Component;␊ use openzeppelin::token::common::erc2981::ERC2981Component;␊ - use openzeppelin::token::erc1155::ERC1155Component;␊ - use openzeppelin::token::erc1155::ERC1155HooksEmptyImpl;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ + use openzeppelin::token::erc1155::{ERC1155Component, ERC1155HooksEmptyImpl};␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ - use starknet::ClassHash;␊ - use starknet::ContractAddress;␊ - use super::{URI_SETTER_ROLE, UPGRADER_ROLE};␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ + use starknet::{ClassHash, ContractAddress};␊ + use super::{UPGRADER_ROLE, URI_SETTER_ROLE};␊ ␊ component!(path: ERC1155Component, storage: erc1155, event: ERC1155Event);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ @@ -1305,6 +1342,7 @@ Generated by [AVA](https://avajs.dev). component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ component!(path: ERC2981Component, storage: erc2981, event: ERC2981Event);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl ERC1155MixinImpl = ERC1155Component::ERC1155MixinImpl;␊ #[abi(embed_v0)]␊ @@ -1318,6 +1356,7 @@ Generated by [AVA](https://avajs.dev). #[abi(embed_v0)]␊ impl ERC2981AdminAccessControlImpl = ERC2981Component::ERC2981AdminAccessControlImpl;␊ ␊ + // Internal␊ impl ERC1155InternalImpl = ERC1155Component::InternalImpl;␊ impl AccessControlInternalImpl = AccessControlComponent::InternalImpl;␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ @@ -1374,15 +1413,7 @@ Generated by [AVA](https://avajs.dev). impl ERC2981ImmutableConfig of ERC2981Component::ImmutableConfig {␊ const FEE_DENOMINATOR: u128 = 100000;␊ }␊ - ␊ - #[abi(embed_v0)]␊ - impl UpgradeableImpl of IUpgradeable {␊ - fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ - self.accesscontrol.assert_only_role(UPGRADER_ROLE);␊ - self.upgradeable.upgrade(new_class_hash);␊ - }␊ - }␊ - ␊ + ␊ #[generate_trait]␊ #[abi(per_item)]␊ impl ExternalImpl of ExternalTrait {␊ @@ -1397,6 +1428,18 @@ Generated by [AVA](https://avajs.dev). self.set_base_uri(baseUri);␊ }␊ }␊ + ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ + #[abi(embed_v0)]␊ + impl UpgradeableImpl of IUpgradeable {␊ + fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ + self.accesscontrol.assert_only_role(UPGRADER_ROLE);␊ + self.upgradeable.upgrade(new_class_hash);␊ + }␊ + }␊ }␊ ` @@ -1413,16 +1456,13 @@ Generated by [AVA](https://avajs.dev). ␊ #[starknet::contract]␊ mod MyToken {␊ - use openzeppelin::access::accesscontrol::AccessControlComponent;␊ - use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE;␊ + use openzeppelin::access::accesscontrol::{AccessControlComponent, DEFAULT_ADMIN_ROLE};␊ use openzeppelin::introspection::src5::SRC5Component;␊ use openzeppelin::security::pausable::PausableComponent;␊ - use openzeppelin::token::common::erc2981::DefaultConfig;␊ - use openzeppelin::token::common::erc2981::ERC2981Component;␊ + use openzeppelin::token::common::erc2981::{DefaultConfig, ERC2981Component};␊ use openzeppelin::token::erc1155::ERC1155Component;␊ - use starknet::ContractAddress;␊ - use starknet::get_caller_address;␊ - use super::{PAUSER_ROLE, MINTER_ROLE, URI_SETTER_ROLE};␊ + use starknet::{ContractAddress, get_caller_address};␊ + use super::{MINTER_ROLE, PAUSER_ROLE, URI_SETTER_ROLE};␊ ␊ component!(path: ERC1155Component, storage: erc1155, event: ERC1155Event);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ @@ -1430,6 +1470,7 @@ Generated by [AVA](https://avajs.dev). component!(path: AccessControlComponent, storage: accesscontrol, event: AccessControlEvent);␊ component!(path: ERC2981Component, storage: erc2981, event: ERC2981Event);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl ERC1155MixinImpl = ERC1155Component::ERC1155MixinImpl;␊ #[abi(embed_v0)]␊ @@ -1445,6 +1486,7 @@ Generated by [AVA](https://avajs.dev). #[abi(embed_v0)]␊ impl ERC2981AdminAccessControlImpl = ERC2981Component::ERC2981AdminAccessControlImpl;␊ ␊ + // Internal␊ impl ERC1155InternalImpl = ERC1155Component::InternalImpl;␊ impl PausableInternalImpl = PausableComponent::InternalImpl;␊ impl AccessControlInternalImpl = AccessControlComponent::InternalImpl;␊ @@ -1512,7 +1554,7 @@ Generated by [AVA](https://avajs.dev). contract_state.pausable.assert_not_paused();␊ }␊ }␊ - ␊ + ␊ #[generate_trait]␊ #[abi(per_item)]␊ impl ExternalImpl of ExternalTrait {␊ @@ -1624,19 +1666,15 @@ Generated by [AVA](https://avajs.dev). ␊ #[starknet::contract]␊ mod MyToken {␊ - use openzeppelin::access::accesscontrol::AccessControlComponent;␊ - use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE;␊ + use openzeppelin::access::accesscontrol::{AccessControlComponent, DEFAULT_ADMIN_ROLE};␊ use openzeppelin::introspection::src5::SRC5Component;␊ use openzeppelin::security::pausable::PausableComponent;␊ - use openzeppelin::token::common::erc2981::DefaultConfig;␊ - use openzeppelin::token::common::erc2981::ERC2981Component;␊ + use openzeppelin::token::common::erc2981::{DefaultConfig, ERC2981Component};␊ use openzeppelin::token::erc1155::ERC1155Component;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ - use starknet::ClassHash;␊ - use starknet::ContractAddress;␊ - use starknet::get_caller_address;␊ - use super::{PAUSER_ROLE, MINTER_ROLE, URI_SETTER_ROLE, UPGRADER_ROLE};␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ + use starknet::{ClassHash, ContractAddress, get_caller_address};␊ + use super::{MINTER_ROLE, PAUSER_ROLE, UPGRADER_ROLE, URI_SETTER_ROLE};␊ ␊ component!(path: ERC1155Component, storage: erc1155, event: ERC1155Event);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ @@ -1645,6 +1683,7 @@ Generated by [AVA](https://avajs.dev). component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ component!(path: ERC2981Component, storage: erc2981, event: ERC2981Event);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl ERC1155MixinImpl = ERC1155Component::ERC1155MixinImpl;␊ #[abi(embed_v0)]␊ @@ -1660,6 +1699,7 @@ Generated by [AVA](https://avajs.dev). #[abi(embed_v0)]␊ impl ERC2981AdminAccessControlImpl = ERC2981Component::ERC2981AdminAccessControlImpl;␊ ␊ + // Internal␊ impl ERC1155InternalImpl = ERC1155Component::InternalImpl;␊ impl PausableInternalImpl = PausableComponent::InternalImpl;␊ impl AccessControlInternalImpl = AccessControlComponent::InternalImpl;␊ @@ -1734,15 +1774,7 @@ Generated by [AVA](https://avajs.dev). contract_state.pausable.assert_not_paused();␊ }␊ }␊ - ␊ - #[abi(embed_v0)]␊ - impl UpgradeableImpl of IUpgradeable {␊ - fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ - self.accesscontrol.assert_only_role(UPGRADER_ROLE);␊ - self.upgradeable.upgrade(new_class_hash);␊ - }␊ - }␊ - ␊ + ␊ #[generate_trait]␊ #[abi(per_item)]␊ impl ExternalImpl of ExternalTrait {␊ @@ -1837,5 +1869,17 @@ Generated by [AVA](https://avajs.dev). self.set_base_uri(baseUri);␊ }␊ }␊ + ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ + #[abi(embed_v0)]␊ + impl UpgradeableImpl of IUpgradeable {␊ + fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ + self.accesscontrol.assert_only_role(UPGRADER_ROLE);␊ + self.upgradeable.upgrade(new_class_hash);␊ + }␊ + }␊ }␊ ` diff --git a/packages/core-cairo/src/erc1155.test.ts.snap b/packages/core-cairo/src/erc1155.test.ts.snap index af295dcb..ee615fb3 100644 Binary files a/packages/core-cairo/src/erc1155.test.ts.snap and b/packages/core-cairo/src/erc1155.test.ts.snap differ diff --git a/packages/core-cairo/src/erc1155.ts b/packages/core-cairo/src/erc1155.ts index 2aded8ab..d17cb8f3 100644 --- a/packages/core-cairo/src/erc1155.ts +++ b/packages/core-cairo/src/erc1155.ts @@ -100,7 +100,7 @@ function addHooks(c: ContractBuilder, allOpts: Required) { priority: 1, }; c.addImplementedTrait(hooksTrait); - c.addStandaloneImport('starknet::ContractAddress'); + c.addUseClause('starknet', 'ContractAddress'); c.addFunction(hooksTrait, { name: 'before_update', @@ -117,7 +117,7 @@ function addHooks(c: ContractBuilder, allOpts: Required) { ], }); } else { - c.addStandaloneImport('openzeppelin::token::erc1155::ERC1155HooksEmptyImpl'); + c.addUseClause('openzeppelin::token::erc1155', 'ERC1155HooksEmptyImpl'); } } @@ -141,15 +141,15 @@ function addBase(c: ContractBuilder, baseUri: string) { } function addBurnable(c: ContractBuilder) { - c.addStandaloneImport('starknet::ContractAddress'); - c.addStandaloneImport('starknet::get_caller_address'); + c.addUseClause('starknet', 'ContractAddress'); + c.addUseClause('starknet', 'get_caller_address'); c.addFunction(externalTrait, functions.burn); c.addFunction(externalTrait, functions.batch_burn); c.addFunction(externalTrait, functions.batchBurn); } function addMintable(c: ContractBuilder, access: Access) { - c.addStandaloneImport('starknet::ContractAddress'); + c.addUseClause('starknet', 'ContractAddress'); requireAccessControl(c, externalTrait, functions.mint, access, 'MINTER', 'minter'); requireAccessControl(c, externalTrait, functions.batch_mint, access, 'MINTER', 'minter'); @@ -175,11 +175,11 @@ const components = defineComponents( { name: 'ERC1155Event', type: 'ERC1155Component::Event', }, - impls: [], - internalImpl: { + impls: [{ name: 'ERC1155InternalImpl', + embed: false, value: 'ERC1155Component::InternalImpl', - }, + }], }, }); diff --git a/packages/core-cairo/src/erc20.test.ts.md b/packages/core-cairo/src/erc20.test.ts.md index 9d6120c4..4f2d5b91 100644 --- a/packages/core-cairo/src/erc20.test.ts.md +++ b/packages/core-cairo/src/erc20.test.ts.md @@ -13,14 +13,15 @@ Generated by [AVA](https://avajs.dev). ␊ #[starknet::contract]␊ mod MyToken {␊ - use openzeppelin::token::erc20::ERC20Component;␊ - use openzeppelin::token::erc20::ERC20HooksEmptyImpl;␊ + use openzeppelin::token::erc20::{ERC20Component, ERC20HooksEmptyImpl};␊ ␊ component!(path: ERC20Component, storage: erc20, event: ERC20Event);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl ERC20MixinImpl = ERC20Component::ERC20MixinImpl;␊ ␊ + // Internal␊ impl ERC20InternalImpl = ERC20Component::InternalImpl;␊ ␊ #[storage]␊ @@ -53,22 +54,22 @@ Generated by [AVA](https://avajs.dev). #[starknet::contract]␊ mod MyToken {␊ use openzeppelin::access::ownable::OwnableComponent;␊ - use openzeppelin::token::erc20::ERC20Component;␊ - use openzeppelin::token::erc20::ERC20HooksEmptyImpl;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ + use openzeppelin::token::erc20::{ERC20Component, ERC20HooksEmptyImpl};␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ - use starknet::ClassHash;␊ - use starknet::ContractAddress;␊ + 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;␊ #[abi(embed_v0)]␊ impl OwnableMixinImpl = OwnableComponent::OwnableMixinImpl;␊ ␊ + // Internal␊ impl ERC20InternalImpl = ERC20Component::InternalImpl;␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ impl OwnableInternalImpl = OwnableComponent::InternalImpl;␊ @@ -100,6 +101,10 @@ Generated by [AVA](https://avajs.dev). self.ownable.initializer(owner);␊ }␊ ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ #[abi(embed_v0)]␊ impl UpgradeableImpl of IUpgradeable {␊ fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ @@ -120,23 +125,22 @@ Generated by [AVA](https://avajs.dev). #[starknet::contract]␊ mod MyToken {␊ use openzeppelin::access::ownable::OwnableComponent;␊ - use openzeppelin::token::erc20::ERC20Component;␊ - use openzeppelin::token::erc20::ERC20HooksEmptyImpl;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ + use openzeppelin::token::erc20::{ERC20Component, ERC20HooksEmptyImpl};␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ - use starknet::ClassHash;␊ - use starknet::ContractAddress;␊ - use starknet::get_caller_address;␊ + 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;␊ #[abi(embed_v0)]␊ impl OwnableMixinImpl = OwnableComponent::OwnableMixinImpl;␊ ␊ + // Internal␊ impl ERC20InternalImpl = ERC20Component::InternalImpl;␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ impl OwnableInternalImpl = OwnableComponent::InternalImpl;␊ @@ -167,14 +171,6 @@ Generated by [AVA](https://avajs.dev). self.erc20.initializer("MyToken", "MTK");␊ self.ownable.initializer(owner);␊ }␊ - ␊ - #[abi(embed_v0)]␊ - impl UpgradeableImpl of IUpgradeable {␊ - fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ - self.ownable.assert_only_owner();␊ - self.upgradeable.upgrade(new_class_hash);␊ - }␊ - }␊ ␊ #[generate_trait]␊ #[abi(per_item)]␊ @@ -184,6 +180,18 @@ Generated by [AVA](https://avajs.dev). self.erc20.burn(get_caller_address(), value);␊ }␊ }␊ + ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ + #[abi(embed_v0)]␊ + impl UpgradeableImpl of IUpgradeable {␊ + fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ + self.ownable.assert_only_owner();␊ + self.upgradeable.upgrade(new_class_hash);␊ + }␊ + }␊ }␊ ` @@ -199,16 +207,16 @@ Generated by [AVA](https://avajs.dev). use openzeppelin::access::ownable::OwnableComponent;␊ use openzeppelin::security::pausable::PausableComponent;␊ use openzeppelin::token::erc20::ERC20Component;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ - use starknet::ClassHash;␊ - use starknet::ContractAddress;␊ + 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;␊ #[abi(embed_v0)]␊ @@ -216,6 +224,7 @@ Generated by [AVA](https://avajs.dev). #[abi(embed_v0)]␊ impl OwnableMixinImpl = OwnableComponent::OwnableMixinImpl;␊ ␊ + // Internal␊ impl ERC20InternalImpl = ERC20Component::InternalImpl;␊ impl PausableInternalImpl = PausableComponent::InternalImpl;␊ impl OwnableInternalImpl = OwnableComponent::InternalImpl;␊ @@ -263,15 +272,7 @@ Generated by [AVA](https://avajs.dev). contract_state.pausable.assert_not_paused();␊ }␊ }␊ - ␊ - #[abi(embed_v0)]␊ - impl UpgradeableImpl of IUpgradeable {␊ - fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ - self.ownable.assert_only_owner();␊ - self.upgradeable.upgrade(new_class_hash);␊ - }␊ - }␊ - ␊ + ␊ #[generate_trait]␊ #[abi(per_item)]␊ impl ExternalImpl of ExternalTrait {␊ @@ -287,6 +288,18 @@ Generated by [AVA](https://avajs.dev). self.pausable.unpause();␊ }␊ }␊ + ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ + #[abi(embed_v0)]␊ + impl UpgradeableImpl of IUpgradeable {␊ + fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ + self.ownable.assert_only_owner();␊ + self.upgradeable.upgrade(new_class_hash);␊ + }␊ + }␊ }␊ ` @@ -302,15 +315,13 @@ Generated by [AVA](https://avajs.dev). ␊ #[starknet::contract]␊ mod MyToken {␊ - use openzeppelin::access::accesscontrol::AccessControlComponent;␊ - use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE;␊ + use openzeppelin::access::accesscontrol::{AccessControlComponent, DEFAULT_ADMIN_ROLE};␊ use openzeppelin::introspection::src5::SRC5Component;␊ use openzeppelin::security::pausable::PausableComponent;␊ use openzeppelin::token::erc20::ERC20Component;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ - use starknet::ClassHash;␊ - use starknet::ContractAddress;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ + use starknet::{ClassHash, ContractAddress};␊ use super::{PAUSER_ROLE, UPGRADER_ROLE};␊ ␊ component!(path: ERC20Component, storage: erc20, event: ERC20Event);␊ @@ -319,6 +330,7 @@ Generated by [AVA](https://avajs.dev). component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl ERC20MixinImpl = ERC20Component::ERC20MixinImpl;␊ #[abi(embed_v0)]␊ @@ -326,6 +338,7 @@ Generated by [AVA](https://avajs.dev). #[abi(embed_v0)]␊ impl AccessControlMixinImpl = AccessControlComponent::AccessControlMixinImpl;␊ ␊ + // Internal␊ impl ERC20InternalImpl = ERC20Component::InternalImpl;␊ impl PausableInternalImpl = PausableComponent::InternalImpl;␊ impl AccessControlInternalImpl = AccessControlComponent::InternalImpl;␊ @@ -386,15 +399,7 @@ Generated by [AVA](https://avajs.dev). contract_state.pausable.assert_not_paused();␊ }␊ }␊ - ␊ - #[abi(embed_v0)]␊ - impl UpgradeableImpl of IUpgradeable {␊ - fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ - self.accesscontrol.assert_only_role(UPGRADER_ROLE);␊ - self.upgradeable.upgrade(new_class_hash);␊ - }␊ - }␊ - ␊ + ␊ #[generate_trait]␊ #[abi(per_item)]␊ impl ExternalImpl of ExternalTrait {␊ @@ -410,6 +415,18 @@ Generated by [AVA](https://avajs.dev). self.pausable.unpause();␊ }␊ }␊ + ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ + #[abi(embed_v0)]␊ + impl UpgradeableImpl of IUpgradeable {␊ + fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ + self.accesscontrol.assert_only_role(UPGRADER_ROLE);␊ + self.upgradeable.upgrade(new_class_hash);␊ + }␊ + }␊ }␊ ` @@ -425,17 +442,16 @@ Generated by [AVA](https://avajs.dev). use openzeppelin::access::ownable::OwnableComponent;␊ use openzeppelin::security::pausable::PausableComponent;␊ use openzeppelin::token::erc20::ERC20Component;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ - use starknet::ClassHash;␊ - use starknet::ContractAddress;␊ - use starknet::get_caller_address;␊ + 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;␊ #[abi(embed_v0)]␊ @@ -443,6 +459,7 @@ Generated by [AVA](https://avajs.dev). #[abi(embed_v0)]␊ impl OwnableMixinImpl = OwnableComponent::OwnableMixinImpl;␊ ␊ + // Internal␊ impl ERC20InternalImpl = ERC20Component::InternalImpl;␊ impl PausableInternalImpl = PausableComponent::InternalImpl;␊ impl OwnableInternalImpl = OwnableComponent::InternalImpl;␊ @@ -490,15 +507,7 @@ Generated by [AVA](https://avajs.dev). contract_state.pausable.assert_not_paused();␊ }␊ }␊ - ␊ - #[abi(embed_v0)]␊ - impl UpgradeableImpl of IUpgradeable {␊ - fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ - self.ownable.assert_only_owner();␊ - self.upgradeable.upgrade(new_class_hash);␊ - }␊ - }␊ - ␊ + ␊ #[generate_trait]␊ #[abi(per_item)]␊ impl ExternalImpl of ExternalTrait {␊ @@ -519,6 +528,18 @@ Generated by [AVA](https://avajs.dev). self.erc20.burn(get_caller_address(), value);␊ }␊ }␊ + ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ + #[abi(embed_v0)]␊ + impl UpgradeableImpl of IUpgradeable {␊ + fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ + self.ownable.assert_only_owner();␊ + self.upgradeable.upgrade(new_class_hash);␊ + }␊ + }␊ }␊ ` @@ -532,22 +553,22 @@ Generated by [AVA](https://avajs.dev). #[starknet::contract]␊ mod MyToken {␊ use openzeppelin::access::ownable::OwnableComponent;␊ - use openzeppelin::token::erc20::ERC20Component;␊ - use openzeppelin::token::erc20::ERC20HooksEmptyImpl;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ + use openzeppelin::token::erc20::{ERC20Component, ERC20HooksEmptyImpl};␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ - use starknet::ClassHash;␊ - use starknet::ContractAddress;␊ + 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;␊ #[abi(embed_v0)]␊ impl OwnableMixinImpl = OwnableComponent::OwnableMixinImpl;␊ ␊ + // Internal␊ impl ERC20InternalImpl = ERC20Component::InternalImpl;␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ impl OwnableInternalImpl = OwnableComponent::InternalImpl;␊ @@ -581,6 +602,10 @@ Generated by [AVA](https://avajs.dev). self.erc20.mint(recipient, 1000000000000000000000);␊ }␊ ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ #[abi(embed_v0)]␊ impl UpgradeableImpl of IUpgradeable {␊ fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ @@ -601,22 +626,22 @@ Generated by [AVA](https://avajs.dev). #[starknet::contract]␊ mod MyToken {␊ use openzeppelin::access::ownable::OwnableComponent;␊ - use openzeppelin::token::erc20::ERC20Component;␊ - use openzeppelin::token::erc20::ERC20HooksEmptyImpl;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ + use openzeppelin::token::erc20::{ERC20Component, ERC20HooksEmptyImpl};␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ - use starknet::ClassHash;␊ - use starknet::ContractAddress;␊ + 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;␊ #[abi(embed_v0)]␊ impl OwnableMixinImpl = OwnableComponent::OwnableMixinImpl;␊ ␊ + // Internal␊ impl ERC20InternalImpl = ERC20Component::InternalImpl;␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ impl OwnableInternalImpl = OwnableComponent::InternalImpl;␊ @@ -648,6 +673,10 @@ Generated by [AVA](https://avajs.dev). self.ownable.initializer(owner);␊ }␊ ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ #[abi(embed_v0)]␊ impl UpgradeableImpl of IUpgradeable {␊ fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ @@ -668,22 +697,22 @@ Generated by [AVA](https://avajs.dev). #[starknet::contract]␊ mod MyToken {␊ use openzeppelin::access::ownable::OwnableComponent;␊ - use openzeppelin::token::erc20::ERC20Component;␊ - use openzeppelin::token::erc20::ERC20HooksEmptyImpl;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ + use openzeppelin::token::erc20::{ERC20Component, ERC20HooksEmptyImpl};␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ - use starknet::ClassHash;␊ - use starknet::ContractAddress;␊ + 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;␊ #[abi(embed_v0)]␊ impl OwnableMixinImpl = OwnableComponent::OwnableMixinImpl;␊ ␊ + // Internal␊ impl ERC20InternalImpl = ERC20Component::InternalImpl;␊ impl OwnableInternalImpl = OwnableComponent::InternalImpl;␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ @@ -714,14 +743,6 @@ Generated by [AVA](https://avajs.dev). self.erc20.initializer("MyToken", "MTK");␊ self.ownable.initializer(owner);␊ }␊ - ␊ - #[abi(embed_v0)]␊ - impl UpgradeableImpl of IUpgradeable {␊ - fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ - self.ownable.assert_only_owner();␊ - self.upgradeable.upgrade(new_class_hash);␊ - }␊ - }␊ ␊ #[generate_trait]␊ #[abi(per_item)]␊ @@ -732,6 +753,18 @@ Generated by [AVA](https://avajs.dev). self.erc20.mint(recipient, amount);␊ }␊ }␊ + ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ + #[abi(embed_v0)]␊ + impl UpgradeableImpl of IUpgradeable {␊ + fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ + self.ownable.assert_only_owner();␊ + self.upgradeable.upgrade(new_class_hash);␊ + }␊ + }␊ }␊ ` @@ -747,15 +780,12 @@ Generated by [AVA](https://avajs.dev). ␊ #[starknet::contract]␊ mod MyToken {␊ - use openzeppelin::access::accesscontrol::AccessControlComponent;␊ - use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE;␊ + use openzeppelin::access::accesscontrol::{AccessControlComponent, DEFAULT_ADMIN_ROLE};␊ use openzeppelin::introspection::src5::SRC5Component;␊ - use openzeppelin::token::erc20::ERC20Component;␊ - use openzeppelin::token::erc20::ERC20HooksEmptyImpl;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ + use openzeppelin::token::erc20::{ERC20Component, ERC20HooksEmptyImpl};␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ - use starknet::ClassHash;␊ - use starknet::ContractAddress;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ + use starknet::{ClassHash, ContractAddress};␊ use super::{MINTER_ROLE, UPGRADER_ROLE};␊ ␊ component!(path: ERC20Component, storage: erc20, event: ERC20Event);␊ @@ -763,11 +793,13 @@ Generated by [AVA](https://avajs.dev). component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl ERC20MixinImpl = ERC20Component::ERC20MixinImpl;␊ #[abi(embed_v0)]␊ impl AccessControlMixinImpl = AccessControlComponent::AccessControlMixinImpl;␊ ␊ + // Internal␊ impl ERC20InternalImpl = ERC20Component::InternalImpl;␊ impl AccessControlInternalImpl = AccessControlComponent::InternalImpl;␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ @@ -811,14 +843,6 @@ Generated by [AVA](https://avajs.dev). self.accesscontrol._grant_role(MINTER_ROLE, minter);␊ self.accesscontrol._grant_role(UPGRADER_ROLE, upgrader);␊ }␊ - ␊ - #[abi(embed_v0)]␊ - impl UpgradeableImpl of IUpgradeable {␊ - fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ - self.accesscontrol.assert_only_role(UPGRADER_ROLE);␊ - self.upgradeable.upgrade(new_class_hash);␊ - }␊ - }␊ ␊ #[generate_trait]␊ #[abi(per_item)]␊ @@ -829,6 +853,18 @@ Generated by [AVA](https://avajs.dev). self.erc20.mint(recipient, amount);␊ }␊ }␊ + ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ + #[abi(embed_v0)]␊ + impl UpgradeableImpl of IUpgradeable {␊ + fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ + self.accesscontrol.assert_only_role(UPGRADER_ROLE);␊ + self.upgradeable.upgrade(new_class_hash);␊ + }␊ + }␊ }␊ ` @@ -844,12 +880,11 @@ Generated by [AVA](https://avajs.dev). use openzeppelin::access::ownable::OwnableComponent;␊ use openzeppelin::governance::votes::VotesComponent;␊ use openzeppelin::token::erc20::ERC20Component;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ use openzeppelin::utils::cryptography::nonces::NoncesComponent;␊ use openzeppelin::utils::cryptography::snip12::SNIP12Metadata;␊ - use starknet::ClassHash;␊ - use starknet::ContractAddress;␊ + use starknet::{ClassHash, ContractAddress};␊ ␊ component!(path: ERC20Component, storage: erc20, event: ERC20Event);␊ component!(path: NoncesComponent, storage: nonces, event: NoncesEvent);␊ @@ -857,6 +892,7 @@ Generated by [AVA](https://avajs.dev). component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl ERC20MixinImpl = ERC20Component::ERC20MixinImpl;␊ #[abi(embed_v0)]␊ @@ -866,6 +902,7 @@ Generated by [AVA](https://avajs.dev). #[abi(embed_v0)]␊ impl OwnableMixinImpl = OwnableComponent::OwnableMixinImpl;␊ ␊ + // Internal␊ impl ERC20InternalImpl = ERC20Component::InternalImpl;␊ impl VotesInternalImpl = VotesComponent::InternalImpl;␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ @@ -905,16 +942,6 @@ Generated by [AVA](https://avajs.dev). self.erc20.initializer("MyToken", "MTK");␊ self.ownable.initializer(owner);␊ }␊ - ␊ - impl SNIP12MetadataImpl of SNIP12Metadata {␊ - fn name() -> felt252 {␊ - 'MY_DAPP_NAME'␊ - }␊ - ␊ - fn version() -> felt252 {␊ - 'v1'␊ - }␊ - }␊ ␊ impl ERC20HooksImpl of ERC20Component::ERC20HooksTrait {␊ fn after_update(␊ @@ -928,6 +955,24 @@ Generated by [AVA](https://avajs.dev). }␊ }␊ ␊ + //␊ + // SNIP12 Metadata␊ + //␊ + ␊ + impl SNIP12MetadataImpl of SNIP12Metadata {␊ + fn name() -> felt252 {␊ + 'MY_DAPP_NAME'␊ + }␊ + ␊ + fn version() -> felt252 {␊ + 'v1'␊ + }␊ + }␊ + ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ #[abi(embed_v0)]␊ impl UpgradeableImpl of IUpgradeable {␊ fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ @@ -950,12 +995,11 @@ Generated by [AVA](https://avajs.dev). use openzeppelin::access::ownable::OwnableComponent;␊ use openzeppelin::governance::votes::VotesComponent;␊ use openzeppelin::token::erc20::ERC20Component;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ use openzeppelin::utils::cryptography::nonces::NoncesComponent;␊ use openzeppelin::utils::cryptography::snip12::SNIP12Metadata;␊ - use starknet::ClassHash;␊ - use starknet::ContractAddress;␊ + use starknet::{ClassHash, ContractAddress};␊ ␊ component!(path: ERC20Component, storage: erc20, event: ERC20Event);␊ component!(path: NoncesComponent, storage: nonces, event: NoncesEvent);␊ @@ -963,6 +1007,7 @@ Generated by [AVA](https://avajs.dev). component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl ERC20MixinImpl = ERC20Component::ERC20MixinImpl;␊ #[abi(embed_v0)]␊ @@ -972,6 +1017,7 @@ Generated by [AVA](https://avajs.dev). #[abi(embed_v0)]␊ impl OwnableMixinImpl = OwnableComponent::OwnableMixinImpl;␊ ␊ + // Internal␊ impl ERC20InternalImpl = ERC20Component::InternalImpl;␊ impl VotesInternalImpl = VotesComponent::InternalImpl;␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ @@ -1011,16 +1057,6 @@ Generated by [AVA](https://avajs.dev). self.erc20.initializer("MyToken", "MTK");␊ self.ownable.initializer(owner);␊ }␊ - ␊ - impl SNIP12MetadataImpl of SNIP12Metadata {␊ - fn name() -> felt252 {␊ - 'MY_DAPP_NAME'␊ - }␊ - ␊ - fn version() -> felt252 {␊ - 'MY_DAPP_VERSION'␊ - }␊ - }␊ ␊ impl ERC20HooksImpl of ERC20Component::ERC20HooksTrait {␊ fn after_update(␊ @@ -1034,6 +1070,24 @@ Generated by [AVA](https://avajs.dev). }␊ }␊ ␊ + //␊ + // 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 {␊ fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ @@ -1062,6 +1116,7 @@ Generated by [AVA](https://avajs.dev). component!(path: NoncesComponent, storage: nonces, event: NoncesEvent);␊ component!(path: VotesComponent, storage: votes, event: VotesEvent);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl ERC20MixinImpl = ERC20Component::ERC20MixinImpl;␊ #[abi(embed_v0)]␊ @@ -1069,6 +1124,7 @@ Generated by [AVA](https://avajs.dev). #[abi(embed_v0)]␊ impl VotesImpl = VotesComponent::VotesImpl;␊ ␊ + // Internal␊ impl ERC20InternalImpl = ERC20Component::InternalImpl;␊ impl VotesInternalImpl = VotesComponent::InternalImpl;␊ ␊ @@ -1097,16 +1153,6 @@ Generated by [AVA](https://avajs.dev). fn constructor(ref self: ContractState) {␊ self.erc20.initializer("MyToken", "MTK");␊ }␊ - ␊ - impl SNIP12MetadataImpl of SNIP12Metadata {␊ - fn name() -> felt252 {␊ - 'MY_DAPP_NAME'␊ - }␊ - ␊ - fn version() -> felt252 {␊ - 'v1'␊ - }␊ - }␊ ␊ impl ERC20HooksImpl of ERC20Component::ERC20HooksTrait {␊ fn after_update(␊ @@ -1119,6 +1165,20 @@ Generated by [AVA](https://avajs.dev). 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'␊ + }␊ + }␊ }␊ ` @@ -1137,8 +1197,7 @@ Generated by [AVA](https://avajs.dev). use openzeppelin::token::erc20::ERC20Component;␊ use openzeppelin::utils::cryptography::nonces::NoncesComponent;␊ use openzeppelin::utils::cryptography::snip12::SNIP12Metadata;␊ - use starknet::ContractAddress;␊ - use starknet::get_caller_address;␊ + use starknet::{ContractAddress, get_caller_address};␊ ␊ component!(path: ERC20Component, storage: erc20, event: ERC20Event);␊ component!(path: PausableComponent, storage: pausable, event: PausableEvent);␊ @@ -1146,6 +1205,7 @@ Generated by [AVA](https://avajs.dev). component!(path: NoncesComponent, storage: nonces, event: NoncesEvent);␊ component!(path: VotesComponent, storage: votes, event: VotesEvent);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl ERC20MixinImpl = ERC20Component::ERC20MixinImpl;␊ #[abi(embed_v0)]␊ @@ -1157,6 +1217,7 @@ Generated by [AVA](https://avajs.dev). #[abi(embed_v0)]␊ impl VotesImpl = VotesComponent::VotesImpl;␊ ␊ + // Internal␊ impl ERC20InternalImpl = ERC20Component::InternalImpl;␊ impl PausableInternalImpl = PausableComponent::InternalImpl;␊ impl OwnableInternalImpl = OwnableComponent::InternalImpl;␊ @@ -1198,16 +1259,6 @@ Generated by [AVA](https://avajs.dev). ␊ self.erc20.mint(recipient, 2000000000000000000000);␊ }␊ - ␊ - impl SNIP12MetadataImpl of SNIP12Metadata {␊ - fn name() -> felt252 {␊ - 'MY_DAPP_NAME'␊ - }␊ - ␊ - fn version() -> felt252 {␊ - 'MY_DAPP_VERSION'␊ - }␊ - }␊ ␊ impl ERC20HooksImpl of ERC20Component::ERC20HooksTrait {␊ fn before_update(␊ @@ -1230,7 +1281,7 @@ Generated by [AVA](https://avajs.dev). contract_state.votes.transfer_voting_units(from, recipient, amount);␊ }␊ }␊ - ␊ + ␊ #[generate_trait]␊ #[abi(per_item)]␊ impl ExternalImpl of ExternalTrait {␊ @@ -1257,6 +1308,20 @@ Generated by [AVA](https://avajs.dev). self.erc20.mint(recipient, amount);␊ }␊ }␊ + ␊ + //␊ + // SNIP12 Metadata␊ + //␊ + ␊ + impl SNIP12MetadataImpl of SNIP12Metadata {␊ + fn name() -> felt252 {␊ + 'MY_DAPP_NAME'␊ + }␊ + ␊ + fn version() -> felt252 {␊ + 'MY_DAPP_VERSION'␊ + }␊ + }␊ }␊ ` @@ -1273,13 +1338,11 @@ Generated by [AVA](https://avajs.dev). use openzeppelin::governance::votes::VotesComponent;␊ use openzeppelin::security::pausable::PausableComponent;␊ use openzeppelin::token::erc20::ERC20Component;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ use openzeppelin::utils::cryptography::nonces::NoncesComponent;␊ use openzeppelin::utils::cryptography::snip12::SNIP12Metadata;␊ - use starknet::ClassHash;␊ - use starknet::ContractAddress;␊ - use starknet::get_caller_address;␊ + use starknet::{ClassHash, ContractAddress, get_caller_address};␊ ␊ component!(path: ERC20Component, storage: erc20, event: ERC20Event);␊ component!(path: PausableComponent, storage: pausable, event: PausableEvent);␊ @@ -1288,6 +1351,7 @@ Generated by [AVA](https://avajs.dev). component!(path: VotesComponent, storage: votes, event: VotesEvent);␊ component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl ERC20MixinImpl = ERC20Component::ERC20MixinImpl;␊ #[abi(embed_v0)]␊ @@ -1299,6 +1363,7 @@ Generated by [AVA](https://avajs.dev). #[abi(embed_v0)]␊ impl VotesImpl = VotesComponent::VotesImpl;␊ ␊ + // Internal␊ impl ERC20InternalImpl = ERC20Component::InternalImpl;␊ impl PausableInternalImpl = PausableComponent::InternalImpl;␊ impl OwnableInternalImpl = OwnableComponent::InternalImpl;␊ @@ -1345,16 +1410,6 @@ Generated by [AVA](https://avajs.dev). ␊ self.erc20.mint(recipient, 2000000000000000000000);␊ }␊ - ␊ - impl SNIP12MetadataImpl of SNIP12Metadata {␊ - fn name() -> felt252 {␊ - 'MY_DAPP_NAME'␊ - }␊ - ␊ - fn version() -> felt252 {␊ - 'MY_DAPP_VERSION'␊ - }␊ - }␊ ␊ impl ERC20HooksImpl of ERC20Component::ERC20HooksTrait {␊ fn before_update(␊ @@ -1377,15 +1432,7 @@ Generated by [AVA](https://avajs.dev). contract_state.votes.transfer_voting_units(from, recipient, amount);␊ }␊ }␊ - ␊ - #[abi(embed_v0)]␊ - impl UpgradeableImpl of IUpgradeable {␊ - fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ - self.ownable.assert_only_owner();␊ - self.upgradeable.upgrade(new_class_hash);␊ - }␊ - }␊ - ␊ + ␊ #[generate_trait]␊ #[abi(per_item)]␊ impl ExternalImpl of ExternalTrait {␊ @@ -1412,6 +1459,32 @@ Generated by [AVA](https://avajs.dev). 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 {␊ + fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ + self.ownable.assert_only_owner();␊ + self.upgradeable.upgrade(new_class_hash);␊ + }␊ + }␊ }␊ ` @@ -1428,20 +1501,17 @@ Generated by [AVA](https://avajs.dev). ␊ #[starknet::contract]␊ mod MyToken {␊ - use openzeppelin::access::accesscontrol::AccessControlComponent;␊ - use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE;␊ + 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::ERC20Component;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ use openzeppelin::utils::cryptography::nonces::NoncesComponent;␊ use openzeppelin::utils::cryptography::snip12::SNIP12Metadata;␊ - use starknet::ClassHash;␊ - use starknet::ContractAddress;␊ - use starknet::get_caller_address;␊ - use super::{PAUSER_ROLE, MINTER_ROLE, UPGRADER_ROLE};␊ + 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);␊ @@ -1451,6 +1521,7 @@ Generated by [AVA](https://avajs.dev). component!(path: VotesComponent, storage: votes, event: VotesEvent);␊ component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl ERC20MixinImpl = ERC20Component::ERC20MixinImpl;␊ #[abi(embed_v0)]␊ @@ -1462,6 +1533,7 @@ Generated by [AVA](https://avajs.dev). #[abi(embed_v0)]␊ impl VotesImpl = VotesComponent::VotesImpl;␊ ␊ + // Internal␊ impl ERC20InternalImpl = ERC20Component::InternalImpl;␊ impl PausableInternalImpl = PausableComponent::InternalImpl;␊ impl AccessControlInternalImpl = AccessControlComponent::InternalImpl;␊ @@ -1523,16 +1595,6 @@ Generated by [AVA](https://avajs.dev). self.accesscontrol._grant_role(MINTER_ROLE, minter);␊ self.accesscontrol._grant_role(UPGRADER_ROLE, upgrader);␊ }␊ - ␊ - impl SNIP12MetadataImpl of SNIP12Metadata {␊ - fn name() -> felt252 {␊ - 'MY_DAPP_NAME'␊ - }␊ - ␊ - fn version() -> felt252 {␊ - 'MY_DAPP_VERSION'␊ - }␊ - }␊ ␊ impl ERC20HooksImpl of ERC20Component::ERC20HooksTrait {␊ fn before_update(␊ @@ -1555,15 +1617,7 @@ Generated by [AVA](https://avajs.dev). contract_state.votes.transfer_voting_units(from, recipient, amount);␊ }␊ }␊ - ␊ - #[abi(embed_v0)]␊ - impl UpgradeableImpl of IUpgradeable {␊ - fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ - self.accesscontrol.assert_only_role(UPGRADER_ROLE);␊ - self.upgradeable.upgrade(new_class_hash);␊ - }␊ - }␊ - ␊ + ␊ #[generate_trait]␊ #[abi(per_item)]␊ impl ExternalImpl of ExternalTrait {␊ @@ -1590,5 +1644,31 @@ Generated by [AVA](https://avajs.dev). 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 {␊ + fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ + self.accesscontrol.assert_only_role(UPGRADER_ROLE);␊ + self.upgradeable.upgrade(new_class_hash);␊ + }␊ + }␊ }␊ ` diff --git a/packages/core-cairo/src/erc20.test.ts.snap b/packages/core-cairo/src/erc20.test.ts.snap index caabfc5a..42e96309 100644 Binary files a/packages/core-cairo/src/erc20.test.ts.snap and b/packages/core-cairo/src/erc20.test.ts.snap differ diff --git a/packages/core-cairo/src/erc20.ts b/packages/core-cairo/src/erc20.ts index 6e4a349e..57cfe8d8 100644 --- a/packages/core-cairo/src/erc20.ts +++ b/packages/core-cairo/src/erc20.ts @@ -138,7 +138,12 @@ function addHooks(c: ContractBuilder, allOpts: Required) { }); } - addVotesComponent(c, toFelt252(allOpts.appName, 'appName'), toFelt252(allOpts.appVersion, 'appVersion')); + addVotesComponent( + c, + toFelt252(allOpts.appName, 'appName'), + toFelt252(allOpts.appVersion, 'appVersion'), + 'SNIP12 Metadata', + ); const afterUpdateFn = c.addFunction(hooksTrait, { name: 'after_update', @@ -157,7 +162,7 @@ function addHooks(c: ContractBuilder, allOpts: Required) { ); } } else { - c.addStandaloneImport('openzeppelin::token::erc20::ERC20HooksEmptyImpl'); + c.addUseClause('openzeppelin::token::erc20', 'ERC20HooksEmptyImpl'); } } @@ -179,7 +184,7 @@ function addBase(c: ContractBuilder, name: string, symbol: string) { } function addBurnable(c: ContractBuilder) { - c.addStandaloneImport('starknet::get_caller_address'); + c.addUseClause('starknet', 'get_caller_address'); c.addFunction(externalTrait, functions.burn); } @@ -195,7 +200,7 @@ function addPremint(c: ContractBuilder, amount: string) { const premintAbsolute = toUint(getInitialSupply(amount, 18), 'premint', 'u256'); - c.addStandaloneImport('starknet::ContractAddress'); + c.addUseClause('starknet', 'ContractAddress'); c.addConstructorArgument({ name:'recipient', type:'ContractAddress' }); c.addConstructorCode(`self.erc20.mint(recipient, ${premintAbsolute})`); } @@ -203,7 +208,7 @@ function addPremint(c: ContractBuilder, amount: string) { /** * Calculates the initial supply that would be used in an ERC20 contract based on a given premint amount and number of decimals. - * + * * @param premint Premint amount in token units, may be fractional * @param decimals The number of decimals in the token * @returns `premint` with zeros padded or removed based on `decimals`. @@ -243,7 +248,7 @@ export function getInitialSupply(premint: string, decimals: number): string { } function addMintable(c: ContractBuilder, access: Access) { - c.addStandaloneImport('starknet::ContractAddress'); + c.addUseClause('starknet', 'ContractAddress'); requireAccessControl(c, externalTrait, functions.mint, access, 'MINTER', 'minter'); } @@ -258,11 +263,11 @@ const components = defineComponents( { name: 'ERC20Event', type: 'ERC20Component::Event', }, - impls: [], - internalImpl: { + impls: [{ name: 'ERC20InternalImpl', + embed: false, value: 'ERC20Component::InternalImpl', - }, + }], }, }); diff --git a/packages/core-cairo/src/erc721.test.ts.md b/packages/core-cairo/src/erc721.test.ts.md index b7bc574b..2006fd86 100644 --- a/packages/core-cairo/src/erc721.test.ts.md +++ b/packages/core-cairo/src/erc721.test.ts.md @@ -14,15 +14,16 @@ Generated by [AVA](https://avajs.dev). #[starknet::contract]␊ mod MyToken {␊ use openzeppelin::introspection::src5::SRC5Component;␊ - use openzeppelin::token::erc721::ERC721Component;␊ - use openzeppelin::token::erc721::ERC721HooksEmptyImpl;␊ + use openzeppelin::token::erc721::{ERC721Component, ERC721HooksEmptyImpl};␊ ␊ component!(path: ERC721Component, storage: erc721, event: ERC721Event);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl ERC721MixinImpl = ERC721Component::ERC721MixinImpl;␊ ␊ + // Internal␊ impl ERC721InternalImpl = ERC721Component::InternalImpl;␊ ␊ #[storage]␊ @@ -60,23 +61,23 @@ Generated by [AVA](https://avajs.dev). mod MyToken {␊ use openzeppelin::access::ownable::OwnableComponent;␊ use openzeppelin::introspection::src5::SRC5Component;␊ - use openzeppelin::token::erc721::ERC721Component;␊ - use openzeppelin::token::erc721::ERC721HooksEmptyImpl;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ + use openzeppelin::token::erc721::{ERC721Component, ERC721HooksEmptyImpl};␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ - use starknet::ClassHash;␊ - use starknet::ContractAddress;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ + use starknet::{ClassHash, ContractAddress};␊ ␊ component!(path: ERC721Component, storage: erc721, event: ERC721Event);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl ERC721MixinImpl = ERC721Component::ERC721MixinImpl;␊ #[abi(embed_v0)]␊ impl OwnableMixinImpl = OwnableComponent::OwnableMixinImpl;␊ ␊ + // Internal␊ impl ERC721InternalImpl = ERC721Component::InternalImpl;␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ impl OwnableInternalImpl = OwnableComponent::InternalImpl;␊ @@ -112,6 +113,10 @@ Generated by [AVA](https://avajs.dev). self.ownable.initializer(owner);␊ }␊ ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ #[abi(embed_v0)]␊ impl UpgradeableImpl of IUpgradeable {␊ fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ @@ -133,23 +138,23 @@ Generated by [AVA](https://avajs.dev). mod MyToken {␊ use openzeppelin::access::ownable::OwnableComponent;␊ use openzeppelin::introspection::src5::SRC5Component;␊ - use openzeppelin::token::erc721::ERC721Component;␊ - use openzeppelin::token::erc721::ERC721HooksEmptyImpl;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ + use openzeppelin::token::erc721::{ERC721Component, ERC721HooksEmptyImpl};␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ - use starknet::ClassHash;␊ - use starknet::ContractAddress;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ + use starknet::{ClassHash, ContractAddress};␊ ␊ component!(path: ERC721Component, storage: erc721, event: ERC721Event);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl ERC721MixinImpl = ERC721Component::ERC721MixinImpl;␊ #[abi(embed_v0)]␊ impl OwnableMixinImpl = OwnableComponent::OwnableMixinImpl;␊ ␊ + // Internal␊ impl ERC721InternalImpl = ERC721Component::InternalImpl;␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ impl OwnableInternalImpl = OwnableComponent::InternalImpl;␊ @@ -185,6 +190,10 @@ Generated by [AVA](https://avajs.dev). self.ownable.initializer(owner);␊ }␊ ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ #[abi(embed_v0)]␊ impl UpgradeableImpl of IUpgradeable {␊ fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ @@ -207,24 +216,23 @@ Generated by [AVA](https://avajs.dev). use core::num::traits::Zero;␊ use openzeppelin::access::ownable::OwnableComponent;␊ use openzeppelin::introspection::src5::SRC5Component;␊ - use openzeppelin::token::erc721::ERC721Component;␊ - use openzeppelin::token::erc721::ERC721HooksEmptyImpl;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ + use openzeppelin::token::erc721::{ERC721Component, ERC721HooksEmptyImpl};␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ - use starknet::ClassHash;␊ - use starknet::ContractAddress;␊ - use starknet::get_caller_address;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ + use starknet::{ClassHash, ContractAddress, get_caller_address};␊ ␊ component!(path: ERC721Component, storage: erc721, event: ERC721Event);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl ERC721MixinImpl = ERC721Component::ERC721MixinImpl;␊ #[abi(embed_v0)]␊ impl OwnableMixinImpl = OwnableComponent::OwnableMixinImpl;␊ ␊ + // Internal␊ impl ERC721InternalImpl = ERC721Component::InternalImpl;␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ impl OwnableInternalImpl = OwnableComponent::InternalImpl;␊ @@ -259,14 +267,6 @@ Generated by [AVA](https://avajs.dev). self.erc721.initializer("MyToken", "MTK", "");␊ self.ownable.initializer(owner);␊ }␊ - ␊ - #[abi(embed_v0)]␊ - impl UpgradeableImpl of IUpgradeable {␊ - fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ - self.ownable.assert_only_owner();␊ - self.upgradeable.upgrade(new_class_hash);␊ - }␊ - }␊ ␊ #[generate_trait]␊ #[abi(per_item)]␊ @@ -276,6 +276,18 @@ Generated by [AVA](https://avajs.dev). self.erc721.update(Zero::zero(), token_id, get_caller_address());␊ }␊ }␊ + ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ + #[abi(embed_v0)]␊ + impl UpgradeableImpl of IUpgradeable {␊ + fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ + self.ownable.assert_only_owner();␊ + self.upgradeable.upgrade(new_class_hash);␊ + }␊ + }␊ }␊ ` @@ -292,10 +304,9 @@ Generated by [AVA](https://avajs.dev). use openzeppelin::introspection::src5::SRC5Component;␊ use openzeppelin::security::pausable::PausableComponent;␊ use openzeppelin::token::erc721::ERC721Component;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ - use starknet::ClassHash;␊ - use starknet::ContractAddress;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ + use starknet::{ClassHash, ContractAddress};␊ ␊ component!(path: ERC721Component, storage: erc721, event: ERC721Event);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ @@ -303,6 +314,7 @@ Generated by [AVA](https://avajs.dev). component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);␊ component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl ERC721MixinImpl = ERC721Component::ERC721MixinImpl;␊ #[abi(embed_v0)]␊ @@ -310,6 +322,7 @@ Generated by [AVA](https://avajs.dev). #[abi(embed_v0)]␊ impl OwnableMixinImpl = OwnableComponent::OwnableMixinImpl;␊ ␊ + // Internal␊ impl ERC721InternalImpl = ERC721Component::InternalImpl;␊ impl PausableInternalImpl = PausableComponent::InternalImpl;␊ impl OwnableInternalImpl = OwnableComponent::InternalImpl;␊ @@ -361,15 +374,7 @@ Generated by [AVA](https://avajs.dev). contract_state.pausable.assert_not_paused();␊ }␊ }␊ - ␊ - #[abi(embed_v0)]␊ - impl UpgradeableImpl of IUpgradeable {␊ - fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ - self.ownable.assert_only_owner();␊ - self.upgradeable.upgrade(new_class_hash);␊ - }␊ - }␊ - ␊ + ␊ #[generate_trait]␊ #[abi(per_item)]␊ impl ExternalImpl of ExternalTrait {␊ @@ -385,6 +390,18 @@ Generated by [AVA](https://avajs.dev). self.pausable.unpause();␊ }␊ }␊ + ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ + #[abi(embed_v0)]␊ + impl UpgradeableImpl of IUpgradeable {␊ + fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ + self.ownable.assert_only_owner();␊ + self.upgradeable.upgrade(new_class_hash);␊ + }␊ + }␊ }␊ ` @@ -399,23 +416,23 @@ Generated by [AVA](https://avajs.dev). mod MyToken {␊ use openzeppelin::access::ownable::OwnableComponent;␊ use openzeppelin::introspection::src5::SRC5Component;␊ - use openzeppelin::token::erc721::ERC721Component;␊ - use openzeppelin::token::erc721::ERC721HooksEmptyImpl;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ + use openzeppelin::token::erc721::{ERC721Component, ERC721HooksEmptyImpl};␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ - use starknet::ClassHash;␊ - use starknet::ContractAddress;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ + use starknet::{ClassHash, ContractAddress};␊ ␊ component!(path: ERC721Component, storage: erc721, event: ERC721Event);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);␊ component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl ERC721MixinImpl = ERC721Component::ERC721MixinImpl;␊ #[abi(embed_v0)]␊ impl OwnableMixinImpl = OwnableComponent::OwnableMixinImpl;␊ ␊ + // Internal␊ impl ERC721InternalImpl = ERC721Component::InternalImpl;␊ impl OwnableInternalImpl = OwnableComponent::InternalImpl;␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ @@ -450,14 +467,6 @@ Generated by [AVA](https://avajs.dev). self.erc721.initializer("MyToken", "MTK", "");␊ self.ownable.initializer(owner);␊ }␊ - ␊ - #[abi(embed_v0)]␊ - impl UpgradeableImpl of IUpgradeable {␊ - fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ - self.ownable.assert_only_owner();␊ - self.upgradeable.upgrade(new_class_hash);␊ - }␊ - }␊ ␊ #[generate_trait]␊ #[abi(per_item)]␊ @@ -483,6 +492,18 @@ Generated by [AVA](https://avajs.dev). self.safe_mint(recipient, tokenId, data);␊ }␊ }␊ + ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ + #[abi(embed_v0)]␊ + impl UpgradeableImpl of IUpgradeable {␊ + fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ + self.ownable.assert_only_owner();␊ + self.upgradeable.upgrade(new_class_hash);␊ + }␊ + }␊ }␊ ` @@ -499,10 +520,9 @@ Generated by [AVA](https://avajs.dev). use openzeppelin::introspection::src5::SRC5Component;␊ use openzeppelin::token::erc721::ERC721Component;␊ use openzeppelin::token::erc721::extensions::ERC721EnumerableComponent;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ - use starknet::ClassHash;␊ - use starknet::ContractAddress;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ + use starknet::{ClassHash, ContractAddress};␊ ␊ component!(path: ERC721Component, storage: erc721, event: ERC721Event);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ @@ -510,6 +530,7 @@ Generated by [AVA](https://avajs.dev). component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl ERC721MixinImpl = ERC721Component::ERC721MixinImpl;␊ #[abi(embed_v0)]␊ @@ -517,6 +538,7 @@ Generated by [AVA](https://avajs.dev). #[abi(embed_v0)]␊ impl OwnableMixinImpl = OwnableComponent::OwnableMixinImpl;␊ ␊ + // Internal␊ impl ERC721InternalImpl = ERC721Component::InternalImpl;␊ impl ERC721EnumerableInternalImpl = ERC721EnumerableComponent::InternalImpl;␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ @@ -570,6 +592,10 @@ Generated by [AVA](https://avajs.dev). }␊ }␊ ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ #[abi(embed_v0)]␊ impl UpgradeableImpl of IUpgradeable {␊ fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ @@ -594,10 +620,9 @@ Generated by [AVA](https://avajs.dev). use openzeppelin::security::pausable::PausableComponent;␊ use openzeppelin::token::erc721::ERC721Component;␊ use openzeppelin::token::erc721::extensions::ERC721EnumerableComponent;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ - use starknet::ClassHash;␊ - use starknet::ContractAddress;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ + use starknet::{ClassHash, ContractAddress};␊ ␊ component!(path: ERC721Component, storage: erc721, event: ERC721Event);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ @@ -606,6 +631,7 @@ Generated by [AVA](https://avajs.dev). component!(path: ERC721EnumerableComponent, storage: erc721_enumerable, event: ERC721EnumerableEvent);␊ component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl ERC721MixinImpl = ERC721Component::ERC721MixinImpl;␊ #[abi(embed_v0)]␊ @@ -615,6 +641,7 @@ Generated by [AVA](https://avajs.dev). #[abi(embed_v0)]␊ impl ERC721EnumerableImpl = ERC721EnumerableComponent::ERC721EnumerableImpl;␊ ␊ + // Internal␊ impl ERC721InternalImpl = ERC721Component::InternalImpl;␊ impl PausableInternalImpl = PausableComponent::InternalImpl;␊ impl OwnableInternalImpl = OwnableComponent::InternalImpl;␊ @@ -673,15 +700,7 @@ Generated by [AVA](https://avajs.dev). contract_state.erc721_enumerable.before_update(to, token_id);␊ }␊ }␊ - ␊ - #[abi(embed_v0)]␊ - impl UpgradeableImpl of IUpgradeable {␊ - fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ - self.ownable.assert_only_owner();␊ - self.upgradeable.upgrade(new_class_hash);␊ - }␊ - }␊ - ␊ + ␊ #[generate_trait]␊ #[abi(per_item)]␊ impl ExternalImpl of ExternalTrait {␊ @@ -697,6 +716,18 @@ Generated by [AVA](https://avajs.dev). self.pausable.unpause();␊ }␊ }␊ + ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ + #[abi(embed_v0)]␊ + impl UpgradeableImpl of IUpgradeable {␊ + fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ + self.ownable.assert_only_owner();␊ + self.upgradeable.upgrade(new_class_hash);␊ + }␊ + }␊ }␊ ` @@ -712,15 +743,12 @@ Generated by [AVA](https://avajs.dev). ␊ #[starknet::contract]␊ mod MyToken {␊ - use openzeppelin::access::accesscontrol::AccessControlComponent;␊ - use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE;␊ + use openzeppelin::access::accesscontrol::{AccessControlComponent, DEFAULT_ADMIN_ROLE};␊ use openzeppelin::introspection::src5::SRC5Component;␊ - use openzeppelin::token::erc721::ERC721Component;␊ - use openzeppelin::token::erc721::ERC721HooksEmptyImpl;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ + use openzeppelin::token::erc721::{ERC721Component, ERC721HooksEmptyImpl};␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ - use starknet::ClassHash;␊ - use starknet::ContractAddress;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ + use starknet::{ClassHash, ContractAddress};␊ use super::{MINTER_ROLE, UPGRADER_ROLE};␊ ␊ component!(path: ERC721Component, storage: erc721, event: ERC721Event);␊ @@ -728,6 +756,7 @@ Generated by [AVA](https://avajs.dev). component!(path: AccessControlComponent, storage: accesscontrol, event: AccessControlEvent);␊ component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl ERC721MixinImpl = ERC721Component::ERC721MixinImpl;␊ #[abi(embed_v0)]␊ @@ -735,6 +764,7 @@ Generated by [AVA](https://avajs.dev). #[abi(embed_v0)]␊ impl AccessControlCamelImpl = AccessControlComponent::AccessControlCamelImpl;␊ ␊ + // Internal␊ impl ERC721InternalImpl = ERC721Component::InternalImpl;␊ impl AccessControlInternalImpl = AccessControlComponent::InternalImpl;␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ @@ -778,14 +808,6 @@ Generated by [AVA](https://avajs.dev). self.accesscontrol._grant_role(MINTER_ROLE, minter);␊ self.accesscontrol._grant_role(UPGRADER_ROLE, upgrader);␊ }␊ - ␊ - #[abi(embed_v0)]␊ - impl UpgradeableImpl of IUpgradeable {␊ - fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ - self.accesscontrol.assert_only_role(UPGRADER_ROLE);␊ - self.upgradeable.upgrade(new_class_hash);␊ - }␊ - }␊ ␊ #[generate_trait]␊ #[abi(per_item)]␊ @@ -811,6 +833,18 @@ Generated by [AVA](https://avajs.dev). self.safe_mint(recipient, tokenId, data);␊ }␊ }␊ + ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ + #[abi(embed_v0)]␊ + impl UpgradeableImpl of IUpgradeable {␊ + fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ + self.accesscontrol.assert_only_role(UPGRADER_ROLE);␊ + self.upgradeable.upgrade(new_class_hash);␊ + }␊ + }␊ }␊ ` @@ -825,23 +859,23 @@ Generated by [AVA](https://avajs.dev). mod MyToken {␊ use openzeppelin::access::ownable::OwnableComponent;␊ use openzeppelin::introspection::src5::SRC5Component;␊ - use openzeppelin::token::erc721::ERC721Component;␊ - use openzeppelin::token::erc721::ERC721HooksEmptyImpl;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ + use openzeppelin::token::erc721::{ERC721Component, ERC721HooksEmptyImpl};␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ - use starknet::ClassHash;␊ - use starknet::ContractAddress;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ + use starknet::{ClassHash, ContractAddress};␊ ␊ component!(path: ERC721Component, storage: erc721, event: ERC721Event);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl ERC721MixinImpl = ERC721Component::ERC721MixinImpl;␊ #[abi(embed_v0)]␊ impl OwnableMixinImpl = OwnableComponent::OwnableMixinImpl;␊ ␊ + // Internal␊ impl ERC721InternalImpl = ERC721Component::InternalImpl;␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ impl OwnableInternalImpl = OwnableComponent::InternalImpl;␊ @@ -877,6 +911,10 @@ Generated by [AVA](https://avajs.dev). self.ownable.initializer(owner);␊ }␊ ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ #[abi(embed_v0)]␊ impl UpgradeableImpl of IUpgradeable {␊ fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ @@ -898,14 +936,11 @@ Generated by [AVA](https://avajs.dev). mod MyToken {␊ use openzeppelin::access::ownable::OwnableComponent;␊ use openzeppelin::introspection::src5::SRC5Component;␊ - use openzeppelin::token::common::erc2981::DefaultConfig;␊ - use openzeppelin::token::common::erc2981::ERC2981Component;␊ - use openzeppelin::token::erc721::ERC721Component;␊ - use openzeppelin::token::erc721::ERC721HooksEmptyImpl;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ + use openzeppelin::token::common::erc2981::{DefaultConfig, ERC2981Component};␊ + use openzeppelin::token::erc721::{ERC721Component, ERC721HooksEmptyImpl};␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ - use starknet::ClassHash;␊ - use starknet::ContractAddress;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ + use starknet::{ClassHash, ContractAddress};␊ ␊ component!(path: ERC721Component, storage: erc721, event: ERC721Event);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ @@ -913,6 +948,7 @@ Generated by [AVA](https://avajs.dev). component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ component!(path: ERC2981Component, storage: erc2981, event: ERC2981Event);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl ERC721MixinImpl = ERC721Component::ERC721MixinImpl;␊ #[abi(embed_v0)]␊ @@ -924,6 +960,7 @@ Generated by [AVA](https://avajs.dev). #[abi(embed_v0)]␊ impl ERC2981AdminOwnableImpl = ERC2981Component::ERC2981AdminOwnableImpl;␊ ␊ + // Internal␊ impl ERC721InternalImpl = ERC721Component::InternalImpl;␊ impl OwnableInternalImpl = OwnableComponent::InternalImpl;␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ @@ -969,6 +1006,10 @@ Generated by [AVA](https://avajs.dev). self.erc2981.initializer(default_royalty_receiver, 500);␊ }␊ ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ #[abi(embed_v0)]␊ impl UpgradeableImpl of IUpgradeable {␊ fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ @@ -990,17 +1031,13 @@ Generated by [AVA](https://avajs.dev). ␊ #[starknet::contract]␊ mod MyToken {␊ - use openzeppelin::access::accesscontrol::AccessControlComponent;␊ - use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE;␊ + use openzeppelin::access::accesscontrol::{AccessControlComponent, DEFAULT_ADMIN_ROLE};␊ use openzeppelin::introspection::src5::SRC5Component;␊ - use openzeppelin::token::common::erc2981::DefaultConfig;␊ - use openzeppelin::token::common::erc2981::ERC2981Component;␊ - use openzeppelin::token::erc721::ERC721Component;␊ - use openzeppelin::token::erc721::ERC721HooksEmptyImpl;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ + use openzeppelin::token::common::erc2981::{DefaultConfig, ERC2981Component};␊ + use openzeppelin::token::erc721::{ERC721Component, ERC721HooksEmptyImpl};␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ - use starknet::ClassHash;␊ - use starknet::ContractAddress;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ + use starknet::{ClassHash, ContractAddress};␊ use super::UPGRADER_ROLE;␊ ␊ component!(path: ERC721Component, storage: erc721, event: ERC721Event);␊ @@ -1009,6 +1046,7 @@ Generated by [AVA](https://avajs.dev). component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ component!(path: ERC2981Component, storage: erc2981, event: ERC2981Event);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl ERC721MixinImpl = ERC721Component::ERC721MixinImpl;␊ #[abi(embed_v0)]␊ @@ -1022,6 +1060,7 @@ Generated by [AVA](https://avajs.dev). #[abi(embed_v0)]␊ impl ERC2981AdminAccessControlImpl = ERC2981Component::ERC2981AdminAccessControlImpl;␊ ␊ + // Internal␊ impl ERC721InternalImpl = ERC721Component::InternalImpl;␊ impl AccessControlInternalImpl = AccessControlComponent::InternalImpl;␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ @@ -1073,6 +1112,10 @@ Generated by [AVA](https://avajs.dev). self.accesscontrol._grant_role(ERC2981Component::ROYALTY_ADMIN_ROLE, royalty_admin);␊ }␊ ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ #[abi(embed_v0)]␊ impl UpgradeableImpl of IUpgradeable {␊ fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ @@ -1095,12 +1138,10 @@ Generated by [AVA](https://avajs.dev). use openzeppelin::access::ownable::OwnableComponent;␊ use openzeppelin::introspection::src5::SRC5Component;␊ use openzeppelin::token::common::erc2981::ERC2981Component;␊ - use openzeppelin::token::erc721::ERC721Component;␊ - use openzeppelin::token::erc721::ERC721HooksEmptyImpl;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ + use openzeppelin::token::erc721::{ERC721Component, ERC721HooksEmptyImpl};␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ - use starknet::ClassHash;␊ - use starknet::ContractAddress;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ + use starknet::{ClassHash, ContractAddress};␊ ␊ component!(path: ERC721Component, storage: erc721, event: ERC721Event);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ @@ -1108,6 +1149,7 @@ Generated by [AVA](https://avajs.dev). component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ component!(path: ERC2981Component, storage: erc2981, event: ERC2981Event);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl ERC721MixinImpl = ERC721Component::ERC721MixinImpl;␊ #[abi(embed_v0)]␊ @@ -1119,6 +1161,7 @@ Generated by [AVA](https://avajs.dev). #[abi(embed_v0)]␊ impl ERC2981AdminOwnableImpl = ERC2981Component::ERC2981AdminOwnableImpl;␊ ␊ + // Internal␊ impl ERC721InternalImpl = ERC721Component::InternalImpl;␊ impl OwnableInternalImpl = OwnableComponent::InternalImpl;␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ @@ -1168,6 +1211,10 @@ Generated by [AVA](https://avajs.dev). const FEE_DENOMINATOR: u128 = 100000;␊ }␊ ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ #[abi(embed_v0)]␊ impl UpgradeableImpl of IUpgradeable {␊ fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ @@ -1189,16 +1236,13 @@ Generated by [AVA](https://avajs.dev). ␊ #[starknet::contract]␊ mod MyToken {␊ - use openzeppelin::access::accesscontrol::AccessControlComponent;␊ - use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE;␊ + use openzeppelin::access::accesscontrol::{AccessControlComponent, DEFAULT_ADMIN_ROLE};␊ use openzeppelin::introspection::src5::SRC5Component;␊ use openzeppelin::token::common::erc2981::ERC2981Component;␊ - use openzeppelin::token::erc721::ERC721Component;␊ - use openzeppelin::token::erc721::ERC721HooksEmptyImpl;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ + use openzeppelin::token::erc721::{ERC721Component, ERC721HooksEmptyImpl};␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ - use starknet::ClassHash;␊ - use starknet::ContractAddress;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ + use starknet::{ClassHash, ContractAddress};␊ use super::UPGRADER_ROLE;␊ ␊ component!(path: ERC721Component, storage: erc721, event: ERC721Event);␊ @@ -1207,6 +1251,7 @@ Generated by [AVA](https://avajs.dev). component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ component!(path: ERC2981Component, storage: erc2981, event: ERC2981Event);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl ERC721MixinImpl = ERC721Component::ERC721MixinImpl;␊ #[abi(embed_v0)]␊ @@ -1220,6 +1265,7 @@ Generated by [AVA](https://avajs.dev). #[abi(embed_v0)]␊ impl ERC2981AdminAccessControlImpl = ERC2981Component::ERC2981AdminAccessControlImpl;␊ ␊ + // Internal␊ impl ERC721InternalImpl = ERC721Component::InternalImpl;␊ impl AccessControlInternalImpl = AccessControlComponent::InternalImpl;␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ @@ -1275,6 +1321,10 @@ Generated by [AVA](https://avajs.dev). const FEE_DENOMINATOR: u128 = 100000;␊ }␊ ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ #[abi(embed_v0)]␊ impl UpgradeableImpl of IUpgradeable {␊ fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ @@ -1299,14 +1349,12 @@ Generated by [AVA](https://avajs.dev). use openzeppelin::governance::votes::VotesComponent;␊ use openzeppelin::introspection::src5::SRC5Component;␊ use openzeppelin::security::pausable::PausableComponent;␊ - use openzeppelin::token::common::erc2981::DefaultConfig;␊ - use openzeppelin::token::common::erc2981::ERC2981Component;␊ + use openzeppelin::token::common::erc2981::{DefaultConfig, ERC2981Component};␊ use openzeppelin::token::erc721::ERC721Component;␊ use openzeppelin::token::erc721::extensions::ERC721EnumerableComponent;␊ use openzeppelin::utils::cryptography::nonces::NoncesComponent;␊ use openzeppelin::utils::cryptography::snip12::SNIP12Metadata;␊ - use starknet::ContractAddress;␊ - use starknet::get_caller_address;␊ + use starknet::{ContractAddress, get_caller_address};␊ ␊ component!(path: ERC721Component, storage: erc721, event: ERC721Event);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ @@ -1317,6 +1365,7 @@ Generated by [AVA](https://avajs.dev). component!(path: NoncesComponent, storage: nonces, event: NoncesEvent);␊ component!(path: VotesComponent, storage: votes, event: VotesEvent);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl ERC721MixinImpl = ERC721Component::ERC721MixinImpl;␊ #[abi(embed_v0)]␊ @@ -1336,6 +1385,7 @@ Generated by [AVA](https://avajs.dev). #[abi(embed_v0)]␊ impl VotesImpl = VotesComponent::VotesImpl;␊ ␊ + // Internal␊ impl ERC721InternalImpl = ERC721Component::InternalImpl;␊ impl PausableInternalImpl = PausableComponent::InternalImpl;␊ impl OwnableInternalImpl = OwnableComponent::InternalImpl;␊ @@ -1410,17 +1460,7 @@ Generated by [AVA](https://avajs.dev). contract_state.votes.transfer_voting_units(previous_owner, to, 1);␊ }␊ }␊ - ␊ - impl SNIP12MetadataImpl of SNIP12Metadata {␊ - fn name() -> felt252 {␊ - 'MY_DAPP_NAME'␊ - }␊ - ␊ - fn version() -> felt252 {␊ - 'MY_DAPP_VERSION'␊ - }␊ - }␊ - ␊ + ␊ #[generate_trait]␊ #[abi(per_item)]␊ impl ExternalImpl of ExternalTrait {␊ @@ -1462,6 +1502,20 @@ Generated by [AVA](https://avajs.dev). self.safe_mint(recipient, tokenId, data);␊ }␊ }␊ + ␊ + //␊ + // SNIP12 Metadata␊ + //␊ + ␊ + impl SNIP12MetadataImpl of SNIP12Metadata {␊ + fn name() -> felt252 {␊ + 'MY_DAPP_NAME'␊ + }␊ + ␊ + fn version() -> felt252 {␊ + 'MY_DAPP_VERSION'␊ + }␊ + }␊ }␊ ` @@ -1478,12 +1532,11 @@ Generated by [AVA](https://avajs.dev). use openzeppelin::governance::votes::VotesComponent;␊ use openzeppelin::introspection::src5::SRC5Component;␊ use openzeppelin::token::erc721::ERC721Component;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ use openzeppelin::utils::cryptography::nonces::NoncesComponent;␊ use openzeppelin::utils::cryptography::snip12::SNIP12Metadata;␊ - use starknet::ClassHash;␊ - use starknet::ContractAddress;␊ + use starknet::{ClassHash, ContractAddress};␊ ␊ component!(path: ERC721Component, storage: erc721, event: ERC721Event);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ @@ -1492,6 +1545,7 @@ Generated by [AVA](https://avajs.dev). component!(path: NoncesComponent, storage: nonces, event: NoncesEvent);␊ component!(path: VotesComponent, storage: votes, event: VotesEvent);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl ERC721MixinImpl = ERC721Component::ERC721MixinImpl;␊ #[abi(embed_v0)]␊ @@ -1501,6 +1555,7 @@ Generated by [AVA](https://avajs.dev). #[abi(embed_v0)]␊ impl VotesImpl = VotesComponent::VotesImpl;␊ ␊ + // Internal␊ impl ERC721InternalImpl = ERC721Component::InternalImpl;␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ impl OwnableInternalImpl = OwnableComponent::InternalImpl;␊ @@ -1558,6 +1613,10 @@ Generated by [AVA](https://avajs.dev). }␊ }␊ ␊ + //␊ + // SNIP12 Metadata␊ + //␊ + ␊ impl SNIP12MetadataImpl of SNIP12Metadata {␊ fn name() -> felt252 {␊ 'MY_DAPP_NAME'␊ @@ -1568,6 +1627,10 @@ Generated by [AVA](https://avajs.dev). }␊ }␊ ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ #[abi(embed_v0)]␊ impl UpgradeableImpl of IUpgradeable {␊ fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ @@ -1591,12 +1654,11 @@ Generated by [AVA](https://avajs.dev). use openzeppelin::governance::votes::VotesComponent;␊ use openzeppelin::introspection::src5::SRC5Component;␊ use openzeppelin::token::erc721::ERC721Component;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ use openzeppelin::utils::cryptography::nonces::NoncesComponent;␊ use openzeppelin::utils::cryptography::snip12::SNIP12Metadata;␊ - use starknet::ClassHash;␊ - use starknet::ContractAddress;␊ + use starknet::{ClassHash, ContractAddress};␊ ␊ component!(path: ERC721Component, storage: erc721, event: ERC721Event);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ @@ -1605,6 +1667,7 @@ Generated by [AVA](https://avajs.dev). component!(path: NoncesComponent, storage: nonces, event: NoncesEvent);␊ component!(path: VotesComponent, storage: votes, event: VotesEvent);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl ERC721MixinImpl = ERC721Component::ERC721MixinImpl;␊ #[abi(embed_v0)]␊ @@ -1614,6 +1677,7 @@ Generated by [AVA](https://avajs.dev). #[abi(embed_v0)]␊ impl VotesImpl = VotesComponent::VotesImpl;␊ ␊ + // Internal␊ impl ERC721InternalImpl = ERC721Component::InternalImpl;␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ impl OwnableInternalImpl = OwnableComponent::InternalImpl;␊ @@ -1671,6 +1735,10 @@ Generated by [AVA](https://avajs.dev). }␊ }␊ ␊ + //␊ + // SNIP12 Metadata␊ + //␊ + ␊ impl SNIP12MetadataImpl of SNIP12Metadata {␊ fn name() -> felt252 {␊ 'MY_DAPP_NAME'␊ @@ -1681,6 +1749,10 @@ Generated by [AVA](https://avajs.dev). }␊ }␊ ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ #[abi(embed_v0)]␊ impl UpgradeableImpl of IUpgradeable {␊ fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ @@ -1712,6 +1784,7 @@ Generated by [AVA](https://avajs.dev). component!(path: NoncesComponent, storage: nonces, event: NoncesEvent);␊ component!(path: VotesComponent, storage: votes, event: VotesEvent);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl ERC721MixinImpl = ERC721Component::ERC721MixinImpl;␊ #[abi(embed_v0)]␊ @@ -1719,6 +1792,7 @@ Generated by [AVA](https://avajs.dev). #[abi(embed_v0)]␊ impl VotesImpl = VotesComponent::VotesImpl;␊ ␊ + // Internal␊ impl ERC721InternalImpl = ERC721Component::InternalImpl;␊ impl VotesInternalImpl = VotesComponent::InternalImpl;␊ ␊ @@ -1765,6 +1839,10 @@ Generated by [AVA](https://avajs.dev). }␊ }␊ ␊ + //␊ + // SNIP12 Metadata␊ + //␊ + ␊ impl SNIP12MetadataImpl of SNIP12Metadata {␊ fn name() -> felt252 {␊ 'MY_DAPP_NAME'␊ @@ -1791,17 +1869,14 @@ Generated by [AVA](https://avajs.dev). use openzeppelin::governance::votes::VotesComponent;␊ use openzeppelin::introspection::src5::SRC5Component;␊ use openzeppelin::security::pausable::PausableComponent;␊ - use openzeppelin::token::common::erc2981::DefaultConfig;␊ - use openzeppelin::token::common::erc2981::ERC2981Component;␊ + use openzeppelin::token::common::erc2981::{DefaultConfig, ERC2981Component};␊ use openzeppelin::token::erc721::ERC721Component;␊ use openzeppelin::token::erc721::extensions::ERC721EnumerableComponent;␊ - use openzeppelin::upgrades::UpgradeableComponent;␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ use openzeppelin::utils::cryptography::nonces::NoncesComponent;␊ use openzeppelin::utils::cryptography::snip12::SNIP12Metadata;␊ - use starknet::ClassHash;␊ - use starknet::ContractAddress;␊ - use starknet::get_caller_address;␊ + use starknet::{ClassHash, ContractAddress, get_caller_address};␊ ␊ component!(path: ERC721Component, storage: erc721, event: ERC721Event);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ @@ -1813,6 +1888,7 @@ Generated by [AVA](https://avajs.dev). component!(path: NoncesComponent, storage: nonces, event: NoncesEvent);␊ component!(path: VotesComponent, storage: votes, event: VotesEvent);␊ ␊ + // External␊ #[abi(embed_v0)]␊ impl ERC721MixinImpl = ERC721Component::ERC721MixinImpl;␊ #[abi(embed_v0)]␊ @@ -1832,6 +1908,7 @@ Generated by [AVA](https://avajs.dev). #[abi(embed_v0)]␊ impl VotesImpl = VotesComponent::VotesImpl;␊ ␊ + // Internal␊ impl ERC721InternalImpl = ERC721Component::InternalImpl;␊ impl PausableInternalImpl = PausableComponent::InternalImpl;␊ impl OwnableInternalImpl = OwnableComponent::InternalImpl;␊ @@ -1911,25 +1988,7 @@ Generated by [AVA](https://avajs.dev). contract_state.votes.transfer_voting_units(previous_owner, to, 1);␊ }␊ }␊ - ␊ - impl SNIP12MetadataImpl of SNIP12Metadata {␊ - fn name() -> felt252 {␊ - 'MY_DAPP_NAME'␊ - }␊ - ␊ - fn version() -> felt252 {␊ - 'MY_DAPP_VERSION'␊ - }␊ - }␊ - ␊ - #[abi(embed_v0)]␊ - impl UpgradeableImpl of IUpgradeable {␊ - fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ - self.ownable.assert_only_owner();␊ - self.upgradeable.upgrade(new_class_hash);␊ - }␊ - }␊ - ␊ + ␊ #[generate_trait]␊ #[abi(per_item)]␊ impl ExternalImpl of ExternalTrait {␊ @@ -1971,5 +2030,31 @@ Generated by [AVA](https://avajs.dev). self.safe_mint(recipient, tokenId, data);␊ }␊ }␊ + ␊ + //␊ + // 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 {␊ + fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ + self.ownable.assert_only_owner();␊ + self.upgradeable.upgrade(new_class_hash);␊ + }␊ + }␊ }␊ ` diff --git a/packages/core-cairo/src/erc721.test.ts.snap b/packages/core-cairo/src/erc721.test.ts.snap index 20507cf4..cb80f55c 100644 Binary files a/packages/core-cairo/src/erc721.test.ts.snap and b/packages/core-cairo/src/erc721.test.ts.snap differ diff --git a/packages/core-cairo/src/erc721.ts b/packages/core-cairo/src/erc721.ts index 619176cf..6b23e1c2 100644 --- a/packages/core-cairo/src/erc721.ts +++ b/packages/core-cairo/src/erc721.ts @@ -113,7 +113,7 @@ function addHooks(c: ContractBuilder, opts: Required) { priority: 0, }; c.addImplementedTrait(ERC721HooksTrait); - c.addStandaloneImport('starknet::ContractAddress'); + c.addUseClause('starknet', 'ContractAddress'); const requiresMutState = opts.enumerable || opts.votes; const initStateLine = requiresMutState @@ -139,7 +139,12 @@ function addHooks(c: ContractBuilder, opts: Required) { }); } - addVotesComponent(c, toFelt252(opts.appName, 'appName'), toFelt252(opts.appVersion, 'appVersion')); + addVotesComponent( + c, + toFelt252(opts.appName, 'appName'), + toFelt252(opts.appVersion, 'appVersion'), + 'SNIP12 Metadata', + ); beforeUpdateCode.push('let previous_owner = self._owner_of(token_id);'); beforeUpdateCode.push('contract_state.votes.transfer_voting_units(previous_owner, to, 1);'); } @@ -154,7 +159,7 @@ function addHooks(c: ContractBuilder, opts: Required) { code: beforeUpdateCode, }); } else { - c.addStandaloneImport('openzeppelin::token::erc721::ERC721HooksEmptyImpl'); + c.addUseClause('openzeppelin::token::erc721', 'ERC721HooksEmptyImpl'); } } @@ -182,14 +187,14 @@ function addEnumerable(c: ContractBuilder) { } function addBurnable(c: ContractBuilder) { - c.addStandaloneImport('core::num::traits::Zero'); - c.addStandaloneImport('starknet::get_caller_address'); + c.addUseClause('core::num::traits', 'Zero'); + c.addUseClause('starknet', 'get_caller_address'); c.addFunction(externalTrait, functions.burn); } function addMintable(c: ContractBuilder, access: Access) { - c.addStandaloneImport('starknet::ContractAddress'); + c.addUseClause('starknet', 'ContractAddress'); requireAccessControl(c, externalTrait, functions.safe_mint, access, 'MINTER', 'minter'); // Camel case version of safe_mint. Access control and pausable are already set on safe_mint. @@ -207,11 +212,11 @@ const components = defineComponents( { name: 'ERC721Event', type: 'ERC721Component::Event', }, - impls: [], - internalImpl: { + impls: [{ name: 'ERC721InternalImpl', + embed: false, value: 'ERC721Component::InternalImpl', - }, + }], }, ERC721EnumerableComponent: { path: 'openzeppelin::token::erc721::extensions', @@ -223,16 +228,14 @@ const components = defineComponents( { name: 'ERC721EnumerableEvent', type: 'ERC721EnumerableComponent::Event', }, - impls: [ - { - name: 'ERC721EnumerableImpl', - value: 'ERC721EnumerableComponent::ERC721EnumerableImpl', - }, - ], - internalImpl: { + impls: [{ + name: 'ERC721EnumerableImpl', + value: 'ERC721EnumerableComponent::ERC721EnumerableImpl', + }, { name: 'ERC721EnumerableInternalImpl', + embed: false, value: 'ERC721EnumerableComponent::InternalImpl', - }, + }], }, }); diff --git a/packages/core-cairo/src/generate/governor.ts b/packages/core-cairo/src/generate/governor.ts new file mode 100644 index 00000000..8ffee9ae --- /dev/null +++ b/packages/core-cairo/src/generate/governor.ts @@ -0,0 +1,30 @@ +import { clockModeOptions, GovernorOptions, quorumModeOptions, timelockOptions, votesOptions } from '../governor'; +import { infoOptions } from '../set-info'; +import { upgradeableOptions } from '../set-upgradeable'; +import { generateAlternatives } from './alternatives'; + +const booleans = [true, false]; + +const blueprint = { + name: ['MyGovernor'], + delay: ['1 day'], + period: ['1 week'], + proposalThreshold: ['1'], + decimals: [18], + quorumMode: quorumModeOptions, + quorumPercent: [10], + quorumAbsolute: ['10'], + votes: votesOptions, + clockMode: clockModeOptions, + timelock: timelockOptions, + settings: booleans, + appName: ['Openzeppelin Governor'], + appVersion: ['v1'], + upgradeable: upgradeableOptions, + info: infoOptions, +}; + +export function* generateGovernorOptions(): Generator> { + yield* generateAlternatives(blueprint); +} + diff --git a/packages/core-cairo/src/generate/sources.ts b/packages/core-cairo/src/generate/sources.ts index 9d99d898..3ff9365c 100644 --- a/packages/core-cairo/src/generate/sources.ts +++ b/packages/core-cairo/src/generate/sources.ts @@ -7,6 +7,7 @@ import { generateERC721Options } from './erc721'; import { generateERC1155Options } from './erc1155'; import { generateAccountOptions } from './account'; import { generateCustomOptions } from './custom'; +import { generateGovernorOptions } from './governor'; import { buildGeneric, GenericOptions, KindedOptions } from '../build-generic'; import { printContract } from '../print'; import { OptionsError } from '../error'; @@ -47,6 +48,12 @@ export function* generateOptions(kind?: Kind): Generator { yield { kind: 'Custom', ...kindOpts }; } } + + if (!kind || kind === 'Governor') { + for (const kindOpts of generateGovernorOptions()) { + yield { kind: 'Governor', ...kindOpts }; + } + } } interface GeneratedContract { diff --git a/packages/core-cairo/src/governor.test.ts b/packages/core-cairo/src/governor.test.ts new file mode 100644 index 00000000..5b0e0422 --- /dev/null +++ b/packages/core-cairo/src/governor.test.ts @@ -0,0 +1,180 @@ +import test from 'ava'; +import { governor } from '.'; + +import { buildGovernor, GovernorOptions } from './governor'; +import { printContract } from './print'; + +const NAME = 'MyGovernor'; + +function testGovernor(title: string, opts: Partial) { + test(title, t => { + const c = buildGovernor({ + name: NAME, + delay: '1 day', + period: '1 week', + ...opts, + }); + t.snapshot(printContract(c)); + }); +} + +/** + * Tests external API for equivalence with internal API + */ +function testAPIEquivalence(title: string, opts?: GovernorOptions) { + test(title, t => { + t.is(governor.print(opts), printContract(buildGovernor({ + name: NAME, + delay: '1 day', + period: '1 week', + ...opts, + }))); + }); +} + +testGovernor('basic + upgradeable', { + upgradeable: true +}); + +testGovernor('basic non-upgradeable', { + upgradeable: false +}); + +testGovernor('erc20 votes + timelock', { + votes: 'erc20votes', + timelock: 'openzeppelin', +}); + +testGovernor('erc721 votes + timelock', { + votes: 'erc721votes', + timelock: 'openzeppelin', +}); + +testGovernor('custom name', { + name: 'CustomGovernor', +}); + +testGovernor('custom settings', { + delay: '2 hours', + period: '1 year', + proposalThreshold: '300', + settings: true, +}); + +testGovernor('quorum mode absolute', { + quorumMode: 'absolute', + quorumAbsolute: '200', +}); + +testGovernor('quorum mode percent', { + quorumMode: 'percent', + quorumPercent: 40, +}); + +testGovernor('custom snip12 metadata', { + appName: 'Governor', + appVersion: 'v3', +}); + +testGovernor('all options', { + name: NAME, + delay: '4 day', + period: '4 week', + proposalThreshold: '500', + decimals: 10, + quorumMode: 'absolute', + quorumPercent: 50, + quorumAbsolute: '200', + votes: 'erc721votes', + clockMode: 'timestamp', + timelock: 'openzeppelin', + settings: true, + appName: 'MyApp2', + appVersion: 'v5', + upgradeable: true, +}); + +testAPIEquivalence('API basic + upgradeable', { + name: NAME, + delay: '1 day', + period: '1 week', + upgradeable: true +}); + +testAPIEquivalence('API basic non-upgradeable', { + name: NAME, + delay: '1 day', + period: '1 week', + upgradeable: false +}); + +testAPIEquivalence('API erc20 votes + timelock', { + name: NAME, + delay: '1 day', + period: '1 week', + votes: 'erc20votes', + timelock: 'openzeppelin', +}); + +testAPIEquivalence('API erc721 votes + timelock', { + name: NAME, + delay: '1 day', + period: '1 week', + votes: 'erc721votes', + timelock: 'openzeppelin', +}); + +testAPIEquivalence('API custom name', { + delay: '1 day', + period: '1 week', + name: 'CustomGovernor', +}); + +testAPIEquivalence('API custom settings', { + name: NAME, + delay: '2 hours', + period: '1 year', + proposalThreshold: '300', + settings: true, +}); + +testAPIEquivalence('API quorum mode absolute', { + name: NAME, + delay: '1 day', + period: '1 week', + quorumMode: 'absolute', + quorumAbsolute: '200', +}); + +testAPIEquivalence('API quorum mode percent', { name: NAME, + delay: '1 day', + period: '1 week', + quorumMode: 'percent', + quorumPercent: 40, +}); + +testAPIEquivalence('API custom snip12 metadata', { + name: NAME, + delay: '1 day', + period: '1 week', + appName: 'Governor', + appVersion: 'v3', +}); + +testAPIEquivalence('API all options', { + name: NAME, + delay: '4 day', + period: '4 week', + proposalThreshold: '500', + decimals: 10, + quorumMode: 'absolute', + quorumPercent: 50, + quorumAbsolute: '200', + votes: 'erc721votes', + clockMode: 'timestamp', + timelock: 'openzeppelin', + settings: true, + appName: 'MyApp2', + appVersion: 'v5', + upgradeable: true, +}); diff --git a/packages/core-cairo/src/governor.test.ts.md b/packages/core-cairo/src/governor.test.ts.md new file mode 100644 index 00000000..3c8e8a77 --- /dev/null +++ b/packages/core-cairo/src/governor.test.ts.md @@ -0,0 +1,1419 @@ +# Snapshot report for `src/governor.test.ts` + +The actual snapshot is saved in `governor.test.ts.snap`. + +Generated by [AVA](https://avajs.dev). + +## basic + upgradeable + +> Snapshot 1 + + `// SPDX-License-Identifier: MIT␊ + // Compatible with OpenZeppelin Contracts for Cairo ^0.20.0␊ + ␊ + #[starknet::contract]␊ + mod MyGovernor {␊ + use openzeppelin::governance::governor::{DefaultConfig, GovernorComponent};␊ + use openzeppelin::governance::governor::extensions::{␊ + GovernorCountingSimpleComponent, GovernorSettingsComponent,␊ + GovernorTimelockExecutionComponent, GovernorVotesQuorumFractionComponent␊ + };␊ + use openzeppelin::governance::governor::extensions::GovernorSettingsComponent::InternalTrait as GovernorSettingsInternalTrait;␊ + use openzeppelin::governance::governor::extensions::GovernorTimelockExecutionComponent::InternalTrait as GovernorTimelockExecutionInternalTrait;␊ + use openzeppelin::governance::governor::extensions::GovernorVotesQuorumFractionComponent::InternalTrait as GovernorVotesQuorumFractionInternalTrait;␊ + use openzeppelin::governance::governor::GovernorComponent::{␊ + InternalExtendedImpl, InternalTrait as GovernorInternalTrait␊ + };␊ + use openzeppelin::introspection::src5::SRC5Component;␊ + use openzeppelin::upgrades::interface::IUpgradeable;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ + use openzeppelin::utils::cryptography::snip12::SNIP12Metadata;␊ + use starknet::{ClassHash, ContractAddress};␊ + ␊ + const QUORUM_NUMERATOR: u256 = 40; // 4%␊ + const VOTING_DELAY: u64 = 86400; // 1 day␊ + const VOTING_PERIOD: u64 = 604800; // 1 week␊ + const PROPOSAL_THRESHOLD: u256 = 0;␊ + ␊ + component!(path: GovernorComponent, storage: governor, event: GovernorEvent);␊ + component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ + component!(path: GovernorCountingSimpleComponent, storage: governor_counting, event: GovernorCountingSimpleEvent);␊ + component!(path: GovernorVotesQuorumFractionComponent, storage: governor_votes, event: GovernorVotesEvent);␊ + component!(path: GovernorSettingsComponent, storage: governor_settings, event: GovernorSettingsEvent);␊ + component!(path: GovernorTimelockExecutionComponent, storage: governor_timelock_execution, event: GovernorTimelockExecutionEvent);␊ + component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ + ␊ + // Extensions (external)␊ + #[abi(embed_v0)]␊ + impl QuorumFractionImpl = GovernorVotesQuorumFractionComponent::QuorumFractionImpl;␊ + #[abi(embed_v0)]␊ + impl GovernorSettingsAdminImpl = GovernorSettingsComponent::GovernorSettingsAdminImpl;␊ + #[abi(embed_v0)]␊ + impl TimelockedImpl = GovernorTimelockExecutionComponent::TimelockedImpl;␊ + ␊ + // Extensions (internal)␊ + impl GovernorCountingSimpleImpl = GovernorCountingSimpleComponent::GovernorCounting;␊ + impl GovernorQuorumImpl = GovernorVotesQuorumFractionComponent::GovernorQuorum;␊ + impl GovernorVotesImpl = GovernorVotesQuorumFractionComponent::GovernorVotes;␊ + impl GovernorSettingsImpl = GovernorSettingsComponent::GovernorSettings;␊ + impl GovernorTimelockExecutionImpl = GovernorTimelockExecutionComponent::GovernorExecution;␊ + ␊ + // Governor Core␊ + #[abi(embed_v0)]␊ + impl GovernorImpl = GovernorComponent::GovernorImpl;␊ + ␊ + // Internal␊ + impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ + ␊ + // SRC5␊ + #[abi(embed_v0)]␊ + impl SRC5Impl = SRC5Component::SRC5Impl;␊ + ␊ + #[storage]␊ + struct Storage {␊ + #[substorage(v0)]␊ + governor: GovernorComponent::Storage,␊ + #[substorage(v0)]␊ + src5: SRC5Component::Storage,␊ + #[substorage(v0)]␊ + governor_counting: GovernorCountingSimpleComponent::Storage,␊ + #[substorage(v0)]␊ + governor_votes: GovernorVotesQuorumFractionComponent::Storage,␊ + #[substorage(v0)]␊ + governor_settings: GovernorSettingsComponent::Storage,␊ + #[substorage(v0)]␊ + governor_timelock_execution: GovernorTimelockExecutionComponent::Storage,␊ + #[substorage(v0)]␊ + upgradeable: UpgradeableComponent::Storage,␊ + }␊ + ␊ + #[event]␊ + #[derive(Drop, starknet::Event)]␊ + enum Event {␊ + #[flat]␊ + GovernorEvent: GovernorComponent::Event,␊ + #[flat]␊ + SRC5Event: SRC5Component::Event,␊ + #[flat]␊ + GovernorCountingSimpleEvent: GovernorCountingSimpleComponent::Event,␊ + #[flat]␊ + GovernorVotesEvent: GovernorVotesQuorumFractionComponent::Event,␊ + #[flat]␊ + GovernorSettingsEvent: GovernorSettingsComponent::Event,␊ + #[flat]␊ + GovernorTimelockExecutionEvent: GovernorTimelockExecutionComponent::Event,␊ + #[flat]␊ + UpgradeableEvent: UpgradeableComponent::Event,␊ + }␊ + ␊ + #[constructor]␊ + fn constructor(␊ + ref self: ContractState,␊ + votes_token: ContractAddress,␊ + timelock_controller: ContractAddress,␊ + ) {␊ + self.governor.initializer();␊ + self.governor_votes.initializer(votes_token, QUORUM_NUMERATOR);␊ + self.governor_settings.initializer(VOTING_DELAY, VOTING_PERIOD, PROPOSAL_THRESHOLD);␊ + self.governor_timelock_execution.initializer(timelock_controller);␊ + }␊ + ␊ + //␊ + // SNIP12 Metadata␊ + //␊ + ␊ + impl SNIP12MetadataImpl of SNIP12Metadata {␊ + fn name() -> felt252 {␊ + 'OpenZeppelin Governor'␊ + }␊ + ␊ + fn version() -> felt252 {␊ + 'v1'␊ + }␊ + }␊ + ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ + #[abi(embed_v0)]␊ + impl UpgradeableImpl of IUpgradeable {␊ + fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ + self.governor.assert_only_governance();␊ + self.upgradeable.upgrade(new_class_hash);␊ + }␊ + }␊ + }␊ + ` + +## basic non-upgradeable + +> Snapshot 1 + + `// SPDX-License-Identifier: MIT␊ + // Compatible with OpenZeppelin Contracts for Cairo ^0.20.0␊ + ␊ + #[starknet::contract]␊ + mod MyGovernor {␊ + use openzeppelin::governance::governor::{DefaultConfig, GovernorComponent};␊ + use openzeppelin::governance::governor::extensions::{␊ + GovernorCountingSimpleComponent, GovernorSettingsComponent,␊ + GovernorTimelockExecutionComponent, GovernorVotesQuorumFractionComponent␊ + };␊ + use openzeppelin::governance::governor::extensions::GovernorSettingsComponent::InternalTrait as GovernorSettingsInternalTrait;␊ + use openzeppelin::governance::governor::extensions::GovernorTimelockExecutionComponent::InternalTrait as GovernorTimelockExecutionInternalTrait;␊ + use openzeppelin::governance::governor::extensions::GovernorVotesQuorumFractionComponent::InternalTrait as GovernorVotesQuorumFractionInternalTrait;␊ + use openzeppelin::governance::governor::GovernorComponent::InternalTrait as GovernorInternalTrait;␊ + use openzeppelin::introspection::src5::SRC5Component;␊ + use openzeppelin::utils::cryptography::snip12::SNIP12Metadata;␊ + use starknet::ContractAddress;␊ + ␊ + const QUORUM_NUMERATOR: u256 = 40; // 4%␊ + const VOTING_DELAY: u64 = 86400; // 1 day␊ + const VOTING_PERIOD: u64 = 604800; // 1 week␊ + const PROPOSAL_THRESHOLD: u256 = 0;␊ + ␊ + component!(path: GovernorComponent, storage: governor, event: GovernorEvent);␊ + component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ + component!(path: GovernorCountingSimpleComponent, storage: governor_counting, event: GovernorCountingSimpleEvent);␊ + component!(path: GovernorVotesQuorumFractionComponent, storage: governor_votes, event: GovernorVotesEvent);␊ + component!(path: GovernorSettingsComponent, storage: governor_settings, event: GovernorSettingsEvent);␊ + component!(path: GovernorTimelockExecutionComponent, storage: governor_timelock_execution, event: GovernorTimelockExecutionEvent);␊ + ␊ + // Extensions (external)␊ + #[abi(embed_v0)]␊ + impl QuorumFractionImpl = GovernorVotesQuorumFractionComponent::QuorumFractionImpl;␊ + #[abi(embed_v0)]␊ + impl GovernorSettingsAdminImpl = GovernorSettingsComponent::GovernorSettingsAdminImpl;␊ + #[abi(embed_v0)]␊ + impl TimelockedImpl = GovernorTimelockExecutionComponent::TimelockedImpl;␊ + ␊ + // Extensions (internal)␊ + impl GovernorCountingSimpleImpl = GovernorCountingSimpleComponent::GovernorCounting;␊ + impl GovernorQuorumImpl = GovernorVotesQuorumFractionComponent::GovernorQuorum;␊ + impl GovernorVotesImpl = GovernorVotesQuorumFractionComponent::GovernorVotes;␊ + impl GovernorSettingsImpl = GovernorSettingsComponent::GovernorSettings;␊ + impl GovernorTimelockExecutionImpl = GovernorTimelockExecutionComponent::GovernorExecution;␊ + ␊ + // Governor Core␊ + #[abi(embed_v0)]␊ + impl GovernorImpl = GovernorComponent::GovernorImpl;␊ + ␊ + // SRC5␊ + #[abi(embed_v0)]␊ + impl SRC5Impl = SRC5Component::SRC5Impl;␊ + ␊ + #[storage]␊ + struct Storage {␊ + #[substorage(v0)]␊ + governor: GovernorComponent::Storage,␊ + #[substorage(v0)]␊ + src5: SRC5Component::Storage,␊ + #[substorage(v0)]␊ + governor_counting: GovernorCountingSimpleComponent::Storage,␊ + #[substorage(v0)]␊ + governor_votes: GovernorVotesQuorumFractionComponent::Storage,␊ + #[substorage(v0)]␊ + governor_settings: GovernorSettingsComponent::Storage,␊ + #[substorage(v0)]␊ + governor_timelock_execution: GovernorTimelockExecutionComponent::Storage,␊ + }␊ + ␊ + #[event]␊ + #[derive(Drop, starknet::Event)]␊ + enum Event {␊ + #[flat]␊ + GovernorEvent: GovernorComponent::Event,␊ + #[flat]␊ + SRC5Event: SRC5Component::Event,␊ + #[flat]␊ + GovernorCountingSimpleEvent: GovernorCountingSimpleComponent::Event,␊ + #[flat]␊ + GovernorVotesEvent: GovernorVotesQuorumFractionComponent::Event,␊ + #[flat]␊ + GovernorSettingsEvent: GovernorSettingsComponent::Event,␊ + #[flat]␊ + GovernorTimelockExecutionEvent: GovernorTimelockExecutionComponent::Event,␊ + }␊ + ␊ + #[constructor]␊ + fn constructor(␊ + ref self: ContractState,␊ + votes_token: ContractAddress,␊ + timelock_controller: ContractAddress,␊ + ) {␊ + self.governor.initializer();␊ + self.governor_votes.initializer(votes_token, QUORUM_NUMERATOR);␊ + self.governor_settings.initializer(VOTING_DELAY, VOTING_PERIOD, PROPOSAL_THRESHOLD);␊ + self.governor_timelock_execution.initializer(timelock_controller);␊ + }␊ + ␊ + //␊ + // SNIP12 Metadata␊ + //␊ + ␊ + impl SNIP12MetadataImpl of SNIP12Metadata {␊ + fn name() -> felt252 {␊ + 'OpenZeppelin Governor'␊ + }␊ + ␊ + fn version() -> felt252 {␊ + 'v1'␊ + }␊ + }␊ + }␊ + ` + +## erc20 votes + timelock + +> Snapshot 1 + + `// SPDX-License-Identifier: MIT␊ + // Compatible with OpenZeppelin Contracts for Cairo ^0.20.0␊ + ␊ + #[starknet::contract]␊ + mod MyGovernor {␊ + use openzeppelin::governance::governor::{DefaultConfig, GovernorComponent};␊ + use openzeppelin::governance::governor::extensions::{␊ + GovernorCountingSimpleComponent, GovernorSettingsComponent,␊ + GovernorTimelockExecutionComponent, GovernorVotesQuorumFractionComponent␊ + };␊ + use openzeppelin::governance::governor::extensions::GovernorSettingsComponent::InternalTrait as GovernorSettingsInternalTrait;␊ + use openzeppelin::governance::governor::extensions::GovernorTimelockExecutionComponent::InternalTrait as GovernorTimelockExecutionInternalTrait;␊ + use openzeppelin::governance::governor::extensions::GovernorVotesQuorumFractionComponent::InternalTrait as GovernorVotesQuorumFractionInternalTrait;␊ + use openzeppelin::governance::governor::GovernorComponent::{␊ + InternalExtendedImpl, InternalTrait as GovernorInternalTrait␊ + };␊ + use openzeppelin::introspection::src5::SRC5Component;␊ + use openzeppelin::upgrades::interface::IUpgradeable;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ + use openzeppelin::utils::cryptography::snip12::SNIP12Metadata;␊ + use starknet::{ClassHash, ContractAddress};␊ + ␊ + const QUORUM_NUMERATOR: u256 = 40; // 4%␊ + const VOTING_DELAY: u64 = 86400; // 1 day␊ + const VOTING_PERIOD: u64 = 604800; // 1 week␊ + const PROPOSAL_THRESHOLD: u256 = 0;␊ + ␊ + component!(path: GovernorComponent, storage: governor, event: GovernorEvent);␊ + component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ + component!(path: GovernorCountingSimpleComponent, storage: governor_counting, event: GovernorCountingSimpleEvent);␊ + component!(path: GovernorVotesQuorumFractionComponent, storage: governor_votes, event: GovernorVotesEvent);␊ + component!(path: GovernorSettingsComponent, storage: governor_settings, event: GovernorSettingsEvent);␊ + component!(path: GovernorTimelockExecutionComponent, storage: governor_timelock_execution, event: GovernorTimelockExecutionEvent);␊ + component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ + ␊ + // Extensions (external)␊ + #[abi(embed_v0)]␊ + impl QuorumFractionImpl = GovernorVotesQuorumFractionComponent::QuorumFractionImpl;␊ + #[abi(embed_v0)]␊ + impl GovernorSettingsAdminImpl = GovernorSettingsComponent::GovernorSettingsAdminImpl;␊ + #[abi(embed_v0)]␊ + impl TimelockedImpl = GovernorTimelockExecutionComponent::TimelockedImpl;␊ + ␊ + // Extensions (internal)␊ + impl GovernorCountingSimpleImpl = GovernorCountingSimpleComponent::GovernorCounting;␊ + impl GovernorQuorumImpl = GovernorVotesQuorumFractionComponent::GovernorQuorum;␊ + impl GovernorVotesImpl = GovernorVotesQuorumFractionComponent::GovernorVotes;␊ + impl GovernorSettingsImpl = GovernorSettingsComponent::GovernorSettings;␊ + impl GovernorTimelockExecutionImpl = GovernorTimelockExecutionComponent::GovernorExecution;␊ + ␊ + // Governor Core␊ + #[abi(embed_v0)]␊ + impl GovernorImpl = GovernorComponent::GovernorImpl;␊ + ␊ + // Internal␊ + impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ + ␊ + // SRC5␊ + #[abi(embed_v0)]␊ + impl SRC5Impl = SRC5Component::SRC5Impl;␊ + ␊ + #[storage]␊ + struct Storage {␊ + #[substorage(v0)]␊ + governor: GovernorComponent::Storage,␊ + #[substorage(v0)]␊ + src5: SRC5Component::Storage,␊ + #[substorage(v0)]␊ + governor_counting: GovernorCountingSimpleComponent::Storage,␊ + #[substorage(v0)]␊ + governor_votes: GovernorVotesQuorumFractionComponent::Storage,␊ + #[substorage(v0)]␊ + governor_settings: GovernorSettingsComponent::Storage,␊ + #[substorage(v0)]␊ + governor_timelock_execution: GovernorTimelockExecutionComponent::Storage,␊ + #[substorage(v0)]␊ + upgradeable: UpgradeableComponent::Storage,␊ + }␊ + ␊ + #[event]␊ + #[derive(Drop, starknet::Event)]␊ + enum Event {␊ + #[flat]␊ + GovernorEvent: GovernorComponent::Event,␊ + #[flat]␊ + SRC5Event: SRC5Component::Event,␊ + #[flat]␊ + GovernorCountingSimpleEvent: GovernorCountingSimpleComponent::Event,␊ + #[flat]␊ + GovernorVotesEvent: GovernorVotesQuorumFractionComponent::Event,␊ + #[flat]␊ + GovernorSettingsEvent: GovernorSettingsComponent::Event,␊ + #[flat]␊ + GovernorTimelockExecutionEvent: GovernorTimelockExecutionComponent::Event,␊ + #[flat]␊ + UpgradeableEvent: UpgradeableComponent::Event,␊ + }␊ + ␊ + #[constructor]␊ + fn constructor(␊ + ref self: ContractState,␊ + votes_token: ContractAddress,␊ + timelock_controller: ContractAddress,␊ + ) {␊ + self.governor.initializer();␊ + self.governor_votes.initializer(votes_token, QUORUM_NUMERATOR);␊ + self.governor_settings.initializer(VOTING_DELAY, VOTING_PERIOD, PROPOSAL_THRESHOLD);␊ + self.governor_timelock_execution.initializer(timelock_controller);␊ + }␊ + ␊ + //␊ + // SNIP12 Metadata␊ + //␊ + ␊ + impl SNIP12MetadataImpl of SNIP12Metadata {␊ + fn name() -> felt252 {␊ + 'OpenZeppelin Governor'␊ + }␊ + ␊ + fn version() -> felt252 {␊ + 'v1'␊ + }␊ + }␊ + ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ + #[abi(embed_v0)]␊ + impl UpgradeableImpl of IUpgradeable {␊ + fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ + self.governor.assert_only_governance();␊ + self.upgradeable.upgrade(new_class_hash);␊ + }␊ + }␊ + }␊ + ` + +## erc721 votes + timelock + +> Snapshot 1 + + `// SPDX-License-Identifier: MIT␊ + // Compatible with OpenZeppelin Contracts for Cairo ^0.20.0␊ + ␊ + #[starknet::contract]␊ + mod MyGovernor {␊ + use openzeppelin::governance::governor::{DefaultConfig, GovernorComponent};␊ + use openzeppelin::governance::governor::extensions::{␊ + GovernorCountingSimpleComponent, GovernorSettingsComponent,␊ + GovernorTimelockExecutionComponent, GovernorVotesQuorumFractionComponent␊ + };␊ + use openzeppelin::governance::governor::extensions::GovernorSettingsComponent::InternalTrait as GovernorSettingsInternalTrait;␊ + use openzeppelin::governance::governor::extensions::GovernorTimelockExecutionComponent::InternalTrait as GovernorTimelockExecutionInternalTrait;␊ + use openzeppelin::governance::governor::extensions::GovernorVotesQuorumFractionComponent::InternalTrait as GovernorVotesQuorumFractionInternalTrait;␊ + use openzeppelin::governance::governor::GovernorComponent::{␊ + InternalExtendedImpl, InternalTrait as GovernorInternalTrait␊ + };␊ + use openzeppelin::introspection::src5::SRC5Component;␊ + use openzeppelin::upgrades::interface::IUpgradeable;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ + use openzeppelin::utils::cryptography::snip12::SNIP12Metadata;␊ + use starknet::{ClassHash, ContractAddress};␊ + ␊ + const QUORUM_NUMERATOR: u256 = 40; // 4%␊ + const VOTING_DELAY: u64 = 86400; // 1 day␊ + const VOTING_PERIOD: u64 = 604800; // 1 week␊ + const PROPOSAL_THRESHOLD: u256 = 0;␊ + ␊ + component!(path: GovernorComponent, storage: governor, event: GovernorEvent);␊ + component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ + component!(path: GovernorCountingSimpleComponent, storage: governor_counting, event: GovernorCountingSimpleEvent);␊ + component!(path: GovernorVotesQuorumFractionComponent, storage: governor_votes, event: GovernorVotesEvent);␊ + component!(path: GovernorSettingsComponent, storage: governor_settings, event: GovernorSettingsEvent);␊ + component!(path: GovernorTimelockExecutionComponent, storage: governor_timelock_execution, event: GovernorTimelockExecutionEvent);␊ + component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ + ␊ + // Extensions (external)␊ + #[abi(embed_v0)]␊ + impl QuorumFractionImpl = GovernorVotesQuorumFractionComponent::QuorumFractionImpl;␊ + #[abi(embed_v0)]␊ + impl GovernorSettingsAdminImpl = GovernorSettingsComponent::GovernorSettingsAdminImpl;␊ + #[abi(embed_v0)]␊ + impl TimelockedImpl = GovernorTimelockExecutionComponent::TimelockedImpl;␊ + ␊ + // Extensions (internal)␊ + impl GovernorCountingSimpleImpl = GovernorCountingSimpleComponent::GovernorCounting;␊ + impl GovernorQuorumImpl = GovernorVotesQuorumFractionComponent::GovernorQuorum;␊ + impl GovernorVotesImpl = GovernorVotesQuorumFractionComponent::GovernorVotes;␊ + impl GovernorSettingsImpl = GovernorSettingsComponent::GovernorSettings;␊ + impl GovernorTimelockExecutionImpl = GovernorTimelockExecutionComponent::GovernorExecution;␊ + ␊ + // Governor Core␊ + #[abi(embed_v0)]␊ + impl GovernorImpl = GovernorComponent::GovernorImpl;␊ + ␊ + // Internal␊ + impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ + ␊ + // SRC5␊ + #[abi(embed_v0)]␊ + impl SRC5Impl = SRC5Component::SRC5Impl;␊ + ␊ + #[storage]␊ + struct Storage {␊ + #[substorage(v0)]␊ + governor: GovernorComponent::Storage,␊ + #[substorage(v0)]␊ + src5: SRC5Component::Storage,␊ + #[substorage(v0)]␊ + governor_counting: GovernorCountingSimpleComponent::Storage,␊ + #[substorage(v0)]␊ + governor_votes: GovernorVotesQuorumFractionComponent::Storage,␊ + #[substorage(v0)]␊ + governor_settings: GovernorSettingsComponent::Storage,␊ + #[substorage(v0)]␊ + governor_timelock_execution: GovernorTimelockExecutionComponent::Storage,␊ + #[substorage(v0)]␊ + upgradeable: UpgradeableComponent::Storage,␊ + }␊ + ␊ + #[event]␊ + #[derive(Drop, starknet::Event)]␊ + enum Event {␊ + #[flat]␊ + GovernorEvent: GovernorComponent::Event,␊ + #[flat]␊ + SRC5Event: SRC5Component::Event,␊ + #[flat]␊ + GovernorCountingSimpleEvent: GovernorCountingSimpleComponent::Event,␊ + #[flat]␊ + GovernorVotesEvent: GovernorVotesQuorumFractionComponent::Event,␊ + #[flat]␊ + GovernorSettingsEvent: GovernorSettingsComponent::Event,␊ + #[flat]␊ + GovernorTimelockExecutionEvent: GovernorTimelockExecutionComponent::Event,␊ + #[flat]␊ + UpgradeableEvent: UpgradeableComponent::Event,␊ + }␊ + ␊ + #[constructor]␊ + fn constructor(␊ + ref self: ContractState,␊ + votes_token: ContractAddress,␊ + timelock_controller: ContractAddress,␊ + ) {␊ + self.governor.initializer();␊ + self.governor_votes.initializer(votes_token, QUORUM_NUMERATOR);␊ + self.governor_settings.initializer(VOTING_DELAY, VOTING_PERIOD, PROPOSAL_THRESHOLD);␊ + self.governor_timelock_execution.initializer(timelock_controller);␊ + }␊ + ␊ + //␊ + // SNIP12 Metadata␊ + //␊ + ␊ + impl SNIP12MetadataImpl of SNIP12Metadata {␊ + fn name() -> felt252 {␊ + 'OpenZeppelin Governor'␊ + }␊ + ␊ + fn version() -> felt252 {␊ + 'v1'␊ + }␊ + }␊ + ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ + #[abi(embed_v0)]␊ + impl UpgradeableImpl of IUpgradeable {␊ + fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ + self.governor.assert_only_governance();␊ + self.upgradeable.upgrade(new_class_hash);␊ + }␊ + }␊ + }␊ + ` + +## custom name + +> Snapshot 1 + + `// SPDX-License-Identifier: MIT␊ + // Compatible with OpenZeppelin Contracts for Cairo ^0.20.0␊ + ␊ + #[starknet::contract]␊ + mod CustomGovernor {␊ + use openzeppelin::governance::governor::{DefaultConfig, GovernorComponent};␊ + use openzeppelin::governance::governor::extensions::{␊ + GovernorCountingSimpleComponent, GovernorSettingsComponent,␊ + GovernorTimelockExecutionComponent, GovernorVotesQuorumFractionComponent␊ + };␊ + use openzeppelin::governance::governor::extensions::GovernorSettingsComponent::InternalTrait as GovernorSettingsInternalTrait;␊ + use openzeppelin::governance::governor::extensions::GovernorTimelockExecutionComponent::InternalTrait as GovernorTimelockExecutionInternalTrait;␊ + use openzeppelin::governance::governor::extensions::GovernorVotesQuorumFractionComponent::InternalTrait as GovernorVotesQuorumFractionInternalTrait;␊ + use openzeppelin::governance::governor::GovernorComponent::{␊ + InternalExtendedImpl, InternalTrait as GovernorInternalTrait␊ + };␊ + use openzeppelin::introspection::src5::SRC5Component;␊ + use openzeppelin::upgrades::interface::IUpgradeable;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ + use openzeppelin::utils::cryptography::snip12::SNIP12Metadata;␊ + use starknet::{ClassHash, ContractAddress};␊ + ␊ + const QUORUM_NUMERATOR: u256 = 40; // 4%␊ + const VOTING_DELAY: u64 = 86400; // 1 day␊ + const VOTING_PERIOD: u64 = 604800; // 1 week␊ + const PROPOSAL_THRESHOLD: u256 = 0;␊ + ␊ + component!(path: GovernorComponent, storage: governor, event: GovernorEvent);␊ + component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ + component!(path: GovernorCountingSimpleComponent, storage: governor_counting, event: GovernorCountingSimpleEvent);␊ + component!(path: GovernorVotesQuorumFractionComponent, storage: governor_votes, event: GovernorVotesEvent);␊ + component!(path: GovernorSettingsComponent, storage: governor_settings, event: GovernorSettingsEvent);␊ + component!(path: GovernorTimelockExecutionComponent, storage: governor_timelock_execution, event: GovernorTimelockExecutionEvent);␊ + component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ + ␊ + // Extensions (external)␊ + #[abi(embed_v0)]␊ + impl QuorumFractionImpl = GovernorVotesQuorumFractionComponent::QuorumFractionImpl;␊ + #[abi(embed_v0)]␊ + impl GovernorSettingsAdminImpl = GovernorSettingsComponent::GovernorSettingsAdminImpl;␊ + #[abi(embed_v0)]␊ + impl TimelockedImpl = GovernorTimelockExecutionComponent::TimelockedImpl;␊ + ␊ + // Extensions (internal)␊ + impl GovernorCountingSimpleImpl = GovernorCountingSimpleComponent::GovernorCounting;␊ + impl GovernorQuorumImpl = GovernorVotesQuorumFractionComponent::GovernorQuorum;␊ + impl GovernorVotesImpl = GovernorVotesQuorumFractionComponent::GovernorVotes;␊ + impl GovernorSettingsImpl = GovernorSettingsComponent::GovernorSettings;␊ + impl GovernorTimelockExecutionImpl = GovernorTimelockExecutionComponent::GovernorExecution;␊ + ␊ + // Governor Core␊ + #[abi(embed_v0)]␊ + impl GovernorImpl = GovernorComponent::GovernorImpl;␊ + ␊ + // Internal␊ + impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ + ␊ + // SRC5␊ + #[abi(embed_v0)]␊ + impl SRC5Impl = SRC5Component::SRC5Impl;␊ + ␊ + #[storage]␊ + struct Storage {␊ + #[substorage(v0)]␊ + governor: GovernorComponent::Storage,␊ + #[substorage(v0)]␊ + src5: SRC5Component::Storage,␊ + #[substorage(v0)]␊ + governor_counting: GovernorCountingSimpleComponent::Storage,␊ + #[substorage(v0)]␊ + governor_votes: GovernorVotesQuorumFractionComponent::Storage,␊ + #[substorage(v0)]␊ + governor_settings: GovernorSettingsComponent::Storage,␊ + #[substorage(v0)]␊ + governor_timelock_execution: GovernorTimelockExecutionComponent::Storage,␊ + #[substorage(v0)]␊ + upgradeable: UpgradeableComponent::Storage,␊ + }␊ + ␊ + #[event]␊ + #[derive(Drop, starknet::Event)]␊ + enum Event {␊ + #[flat]␊ + GovernorEvent: GovernorComponent::Event,␊ + #[flat]␊ + SRC5Event: SRC5Component::Event,␊ + #[flat]␊ + GovernorCountingSimpleEvent: GovernorCountingSimpleComponent::Event,␊ + #[flat]␊ + GovernorVotesEvent: GovernorVotesQuorumFractionComponent::Event,␊ + #[flat]␊ + GovernorSettingsEvent: GovernorSettingsComponent::Event,␊ + #[flat]␊ + GovernorTimelockExecutionEvent: GovernorTimelockExecutionComponent::Event,␊ + #[flat]␊ + UpgradeableEvent: UpgradeableComponent::Event,␊ + }␊ + ␊ + #[constructor]␊ + fn constructor(␊ + ref self: ContractState,␊ + votes_token: ContractAddress,␊ + timelock_controller: ContractAddress,␊ + ) {␊ + self.governor.initializer();␊ + self.governor_votes.initializer(votes_token, QUORUM_NUMERATOR);␊ + self.governor_settings.initializer(VOTING_DELAY, VOTING_PERIOD, PROPOSAL_THRESHOLD);␊ + self.governor_timelock_execution.initializer(timelock_controller);␊ + }␊ + ␊ + //␊ + // SNIP12 Metadata␊ + //␊ + ␊ + impl SNIP12MetadataImpl of SNIP12Metadata {␊ + fn name() -> felt252 {␊ + 'OpenZeppelin Governor'␊ + }␊ + ␊ + fn version() -> felt252 {␊ + 'v1'␊ + }␊ + }␊ + ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ + #[abi(embed_v0)]␊ + impl UpgradeableImpl of IUpgradeable {␊ + fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ + self.governor.assert_only_governance();␊ + self.upgradeable.upgrade(new_class_hash);␊ + }␊ + }␊ + }␊ + ` + +## custom settings + +> Snapshot 1 + + `// SPDX-License-Identifier: MIT␊ + // Compatible with OpenZeppelin Contracts for Cairo ^0.20.0␊ + ␊ + #[starknet::contract]␊ + mod MyGovernor {␊ + use openzeppelin::governance::governor::{DefaultConfig, GovernorComponent};␊ + use openzeppelin::governance::governor::extensions::{␊ + GovernorCountingSimpleComponent, GovernorSettingsComponent,␊ + GovernorTimelockExecutionComponent, GovernorVotesQuorumFractionComponent␊ + };␊ + use openzeppelin::governance::governor::extensions::GovernorSettingsComponent::InternalTrait as GovernorSettingsInternalTrait;␊ + use openzeppelin::governance::governor::extensions::GovernorTimelockExecutionComponent::InternalTrait as GovernorTimelockExecutionInternalTrait;␊ + use openzeppelin::governance::governor::extensions::GovernorVotesQuorumFractionComponent::InternalTrait as GovernorVotesQuorumFractionInternalTrait;␊ + use openzeppelin::governance::governor::GovernorComponent::{␊ + InternalExtendedImpl, InternalTrait as GovernorInternalTrait␊ + };␊ + use openzeppelin::introspection::src5::SRC5Component;␊ + use openzeppelin::upgrades::interface::IUpgradeable;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ + use openzeppelin::utils::cryptography::snip12::SNIP12Metadata;␊ + use starknet::{ClassHash, ContractAddress};␊ + ␊ + const QUORUM_NUMERATOR: u256 = 40; // 4%␊ + const VOTING_DELAY: u64 = 7200; // 2 hours␊ + const VOTING_PERIOD: u64 = 31536000; // 1 year␊ + const PROPOSAL_THRESHOLD: u256 = 300000000000000000000; // 300 * pow!(10, 18)␊ + ␊ + component!(path: GovernorComponent, storage: governor, event: GovernorEvent);␊ + component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ + component!(path: GovernorCountingSimpleComponent, storage: governor_counting, event: GovernorCountingSimpleEvent);␊ + component!(path: GovernorVotesQuorumFractionComponent, storage: governor_votes, event: GovernorVotesEvent);␊ + component!(path: GovernorSettingsComponent, storage: governor_settings, event: GovernorSettingsEvent);␊ + component!(path: GovernorTimelockExecutionComponent, storage: governor_timelock_execution, event: GovernorTimelockExecutionEvent);␊ + component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ + ␊ + // Extensions (external)␊ + #[abi(embed_v0)]␊ + impl QuorumFractionImpl = GovernorVotesQuorumFractionComponent::QuorumFractionImpl;␊ + #[abi(embed_v0)]␊ + impl GovernorSettingsAdminImpl = GovernorSettingsComponent::GovernorSettingsAdminImpl;␊ + #[abi(embed_v0)]␊ + impl TimelockedImpl = GovernorTimelockExecutionComponent::TimelockedImpl;␊ + ␊ + // Extensions (internal)␊ + impl GovernorCountingSimpleImpl = GovernorCountingSimpleComponent::GovernorCounting;␊ + impl GovernorQuorumImpl = GovernorVotesQuorumFractionComponent::GovernorQuorum;␊ + impl GovernorVotesImpl = GovernorVotesQuorumFractionComponent::GovernorVotes;␊ + impl GovernorSettingsImpl = GovernorSettingsComponent::GovernorSettings;␊ + impl GovernorTimelockExecutionImpl = GovernorTimelockExecutionComponent::GovernorExecution;␊ + ␊ + // Governor Core␊ + #[abi(embed_v0)]␊ + impl GovernorImpl = GovernorComponent::GovernorImpl;␊ + ␊ + // Internal␊ + impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ + ␊ + // SRC5␊ + #[abi(embed_v0)]␊ + impl SRC5Impl = SRC5Component::SRC5Impl;␊ + ␊ + #[storage]␊ + struct Storage {␊ + #[substorage(v0)]␊ + governor: GovernorComponent::Storage,␊ + #[substorage(v0)]␊ + src5: SRC5Component::Storage,␊ + #[substorage(v0)]␊ + governor_counting: GovernorCountingSimpleComponent::Storage,␊ + #[substorage(v0)]␊ + governor_votes: GovernorVotesQuorumFractionComponent::Storage,␊ + #[substorage(v0)]␊ + governor_settings: GovernorSettingsComponent::Storage,␊ + #[substorage(v0)]␊ + governor_timelock_execution: GovernorTimelockExecutionComponent::Storage,␊ + #[substorage(v0)]␊ + upgradeable: UpgradeableComponent::Storage,␊ + }␊ + ␊ + #[event]␊ + #[derive(Drop, starknet::Event)]␊ + enum Event {␊ + #[flat]␊ + GovernorEvent: GovernorComponent::Event,␊ + #[flat]␊ + SRC5Event: SRC5Component::Event,␊ + #[flat]␊ + GovernorCountingSimpleEvent: GovernorCountingSimpleComponent::Event,␊ + #[flat]␊ + GovernorVotesEvent: GovernorVotesQuorumFractionComponent::Event,␊ + #[flat]␊ + GovernorSettingsEvent: GovernorSettingsComponent::Event,␊ + #[flat]␊ + GovernorTimelockExecutionEvent: GovernorTimelockExecutionComponent::Event,␊ + #[flat]␊ + UpgradeableEvent: UpgradeableComponent::Event,␊ + }␊ + ␊ + #[constructor]␊ + fn constructor(␊ + ref self: ContractState,␊ + votes_token: ContractAddress,␊ + timelock_controller: ContractAddress,␊ + ) {␊ + self.governor.initializer();␊ + self.governor_votes.initializer(votes_token, QUORUM_NUMERATOR);␊ + self.governor_settings.initializer(VOTING_DELAY, VOTING_PERIOD, PROPOSAL_THRESHOLD);␊ + self.governor_timelock_execution.initializer(timelock_controller);␊ + }␊ + ␊ + //␊ + // SNIP12 Metadata␊ + //␊ + ␊ + impl SNIP12MetadataImpl of SNIP12Metadata {␊ + fn name() -> felt252 {␊ + 'OpenZeppelin Governor'␊ + }␊ + ␊ + fn version() -> felt252 {␊ + 'v1'␊ + }␊ + }␊ + ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ + #[abi(embed_v0)]␊ + impl UpgradeableImpl of IUpgradeable {␊ + fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ + self.governor.assert_only_governance();␊ + self.upgradeable.upgrade(new_class_hash);␊ + }␊ + }␊ + }␊ + ` + +## quorum mode absolute + +> Snapshot 1 + + `// SPDX-License-Identifier: MIT␊ + // Compatible with OpenZeppelin Contracts for Cairo ^0.20.0␊ + ␊ + #[starknet::contract]␊ + mod MyGovernor {␊ + use openzeppelin::governance::governor::{DefaultConfig, GovernorComponent};␊ + use openzeppelin::governance::governor::extensions::{␊ + GovernorCountingSimpleComponent, GovernorSettingsComponent,␊ + GovernorTimelockExecutionComponent, GovernorVotesComponent␊ + };␊ + use openzeppelin::governance::governor::extensions::GovernorSettingsComponent::InternalTrait as GovernorSettingsInternalTrait;␊ + use openzeppelin::governance::governor::extensions::GovernorTimelockExecutionComponent::InternalTrait as GovernorTimelockExecutionInternalTrait;␊ + use openzeppelin::governance::governor::extensions::GovernorVotesComponent::InternalTrait as GovernorVotesInternalTrait;␊ + use openzeppelin::governance::governor::GovernorComponent::{␊ + InternalExtendedImpl, InternalTrait as GovernorInternalTrait␊ + };␊ + use openzeppelin::introspection::src5::SRC5Component;␊ + use openzeppelin::upgrades::interface::IUpgradeable;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ + use openzeppelin::utils::cryptography::snip12::SNIP12Metadata;␊ + use starknet::{ClassHash, ContractAddress};␊ + ␊ + const QUORUM: u256 = 200000000000000000000; // 200 * pow!(10, 18)␊ + const VOTING_DELAY: u64 = 86400; // 1 day␊ + const VOTING_PERIOD: u64 = 604800; // 1 week␊ + const PROPOSAL_THRESHOLD: u256 = 0;␊ + ␊ + component!(path: GovernorComponent, storage: governor, event: GovernorEvent);␊ + component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ + component!(path: GovernorCountingSimpleComponent, storage: governor_counting, event: GovernorCountingSimpleEvent);␊ + component!(path: GovernorVotesComponent, storage: governor_votes, event: GovernorVotesEvent);␊ + component!(path: GovernorSettingsComponent, storage: governor_settings, event: GovernorSettingsEvent);␊ + component!(path: GovernorTimelockExecutionComponent, storage: governor_timelock_execution, event: GovernorTimelockExecutionEvent);␊ + component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ + ␊ + // Extensions (external)␊ + #[abi(embed_v0)]␊ + impl VotesTokenImpl = GovernorVotesComponent::VotesTokenImpl;␊ + #[abi(embed_v0)]␊ + impl GovernorSettingsAdminImpl = GovernorSettingsComponent::GovernorSettingsAdminImpl;␊ + #[abi(embed_v0)]␊ + impl TimelockedImpl = GovernorTimelockExecutionComponent::TimelockedImpl;␊ + ␊ + // Extensions (internal)␊ + impl GovernorCountingSimpleImpl = GovernorCountingSimpleComponent::GovernorCounting;␊ + impl GovernorVotesImpl = GovernorVotesComponent::GovernorVotes;␊ + impl GovernorSettingsImpl = GovernorSettingsComponent::GovernorSettings;␊ + impl GovernorTimelockExecutionImpl = GovernorTimelockExecutionComponent::GovernorExecution;␊ + ␊ + // Governor Core␊ + #[abi(embed_v0)]␊ + impl GovernorImpl = GovernorComponent::GovernorImpl;␊ + ␊ + // Internal␊ + impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ + ␊ + // SRC5␊ + #[abi(embed_v0)]␊ + impl SRC5Impl = SRC5Component::SRC5Impl;␊ + ␊ + #[storage]␊ + struct Storage {␊ + #[substorage(v0)]␊ + governor: GovernorComponent::Storage,␊ + #[substorage(v0)]␊ + src5: SRC5Component::Storage,␊ + #[substorage(v0)]␊ + governor_counting: GovernorCountingSimpleComponent::Storage,␊ + #[substorage(v0)]␊ + governor_votes: GovernorVotesComponent::Storage,␊ + #[substorage(v0)]␊ + governor_settings: GovernorSettingsComponent::Storage,␊ + #[substorage(v0)]␊ + governor_timelock_execution: GovernorTimelockExecutionComponent::Storage,␊ + #[substorage(v0)]␊ + upgradeable: UpgradeableComponent::Storage,␊ + }␊ + ␊ + #[event]␊ + #[derive(Drop, starknet::Event)]␊ + enum Event {␊ + #[flat]␊ + GovernorEvent: GovernorComponent::Event,␊ + #[flat]␊ + SRC5Event: SRC5Component::Event,␊ + #[flat]␊ + GovernorCountingSimpleEvent: GovernorCountingSimpleComponent::Event,␊ + #[flat]␊ + GovernorVotesEvent: GovernorVotesComponent::Event,␊ + #[flat]␊ + GovernorSettingsEvent: GovernorSettingsComponent::Event,␊ + #[flat]␊ + GovernorTimelockExecutionEvent: GovernorTimelockExecutionComponent::Event,␊ + #[flat]␊ + UpgradeableEvent: UpgradeableComponent::Event,␊ + }␊ + ␊ + #[constructor]␊ + fn constructor(␊ + ref self: ContractState,␊ + votes_token: ContractAddress,␊ + timelock_controller: ContractAddress,␊ + ) {␊ + self.governor.initializer();␊ + self.governor_votes.initializer(votes_token);␊ + self.governor_settings.initializer(VOTING_DELAY, VOTING_PERIOD, PROPOSAL_THRESHOLD);␊ + self.governor_timelock_execution.initializer(timelock_controller);␊ + }␊ + ␊ + //␊ + // Locally implemented extensions␊ + //␊ + ␊ + impl GovernorQuorum of GovernorComponent::GovernorQuorumTrait {␊ + fn quorum(self: @GovernorComponent::ComponentState, timepoint: u64) -> u256 {␊ + QUORUM␊ + }␊ + }␊ + ␊ + //␊ + // SNIP12 Metadata␊ + //␊ + ␊ + impl SNIP12MetadataImpl of SNIP12Metadata {␊ + fn name() -> felt252 {␊ + 'OpenZeppelin Governor'␊ + }␊ + ␊ + fn version() -> felt252 {␊ + 'v1'␊ + }␊ + }␊ + ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ + #[abi(embed_v0)]␊ + impl UpgradeableImpl of IUpgradeable {␊ + fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ + self.governor.assert_only_governance();␊ + self.upgradeable.upgrade(new_class_hash);␊ + }␊ + }␊ + }␊ + ` + +## quorum mode percent + +> Snapshot 1 + + `// SPDX-License-Identifier: MIT␊ + // Compatible with OpenZeppelin Contracts for Cairo ^0.20.0␊ + ␊ + #[starknet::contract]␊ + mod MyGovernor {␊ + use openzeppelin::governance::governor::{DefaultConfig, GovernorComponent};␊ + use openzeppelin::governance::governor::extensions::{␊ + GovernorCountingSimpleComponent, GovernorSettingsComponent,␊ + GovernorTimelockExecutionComponent, GovernorVotesQuorumFractionComponent␊ + };␊ + use openzeppelin::governance::governor::extensions::GovernorSettingsComponent::InternalTrait as GovernorSettingsInternalTrait;␊ + use openzeppelin::governance::governor::extensions::GovernorTimelockExecutionComponent::InternalTrait as GovernorTimelockExecutionInternalTrait;␊ + use openzeppelin::governance::governor::extensions::GovernorVotesQuorumFractionComponent::InternalTrait as GovernorVotesQuorumFractionInternalTrait;␊ + use openzeppelin::governance::governor::GovernorComponent::{␊ + InternalExtendedImpl, InternalTrait as GovernorInternalTrait␊ + };␊ + use openzeppelin::introspection::src5::SRC5Component;␊ + use openzeppelin::upgrades::interface::IUpgradeable;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ + use openzeppelin::utils::cryptography::snip12::SNIP12Metadata;␊ + use starknet::{ClassHash, ContractAddress};␊ + ␊ + const QUORUM_NUMERATOR: u256 = 400; // 40%␊ + const VOTING_DELAY: u64 = 86400; // 1 day␊ + const VOTING_PERIOD: u64 = 604800; // 1 week␊ + const PROPOSAL_THRESHOLD: u256 = 0;␊ + ␊ + component!(path: GovernorComponent, storage: governor, event: GovernorEvent);␊ + component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ + component!(path: GovernorCountingSimpleComponent, storage: governor_counting, event: GovernorCountingSimpleEvent);␊ + component!(path: GovernorVotesQuorumFractionComponent, storage: governor_votes, event: GovernorVotesEvent);␊ + component!(path: GovernorSettingsComponent, storage: governor_settings, event: GovernorSettingsEvent);␊ + component!(path: GovernorTimelockExecutionComponent, storage: governor_timelock_execution, event: GovernorTimelockExecutionEvent);␊ + component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ + ␊ + // Extensions (external)␊ + #[abi(embed_v0)]␊ + impl QuorumFractionImpl = GovernorVotesQuorumFractionComponent::QuorumFractionImpl;␊ + #[abi(embed_v0)]␊ + impl GovernorSettingsAdminImpl = GovernorSettingsComponent::GovernorSettingsAdminImpl;␊ + #[abi(embed_v0)]␊ + impl TimelockedImpl = GovernorTimelockExecutionComponent::TimelockedImpl;␊ + ␊ + // Extensions (internal)␊ + impl GovernorCountingSimpleImpl = GovernorCountingSimpleComponent::GovernorCounting;␊ + impl GovernorQuorumImpl = GovernorVotesQuorumFractionComponent::GovernorQuorum;␊ + impl GovernorVotesImpl = GovernorVotesQuorumFractionComponent::GovernorVotes;␊ + impl GovernorSettingsImpl = GovernorSettingsComponent::GovernorSettings;␊ + impl GovernorTimelockExecutionImpl = GovernorTimelockExecutionComponent::GovernorExecution;␊ + ␊ + // Governor Core␊ + #[abi(embed_v0)]␊ + impl GovernorImpl = GovernorComponent::GovernorImpl;␊ + ␊ + // Internal␊ + impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ + ␊ + // SRC5␊ + #[abi(embed_v0)]␊ + impl SRC5Impl = SRC5Component::SRC5Impl;␊ + ␊ + #[storage]␊ + struct Storage {␊ + #[substorage(v0)]␊ + governor: GovernorComponent::Storage,␊ + #[substorage(v0)]␊ + src5: SRC5Component::Storage,␊ + #[substorage(v0)]␊ + governor_counting: GovernorCountingSimpleComponent::Storage,␊ + #[substorage(v0)]␊ + governor_votes: GovernorVotesQuorumFractionComponent::Storage,␊ + #[substorage(v0)]␊ + governor_settings: GovernorSettingsComponent::Storage,␊ + #[substorage(v0)]␊ + governor_timelock_execution: GovernorTimelockExecutionComponent::Storage,␊ + #[substorage(v0)]␊ + upgradeable: UpgradeableComponent::Storage,␊ + }␊ + ␊ + #[event]␊ + #[derive(Drop, starknet::Event)]␊ + enum Event {␊ + #[flat]␊ + GovernorEvent: GovernorComponent::Event,␊ + #[flat]␊ + SRC5Event: SRC5Component::Event,␊ + #[flat]␊ + GovernorCountingSimpleEvent: GovernorCountingSimpleComponent::Event,␊ + #[flat]␊ + GovernorVotesEvent: GovernorVotesQuorumFractionComponent::Event,␊ + #[flat]␊ + GovernorSettingsEvent: GovernorSettingsComponent::Event,␊ + #[flat]␊ + GovernorTimelockExecutionEvent: GovernorTimelockExecutionComponent::Event,␊ + #[flat]␊ + UpgradeableEvent: UpgradeableComponent::Event,␊ + }␊ + ␊ + #[constructor]␊ + fn constructor(␊ + ref self: ContractState,␊ + votes_token: ContractAddress,␊ + timelock_controller: ContractAddress,␊ + ) {␊ + self.governor.initializer();␊ + self.governor_votes.initializer(votes_token, QUORUM_NUMERATOR);␊ + self.governor_settings.initializer(VOTING_DELAY, VOTING_PERIOD, PROPOSAL_THRESHOLD);␊ + self.governor_timelock_execution.initializer(timelock_controller);␊ + }␊ + ␊ + //␊ + // SNIP12 Metadata␊ + //␊ + ␊ + impl SNIP12MetadataImpl of SNIP12Metadata {␊ + fn name() -> felt252 {␊ + 'OpenZeppelin Governor'␊ + }␊ + ␊ + fn version() -> felt252 {␊ + 'v1'␊ + }␊ + }␊ + ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ + #[abi(embed_v0)]␊ + impl UpgradeableImpl of IUpgradeable {␊ + fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ + self.governor.assert_only_governance();␊ + self.upgradeable.upgrade(new_class_hash);␊ + }␊ + }␊ + }␊ + ` + +## custom snip12 metadata + +> Snapshot 1 + + `// SPDX-License-Identifier: MIT␊ + // Compatible with OpenZeppelin Contracts for Cairo ^0.20.0␊ + ␊ + #[starknet::contract]␊ + mod MyGovernor {␊ + use openzeppelin::governance::governor::{DefaultConfig, GovernorComponent};␊ + use openzeppelin::governance::governor::extensions::{␊ + GovernorCountingSimpleComponent, GovernorSettingsComponent,␊ + GovernorTimelockExecutionComponent, GovernorVotesQuorumFractionComponent␊ + };␊ + use openzeppelin::governance::governor::extensions::GovernorSettingsComponent::InternalTrait as GovernorSettingsInternalTrait;␊ + use openzeppelin::governance::governor::extensions::GovernorTimelockExecutionComponent::InternalTrait as GovernorTimelockExecutionInternalTrait;␊ + use openzeppelin::governance::governor::extensions::GovernorVotesQuorumFractionComponent::InternalTrait as GovernorVotesQuorumFractionInternalTrait;␊ + use openzeppelin::governance::governor::GovernorComponent::{␊ + InternalExtendedImpl, InternalTrait as GovernorInternalTrait␊ + };␊ + use openzeppelin::introspection::src5::SRC5Component;␊ + use openzeppelin::upgrades::interface::IUpgradeable;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ + use openzeppelin::utils::cryptography::snip12::SNIP12Metadata;␊ + use starknet::{ClassHash, ContractAddress};␊ + ␊ + const QUORUM_NUMERATOR: u256 = 40; // 4%␊ + const VOTING_DELAY: u64 = 86400; // 1 day␊ + const VOTING_PERIOD: u64 = 604800; // 1 week␊ + const PROPOSAL_THRESHOLD: u256 = 0;␊ + ␊ + component!(path: GovernorComponent, storage: governor, event: GovernorEvent);␊ + component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ + component!(path: GovernorCountingSimpleComponent, storage: governor_counting, event: GovernorCountingSimpleEvent);␊ + component!(path: GovernorVotesQuorumFractionComponent, storage: governor_votes, event: GovernorVotesEvent);␊ + component!(path: GovernorSettingsComponent, storage: governor_settings, event: GovernorSettingsEvent);␊ + component!(path: GovernorTimelockExecutionComponent, storage: governor_timelock_execution, event: GovernorTimelockExecutionEvent);␊ + component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ + ␊ + // Extensions (external)␊ + #[abi(embed_v0)]␊ + impl QuorumFractionImpl = GovernorVotesQuorumFractionComponent::QuorumFractionImpl;␊ + #[abi(embed_v0)]␊ + impl GovernorSettingsAdminImpl = GovernorSettingsComponent::GovernorSettingsAdminImpl;␊ + #[abi(embed_v0)]␊ + impl TimelockedImpl = GovernorTimelockExecutionComponent::TimelockedImpl;␊ + ␊ + // Extensions (internal)␊ + impl GovernorCountingSimpleImpl = GovernorCountingSimpleComponent::GovernorCounting;␊ + impl GovernorQuorumImpl = GovernorVotesQuorumFractionComponent::GovernorQuorum;␊ + impl GovernorVotesImpl = GovernorVotesQuorumFractionComponent::GovernorVotes;␊ + impl GovernorSettingsImpl = GovernorSettingsComponent::GovernorSettings;␊ + impl GovernorTimelockExecutionImpl = GovernorTimelockExecutionComponent::GovernorExecution;␊ + ␊ + // Governor Core␊ + #[abi(embed_v0)]␊ + impl GovernorImpl = GovernorComponent::GovernorImpl;␊ + ␊ + // Internal␊ + impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ + ␊ + // SRC5␊ + #[abi(embed_v0)]␊ + impl SRC5Impl = SRC5Component::SRC5Impl;␊ + ␊ + #[storage]␊ + struct Storage {␊ + #[substorage(v0)]␊ + governor: GovernorComponent::Storage,␊ + #[substorage(v0)]␊ + src5: SRC5Component::Storage,␊ + #[substorage(v0)]␊ + governor_counting: GovernorCountingSimpleComponent::Storage,␊ + #[substorage(v0)]␊ + governor_votes: GovernorVotesQuorumFractionComponent::Storage,␊ + #[substorage(v0)]␊ + governor_settings: GovernorSettingsComponent::Storage,␊ + #[substorage(v0)]␊ + governor_timelock_execution: GovernorTimelockExecutionComponent::Storage,␊ + #[substorage(v0)]␊ + upgradeable: UpgradeableComponent::Storage,␊ + }␊ + ␊ + #[event]␊ + #[derive(Drop, starknet::Event)]␊ + enum Event {␊ + #[flat]␊ + GovernorEvent: GovernorComponent::Event,␊ + #[flat]␊ + SRC5Event: SRC5Component::Event,␊ + #[flat]␊ + GovernorCountingSimpleEvent: GovernorCountingSimpleComponent::Event,␊ + #[flat]␊ + GovernorVotesEvent: GovernorVotesQuorumFractionComponent::Event,␊ + #[flat]␊ + GovernorSettingsEvent: GovernorSettingsComponent::Event,␊ + #[flat]␊ + GovernorTimelockExecutionEvent: GovernorTimelockExecutionComponent::Event,␊ + #[flat]␊ + UpgradeableEvent: UpgradeableComponent::Event,␊ + }␊ + ␊ + #[constructor]␊ + fn constructor(␊ + ref self: ContractState,␊ + votes_token: ContractAddress,␊ + timelock_controller: ContractAddress,␊ + ) {␊ + self.governor.initializer();␊ + self.governor_votes.initializer(votes_token, QUORUM_NUMERATOR);␊ + self.governor_settings.initializer(VOTING_DELAY, VOTING_PERIOD, PROPOSAL_THRESHOLD);␊ + self.governor_timelock_execution.initializer(timelock_controller);␊ + }␊ + ␊ + //␊ + // SNIP12 Metadata␊ + //␊ + ␊ + impl SNIP12MetadataImpl of SNIP12Metadata {␊ + fn name() -> felt252 {␊ + 'Governor'␊ + }␊ + ␊ + fn version() -> felt252 {␊ + 'v3'␊ + }␊ + }␊ + ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ + #[abi(embed_v0)]␊ + impl UpgradeableImpl of IUpgradeable {␊ + fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ + self.governor.assert_only_governance();␊ + self.upgradeable.upgrade(new_class_hash);␊ + }␊ + }␊ + }␊ + ` + +## all options + +> Snapshot 1 + + `// SPDX-License-Identifier: MIT␊ + // Compatible with OpenZeppelin Contracts for Cairo ^0.20.0␊ + ␊ + #[starknet::contract]␊ + mod MyGovernor {␊ + use openzeppelin::governance::governor::{DefaultConfig, GovernorComponent};␊ + use openzeppelin::governance::governor::extensions::{␊ + GovernorCountingSimpleComponent, GovernorSettingsComponent,␊ + GovernorTimelockExecutionComponent, GovernorVotesComponent␊ + };␊ + use openzeppelin::governance::governor::extensions::GovernorSettingsComponent::InternalTrait as GovernorSettingsInternalTrait;␊ + use openzeppelin::governance::governor::extensions::GovernorTimelockExecutionComponent::InternalTrait as GovernorTimelockExecutionInternalTrait;␊ + use openzeppelin::governance::governor::extensions::GovernorVotesComponent::InternalTrait as GovernorVotesInternalTrait;␊ + use openzeppelin::governance::governor::GovernorComponent::{␊ + InternalExtendedImpl, InternalTrait as GovernorInternalTrait␊ + };␊ + use openzeppelin::introspection::src5::SRC5Component;␊ + use openzeppelin::upgrades::interface::IUpgradeable;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ + use openzeppelin::utils::cryptography::snip12::SNIP12Metadata;␊ + use starknet::{ClassHash, ContractAddress};␊ + ␊ + const QUORUM: u256 = 200;␊ + const VOTING_DELAY: u64 = 345600; // 4 day␊ + const VOTING_PERIOD: u64 = 2419200; // 4 week␊ + const PROPOSAL_THRESHOLD: u256 = 500;␊ + ␊ + component!(path: GovernorComponent, storage: governor, event: GovernorEvent);␊ + component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ + component!(path: GovernorCountingSimpleComponent, storage: governor_counting, event: GovernorCountingSimpleEvent);␊ + component!(path: GovernorVotesComponent, storage: governor_votes, event: GovernorVotesEvent);␊ + component!(path: GovernorSettingsComponent, storage: governor_settings, event: GovernorSettingsEvent);␊ + component!(path: GovernorTimelockExecutionComponent, storage: governor_timelock_execution, event: GovernorTimelockExecutionEvent);␊ + component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ + ␊ + // Extensions (external)␊ + #[abi(embed_v0)]␊ + impl VotesTokenImpl = GovernorVotesComponent::VotesTokenImpl;␊ + #[abi(embed_v0)]␊ + impl GovernorSettingsAdminImpl = GovernorSettingsComponent::GovernorSettingsAdminImpl;␊ + #[abi(embed_v0)]␊ + impl TimelockedImpl = GovernorTimelockExecutionComponent::TimelockedImpl;␊ + ␊ + // Extensions (internal)␊ + impl GovernorCountingSimpleImpl = GovernorCountingSimpleComponent::GovernorCounting;␊ + impl GovernorVotesImpl = GovernorVotesComponent::GovernorVotes;␊ + impl GovernorSettingsImpl = GovernorSettingsComponent::GovernorSettings;␊ + impl GovernorTimelockExecutionImpl = GovernorTimelockExecutionComponent::GovernorExecution;␊ + ␊ + // Governor Core␊ + #[abi(embed_v0)]␊ + impl GovernorImpl = GovernorComponent::GovernorImpl;␊ + ␊ + // Internal␊ + impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ + ␊ + // SRC5␊ + #[abi(embed_v0)]␊ + impl SRC5Impl = SRC5Component::SRC5Impl;␊ + ␊ + #[storage]␊ + struct Storage {␊ + #[substorage(v0)]␊ + governor: GovernorComponent::Storage,␊ + #[substorage(v0)]␊ + src5: SRC5Component::Storage,␊ + #[substorage(v0)]␊ + governor_counting: GovernorCountingSimpleComponent::Storage,␊ + #[substorage(v0)]␊ + governor_votes: GovernorVotesComponent::Storage,␊ + #[substorage(v0)]␊ + governor_settings: GovernorSettingsComponent::Storage,␊ + #[substorage(v0)]␊ + governor_timelock_execution: GovernorTimelockExecutionComponent::Storage,␊ + #[substorage(v0)]␊ + upgradeable: UpgradeableComponent::Storage,␊ + }␊ + ␊ + #[event]␊ + #[derive(Drop, starknet::Event)]␊ + enum Event {␊ + #[flat]␊ + GovernorEvent: GovernorComponent::Event,␊ + #[flat]␊ + SRC5Event: SRC5Component::Event,␊ + #[flat]␊ + GovernorCountingSimpleEvent: GovernorCountingSimpleComponent::Event,␊ + #[flat]␊ + GovernorVotesEvent: GovernorVotesComponent::Event,␊ + #[flat]␊ + GovernorSettingsEvent: GovernorSettingsComponent::Event,␊ + #[flat]␊ + GovernorTimelockExecutionEvent: GovernorTimelockExecutionComponent::Event,␊ + #[flat]␊ + UpgradeableEvent: UpgradeableComponent::Event,␊ + }␊ + ␊ + #[constructor]␊ + fn constructor(␊ + ref self: ContractState,␊ + votes_token: ContractAddress,␊ + timelock_controller: ContractAddress,␊ + ) {␊ + self.governor.initializer();␊ + self.governor_votes.initializer(votes_token);␊ + self.governor_settings.initializer(VOTING_DELAY, VOTING_PERIOD, PROPOSAL_THRESHOLD);␊ + self.governor_timelock_execution.initializer(timelock_controller);␊ + }␊ + ␊ + //␊ + // Locally implemented extensions␊ + //␊ + ␊ + impl GovernorQuorum of GovernorComponent::GovernorQuorumTrait {␊ + fn quorum(self: @GovernorComponent::ComponentState, timepoint: u64) -> u256 {␊ + QUORUM␊ + }␊ + }␊ + ␊ + //␊ + // SNIP12 Metadata␊ + //␊ + ␊ + impl SNIP12MetadataImpl of SNIP12Metadata {␊ + fn name() -> felt252 {␊ + 'MyApp2'␊ + }␊ + ␊ + fn version() -> felt252 {␊ + 'v5'␊ + }␊ + }␊ + ␊ + //␊ + // Upgradeable␊ + //␊ + ␊ + #[abi(embed_v0)]␊ + impl UpgradeableImpl of IUpgradeable {␊ + fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ + self.governor.assert_only_governance();␊ + self.upgradeable.upgrade(new_class_hash);␊ + }␊ + }␊ + }␊ + ` diff --git a/packages/core-cairo/src/governor.test.ts.snap b/packages/core-cairo/src/governor.test.ts.snap new file mode 100644 index 00000000..cbf65b0b Binary files /dev/null and b/packages/core-cairo/src/governor.test.ts.snap differ diff --git a/packages/core-cairo/src/governor.ts b/packages/core-cairo/src/governor.ts new file mode 100644 index 00000000..5ff6fb99 --- /dev/null +++ b/packages/core-cairo/src/governor.ts @@ -0,0 +1,498 @@ +import { contractDefaults as commonDefaults, withCommonDefaults } from './common-options'; +import type { CommonOptions } from './common-options'; +import { ContractBuilder, Contract } from "./contract"; +import { OptionsError } from "./error"; +import { printContract } from "./print"; +import { setInfo } from "./set-info"; +import { setUpgradeableGovernor } from "./set-upgradeable"; +import { defineComponents } from './utils/define-components'; +import { durationToTimestamp } from './utils/duration'; +import { addSNIP12Metadata, addSRC5Component } from './common-components'; +import { toUint } from './utils/convert-strings'; +export const clockModeOptions = ['timestamp'] as const; +export const clockModeDefault = 'timestamp' as const; +export type ClockMode = typeof clockModeOptions[number]; + +const extensionPath = 'openzeppelin::governance::governor::extensions'; +const extensionExternalSection = 'Extensions (external)'; +const extensionInternalSection = 'Extensions (internal)'; + +export const defaults: Required = { + name: 'MyGovernor', + delay: '1 day', + period: '1 week', + votes: 'erc20votes', + clockMode: clockModeDefault, + timelock: 'openzeppelin', + decimals: 18, + proposalThreshold: '0', + quorumMode: 'percent', + quorumPercent: 4, + quorumAbsolute: '', + settings: true, + upgradeable: commonDefaults.upgradeable, + appName: 'OpenZeppelin Governor', + appVersion: 'v1', + info: commonDefaults.info +} as const; + +export const quorumModeOptions = ['percent', 'absolute'] as const; +export type QuorumMode = typeof quorumModeOptions[number]; + +export const votesOptions = ['erc20votes', 'erc721votes'] as const; +export type VotesOptions = typeof votesOptions[number]; + +export const timelockOptions = [false, 'openzeppelin'] as const; +export type TimelockOptions = typeof timelockOptions[number]; + +export function printGovernor(opts: GovernorOptions = defaults): string { + return printContract(buildGovernor(opts)); +} +export interface GovernorOptions extends CommonOptions { + name: string; + delay: string; + period: string; + proposalThreshold?: string; + decimals?: number; + quorumMode?: QuorumMode; + quorumPercent?: number; + quorumAbsolute?: string; + votes?: VotesOptions; + clockMode?: ClockMode; + timelock?: TimelockOptions; + settings?: boolean; + appName?: string; + appVersion?: string; +} + +export function isAccessControlRequired(opts: Partial): boolean { + return false; +} + +function withDefaults(opts: GovernorOptions): Required { + return { + ...opts, + ...withCommonDefaults(opts), + delay: opts.delay ?? defaults.delay, + period: opts.period ?? defaults.period, + proposalThreshold: opts.proposalThreshold || defaults.proposalThreshold, + decimals: opts.decimals ?? defaults.decimals, + quorumPercent: opts.quorumPercent ?? defaults.quorumPercent, + quorumAbsolute: opts.quorumAbsolute ?? defaults.quorumAbsolute, + settings: opts.settings ?? defaults.settings, + quorumMode: opts.quorumMode ?? defaults.quorumMode, + votes: opts.votes ?? defaults.votes, + clockMode: opts.clockMode ?? defaults.clockMode, + timelock: opts.timelock ?? defaults.timelock, + appName: opts.appName ?? defaults.appName, + appVersion: opts.appVersion ?? defaults.appVersion, + }; +} + +export function buildGovernor(opts: GovernorOptions): Contract { + const allOpts = withDefaults(opts); + + const c = new ContractBuilder(allOpts.name); + + validateDecimals(allOpts.decimals); + + addBase(c, allOpts); + addSRC5Component(c, 'SRC5'); + addSNIP12Metadata(c, allOpts.appName, allOpts.appVersion, 'SNIP12 Metadata'); + addCounting(c, allOpts); + addQuorumAndVotes(c, allOpts); + addSettings(c, allOpts); + addExecution(c, allOpts); + setUpgradeableGovernor(c, allOpts.upgradeable); + setInfo(c, allOpts.info); + + return c; +} + +const components = defineComponents( { + GovernorComponent: { + path: 'openzeppelin::governance::governor', + substorage: { + name: 'governor', + type: 'GovernorComponent::Storage', + }, + event: { + name: 'GovernorEvent', + type: 'GovernorComponent::Event', + }, + impls: [{ + name: 'GovernorImpl', + value: 'GovernorComponent::GovernorImpl', + section: 'Governor Core', + }], + }, + GovernorSettingsComponent: { + path: extensionPath, + substorage: { + name: 'governor_settings', + type: 'GovernorSettingsComponent::Storage', + }, + event: { + name: 'GovernorSettingsEvent', + type: 'GovernorSettingsComponent::Event', + }, + impls: [{ + name: 'GovernorSettingsAdminImpl', + value: 'GovernorSettingsComponent::GovernorSettingsAdminImpl', + section: extensionExternalSection, + }, { + name: 'GovernorSettingsImpl', + value: 'GovernorSettingsComponent::GovernorSettings', + embed: false, + section: extensionInternalSection, + }], + }, + GovernorVotesComponent: { + path: extensionPath, + substorage: { + name: 'governor_votes', + type: 'GovernorVotesComponent::Storage', + }, + event: { + name: 'GovernorVotesEvent', + type: 'GovernorVotesComponent::Event', + }, + impls: [{ + name: 'VotesTokenImpl', + value: 'GovernorVotesComponent::VotesTokenImpl', + section: extensionExternalSection, + }, { + name: 'GovernorVotesImpl', + value: 'GovernorVotesComponent::GovernorVotes', + embed: false, + section: extensionInternalSection, + }], + }, + GovernorVotesQuorumFractionComponent: { + path: extensionPath, + substorage: { + name: 'governor_votes', + type: 'GovernorVotesQuorumFractionComponent::Storage', + }, + event: { + name: 'GovernorVotesEvent', + type: 'GovernorVotesQuorumFractionComponent::Event', + }, + impls: [{ + name: 'GovernorQuorumImpl', + value: 'GovernorVotesQuorumFractionComponent::GovernorQuorum', + embed: false, + section: extensionInternalSection, + }, { + name: 'GovernorVotesImpl', + value: 'GovernorVotesQuorumFractionComponent::GovernorVotes', + embed: false, + section: extensionInternalSection, + }, { + name: 'QuorumFractionImpl', + value: 'GovernorVotesQuorumFractionComponent::QuorumFractionImpl', + section: extensionExternalSection, + }], + }, + GovernorCountingSimpleComponent: { + path: extensionPath, + substorage: { + name: 'governor_counting', + type: 'GovernorCountingSimpleComponent::Storage', + }, + event: { + name: 'GovernorCountingSimpleEvent', + type: 'GovernorCountingSimpleComponent::Event', + }, + impls: [{ + name: 'GovernorCountingSimpleImpl', + value: 'GovernorCountingSimpleComponent::GovernorCounting', + embed: false, + section: extensionInternalSection, + }], + }, + GovernorCoreExecutionComponent: { + path: extensionPath, + substorage: { + name: 'governor_execution', + type: 'GovernorCoreExecutionComponent::Storage', + }, + event: { + name: 'GovernorCoreExecutionEvent', + type: 'GovernorCoreExecutionComponent::Event', + }, + impls: [{ + name: 'GovernorCoreExecutionImpl', + value: 'GovernorCoreExecutionComponent::GovernorExecution', + embed: false, + section: extensionInternalSection, + }], + }, + GovernorTimelockExecutionComponent: { + path: extensionPath, + substorage: { + name: 'governor_timelock_execution', + type: 'GovernorTimelockExecutionComponent::Storage', + }, + event: { + name: 'GovernorTimelockExecutionEvent', + type: 'GovernorTimelockExecutionComponent::Event', + }, + impls: [{ + name: 'TimelockedImpl', + value: 'GovernorTimelockExecutionComponent::TimelockedImpl', + section: extensionExternalSection, + }, { + name: 'GovernorTimelockExecutionImpl', + value: 'GovernorTimelockExecutionComponent::GovernorExecution', + embed: false, + section: extensionInternalSection, + }], + }, +}); + +function addBase(c: ContractBuilder, _: GovernorOptions) { + c.addUseClause('starknet', 'ContractAddress'); + c.addUseClause('openzeppelin::governance::governor', 'DefaultConfig'); + c.addConstructorArgument({ name: 'votes_token', type: 'ContractAddress' }); + c.addUseClause('openzeppelin::governance::governor::GovernorComponent', 'InternalTrait', { alias: 'GovernorInternalTrait' }); + c.addComponent(components.GovernorComponent, [], true); +} + +function addSettings(c: ContractBuilder, allOpts: Required) { + c.addConstant({ + name: 'VOTING_DELAY', + type: 'u64', + value: getVotingDelay(allOpts).toString(), + comment: allOpts.delay, + inlineComment: true, + }); + c.addConstant({ + name: 'VOTING_PERIOD', + type: 'u64', + value: getVotingPeriod(allOpts).toString(), + comment: allOpts.period, + inlineComment: true, + }); + c.addConstant({ + name: 'PROPOSAL_THRESHOLD', + type: 'u256', + ...getProposalThreshold(allOpts), + inlineComment: true, + }); + + if (allOpts.settings) { + c.addUseClause(`${extensionPath}::GovernorSettingsComponent`, 'InternalTrait', { alias: 'GovernorSettingsInternalTrait' }); + c.addComponent(components.GovernorSettingsComponent, [ + { lit: 'VOTING_DELAY' }, + { lit: 'VOTING_PERIOD' }, + { lit: 'PROPOSAL_THRESHOLD' }, + ], true); + } else { + addSettingsLocalImpl(c, allOpts); + } +} + +function getVotingDelay(opts: Required): number { + try { + if (opts.clockMode === 'timestamp') { + return durationToTimestamp(opts.delay); + } else { + throw new Error('Invalid clock mode'); + } + } catch (e) { + if (e instanceof Error) { + throw new OptionsError({ + delay: e.message, + }); + } else { + throw e; + } + } +} + +function getVotingPeriod(opts: Required): number { + try { + if (opts.clockMode === 'timestamp') { + return durationToTimestamp(opts.period); + } else { + throw new Error('Invalid clock mode'); + } + } catch (e) { + if (e instanceof Error) { + throw new OptionsError({ + period: e.message, + }); + } else { + throw e; + } + } +} + +function validateDecimals(decimals: number) { + if (!/^\d+$/.test(decimals.toString())) { + throw new OptionsError({ + decimals: 'Not a valid number', + }); + } +} + +function getProposalThreshold({ proposalThreshold, decimals, votes }: Required): {value: string, comment?: string} { + if (!/^\d+$/.test(proposalThreshold)) { + throw new OptionsError({ + proposalThreshold: 'Not a valid number', + }); + } + + if (/^0+$/.test(proposalThreshold) || decimals === 0 || votes === 'erc721votes') { + return { value: proposalThreshold }; + } else { + let value = `${BigInt(proposalThreshold)*BigInt(10)**BigInt(decimals)}`; + value = toUint(value, 'proposalThreshold', 'u256').toString(); + return { value: `${value}`, comment: `${proposalThreshold} * pow!(10, ${decimals})` }; + } +} + +function addSettingsLocalImpl(c: ContractBuilder, _: Required) { + const settingsTrait = { + name: 'GovernorSettings', + of: 'GovernorComponent::GovernorSettingsTrait', + tags: [], + section: 'Locally implemented extensions', + priority: 2, + }; + c.addImplementedTrait(settingsTrait); + + c.addFunction(settingsTrait, { + name: 'voting_delay', + args: [{ + name: 'self', + type: '@GovernorComponent::ComponentState' + }], + returns: 'u64', + code: ['VOTING_DELAY'], + }); + + c.addFunction(settingsTrait, { + name: 'voting_period', + args: [{ + name: 'self', + type: '@GovernorComponent::ComponentState' + }], + returns: 'u64', + code: ['VOTING_PERIOD'], + }); + + c.addFunction(settingsTrait, { + name: 'proposal_threshold', + args: [{ + name: 'self', + type: '@GovernorComponent::ComponentState' + }], + returns: 'u256', + code: ['PROPOSAL_THRESHOLD'], + }); +} + +function addQuorumAndVotes(c: ContractBuilder, allOpts: Required) { + if (allOpts.quorumMode === 'percent') { + if (allOpts.quorumPercent > 100) { + throw new OptionsError({ + quorumPercent: 'Invalid percentage', + }); + } + + addVotesQuorumFractionComponent(c, allOpts.quorumPercent); + } + else if (allOpts.quorumMode === 'absolute') { + if (!numberPattern.test(allOpts.quorumAbsolute)) { + throw new OptionsError({ + quorumAbsolute: 'Not a valid number', + }); + } + + let quorum: string; + let comment = ''; + if (allOpts.decimals === 0 || allOpts.votes === 'erc721votes') { + quorum = `${allOpts.quorumAbsolute}`; + } else { + quorum = `${BigInt(allOpts.quorumAbsolute)*BigInt(10)**BigInt(allOpts.decimals)}`; + quorum = toUint(quorum, 'quorumAbsolute', 'u256').toString(); + comment = `${allOpts.quorumAbsolute} * pow!(10, ${allOpts.decimals})`; + } + + addVotesComponent(c, allOpts); + addQuorumLocalImpl(c, quorum, comment); + } +} + +function addVotesQuorumFractionComponent(c: ContractBuilder, quorumNumerator: number) { + c.addConstant({ + name: 'QUORUM_NUMERATOR', + type: 'u256', + value: (quorumNumerator * 10).toString(), + comment: `${quorumNumerator}%`, + inlineComment: true, + }); + c.addUseClause(`${extensionPath}::GovernorVotesQuorumFractionComponent`, 'InternalTrait', { alias: 'GovernorVotesQuorumFractionInternalTrait' }); + c.addComponent(components.GovernorVotesQuorumFractionComponent, [ + { lit: 'votes_token' }, + { lit: 'QUORUM_NUMERATOR' }, + ], true); +} + +function addVotesComponent(c: ContractBuilder, _: Required) { + c.addUseClause(`${extensionPath}::GovernorVotesComponent`, 'InternalTrait', { alias: 'GovernorVotesInternalTrait' }); + c.addComponent(components.GovernorVotesComponent, [ + { lit: 'votes_token' }, + ], true); +} + +function addQuorumLocalImpl(c: ContractBuilder, quorum: string, comment: string) { + c.addConstant({ + name: 'QUORUM', + type: 'u256', + value: quorum, + comment, + inlineComment: true, + }); + const quorumTrait = { + name: 'GovernorQuorum', + of: 'GovernorComponent::GovernorQuorumTrait', + tags: [], + section: 'Locally implemented extensions', + priority: 1, + }; + c.addImplementedTrait(quorumTrait); + + c.addFunction(quorumTrait, { + name: 'quorum', + args: [{ + name: 'self', + type: '@GovernorComponent::ComponentState' + }, { + name: 'timepoint', + type: 'u64', + }], + returns: 'u256', + code: ['QUORUM'], + }); +} + +function addCounting(c: ContractBuilder, _: Required) { + c.addComponent(components.GovernorCountingSimpleComponent, [], false); +} + +function addExecution(c: ContractBuilder, { timelock }: Required) { + if (timelock === false) { + c.addComponent(components.GovernorCoreExecutionComponent, [], false); + } else { + c.addConstructorArgument({ name: 'timelock_controller', type: 'ContractAddress' }); + c.addUseClause(`${extensionPath}::GovernorTimelockExecutionComponent`, 'InternalTrait', { alias: 'GovernorTimelockExecutionInternalTrait' }); + c.addComponent(components.GovernorTimelockExecutionComponent, [ + { lit: 'timelock_controller' }, + ], true); + } +} + +export const numberPattern = /^(?!$)(\d*)(?:\.(\d+))?(?:e(\d+))?$/; diff --git a/packages/core-cairo/src/index.ts b/packages/core-cairo/src/index.ts index 7551f94a..c799d08f 100644 --- a/packages/core-cairo/src/index.ts +++ b/packages/core-cairo/src/index.ts @@ -25,4 +25,4 @@ export { sanitizeKind } from './kind'; export { contractsVersion, contractsVersionTag, compatibleContractsSemver } from './utils/version'; -export { erc20, erc721, erc1155, account, custom } from './api'; +export { erc20, erc721, erc1155, account, governor, custom } from './api'; diff --git a/packages/core-cairo/src/kind.ts b/packages/core-cairo/src/kind.ts index 9dcd2710..0f6ee068 100644 --- a/packages/core-cairo/src/kind.ts +++ b/packages/core-cairo/src/kind.ts @@ -18,6 +18,7 @@ function isKind(value: Kind | T): value is Kind { case 'ERC721': case 'ERC1155': case 'Account': + case 'Governor': case 'Custom': return true; diff --git a/packages/core-cairo/src/print.ts b/packages/core-cairo/src/print.ts index 153521e0..496a3a5c 100644 --- a/packages/core-cairo/src/print.ts +++ b/packages/core-cairo/src/print.ts @@ -1,11 +1,16 @@ import 'array.prototype.flatmap/auto'; -import type { Contract, Component, Argument, Value, Impl, ContractFunction, } from './contract'; +import type { Contract, Component, Argument, Value, Impl, ContractFunction, ImplementedTrait, UseClause, } from './contract'; import { formatLines, spaceBetween, Lines } from './utils/format-lines'; import { getSelfArg } from './common-options'; import { compatibleContractsSemver } from './utils/version'; +const DEFAULT_SECTION = '1. with no section'; +const STANDALONE_IMPORTS_GROUP = 'Standalone Imports'; +const MAX_USE_CLAUSE_LINE_LENGTH = 90; +const TAB = "\t"; + export function printContract(contract: Contract): string { const contractAttribute = contract.account ? '#[starknet::contract(account)]' : '#[starknet::contract]' return formatLines( @@ -19,7 +24,8 @@ export function printContract(contract: Contract): string { `${contractAttribute}`, `mod ${contract.name} {`, spaceBetween( - printImports(contract), + printUseClauses(contract), + printConstants(contract), printComponentDeclarations(contract), printImpls(contract), printStorage(contract), @@ -41,25 +47,123 @@ function printSuperVariables(contract: Contract): string[] { return withSemicolons(contract.superVariables.map(v => `const ${v.name}: ${v.type} = ${v.value}`)); } -function printImports(contract: Contract): string[] { - const lines: string[] = []; - sortImports(contract).forEach(i => lines.push(`use ${i}`)); - return withSemicolons(lines); +function printUseClauses(contract: Contract): Lines[] { + const useClauses = sortUseClauses(contract); + + // group by containerPath + const grouped = useClauses.reduce( + (result: { [containerPath: string]: UseClause[] }, useClause: UseClause) => { + if (useClause.groupable) { + (result[useClause.containerPath] = result[useClause.containerPath] || []).push(useClause); + } else { + (result[STANDALONE_IMPORTS_GROUP] = result[STANDALONE_IMPORTS_GROUP] || []).push(useClause); + } + return result; + }, {}); + + const lines = Object.entries(grouped).flatMap(([groupName, group]) => getLinesFromUseClausesGroup(group, groupName)); + return lines.flatMap(line => splitLongUseClauseLine(line.toString())); } -function sortImports(contract: Contract): string[] { - const componentImports = contract.components.flatMap(c => `${c.path}::${c.name}`); - const allImports = componentImports.concat(contract.standaloneImports); - const superVars = contract.superVariables; - if (superVars.length === 1) { - allImports.push(`super::${superVars[0]!.name}`); - } else if (superVars.length > 1) { - allImports.push(`super::{${superVars.map(v => v.name).join(', ')}}`); +function getLinesFromUseClausesGroup(group: UseClause[], groupName: string): Lines[] { + const lines = []; + if (groupName === STANDALONE_IMPORTS_GROUP) { + for (const useClause of group) { + const alias = useClause.alias ?? ''; + if (alias.length > 0) { + lines.push(`use ${useClause.containerPath}::${useClause.name} as ${alias};`); + } else { + lines.push(`use ${useClause.containerPath}::${useClause.name};`); + } + } + } else { + if (group.length == 1) { + const alias = group[0]!.alias ?? ''; + if (alias.length > 0) { + lines.push(`use ${groupName}::${group[0]!.name} as ${alias};`); + } else { + lines.push(`use ${groupName}::${group[0]!.name};`); + } + + } else if (group.length > 1) { + let clauses = group.reduce((clauses, useClause) => { + const alias = useClause.alias ?? ''; + if (alias.length > 0) { + clauses += `${useClause.name} as ${useClause.alias}, `; + } else { + clauses += `${useClause.name}, `; + } + return clauses; + }, ''); + clauses = clauses.slice(0, -2); + + lines.push(`use ${groupName}::{${clauses}};`); + } } - return allImports.sort(); + return lines; } -function printComponentDeclarations(contract: Contract): string[] { +// TODO: remove this when we can use a formatting js library +function splitLongUseClauseLine(line: string): Lines[] { + const lines = []; + + const containsBraces = line.indexOf('{') !== -1; + if (containsBraces && line.length > MAX_USE_CLAUSE_LINE_LENGTH) { + // split at the first brace + lines.push(line.slice(0, line.indexOf('{') + 1)); + lines.push(...splitLongLineInner(line.slice(line.indexOf('{') + 1, -2))); + lines.push("};"); + } else { + lines.push(line); + } + return lines; +} + +function splitLongLineInner(line: string): Lines[] { + const lines = []; + if (line.length > MAX_USE_CLAUSE_LINE_LENGTH) { + const max_accessible_string = line.slice(0, MAX_USE_CLAUSE_LINE_LENGTH); + const lastCommaIndex = max_accessible_string.lastIndexOf(','); + if (lastCommaIndex !== -1) { + lines.push(TAB + max_accessible_string.slice(0, lastCommaIndex + 1)); + lines.push(...splitLongLineInner(line.slice(lastCommaIndex + 2))); + } else { + lines.push(TAB + max_accessible_string); + } + } else { + lines.push(TAB + line); + } + return lines; +} + +function sortUseClauses(contract: Contract): UseClause[] { + return contract.useClauses.sort((a, b) => { + const aFullPath = `${a.containerPath}::${a.name}`; + const bFullPath = `${b.containerPath}::${b.name}`; + return aFullPath.localeCompare(bFullPath); + }); +} + +function printConstants(contract: Contract): Lines[] { + const lines = []; + for (const constant of contract.constants) { + // inlineComment is optional, default to false + const inlineComment = constant.inlineComment ?? false; + const commented = !!constant.comment; + + if (commented && !inlineComment) { + lines.push(`// ${constant.comment}`); + lines.push(`const ${constant.name}: ${constant.type} = ${constant.value};`); + } else if (commented) { + lines.push(`const ${constant.name}: ${constant.type} = ${constant.value}; // ${constant.comment}`); + } else { + lines.push(`const ${constant.name}: ${constant.type} = ${constant.value};`); + } + } + return lines; +} + +function printComponentDeclarations(contract: Contract): Lines[] { const lines = []; for (const component of contract.components) { lines.push(`component!(path: ${component.name}, storage: ${component.substorage.name}, event: ${component.event.name});`); @@ -68,18 +172,36 @@ function printComponentDeclarations(contract: Contract): string[] { } function printImpls(contract: Contract): Lines[] { - const externalImpls = contract.components.flatMap(c => c.impls); - const internalImpls = contract.components.flatMap(c => c.internalImpl ? [c.internalImpl] : []); - - return spaceBetween( - externalImpls.flatMap(impl => printImpl(impl)), - internalImpls.flatMap(impl => printImpl(impl, true)) + const impls = contract.components.flatMap(c => c.impls); + + // group by section + const grouped = impls.reduce( + (result: { [section: string]: Impl[] }, current:Impl) => { + // default section depends on embed + // embed defaults to true + const embed = current.embed ?? true; + const section = current.section ?? (embed ? 'External' : 'Internal'); + (result[section] = result[section] || []).push(current); + return result; + }, {}); + + const sections = Object.entries(grouped).sort((a, b) => a[0].localeCompare(b[0])).map( + ([section, impls]) => printSection(section, impls as Impl[]), ); + return spaceBetween(...sections); } -function printImpl(impl: Impl, internal = false): string[] { +function printSection(section: string, impls: Impl[]): Lines[] { const lines = []; - if (!internal) { + lines.push(`// ${section}`); + impls.map(impl => lines.push(...printImpl(impl))); + return lines; +} + +function printImpl(impl: Impl): Lines[] { + const lines = []; + // embed is optional, default to true + if (impl.embed ?? true) { lines.push('#[abi(embed_v0)]'); } lines.push(`impl ${impl.name} = ${impl.value};`); @@ -119,8 +241,6 @@ function printEvents(contract: Contract): (string | string[])[] { } function printImplementedTraits(contract: Contract): Lines[] { - const impls = []; - // sort first by priority, then number of tags, then name const sortedTraits = contract.implementedTraits.sort((a, b) => { if (a.priority !== b.priority) { @@ -132,23 +252,53 @@ function printImplementedTraits(contract: Contract): Lines[] { return a.name.localeCompare(b.name); }); - for (const trait of sortedTraits) { - const implLines = []; - implLines.push(...trait.tags.map(t => `#[${t}]`)); - implLines.push(`impl ${trait.name} of ${trait.of} {`); - - const superVars = withSemicolons( - trait.superVariables.map(v => `const ${v.name}: ${v.type} = ${v.value}`) - ); - implLines.push(superVars); + // group by section + const grouped = sortedTraits.reduce( + (result: { [section: string]: ImplementedTrait[] }, current:ImplementedTrait) => { + // default to no section + const section = current.section ?? DEFAULT_SECTION; + (result[section] = result[section] || []).push(current); + return result; + }, {}); + + const sections = Object.entries(grouped).sort((a, b) => a[0].localeCompare(b[0])).map( + ([section, impls]) => printImplementedTraitsSection(section, impls as ImplementedTrait[]), + ); - const fns = trait.functions.map(fn => printFunction(fn)); - implLines.push(spaceBetween(...fns)); + return spaceBetween(...sections); +} - implLines.push('}'); - impls.push(implLines); +function printImplementedTraitsSection(section: string, impls: ImplementedTrait[]): Lines[] { + const lines = []; + const isDefaultSection = section === DEFAULT_SECTION; + if (!isDefaultSection) { + lines.push('//'); + lines.push(`// ${section}`); + lines.push('//'); } - return spaceBetween(...impls); + impls.forEach((trait, index) => { + if (index > 0 || !isDefaultSection) { + lines.push(''); + } + lines.push(...printImplementedTrait(trait)); + }); + return lines; +} + +function printImplementedTrait(trait: ImplementedTrait): Lines[] { + const implLines = []; + implLines.push(...trait.tags.map(t => `#[${t}]`)); + implLines.push(`impl ${trait.name} of ${trait.of} {`); + + const superVars = withSemicolons( + trait.superVariables.map(v => `const ${v.name}: ${v.type} = ${v.value}`) + ); + implLines.push(superVars); + + const fns = trait.functions.map(fn => printFunction(fn)); + implLines.push(spaceBetween(...fns)); + implLines.push('}'); + return implLines; } function printFunction(fn: ContractFunction): Lines[] { @@ -172,9 +322,9 @@ function printFunction(fn: ContractFunction): Lines[] { } function printConstructor(contract: Contract): Lines[] { - const hasParentParams = contract.components.some(p => p.initializer !== undefined && p.initializer.params.length > 0); + const hasInitializers = contract.components.some(p => p.initializer !== undefined); const hasConstructorCode = contract.constructorCode.length > 0; - if (hasParentParams || hasConstructorCode) { + if (hasInitializers || hasConstructorCode) { const parents = contract.components .filter(hasInitializer) .flatMap(p => printParentConstructor(p)); @@ -220,7 +370,8 @@ export function printValue(value: Value): string { if ('lit' in value) { return value.lit; } else if ('note' in value) { - return `${printValue(value.value)} /* ${value.note} */`; + // TODO: add /* ${value.note} */ after lsp is fixed + return `${printValue(value.value)}`; } else { throw Error('Unknown value type'); } @@ -240,11 +391,11 @@ export function printValue(value: Value): string { // generic for functions and constructors // kindedName = 'fn foo' function printFunction2( - kindedName: string, - args: string[], - tag: string | undefined, - returns: string | undefined, - returnLine: string | undefined, + kindedName: string, + args: string[], + tag: string | undefined, + returns: string | undefined, + returnLine: string | undefined, code: Lines[] ): Lines[] { const fn = []; @@ -256,7 +407,7 @@ function printFunction2( let accum = `${kindedName}(`; if (args.length > 0) { - let formattedArgs = args.join(', '); + const formattedArgs = args.join(', '); if (formattedArgs.length > 80) { fn.push(accum); accum = ''; @@ -275,13 +426,10 @@ function printFunction2( } fn.push(accum); - fn.push(code); - if (returnLine !== undefined) { fn.push([returnLine]); } - fn.push('}'); return fn; diff --git a/packages/core-cairo/src/set-access-control.ts b/packages/core-cairo/src/set-access-control.ts index 328ad337..7bd3c221 100644 --- a/packages/core-cairo/src/set-access-control.ts +++ b/packages/core-cairo/src/set-access-control.ts @@ -15,7 +15,7 @@ export type Access = typeof accessOptions[number]; case 'ownable': { c.addComponent(components.OwnableComponent, [{ lit: 'owner' }], true); - c.addStandaloneImport('starknet::ContractAddress'); + c.addUseClause('starknet', 'ContractAddress'); c.addConstructorArgument({ name: 'owner', type: 'ContractAddress'}); break; @@ -40,10 +40,10 @@ export type Access = typeof accessOptions[number]; } addSRC5Component(c); - c.addStandaloneImport('starknet::ContractAddress'); + c.addUseClause('starknet', 'ContractAddress'); c.addConstructorArgument({ name: 'default_admin', type: 'ContractAddress'}); - c.addStandaloneImport('openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE'); + c.addUseClause('openzeppelin::access::accesscontrol', 'DEFAULT_ADMIN_ROLE'); c.addConstructorCode('self.accesscontrol._grant_role(DEFAULT_ADMIN_ROLE, default_admin)'); } break; @@ -76,7 +76,7 @@ export function requireAccessControl( const roleId = roleIdPrefix + '_ROLE'; const addedSuper = c.addSuperVariable({ name: roleId, type: 'felt252', value: `selector!("${roleId}")` }) if (roleOwner !== undefined) { - c.addStandaloneImport('starknet::ContractAddress'); + c.addUseClause('starknet', 'ContractAddress'); c.addConstructorArgument({ name: roleOwner, type: 'ContractAddress'}); if (addedSuper) { c.addConstructorCode(`self.accesscontrol._grant_role(${roleId}, ${roleOwner})`); @@ -101,16 +101,14 @@ const components = defineComponents( { name: 'OwnableEvent', type: 'OwnableComponent::Event', }, - impls: [ - { - name: 'OwnableMixinImpl', - value: 'OwnableComponent::OwnableMixinImpl', - }, - ], - internalImpl: { + impls: [{ + name: 'OwnableMixinImpl', + value: 'OwnableComponent::OwnableMixinImpl', + }, { name: 'OwnableInternalImpl', + embed: false, value: 'OwnableComponent::InternalImpl', - }, + }], }, AccessControlComponent: { path: 'openzeppelin::access::accesscontrol', @@ -122,10 +120,10 @@ const components = defineComponents( { name: 'AccessControlEvent', type: 'AccessControlComponent::Event', }, - impls: [], - internalImpl: { + impls: [{ name: 'AccessControlInternalImpl', + embed: false, value: 'AccessControlComponent::InternalImpl', - }, + }], }, }); diff --git a/packages/core-cairo/src/set-royalty-info.ts b/packages/core-cairo/src/set-royalty-info.ts index 0a7ef470..5464be10 100644 --- a/packages/core-cairo/src/set-royalty-info.ts +++ b/packages/core-cairo/src/set-royalty-info.ts @@ -48,7 +48,7 @@ export function setRoyaltyInfo(c: ContractBuilder, options: RoyaltyInfoOptions, ]; c.addComponent(components.ERC2981Component, initParams, true); - c.addStandaloneImport('starknet::ContractAddress'); + c.addUseClause('starknet', 'ContractAddress'); c.addConstructorArgument({ name: 'default_royalty_receiver', type: 'ContractAddress'}); switch (access) { @@ -67,9 +67,9 @@ export function setRoyaltyInfo(c: ContractBuilder, options: RoyaltyInfoOptions, c.addConstructorCode('self.accesscontrol._grant_role(ERC2981Component::ROYALTY_ADMIN_ROLE, royalty_admin)'); break; } - + if (feeDenominator === DEFAULT_FEE_DENOMINATOR) { - c.addStandaloneImport('openzeppelin::token::common::erc2981::DefaultConfig'); + c.addUseClause('openzeppelin::token::common::erc2981', 'DefaultConfig'); } else { const trait: BaseImplementedTrait = { name: 'ERC2981ImmutableConfig', @@ -120,11 +120,12 @@ const components = defineComponents({ { name: 'ERC2981InfoImpl', value: 'ERC2981Component::ERC2981InfoImpl', + }, + { + name: 'ERC2981InternalImpl', + value: 'ERC2981Component::InternalImpl', + embed: false } ], - internalImpl: { - name: 'ERC2981InternalImpl', - value: 'ERC2981Component::InternalImpl', - }, }, }); diff --git a/packages/core-cairo/src/set-upgradeable.ts b/packages/core-cairo/src/set-upgradeable.ts index a419439d..30793da2 100644 --- a/packages/core-cairo/src/set-upgradeable.ts +++ b/packages/core-cairo/src/set-upgradeable.ts @@ -18,12 +18,13 @@ function setUpgradeableBase(c: ContractBuilder, upgradeable: Upgradeable): BaseI c.addComponent(components.UpgradeableComponent, [], false); - c.addStandaloneImport('openzeppelin::upgrades::interface::IUpgradeable'); - c.addStandaloneImport('starknet::ClassHash'); + c.addUseClause('openzeppelin::upgrades::interface', 'IUpgradeable'); + c.addUseClause('starknet', 'ClassHash'); const t: BaseImplementedTrait = { name: 'UpgradeableImpl', of: 'IUpgradeable', + section: 'Upgradeable', tags: [ 'abi(embed_v0)' ], @@ -40,6 +41,14 @@ export function setUpgradeable(c: ContractBuilder, upgradeable: Upgradeable, acc } } +export function setUpgradeableGovernor(c: ContractBuilder, upgradeable: Upgradeable): void { + const trait = setUpgradeableBase(c, upgradeable); + if (trait !== undefined) { + c.addUseClause('openzeppelin::governance::governor::GovernorComponent', 'InternalExtendedImpl'); + c.addFunctionCodeBefore(trait, functions.upgrade, 'self.governor.assert_only_governance()'); + } +} + export function setAccountUpgradeable(c: ContractBuilder, upgradeable: Upgradeable, type: Account): void { const trait = setUpgradeableBase(c, upgradeable); if (trait !== undefined) { @@ -65,11 +74,11 @@ const components = defineComponents( { name: 'UpgradeableEvent', type: 'UpgradeableComponent::Event', }, - impls: [], - internalImpl: { + impls: [{ name: 'UpgradeableInternalImpl', + embed: false, value: 'UpgradeableComponent::InternalImpl', - }, + }], }, }); diff --git a/packages/core-cairo/src/test.ts b/packages/core-cairo/src/test.ts index e8651979..a6d7fce7 100644 --- a/packages/core-cairo/src/test.ts +++ b/packages/core-cairo/src/test.ts @@ -63,7 +63,7 @@ test('is access control required', async t => { for (const contract of generateSources('all')) { const regexOwnable = /(use openzeppelin::access::ownable::OwnableComponent)/gm; - if (contract.options.kind !== 'Account' && !contract.options.access) { + if (contract.options.kind !== 'Account' && contract.options.kind !== 'Governor' && !contract.options.access) { if (isAccessControlRequired(contract.options)) { t.regex(contract.source, regexOwnable, JSON.stringify(contract.options)); } else { diff --git a/packages/core-cairo/src/utils/duration.ts b/packages/core-cairo/src/utils/duration.ts new file mode 100644 index 00000000..de24b28c --- /dev/null +++ b/packages/core-cairo/src/utils/duration.ts @@ -0,0 +1,26 @@ +const durationUnits = ['second', 'minute', 'hour', 'day', 'week', 'month', 'year'] as const; +type DurationUnit = typeof durationUnits[number]; +export const durationPattern = new RegExp(`^(\\d+(?:\\.\\d+)?) +(${durationUnits.join('|')})s?$`); + +const second = 1; +const minute = 60 * second; +const hour = 60 * minute; +const day = 24 * hour; +const week = 7 * day; +const month = 30 * day; +const year = 365 * day; +const secondsForUnit = { second, minute, hour, day, week, month, year }; + +export function durationToTimestamp(duration: string): number { + const match = duration.trim().match(durationPattern); + + if (!match) { + throw new Error('Bad duration format'); + } + + const value = parseFloat(match[1]!); + const unit = match[2]! as DurationUnit; + + const durationSeconds = value * secondsForUnit[unit]; + return Math.round(durationSeconds); +} diff --git a/packages/ui/src/cairo/App.svelte b/packages/ui/src/cairo/App.svelte index f8071449..4c7d037f 100644 --- a/packages/ui/src/cairo/App.svelte +++ b/packages/ui/src/cairo/App.svelte @@ -8,6 +8,7 @@ import ERC1155Controls from './ERC1155Controls.svelte'; import CustomControls from './CustomControls.svelte'; import AccountControls from './AccountControls.svelte'; + import GovernorControls from './GovernorControls.svelte'; import CopyIcon from '../icons/CopyIcon.svelte'; import CheckIcon from '../icons/CheckIcon.svelte'; import DownloadIcon from '../icons/DownloadIcon.svelte'; @@ -54,7 +55,7 @@ opts.symbol = initialOpts.symbol ?? opts.symbol; break; case 'Account': - break; + case 'Governor': case 'ERC1155': case 'Custom': } @@ -117,6 +118,9 @@ + @@ -165,6 +169,9 @@
+
+ +
diff --git a/packages/ui/src/cairo/GovernorControls.svelte b/packages/ui/src/cairo/GovernorControls.svelte new file mode 100644 index 00000000..8dcf9995 --- /dev/null +++ b/packages/ui/src/cairo/GovernorControls.svelte @@ -0,0 +1,231 @@ + + +
+

Settings

+ + + +
+ + + +
+ + + + + +

+ + Token amounts above will be extended with this number of zeroes. Does not apply to ERC721Votes. +

+ +
+ + +
+
+ +
+

Votes

+ +
+ + + +
+
+ +
+

+ + +

+ +
+ +
+
+ +
+

+ + +

+ +
+ +
+
+ +
+

+ + +

+ + + + +
+ +