Skip to content

Commit

Permalink
User State & Operations Added (#7)
Browse files Browse the repository at this point in the history
  • Loading branch information
eddnewgate authored Aug 10, 2024
1 parent e72e488 commit f3d4f0a
Showing 1 changed file with 165 additions and 7 deletions.
172 changes: 165 additions & 7 deletions src/lib.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,31 @@ pub trait IPushComm<TContractState> {
fn get_migration_status(self: @TContractState) -> bool;
fn set_push_core_address(ref self: TContractState, core_address: felt252);
fn get_push_core_address(self: @TContractState) -> felt252;
fn verify_channel_alias(ref self: TContractState, channel_address: felt252);
fn get_push_governance_address(self: @TContractState) -> felt252;
fn set_push_governance_address(ref self: TContractState, governance_address: felt252);
fn get_push_token_address(self: @TContractState) -> felt252;
fn set_push_token_address(ref self: TContractState, push_token_address: felt252);
// Channel
fn verify_channel_alias(ref self: TContractState, channel_address: felt252);
fn add_delegate(ref self: TContractState, delegate: ContractAddress);
fn remove_delegate(ref self: TContractState, delegate: ContractAddress);
// User
fn is_user_subscribed(
self: @TContractState, channel: ContractAddress, user: ContractAddress
) -> bool;
fn subscribe(ref self: TContractState, channel: ContractAddress);
fn unsubscribe(ref self: TContractState, channel: ContractAddress);
fn batch_subscribe(ref self: TContractState, channels: Array<ContractAddress>);
fn batch_unsubscribe(ref self: TContractState, channels: Array<ContractAddress>);
}

#[starknet::contract]
pub mod PushComm {
use push_comm::IPushComm;
use core::starknet::event::EventEmitter;
use core::starknet::storage::MutableStorageNode;
use core::starknet::storage::StoragePointerReadAccess;
use core::starknet::storage::StoragePathEntry;
use openzeppelin::access::ownable::interface::OwnableABI;
use core::starknet::storage::StoragePointerWriteAccess;
use starknet::storage::{Map, StorageMapReadAccess, StorageMapWriteAccess};
Expand All @@ -38,10 +54,10 @@ pub mod PushComm {
// Users
users: Map<ContractAddress, User>,
users_count: u256,
map_address_users: u256,
map_address_users: Map<u256, ContractAddress>,
user_to_channel_notifs: Map<ContractAddress, Map<ContractAddress, ByteArray>>,
// Channels
delegatedNotificationSenders: Map<ContractAddress, bool>,
delegatedNotificationSenders: Map<ContractAddress, Map<ContractAddress, bool>>,
// Contract State
governance: felt252,
is_migration_complete: bool,
Expand All @@ -58,19 +74,52 @@ pub mod PushComm {
is_public_key_registered: bool,
start_block: u256,
subscribed_count: u256,
is_subscribed: Map<ContractAddress, u8>,
subscribed: Map<ContractAddress, u8>,
map_address_subscribed: Map<ContractAddress, u8>,
is_subscribed: Map<ContractAddress, bool>,
subscribed: Map<ContractAddress, u256>,
map_address_subscribed: Map<u256, ContractAddress>,
}

#[event]
#[derive(Drop, starknet::Event)]
pub enum Event {
#[flat]
OwnableEvent: OwnableComponent::Event,
ChannelAlias: ChannelAlias
ChannelAlias: ChannelAlias,
Subscribe: Subscribe,
UnSubscribe: UnSubscribe,
AddDelegate: AddDelegate,
RemoveDelegate: RemoveDelegate,
}

#[derive(Drop, starknet::Event)]
pub struct ChannelAlias {
#[key]
pub chain_name: felt252,
pub chain_id: felt252,
pub channel_owner_address: ContractAddress,
pub ethereum_channel_address: felt252,
}

#[derive(Drop, starknet::Event)]
pub struct Subscribe {
#[key]
pub channel: ContractAddress,
pub user: ContractAddress,
}

#[derive(Drop, starknet::Event)]
pub struct UnSubscribe {
#[key]
pub channel: ContractAddress,
pub user: ContractAddress,
}

#[derive(Drop, starknet::Event)]
pub struct AddDelegate {
#[key]
pub channel: ContractAddress,
pub delegate: ContractAddress,

#[derive(Drop, starknet::Event)]
pub struct ChannelAlias {
#[key]
Expand All @@ -80,6 +129,14 @@ pub mod PushComm {
pub ethereum_channel_address: felt252,
}

#[derive(Drop, starknet::Event)]
pub struct RemoveDelegate {
#[key]
pub channel: ContractAddress,
pub delegate: ContractAddress,
}


#[constructor]
fn constructor(
ref self: ContractState, owner: ContractAddress, chain_id: felt252, chain_name: felt252
Expand All @@ -90,9 +147,95 @@ pub mod PushComm {
self.chain_name.write(chain_name);
}

#[generate_trait]
impl InternalFunctions of InternalFunctionsTrait {
fn _is_user_subscribed(
self: @ContractState, channel: ContractAddress, user: ContractAddress
) -> bool {
let user_info = self.users.entry(user);
user_info.is_subscribed.entry(channel).read()
}

fn _subscribe(ref self: ContractState, channel: ContractAddress, user: ContractAddress) {
if !self._is_user_subscribed(channel, user) {
self._add_user(user);

let user_info = self.users.entry(user).storage_node_mut();
let _subscribed_count = user_info.subscribed_count.read();

// treat the count as index and update user struct
user_info.is_subscribed.write(channel, true);
user_info.subscribed.write(channel, _subscribed_count);
user_info.map_address_subscribed.write(_subscribed_count, channel);
user_info.subscribed_count.write(_subscribed_count + 1);

// Emit
self.emit(Subscribe { channel: channel, user: user });
}
}

fn _unsubscribe(ref self: ContractState, channel: ContractAddress, user: ContractAddress) {
if self._is_user_subscribed(channel, user) {
let user_info = self.users.entry(user).storage_node_mut();
let _subscribed_count = user_info.subscribed_count.read() - 1;

// treat the count as index and update user struct
user_info.is_subscribed.write(channel, false);

// TODO: handle _unsubscribe core

// Emit
self.emit(UnSubscribe { channel: channel, user: user });
}
}


fn _add_user(ref self: ContractState, user: ContractAddress) {
let user_info = self.users.entry(user).storage_node_mut();

if !user_info.is_activated.read() {
user_info.is_activated.write(true);
user_info.start_block.write(1);

let user_count = self.users_count.read();
self.map_address_users.write(user_count, user);
self.users_count.write(user_count + 1);
}
}
}


#[abi(embed_v0)]
impl PushComm of super::IPushComm<ContractState> {
// User
fn is_user_subscribed(
self: @ContractState, channel: ContractAddress, user: ContractAddress
) -> bool {
self._is_user_subscribed(channel, user)
}

fn subscribe(ref self: ContractState, channel: ContractAddress) {
self._subscribe(channel, get_caller_address());
}

fn unsubscribe(ref self: ContractState, channel: ContractAddress) {
self._unsubscribe(channel, get_caller_address());
}

fn batch_subscribe(ref self: ContractState, channels: Array<ContractAddress>) {
for channel in channels {
self._subscribe(channel, get_caller_address());
}
}

fn batch_unsubscribe(ref self: ContractState, channels: Array<ContractAddress>) {
for channel in channels {
self._unsubscribe(channel, get_caller_address());
}
}


// Admin
fn complete_migration(ref self: ContractState) {
self.ownable.assert_only_owner();
self.is_migration_complete.write(true);
Expand All @@ -111,6 +254,7 @@ pub mod PushComm {
self.push_core_address.read()
}

// Channel
fn verify_channel_alias(ref self: ContractState, channel_address: felt252) {
self
.emit(
Expand All @@ -123,6 +267,20 @@ pub mod PushComm {
);
}

fn add_delegate(ref self: ContractState, delegate: ContractAddress) {
let channel = get_caller_address();
self.delegatedNotificationSenders.entry(channel).write(delegate, true);
self.emit(AddDelegate { channel: channel, delegate: delegate });
}

fn remove_delegate(ref self: ContractState, delegate: ContractAddress) {
let channel = get_caller_address();
self.delegatedNotificationSenders.entry(channel).write(delegate, false);
self.emit(RemoveDelegate { channel: channel, delegate: delegate });
}


// Infos
fn set_push_governance_address(ref self: ContractState, governance_address: felt252) {
self.ownable.assert_only_owner();
self.governance.write(governance_address);
Expand Down

0 comments on commit f3d4f0a

Please sign in to comment.