From fc8c4b300cbbc2152b28132103f5ef33c65cef47 Mon Sep 17 00:00:00 2001 From: immrsd Date: Tue, 10 Dec 2024 14:52:49 +0100 Subject: [PATCH 01/28] Add Multisig API references --- docs/modules/ROOT/pages/api/governance.adoc | 594 +++++++++++++++++++- 1 file changed, 578 insertions(+), 16 deletions(-) diff --git a/docs/modules/ROOT/pages/api/governance.adoc b/docs/modules/ROOT/pages/api/governance.adoc index ed0a37486..120d58772 100644 --- a/docs/modules/ROOT/pages/api/governance.adoc +++ b/docs/modules/ROOT/pages/api/governance.adoc @@ -1,10 +1,18 @@ :github-icon: pass:[] -:CallScheduled: xref:ITimelock-CallScheduled[CallScheduled] -:CallExecuted: xref:ITimelock-CallExecuted[CallExecuted] -:CallSalt: xref:ITimelock-CallSalt[CallSalt] -:CallCancelled: xref:ITimelock-CallCancelled[CallCancelled] -:MinDelayChanged: xref:ITimelock-MinDelayChanged[MinDelayChanged] -:RoleGranted: xref:api/access.adoc#IAccessControl-RoleGranted[IAccessControl::RoleGranted] +:IMultisig-CallSalt: xref:IMultisig-CallSalt[CallSalt] +:IMultisig-SignerAdded: xref:IMultisig-CallSalt[SignerAdded] +:IMultisig-SignerRemoved: xref:IMultisig-CallSalt[SignerRemoved] +:IMultisig-QuorumUpdated: xref:IMultisig-CallSalt[QuorumUpdated] +:IMultisig-TransactionSubmitted: xref:IMultisig-CallSalt[TransactionSubmitted] +:IMultisig-TransactionConfirmed: xref:IMultisig-CallSalt[TransactionConfirmed] +:IMultisig-ConfirmationRevoked: xref:IMultisig-CallSalt[ConfirmationRevoked] +:IMultisig-TransactionExecuted: xref:IMultisig-CallSalt[TransactionExecuted] +:ITimelock-CallScheduled: xref:ITimelock-CallScheduled[CallScheduled] +:ITimelock-CallExecuted: xref:ITimelock-CallExecuted[CallExecuted] +:ITimelock-CallSalt: xref:ITimelock-CallSalt[CallSalt] +:ITimelock-CallCancelled: xref:ITimelock-CallCancelled[CallCancelled] +:ITimelock-MinDelayChanged: xref:ITimelock-MinDelayChanged[MinDelayChanged] +:ITimelock-RoleGranted: xref:api/access.adoc#IAccessControl-RoleGranted[IAccessControl::RoleGranted] :DelegateChanged: xref:VotesComponent-DelegateChanged[DelegateChanged] :DelegateVotesChanged: xref:VotesComponent-DelegateVotesChanged[DelegateVotesChanged] :VotingUnitsTrait: xref:VotingUnitsTrait[VotingUnitsTrait] @@ -1982,6 +1990,560 @@ Emits a {TimelockUpdated} event. Emitted when the timelock controller is updated. +== Multisig + +Description + +[.contract] +[[IMultisig]] +=== `++IMultisig++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.20.0/packages/governance/src/multisig/interface.cairo[{github-icon},role=heading-link] + +[.hljs-theme-dark] +```cairo +use openzeppelin_governance::multisig::interface::IMultisig; +``` + +Interface of a multisig contract. + +[.contract-index] +.Functions +-- +* xref:#IMultisig-get_quorum[`++get_quorum()++`] +* xref:#IMultisig-is_signer[`++is_signer(signer)++`] +* xref:#IMultisig-get_signers[`++get_signers()++`] +* xref:#IMultisig-is_confirmed[`++is_confirmed(id)++`] +* xref:#IMultisig-is_confirmed_by[`++is_confirmed_by(id, signer)++`] +* xref:#IMultisig-is_executed[`++is_executed(id)++`] +* xref:#IMultisig-get_submitted_block[`++get_submitted_block(id)++`] +* xref:#IMultisig-get_transaction_state[`++get_transaction_state(id)++`] +* xref:#IMultisig-get_transaction_confirmations[`++get_transaction_confirmations(id)++`] +* xref:#IMultisig-hash_transaction[`++hash_transaction(to, selector, calldata, salt)++`] +* xref:#IMultisig-hash_transaction_batch[`++hash_transaction_batch(calls, salt)++`] +* xref:#IMultisig-add_signers[`++add_signers(new_quorum, signers_to_add)++`] +* xref:#IMultisig-remove_signers[`++remove_signers(new_quorum, signers_to_remove)++`] +* xref:#IMultisig-replace_signer[`++replace_signer(signer_to_remove, signer_to_add)++`] +* xref:#IMultisig-change_quorum[`++change_quorum(new_quorum)++`] +* xref:#IMultisig-submit_transaction[`++submit_transaction(to, selector, calldata, salt)++`] +* xref:#IMultisig-submit_transaction_batch[`++submit_transaction_batch(calls, salt)++`] +* xref:#IMultisig-confirm_transaction[`++confirm_transaction(id)++`] +* xref:#IMultisig-revoke_confirmation[`++revoke_confirmation(id)++`] +* xref:#IMultisig-execute_transaction[`++execute_transaction(to, selector, calldata, salt)++`] +* xref:#IMultisig-execute_transaction_batch[`++execute_transaction_batch(calls, salt)++`] +-- + +[.contract-index] +.Events +-- +* xref:#IMultisig-SignerAdded[`++SignerAdded(signer)++`] +* xref:#IMultisig-SignerRemoved[`++SignerRemoved(signer)++`] +* xref:#IMultisig-QuorumUpdated[`++QuorumUpdated(old_quorum, new_quorum)++`] +* xref:#IMultisig-TransactionSubmitted[`++TransactionSubmitted(id, signer)++`] +* xref:#IMultisig-TransactionConfirmed[`++TransactionConfirmed(id, signer)++`] +* xref:#IMultisig-ConfirmationRevoked[`++ConfirmationRevoked(id, signer)++`] +* xref:#IMultisig-TransactionExecuted[`++TransactionExecuted(id)++`] +* xref:#IMultisig-CallSalt[`++CallSalt(id, salt)++`] +-- + +[#IMultisig-Functions] +==== Functions + +[.contract-item] +[[IMultisig-get_quorum]] +==== `[.contract-item-name]#++get_quorum++#++() → u32++` [.item-kind]#external# + +Returns the current quorum value. The quorum is the minimum number of confirmations required to approve a transaction. + +[.contract-item] +[[IMultisig-is_signer]] +==== `[.contract-item-name]#++is_signer++#++(signer: ContractAddress) → bool++` [.item-kind]#external# + +Returns whether the given `signer` is registered. Only registered signers can submit, confirm, or execute transactions. + +[.contract-item] +[[IMultisig-get_signers]] +==== `[.contract-item-name]#++get_signers++#++() → Span++` [.item-kind]#external# + +Returns the list of all current signers. + +[.contract-item] +[[IMultisig-is_confirmed]] +==== `[.contract-item-name]#++is_confirmed++#++(id: TransactionID) → bool++` [.item-kind]#external# + +Returns whether the transaction with the given `id` has been confirmed. + +[.contract-item] +[[IMultisig-is_confirmed_by]] +==== `[.contract-item-name]#++is_confirmed_by++#++(id: TransactionID, signer: ContractAddress) → bool++` [.item-kind]#external# + +Returns whether the transaction with the given `id` has been confirmed by the specified `signer`. + +[.contract-item] +[[IMultisig-is_executed]] +==== `[.contract-item-name]#++is_executed++#++(id: TransactionID) → bool++` [.item-kind]#external# + +Returns whether the transaction with the given `id` has been executed. + +[.contract-item] +[[IMultisig-get_transaction_state]] +==== `[.contract-item-name]#++get_transaction_state++#++(id: TransactionID) → TransactionState++` [.item-kind]#external# + +Returns the current state of the transaction with the given `id`. + +[.contract-item] +[[IMultisig-get_transaction_confirmations]] +==== `[.contract-item-name]#++get_transaction_confirmations++#++(id: TransactionID) → u32++` [.item-kind]#external# + +Returns the number of confirmations from registered signers for the transaction with the specified `id`. + +[.contract-item] +[[IMultisig-get_submitted_block]] +==== `[.contract-item-name]#++get_submitted_block++#++(id: TransactionID) → u64++` [.item-kind]#external# + +Returns the block number when the transaction with the given `id` was submitted. + +[.contract-item] +[[IMultisig-add_signers]] +==== `[.contract-item-name]#++add_signers++#++(new_quorum: u32, signers_to_add: Span)++` [.item-kind]#external# + +Adds new signers and updates the quorum. + +Requirements: +- The caller must be the contract itself. +- `new_quorum` must be less than or equal to the total number of signers after addition. + +Emits a {IMultisig-SignerAdded} event for each signer added. +Emits a {IMultisig-QuorumUpdated} event if the quorum changes. + +[.contract-item] +[[IMultisig-remove_signers]] +==== `[.contract-item-name]#++remove_signers++#++(new_quorum: u32, signers_to_remove: Span)++` [.item-kind]#external# + +Removes signers and updates the quorum. + +Requirements: +- The caller must be the contract itself. +- `new_quorum` must be less than or equal to the total number of signers after removal. + +Emits a {IMultisig-SignerRemoved} event for each signer removed. +Emits a {IMultisig-QuorumUpdated} event if the quorum changes. + +[.contract-item] +[[IMultisig-replace_signer]] +==== `[.contract-item-name]#++replace_signer++#++(signer_to_remove: ContractAddress, signer_to_add: ContractAddress)++` [.item-kind]#external# + +Replaces an existing signer with a new signer. + +Requirements: +- The caller must be the contract itself. +- `signer_to_remove` must be an existing signer. +- `signer_to_add` must not be an existing signer. + +Emits a {IMultisig-SignerRemoved} event for the removed signer. +Emits a {IMultisig-SignerAdded} event for the new signer. + +[.contract-item] +[[IMultisig-change_quorum]] +==== `[.contract-item-name]#++change_quorum++#++(new_quorum: u32)++` [.item-kind]#external# + +Updates the quorum value to `new_quorum` if it differs from the current quorum. + +Requirements: +- The caller must be the contract itself. +- `new_quorum` must be non-zero. +- `new_quorum` must be less than or equal to the total number of signers. + +Emits a {IMultisig-QuorumUpdated} event if the quorum changes. + +[.contract-item] +[[IMultisig-submit_transaction]] +==== `[.contract-item-name]#++submit_transaction++#++(to: ContractAddress, selector: felt252, calldata: Span, salt: felt252) → TransactionID++` [.item-kind]#external# + +Submits a new transaction for confirmation. + +Requirements: +- The caller must be a registered signer. +- The transaction must not have been submitted before. + +Emits a {IMultisig-TransactionSubmitted} event. +Emits a {IMultisig-CallSalt} event if `salt` is not zero. + +[.contract-item] +[[IMultisig-submit_transaction_batch]] +==== `[.contract-item-name]#++submit_transaction_batch++#++(calls: Span, salt: felt252) → TransactionID++` [.item-kind]#external# + +Submits a new batch transaction for confirmation. + +Requirements: +- The caller must be a registered signer. +- The transaction must not have been submitted before. + +Emits a {IMultisig-TransactionSubmitted} event. +Emits a {IMultisig-CallSalt} event if `salt` is not zero. + +[.contract-item] +[[IMultisig-confirm_transaction]] +==== `[.contract-item-name]#++confirm_transaction++#++(id: TransactionID)++` [.item-kind]#external# + +Confirms a transaction with the given `id`. + +Requirements: +- The caller must be a registered signer. +- The transaction must exist and not be executed. +- The caller must not have already confirmed the transaction. + +Emits a {IMultisig-TransactionConfirmed} event. + +[.contract-item] +[[IMultisig-revoke_confirmation]] +==== `[.contract-item-name]#++revoke_confirmation++#++(id: TransactionID)++` [.item-kind]#external# + +Revokes a previous confirmation for a transaction with the given `id`. + +Requirements: +- The transaction must exist and not be executed. +- The caller must have previously confirmed the transaction. + +Emits a {IMultisig-ConfirmationRevoked} event. + +[.contract-item] +[[IMultisig-execute_transaction]] +==== `[.contract-item-name]#++execute_transaction++#++(to: ContractAddress, selector: felt252, calldata: Span, salt: felt252)++` [.item-kind]#external# + +Executes a confirmed transaction. + +Requirements: +- The caller must be a registered signer. +- The transaction must be confirmed and not yet executed. + +Emits a {IMultisig-TransactionExecuted} event. + +[.contract-item] +[[IMultisig-execute_transaction_batch]] +==== `[.contract-item-name]#++execute_transaction_batch++#++(calls: Span, salt: felt252)++` [.item-kind]#external# + +Executes a confirmed batch transaction. + +Requirements: +- The caller must be a registered signer. +- The transaction must be confirmed and not yet executed. + +Emits a {IMultisig-TransactionExecuted} event. + +[.contract-item] +[[IMultisig-hash_transaction]] +==== `[.contract-item-name]#++hash_transaction++#++(to: ContractAddress, selector: felt252, calldata: Span, salt: felt252) → TransactionID++` [.item-kind]#external# + +Returns the computed identifier of a transaction containing a single call. + +[.contract-item] +[[IMultisig-hash_transaction_batch]] +==== `[.contract-item-name]#++hash_transaction_batch++#++(calls: Span, salt: felt252) → TransactionID++` [.item-kind]#external# + +Returns the computed identifier of a transaction containing a batch of calls. + +[#IMultisig-Events] +==== Events + +[.contract-item] +[[IMultisig-SignerAdded]] +==== `[.contract-item-name]#++SignerAdded++#++(signer: ContractAddress)++` [.item-kind]#event# + +Emitted when a new `signer` is added. + +[.contract-item] +[[IMultisig-SignerRemoved]] +==== `[.contract-item-name]#++SignerRemoved++#++(signer: ContractAddress)++` [.item-kind]#event# + +Emitted when a `signer` is removed. + +[.contract-item] +[[IMultisig-QuorumUpdated]] +==== `[.contract-item-name]#++QuorumUpdated++#++(old_quorum: u32, new_quorum: u32)++` [.item-kind]#event# + +Emitted when the `quorum` value is updated. + +[.contract-item] +[[IMultisig-TransactionSubmitted]] +==== `[.contract-item-name]#++TransactionSubmitted++#++(id: TransactionID, signer: ContractAddress)++` [.item-kind]#event# + +Emitted when a new transaction is submitted by a `signer`. + +[.contract-item] +[[IMultisig-TransactionConfirmed]] +==== `[.contract-item-name]#++TransactionConfirmed++#++(id: TransactionID, signer: ContractAddress)++` [.item-kind]#event# + +Emitted when a transaction is confirmed by a `signer`. + +[.contract-item] +[[IMultisig-ConfirmationRevoked]] +==== `[.contract-item-name]#++ConfirmationRevoked++#++(id: TransactionID, signer: ContractAddress)++` [.item-kind]#event# + +Emitted when a `signer` revokes his confirmation. + +[.contract-item] +[[IMultisig-TransactionExecuted]] +==== `[.contract-item-name]#++TransactionExecuted++#++(id: TransactionID)++` [.item-kind]#event# + +Emitted when a transaction is executed. + +[.contract-item] +[[IMultisig-CallSalt]] +==== `[.contract-item-name]#++CallSalt++#++(id: felt252, salt: felt252)++` [.item-kind]#event# + +Emitted when a new transaction is submitted with non-zero salt. + +[.contract] +[[MultisigComponent]] +=== `++MultisigComponent++` + +Component that implements `IMultisig` and provides functionality for multisignature wallets, including transaction management, quorum handling, and signer operations. + +[.contract-index#MultisigComponent-Embeddable-Impls] +.Embeddable Implementations +-- +.MultisigImpl + +* xref:#MultisigComponent-get_quorum[`++get_quorum(self)++`] +* xref:#MultisigComponent-is_signer[`++is_signer(self, signer)++`] +* xref:#MultisigComponent-get_signers[`++get_signers(self)++`] +* xref:#MultisigComponent-is_confirmed[`++is_confirmed(self, id)++`] +* xref:#MultisigComponent-is_confirmed_by[`++is_confirmed_by(self, id, signer)++`] +* xref:#MultisigComponent-is_executed[`++is_executed(self, id)++`] +* xref:#MultisigComponent-get_transaction_state[`++get_transaction_state(self, id)++`] +* xref:#MultisigComponent-get_transaction_confirmations[`++get_transaction_confirmations(self, id)++`] +* xref:#MultisigComponent-get_submitted_block[`++get_submitted_block(self, id)++`] +* xref:#MultisigComponent-add_signers[`++add_signers(ref self, new_quorum, signers_to_add)++`] +* xref:#MultisigComponent-remove_signers[`++remove_signers(ref self, new_quorum, signers_to_remove)++`] +* xref:#MultisigComponent-replace_signer[`++replace_signer(ref self, signer_to_remove, signer_to_add)++`] +* xref:#MultisigComponent-change_quorum[`++change_quorum(ref self, new_quorum)++`] +* xref:#MultisigComponent-submit_transaction[`++submit_transaction(ref self, to, selector, calldata, salt)++`] +* xref:#MultisigComponent-submit_transaction_batch[`++submit_transaction_batch(ref self, calls, salt)++`] +* xref:#MultisigComponent-confirm_transaction[`++confirm_transaction(ref self, id)++`] +* xref:#MultisigComponent-revoke_confirmation[`++revoke_confirmation(ref self, id)++`] +* xref:#MultisigComponent-execute_transaction[`++execute_transaction(ref self, to, selector, calldata, salt)++`] +* xref:#MultisigComponent-execute_transaction_batch[`++execute_transaction_batch(ref self, calls, salt)++`] +* xref:#MultisigComponent-hash_transaction[`++hash_transaction(self, to, selector, calldata, salt)++`] +* xref:#MultisigComponent-hash_transaction_batch[`++hash_transaction_batch(self, calls, salt)++`] +-- + +[.contract-index#MultisigComponent-Internal-Impls] +.Internal Implementations +-- +.InternalImpl + +* xref:#MultisigComponent-initializer[`++initializer(ref self, quorum, signers)++`] +* xref:#MultisigComponent-resolve_tx_state[`++resolve_tx_state(self, id)++`] +* xref:#MultisigComponent-assert_one_of_signers[`++assert_one_of_signers(self, caller)++`] +* xref:#MultisigComponent-assert_tx_exists[`++assert_tx_exists(self, id)++`] +* xref:#MultisigComponent-assert_only_self[`++assert_only_self(self)++`] +* xref:#MultisigComponent-_add_signers[`++_add_signers(ref self, new_quorum, signers_to_add)++`] +* xref:#MultisigComponent-_remove_signers[`++_remove_signers(ref self, new_quorum, signers_to_remove)++`] +* xref:#MultisigComponent-_replace_signer[`++_replace_signer(ref self, signer_to_remove, signer_to_add)++`] +* xref:#MultisigComponent-_change_quorum[`++_change_quorum(ref self, new_quorum)++`] +-- + +[.contract-index#MultisigComponent-Events] +.Events +-- +* xref:#MultisigComponent-SignerAdded[`++SignerAdded(signer)++`] +* xref:#MultisigComponent-SignerRemoved[`++SignerRemoved(signer)++`] +* xref:#MultisigComponent-QuorumUpdated[`++QuorumUpdated(old_quorum, new_quorum)++`] +* xref:#MultisigComponent-TransactionSubmitted[`++TransactionSubmitted(id, signer)++`] +* xref:#MultisigComponent-TransactionConfirmed[`++TransactionConfirmed(id, signer)++`] +* xref:#MultisigComponent-ConfirmationRevoked[`++ConfirmationRevoked(id, signer)++`] +* xref:#MultisigComponent-TransactionExecuted[`++TransactionExecuted(id)++`] +* xref:#MultisigComponent-CallSalt[`++CallSalt(id, salt)++`] +-- + +[#MultisigComponent-Functions] +==== Embeddable functions + +[.contract-item] +[[MultisigComponent-get_quorum]] +==== `[.contract-item-name]#++get_quorum++#++(self: @ContractState) → u32++` [.item-kind]#external# + +Returns the current quorum value. + +[.contract-item] +[[MultisigComponent-is_signer]] +==== `[.contract-item-name]#++is_signer++#++(self: @ContractState, signer: ContractAddress) → bool++` [.item-kind]#external# + +Checks if a given `signer` is registered. + +[.contract-item] +[[MultisigComponent-get_signers]] +==== `[.contract-item-name]#++get_signers++#++(self: @ContractState) → Span++` [.item-kind]#external# + +Returns a list of all current signers. + +[.contract-item] +[[MultisigComponent-is_confirmed]] +==== `[.contract-item-name]#++is_confirmed++#++(self: @ContractState, id: TransactionID) → bool++` [.item-kind]#external# + +Determines if the transaction with `id` is confirmed. + +[.contract-item] +[[MultisigComponent-is_confirmed_by]] +==== `[.contract-item-name]#++is_confirmed_by++#++(self: @ContractState, id: TransactionID, signer: ContractAddress) → bool++` [.item-kind]#external# + +Checks if the transaction with `id` has been confirmed by the specified `signer`. + +[.contract-item] +[[MultisigComponent-is_executed]] +==== `[.contract-item-name]#++is_executed++#++(self: @ContractState, id: TransactionID) → bool++` [.item-kind]#external# + +Checks if the transaction with `id` has been executed. + +[.contract-item] +[[MultisigComponent-get_transaction_state]] +==== `[.contract-item-name]#++get_transaction_state++#++(self: @ContractState, id: TransactionID) → TransactionState++` [.item-kind]#external# + +Returns the current state of the transaction with `id`. + +[.contract-item] +[[MultisigComponent-get_transaction_confirmations]] +==== `[.contract-item-name]#++get_transaction_confirmations++#++(self: @ContractState, id: TransactionID) → u32++` [.item-kind]#external# + +Returns the number of confirmations from registered signers for the transaction with `id`. + +[.contract-item] +[[MultisigComponent-get_submitted_block]] +==== `[.contract-item-name]#++get_submitted_block++#++(self: @ContractState, id: TransactionID) → u64++` [.item-kind]#external# + +Returns the block number when the transaction with `id` was submitted. + +[.contract-item] +[[MultisigComponent-add_signers]] +==== `[.contract-item-name]#++add_signers++#++(ref self: ContractState, new_quorum: u32, signers_to_add: Span)++` [.item-kind]#external# + +Adds new signers and updates the quorum. + +[.contract-item] +[[MultisigComponent-remove_signers]] +==== `[.contract-item-name]#++remove_signers++#++(ref self: ContractState, new_quorum: u32, signers_to_remove: Span)++` [.item-kind]#external# + +Removes signers and updates the quorum. + +[.contract-item] +[[MultisigComponent-replace_signer]] +==== `[.contract-item-name]#++replace_signer++#++(ref self: ContractState, signer_to_remove: ContractAddress, signer_to_add: ContractAddress)++` [.item-kind]#external# + +Replaces an existing signer with a new signer. + +[.contract-item] +[[MultisigComponent-change_quorum]] +==== `[.contract-item-name]#++change_quorum++#++(ref self: ContractState, new_quorum: u32)++` [.item-kind]#external# + +Updates the quorum value to `new_quorum`. + +[.contract-item] +[[MultisigComponent-submit_transaction]] +==== `[.contract-item-name]#++submit_transaction++#++(ref self: ContractState, to: ContractAddress, selector: felt252, calldata: Span, salt: felt252)++` [.item-kind]#external# + +Submits a new transaction for confirmation. + +[.contract-item] +[[MultisigComponent-submit_transaction_batch]] +==== `[.contract-item-name]#++submit_transaction_batch++#++(ref self: ContractState, calls: Span, salt: felt252)++` [.item-kind]#external# + +Submits a new batch transaction for confirmation. + +[.contract-item] +[[MultisigComponent-confirm_transaction]] +==== `[.contract-item-name]#++confirm_transaction++#++(ref self: ContractState, id: TransactionID)++` [.item-kind]#external# + +Confirms a transaction with the given `id`. + +[.contract-item] +[[MultisigComponent-revoke_confirmation]] +==== `[.contract-item-name]#++revoke_confirmation++#++(ref self: ContractState, id: TransactionID)++` [.item-kind]#external# + +Revokes a previous confirmation for a transaction with the given `id`. + +[.contract-item] +[[MultisigComponent-execute_transaction]] +==== `[.contract-item-name]#++execute_transaction++#++(ref self: ContractState, to: ContractAddress, selector: felt252, calldata: Span, salt: felt252)++` [.item-kind]#external# + +Executes a confirmed transaction. + +[.contract-item] +[[MultisigComponent-execute_transaction_batch]] +==== `[.contract-item-name]#++execute_transaction_batch++#++(ref self: ContractState, calls: Span, salt: felt252)++` [.item-kind]#external# + +Executes a confirmed batch transaction. + +[.contract-item] +[[MultisigComponent-hash_transaction]] +==== `[.contract-item-name]#++hash_transaction++#++(self: @ContractState, to: ContractAddress, selector: felt252, calldata: Span, salt: felt252)++` [.item-kind]#external# + +Returns the computed identifier of a transaction containing a single call. + +[.contract-item] +[[MultisigComponent-hash_transaction_batch]] +==== `[.contract-item-name]#++hash_transaction_batch++#++(self: @ContractState, calls: Span, salt: felt252)++` [.item-kind]#external# + +Returns the computed identifier of a transaction containing a batch of calls. + +[#MultisigComponent-Internal-Functions] +==== Internal functions + +[.contract-item] +[[MultisigComponent-initializer]] +==== `[.contract-item-name]#++initializer++#++(ref self: ContractState, quorum: u32, signers: Span)++` [.item-kind]#internal# + +Initializes the Multisig component with the initial `quorum` and `signers`. + +Emits a `SignerAdded` event for each signer added. +Emits a `QuorumUpdated` event if the quorum changes. + +[.contract-item] +[[MultisigComponent-resolve_tx_state]] +==== `[.contract-item-name]#++resolve_tx_state++#++(self: @ContractState, id: TransactionID) → TransactionState++` [.item-kind]#internal# + +Resolves and returns the current state of the transaction with the given `id`. + +[.contract-item] +[[MultisigComponent-assert_one_of_signers]] +==== `[.contract-item-name]#++assert_one_of_signers++#++(self: @ContractState, caller: ContractAddress)++` [.item-kind]#internal# + +Asserts that the `caller` is one of the registered signers. + +[.contract-item] +[[MultisigComponent-assert_tx_exists]] +==== `[.contract-item-name]#++assert_tx_exists++#++(self: @ContractState, id: TransactionID)++` [.item-kind]#internal# + +Asserts that a transaction with the given `id` exists. + +[.contract-item] +[[MultisigComponent-assert_only_self]] +==== `[.contract-item-name]#++assert_only_self++#++(self: @ContractState)++` [.item-kind]#internal# + +Asserts that the caller is the contract itself. + +[.contract-item] +[[MultisigComponent-_add_signers]] +==== `[.contract-item-name]#++_add_signers++#++(ref self: ContractState, new_quorum: u32, signers_to_add: Span)++` [.item-kind]#internal# + +Adds new signers and updates the quorum. + +[.contract-item] +[[MultisigComponent-_remove_signers]] +==== `[.contract-item-name]#++_remove_signers++#++(ref self: ContractState, new_quorum: u32, signers_to_remove: Span)++` [.item-kind]#internal# + +Removes existing signers and updates the quorum. + +[.contract-item] +[[MultisigComponent-_replace_signer]] +==== `[.contract-item-name]#++_replace_signer++#++(ref self: ContractState, signer_to_remove: ContractAddress, signer_to_add: ContractAddress)++` [.item-kind]#internal# + +Replaces an existing signer with a new signer. + +[.contract-item] +[[MultisigComponent-_change_quorum]] +==== `[.contract-item-name]#++_change_quorum++#++(ref self: ContractState, new_quorum: u32)++` [.item-kind]#internal# + +Updates the quorum value to `new_quorum` if it differs from the current quorum. + == Timelock In a governance system, `TimelockControllerComponent` is in charge of introducing a delay between a proposal and its execution. @@ -2100,8 +2662,8 @@ Requirements: - The caller must have the `PROPOSER_ROLE` role. -Emits {CallScheduled} event. -Emits {CallSalt} event if `salt` is not zero. +Emits {ITimelock-CallScheduled} event. +Emits {ITimelock-CallSalt} event if `salt` is not zero. [.contract-item] [[ITimelock-schedule_batch]] @@ -2113,8 +2675,8 @@ Requirements: - The caller must have the `PROPOSER_ROLE` role. -Emits one {CallScheduled} event for each transaction in the batch. -Emits {CallSalt} event if `salt` is not zero. +Emits one {ITimelock-CallScheduled} event for each transaction in the batch. +Emits {ITimelock-CallSalt} event if `salt` is not zero. [.contract-item] [[ITimelock-cancel]] @@ -2127,7 +2689,7 @@ Requirements: - The caller must have the `CANCELLER_ROLE` role. - `id` must be an operation. -Emits a {CallCancelled} event. +Emits a {ITimelock-CallCancelled} event. [.contract-item] [[ITimelock-execute]] @@ -2141,7 +2703,7 @@ Requirements: - `id` must be in Ready OperationState. - `predecessor` must either be `0` or in Done OperationState. -Emits a {CallExecuted} event. +Emits a {ITimelock-CallExecuted} event. NOTE: This function can reenter, but it doesn't pose a risk because <> checks that the proposal is pending, thus any modifications to the operation during @@ -2159,7 +2721,7 @@ Requirements: - `id` must be in Ready OperationState. - `predecessor` must either be `0` or in Done OperationState. -Emits a {CallExecuted} event for each Call. +Emits a {ITimelock-CallExecuted} event for each Call. NOTE: This function can reenter, but it doesn't pose a risk because `_after_call` checks that the proposal is pending, thus any modifications to the operation during @@ -2177,7 +2739,7 @@ Requirements: and later executing an operation where the timelock is the target and the data is the serialized call to this function. -Emits a {MinDelayChanged} event. +Emits a {ITimelock-MinDelayChanged} event. [#ITimelock-Events] ==== Events @@ -2378,7 +2940,7 @@ Requirements: - `delay` must be greater than or equal to the min delay. Emits {CallScheduled} event. -Emits {CallSalt} event if `salt` is not zero. +Emits {ITimelock-CallSalt} event if `salt` is not zero. [.contract-item] [[TimelockControllerComponent-schedule_batch]] @@ -2393,7 +2955,7 @@ Requirements: - `delay` must be greater than or equal to the min delay. Emits one {CallScheduled} event for each transaction in the batch. -Emits {CallSalt} event if `salt` is not zero. +Emits {ITimelock-CallSalt} event if `salt` is not zero. [.contract-item] [[TimelockControllerComponent-cancel]] From 0acb8750002a2d9effbb7edcf495672b356ddf7e Mon Sep 17 00:00:00 2001 From: immrsd Date: Tue, 10 Dec 2024 14:57:59 +0100 Subject: [PATCH 02/28] Fix Votes broken link --- docs/modules/ROOT/pages/governance/votes.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/governance/votes.adoc b/docs/modules/ROOT/pages/governance/votes.adoc index d66ea7041..00aa3e943 100644 --- a/docs/modules/ROOT/pages/governance/votes.adoc +++ b/docs/modules/ROOT/pages/governance/votes.adoc @@ -4,7 +4,7 @@ :delegate: xref:api/governance.adoc#VotesComponent-delegate[delegate] :delegate_by_sig: xref:api/governance.adoc#VotesComponent-delegate_by_sig[delegate_by_sig] :voting_units_trait: xref:api/governance.adoc#VotingUnitsTrait[VotingUnitsTrait] -:votes-usage: xref:../governance.adoc#usage_2[usage] +:votes-usage: xref:Usage[usage] :nonces-component: xref:api/utilities.adoc#NoncesComponent[NoncesComponent] :snip12-metadata: xref:api/utilities.adoc#snip12[SNIP12Metadata] From c962eefe003b4179245d1799c96fabd716b7c119 Mon Sep 17 00:00:00 2001 From: immrsd Date: Tue, 10 Dec 2024 14:58:38 +0100 Subject: [PATCH 03/28] Add Multisig doc page --- docs/modules/ROOT/nav.adoc | 1 + .../ROOT/pages/governance/multisig.adoc | 147 ++++++++++++++++++ 2 files changed, 148 insertions(+) create mode 100644 docs/modules/ROOT/pages/governance/multisig.adoc diff --git a/docs/modules/ROOT/nav.adoc b/docs/modules/ROOT/nav.adoc index f8c64e604..f464a2239 100644 --- a/docs/modules/ROOT/nav.adoc +++ b/docs/modules/ROOT/nav.adoc @@ -22,6 +22,7 @@ ** Governance *** xref:/governance/governor.adoc[Governor] +*** xref:/governance/multisig.adoc[Multisig] *** xref:/governance/timelock.adoc[Timelock Controller] *** xref:/governance/votes.adoc[Votes] *** xref:/api/governance.adoc[API Reference] diff --git a/docs/modules/ROOT/pages/governance/multisig.adoc b/docs/modules/ROOT/pages/governance/multisig.adoc new file mode 100644 index 000000000..2a161ba26 --- /dev/null +++ b/docs/modules/ROOT/pages/governance/multisig.adoc @@ -0,0 +1,147 @@ += Multisig + +:multisig-component: xref:api/governance.adoc#MultisigComponent[MultisigComponent] +:snip12-metadata: xref:api/utilities.adoc#snip12[SNIP12Metadata] + +The Multisig component implements a multi-signature mechanism to enhance the security and +governance of smart contract transactions. It ensures that no single signer can unilaterally +execute critical actions, requiring multiple registered signers to approve and collectively +execute transactions. + +This component is designed to secure operations such as fund management or protocol governance, +where collective decision-making is essential. The Multisig Component is self-administered, +meaning that changes to signers or quorum must be approved through the multisig process itself. + +== Key Features + +- *Multi-Signature Security*: Transactions must be approved by multiple signers, ensuring +distributed governance. + +- *Quorum Enforcement*: Defines the minimum number of approvals required for transaction execution. + +- *Self-Administration*: All modifications to the component (e.g., adding or removing signers) +must pass through the multisig process. + +- *Event Logging*: Provides comprehensive event logging for transparency and auditability. + +== Signer Management + +The Multisig component introduces the concept of signers and quorum: + +- *Signers*: Only registered signers can submit, confirm, revoke, or execute transactions. The Multisig +Component supports adding, removing, or replacing signers. +- *Quorum*: The quorum defines the minimum number of confirmations required to approve a transaction. + +NOTE: To prevent unauthorized modifications, only the contract itself can add, remove, or replace signers or change the quorum. +This ensures that all modifications pass through the multisig approval process. + +== Transaction Lifecycle + +A transaction in the Multisig component follows a specific lifecycle: + +`NotFound` → `Pending` → `Confirmed` → `Executed` + +The state of a transaction is respresented by `TransactionState` enum can be checked +by calling the `get_transaction_state` function. + +- *NotFound*: The transaction does not exist. +- *Pending*: The transaction exists but has not reached the required confirmations. +- *Confirmed*: The transaction has reached the quorum but has not yet been executed. +- *Executed*: The transaction has been successfully executed. + +== Usage + +Integrating the Multisig functionality into a contract requires implementing {multisig-component}. +The contract's constructor should initialize the component with a quorum value and a list of initial signers. + +Here's an example of a simple wallet contract featuring the Multisig functionality: + +[,cairo] +---- +#[starknet::contract] +mod MultisigWallet { + use openzeppelin_governance::multisig::MultisigComponent; + use starknet::ContractAddress; + + component!(path: MultisigComponent, storage: multisig, event: MultisigEvent); + + #[abi(embed_v0)] + impl MultisigImpl = MultisigComponent::MultisigImpl; + impl MultisigInternalImpl = MultisigComponent::InternalImpl; + + #[storage] + struct Storage { + #[substorage(v0)] + multisig: MultisigComponent::Storage, + } + + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + #[flat] + MultisigEvent: MultisigComponent::Event, + } + + #[constructor] + fn constructor(ref self: ContractState, quorum: u32, signers: Span) { + self.multisig.initializer(quorum, signers); + } +} +---- + +== Interface + +This is the interface of a contract implementing the {multisig-component}: + +[,cairo] +---- +#[starknet::interface] +pub trait MultisigABI { + // Read functions + fn get_quorum(self: @TState) -> u32; + fn is_signer(self: @TState, signer: ContractAddress) -> bool; + fn get_signers(self: @TState) -> Span; + fn is_confirmed(self: @TState, id: TransactionID) -> bool; + fn is_confirmed_by(self: @TState, id: TransactionID, signer: ContractAddress) -> bool; + fn is_executed(self: @TState, id: TransactionID) -> bool; + fn get_submitted_block(self: @TState, id: TransactionID) -> u64; + fn get_transaction_state(self: @TState, id: TransactionID) -> TransactionState; + fn get_transaction_confirmations(self: @TState, id: TransactionID) -> u32; + fn hash_transaction( + self: @TState, + to: ContractAddress, + selector: felt252, + calldata: Span, + salt: felt252, + ) -> TransactionID; + fn hash_transaction_batch(self: @TState, calls: Span, salt: felt252) -> TransactionID; + + // Write functions + fn add_signers(ref self: TState, new_quorum: u32, signers_to_add: Span); + fn remove_signers(ref self: TState, new_quorum: u32, signers_to_remove: Span); + fn replace_signer( + ref self: TState, signer_to_remove: ContractAddress, signer_to_add: ContractAddress, + ); + fn change_quorum(ref self: TState, new_quorum: u32); + fn submit_transaction( + ref self: TState, + to: ContractAddress, + selector: felt252, + calldata: Span, + salt: felt252, + ) -> TransactionID; + fn submit_transaction_batch( + ref self: TState, calls: Span, salt: felt252, + ) -> TransactionID; + fn confirm_transaction(ref self: TState, id: TransactionID); + fn revoke_confirmation(ref self: TState, id: TransactionID); + fn execute_transaction( + ref self: TState, + to: ContractAddress, + selector: felt252, + calldata: Span, + salt: felt252, + ); + fn execute_transaction_batch(ref self: TState, calls: Span, salt: felt252); +} +---- From 300bd57c96e553a650edfc6b6585447dc6ba81b7 Mon Sep 17 00:00:00 2001 From: immrsd Date: Tue, 10 Dec 2024 15:03:24 +0100 Subject: [PATCH 04/28] Fix RoleGranted event link in doc --- docs/modules/ROOT/pages/api/governance.adoc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/modules/ROOT/pages/api/governance.adoc b/docs/modules/ROOT/pages/api/governance.adoc index 120d58772..f561d7a6b 100644 --- a/docs/modules/ROOT/pages/api/governance.adoc +++ b/docs/modules/ROOT/pages/api/governance.adoc @@ -12,7 +12,7 @@ :ITimelock-CallSalt: xref:ITimelock-CallSalt[CallSalt] :ITimelock-CallCancelled: xref:ITimelock-CallCancelled[CallCancelled] :ITimelock-MinDelayChanged: xref:ITimelock-MinDelayChanged[MinDelayChanged] -:ITimelock-RoleGranted: xref:api/access.adoc#IAccessControl-RoleGranted[IAccessControl::RoleGranted] +:IAccessControl-RoleGranted: xref:api/access.adoc#IAccessControl-RoleGranted[IAccessControl::RoleGranted] :DelegateChanged: xref:VotesComponent-DelegateChanged[DelegateChanged] :DelegateVotesChanged: xref:VotesComponent-DelegateVotesChanged[DelegateVotesChanged] :VotingUnitsTrait: xref:VotingUnitsTrait[VotingUnitsTrait] @@ -3040,12 +3040,12 @@ WARNING: The optional admin can aid with initial configuration of roles after de without being subject to delay, but this role should be subsequently renounced in favor of administration through timelocked proposals. -Emits two {RoleGranted} events for each account in `proposers` with `PROPOSER_ROLE` and +Emits two {IAccessControl-RoleGranted} events for each account in `proposers` with `PROPOSER_ROLE` and `CANCELLER_ROLE` roles. -Emits a {RoleGranted} event for each account in `executors` with `EXECUTOR_ROLE` role. +Emits a {IAccessControl-RoleGranted} event for each account in `executors` with `EXECUTOR_ROLE` role. -May emit a {RoleGranted} event for `admin` with `DEFAULT_ADMIN_ROLE` role (if `admin` is +May emit a {IAccessControl-RoleGranted} event for `admin` with `DEFAULT_ADMIN_ROLE` role (if `admin` is not zero). Emits {MinDelayChanged} event. From cb291f3114bc0518ae3618de7c8d21a956845648 Mon Sep 17 00:00:00 2001 From: immrsd Date: Tue, 10 Dec 2024 15:06:14 +0100 Subject: [PATCH 05/28] Rename refs to events from Votes component to be explicit --- docs/modules/ROOT/pages/api/governance.adoc | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/modules/ROOT/pages/api/governance.adoc b/docs/modules/ROOT/pages/api/governance.adoc index f561d7a6b..d76c8e669 100644 --- a/docs/modules/ROOT/pages/api/governance.adoc +++ b/docs/modules/ROOT/pages/api/governance.adoc @@ -13,8 +13,8 @@ :ITimelock-CallCancelled: xref:ITimelock-CallCancelled[CallCancelled] :ITimelock-MinDelayChanged: xref:ITimelock-MinDelayChanged[MinDelayChanged] :IAccessControl-RoleGranted: xref:api/access.adoc#IAccessControl-RoleGranted[IAccessControl::RoleGranted] -:DelegateChanged: xref:VotesComponent-DelegateChanged[DelegateChanged] -:DelegateVotesChanged: xref:VotesComponent-DelegateVotesChanged[DelegateVotesChanged] +:VotesComponent-DelegateChanged: xref:VotesComponent-DelegateChanged[DelegateChanged] +:VotesComponent-DelegateVotesChanged: xref:VotesComponent-DelegateVotesChanged[DelegateVotesChanged] :VotingUnitsTrait: xref:VotingUnitsTrait[VotingUnitsTrait] :VotesComponent: xref:VotesComponent[VotesComponent] :IVotes: xref:IVotes[IVotes] @@ -3347,9 +3347,9 @@ Returns the delegate that `account` has chosen. Delegates votes from the sender to `delegatee`. -Emits a {DelegateChanged} event. +Emits a {VotesComponent-DelegateChanged} event. -May emit one or two {DelegateVotesChanged} events. +May emit one or two {VotesComponent-DelegateVotesChanged} events. [.contract-item] [[VotesComponent-delegate_by_sig]] @@ -3364,9 +3364,9 @@ Requirements: - `delegator` must implement `SRC6::is_valid_signature`. - `signature` should be valid for the message hash. -Emits a {DelegateChanged} event. +Emits a {VotesComponent-DelegateChanged} event. -May emit one or two {DelegateVotesChanged} events. +May emit one or two {VotesComponent-DelegateVotesChanged} events. [#VotesComponent-Internal-functions] ==== Internal functions @@ -3383,7 +3383,7 @@ Returns the current total supply of votes. Moves delegated votes from one delegate to another. -May emit one or two {DelegateVotesChanged} events. +May emit one or two {VotesComponent-DelegateVotesChanged} events. [.contract-item] [[VotesComponent-transfer_voting_units]] @@ -3396,7 +3396,7 @@ should be zero. Total supply of voting units will be adjusted with mints and bur WARNING: If voting units are based on an underlying transferable asset (like a token), you must call this function every time the asset is transferred to keep the internal voting power accounting in sync. For ERC20 and ERC721 tokens, this is typically handled using hooks. -May emit one or two {DelegateVotesChanged} events. +May emit one or two {VotesComponent-DelegateVotesChanged} events. [.contract-item] [[VotesComponent-num_checkpoints]] @@ -3416,9 +3416,9 @@ Returns the `pos`-th checkpoint for `account`. Delegates all of ``account``'s voting units to `delegatee`. -Emits a {DelegateChanged} event. +Emits a {VotesComponent-DelegateChanged} event. -May emit one or two {DelegateVotesChanged} events. +May emit one or two {VotesComponent-DelegateVotesChanged} events. [#VotesComponent-Events] ==== Events From dbf36cc8ce031e7cb79e045627949245e1fdf0d5 Mon Sep 17 00:00:00 2001 From: immrsd Date: Wed, 11 Dec 2024 08:16:05 +0100 Subject: [PATCH 06/28] Add newlines after "Requirements:" --- docs/modules/ROOT/pages/api/governance.adoc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/modules/ROOT/pages/api/governance.adoc b/docs/modules/ROOT/pages/api/governance.adoc index d76c8e669..4a308f4e7 100644 --- a/docs/modules/ROOT/pages/api/governance.adoc +++ b/docs/modules/ROOT/pages/api/governance.adoc @@ -2108,6 +2108,7 @@ Returns the block number when the transaction with the given `id` was submitted. Adds new signers and updates the quorum. Requirements: + - The caller must be the contract itself. - `new_quorum` must be less than or equal to the total number of signers after addition. @@ -2121,6 +2122,7 @@ Emits a {IMultisig-QuorumUpdated} event if the quorum changes. Removes signers and updates the quorum. Requirements: + - The caller must be the contract itself. - `new_quorum` must be less than or equal to the total number of signers after removal. @@ -2134,6 +2136,7 @@ Emits a {IMultisig-QuorumUpdated} event if the quorum changes. Replaces an existing signer with a new signer. Requirements: + - The caller must be the contract itself. - `signer_to_remove` must be an existing signer. - `signer_to_add` must not be an existing signer. @@ -2148,6 +2151,7 @@ Emits a {IMultisig-SignerAdded} event for the new signer. Updates the quorum value to `new_quorum` if it differs from the current quorum. Requirements: + - The caller must be the contract itself. - `new_quorum` must be non-zero. - `new_quorum` must be less than or equal to the total number of signers. @@ -2161,6 +2165,7 @@ Emits a {IMultisig-QuorumUpdated} event if the quorum changes. Submits a new transaction for confirmation. Requirements: + - The caller must be a registered signer. - The transaction must not have been submitted before. @@ -2174,6 +2179,7 @@ Emits a {IMultisig-CallSalt} event if `salt` is not zero. Submits a new batch transaction for confirmation. Requirements: + - The caller must be a registered signer. - The transaction must not have been submitted before. @@ -2187,6 +2193,7 @@ Emits a {IMultisig-CallSalt} event if `salt` is not zero. Confirms a transaction with the given `id`. Requirements: + - The caller must be a registered signer. - The transaction must exist and not be executed. - The caller must not have already confirmed the transaction. @@ -2200,6 +2207,7 @@ Emits a {IMultisig-TransactionConfirmed} event. Revokes a previous confirmation for a transaction with the given `id`. Requirements: + - The transaction must exist and not be executed. - The caller must have previously confirmed the transaction. @@ -2212,6 +2220,7 @@ Emits a {IMultisig-ConfirmationRevoked} event. Executes a confirmed transaction. Requirements: + - The caller must be a registered signer. - The transaction must be confirmed and not yet executed. @@ -2224,6 +2233,7 @@ Emits a {IMultisig-TransactionExecuted} event. Executes a confirmed batch transaction. Requirements: + - The caller must be a registered signer. - The transaction must be confirmed and not yet executed. From 30387bb5024907533de2485c1fbdd588e0a724e7 Mon Sep 17 00:00:00 2001 From: immrsd Date: Wed, 11 Dec 2024 08:17:31 +0100 Subject: [PATCH 07/28] Improve description of the is_confirmed fn --- docs/modules/ROOT/pages/api/governance.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/api/governance.adoc b/docs/modules/ROOT/pages/api/governance.adoc index 4a308f4e7..941e4a637 100644 --- a/docs/modules/ROOT/pages/api/governance.adoc +++ b/docs/modules/ROOT/pages/api/governance.adoc @@ -2390,7 +2390,7 @@ Returns a list of all current signers. [[MultisigComponent-is_confirmed]] ==== `[.contract-item-name]#++is_confirmed++#++(self: @ContractState, id: TransactionID) → bool++` [.item-kind]#external# -Determines if the transaction with `id` is confirmed. +Returns whether the transaction with the given `id` has been confirmed. A confirmed transaction has received the required number of confirmations (quorum). [.contract-item] [[MultisigComponent-is_confirmed_by]] From b0308c7240674182221b435579383a44a6fe0403 Mon Sep 17 00:00:00 2001 From: immrsd Date: Wed, 11 Dec 2024 08:18:06 +0100 Subject: [PATCH 08/28] Add requirements and events to Multisig component function references --- docs/modules/ROOT/pages/api/governance.adoc | 137 +++++++++++++++++++- 1 file changed, 135 insertions(+), 2 deletions(-) diff --git a/docs/modules/ROOT/pages/api/governance.adoc b/docs/modules/ROOT/pages/api/governance.adoc index 941e4a637..0c1bb8b9c 100644 --- a/docs/modules/ROOT/pages/api/governance.adoc +++ b/docs/modules/ROOT/pages/api/governance.adoc @@ -2428,60 +2428,138 @@ Returns the block number when the transaction with `id` was submitted. Adds new signers and updates the quorum. +Requirements: + +- The caller must be the contract itself. +- `new_quorum` must be less than or equal to the total number of signers after addition. + +Emits a {IMultisig-SignerAdded} event for each signer added. +Emits a {IMultisig-QuorumUpdated} event if the quorum changes. + [.contract-item] [[MultisigComponent-remove_signers]] ==== `[.contract-item-name]#++remove_signers++#++(ref self: ContractState, new_quorum: u32, signers_to_remove: Span)++` [.item-kind]#external# Removes signers and updates the quorum. +Requirements: + +- The caller must be the contract itself. +- `new_quorum` must be less than or equal to the total number of signers after removal. + +Emits a {IMultisig-SignerRemoved} event for each signer removed. +Emits a {IMultisig-QuorumUpdated} event if the quorum changes. + [.contract-item] [[MultisigComponent-replace_signer]] ==== `[.contract-item-name]#++replace_signer++#++(ref self: ContractState, signer_to_remove: ContractAddress, signer_to_add: ContractAddress)++` [.item-kind]#external# Replaces an existing signer with a new signer. +Requirements: + +- The caller must be the contract itself. +- `signer_to_remove` must be an existing signer. +- `signer_to_add` must not be an existing signer. + +Emits a {IMultisig-SignerRemoved} event for the removed signer. +Emits a {IMultisig-SignerAdded} event for the new signer. + [.contract-item] [[MultisigComponent-change_quorum]] ==== `[.contract-item-name]#++change_quorum++#++(ref self: ContractState, new_quorum: u32)++` [.item-kind]#external# Updates the quorum value to `new_quorum`. +Requirements: + +- The caller must be the contract itself. +- `new_quorum` must be non-zero. +- `new_quorum` must be less than or equal to the total number of signers. + +Emits a {IMultisig-QuorumUpdated} event if the quorum changes. + [.contract-item] [[MultisigComponent-submit_transaction]] ==== `[.contract-item-name]#++submit_transaction++#++(ref self: ContractState, to: ContractAddress, selector: felt252, calldata: Span, salt: felt252)++` [.item-kind]#external# Submits a new transaction for confirmation. +Requirements: + +- The caller must be a registered signer. +- The transaction must not have been submitted before. + +Emits a {IMultisig-TransactionSubmitted} event. +Emits a {IMultisig-CallSalt} event if `salt` is not zero. + [.contract-item] [[MultisigComponent-submit_transaction_batch]] ==== `[.contract-item-name]#++submit_transaction_batch++#++(ref self: ContractState, calls: Span, salt: felt252)++` [.item-kind]#external# Submits a new batch transaction for confirmation. +Requirements: + +- The caller must be a registered signer. +- The transaction must not have been submitted before. + +Emits a {IMultisig-TransactionSubmitted} event. +Emits a {IMultisig-CallSalt} event if `salt` is not zero. + [.contract-item] [[MultisigComponent-confirm_transaction]] ==== `[.contract-item-name]#++confirm_transaction++#++(ref self: ContractState, id: TransactionID)++` [.item-kind]#external# Confirms a transaction with the given `id`. +Requirements: + +- The caller must be a registered signer. +- The transaction must exist and not be executed. +- The caller must not have already confirmed the transaction. + +Emits a {IMultisig-TransactionConfirmed} event. + [.contract-item] [[MultisigComponent-revoke_confirmation]] ==== `[.contract-item-name]#++revoke_confirmation++#++(ref self: ContractState, id: TransactionID)++` [.item-kind]#external# Revokes a previous confirmation for a transaction with the given `id`. +Requirements: + +- The transaction must exist and not be executed. +- The caller must have previously confirmed the transaction. + +Emits a {IMultisig-ConfirmationRevoked} event. + [.contract-item] [[MultisigComponent-execute_transaction]] ==== `[.contract-item-name]#++execute_transaction++#++(ref self: ContractState, to: ContractAddress, selector: felt252, calldata: Span, salt: felt252)++` [.item-kind]#external# Executes a confirmed transaction. +Requirements: + +- The caller must be a registered signer. +- The transaction must be confirmed and not yet executed. + +Emits a {IMultisig-TransactionExecuted} event. + [.contract-item] [[MultisigComponent-execute_transaction_batch]] ==== `[.contract-item-name]#++execute_transaction_batch++#++(ref self: ContractState, calls: Span, salt: felt252)++` [.item-kind]#external# Executes a confirmed batch transaction. +Requirements: + +- The caller must be a registered signer. +- The transaction must be confirmed and not yet executed. + +Emits a {IMultisig-TransactionExecuted} event. + [.contract-item] [[MultisigComponent-hash_transaction]] ==== `[.contract-item-name]#++hash_transaction++#++(self: @ContractState, to: ContractAddress, selector: felt252, calldata: Span, salt: felt252)++` [.item-kind]#external# @@ -2502,9 +2580,14 @@ Returns the computed identifier of a transaction containing a batch of calls. ==== `[.contract-item-name]#++initializer++#++(ref self: ContractState, quorum: u32, signers: Span)++` [.item-kind]#internal# Initializes the Multisig component with the initial `quorum` and `signers`. +This function must be called during contract initialization to set up the initial state. -Emits a `SignerAdded` event for each signer added. -Emits a `QuorumUpdated` event if the quorum changes. +Requirements: + +- `quorum` must be non-zero and less than or equal to the number of `signers`. + +Emits a `SignerAdded` event for each signer added. +Emits a `QuorumUpdated` event. [.contract-item] [[MultisigComponent-resolve_tx_state]] @@ -2512,48 +2595,98 @@ Emits a `QuorumUpdated` event if the quorum changes. Resolves and returns the current state of the transaction with the given `id`. +The possible states are: +- `NotFound`: The transaction does not exist. +- `Pending`: The transaction exists but hasn't reached the required confirmations. +- `Confirmed`: The transaction has reached the required confirmations but hasn't been executed. +- `Executed`: The transaction has been executed. + [.contract-item] [[MultisigComponent-assert_one_of_signers]] ==== `[.contract-item-name]#++assert_one_of_signers++#++(self: @ContractState, caller: ContractAddress)++` [.item-kind]#internal# Asserts that the `caller` is one of the registered signers. +Requirements: + +- The `caller` must be a registered signer. + [.contract-item] [[MultisigComponent-assert_tx_exists]] ==== `[.contract-item-name]#++assert_tx_exists++#++(self: @ContractState, id: TransactionID)++` [.item-kind]#internal# Asserts that a transaction with the given `id` exists. +Requirements: + +- The transaction with `id` must have been submitted. + [.contract-item] [[MultisigComponent-assert_only_self]] ==== `[.contract-item-name]#++assert_only_self++#++(self: @ContractState)++` [.item-kind]#internal# Asserts that the caller is the contract itself. +Requirements: + +- The caller must be the contract's own address. + [.contract-item] [[MultisigComponent-_add_signers]] ==== `[.contract-item-name]#++_add_signers++#++(ref self: ContractState, new_quorum: u32, signers_to_add: Span)++` [.item-kind]#internal# Adds new signers and updates the quorum. +Requirements: + +- Each signer address must be non-zero. +- `new_quorum` must be non-zero and less than or equal to the total number of signers after addition. + +Emits a `SignerAdded` event for each new signer added. +Emits a `QuorumUpdated` event if the quorum changes. + [.contract-item] [[MultisigComponent-_remove_signers]] ==== `[.contract-item-name]#++_remove_signers++#++(ref self: ContractState, new_quorum: u32, signers_to_remove: Span)++` [.item-kind]#internal# Removes existing signers and updates the quorum. +Requirements: + +- `new_quorum` must be non-zero and less than or equal to the total number of signers +after removal. + +Emits a `SignerRemoved` event for each signer removed. +Emits a `QuorumUpdated` event if the quorum changes. + [.contract-item] [[MultisigComponent-_replace_signer]] ==== `[.contract-item-name]#++_replace_signer++#++(ref self: ContractState, signer_to_remove: ContractAddress, signer_to_add: ContractAddress)++` [.item-kind]#internal# Replaces an existing signer with a new signer. +Requirements: + +- `signer_to_remove` must be an existing signer. +- `signer_to_add` must not be an existing signer. +- `signer_to_add` must be a non-zero address. + +Emits a `SignerRemoved` event for the removed signer. +Emits a `SignerAdded` event for the new signer. + [.contract-item] [[MultisigComponent-_change_quorum]] ==== `[.contract-item-name]#++_change_quorum++#++(ref self: ContractState, new_quorum: u32)++` [.item-kind]#internal# Updates the quorum value to `new_quorum` if it differs from the current quorum. +Requirements: + +- `new_quorum` must be non-zero. +- `new_quorum` must be less than or equal to the total number of signers. + +Emits a `QuorumUpdated` event if the quorum changes. + == Timelock In a governance system, `TimelockControllerComponent` is in charge of introducing a delay between a proposal and its execution. From 9d715d6473979c2990b9f99ebc52c07ed2977524 Mon Sep 17 00:00:00 2001 From: immrsd Date: Wed, 11 Dec 2024 08:18:37 +0100 Subject: [PATCH 09/28] Fix typo --- docs/modules/ROOT/pages/governance/multisig.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/governance/multisig.adoc b/docs/modules/ROOT/pages/governance/multisig.adoc index 2a161ba26..f029ae659 100644 --- a/docs/modules/ROOT/pages/governance/multisig.adoc +++ b/docs/modules/ROOT/pages/governance/multisig.adoc @@ -41,7 +41,7 @@ A transaction in the Multisig component follows a specific lifecycle: `NotFound` → `Pending` → `Confirmed` → `Executed` -The state of a transaction is respresented by `TransactionState` enum can be checked +The state of a transaction is represented by the `TransactionState` enum and can be checked by calling the `get_transaction_state` function. - *NotFound*: The transaction does not exist. From af8bef451c7cbb7b45e94ec78fef8a610e03165c Mon Sep 17 00:00:00 2001 From: immrsd Date: Wed, 11 Dec 2024 08:19:18 +0100 Subject: [PATCH 10/28] Fix doc line regarding QuorumUpdated event --- packages/governance/src/multisig/multisig.cairo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/governance/src/multisig/multisig.cairo b/packages/governance/src/multisig/multisig.cairo index b641f2272..5e9a76c1b 100644 --- a/packages/governance/src/multisig/multisig.cairo +++ b/packages/governance/src/multisig/multisig.cairo @@ -467,7 +467,7 @@ pub mod MultisigComponent { /// - `quorum` must be non-zero and less than or equal to the number of `signers`. /// /// Emits a `SignerAdded` event for each signer added. - /// Emits a `QuorumUpdated` event if the quorum changes. + /// Emits a `QuorumUpdated` event. fn initializer( ref self: ComponentState, quorum: u32, signers: Span, ) { From 4d9b4910045feae80ca63ee5bb48a974cd24d711 Mon Sep 17 00:00:00 2001 From: immrsd Date: Wed, 11 Dec 2024 08:35:13 +0100 Subject: [PATCH 11/28] Fix event links --- docs/modules/ROOT/pages/api/governance.adoc | 162 ++++++++++++++------ 1 file changed, 115 insertions(+), 47 deletions(-) diff --git a/docs/modules/ROOT/pages/api/governance.adoc b/docs/modules/ROOT/pages/api/governance.adoc index 0c1bb8b9c..ad1fe318d 100644 --- a/docs/modules/ROOT/pages/api/governance.adoc +++ b/docs/modules/ROOT/pages/api/governance.adoc @@ -1,17 +1,4 @@ :github-icon: pass:[] -:IMultisig-CallSalt: xref:IMultisig-CallSalt[CallSalt] -:IMultisig-SignerAdded: xref:IMultisig-CallSalt[SignerAdded] -:IMultisig-SignerRemoved: xref:IMultisig-CallSalt[SignerRemoved] -:IMultisig-QuorumUpdated: xref:IMultisig-CallSalt[QuorumUpdated] -:IMultisig-TransactionSubmitted: xref:IMultisig-CallSalt[TransactionSubmitted] -:IMultisig-TransactionConfirmed: xref:IMultisig-CallSalt[TransactionConfirmed] -:IMultisig-ConfirmationRevoked: xref:IMultisig-CallSalt[ConfirmationRevoked] -:IMultisig-TransactionExecuted: xref:IMultisig-CallSalt[TransactionExecuted] -:ITimelock-CallScheduled: xref:ITimelock-CallScheduled[CallScheduled] -:ITimelock-CallExecuted: xref:ITimelock-CallExecuted[CallExecuted] -:ITimelock-CallSalt: xref:ITimelock-CallSalt[CallSalt] -:ITimelock-CallCancelled: xref:ITimelock-CallCancelled[CallCancelled] -:ITimelock-MinDelayChanged: xref:ITimelock-MinDelayChanged[MinDelayChanged] :IAccessControl-RoleGranted: xref:api/access.adoc#IAccessControl-RoleGranted[IAccessControl::RoleGranted] :VotesComponent-DelegateChanged: xref:VotesComponent-DelegateChanged[DelegateChanged] :VotesComponent-DelegateVotesChanged: xref:VotesComponent-DelegateVotesChanged[DelegateVotesChanged] @@ -1992,12 +1979,21 @@ Emitted when the timelock controller is updated. == Multisig -Description +TODO: Add description [.contract] [[IMultisig]] === `++IMultisig++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.20.0/packages/governance/src/multisig/interface.cairo[{github-icon},role=heading-link] +:IMultisig-CallSalt: xref:IMultisig-CallSalt[CallSalt] +:IMultisig-SignerAdded: xref:IMultisig-CallSalt[SignerAdded] +:IMultisig-SignerRemoved: xref:IMultisig-CallSalt[SignerRemoved] +:IMultisig-QuorumUpdated: xref:IMultisig-CallSalt[QuorumUpdated] +:IMultisig-TransactionSubmitted: xref:IMultisig-CallSalt[TransactionSubmitted] +:IMultisig-TransactionConfirmed: xref:IMultisig-CallSalt[TransactionConfirmed] +:IMultisig-ConfirmationRevoked: xref:IMultisig-CallSalt[ConfirmationRevoked] +:IMultisig-TransactionExecuted: xref:IMultisig-CallSalt[TransactionExecuted] + [.hljs-theme-dark] ```cairo use openzeppelin_governance::multisig::interface::IMultisig; @@ -2306,6 +2302,15 @@ Emitted when a new transaction is submitted with non-zero salt. [[MultisigComponent]] === `++MultisigComponent++` +:MultisigComponent-CallSalt: xref:MultisigComponent-CallSalt[CallSalt] +:MultisigComponent-SignerAdded: xref:MultisigComponent-CallSalt[SignerAdded] +:MultisigComponent-SignerRemoved: xref:MultisigComponent-CallSalt[SignerRemoved] +:MultisigComponent-QuorumUpdated: xref:MultisigComponent-CallSalt[QuorumUpdated] +:MultisigComponent-TransactionSubmitted: xref:MultisigComponent-CallSalt[TransactionSubmitted] +:MultisigComponent-TransactionConfirmed: xref:MultisigComponent-CallSalt[TransactionConfirmed] +:MultisigComponent-ConfirmationRevoked: xref:MultisigComponent-CallSalt[ConfirmationRevoked] +:MultisigComponent-TransactionExecuted: xref:MultisigComponent-CallSalt[TransactionExecuted] + Component that implements `IMultisig` and provides functionality for multisignature wallets, including transaction management, quorum handling, and signer operations. [.contract-index#MultisigComponent-Embeddable-Impls] @@ -2433,8 +2438,8 @@ Requirements: - The caller must be the contract itself. - `new_quorum` must be less than or equal to the total number of signers after addition. -Emits a {IMultisig-SignerAdded} event for each signer added. -Emits a {IMultisig-QuorumUpdated} event if the quorum changes. +Emits a {MultisigComponent-SignerAdded} event for each signer added. +Emits a {MultisigComponent-QuorumUpdated} event if the quorum changes. [.contract-item] [[MultisigComponent-remove_signers]] @@ -2447,8 +2452,8 @@ Requirements: - The caller must be the contract itself. - `new_quorum` must be less than or equal to the total number of signers after removal. -Emits a {IMultisig-SignerRemoved} event for each signer removed. -Emits a {IMultisig-QuorumUpdated} event if the quorum changes. +Emits a {MultisigComponent-SignerRemoved} event for each signer removed. +Emits a {MultisigComponent-QuorumUpdated} event if the quorum changes. [.contract-item] [[MultisigComponent-replace_signer]] @@ -2462,8 +2467,8 @@ Requirements: - `signer_to_remove` must be an existing signer. - `signer_to_add` must not be an existing signer. -Emits a {IMultisig-SignerRemoved} event for the removed signer. -Emits a {IMultisig-SignerAdded} event for the new signer. +Emits a {MultisigComponent-SignerRemoved} event for the removed signer. +Emits a {MultisigComponent-SignerAdded} event for the new signer. [.contract-item] [[MultisigComponent-change_quorum]] @@ -2477,7 +2482,7 @@ Requirements: - `new_quorum` must be non-zero. - `new_quorum` must be less than or equal to the total number of signers. -Emits a {IMultisig-QuorumUpdated} event if the quorum changes. +Emits a {MultisigComponent-QuorumUpdated} event if the quorum changes. [.contract-item] [[MultisigComponent-submit_transaction]] @@ -2490,8 +2495,8 @@ Requirements: - The caller must be a registered signer. - The transaction must not have been submitted before. -Emits a {IMultisig-TransactionSubmitted} event. -Emits a {IMultisig-CallSalt} event if `salt` is not zero. +Emits a {MultisigComponent-TransactionSubmitted} event. +Emits a {MultisigComponent-CallSalt} event if `salt` is not zero. [.contract-item] [[MultisigComponent-submit_transaction_batch]] @@ -2504,8 +2509,8 @@ Requirements: - The caller must be a registered signer. - The transaction must not have been submitted before. -Emits a {IMultisig-TransactionSubmitted} event. -Emits a {IMultisig-CallSalt} event if `salt` is not zero. +Emits a {MultisigComponent-TransactionSubmitted} event. +Emits a {MultisigComponent-CallSalt} event if `salt` is not zero. [.contract-item] [[MultisigComponent-confirm_transaction]] @@ -2519,7 +2524,7 @@ Requirements: - The transaction must exist and not be executed. - The caller must not have already confirmed the transaction. -Emits a {IMultisig-TransactionConfirmed} event. +Emits a {MultisigComponent-TransactionConfirmed} event. [.contract-item] [[MultisigComponent-revoke_confirmation]] @@ -2532,7 +2537,7 @@ Requirements: - The transaction must exist and not be executed. - The caller must have previously confirmed the transaction. -Emits a {IMultisig-ConfirmationRevoked} event. +Emits a {MultisigComponent-ConfirmationRevoked} event. [.contract-item] [[MultisigComponent-execute_transaction]] @@ -2545,7 +2550,7 @@ Requirements: - The caller must be a registered signer. - The transaction must be confirmed and not yet executed. -Emits a {IMultisig-TransactionExecuted} event. +Emits a {MultisigComponent-TransactionExecuted} event. [.contract-item] [[MultisigComponent-execute_transaction_batch]] @@ -2558,7 +2563,7 @@ Requirements: - The caller must be a registered signer. - The transaction must be confirmed and not yet executed. -Emits a {IMultisig-TransactionExecuted} event. +Emits a {MultisigComponent-TransactionExecuted} event. [.contract-item] [[MultisigComponent-hash_transaction]] @@ -2586,8 +2591,8 @@ Requirements: - `quorum` must be non-zero and less than or equal to the number of `signers`. -Emits a `SignerAdded` event for each signer added. -Emits a `QuorumUpdated` event. +Emits a {MultisigComponent-SignerAdded} event for each signer added. +Emits a {MultisigComponent-QuorumUpdated} event. [.contract-item] [[MultisigComponent-resolve_tx_state]] @@ -2642,8 +2647,8 @@ Requirements: - Each signer address must be non-zero. - `new_quorum` must be non-zero and less than or equal to the total number of signers after addition. -Emits a `SignerAdded` event for each new signer added. -Emits a `QuorumUpdated` event if the quorum changes. +Emits a {MultisigComponent-SignerAdded} event for each new signer added. +Emits a {MultisigComponent-QuorumUpdated} event if the quorum changes. [.contract-item] [[MultisigComponent-_remove_signers]] @@ -2656,8 +2661,8 @@ Requirements: - `new_quorum` must be non-zero and less than or equal to the total number of signers after removal. -Emits a `SignerRemoved` event for each signer removed. -Emits a `QuorumUpdated` event if the quorum changes. +Emits a {MultisigComponent-SignerRemoved} event for each signer removed. +Emits a {MultisigComponent-QuorumUpdated} event if the quorum changes. [.contract-item] [[MultisigComponent-_replace_signer]] @@ -2671,8 +2676,8 @@ Requirements: - `signer_to_add` must not be an existing signer. - `signer_to_add` must be a non-zero address. -Emits a `SignerRemoved` event for the removed signer. -Emits a `SignerAdded` event for the new signer. +Emits a {MultisigComponent-SignerRemoved} event for the removed signer. +Emits a {MultisigComponent-SignerAdded} event for the new signer. [.contract-item] [[MultisigComponent-_change_quorum]] @@ -2685,7 +2690,58 @@ Requirements: - `new_quorum` must be non-zero. - `new_quorum` must be less than or equal to the total number of signers. -Emits a `QuorumUpdated` event if the quorum changes. +Emits a {MultisigComponent-QuorumUpdated} event if the quorum changes. + +[#MultisigComponent-Events] +==== Events + +[.contract-item] +[[MultisigComponent-SignerAdded]] +==== `[.contract-item-name]#++SignerAdded++#++(signer: ContractAddress)++` [.item-kind]#event# + +Emitted when a new `signer` is added. + +[.contract-item] +[[MultisigComponent-SignerRemoved]] +==== `[.contract-item-name]#++SignerRemoved++#++(signer: ContractAddress)++` [.item-kind]#event# + +Emitted when a `signer` is removed. + +[.contract-item] +[[MultisigComponent-QuorumUpdated]] +==== `[.contract-item-name]#++QuorumUpdated++#++(old_quorum: u32, new_quorum: u32)++` [.item-kind]#event# + +Emitted when the `quorum` value is updated. + +[.contract-item] +[[MultisigComponent-TransactionSubmitted]] +==== `[.contract-item-name]#++TransactionSubmitted++#++(id: TransactionID, signer: ContractAddress)++` [.item-kind]#event# + +Emitted when a new transaction is submitted by a `signer`. + +[.contract-item] +[[MultisigComponent-TransactionConfirmed]] +==== `[.contract-item-name]#++TransactionConfirmed++#++(id: TransactionID, signer: ContractAddress)++` [.item-kind]#event# + +Emitted when a transaction is confirmed by a `signer`. + +[.contract-item] +[[MultisigComponent-ConfirmationRevoked]] +==== `[.contract-item-name]#++ConfirmationRevoked++#++(id: TransactionID, signer: ContractAddress)++` [.item-kind]#event# + +Emitted when a `signer` revokes his confirmation. + +[.contract-item] +[[MultisigComponent-TransactionExecuted]] +==== `[.contract-item-name]#++TransactionExecuted++#++(id: TransactionID)++` [.item-kind]#event# + +Emitted when a transaction is executed. + +[.contract-item] +[[MultisigComponent-CallSalt]] +==== `[.contract-item-name]#++CallSalt++#++(id: felt252, salt: felt252)++` [.item-kind]#event# + +Emitted when a new transaction is submitted with non-zero salt. == Timelock @@ -2695,6 +2751,12 @@ In a governance system, `TimelockControllerComponent` is in charge of introducin [[ITimelock]] === `++ITimelock++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.20.0/packages/governance/src/timelock/interface.cairo[{github-icon},role=heading-link] +:ITimelock-CallScheduled: xref:ITimelock-CallScheduled[CallScheduled] +:ITimelock-CallExecuted: xref:ITimelock-CallExecuted[CallExecuted] +:ITimelock-CallSalt: xref:ITimelock-CallSalt[CallSalt] +:ITimelock-CallCancelled: xref:ITimelock-CallCancelled[CallCancelled] +:ITimelock-MinDelayChanged: xref:ITimelock-MinDelayChanged[MinDelayChanged] + [.hljs-theme-dark] ```cairo use openzeppelin_governance::timelock::interface::ITimelock; @@ -2921,6 +2983,12 @@ Emitted when the minimum delay for future operations is modified. [[TimelockControllerComponent]] === `++TimelockControllerComponent++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.20.0/packages/governance/src/timelock/timelock_controller.cairo[{github-icon},role=heading-link] +:TimelockComponent-CallScheduled: xref:TimelockControllerComponent-CallScheduled[CallScheduled] +:TimelockComponent-CallExecuted: xref:TimelockControllerComponent-CallExecuted[CallExecuted] +:TimelockComponent-CallSalt: xref:TimelockControllerComponent-CallSalt[CallSalt] +:TimelockComponent-CallCancelled: xref:TimelockControllerComponent-CallCancelled[CallCancelled] +:TimelockComponent-MinDelayChanged: xref:TimelockControllerComponent-MinDelayChanged[MinDelayChanged] + include::../utils/_common.adoc[] [.hljs-theme-dark] @@ -3082,8 +3150,8 @@ Requirements: - The proposal must not already exist. - `delay` must be greater than or equal to the min delay. -Emits {CallScheduled} event. -Emits {ITimelock-CallSalt} event if `salt` is not zero. +Emits {TimelockComponent-CallScheduled} event. +Emits {TimelockComponent-CallSalt} event if `salt` is not zero. [.contract-item] [[TimelockControllerComponent-schedule_batch]] @@ -3097,8 +3165,8 @@ Requirements: - The proposal must not already exist. - `delay` must be greater than or equal to the min delay. -Emits one {CallScheduled} event for each transaction in the batch. -Emits {ITimelock-CallSalt} event if `salt` is not zero. +Emits one {TimelockComponent-CallScheduled} event for each transaction in the batch. +Emits {TimelockComponent-CallSalt} event if `salt` is not zero. [.contract-item] [[TimelockControllerComponent-cancel]] @@ -3111,7 +3179,7 @@ Requirements: - The caller must have the `CANCELLER_ROLE` role. - `id` must be an operation. -Emits a {CallCancelled} event. +Emits a {TimelockComponent-CallCancelled} event. [.contract-item] [[TimelockControllerComponent-execute]] @@ -3125,7 +3193,7 @@ Requirements: - `id` must be in Ready OperationState. - `predecessor` must either be `0` or in Done OperationState. -Emits a {CallExecuted} event. +Emits a {TimelockComponent-CallExecuted} event. NOTE: This function can reenter, but it doesn't pose a risk because <> checks that the proposal is pending, thus any modifications to the operation during @@ -3143,7 +3211,7 @@ Requirements: - `id` must be in Ready OperationState. - `predecessor` must either be `0` or in Done OperationState. -Emits a {CallExecuted} event for each Call. +Emits a {TimelockComponent-CallExecuted} event for each Call. NOTE: This function can reenter, but it doesn't pose a risk because `_after_call` checks that the proposal is pending, thus any modifications to the operation during @@ -3161,7 +3229,7 @@ Requirements: and later executing an operation where the timelock is the target and the data is the serialized call to this function. -Emits a {MinDelayChanged} event. +Emits a {TimelockComponent-MinDelayChanged} event. [#TimelockControllerComponent-Internal-Functions] ==== Internal functions @@ -3191,7 +3259,7 @@ Emits a {IAccessControl-RoleGranted} event for each account in `executors` with May emit a {IAccessControl-RoleGranted} event for `admin` with `DEFAULT_ADMIN_ROLE` role (if `admin` is not zero). -Emits {MinDelayChanged} event. +Emits {TimelockComponent-MinDelayChanged} event. [.contract-item] [[TimelockControllerComponent-assert_only_role]] From 31d4188bf0b602465c0fb4861ef72c2228a3cb89 Mon Sep 17 00:00:00 2001 From: immrsd Date: Fri, 13 Dec 2024 09:02:23 +0100 Subject: [PATCH 12/28] Fix functions order in doc --- docs/modules/ROOT/pages/api/governance.adoc | 74 ++++++++++----------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/docs/modules/ROOT/pages/api/governance.adoc b/docs/modules/ROOT/pages/api/governance.adoc index ad1fe318d..74212f18a 100644 --- a/docs/modules/ROOT/pages/api/governance.adoc +++ b/docs/modules/ROOT/pages/api/governance.adoc @@ -2079,6 +2079,12 @@ Returns whether the transaction with the given `id` has been confirmed by the sp Returns whether the transaction with the given `id` has been executed. +[.contract-item] +[[IMultisig-get_submitted_block]] +==== `[.contract-item-name]#++get_submitted_block++#++(id: TransactionID) → u64++` [.item-kind]#external# + +Returns the block number when the transaction with the given `id` was submitted. + [.contract-item] [[IMultisig-get_transaction_state]] ==== `[.contract-item-name]#++get_transaction_state++#++(id: TransactionID) → TransactionState++` [.item-kind]#external# @@ -2092,10 +2098,16 @@ Returns the current state of the transaction with the given `id`. Returns the number of confirmations from registered signers for the transaction with the specified `id`. [.contract-item] -[[IMultisig-get_submitted_block]] -==== `[.contract-item-name]#++get_submitted_block++#++(id: TransactionID) → u64++` [.item-kind]#external# +[[IMultisig-hash_transaction]] +==== `[.contract-item-name]#++hash_transaction++#++(to: ContractAddress, selector: felt252, calldata: Span, salt: felt252) → TransactionID++` [.item-kind]#external# -Returns the block number when the transaction with the given `id` was submitted. +Returns the computed identifier of a transaction containing a single call. + +[.contract-item] +[[IMultisig-hash_transaction_batch]] +==== `[.contract-item-name]#++hash_transaction_batch++#++(calls: Span, salt: felt252) → TransactionID++` [.item-kind]#external# + +Returns the computed identifier of a transaction containing a batch of calls. [.contract-item] [[IMultisig-add_signers]] @@ -2235,18 +2247,6 @@ Requirements: Emits a {IMultisig-TransactionExecuted} event. -[.contract-item] -[[IMultisig-hash_transaction]] -==== `[.contract-item-name]#++hash_transaction++#++(to: ContractAddress, selector: felt252, calldata: Span, salt: felt252) → TransactionID++` [.item-kind]#external# - -Returns the computed identifier of a transaction containing a single call. - -[.contract-item] -[[IMultisig-hash_transaction_batch]] -==== `[.contract-item-name]#++hash_transaction_batch++#++(calls: Span, salt: felt252) → TransactionID++` [.item-kind]#external# - -Returns the computed identifier of a transaction containing a batch of calls. - [#IMultisig-Events] ==== Events @@ -2324,9 +2324,11 @@ Component that implements `IMultisig` and provides functionality for multisignat * xref:#MultisigComponent-is_confirmed[`++is_confirmed(self, id)++`] * xref:#MultisigComponent-is_confirmed_by[`++is_confirmed_by(self, id, signer)++`] * xref:#MultisigComponent-is_executed[`++is_executed(self, id)++`] +* xref:#MultisigComponent-get_submitted_block[`++get_submitted_block(self, id)++`] * xref:#MultisigComponent-get_transaction_state[`++get_transaction_state(self, id)++`] * xref:#MultisigComponent-get_transaction_confirmations[`++get_transaction_confirmations(self, id)++`] -* xref:#MultisigComponent-get_submitted_block[`++get_submitted_block(self, id)++`] +* xref:#MultisigComponent-hash_transaction[`++hash_transaction(self, to, selector, calldata, salt)++`] +* xref:#MultisigComponent-hash_transaction_batch[`++hash_transaction_batch(self, calls, salt)++`] * xref:#MultisigComponent-add_signers[`++add_signers(ref self, new_quorum, signers_to_add)++`] * xref:#MultisigComponent-remove_signers[`++remove_signers(ref self, new_quorum, signers_to_remove)++`] * xref:#MultisigComponent-replace_signer[`++replace_signer(ref self, signer_to_remove, signer_to_add)++`] @@ -2337,8 +2339,6 @@ Component that implements `IMultisig` and provides functionality for multisignat * xref:#MultisigComponent-revoke_confirmation[`++revoke_confirmation(ref self, id)++`] * xref:#MultisigComponent-execute_transaction[`++execute_transaction(ref self, to, selector, calldata, salt)++`] * xref:#MultisigComponent-execute_transaction_batch[`++execute_transaction_batch(ref self, calls, salt)++`] -* xref:#MultisigComponent-hash_transaction[`++hash_transaction(self, to, selector, calldata, salt)++`] -* xref:#MultisigComponent-hash_transaction_batch[`++hash_transaction_batch(self, calls, salt)++`] -- [.contract-index#MultisigComponent-Internal-Impls] @@ -2401,31 +2401,43 @@ Returns whether the transaction with the given `id` has been confirmed. A confir [[MultisigComponent-is_confirmed_by]] ==== `[.contract-item-name]#++is_confirmed_by++#++(self: @ContractState, id: TransactionID, signer: ContractAddress) → bool++` [.item-kind]#external# -Checks if the transaction with `id` has been confirmed by the specified `signer`. +Returns whether the transaction with the given `id` has been confirmed by the specified `signer`. [.contract-item] [[MultisigComponent-is_executed]] ==== `[.contract-item-name]#++is_executed++#++(self: @ContractState, id: TransactionID) → bool++` [.item-kind]#external# -Checks if the transaction with `id` has been executed. +Returns whether the transaction with the given `id` has been executed. + +[.contract-item] +[[MultisigComponent-get_submitted_block]] +==== `[.contract-item-name]#++get_submitted_block++#++(self: @ContractState, id: TransactionID) → u64++` [.item-kind]#external# + +Returns the block number when the transaction with the given `id` was submitted. [.contract-item] [[MultisigComponent-get_transaction_state]] ==== `[.contract-item-name]#++get_transaction_state++#++(self: @ContractState, id: TransactionID) → TransactionState++` [.item-kind]#external# -Returns the current state of the transaction with `id`. +Returns the current state of the transaction with the given `id`. [.contract-item] [[MultisigComponent-get_transaction_confirmations]] ==== `[.contract-item-name]#++get_transaction_confirmations++#++(self: @ContractState, id: TransactionID) → u32++` [.item-kind]#external# -Returns the number of confirmations from registered signers for the transaction with `id`. +Returns the number of confirmations from registered signers for the transaction with the specified `id`. [.contract-item] -[[MultisigComponent-get_submitted_block]] -==== `[.contract-item-name]#++get_submitted_block++#++(self: @ContractState, id: TransactionID) → u64++` [.item-kind]#external# +[[MultisigComponent-hash_transaction]] +==== `[.contract-item-name]#++hash_transaction++#++(self: @ContractState, to: ContractAddress, selector: felt252, calldata: Span, salt: felt252)++` [.item-kind]#external# + +Returns the computed identifier of a transaction containing a single call. -Returns the block number when the transaction with `id` was submitted. +[.contract-item] +[[MultisigComponent-hash_transaction_batch]] +==== `[.contract-item-name]#++hash_transaction_batch++#++(self: @ContractState, calls: Span, salt: felt252)++` [.item-kind]#external# + +Returns the computed identifier of a transaction containing a batch of calls. [.contract-item] [[MultisigComponent-add_signers]] @@ -2565,18 +2577,6 @@ Requirements: Emits a {MultisigComponent-TransactionExecuted} event. -[.contract-item] -[[MultisigComponent-hash_transaction]] -==== `[.contract-item-name]#++hash_transaction++#++(self: @ContractState, to: ContractAddress, selector: felt252, calldata: Span, salt: felt252)++` [.item-kind]#external# - -Returns the computed identifier of a transaction containing a single call. - -[.contract-item] -[[MultisigComponent-hash_transaction_batch]] -==== `[.contract-item-name]#++hash_transaction_batch++#++(self: @ContractState, calls: Span, salt: felt252)++` [.item-kind]#external# - -Returns the computed identifier of a transaction containing a batch of calls. - [#MultisigComponent-Internal-Functions] ==== Internal functions From 992bb784acb23c07996d19df93374f0345916a40 Mon Sep 17 00:00:00 2001 From: immrsd Date: Fri, 13 Dec 2024 09:09:09 +0100 Subject: [PATCH 13/28] Fix capitalisation --- docs/modules/ROOT/pages/api/governance.adoc | 10 +++---- .../ROOT/pages/governance/multisig.adoc | 26 +++++++++---------- docs/modules/ROOT/pages/governance/votes.adoc | 2 +- .../governance/src/multisig/multisig.cairo | 18 ++++++------- 4 files changed, 28 insertions(+), 28 deletions(-) diff --git a/docs/modules/ROOT/pages/api/governance.adoc b/docs/modules/ROOT/pages/api/governance.adoc index 74212f18a..9023ab27b 100644 --- a/docs/modules/ROOT/pages/api/governance.adoc +++ b/docs/modules/ROOT/pages/api/governance.adoc @@ -2601,10 +2601,10 @@ Emits a {MultisigComponent-QuorumUpdated} event. Resolves and returns the current state of the transaction with the given `id`. The possible states are: -- `NotFound`: The transaction does not exist. -- `Pending`: The transaction exists but hasn't reached the required confirmations. -- `Confirmed`: The transaction has reached the required confirmations but hasn't been executed. -- `Executed`: The transaction has been executed. +- `NotFound`: the transaction does not exist. +- `Pending`: the transaction exists but hasn't reached the required confirmations. +- `Confirmed`: the transaction has reached the required confirmations but hasn't been executed. +- `Executed`: the transaction has been executed. [.contract-item] [[MultisigComponent-assert_one_of_signers]] @@ -2624,7 +2624,7 @@ Asserts that a transaction with the given `id` exists. Requirements: -- The transaction with `id` must have been submitted. +- The transaction with the given `id` must have been submitted. [.contract-item] [[MultisigComponent-assert_only_self]] diff --git a/docs/modules/ROOT/pages/governance/multisig.adoc b/docs/modules/ROOT/pages/governance/multisig.adoc index f029ae659..444d45b31 100644 --- a/docs/modules/ROOT/pages/governance/multisig.adoc +++ b/docs/modules/ROOT/pages/governance/multisig.adoc @@ -12,30 +12,30 @@ This component is designed to secure operations such as fund management or proto where collective decision-making is essential. The Multisig Component is self-administered, meaning that changes to signers or quorum must be approved through the multisig process itself. -== Key Features +== Key features -- *Multi-Signature Security*: Transactions must be approved by multiple signers, ensuring +- *Multi-Signature Security*: transactions must be approved by multiple signers, ensuring distributed governance. -- *Quorum Enforcement*: Defines the minimum number of approvals required for transaction execution. +- *Quorum Enforcement*: defines the minimum number of approvals required for transaction execution. -- *Self-Administration*: All modifications to the component (e.g., adding or removing signers) +- *Self-Administration*: all modifications to the component (e.g., adding or removing signers) must pass through the multisig process. -- *Event Logging*: Provides comprehensive event logging for transparency and auditability. +- *Event Logging*: provides comprehensive event logging for transparency and auditability. -== Signer Management +== Signer management The Multisig component introduces the concept of signers and quorum: -- *Signers*: Only registered signers can submit, confirm, revoke, or execute transactions. The Multisig +- *Signers*: only registered signers can submit, confirm, revoke, or execute transactions. The Multisig Component supports adding, removing, or replacing signers. -- *Quorum*: The quorum defines the minimum number of confirmations required to approve a transaction. +- *Quorum*: the quorum defines the minimum number of confirmations required to approve a transaction. NOTE: To prevent unauthorized modifications, only the contract itself can add, remove, or replace signers or change the quorum. This ensures that all modifications pass through the multisig approval process. -== Transaction Lifecycle +== Transaction lifecycle A transaction in the Multisig component follows a specific lifecycle: @@ -44,10 +44,10 @@ A transaction in the Multisig component follows a specific lifecycle: The state of a transaction is represented by the `TransactionState` enum and can be checked by calling the `get_transaction_state` function. -- *NotFound*: The transaction does not exist. -- *Pending*: The transaction exists but has not reached the required confirmations. -- *Confirmed*: The transaction has reached the quorum but has not yet been executed. -- *Executed*: The transaction has been successfully executed. +- *NotFound*: the transaction does not exist. +- *Pending*: the transaction exists but has not reached the required confirmations. +- *Confirmed*: the transaction has reached the quorum but has not yet been executed. +- *Executed*: the transaction has been successfully executed. == Usage diff --git a/docs/modules/ROOT/pages/governance/votes.adoc b/docs/modules/ROOT/pages/governance/votes.adoc index 00aa3e943..d47ec99ea 100644 --- a/docs/modules/ROOT/pages/governance/votes.adoc +++ b/docs/modules/ROOT/pages/governance/votes.adoc @@ -15,7 +15,7 @@ NOTE: By default, token balance does not account for voting power. This makes tr IMPORTANT: The transferring of voting units must be handled by the implementing contract. In the case of `ERC20` and `ERC721` this is usually done via the hooks. You can check the {votes-usage} section for examples of how to implement this. -== Key Features +== Key features 1. *Delegation*: Users can delegate their voting power to any address, including themselves. Vote power can be delegated either by calling the {delegate} function directly, or by providing a signature to be used with {delegate_by_sig}. 2. *Historical lookups*: The system keeps track of historical snapshots for each account, which allows the voting power of an account to be queried at a specific timestamp. + diff --git a/packages/governance/src/multisig/multisig.cairo b/packages/governance/src/multisig/multisig.cairo index 5e9a76c1b..fed772a7d 100644 --- a/packages/governance/src/multisig/multisig.cairo +++ b/packages/governance/src/multisig/multisig.cairo @@ -193,11 +193,11 @@ pub mod MultisigComponent { /// Returns the current state of the transaction with the given `id`. /// /// The possible states are: - /// - `NotFound`: The transaction does not exist. - /// - `Pending`: The transaction exists but hasn't reached the required confirmations. - /// - `Confirmed`: The transaction has reached the required confirmations but hasn't been + /// - `NotFound`: the transaction does not exist. + /// - `Pending`: the transaction exists but hasn't reached the required confirmations. + /// - `Confirmed`: the transaction has reached the required confirmations but hasn't been /// executed. - /// - `Executed`: The transaction has been executed. + /// - `Executed`: the transaction has been executed. fn get_transaction_state( self: @ComponentState, id: TransactionID, ) -> TransactionState { @@ -477,11 +477,11 @@ pub mod MultisigComponent { /// Resolves and returns the current state of the transaction with the given `id`. /// /// The possible states are: - /// - `NotFound`: The transaction does not exist. - /// - `Pending`: The transaction exists but hasn't reached the required confirmations. - /// - `Confirmed`: The transaction has reached the required confirmations but hasn't been + /// - `NotFound`: the transaction does not exist. + /// - `Pending`: the transaction exists but hasn't reached the required confirmations. + /// - `Confirmed`: the transaction has reached the required confirmations but hasn't been /// executed. - /// - `Executed`: The transaction has been executed. + /// - `Executed`: the transaction has been executed. fn resolve_tx_state( self: @ComponentState, id: TransactionID, ) -> TransactionState { @@ -513,7 +513,7 @@ pub mod MultisigComponent { /// /// Requirements: /// - /// - The transaction with `id` must have been submitted. + /// - The transaction with the given `id` must have been submitted. fn assert_tx_exists(self: @ComponentState, id: TransactionID) { assert(self.get_submitted_block(id).is_non_zero(), Errors::TX_NOT_FOUND); } From 95cb2d0c2391020744fd778e07ed971207d5deed Mon Sep 17 00:00:00 2001 From: immrsd Date: Fri, 13 Dec 2024 09:12:45 +0100 Subject: [PATCH 14/28] Add import section --- docs/modules/ROOT/pages/api/governance.adoc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/api/governance.adoc b/docs/modules/ROOT/pages/api/governance.adoc index 9023ab27b..75d694ae5 100644 --- a/docs/modules/ROOT/pages/api/governance.adoc +++ b/docs/modules/ROOT/pages/api/governance.adoc @@ -2311,7 +2311,13 @@ Emitted when a new transaction is submitted with non-zero salt. :MultisigComponent-ConfirmationRevoked: xref:MultisigComponent-CallSalt[ConfirmationRevoked] :MultisigComponent-TransactionExecuted: xref:MultisigComponent-CallSalt[TransactionExecuted] -Component that implements `IMultisig` and provides functionality for multisignature wallets, including transaction management, quorum handling, and signer operations. +[.hljs-theme-dark] +```cairo +use openzeppelin_governance::multisig::MultisigComponent; +``` + +Component that implements `IMultisig` and provides functionality for multisignature wallets, +including transaction management, quorum handling, and signer operations. [.contract-index#MultisigComponent-Embeddable-Impls] .Embeddable Implementations From 634343bf9870ec5c6bb1ec1ce148f24e293f84c8 Mon Sep 17 00:00:00 2001 From: immrsd Date: Fri, 13 Dec 2024 09:17:39 +0100 Subject: [PATCH 15/28] Add description for Multisig module --- docs/modules/ROOT/pages/api/governance.adoc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/api/governance.adoc b/docs/modules/ROOT/pages/api/governance.adoc index 75d694ae5..71f3a35bd 100644 --- a/docs/modules/ROOT/pages/api/governance.adoc +++ b/docs/modules/ROOT/pages/api/governance.adoc @@ -1979,7 +1979,10 @@ Emitted when the timelock controller is updated. == Multisig -TODO: Add description +A Multisig module enhances security and decentralization by requiring multiple signers to +approve and execute transactions. Features include configurable quorum, signer management, +and self-administration, ensuring collective decision-making and transparency for critical +operations. [.contract] [[IMultisig]] From 1e4c8714fa08aae9aee31c834b21c11d49a88611 Mon Sep 17 00:00:00 2001 From: immrsd Date: Sun, 15 Dec 2024 11:17:05 +0100 Subject: [PATCH 16/28] Add newlines where necessary --- docs/modules/ROOT/pages/api/governance.adoc | 1 + packages/governance/src/multisig/multisig.cairo | 2 ++ 2 files changed, 3 insertions(+) diff --git a/docs/modules/ROOT/pages/api/governance.adoc b/docs/modules/ROOT/pages/api/governance.adoc index 71f3a35bd..fa1a6ad92 100644 --- a/docs/modules/ROOT/pages/api/governance.adoc +++ b/docs/modules/ROOT/pages/api/governance.adoc @@ -2610,6 +2610,7 @@ Emits a {MultisigComponent-QuorumUpdated} event. Resolves and returns the current state of the transaction with the given `id`. The possible states are: + - `NotFound`: the transaction does not exist. - `Pending`: the transaction exists but hasn't reached the required confirmations. - `Confirmed`: the transaction has reached the required confirmations but hasn't been executed. diff --git a/packages/governance/src/multisig/multisig.cairo b/packages/governance/src/multisig/multisig.cairo index fed772a7d..088aa831a 100644 --- a/packages/governance/src/multisig/multisig.cairo +++ b/packages/governance/src/multisig/multisig.cairo @@ -193,6 +193,7 @@ pub mod MultisigComponent { /// Returns the current state of the transaction with the given `id`. /// /// The possible states are: + /// /// - `NotFound`: the transaction does not exist. /// - `Pending`: the transaction exists but hasn't reached the required confirmations. /// - `Confirmed`: the transaction has reached the required confirmations but hasn't been @@ -477,6 +478,7 @@ pub mod MultisigComponent { /// Resolves and returns the current state of the transaction with the given `id`. /// /// The possible states are: + /// /// - `NotFound`: the transaction does not exist. /// - `Pending`: the transaction exists but hasn't reached the required confirmations. /// - `Confirmed`: the transaction has reached the required confirmations but hasn't been From 0b6cd5b913c713bd0b90537d11c79061ce058848 Mon Sep 17 00:00:00 2001 From: immrsd Date: Sun, 15 Dec 2024 12:32:55 +0100 Subject: [PATCH 17/28] Improve multisig doc indices --- docs/modules/ROOT/pages/api/governance.adoc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/modules/ROOT/pages/api/governance.adoc b/docs/modules/ROOT/pages/api/governance.adoc index fa1a6ad92..025101696 100644 --- a/docs/modules/ROOT/pages/api/governance.adoc +++ b/docs/modules/ROOT/pages/api/governance.adoc @@ -2322,7 +2322,7 @@ use openzeppelin_governance::multisig::MultisigComponent; Component that implements `IMultisig` and provides functionality for multisignature wallets, including transaction management, quorum handling, and signer operations. -[.contract-index#MultisigComponent-Embeddable-Impls] +[.contract-index] .Embeddable Implementations -- .MultisigImpl @@ -2350,7 +2350,7 @@ including transaction management, quorum handling, and signer operations. * xref:#MultisigComponent-execute_transaction_batch[`++execute_transaction_batch(ref self, calls, salt)++`] -- -[.contract-index#MultisigComponent-Internal-Impls] +[.contract-index] .Internal Implementations -- .InternalImpl @@ -2366,7 +2366,7 @@ including transaction management, quorum handling, and signer operations. * xref:#MultisigComponent-_change_quorum[`++_change_quorum(ref self, new_quorum)++`] -- -[.contract-index#MultisigComponent-Events] +[.contract-index] .Events -- * xref:#MultisigComponent-SignerAdded[`++SignerAdded(signer)++`] From 7e24ff6e32a8b96973307cb47548eec605da3500 Mon Sep 17 00:00:00 2001 From: immrsd Date: Sun, 15 Dec 2024 12:33:29 +0100 Subject: [PATCH 18/28] Add detailed explanation of ID computation of a multisig tx --- docs/modules/ROOT/pages/governance/multisig.adoc | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/docs/modules/ROOT/pages/governance/multisig.adoc b/docs/modules/ROOT/pages/governance/multisig.adoc index 444d45b31..d1979c635 100644 --- a/docs/modules/ROOT/pages/governance/multisig.adoc +++ b/docs/modules/ROOT/pages/governance/multisig.adoc @@ -37,13 +37,20 @@ This ensures that all modifications pass through the multisig approval process. == Transaction lifecycle +The state of a transaction is represented by the `TransactionState` enum and can be retrieved +by calling the `get_transaction_state` function with the transaction's identifier. + +The identifier of a multisig transaction is a `felt252` value, computed as the Pedersen hash +of the transaction's calls and salt. It can be computed by invoking the implementing contract's +`hash_transaction` method for single-call transactions or `hash_transaction_batch` for multi-call +transactions. Submitting a transaction with identical calls and the same salt value a second time +will fail, as transaction identifiers must be unique. To resolve this, use a different salt value +to generate a unique identifier. + A transaction in the Multisig component follows a specific lifecycle: `NotFound` → `Pending` → `Confirmed` → `Executed` -The state of a transaction is represented by the `TransactionState` enum and can be checked -by calling the `get_transaction_state` function. - - *NotFound*: the transaction does not exist. - *Pending*: the transaction exists but has not reached the required confirmations. - *Confirmed*: the transaction has reached the quorum but has not yet been executed. From 9ead17dccaef5d4e6c7335b2c271905669f3d822 Mon Sep 17 00:00:00 2001 From: immrsd Date: Sun, 15 Dec 2024 12:33:39 +0100 Subject: [PATCH 19/28] Add detailed explanation of ID computation of a timelock operation --- docs/modules/ROOT/pages/governance/timelock.adoc | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/governance/timelock.adoc b/docs/modules/ROOT/pages/governance/timelock.adoc index 7fb13fef6..c8c9913a2 100644 --- a/docs/modules/ROOT/pages/governance/timelock.adoc +++ b/docs/modules/ROOT/pages/governance/timelock.adoc @@ -11,7 +11,17 @@ NOTE: The Timelock contract itself executes transactions, not the user. The Time == Operation lifecycle -Timelocked operations are identified by a unique id (their hash) and follow a specific `OperationState` lifecycle: +The state of an operation is represented by the `OperationState` enum and can be retrieved +by calling the `get_operation_state` function with the operation's identifier. + +The identifier of an operation is a `felt252` value, computed as the Pedersen hash of the +operation's call or calls, its predecessor, and salt. It can be computed by invoking the +implementing contract's `hash_operation` function for single-call operations or +`hash_operation_batch` for multi-call operations. Submitting an operation with identical calls, +predecessor, and the same salt value a second time will fail, as operation identifiers must be +unique. To resolve this, use a different salt value to generate a unique identifier. + +Timelocked operations follow a specific lifecycle: `Unset` → `Waiting` → `Ready` → `Done` From b8e4d8aede753b5f2a5fb4fef224c1e5297f31e8 Mon Sep 17 00:00:00 2001 From: immrsd Date: Sun, 15 Dec 2024 12:34:24 +0100 Subject: [PATCH 20/28] Fix order of Multisig functions --- .../governance/src/multisig/multisig.cairo | 44 +++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/packages/governance/src/multisig/multisig.cairo b/packages/governance/src/multisig/multisig.cairo index 088aa831a..e65c8f3ce 100644 --- a/packages/governance/src/multisig/multisig.cairo +++ b/packages/governance/src/multisig/multisig.cairo @@ -190,6 +190,11 @@ pub mod MultisigComponent { self.Multisig_tx_info.read(id).is_executed } + /// Returns the block number when the transaction with the given `id` was submitted. + fn get_submitted_block(self: @ComponentState, id: TransactionID) -> u64 { + self.Multisig_tx_info.read(id).submitted_block + } + /// Returns the current state of the transaction with the given `id`. /// /// The possible states are: @@ -220,9 +225,23 @@ pub mod MultisigComponent { result } - /// Returns the block number when the transaction with the given `id` was submitted. - fn get_submitted_block(self: @ComponentState, id: TransactionID) -> u64 { - self.Multisig_tx_info.read(id).submitted_block + /// Returns the computed identifier of a transaction containing a single call. + fn hash_transaction( + self: @ComponentState, + to: ContractAddress, + selector: felt252, + calldata: Span, + salt: felt252, + ) -> TransactionID { + let call = Call { to, selector, calldata }; + self.hash_transaction_batch(array![call].span(), salt) + } + + /// Returns the computed identifier of a transaction containing a batch of calls. + fn hash_transaction_batch( + self: @ComponentState, calls: Span, salt: felt252, + ) -> TransactionID { + PedersenTrait::new(0).update_with(calls).update_with(salt).finalize() } /// Adds new signers and updates the quorum. @@ -431,25 +450,6 @@ pub mod MultisigComponent { }, }; } - - /// Returns the computed identifier of a transaction containing a single call. - fn hash_transaction( - self: @ComponentState, - to: ContractAddress, - selector: felt252, - calldata: Span, - salt: felt252, - ) -> TransactionID { - let call = Call { to, selector, calldata }; - self.hash_transaction_batch(array![call].span(), salt) - } - - /// Returns the computed identifier of a transaction containing a batch of calls. - fn hash_transaction_batch( - self: @ComponentState, calls: Span, salt: felt252, - ) -> TransactionID { - PedersenTrait::new(0).update_with(calls).update_with(salt).finalize() - } } // From 9e0f29bb06bf3e3dedd1705c1a3c7b59db28eb36 Mon Sep 17 00:00:00 2001 From: immrsd Date: Sun, 15 Dec 2024 18:31:00 +0100 Subject: [PATCH 21/28] Add descriptions for possible states of a Timelock operation --- docs/modules/ROOT/pages/api/governance.adoc | 18 ++++++++++++++++-- .../ROOT/pages/governance/timelock.adoc | 5 +++++ .../src/timelock/timelock_controller.cairo | 7 +++++++ 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/docs/modules/ROOT/pages/api/governance.adoc b/docs/modules/ROOT/pages/api/governance.adoc index 025101696..f3250fb4a 100644 --- a/docs/modules/ROOT/pages/api/governance.adoc +++ b/docs/modules/ROOT/pages/api/governance.adoc @@ -2846,7 +2846,14 @@ is `Done`. [[ITimelock-get_operation_state]] ==== `[.contract-item-name]#++get_operation_state++#++(id: felt252) → OperationState++` [.item-kind]#external# -Returns the OperationState for `id`. +Returns the current state of the operation with the given `id`. + +The possible states are: + +- `Unset`: the operation has not been scheduled or has been canceled. +- `Waiting`: the operation has been scheduled and is pending the minimum delay. +- `Ready`: the timer has expired, and the operation is eligible for execution. +- `Done`: the operation has been executed. [.contract-item] [[ITimelock-get_min_delay]] @@ -3127,7 +3134,14 @@ is `Done`. [[TimelockControllerComponent-get_operation_state]] ==== `[.contract-item-name]#++get_operation_state++#++(self: @ContractState, id: felt252) → OperationState++` [.item-kind]#external# -Returns the OperationState for `id`. +Returns the current state of the operation with the given `id`. + +The possible states are: + +- `Unset`: the operation has not been scheduled or has been canceled. +- `Waiting`: the operation has been scheduled and is pending the minimum delay. +- `Ready`: the timer has expired, and the operation is eligible for execution. +- `Done`: the operation has been executed. [.contract-item] [[TimelockControllerComponent-get_min_delay]] diff --git a/docs/modules/ROOT/pages/governance/timelock.adoc b/docs/modules/ROOT/pages/governance/timelock.adoc index c8c9913a2..511a93945 100644 --- a/docs/modules/ROOT/pages/governance/timelock.adoc +++ b/docs/modules/ROOT/pages/governance/timelock.adoc @@ -25,6 +25,11 @@ Timelocked operations follow a specific lifecycle: `Unset` → `Waiting` → `Ready` → `Done` +- `Unset`: the operation has not been scheduled or has been canceled. +- `Waiting`: the operation has been scheduled and is pending the minimum delay. +- `Ready`: the timer has expired, and the operation is eligible for execution. +- `Done`: the operation has been executed. + == Timelock flow === Schedule diff --git a/packages/governance/src/timelock/timelock_controller.cairo b/packages/governance/src/timelock/timelock_controller.cairo index a241e1852..4d817a827 100644 --- a/packages/governance/src/timelock/timelock_controller.cairo +++ b/packages/governance/src/timelock/timelock_controller.cairo @@ -153,6 +153,13 @@ pub mod TimelockControllerComponent { } /// Returns the OperationState for `id`. + /// + /// The possible states are: + /// + /// - `Unset`: The operation has not been scheduled or has been canceled. + /// - `Waiting`: the operation has been scheduled and is pending the minimum delay. + /// - `Ready`: the timer has expired, and the operation is eligible for execution. + /// - `Done`: the operation has been executed. fn get_operation_state( self: @ComponentState, id: felt252, ) -> OperationState { From 5aa6363202c3c9462a5e36e99c267d3d8b11f80f Mon Sep 17 00:00:00 2001 From: immrsd Date: Sun, 15 Dec 2024 18:31:54 +0100 Subject: [PATCH 22/28] Add multisig tx states description --- docs/modules/ROOT/pages/api/governance.adoc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/modules/ROOT/pages/api/governance.adoc b/docs/modules/ROOT/pages/api/governance.adoc index f3250fb4a..579887a93 100644 --- a/docs/modules/ROOT/pages/api/governance.adoc +++ b/docs/modules/ROOT/pages/api/governance.adoc @@ -2430,6 +2430,13 @@ Returns the block number when the transaction with the given `id` was submitted. Returns the current state of the transaction with the given `id`. +The possible states are: + +- `NotFound`: the transaction does not exist. +- `Pending`: the transaction exists but hasn't reached the required confirmations. +- `Confirmed`: the transaction has reached the required confirmations but hasn't been executed. +- `Executed`: the transaction has been executed. + [.contract-item] [[MultisigComponent-get_transaction_confirmations]] ==== `[.contract-item-name]#++get_transaction_confirmations++#++(self: @ContractState, id: TransactionID) → u32++` [.item-kind]#external# From c1715c71144a7aa33dfe7be09a9a4b4f1bb37e87 Mon Sep 17 00:00:00 2001 From: immrsd Date: Sun, 15 Dec 2024 18:32:14 +0100 Subject: [PATCH 23/28] Fix minor issues in governance doc --- docs/modules/ROOT/pages/governance/governor.adoc | 1 + docs/modules/ROOT/pages/governance/timelock.adoc | 1 - docs/modules/ROOT/pages/governance/votes.adoc | 2 -- packages/governance/src/timelock/timelock_controller.cairo | 2 +- 4 files changed, 2 insertions(+), 4 deletions(-) diff --git a/docs/modules/ROOT/pages/governance/governor.adoc b/docs/modules/ROOT/pages/governance/governor.adoc index 28bc08a37..4ebce6c22 100644 --- a/docs/modules/ROOT/pages/governance/governor.adoc +++ b/docs/modules/ROOT/pages/governance/governor.adoc @@ -1,4 +1,5 @@ = Governor + :votes-component: xref:api/governance.adoc#VotesComponent[VotesComponent] :governor-component: xref:api/governance.adoc#GovernorComponent[GovernorComponent] :access-control: xref:access.adoc#role_based_accesscontrol[AccessControl] diff --git a/docs/modules/ROOT/pages/governance/timelock.adoc b/docs/modules/ROOT/pages/governance/timelock.adoc index 511a93945..6746b9399 100644 --- a/docs/modules/ROOT/pages/governance/timelock.adoc +++ b/docs/modules/ROOT/pages/governance/timelock.adoc @@ -4,7 +4,6 @@ :accesscontrol-component: xref:api/access.adoc#AccessControlComponent[AccessControlComponent] :src5-component: xref:api/introspection.adoc#SRC5Component[SRC5Component] - The Timelock Controller provides a means of enforcing time delays on the execution of transactions. This is considered good practice regarding governance systems because it allows users the opportunity to exit the system if they disagree with a decision before it is executed. NOTE: The Timelock contract itself executes transactions, not the user. The Timelock should, therefore, hold associated funds, ownership, and access control roles. diff --git a/docs/modules/ROOT/pages/governance/votes.adoc b/docs/modules/ROOT/pages/governance/votes.adoc index d47ec99ea..67df15525 100644 --- a/docs/modules/ROOT/pages/governance/votes.adoc +++ b/docs/modules/ROOT/pages/governance/votes.adoc @@ -8,7 +8,6 @@ :nonces-component: xref:api/utilities.adoc#NoncesComponent[NoncesComponent] :snip12-metadata: xref:api/utilities.adoc#snip12[SNIP12Metadata] - The {votes-component} provides a flexible system for tracking and delegating voting power. This system allows users to delegate their voting power to other addresses, enabling more active participation in governance. NOTE: By default, token balance does not account for voting power. This makes transfers cheaper. The downside is that it requires users to delegate to themselves in order to activate checkpoints and have their voting power tracked. @@ -29,7 +28,6 @@ Additionally, you must implement the {nonces-component} and the {snip12-metadata Here's an example of how to structure a simple ERC20Votes contract: - [source,cairo] ---- #[starknet::contract] diff --git a/packages/governance/src/timelock/timelock_controller.cairo b/packages/governance/src/timelock/timelock_controller.cairo index 4d817a827..544939462 100644 --- a/packages/governance/src/timelock/timelock_controller.cairo +++ b/packages/governance/src/timelock/timelock_controller.cairo @@ -156,7 +156,7 @@ pub mod TimelockControllerComponent { /// /// The possible states are: /// - /// - `Unset`: The operation has not been scheduled or has been canceled. + /// - `Unset`: the operation has not been scheduled or has been canceled. /// - `Waiting`: the operation has been scheduled and is pending the minimum delay. /// - `Ready`: the timer has expired, and the operation is eligible for execution. /// - `Done`: the operation has been executed. From 3d22a75e901e6b7b1668faa5361b95dd9a2537d9 Mon Sep 17 00:00:00 2001 From: immrsd Date: Mon, 16 Dec 2024 07:27:32 +0100 Subject: [PATCH 24/28] Improve doc for Timelock cancel function --- docs/modules/ROOT/pages/api/governance.adoc | 8 ++++---- .../governance/src/timelock/timelock_controller.cairo | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/modules/ROOT/pages/api/governance.adoc b/docs/modules/ROOT/pages/api/governance.adoc index 579887a93..78b2a06d5 100644 --- a/docs/modules/ROOT/pages/api/governance.adoc +++ b/docs/modules/ROOT/pages/api/governance.adoc @@ -2911,12 +2911,12 @@ Emits {ITimelock-CallSalt} event if `salt` is not zero. [[ITimelock-cancel]] ==== `[.contract-item-name]#++cancel++#++(id: felt252)++` [.item-kind]#external# -Cancel an operation. +Cancels an operation. A canceled operation returns to `Unset` OperationState. Requirements: - The caller must have the `CANCELLER_ROLE` role. -- `id` must be an operation. +- `id` must be a pending operation. Emits a {ITimelock-CallCancelled} event. @@ -3203,12 +3203,12 @@ Emits {TimelockComponent-CallSalt} event if `salt` is not zero. [[TimelockControllerComponent-cancel]] ==== `[.contract-item-name]#++cancel++#++(ref self: ContractState, id: felt252)++` [.item-kind]#external# -Cancel an operation. +Cancels an operation. A canceled operation returns to `Unset` OperationState. Requirements: - The caller must have the `CANCELLER_ROLE` role. -- `id` must be an operation. +- `id` must be a pending operation. Emits a {TimelockComponent-CallCancelled} event. diff --git a/packages/governance/src/timelock/timelock_controller.cairo b/packages/governance/src/timelock/timelock_controller.cairo index 544939462..c90dce086 100644 --- a/packages/governance/src/timelock/timelock_controller.cairo +++ b/packages/governance/src/timelock/timelock_controller.cairo @@ -267,7 +267,7 @@ pub mod TimelockControllerComponent { } } - /// Cancels an operation. + /// Cancels an operation. A canceled operation returns to `Unset` OperationState. /// /// Requirements: /// From 7af622b9e65aafddb1b19f33508849290c565753 Mon Sep 17 00:00:00 2001 From: immrsd Date: Tue, 17 Dec 2024 15:04:58 +0100 Subject: [PATCH 25/28] Fix description of Waiting state of a Timelock tx --- docs/modules/ROOT/pages/api/governance.adoc | 4 ++-- docs/modules/ROOT/pages/governance/timelock.adoc | 2 +- packages/governance/src/timelock/timelock_controller.cairo | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/modules/ROOT/pages/api/governance.adoc b/docs/modules/ROOT/pages/api/governance.adoc index 78b2a06d5..93e55586b 100644 --- a/docs/modules/ROOT/pages/api/governance.adoc +++ b/docs/modules/ROOT/pages/api/governance.adoc @@ -2858,7 +2858,7 @@ Returns the current state of the operation with the given `id`. The possible states are: - `Unset`: the operation has not been scheduled or has been canceled. -- `Waiting`: the operation has been scheduled and is pending the minimum delay. +- `Waiting`: the operation has been scheduled and is pending the scheduled delay. - `Ready`: the timer has expired, and the operation is eligible for execution. - `Done`: the operation has been executed. @@ -3146,7 +3146,7 @@ Returns the current state of the operation with the given `id`. The possible states are: - `Unset`: the operation has not been scheduled or has been canceled. -- `Waiting`: the operation has been scheduled and is pending the minimum delay. +- `Waiting`: the operation has been scheduled and is pending the scheduled delay. - `Ready`: the timer has expired, and the operation is eligible for execution. - `Done`: the operation has been executed. diff --git a/docs/modules/ROOT/pages/governance/timelock.adoc b/docs/modules/ROOT/pages/governance/timelock.adoc index 6746b9399..6f016e5ba 100644 --- a/docs/modules/ROOT/pages/governance/timelock.adoc +++ b/docs/modules/ROOT/pages/governance/timelock.adoc @@ -25,7 +25,7 @@ Timelocked operations follow a specific lifecycle: `Unset` → `Waiting` → `Ready` → `Done` - `Unset`: the operation has not been scheduled or has been canceled. -- `Waiting`: the operation has been scheduled and is pending the minimum delay. +- `Waiting`: the operation has been scheduled and is pending the scheduled delay. - `Ready`: the timer has expired, and the operation is eligible for execution. - `Done`: the operation has been executed. diff --git a/packages/governance/src/timelock/timelock_controller.cairo b/packages/governance/src/timelock/timelock_controller.cairo index c90dce086..9e70887e7 100644 --- a/packages/governance/src/timelock/timelock_controller.cairo +++ b/packages/governance/src/timelock/timelock_controller.cairo @@ -157,7 +157,7 @@ pub mod TimelockControllerComponent { /// The possible states are: /// /// - `Unset`: the operation has not been scheduled or has been canceled. - /// - `Waiting`: the operation has been scheduled and is pending the minimum delay. + /// - `Waiting`: the operation has been scheduled and is pending the scheduled delay. /// - `Ready`: the timer has expired, and the operation is eligible for execution. /// - `Done`: the operation has been executed. fn get_operation_state( From ba26c698cfb2814fc801182606f90c514977e0d3 Mon Sep 17 00:00:00 2001 From: immrsd Date: Tue, 17 Dec 2024 15:16:09 +0100 Subject: [PATCH 26/28] Fix links --- docs/modules/ROOT/pages/api/governance.adoc | 28 ++++++++++----------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/docs/modules/ROOT/pages/api/governance.adoc b/docs/modules/ROOT/pages/api/governance.adoc index 93e55586b..5ec7b714c 100644 --- a/docs/modules/ROOT/pages/api/governance.adoc +++ b/docs/modules/ROOT/pages/api/governance.adoc @@ -1989,13 +1989,13 @@ operations. === `++IMultisig++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.20.0/packages/governance/src/multisig/interface.cairo[{github-icon},role=heading-link] :IMultisig-CallSalt: xref:IMultisig-CallSalt[CallSalt] -:IMultisig-SignerAdded: xref:IMultisig-CallSalt[SignerAdded] -:IMultisig-SignerRemoved: xref:IMultisig-CallSalt[SignerRemoved] -:IMultisig-QuorumUpdated: xref:IMultisig-CallSalt[QuorumUpdated] -:IMultisig-TransactionSubmitted: xref:IMultisig-CallSalt[TransactionSubmitted] -:IMultisig-TransactionConfirmed: xref:IMultisig-CallSalt[TransactionConfirmed] -:IMultisig-ConfirmationRevoked: xref:IMultisig-CallSalt[ConfirmationRevoked] -:IMultisig-TransactionExecuted: xref:IMultisig-CallSalt[TransactionExecuted] +:IMultisig-SignerAdded: xref:IMultisig-SignerAdded[SignerAdded] +:IMultisig-SignerRemoved: xref:IMultisig-SignerRemoved[SignerRemoved] +:IMultisig-QuorumUpdated: xref:IMultisig-QuorumUpdated[QuorumUpdated] +:IMultisig-TransactionSubmitted: xref:IMultisig-TransactionSubmitted[TransactionSubmitted] +:IMultisig-TransactionConfirmed: xref:IMultisig-TransactionConfirmed[TransactionConfirmed] +:IMultisig-ConfirmationRevoked: xref:IMultisig-ConfirmationRevoked[ConfirmationRevoked] +:IMultisig-TransactionExecuted: xref:IMultisig-TransactionExecuted[TransactionExecuted] [.hljs-theme-dark] ```cairo @@ -2306,13 +2306,13 @@ Emitted when a new transaction is submitted with non-zero salt. === `++MultisigComponent++` :MultisigComponent-CallSalt: xref:MultisigComponent-CallSalt[CallSalt] -:MultisigComponent-SignerAdded: xref:MultisigComponent-CallSalt[SignerAdded] -:MultisigComponent-SignerRemoved: xref:MultisigComponent-CallSalt[SignerRemoved] -:MultisigComponent-QuorumUpdated: xref:MultisigComponent-CallSalt[QuorumUpdated] -:MultisigComponent-TransactionSubmitted: xref:MultisigComponent-CallSalt[TransactionSubmitted] -:MultisigComponent-TransactionConfirmed: xref:MultisigComponent-CallSalt[TransactionConfirmed] -:MultisigComponent-ConfirmationRevoked: xref:MultisigComponent-CallSalt[ConfirmationRevoked] -:MultisigComponent-TransactionExecuted: xref:MultisigComponent-CallSalt[TransactionExecuted] +:MultisigComponent-SignerAdded: xref:MultisigComponent-SignerAdded[SignerAdded] +:MultisigComponent-SignerRemoved: xref:MultisigComponent-SignerRemoved[SignerRemoved] +:MultisigComponent-QuorumUpdated: xref:MultisigComponent-QuorumUpdated[QuorumUpdated] +:MultisigComponent-TransactionSubmitted: xref:MultisigComponent-TransactionSubmitted[TransactionSubmitted] +:MultisigComponent-TransactionConfirmed: xref:MultisigComponent-TransactionConfirmed[TransactionConfirmed] +:MultisigComponent-ConfirmationRevoked: xref:MultisigComponent-ConfirmationRevoked[ConfirmationRevoked] +:MultisigComponent-TransactionExecuted: xref:MultisigComponent-TransactionExecuted[TransactionExecuted] [.hljs-theme-dark] ```cairo From 7b4ba48207cdfa951e159615e2d41a110da22923 Mon Sep 17 00:00:00 2001 From: immrsd Date: Tue, 17 Dec 2024 20:01:15 +0100 Subject: [PATCH 27/28] Fix doc review issues --- docs/modules/ROOT/pages/api/governance.adoc | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/api/governance.adoc b/docs/modules/ROOT/pages/api/governance.adoc index 5ec7b714c..c92bef16e 100644 --- a/docs/modules/ROOT/pages/api/governance.adoc +++ b/docs/modules/ROOT/pages/api/governance.adoc @@ -2124,6 +2124,7 @@ Requirements: - `new_quorum` must be less than or equal to the total number of signers after addition. Emits a {IMultisig-SignerAdded} event for each signer added. + Emits a {IMultisig-QuorumUpdated} event if the quorum changes. [.contract-item] @@ -2138,6 +2139,7 @@ Requirements: - `new_quorum` must be less than or equal to the total number of signers after removal. Emits a {IMultisig-SignerRemoved} event for each signer removed. + Emits a {IMultisig-QuorumUpdated} event if the quorum changes. [.contract-item] @@ -2153,6 +2155,7 @@ Requirements: - `signer_to_add` must not be an existing signer. Emits a {IMultisig-SignerRemoved} event for the removed signer. + Emits a {IMultisig-SignerAdded} event for the new signer. [.contract-item] @@ -2181,6 +2184,7 @@ Requirements: - The transaction must not have been submitted before. Emits a {IMultisig-TransactionSubmitted} event. + Emits a {IMultisig-CallSalt} event if `salt` is not zero. [.contract-item] @@ -2195,6 +2199,7 @@ Requirements: - The transaction must not have been submitted before. Emits a {IMultisig-TransactionSubmitted} event. + Emits a {IMultisig-CallSalt} event if `salt` is not zero. [.contract-item] @@ -2319,7 +2324,7 @@ Emitted when a new transaction is submitted with non-zero salt. use openzeppelin_governance::multisig::MultisigComponent; ``` -Component that implements `IMultisig` and provides functionality for multisignature wallets, +Component that implements <> and provides functionality for multisignature wallets, including transaction management, quorum handling, and signer operations. [.contract-index] @@ -2467,6 +2472,7 @@ Requirements: - `new_quorum` must be less than or equal to the total number of signers after addition. Emits a {MultisigComponent-SignerAdded} event for each signer added. + Emits a {MultisigComponent-QuorumUpdated} event if the quorum changes. [.contract-item] @@ -2481,6 +2487,7 @@ Requirements: - `new_quorum` must be less than or equal to the total number of signers after removal. Emits a {MultisigComponent-SignerRemoved} event for each signer removed. + Emits a {MultisigComponent-QuorumUpdated} event if the quorum changes. [.contract-item] @@ -2496,6 +2503,7 @@ Requirements: - `signer_to_add` must not be an existing signer. Emits a {MultisigComponent-SignerRemoved} event for the removed signer. + Emits a {MultisigComponent-SignerAdded} event for the new signer. [.contract-item] @@ -2524,6 +2532,7 @@ Requirements: - The transaction must not have been submitted before. Emits a {MultisigComponent-TransactionSubmitted} event. + Emits a {MultisigComponent-CallSalt} event if `salt` is not zero. [.contract-item] @@ -2538,6 +2547,7 @@ Requirements: - The transaction must not have been submitted before. Emits a {MultisigComponent-TransactionSubmitted} event. + Emits a {MultisigComponent-CallSalt} event if `salt` is not zero. [.contract-item] @@ -2608,6 +2618,7 @@ Requirements: - `quorum` must be non-zero and less than or equal to the number of `signers`. Emits a {MultisigComponent-SignerAdded} event for each signer added. + Emits a {MultisigComponent-QuorumUpdated} event. [.contract-item] @@ -2665,6 +2676,7 @@ Requirements: - `new_quorum` must be non-zero and less than or equal to the total number of signers after addition. Emits a {MultisigComponent-SignerAdded} event for each new signer added. + Emits a {MultisigComponent-QuorumUpdated} event if the quorum changes. [.contract-item] @@ -2679,6 +2691,7 @@ Requirements: after removal. Emits a {MultisigComponent-SignerRemoved} event for each signer removed. + Emits a {MultisigComponent-QuorumUpdated} event if the quorum changes. [.contract-item] @@ -2694,6 +2707,7 @@ Requirements: - `signer_to_add` must be a non-zero address. Emits a {MultisigComponent-SignerRemoved} event for the removed signer. + Emits a {MultisigComponent-SignerAdded} event for the new signer. [.contract-item] From 6146c2b4a77a8d2b77b7864aee30a322a88094a0 Mon Sep 17 00:00:00 2001 From: immrsd Date: Tue, 17 Dec 2024 20:04:24 +0100 Subject: [PATCH 28/28] Add corresponding newlines in in-code Multisig doc --- packages/governance/src/multisig/multisig.cairo | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/governance/src/multisig/multisig.cairo b/packages/governance/src/multisig/multisig.cairo index e65c8f3ce..27f103bda 100644 --- a/packages/governance/src/multisig/multisig.cairo +++ b/packages/governance/src/multisig/multisig.cairo @@ -252,6 +252,7 @@ pub mod MultisigComponent { /// - `new_quorum` must be less than or equal to the total number of signers after addition. /// /// Emits a `SignerAdded` event for each signer added. + /// /// Emits a `QuorumUpdated` event if the quorum changes. fn add_signers( ref self: ComponentState, @@ -270,6 +271,7 @@ pub mod MultisigComponent { /// - `new_quorum` must be less than or equal to the total number of signers after removal. /// /// Emits a `SignerRemoved` event for each signer removed. + /// /// Emits a `QuorumUpdated` event if the quorum changes. fn remove_signers( ref self: ComponentState, @@ -290,6 +292,7 @@ pub mod MultisigComponent { /// - `signer_to_add` must be a non-zero address. /// /// Emits a `SignerRemoved` event for the removed signer. + /// /// Emits a `SignerAdded` event for the new signer. fn replace_signer( ref self: ComponentState, @@ -322,6 +325,7 @@ pub mod MultisigComponent { /// - The transaction must not have been submitted before. /// /// Emits a `TransactionSubmitted` event. + /// /// Emits a `CallSalt` event if `salt` is not zero. fn submit_transaction( ref self: ComponentState, @@ -342,6 +346,7 @@ pub mod MultisigComponent { /// - The transaction must not have been submitted before. /// /// Emits a `TransactionSubmitted` event. + /// /// Emits a `CallSalt` event if `salt` is not zero. fn submit_transaction_batch( ref self: ComponentState, calls: Span, salt: felt252, @@ -468,6 +473,7 @@ pub mod MultisigComponent { /// - `quorum` must be non-zero and less than or equal to the number of `signers`. /// /// Emits a `SignerAdded` event for each signer added. + /// /// Emits a `QuorumUpdated` event. fn initializer( ref self: ComponentState, quorum: u32, signers: Span, @@ -540,6 +546,7 @@ pub mod MultisigComponent { /// after addition. /// /// Emits a `SignerAdded` event for each new signer added. + /// /// Emits a `QuorumUpdated` event if the quorum changes. fn _add_signers( ref self: ComponentState, @@ -575,6 +582,7 @@ pub mod MultisigComponent { /// after removal. /// /// Emits a `SignerRemoved` event for each signer removed. + /// /// Emits a `QuorumUpdated` event if the quorum changes. fn _remove_signers( ref self: ComponentState, @@ -618,6 +626,7 @@ pub mod MultisigComponent { /// - `signer_to_add` must be a non-zero address. /// /// Emits a `SignerRemoved` event for the removed signer. + /// /// Emits a `SignerAdded` event for the new signer. fn _replace_signer( ref self: ComponentState,