diff --git a/cairo-contracts/packages/contracts/src/core.cairo b/cairo-contracts/packages/contracts/src/core.cairo index 6b0db7bc..83f9957a 100644 --- a/cairo-contracts/packages/contracts/src/core.cairo +++ b/cairo-contracts/packages/contracts/src/core.cairo @@ -7,6 +7,17 @@ pub mod IBCCore { use starknet_ibc_core::connection::ConnectionEventEmitterComponent; use starknet_ibc_core::connection::ConnectionHandlerComponent; use starknet_ibc_core::router::RouterHandlerComponent; + use starknet_ibc_utils::governance::IBCGovernanceComponent; + + // ----------------------------------------------------------- + // Setup Governance Component + // ----------------------------------------------------------- + + component!(path: IBCGovernanceComponent, storage: governance, event: IBCGovernanceEvent); + + #[abi(embed_v0)] + impl IBCGovernanceImpl = IBCGovernanceComponent::Governance; + impl IBCGovernanceInternalImpl = IBCGovernanceComponent::GovernanceInternalImpl; // ----------------------------------------------------------- // Setup Client Components @@ -77,6 +88,8 @@ pub mod IBCCore { #[storage] struct Storage { + #[substorage(v0)] + governance: IBCGovernanceComponent::Storage, #[substorage(v0)] client_emitter: ClientEventEmitterComponent::Storage, #[substorage(v0)] @@ -96,6 +109,8 @@ pub mod IBCCore { #[event] #[derive(Debug, Drop, starknet::Event)] pub enum Event { + #[flat] + IBCGovernanceEvent: IBCGovernanceComponent::Event, #[flat] ClientEventEmitterEvent: ClientEventEmitterComponent::Event, #[flat] @@ -114,6 +129,7 @@ pub mod IBCCore { #[constructor] fn constructor(ref self: ContractState) { + self.governance.initializer(); self.client_handler.initializer(); self.router_handler.initializer(); } diff --git a/cairo-contracts/packages/core/src/client/components/handler.cairo b/cairo-contracts/packages/core/src/client/components/handler.cairo index 0c2d48e7..03fa8f9b 100644 --- a/cairo-contracts/packages/core/src/client/components/handler.cairo +++ b/cairo-contracts/packages/core/src/client/components/handler.cairo @@ -1,8 +1,11 @@ #[starknet::component] pub mod ClientHandlerComponent { use core::num::traits::Zero; - use starknet::ContractAddress; - use starknet::storage::{Map, StorageMapReadAccess, StorageMapWriteAccess}; + use starknet::storage::{ + Map, StorageMapReadAccess, StorageMapWriteAccess, Vec, VecTrait, MutableVecTrait, + StoragePointerReadAccess, StoragePointerWriteAccess + }; + use starknet::{ContractAddress, get_caller_address}; use starknet_ibc_core::client::ClientEventEmitterComponent::ClientEventEmitterTrait; use starknet_ibc_core::client::ClientEventEmitterComponent; use starknet_ibc_core::client::interface::{IClientHandler, IRegisterClient}; @@ -11,9 +14,14 @@ pub mod ClientHandlerComponent { CreateResponse, UpdateResponse, ClientErrors, ClientContract, ClientContractHandlerTrait }; use starknet_ibc_core::host::{ClientId, ClientIdImpl}; + use starknet_ibc_utils::governance::IBCGovernanceComponent::GovernanceInternalTrait; + use starknet_ibc_utils::governance::IBCGovernanceComponent; #[storage] pub struct Storage { + // NOTE: Temporary relayer whitelist for phase two, + // to be replaced after Comet client contract is implemented. + allowed_relayers: Vec, supported_clients: Map, } @@ -29,7 +37,9 @@ pub mod ClientHandlerComponent { pub impl ClientInitializerImpl< TContractState, +HasComponent, +Drop > of ClientInitializerTrait { - fn initializer(ref self: ComponentState) {} + fn initializer(ref self: ComponentState) { + self.write_allowed_relayer(get_caller_address()); + } } // ----------------------------------------------------------- @@ -41,7 +51,7 @@ pub mod ClientHandlerComponent { TContractState, +HasComponent, +Drop, - impl EventEmitter: ClientEventEmitterComponent::HasComponent + impl EventEmitter: ClientEventEmitterComponent::HasComponent, > of IClientHandler> { fn create_client( ref self: ComponentState, msg: MsgCreateClient @@ -58,6 +68,8 @@ pub mod ClientHandlerComponent { fn update_client( ref self: ComponentState, msg: MsgUpdateClient ) -> UpdateResponse { + assert(self.in_allowed_relayers(get_caller_address()), ClientErrors::INVALID_RELAYER); + let mut client = self.get_client(msg.client_id.client_type); let update_result = client.update(msg.clone()); @@ -105,6 +117,28 @@ pub mod ClientHandlerComponent { } } + // ----------------------------------------------------------- + // Allowed Relayers + // ----------------------------------------------------------- + + #[generate_trait] + pub impl RegisterRelayerImpl< + TContractState, + +HasComponent, + +Drop, + impl Governance: IBCGovernanceComponent::HasComponent + > of RegisterRelayerTrait { + fn register_relayer( + ref self: ComponentState, relayer_address: ContractAddress + ) { + let governor = get_dep_component!(@self, Governance).governor(); + + assert(governor == get_caller_address(), ClientErrors::INVALID_GOVERNOR); + + self.write_allowed_relayer(relayer_address); + } + } + // ----------------------------------------------------------- // Client Internal // ----------------------------------------------------------- @@ -128,6 +162,21 @@ pub mod ClientHandlerComponent { pub(crate) impl ClientReaderImpl< TContractState, +HasComponent, +Drop > of ClientReaderTrait { + fn in_allowed_relayers( + self: @ComponentState, caller: ContractAddress + ) -> bool { + let mut allowed = false; + let mut i = 0; + while i < self.allowed_relayers.len() { + if self.allowed_relayers.at(i).read() == caller { + allowed = true; + break; + } + i += 1; + }; + allowed + } + fn read_supported_client( self: @ComponentState, client_type: felt252 ) -> ContractAddress { @@ -143,6 +192,12 @@ pub mod ClientHandlerComponent { pub(crate) impl ClientWriterImpl< TContractState, +HasComponent, +Drop > of ClientWriterTrait { + fn write_allowed_relayer( + ref self: ComponentState, relayer_address: ContractAddress + ) { + self.allowed_relayers.append().write(relayer_address); + } + fn write_supported_client( ref self: ComponentState, client_type: felt252, diff --git a/cairo-contracts/packages/core/src/client/errors.cairo b/cairo-contracts/packages/core/src/client/errors.cairo index 7e56364d..86a92f14 100644 --- a/cairo-contracts/packages/core/src/client/errors.cairo +++ b/cairo-contracts/packages/core/src/client/errors.cairo @@ -6,6 +6,8 @@ pub mod ClientErrors { pub const EMPTY_CLIENT_MESSAGE: felt252 = 'ICS02: empty client message'; pub const INACTIVE_CLIENT: felt252 = 'ICS02: inactive client'; pub const INVALID_PROOF_HEIGHT: felt252 = 'ICS04: invalid proof height'; + pub const INVALID_GOVERNOR: felt252 = 'ICS02: invalid governor'; + pub const INVALID_RELAYER: felt252 = 'ICS02: invalid relayer'; pub const INVALID_SUBSTITUTE_CLIENT_ID: felt252 = 'ICS02: invalid subs client id'; pub const OVERFLOWED_HEIGHT: felt252 = 'ICS02: overflowed height'; pub const OVERFLOWED_TIMESTAMP: felt252 = 'ICS02: overflowed timestamp'; diff --git a/cairo-contracts/packages/utils/src/governance/component.cairo b/cairo-contracts/packages/utils/src/governance/component.cairo index 75727185..1c6f3da8 100644 --- a/cairo-contracts/packages/utils/src/governance/component.cairo +++ b/cairo-contracts/packages/utils/src/governance/component.cairo @@ -1,6 +1,6 @@ #[starknet::component] pub mod IBCGovernanceComponent { - use starknet::storage::StoragePointerWriteAccess; + use starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess}; use starknet::{ContractAddress, get_caller_address}; use starknet_ibc_utils::governance::IGovernance; @@ -25,6 +25,10 @@ pub mod IBCGovernanceComponent { fn initializer(ref self: ComponentState) { self.governor.write(get_caller_address()); } + + fn governor(self: @ComponentState) -> ContractAddress { + self.governor.read() + } } }