Skip to content

Commit

Permalink
Introduce internal components (#634)
Browse files Browse the repository at this point in the history
* remove state from eip712 mod

* move SNIP12 to components

* add simple quorum component

* annotate ownableImpl with embed_v0

* add space manager component

* add reinitializable component

* scarb: fmt

* add Single Slot Proof Component

* scarb fmt

* use storage prefix to avoid clashes

* add SingleSlotProofImpl as embeddable

* chore: fmt

* ensure ozvotes / evm_slot_value strategies expose the SingleSlotProof external functions

* remove cfg test
  • Loading branch information
pscott authored Oct 21, 2024
1 parent 66ff926 commit af131eb
Show file tree
Hide file tree
Showing 25 changed files with 910 additions and 748 deletions.
24 changes: 5 additions & 19 deletions starknet/src/authenticators/eth_sig.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ mod EthSigAuthenticator {
use starknet::{ContractAddress, EthAddress};
use sx::interfaces::{ISpaceDispatcher, ISpaceDispatcherTrait};
use sx::types::{Strategy, IndexedStrategy, Choice, UserAddress};
use sx::utils::{EIP712, LegacyHashEthAddress, ByteReverse};
use sx::utils::{eip712, LegacyHashEthAddress, ByteReverse};

#[storage]
struct Storage {
Expand All @@ -112,9 +112,7 @@ mod EthSigAuthenticator {
) {
assert(!self._used_salts.read((author, salt)), 'Salt Already Used');

let state = EIP712::unsafe_new_contract_state();
EIP712::InternalImpl::verify_propose_sig(
@state,
eip712::verify_propose_sig(
r,
s,
v,
Expand Down Expand Up @@ -149,9 +147,7 @@ mod EthSigAuthenticator {
) {
// No need to check salts here, as double voting is prevented by the space itself.

let state = EIP712::unsafe_new_contract_state();
EIP712::InternalImpl::verify_vote_sig(
@state,
eip712::verify_vote_sig(
r,
s,
v,
Expand Down Expand Up @@ -187,18 +183,8 @@ mod EthSigAuthenticator {
) {
assert(!self._used_salts.read((author, salt)), 'Salt Already Used');

let state = EIP712::unsafe_new_contract_state();
EIP712::InternalImpl::verify_update_proposal_sig(
@state,
r,
s,
v,
space,
author,
proposal_id,
@execution_strategy,
metadata_uri.span(),
salt
eip712::verify_update_proposal_sig(
r, s, v, space, author, proposal_id, @execution_strategy, metadata_uri.span(), salt
);
self._used_salts.write((author, salt), true);
ISpaceDispatcher { contract_address: space }
Expand Down
85 changes: 48 additions & 37 deletions starknet/src/authenticators/stark_sig.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,23 @@ mod StarkSigAuthenticator {
use starknet::{ContractAddress, info};
use sx::interfaces::{ISpaceDispatcher, ISpaceDispatcherTrait};
use sx::types::{Strategy, IndexedStrategy, UserAddress, Choice};
use sx::utils::SNIP12;
use sx::utils::snip12::SNIP12Component;

component!(path: SNIP12Component, storage: snip12, event: SNIP12Event);

impl SNIP12InternalImpl = SNIP12Component::InternalImpl<ContractState>;

#[storage]
struct Storage {
_used_salts: LegacyMap::<(ContractAddress, felt252), bool>
_used_salts: LegacyMap::<(ContractAddress, felt252), bool>,
#[substorage(v0)]
snip12: SNIP12Component::Storage
}

#[event]
#[derive(Drop, starknet::Event)]
enum Event {
SNIP12Event: SNIP12Component::Event
}

#[abi(embed_v0)]
Expand All @@ -102,17 +114,17 @@ mod StarkSigAuthenticator {
) {
assert(!self._used_salts.read((author, salt)), 'Salt Already Used');

let state = SNIP12::unsafe_new_contract_state();
SNIP12::InternalImpl::verify_propose_sig(
@state,
signature,
space,
author,
metadata_uri.span(),
@execution_strategy,
user_proposal_validation_params.span(),
salt
);
self
.snip12
.verify_propose_sig(
signature,
space,
author,
metadata_uri.span(),
@execution_strategy,
user_proposal_validation_params.span(),
salt
);

self._used_salts.write((author, salt), true);
ISpaceDispatcher { contract_address: space }
Expand All @@ -136,17 +148,17 @@ mod StarkSigAuthenticator {
) {
// No need to check salts here, as double voting is prevented by the space itself.

let state = SNIP12::unsafe_new_contract_state();
SNIP12::InternalImpl::verify_vote_sig(
@state,
signature,
space,
voter,
proposal_id,
choice,
user_voting_strategies.span(),
metadata_uri.span()
);
self
.snip12
.verify_vote_sig(
signature,
space,
voter,
proposal_id,
choice,
user_voting_strategies.span(),
metadata_uri.span()
);

ISpaceDispatcher { contract_address: space }
.vote(
Expand All @@ -170,17 +182,17 @@ mod StarkSigAuthenticator {
) {
assert(!self._used_salts.read((author, salt)), 'Salt Already Used');

let state = SNIP12::unsafe_new_contract_state();
SNIP12::InternalImpl::verify_update_proposal_sig(
@state,
signature,
space,
author,
proposal_id,
@execution_strategy,
metadata_uri.span(),
salt
);
self
.snip12
.verify_update_proposal_sig(
signature,
space,
author,
proposal_id,
@execution_strategy,
metadata_uri.span(),
salt
);

self._used_salts.write((author, salt), true);
ISpaceDispatcher { contract_address: space }
Expand All @@ -191,7 +203,6 @@ mod StarkSigAuthenticator {
}
#[constructor]
fn constructor(ref self: ContractState, name: felt252, version: felt252) {
let mut state = SNIP12::unsafe_new_contract_state();
SNIP12::InternalImpl::initializer(ref state, name, version);
self.snip12.initializer(name, version);
}
}
82 changes: 34 additions & 48 deletions starknet/src/execution_strategies/timelock.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,6 @@ trait ITimelockExecutionStrategy<TContractState> {
fn disable_space(ref self: TContractState, space: ContractAddress);

fn is_space_enabled(self: @TContractState, space: ContractAddress) -> bool;

/// Transfers the ownership to `new_owner`.
fn transfer_ownership(ref self: TContractState, new_owner: ContractAddress);
/// Renounces the ownership of the contract. CAUTION: This is a one-way operation.
fn renounce_ownership(ref self: TContractState);

fn owner(self: @TContractState) -> ContractAddress;
}

#[starknet::contract]
Expand All @@ -37,20 +30,34 @@ mod TimelockExecutionStrategy {
use sx::interfaces::IExecutionStrategy;
use super::ITimelockExecutionStrategy;
use sx::types::{Proposal, ProposalStatus};
use sx::utils::{SimpleQuorum, SpaceManager};
use sx::utils::{simple_quorum::SimpleQuorumComponent, space_manager::SpaceManagerComponent};

component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);

impl OwnableInternalImpl = OwnableComponent::InternalImpl<ContractState>;
#[abi(embed_v0)]
impl OwnableImpl = OwnableComponent::OwnableImpl<ContractState>;
impl OwnableInternalImpl = OwnableComponent::InternalImpl<ContractState>;

component!(path: SimpleQuorumComponent, storage: simple_quorum, event: SimpleQuorumEvent);

#[abi(embed_v0)]
impl SimpleQuorumImpl = SimpleQuorumComponent::SimpleQuorumImpl<ContractState>;
impl SimpleQuorumInternalImpl = SimpleQuorumComponent::InternalImpl<ContractState>;

component!(path: SpaceManagerComponent, storage: space_manager, event: SpaceManagerEvent);
impl SpaceManagerInternalImpl = SpaceManagerComponent::InternalImpl<ContractState>;

#[storage]
struct Storage {
_timelock_delay: u32,
_veto_guardian: ContractAddress,
_proposal_execution_time: LegacyMap::<felt252, u32>,
#[substorage(v0)]
ownable: OwnableComponent::Storage
ownable: OwnableComponent::Storage,
#[substorage(v0)]
simple_quorum: SimpleQuorumComponent::Storage,
#[substorage(v0)]
space_manager: SpaceManagerComponent::Storage,
}

#[event]
Expand All @@ -65,7 +72,11 @@ mod TimelockExecutionStrategy {
ProposalExecuted: ProposalExecuted,
ProposalVetoed: ProposalVetoed,
#[flat]
OwnableEvent: OwnableComponent::Event
OwnableEvent: OwnableComponent::Event,
#[flat]
SimpleQuorumEvent: SimpleQuorumComponent::Event,
#[flat]
SpaceManagerEvent: SpaceManagerComponent::Event,
}

#[derive(Drop, PartialEq, starknet::Event)]
Expand Down Expand Up @@ -132,11 +143,9 @@ mod TimelockExecutionStrategy {
) {
self.ownable.initializer(owner);

let mut state = SimpleQuorum::unsafe_new_contract_state();
SimpleQuorum::InternalImpl::initializer(ref state, quorum);
self.simple_quorum.initializer(quorum);

let mut state = SpaceManager::unsafe_new_contract_state();
SpaceManager::InternalImpl::initializer(ref state, spaces);
self.space_manager.initializer(spaces);

self._timelock_delay.write(timelock_delay);
self._veto_guardian.write(veto_guardian);
Expand All @@ -153,14 +162,10 @@ mod TimelockExecutionStrategy {
votes_abstain: u256,
payload: Array<felt252>
) {
// Migration to components planned ; disregard the `unsafe` keyword,
// it is actually safe.
let state = SpaceManager::unsafe_new_contract_state();
SpaceManager::InternalImpl::assert_only_spaces(@state);
let state = SimpleQuorum::unsafe_new_contract_state();
let proposal_status = SimpleQuorum::InternalImpl::get_proposal_status(
@state, @proposal, votes_for, votes_against, votes_abstain
);
self.space_manager.assert_only_spaces();
let proposal_status = self
.simple_quorum
.get_proposal_status(@proposal, votes_for, votes_against, votes_abstain);
assert(
proposal_status == ProposalStatus::Accepted(())
|| proposal_status == ProposalStatus::VotingPeriodAccepted(()),
Expand Down Expand Up @@ -201,10 +206,9 @@ mod TimelockExecutionStrategy {
votes_against: u256,
votes_abstain: u256,
) -> ProposalStatus {
let state = SimpleQuorum::unsafe_new_contract_state();
SimpleQuorum::InternalImpl::get_proposal_status(
@state, @proposal, votes_for, votes_against, votes_abstain
)
self
.simple_quorum
.get_proposal_status(@proposal, votes_for, votes_against, votes_abstain)
}

fn get_strategy_type(self: @ContractState) -> felt252 {
Expand Down Expand Up @@ -295,34 +299,16 @@ mod TimelockExecutionStrategy {

fn enable_space(ref self: ContractState, space: ContractAddress) {
self.ownable.assert_only_owner();
let mut state = SpaceManager::unsafe_new_contract_state();
SpaceManager::InternalImpl::enable_space(ref state, space);
self.space_manager.enable_space(space);
}

fn disable_space(ref self: ContractState, space: ContractAddress) {
self.ownable.assert_only_owner();
let mut state = SpaceManager::unsafe_new_contract_state();
SpaceManager::InternalImpl::disable_space(ref state, space);
self.space_manager.disable_space(space);
}

fn is_space_enabled(self: @ContractState, space: ContractAddress) -> bool {
// Migration to components planned ; disregard the `unsafe` keyword,
// it is actually safe.
let state = SpaceManager::unsafe_new_contract_state();
SpaceManager::InternalImpl::is_space_enabled(@state, space)
}

// TODO: use Ownable impl as abi_embed(v0)?
fn owner(self: @ContractState) -> ContractAddress {
self.ownable.owner()
}

fn transfer_ownership(ref self: ContractState, new_owner: ContractAddress) {
self.ownable.transfer_ownership(new_owner);
}

fn renounce_ownership(ref self: ContractState) {
self.ownable.renounce_ownership();
self.space_manager.is_space_enabled(space)
}
}

Expand Down
28 changes: 28 additions & 0 deletions starknet/src/interfaces/i_single_slot_proof.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
use sx::external::herodotus::BinarySearchTree;

/// Optional trait that execution strategies can decide to implement.
#[starknet::interface]
trait ISingleSlotProof<TContractState> {
/// Queries the Timestamp Remapper contract for the closest L1 block number that occurred before
/// the given timestamp and then caches the result. If the queried timestamp is less than the earliest
/// timestamp or larger than the latest timestamp in the mapper then the transaction will revert.
/// This function should be used to cache a remapped timestamp before it's used when calling the
/// `get_storage_slot` function with the same timestamp.
///
/// # Arguments
///
/// * `timestamp` - The timestamp at which to query.
/// * `tree` - The tree proof required to query the remapper.
fn cache_timestamp(ref self: TContractState, timestamp: u32, tree: BinarySearchTree);

/// View function exposing the cached remapped timestamps. Reverts if the timestamp is not cached.
///
/// # Arguments
///
/// * `timestamp` - The timestamp to query.
///
/// # Returns
///
/// * `u256` - The cached L1 block number corresponding to the timestamp.
fn cached_timestamps(self: @TContractState, timestamp: u32) -> u256;
}
7 changes: 0 additions & 7 deletions starknet/src/interfaces/i_space.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@ use sx::types::{
trait ISpace<TContractState> {
// -- View functions --

/// Returns the owner of the contract.
fn owner(self: @TContractState) -> ContractAddress;

/// The voting delay in seconds between when a proposal is created and the start of the voting period.
fn voting_delay(self: @TContractState) -> u32;

Expand Down Expand Up @@ -60,10 +57,6 @@ trait ISpace<TContractState> {
/// struct is passed to be able to update different settings in a single call. Settings that should not
/// be updated should have the `no_update` value (see `UpdateSettingsCalldata`).
fn update_settings(ref self: TContractState, input: UpdateSettingsCalldata);
/// Transfers the ownership to `new_owner`.
fn transfer_ownership(ref self: TContractState, new_owner: ContractAddress);
/// Renounces the ownership of the contract. CAUTION: This is a one-way operation.
fn renounce_ownership(ref self: TContractState);

// -- Actions --
/// Initializes the contract. Can only be called once.
Expand Down
Loading

0 comments on commit af131eb

Please sign in to comment.