From 355d098b2085adbd5bc4049a05f5b47f59b5c92a Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Thu, 12 Dec 2024 17:44:10 +0100 Subject: [PATCH] Add Governor (#417) --- packages/core-cairo/CHANGELOG.md | 2 + packages/core-cairo/src/account.test.ts.md | 156 +- packages/core-cairo/src/account.test.ts.snap | Bin 1731 -> 1783 bytes packages/core-cairo/src/account.ts | 14 +- packages/core-cairo/src/add-pausable.ts | 13 +- packages/core-cairo/src/api.ts | 7 + packages/core-cairo/src/build-generic.ts | 6 +- packages/core-cairo/src/common-components.ts | 18 +- packages/core-cairo/src/contract.test.ts | 16 +- packages/core-cairo/src/contract.test.ts.md | 9 + packages/core-cairo/src/contract.test.ts.snap | Bin 715 -> 720 bytes packages/core-cairo/src/contract.ts | 55 +- packages/core-cairo/src/custom.test.ts.md | 76 +- packages/core-cairo/src/custom.test.ts.snap | Bin 1319 -> 1351 bytes packages/core-cairo/src/erc1155.test.ts.md | 432 ++--- packages/core-cairo/src/erc1155.test.ts.snap | Bin 3353 -> 3417 bytes packages/core-cairo/src/erc1155.ts | 16 +- packages/core-cairo/src/erc20.test.ts.md | 472 +++--- packages/core-cairo/src/erc20.test.ts.snap | Bin 2730 -> 2779 bytes packages/core-cairo/src/erc20.ts | 23 +- packages/core-cairo/src/erc721.test.ts.md | 405 +++-- packages/core-cairo/src/erc721.test.ts.snap | Bin 3490 -> 3527 bytes packages/core-cairo/src/erc721.ts | 37 +- packages/core-cairo/src/generate/governor.ts | 30 + packages/core-cairo/src/generate/sources.ts | 7 + packages/core-cairo/src/governor.test.ts | 180 +++ packages/core-cairo/src/governor.test.ts.md | 1419 +++++++++++++++++ packages/core-cairo/src/governor.test.ts.snap | Bin 0 -> 2322 bytes packages/core-cairo/src/governor.ts | 498 ++++++ packages/core-cairo/src/index.ts | 2 +- packages/core-cairo/src/kind.ts | 1 + packages/core-cairo/src/print.ts | 252 ++- packages/core-cairo/src/set-access-control.ts | 28 +- packages/core-cairo/src/set-royalty-info.ts | 15 +- packages/core-cairo/src/set-upgradeable.ts | 19 +- packages/core-cairo/src/test.ts | 2 +- packages/core-cairo/src/utils/duration.ts | 26 + packages/ui/src/cairo/App.svelte | 9 +- packages/ui/src/cairo/GovernorControls.svelte | 231 +++ 39 files changed, 3729 insertions(+), 747 deletions(-) create mode 100644 packages/core-cairo/src/generate/governor.ts create mode 100644 packages/core-cairo/src/governor.test.ts create mode 100644 packages/core-cairo/src/governor.test.ts.md create mode 100644 packages/core-cairo/src/governor.test.ts.snap create mode 100644 packages/core-cairo/src/governor.ts create mode 100644 packages/core-cairo/src/utils/duration.ts create mode 100644 packages/ui/src/cairo/GovernorControls.svelte 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 0c6195e84506b6521864a5521856fa2ffdae58b3..a013fa64f04464e7787db06f8f16d27c94eee0c3 100644 GIT binary patch literal 1783 zcmV#Vp!&1hKk~L#S!GT`nr5WA|)M-XUG@ zo=;nhHXUXMoO(gq6~WgJTP-T+=hwvxOV^hMujiJRUV5Hguhq!$(cWhppV%hj0oyoe zF)nP&X1+lV4?Zo`YNYOVJSyy_!^pWU+T@nU_!rFcm}7HNce(JXDFR}-KB-gNcgdHV z)ve9yW~p@JZXl?C%9$_>Gi+E6Z+QKr)Nxznu)jMxCJ#!45Yi18aXrTGhXWW!*xoS0 zhJ)L2IpbnyN(Y+@-wixw3ftv|5%}h|VI1GCZ)f%lT^9^(FyEpkGmL{fi9@qHN{uzc zCGMy@GzdPTL3^h(ylO^`*UBChZG()@wn75o`t%+%l7BfnV_d{d_XkJoJ9=}<{3Tlh z@5F`%jZ&@XW+xewmR@XA>JphA+OE~eeoru;Q)hU5<1TI5W!7o3R^x1Q{bYF3?s!f# zy~Dx!J{X+1IpLgmam0<@j~3>!pn`pn40^z&L1p{Vg{ecx4JORT)};B4S=2c%!)oZ6 z(7_|01j6r{f*g;|h1(`<*KLMP%drawuV@QtCKZ~gT*At5BdH7NvHDA^L%)*7tX)LY zAFia6@Sw$f`;3+MeAlZ;`)RbcMvWNncF6FA;vLJOBDouR)94&Cyil3iJ>Du49?9r9 zz8|K!LNXIO!gTrQzwi1ZgBB;!xw6kJ5-`Uyh_a9>#OpR4+iaY&zCkSJh^_6db;&n_ zKGkrMRBdhxn>zM==9iOxVMMry_EEH*q??zoWNc}9lMIesi^ySiY#&H>YVl|pO`j}h z=M8fZUK?#1v<(u6T6xM7)22bde9>^Z({Btel*1V-jin_V{asdvlX_i*9=j+-nR_EW zb90w(q-O7Ho|3)kwFS-I`OKK}nAQrGfQp|oauw^7$n`esd5&$`5FHR55FL4m&RU*= z=z!>e=z!>mQg<~YbwhPPb>u9s6)Xc4KWF4B*e9Xu)g}#WGucO}VQS?yB}~1zvY=r~ z-xDe$k1FH%cKyAnAu_tC#r|}gb=qOhE$;MFjVrAlf0XUe_;_dxuRshz49z^T={iCT zEv^`PbBri5#n1A~3RSEuFDO;yGm|6T&Me&)EHM^8mE|f2#SzsDJCGJL9qKb*Bh1c~ z5ZZ{V7k6A1ILG08#)c zfRw9)lxQcWV2a!XpaM_ z+*Q<%5`n$IUSKb<7uahC>{U?;rZUmqjneYv3J?CHkl3F^Dm=(UyAdDk$1~65tGJJZ zSNozJXOQ_OI*p?wc9MJ=vs2PzUfC|0pZp&kU)c1tC%D1|bKBlA(g-`F3N>lCUri?EXAQT`J zAQa&272w(=%w!kV|5gE-uZmPyKaW6@cZfiy&qby$W=@`$ESk^s7YFhniQsAV{Qp%V z_ur7BkfM;HMN3d)-&fX-k(ZwefYOE1h0=x6ow?HODu9$yitaxJksbk&fJi{3;vv%5 zSBs}WQeG<20h549z$9Q&t}rRJQc6R?q@yBLN&zMTlYmLO3Mtw_o_dj#^igtACj~qP z9s`eo$7arBy|*-P?4|#h!s;Cb%{~O00nLDBMMJYIev=Om$N*%S{Q+bEG6317fGqV{ z+0P1){RkifkO9a5WOx(@@&oyS{6K!iAip*3N60eR?-zyreggY}{lI?3W4|kZS_b|D Z|AGJX1P1;C|ILv9{s&sHVxq{u001J9SwsK; literal 1731 zcmV;!20ZyeRzVR^kY_)AJh#MeaXITlQkp9_9<>10fRa%J(s;#yl z0ZWM{&UiDbGq&tWw^`@`&Rn=55QlO@;=qwl0H1*Gz=1mlF35>v&p3|V(q?NXPfkrT z^G@dN%=`Qv$C)#$X*=eT|J{o}G0COPPL^8CqFq}Ot83eYnx@kgvPL@mgbVT(>AH_R z+G4b6GwuuO`fW%0U!ApDRMJmwt~@t)b1ry1Ge7sjv$t-pu9AcO?T?o~;3gA3Ti$Ik zA-TnwXOO+!4=byyr0#TFDtXgpXds9`Fw3< zeQjl}Qn~Zcm()8FOd5t6Hmrspc5Z9zNipFNY`h?ahZ4$4qzBzd&3AD z1|P=}OvueK9k`I53H-JGva?aJ7z*gO?QH4OPlH8wD~Ks zg6u?rf<~E9($b;?Qoi%balE#4*ng3CTzfd3y1~0rj zl8k6EM2+4VF2n;#CA$|6qQ=_|{yBo$V?(M9M#4qWl=&ngrX?pQYM6;IfrA|Q((9U% z91LCyw?){l+YFmlqm%`Y;TB1mR2Zgqjwt<&qA!#S^;iD;=_@4>?Q}T({z^FvpR}0A zk6CrwbKIJ;Uj}Pu(1?j{hxA|2vSZm)#-B#r6lsa+zfl|8J=zK*8OiCGT<_yjp@fMN zVLD>)-*>!0KuZwiwW`M~;xpSah_;Yw#O*e1ZZ?is&mb1F<@(0@l9HRC&q}yRR=D7j zQ=30wUN!C)?)cNZ&8aT`;JITFwbUh6xbhh+Fj*nAjdoxqM|9x_;0NFb z;0Lb354_x@J~!iilFk2rYGvqm@IUy!X#9Whp#JvQk~n-b70|O|)@g^?_l4cd46e1h z_$V7;@MI|r-+@hmO@U2;O_`8Qc`d;L`L^UAjR*dMEh&-)Lnz^%rbUDbr5;hmbi)p$ z#Y~%e%o{C{3wN~=`TD|)mdNy;uuQN_mr;W4aNms`Ky6Sul}Y7M*fH2K*s&R~V_pmw zuI=>F9oWK#h8J%DFMt=oi>t$n;m*qd47CXm1Bd~{0AiF4F$M`EN355E7(Zx;@eL3I zhyld7D#Y0D@4WZf_z|=g|2KO7BjyhgH3P^1WB@V%nUa9a$t%fkVrto!O}^Eb=4&tw zmsUIH(Hm%vMx`_aPaZ8AB; z^sh!te}kAnOdzJR+%f}d0yTk}Kuw^gOHorzJD`%u_SR5P&vy{q&l*F0U#5c~m~1zq zCp*#1a~UVkxk2sUW8ZP49($%hYu4}uRW zf^toZ))Z4D;-dKK;NVZS7-km0g*~kR-Ye5BG({|c={@0lisgHhn{v`i-__lhGdBLU z9h(Yo25$y$25&Y=Z+3eWLvp>?{E>ztpUneBX4#8Dqv03JuYbi9uBcG^afQx0`TQ5H zGXDsZ2$KktSabnO{NgorjO#j79Uc@O6dn{Fbb=nVtD#NC0b;*uaB~K@0o(v?iVru5 zAE%DNo9jA141fc`0pI{|o)X|>oszNmk_I@HMF0)}2Y^#>z)7BtkvhngACQqf%C(%4 z0g?hqfuulEle}HwR?634*~iW=KCeO59H0tN1*j@IR89CRFsI3EP1GRzLicf75zd{9a Z1G$0R1`m)M$ZaCz_8%rshS?mt007RzLBIe2 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 86a5513b7768429e847d78d7010546c25033f5c9..f18abae37cf688fe8e500e2154a60e171287084e 100644 GIT binary patch literal 720 zcmV;>0x$hRRzV)Hsgq4RK^_U+&lN&gl7+@BNoj>q{}U2Afgzr zO#Hg}pf>XT<}Df7K`R56aH*?9`vxUgOk^2sIkPc*sU5K5$VHDnCPWs2I~$ z8B}SO!1fuV(INqo)92lMV}<3leROa9)1KSx^r{O`*^^%-!4qAs)2tj|R=tg1t2g73 zs~_Hlnm0vFsH>^8VkHvw0S#orh;)v2%Xezp{aE_%+Knw1BL_hy_&5j#M0r8dsCl#0 zESjtz`vnH7n00X42Ox>o0Z&nL0ol%Pq@)CKsHWvHEg;+TS_Y4mS=Rbmj~a1v6#c_Vv0g3f?Aeh|#E1^tTLU zIlmJPOGZl&>TwE1pw@>>1YcI4s4&|?5u9n@Z~VM4ksV3YsaU~ZExhn#bQ%!4 literal 715 zcmV;+0yO$fPALqC;B5c^P-4i4ecY{%mdz+(7&@EBoCc?X@9^Z_q{XV3gtT)Z z0|}*guHzSTcN;C=p1UF~duXje2ba3ubZAh5#Y{$%x`r$m+dfW}fN~s+bi#^s*zTXB zbopXRoz-Hl63R$lGyLZaFEkmJ9_r|gQIeT8xbGUY7FUecebi_K;~pEKc-LD+til4# zo?^_~&ZzPtgY^?eqeTWJC(m1@V~yp-9rSO)qn>y6dNl>8`IMIv5ylL#JkpD4I&^-ItnUU-2@Y_7sge!f?${QSvv| z$T8+Xs7Eyef4xKh#SWbYKLFR*_?;mQ000-iS=s;q 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 10ce3638eb4d89c3090d1c27cc8177b58adfabcc..fb2302b7eeddbd77ce0c80d27359a3cdb8356a92 100644 GIT binary patch literal 1351 zcmV-N1-SY_RzV+%8M;$_Wh<;vKUR_yUX*Axv7n1OE1`=ae8J;xyp@(*^wIjM|AcRnC z8gg<5CrMLCK5!*ENS`U2VPn`(cteHP1D^~6DGET3=YO}5{xUx;NCyH?7y zOm(;jzb3w>wvl^K1bGjt${ zgl|WkcA3#>65jxRiO)z;BIq?{%r{2B*rjnWZqPqY;kslE7Gn zYuzK7ULz%7tSCc0{GDBxcUl{%5wJlYB@Zlgen8}C6!|i(0+zgN zRfaK3vkZ~pp5bvrmQF&*(?C8$#PjG*HHF%PPUklu=1Z zKtBL)Ca!8J4s|i>nl_M|Z|+!EX5Gi_&`0LRl`BSLkUrBDRSlKFrQ^o?mD3}lhf%h7 znP>}$i4ef06SCmiNf0*`WXswpXZ^cr_h)zw^SsrI$Uu}b^YOyJ7GeFpFoT38z#VWZ zuQAqnz<5vndg*Lez+rHbMw^k6Hl7g4O^}Ws$e$XhqM$;OM)P0EXwOH^+0bkrEdlX_ zv^*K-y-8__q1%VCvo%$q-q;1?v!tRcrN$WagkCYrX-AfLxX<_o?8!!`yDAYl zwI+PLCOp6Gz@|ROcz$J9pJUYL81*?ueU4FcR>oPE>0XZ#jtB$f(L^G6GyB2eA_rI{ zyXNaDhF&;C)wEFK}$Cjd2HKZ>tqj=p#pK*>k*g_cELUrqKKL{dKJXz%;| zjm@onXMcBl3nL!_xw^KB-o~&YF0EJ1*OtxecsCsj@umM&PB6aNNZOsWZS3`%Ti*bflQ9gd7>>riA_7;^F#h1d-8GC4_B(4Yhg38BK?EFQEB95DTa~$tC9PCv zJZZVzO2SqOjks}wvv9G|^ijD5(j@fqq+wj{@BnhR0^|s}s?(QC^!6&Q1o!~bPgbp6 zaxYjk6c<@_lI{=?*#awM=NXkp)=3pFX9nuFm_xiiWd%vn%Fka>wWKBm?P67+rC{`K zQDN$wal)h%vvIRXGA(<+2EX4C%G$D98Jw9_Qg$XxJylG{__fv5*ZK=dDuC{LG;%!u zpQX0`nZ=`m2j2J?4KcU!Uc#-52kL_QYQ&VD^gs0_hS|AxFm0y=^?iXUy)Q6q{0}lJ Jp$Eb+003ptgXRDL literal 1319 zcmV+?1=#vQRzV`2`f>#>^|{ zO&6PwWgm+O00000000B+TFq|bHV{r*G(~)CpMcq-fCD%`2#^cYEfCmg*Fe$)`9U`= zQh}C6F%g**NGd;Di9 z&p-ZiX>${u9(UfZA5a&Vg!QfmOi`bL!051h*4W%cZ9WKzqP+mnEmeJV6axDZ!Vm(= zP@6L)h^r*>xj=0~1xG(`ZESCCY&9BR{v;I<*9;WKt`@v(47i65?=wa8O9LT@~G>nhZAMtWH1EzLs6!lI^jL(OA{tPY36bPTVfN|HbFjO3ZY6nEhH$?U;Z)${l zo+m)c-9{qgW(!$uhD7x-s#;_V>3zq@h}#x|8(_*(*^jTR?N*yEddx7Zy_%cUqM11z zeWXX5FzA8j+-$9-F-QktkVzlXJIcE8h1aFI^8Lz%zRnzSs)&Mb^dyNr15h{iJ|lrP zTjd>$O`($6;wlRk%L{$f+LQB8%SAmc+RR;+gvJm@^_F9-&9$CjEz5}tFqV~vZ28G9 zU+RGeg5E&0BY4;{;x*m-R0vo!K*wqOUTeW7)(5pgZsONZG&eBcb zA~obQWL#?s@R5YT$H>~xR_wX>Xe;FAnt?J_+t3c)po}U?0{RX_Gf~y4_An|#%!rQ1 z+(+hNQV26+dY@&nQV)W`t>eZ=kJBfzk5PUMnK(*Vh?F3d!&z|eBv_gnj3sRZYWBNn z&u3^o6d9-=l1Nr^?8VAo7WMqGGKbV7!Hon}_ZVk>!1!4Inm67m;WF4IL!Z-2COjd! znjo=`$ny-CCYO>^hWlU3RWC=g`BH2~tXT9566|D(fHBc_p2k&9ngC&sw}_Z5{aZO* z>7eluf0g?GC_fhU!*tdU+8I~CKoA9v5`^aQ8oMY2;ZOww(?$Dt#v#G|e0&xwTX75e zj-5?DOVYd6Ph)UKc6@B46IsZgvc8DD*b1|$9;@!IA8Vp4dJEH6qb+(1i{8Sbx3K6f z7>qJ=wL#84x9O>klGC0C$fF5!d2`#&zbOFL&R#I@3^4C3_ACAqb4EZL8ziYOfpAXgN41M@#Kd=CxdE*o_^Yn~Q}$JbzoDOct+p zQXyoY!swPlfraZPnO%0bbF&uUGnhWfQahw(xKb!5QN5E!R1J9omAvx-%Z+@JI?B!k z^aocC@dlKY>X24(|H`FGDpD#~tO&Hqmh3dB5p}KvVakb#x>@Fwmc3wu`bU_uj^tJj zX9mkB8>3l7m4S}Gpt}1i>$|5_&r>@a7t8-zCDuRl_@w{Lk0@sP!-WwEv-rATN?PnM d{T;ykyt$vghx^4_<|%#4{2u|X1`oe40032reHs7& 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 af295dcb7112a1a855132d0692c0dbf391b50620..ee615fb389db7c1778b57cf1ffced23782e6329d 100644 GIT binary patch literal 3417 zcmV-f4W{xzRzVtHZcft*B61R&TLqpV}PhIS4FoLP=dG;UZ_Q5>diDa!FtbE~i>_d28~glQWaTU&~9)jDc=-{OjO6#nIrdYLe>4WR84YRAxG<=vNwl3(h@vD5eHp3tm}5@9dS1{**h8_6qK;{s{-X^4_J3LZasFBcUfi4`*T#cjS;BVn=7nXCoVbNNwI`0$R2pNM3 z#nf*g#lHdNi8)sNXaUGjf+XcS8n!<(--bVWgc)a~w#zKLF5I2Ld<_Z_>JE_q2T3cs ziTSV>;?0+(5dT6ww|acbr8H4cQM|vhR3KE36`)x(u(rhlK{`dk-)fBL$RVb#AZg;% zJym|lqS6bRh3hswQbn%Hq(Vy9nEt~l3A;w@#0%hI19QgH5Lu|gGa#1_dBi=_z` zN=VEyH@J7>N)hgg>^lgY#p3G8Wh76N;B$h{S#F;*e27HP5@DK)R|=kI;+h`XQS_7& z%eK&4okr_b{&*=lS2fQ;Qv2BHD=2oBreHo{v5dag4Si1{0uS6Bu?60zt@-C z_1E|A)Lr-27<6*fR*zeqPU}cLI(XGmkWNg#xwVP5y%7^{1$tO}lqluh>|yo8Umi7f z3o46cysA?`3c>$=UCUIItA_u(8T=NUzunf0#>uOW+SuJ|@B1Cdb>IO@q_IR?-n9u+ zlq<=U_2lF!7x>7VGO;*mj>U4NYRd^nBo%~>WNTAVQe|(`Rud1%SPjM%<_3o3@yjyv zh5*3mcECt}IOM7sK+>2XDZTXND|e27DQ+asMT`sdh>l&8tGG8XXbMRU%el<(9Cn@o zx9Z6`l2>F=aG7*-NR3Aio1CKRDZ`Yjp6^;qyH#~rnWI}3MJ0TQx}fYagvfqLWQvMG zO?mtxV#(4Zz|RuE&mxnG^LqM#)TS14Z4Y~T_|auX8k2tTZwZtB>jMZORUh`12*phY zWMztmT%Nh1rm13^qz)iMXkuJ5TH12w8%+Rdvcy2z5*jmvR3Ue8meGiQ*JU(2)A^$Z zlGAtZBXIgE?)25sDdDPyO_MMcm(dY~T%syEf{;rDxkP1i1R$?%E(NmDSx%GJ+ong}@!H=Y4XcCTs2Q%8vcuFTdLqm_6MGv>5in2uS6L^?4 z*{Y6;ZJSwVq^If@Q?Y5*LRs}t(vy1Djl`J6JU?W=angBtaMXU&+D-K8I_Qj`%@Y~qzLvpQNY?7f|ghI+Ff~3fFv9zc#P!v<3C?aKs@>7Nw-Y}KtKjMMP z;xbeMd`j?H3_c}Z+p|msyv$s98EK8qGz<_si%IN=3#%Vii5Z)`M~`31=W#}Q-(8|x zjHrGN6v;!9=|zqGnFf`Mt`!L8btrVod}MjSYHTIJr`{VD=-0ML+-P&VKTxOI6F54? z^uKrK>Yq6FKbiK0S(Td{FrmT#z5{%p(0sRi!8C&J`I{bn`f~}!uYWp&O^^24`vn^w z2_=Nhj$p4OpeAm-SCTM=>IgPYf{l}4KdpG7Nr#%V$SlpOhg-0f*WWpv~9Gm$V)mC{=n!bU6^j&du@VfD;^I96B zG*K!>6hZ29<;bJ?raoW%G?Px!T!&kOQ7IJnA4`1Fk6{bJLdqt&d@UbCQzF6zGA1Bn zV!;Ux$d~{kqgV=LOjM1$fQ$*qm>7>Y*x1_G+{!)|B6!jbTpn283nqrALnK$cM4_R= zf@tlFR!iM&?H}y5_ZyvqBL%q|n_r-9w6X4eqPEc-Pcwj=4S?Mfn(vk%`|)UyotLul zdkJFOpFqk+sZ%xp|0BrIfD8@D(0~jL$j|^{W8TCDWN0ih$pIM}kfBk+42_6s8Pyu( zXpG9y0AdPqM1ZUs&!l&oBf@ppG!eDvQ$bFeu6odt=&H{j%z&;sY@8gAW}Ac(Lz-&V zhgejN;c|%PGJ{_#N_<$mk~$N7Zf`Utoz!feD&d_V{{UxfnuMwNW(QLUQ>*0MRmygP zq{zatH0dn(xv^oDqO2m7hVoP97~WmLhXEh9kbGD?L1l3nQ+eL}8ZcqW`td_N%UpA1 z)RvnAlb*Dh#+e<7Ru1;do5>?Ns_C4n0_0e^USEf zpTZi+b99MrF`~M54|9@t8b-R2_^U57(Sm%Ah0d%&;b9qfd$>uGk}(NK5r|hEug?Ji zps)HEGQ5(^Ba&;ZM$g=c&7l@o{h8UTWpFWQj_jo0t2`!a61qyb8?(r&STjMxW7CZ; zom-EirpG@~#$`00EX+MKCV60zct}#_to8W~w4FhAB&VyPN6n&#+fhYXqW1|@Rg<4q zj*4xYS!blD>K0S6X%0`62_!wKXDvO9SOZBTj0{P(}L|nt+4d;9xg6*bNSL z8%tpjxt?<5Iu5$pe$aJfz!m*h3b_6ULBJK>MyO1zb`f7;xP6qkLN7d&FlY>~P(VBy z;?WR~UZ{99yzjB>QEqr|q?$4FrF!vXMxl3jbp@jHixr(;oL6Qbybs}h2=7C9zmnl! v2=7>pI-~_Pb68 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 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 caabfc5adebfcb7cb66f82a481ac73e4765c7916..42e963093102131a963546147234838e409def3e 100644 GIT binary patch literal 2779 zcmV<13MBPGRzVNFL{9DCLV3(-9Bm{U zpHHT}4IhgL00000000B+T}^M}xEY>yP;@8Q9qa&m*rHp2lR1n7I3E)rJ#e}Uq)FNh zI?1H@Sads>3XDu8LS#yiC{MD%9QqG>>U|6JC-mG)Zv}cT`Ue*M14V&e3hK+GOv{cf z+miD7;xFDoCLOssBdm=v=MXJYUo|~q(jNM zL+yYOFSvAh@cVB&9m2`i58pm~@WTh<^}QcFc=G+jhwJO;wu4c0I!FbBCgLHoru#J<5JdJ&!szLpv_xJ~4TKEZ0Xn#P(hEyN$KY zjkS%XrDtyfPW&rIImTv^@aE8bi0HQLSaCW>rwVif{HO0|6&|93*+0p zT2^!?cza&EV1_ndZ&-p0z?=tsNjIdR?t``TurCg}5AnHZ}H zewG^TgcDA`=oh!oq~iL>>CZ#J<-hgNq93A0$8`?4ADSGU#J?qdkfaOGlccSziQ*M^ z#6ZyrL_13NJ}oS==-cE=hx&Gpwsw8j6Shx>Lu~0d5oKW)ML#HYu^httHR$)xU^Swj zbCob%7Pr&&V-SlW>9>|oEfi44!bmaMic|&h_gd8QHJjPoCXW3L^;^ry;9YK`<%82- zEw8*xN`AkTT$NYSMLBp4eh@0xp!GpTuR&s(Gzc(u-!UEn-rP_s{xM+~|x_VolBa#<|^bNDzEUg3ESh(d|yhr$JEa+@b~2RZ@bJ=JX6y z%2EiO?==ZF>Ddf2NxGm}uoyk5n~a}tSvEo!GSg;AQpe=*biF(-YSOeE;-CqtvKka4 zNCR3w`0s?4&QKb2RBwgSWzAp9!)!7FM!tS^#wc-}Yzw1{1u8dHPQHF-Ig;K~@-=zo^oSFRxq5T!r&?kXTOz_3Tw+=)34n%f07ILap?M?>^bGAI zqA;}MkDA8N0&0f7&2KPHjezk{^68HBPMy`N&Esaz*#?X#VWpWa!6&R zSYT?#1bd(h`a`?X6fzg58K=v_0%;C2c z5X*PF0~TxN$}w%vj{2}L9qGEENF!MQ6R-~si%`- z*FRFVSgf6V*P+3nEc^IxiY)uf$1{~>(WH%zw$D!Xj*a8jul6vqsKYn6Hsfoais}4m zYgtMmrrtQ)+0ieLw|9#(DrrR45|m*49_4i%jBmH2?>q5#iSY04{bKv<)v2+)d$4~P zRbZ$K-WGWSkDA>}IEsRf&ceX%f4po_1`p~03#<$WKX{%$Sj*@iPpvqvCQJ7&X z*$N9#Mwf&u#$E;|5`ok$QR*uFBR4_c-x%vNG(!9;P0N7}GY1Ia>4mVmehoGC9T21S zN}W+aR8J(T2j}nM9W(+eo4W^kW`W8)D`Xgt&JuK}MM8%gq|>!ofv}7u!=R>b=LgrY zBqfM{<$_Xjrfb`fq{f9$7&inJZw<1=wrYdoQe`NG3B~pqKeNJ|+L`shkI{dDAEOjM zhB^jiC7d6{Rq<<-RO5T(=NMrzWwI&X^YKo-O|W1$`tg$D_V^#{MmNJxu$a3FVTZb5 zvK@A)VTT%asOu)CVTW4E0Xx*7>|lp_7CY4A)DiAruHCk|o9vqVv?~-$M-v184@ETo z6=LA49%KdqWs4VT_0dugP&OI?0?KM1P*y;W7b8b>*kTQCWi@T17aO`41lN~9e0+uY zh*rb-Kfrx}`vCU=?gQMXS=?vQ?pB~E(?pjGexl#cfAnXCp8OHc{{eaed+5!fC$KGD z9-$~kY0P#q>;`KV>*}5LlQ?=N@Kwp1wcRfuX>p*blma4D8_!g;^hxZg)cbRfJ%vcoMbYIt2XjL3B?L`YgqTCjW13*x zn8)abB#3#Gp_COkwol11kIm9TBLcG|bAmRytMO(W)piw&rJl=m^62rdB9FEnH_h{X z;r7JU!UXq^Y=H4s;;o)hY`I+Ab^?q||Hk9)g-^W88;qIDOaXKly-$V_Fxz{viSfzd z{?Uug1ImdQER}Q7=b9)X#YV`W;)I1*>Y$LIqCt}(Makf{hN*;5+#3mUt`F03I{|Fe zH3_QPo5>~L=q--8g(_0s3UDt+{F+|hC6nyn=)D6*yc!L365LTTsWOyic}>rZ$lRaU z2fGCBWT`{oAh9_08x}X%4abQcG`iua_`zthS>rxofkl0z=W?4}7$LKH&=M_^^x^o* zET)Gj<%a|6Eb3&HL#7?A{;GB)BVF2BL91V6TOg`oo*#T|>~0?&8Hd{kd(Wjx${;=J z2e!)!ae6PFk7{D=#pgUX=C~v^+i4GIH0Q4s&G~cCoS->DbAsjs%?X+lG$&|I(43$- zL31L|oK4i6Db81W$0z%*4?%#csi(X%^fN_)GMBANfSS0UwxUFTQq{Ph`3lN;E4+p) zHqb%CbWklc%DvNZCDBt5V)Bq`Rr8IY;%}Paj$_LSqgK zx(^;XUDkyhKMIaLaO{C&4;*{o*aOGj=t_ZOuO5!QTzerN;V$tAPxa2w!V{}M{g2`o z{qEB_oLGIdeRfiO@U)boe_}NpbUm?;ck&am!8=?*?{J2pJK|fqcIJNGclmzhnw%gG z{^|z!t7mm)dU2`X!Jg8CJ-g%L!JA!-P?k5ldI#8pXS`aT@hY6d-$eI%R>;Wn|Htt= zj{A&&$g@=RjDUJQL|_76|Bzy4^Z)`y62!)@($foI#{+geV8^2_J02q*Fd@w~RoMY4 hsm8D)QiJEWzz&H#oz!55WI@lX`9Cj4&yncS001yrdQSiV literal 2730 zcmV;b3RU$%RzVYtRw~emIHY? zorzzt-ye$z00000000B+T}^M~wi(`Z5j1OH(JYX|7R`a{9Ci$hz1{(~2W}I%I5yJ^In{{b$e6>G9rgHecB$WdYqh=uyUP z%ced?hX-eC&z_-Ox9<^dcO8n}+WZo|_9*);^*rj>4DGs%`^4k{vRohS65Dst@3yx( z+gsafYoB}-aN=Jv$}u+Mgm2dRZVw&aoViz&p>Ng@LTC_B|s^K!q_{-_@eD1ne!G7Q4HwS&sdASzmG!vjFEsyX^j8ynG3b^Z&3yKq~(jjF$ zPPQ-JZ^THSd_}r;i}t&;XAHMD-h^M;eb0%~9@^J769uDBGiAipOB4JeG2Uj7%=%~J(TE)uu)MR1MUw@j!vWR;$Dc;4Z3mCR@x--ip-iTI)-S6>E0!U zg%*1gf9O%)9@5sH?|Qn!1#Q$^i3>ol*<;g z$08=h_&`D!WgMAr*C9dhISDScKgPD*>GgaX1ZA!^S|D9(B{*pxNI|76h0xi4mSE$t zkV3{um$WVxqsMiT@v|*S$M90t-V{kPdG06I!xn zY0Oc*JxiB0J6FfqWCDylKXt|^ap!Ccql+yovl7m~qoz6H-c<60g{52Xgrz~Afa0@j zA$hUS%nGT(7E1=^_+~Tu)-c7^U|f>m5~FmRkXxQ>3kd@1bHioMjS;q`CAB(DEzOGL zeM>D*%JnYGLs)2P)E)RtF9;qC6)JM^0H{b4sYpJ_1?7fG9EbV_0m1@=1qcfe79cD@ zSXM(=Vq;tg!a_JTxKHeKYzq^4)HiHS`^wsUEiEIim3}@GnUyh4<6qPnXR(kNjW^Sf zI0LaUbzb~jYnW(Qgc$klw6zffOu^4QG6?ki?BP>|pFMuqG=3IPbKu+j2IIsC7$3*) z7DDbS%h49hzH&yDuoBa!a7p3?kuEJ)(KH5RZ~vD&=daF;oxQ_@qp-5$0Bn&X@TkdcS7=4we1Y-l$?gk~m9xA42Ojk? z{ze*JZFN|^tDy$f4@e1C8G9+VlC7`+Wwc4SVl1X`A`xiYTWDLQKjbFp`!}-?)m!Z< zP04_cYd$F7+bdsnR~l>T84$z$NnJ5OMbD+8^Xv2Y4w?X!uFbigS)mk93mGSX(gZzf zk%7Yv((Bu-KuLzwI4|Pc*}*j~NeOCSnNUj3WbYc2)VS~oURO4w}9dFfV`-%>c ze^C4!|As^4=BxcxKIjKW%{7$Qxe^mUwWNt3H|u?s82=fV*6^zsprXf>$Fu zbl757ZlyJCqvzYY7hDo6yw&b2BuBIwg6sg#0iFXq2YAi|1mHQf=Q*o(p#mMr(2@8O zx8NfB^Y;heDpceT5M&3a$m~=E&cN$KMc`PuJn~SC(wO65IL!qrQnwSs*qb$nLry-4 zF2QPg=UPD9j{jBJ0PmxTa?&WF9Tt`7VLSQWkTwPo)zHNmsvBl?)?&+S)*y zpQTQ6l~+GK{L%Qd@kqCR=nIRiNxa6Z`h5*{$QG0 ziAH}g>1JZMN^WtVu)w0eF?6}jE{p-QdC(FqlQdX?`l*k&Ugo1vT#|zAWLju6;r|p( z_ycG{(1f4~K@)-|1WgE<5HulZLePYFK@%o8U+kZp9=tvRfd~Sz;R5mcV?`k{mu*Ub znp?b?(3Mra#k*X=w`>L0a0Larq|%z<&hha(&3$jnI_GDXH6e{~kkBZeIHE>Bi>Q$` zaGWWa(WAdA%;>vE6=g=t_n|L88h8af;$!b}Kp=2np0y1jUR*}wsdKfXoi~TrS1ZE# zotGJ_j*MOhnN!nvhn*?n9add{t;}l=k>3C=oj)}^od`k263*Jx)QJgf|!OYmHR=Q8WLyndp0T^5E* ze*7=Ri}}yTO9+>IymNk99Q9aAF$$LqQI=|FtY%=D$1nKlZ_PV13U303y6YHvj+t 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 20507cf4211a74b0556be8a664b20a53e453ee01..cb80f55cb5984868b69be2fd2543c7c18ee4fcf9 100644 GIT binary patch literal 3527 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 B-K+or literal 3490 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 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 0000000000000000000000000000000000000000..cbf65b0b991efd13c0d88ddfb25c4df51daf566f GIT binary patch literal 2322 zcmZ{cdpHvcAIH}bVx*hgl_H(F9?Nx;W8`oYA|jn!TZmHm^GztQnJFF3?Mfdz@V1r>c~l8ylWIiVFMCuqD&PIN7xlR)KQ ze`1bnB$kHaJ2D05#h9nS0YvUSO6}aKrNpa7PU;1^5fpA}=mc43%a6RDw5p>NB`Aet zlr0#Ac(d>~6QZ`EzwyE&1+!#<36zULYaj58Bs#i@^*-5lD>#ze#KS5Bl^WX6 zEsYJZx1ASX^+LFE@7IRpjE~43hys6_M;8VFYhi4V4fdSs_z+Nd7rt~Iw^>DO+~}k` z4y+Y|=Zp}y))<4<65acA+n%3b+Ay9^!ZFynp7pI`6n`WmEUBiB4gL{N9`!1bD-MgGjT&s&wJaA z-GmX7&qs61%Cs=QbDFL@e`zgqQ)3|d2{2I_|NiMl1;Zy~5z=dNP-Z^0;pmM>r8K-l zcg*5jNU8)gg0iR-SjS4qa|SEjE>HcdT_wfdXM4`OJOA#$MW|U3@A0A$B1-OJi2UHx z@?ePS_A?|UZJdCAp8gPvY-H-6If9ZKvBQ|9Y-WHZ{`%vg2I^*p^h zD~0Id*mzB3qrvq%0o{luWJ!O0SYz7LcUKpQxM2h}F@i1xu56~2oQXiwrM8f~;YOYn z?#s%$)vt_vCq>}`OVIH_r}^}1yuO$Mg{h%4k#f-7;-);nmb7YYs+-N2hUHwJKU#rt z*2twgn^i z`eg6Lr*w45tJ-_t=z%SbXlRrdNYToVOAT>#-&RXK<$_JQ@&V!PB6}hJyE*%Ms{n65 zKx*3~m!&R#4~a<9*ynjw)WG zHET^MjcV|_=wv5q9@pQH)m;ATBFY_==^jx-^1oSB0{ab(muMam9Nx`jk12USU7kMi z=hL)q)*s6wpX@T~81Jrh`|TTuKPgLp*Ko!MpKo)|OVE9^(zsXTb&;r?R9!FE4OErYRrIa&^RH;H`CbwV$wU`mU(^4pf(g}AQOC%pSy@Kkj~FbqXO!y?%QrMev(HoW5AiCzO1)@*y4EXJ4`}&| zlxXg#!Pu=e8j=w?*OGSyRVDQ{ zTj_zy`aaf6=C|oNo<^HBA&j`fU=z=j2fQ_RJ?~a_b!75KF3Yx0_D!qcfyaeFxP0KJ z_NdNVa={Y@{<+2Y0TPg9j7HtlwjBf;ntJ;M-n)wpzZ&%E`|)Em?eB;H**!3bu9%7L z;tlPNn&$uB17pZcv@P2Y^(+sel)P^B>`xHh$P*iYk;Lq>uU$y=xv!=;Fp?j&E%U?8f(%!;?kHzZ9-!EFW>Sul}-Z0 zVp<@8e8^ZH27${7*XKn{<`be%ri)mU!qTyO1tV=@tk`ue?0SxY5Z}-|{;cJ(b6Y_$ zkV?)Ev)wYj>h|I%zF`uEjN6X4$I+zuhIJpJ*PmflXY3T#B%(y1LdA#ZF>o??O78z* z1xq}t)c{&T%DCZK&Vh>=98lZmsZto~cyk5-9s?%JO-Tfc7zq^~qWz0k0kqNM|B71i zBf-OG{(;9!Q<{#!v`1lLCbqyL(UEWeof!(TC`ChQklCx2rG@G={K_UH#RWmjO~!71 zLJ^&L1J_;LwRqBE9i6NcB;IDs{zd8Me&2;l;qoSuMOZrv-2Y&Z8;;So5oK-VNj_ql z(Vli=v~}UY)pAeX^1~5J$?Vo^*|pUE7#1Huf4_?KVIy!=q{Hs7I2ZI{b2wreOQcXm zo%ufNep%O*XMkB@;o1CVARWVM4+~<3sWcs%kODR7y64sSzKy)|aQnIKlLJS3U_eKc zr;wg`d?SF4F7NS^p+Y19W{P#4MIvWMc2T$K@;xuf9VR<%4`rKx!ODBoP^G*2AW nNiz5pz3{_N%3bE%MF^X-tTtMXK6)CrA&ADEtq&Pv0swylzumOf literal 0 HcmV?d00001 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

+ +
+ + + +
+
+ +
+

+ + +

+ +
+ +
+
+ +
+

+ + +

+ +
+ +
+
+ +
+

+ + +

+ + + + +
+ +