From c962eefe003b4179245d1799c96fabd716b7c119 Mon Sep 17 00:00:00 2001 From: immrsd Date: Tue, 10 Dec 2024 14:58:38 +0100 Subject: [PATCH] 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); +} +----