Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dev: two step ownable #809

Merged
merged 29 commits into from
Feb 9, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
e2a149a
dev: two step ownable
milancermak Nov 2, 2023
34f2dc0
chore: lint
milancermak Nov 2, 2023
0ad5629
test(ownable): two step test suite
milancermak Nov 3, 2023
def6cc9
dev: apply suggestions from code review
milancermak Nov 8, 2023
4b992a6
chore: removing explicit types
milancermak Nov 8, 2023
54365bb
dev: asserting ownable events keys
milancermak Nov 8, 2023
7e1b537
docs: OwnableTwoStep API
milancermak Nov 8, 2023
7551934
docs: OwnableTwoStep usage and impl section
milancermak Nov 9, 2023
22f9c11
docs: using OwnableTwoStepComponent everywhere
milancermak Nov 9, 2023
81cc84f
dev: adding pendingOwner
milancermak Nov 10, 2023
9c0fa08
doc: no more OwnableTwoStepComponent
milancermak Dec 1, 2023
6110012
docs: adding OwnableTwoStepImpl snippet
milancermak Dec 2, 2023
14c1766
test: using component_state_for_testing
milancermak Dec 2, 2023
d17b08a
chore: updating CHANGELOG
milancermak Dec 2, 2023
8e37b19
chore: update CHANGELOG.md
milancermak Dec 2, 2023
2e08530
dev: allow two step ownable transfer to zero
milancermak Dec 2, 2023
fd57323
docs: two step interface
milancermak Dec 11, 2023
76e0dfb
docs: access API with separate two step sections
milancermak Dec 11, 2023
a98e79e
Merge branch 'main' into dev/ownable-two-step
milancermak Dec 19, 2023
5077d05
lint: rm extra blank line
milancermak Dec 19, 2023
535b164
chore: PR comments
milancermak Dec 30, 2023
3fd7466
fix: impl order
milancermak Jan 31, 2024
baec9e1
doc: small fixes
milancermak Jan 31, 2024
fb2be79
doc: combining section overview
milancermak Jan 31, 2024
b1a78ad
Merge branch 'main' into dev/ownable-two-step
milancermak Jan 31, 2024
dde5ab6
lint: changelog.md
milancermak Jan 31, 2024
16ee093
doc: section ordering
milancermak Jan 31, 2024
6d8016e
Merge branch 'main' into dev/ownable-two-step
milancermak Jan 31, 2024
3e2cc60
Merge branch 'main' into dev/ownable-two-step
milancermak Feb 7, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- Two-step transfer functionality of the `Ownable` component
- Documentation for SRC5 migration (#821)
- Usage docs (#823)
- Utilities documentation (#825)
- Documentation for presets (#832)
- Ownable two-step functionality (#809)

### Changed

- `assert_event_ownership_transferred` checks for indexed keys now
- Use ComponentState in tests (#836)
- Docsite navbar (#838)
27 changes: 27 additions & 0 deletions docs/modules/ROOT/pages/access.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,33 @@ impl OwnableTwoStepCamelOnlyImpl =
OwnableComponent::OwnableTwoStepCamelOnlyImpl<ContractState>;
----

[#interface-twostep]
==== Interface

This is the full interface of the two step `Ownable` implementation:

[,javascript]
----
trait IOwnableTwoStep {
/// Returns the address of the current owner.
fn owner() -> ContractAddress;

/// Returns the address of the pending owner.
fn pending_owner() -> ContractAddress;

/// Finishes the two-step ownership transfer process
/// by accepting the ownership.
fn accept_ownership();

/// Starts the two-step ownership transfer process
/// by setting the pending owner.
fn transfer_ownership(new_owner: ContractAddress);

/// Renounces the ownership of the contract.
fn renounce_ownership();
}
----

== Role-Based `AccessControl`

While the simplicity of ownership can be useful for simple systems or quick prototyping, different levels of
Expand Down
156 changes: 103 additions & 53 deletions docs/modules/ROOT/pages/api/access.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -40,37 +40,36 @@ This module includes the internal `assert_only_owner` to restrict a function to
--

[.contract-index]
[[OwnableTwoStepImpl]]
.Embeddable Implementations (two-step transfer)
.Embeddable Implementations (camelCase)
--
.OwnableTwoStepImpl
.OwnableCamelOnlyImpl

* xref:OwnableComponent-owner[`++owner(self)++`]
* xref:OwnableComponent-pending_owner[`++pending_owner(self)++`]
* xref:OwnableComponent-transfer_ownership[`++transfer_ownership(self, new_owner)++`]
* xref:OwnableComponent-renounce_ownership[`++renounce_ownership(self)++`]
* xref:OwnableComponent-accept_ownership[`++accept_ownership(self)++`]
* xref:OwnableComponent-transferOwnership[`++transferOwnership(self, newOwner)++`]
* xref:OwnableComponent-renounceOwnership[`++renounceOwnership(self)++`]
--

[.contract-index]
.Embeddable Implementations (camelCase)
[[OwnableTwoStepImpl]]
.Embeddable Implementations (two step transfer)
milancermak marked this conversation as resolved.
Show resolved Hide resolved
--
.OwnableCamelOnlyImpl
.OwnableTwoStepImpl

* xref:OwnableComponent-transferOwnership[`++transferOwnership(self, newOwner)++`]
* xref:OwnableComponent-renounceOwnership[`++renounceOwnership(self)++`]
* xref:OwnableComponent-two-step-owner[`++owner(self)++`]
* xref:OwnableComponent-two-step-pending_owner[`++pending_owner(self)++`]
* xref:OwnableComponent-two-step-accept_ownership[`++accept_ownership(self)++`]
* xref:OwnableComponent-two-step-transfer_ownership[`++transfer_ownership(self, new_owner)++`]
* xref:OwnableComponent-two-step-renounce_ownership[`++renounce_ownership(self)++`]
--

[.contract-index]
.Embeddable Implementations (camelCase two-step transfer)
.Embeddable Implementations (camelCase two step transfer)
--
.OwnableTwoStepCamelOnlyImpl

* xref:OwnableComponent-owner[`++owner(self)++`]
* xref:OwnableComponent-pendingOwner[`++pendingOwner(self)++`]
* xref:OwnableComponent-transferOwnership[`++transferOwnership(self, new_owner)++`]
* xref:OwnableComponent-renounceOwnership[`++renounceOwnership(self)++`]
* xref:OwnableComponent-acceptOwnership[`++acceptOwnership(self)++`]
* xref:OwnableComponent-two-step-pendingOwner[`++pendingOwner(self)++`]
* xref:OwnableComponent-two-step-acceptOwnership[`++acceptOwnership(self)++`]
* xref:OwnableComponent-two-step-transferOwnership[`++transferOwnership(self, new_owner)++`]
* xref:OwnableComponent-two-step-renounceOwnership[`++renounceOwnership(self)++`]
--

[.contract-index]
Expand All @@ -80,6 +79,8 @@ This module includes the internal `assert_only_owner` to restrict a function to

* xref:OwnableComponent-initializer[`++initializer(self, owner)++`]
* xref:OwnableComponent-assert_only_owner[`++assert_only_owner(self)++`]
* xref:OwnableComponent-_accept_ownership[`++_accept_ownership(self)++`]
* xref:OwnableComponent-_propose_owner[`++_propose_owner(self, new_owner)++`]
* xref:OwnableComponent-_transfer_ownership[`++_transfer_ownership(self, new_owner)++`]
--

Expand All @@ -96,14 +97,9 @@ This module includes the internal `assert_only_owner` to restrict a function to
[.contract-item]
[[OwnableComponent-owner]]
==== `[.contract-item-name]#++owner++#++(self: @ContractState) → ContractAddress++` [.item-kind]#external#

// tag::owner[]
Returns the address of the current owner.

[.contract-item]
[[OwnableComponent-pending_owner]]
==== `[.contract-item-name]#++pending_owner++#++(self: @ContractState) → ContractAddress++` [.item-kind]#external#

Returns the address of the pending owner.
// end::owner[]

[.contract-item]
[[OwnableComponent-transfer_ownership]]
Expand All @@ -117,15 +113,51 @@ Emits an xref:OwnableComponent-OwnershipTransferred[OwnershipTransferred] event.
[.contract-item]
[[OwnableComponent-renounce_ownership]]
==== `[.contract-item-name]#++renounce_ownership++#++(ref self: ContractState)++` [.item-kind]#external#

// tag::renounce_ownership[]
Leaves the contract without owner. It will not be possible to call
`assert_only_owner` functions anymore. Can only be called by the current owner.

NOTE: Renouncing ownership will leave the contract without an owner,
thereby removing any functionality that is only available to the owner.
//end::renounce_ownership[]

[#OwnableComponent-camelCase-Support]
==== camelCase Support

[.contract-item]
[[OwnableComponent-transferOwnership]]
==== `[.contract-item-name]#++transferOwnership++#++(ref self: ContractState, newOwner: ContractAddress)++` [.item-kind]#external#

See xref:OwnableComponent-transfer_ownership[transfer_ownership].

[.contract-item]
[[OwnableComponent-renounceOwnership]]
==== `[.contract-item-name]#++renounceOwnership++#++(ref self: ContractState)++` [.item-kind]#external#

See xref:OwnableComponent-renounce_ownership[renounce_ownership].

[.contract-item]
[[OwnableComponent-acceptOwnership]]
==== `[.contract-item-name]#++acceptOwnership++#++(ref self: ContractState)++` [.item-kind]#external#

See xref:OwnableComponent-accept_ownership[accept_ownership].

milancermak marked this conversation as resolved.
Show resolved Hide resolved
[#OwnableComponent-Embeddable-Functions-Two-Step]
==== Embeddable Functions (Two step transfer)

[.contract-item]
[[OwnableComponent-two-step-owner]]
==== `[.contract-item-name]#++owner++#++(self: @ContractState) → ContractAddress++` [.item-kind]#external#
include::./access.adoc[tag=owner]

[.contract-item]
[[OwnableComponent-two-step-pending_owner]]
==== `[.contract-item-name]#++pending_owner++#++(self: @ContractState) → ContractAddress++` [.item-kind]#external#

Returns the address of the pending owner.

[.contract-item]
[[OwnableComponent-accept_ownership]]
[[OwnableComponent-two-step-accept_ownership]]
==== `[.contract-item-name]#++accept_ownership++#++(ref self: ContractState)++` [.item-kind]#external#

Transfers ownership of the contract to the pending owner.
Expand All @@ -134,32 +166,46 @@ Resets pending owner to zero address.

Emits an xref:OwnableComponent-OwnershipTransferred[OwnershipTransferred] event.

[#OwnableComponent-camelCase-Support]
==== camelCase Support
[.contract-item]
[[OwnableComponent-two-step-transfer_ownership]]
==== `[.contract-item-name]#++transfer_ownership++#++(ref self: ContractState, new_owner: ContractAddress)++` [.item-kind]#external#

Starts the two step ownership transfer process, by setting the pending owner.
Can only be called by the current owner.

Emits an xref:OwnableComponent-OwnershipTransferStarted[OwnershipTransferStarted] event.

[.contract-item]
[[OwnableComponent-acceptOwnership]]
[[OwnableComponent-two-step-renounce_ownership]]
==== `[.contract-item-name]#++renounce_ownership++#++(ref self: ContractState)++` [.item-kind]#external#
include::./access.adoc[tag=renounce_ownership]

[#OwnableComponent-camelCase-Support-Two-Step]
==== camelCase Support (two step transfer)

[.contract-item]
[[OwnableComponent-two-step-pendingOwner]]
==== `[.contract-item-name]#++pendingOwner++#++(self: @ContractState)++` [.item-kind]#external#

See xref:OwnableComponent-pending_owner[pending_owner].
See xref:OwnableComponent-two-step-pending_owner[pending_owner].

[.contract-item]
[[OwnableComponent-transferOwnership]]
==== `[.contract-item-name]#++transferOwnership++#++(ref self: ContractState, newOwner: ContractAddress)++` [.item-kind]#external#
[[OwnableComponent-two-step-acceptOwnership]]
==== `[.contract-item-name]#++acceptOwnership++#++(self: @ContractState)++` [.item-kind]#external#

See xref:OwnableComponent-transfer_ownership[transfer_ownership].
See xref:OwnableComponent-two-step-accept_ownership[accept_ownership].

[.contract-item]
[[OwnableComponent-renounceOwnership]]
==== `[.contract-item-name]#++renounceOwnership++#++(ref self: ContractState)++` [.item-kind]#external#
[[OwnableComponent-two-step-transferOwnership]]
==== `[.contract-item-name]#++transferOwnership++#++(self: @ContractState)++` [.item-kind]#external#

See xref:OwnableComponent-renounce_ownership[renounce_ownership].
See xref:OwnableComponent-two-step-transfer_ownership[transfer_ownership].

[.contract-item]
[[OwnableComponent-acceptOwnership]]
==== `[.contract-item-name]#++acceptOwnership++#++(ref self: ContractState)++` [.item-kind]#external#
[[OwnableComponent-two-step-renounceOwnership]]
==== `[.contract-item-name]#++renounceOwnership++#++(self: @ContractState)++` [.item-kind]#external#

See xref:OwnableComponent-accept_ownership[accept_ownership].
See xref:OwnableComponent-two-step-renounce_ownership[renounce_ownership].

[#OwnableComponent-Internal-Functions]
==== Internal Functions
Expand All @@ -178,33 +224,37 @@ Emits an xref:OwnableComponent-OwnershipTransferred[OwnershipTransferred] event.

Panics if called by any account other than the owner.

[.contract-item]
[[OwnableComponent-_transfer_ownership]]
==== `[.contract-item-name]#++_transfer_ownership++#++(ref self: ContractState, new_owner: ContractAddress)++` [.item-kind]#internal#

Transfers ownership of the contract to a new account (`new_owner`).
Internal function without access restriction.

Emits an xref:OwnableComponent-OwnershipTransferred[OwnershipTransferred] event.

[.contract-item]
[[OwnableComponent-_accept_ownership]]
==== `[.contract-item-name]#++_accept_ownership++#++(ref self: ContractState)++` [.item-kind]#internal#

Transfers ownership of the contract to the pending owner.
Sets the pending owner to zero address.
Internal function without access restriction.
Transfers ownership to the pending owner. Resets pending owner to zero address.
Calls xref:OwnableComponent-_transfer_ownership[_transfer_ownership].

Internal function without access restriction.

[.contract-item]
[[OwnableComponent-_transfer_ownership]]

[.contract-item]
[[OwnableComponent-_propose_owner]]
==== `[.contract-item-name]#++_propose_owner++#++(ref self: ContractState, new_owner: ContractAddress)++` [.item-kind]#internal#

Sets pending owner to a new account (`new_owner`).
Sets a new pending owner in a two step transfer.

Internal function without access restriction.

Emits an xref:OwnableComponent-OwnershipTransferStarted[OwnershipTransferStarted] event.

[.contract-item]
[[OwnableComponent-_transfer_ownership]]
==== `[.contract-item-name]#++_transfer_ownership++#++(ref self: ContractState, new_owner: ContractAddress)++` [.item-kind]#internal#

Transfers ownership of the contract to a new account (`new_owner`).
Internal function without access restriction.

Emits an xref:OwnableComponent-OwnershipTransferred[OwnershipTransferred] event.

[#OwnableComponent-Events]
==== Events

Expand Down
1 change: 0 additions & 1 deletion src/access/ownable/ownable.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,6 @@ mod OwnableComponent {
fn transfer_ownership(
ref self: ComponentState<TContractState>, new_owner: ContractAddress
) {
assert(!new_owner.is_zero(), Errors::ZERO_ADDRESS_OWNER);
self.assert_only_owner();
self._propose_owner(new_owner);
}
Expand Down
10 changes: 8 additions & 2 deletions src/tests/access/test_ownable_twostep.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -103,11 +103,14 @@ fn test_transfer_ownership() {

#[test]
#[available_gas(2000000)]
#[should_panic(expected: ('New owner is the zero address',))]
fn test_transfer_ownership_to_zero() {
let mut state = setup();
testing::set_caller_address(OWNER());
state.transfer_ownership(ZERO());

assert_event_ownership_transfer_started(OWNER(), ZERO());
assert(state.owner() == OWNER(), 'Owner should be OWNER');
assert(state.pending_owner() == ZERO(), 'Pending owner should be ZERO');
}

#[test]
Expand Down Expand Up @@ -148,11 +151,14 @@ fn test_transferOwnership() {

#[test]
#[available_gas(2000000)]
#[should_panic(expected: ('New owner is the zero address',))]
fn test_transferOwnership_to_zero() {
let mut state = setup();
testing::set_caller_address(OWNER());
state.transferOwnership(ZERO());

assert_event_ownership_transfer_started(OWNER(), ZERO());
assert(state.owner() == OWNER(), 'Owner should be OWNER');
assert(state.pendingOwner() == ZERO(), 'Pending owner should be ZERO');
}

#[test]
Expand Down