Skip to content

Commit

Permalink
Trusted Issuers Registry
Browse files Browse the repository at this point in the history
  • Loading branch information
EgeCaner committed Dec 13, 2024
1 parent 6f3ce63 commit 6fc4863
Show file tree
Hide file tree
Showing 3 changed files with 243 additions and 44 deletions.
4 changes: 3 additions & 1 deletion crates/registry/src/identity_registry.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,9 @@ pub mod IdentityRegistry {
for trusted_issuer in trusted_issuers {
claim_ids
.append(
poseidon_hash_span(array![trusted_issuer.into(), claim_topic].span()),
poseidon_hash_span(
array![(*trusted_issuer).into(), claim_topic].span(),
),
);
};

Expand Down
42 changes: 7 additions & 35 deletions crates/registry/src/interface/itrusted_issuers_registry.cairo
Original file line number Diff line number Diff line change
@@ -1,33 +1,5 @@
use starknet::ContractAddress;

#[event]
#[derive(Drop, starknet::Event)]
pub enum TrustedIssuersRegistryEvent {
TrustedIssuerAdded: TrustedIssuerAdded,
TrustedIssuerRemoved: TrustedIssuerRemoved,
ClaimTopicsUpdated: ClaimTopicsUpdated,
}

#[derive(Drop, starknet::Event)]
pub struct TrustedIssuerAdded {
#[key]
trusted_issuer: ContractAddress,
claim_topics: Array<felt252>,
}

#[derive(Drop, starknet::Event)]
pub struct TrustedIssuerRemoved {
#[key]
trusted_issuer: ContractAddress,
}

#[derive(Drop, starknet::Event)]
pub struct ClaimTopicsUpdated {
#[key]
trusted_issuer: ContractAddress,
claim_topics: Array<felt252>,
}

#[starknet::interface]
pub trait ITrustedIssuersRegistry<TContractState> {
fn add_trusted_issuer(
Expand All @@ -37,15 +9,15 @@ pub trait ITrustedIssuersRegistry<TContractState> {
fn update_issuer_claim_topics(
ref self: TContractState, trusted_issuer: ContractAddress, claim_topics: Span<felt252>,
);
fn get_trusted_issuers(self: @TContractState) -> Array<ContractAddress>;
fn has_claim_topic(
self: @TContractState, issuer: ContractAddress, claim_topic: felt252,
) -> bool;
fn is_trusted_issuer(self: @TContractState, issuer: ContractAddress) -> bool;
fn get_trusted_issuers(self: @TContractState) -> Span<ContractAddress>;
fn get_trusted_issuers_for_claim_topic(
self: @TContractState, claim_topic: felt252,
) -> Array<ContractAddress>;
fn is_trusted_issuer(self: @TContractState, issuer: ContractAddress) -> bool;
) -> Span<ContractAddress>;
fn get_trusted_issuer_claim_topics(
self: @TContractState, trusted_issuer: ContractAddress,
) -> Array<felt252>;
fn has_claim_topic(
self: @TContractState, issuer: ContractAddress, claim_topic: felt252,
) -> bool;
) -> Span<felt252>;
}
241 changes: 233 additions & 8 deletions crates/registry/src/trusted_issuers_registry.cairo
Original file line number Diff line number Diff line change
@@ -1,14 +1,239 @@
#[starknet::contract]
mod TrustedIssuersRegistry {
//use registry::interface::itrusted_issuers_registry::{ITrustedIssuersRegistry};
//use starknet::ContractAddress;
use core::num::traits::Zero;
use crate::interface::itrusted_issuers_registry::ITrustedIssuersRegistry;
use openzeppelin_access::ownable::OwnableComponent;
use openzeppelin_upgrades::{interface::IUpgradeable, upgradeable::UpgradeableComponent};
use starknet::{
ClassHash, ContractAddress,
storage::{Map, StoragePathEntry, StoragePointerReadAccess, StoragePointerWriteAccess},
};
use storage::storage_array::{
ContractAddressVecToContractAddressArray as ContractAddressVecInto,
Felt252VecToFelt252Array as FeltVecInto, MutableStorageArrayTrait,
StorageArrayContractAddress, StorageArrayFelt252, StorageArrayTrait,
};

component!(path: UpgradeableComponent, storage: upgrades, event: UpgradeableEvent);

impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl<ContractState>;

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

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

#[storage]
struct Storage {}
struct Storage {
trusted_issuers: StorageArrayContractAddress,
trusted_issuer_claim_topics: Map<ContractAddress, StorageArrayFelt252>,
claim_topics_to_trusted_issuers: Map<felt252, StorageArrayContractAddress>,
#[substorage(v0)]
upgrades: UpgradeableComponent::Storage,
#[substorage(v0)]
ownable: OwnableComponent::Storage,
}

#[event]
#[derive(Drop, starknet::Event)]
enum Event {}
//#[abi(embed_v0)]
//impl TrustedIssuersRegistryImpl of ITrustedIssuersRegistry<ContractState>{
//
//}
pub enum Event {
TrustedIssuerAdded: TrustedIssuerAdded,
TrustedIssuerRemoved: TrustedIssuerRemoved,
ClaimTopicsUpdated: ClaimTopicsUpdated,
#[flat]
UpgradeableEvent: UpgradeableComponent::Event,
#[flat]
OwnableEvent: OwnableComponent::Event,
}

#[derive(Drop, starknet::Event)]
pub struct TrustedIssuerAdded {
#[key]
trusted_issuer: ContractAddress,
claim_topics: Span<felt252>,
}

#[derive(Drop, starknet::Event)]
pub struct TrustedIssuerRemoved {
#[key]
trusted_issuer: ContractAddress,
}

#[derive(Drop, starknet::Event)]
pub struct ClaimTopicsUpdated {
#[key]
trusted_issuer: ContractAddress,
claim_topics: Span<felt252>,
}

#[constructor]
fn constructor(ref self: ContractState, owner: ContractAddress) {
self.ownable.initializer(owner);
}

#[abi(embed_v0)]
impl UpgradeableImpl of IUpgradeable<ContractState> {
/// Upgrades the implementation used by this contract.
///
/// # Arguments
///
/// - `new_class_hash` A `ClassHash` representing the implementation to update to.
///
/// # Requirements
///
/// - This function can only be called by the owner.
/// - The `ClassHash` should already have been declared.
fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {
self.ownable.assert_only_owner();
self.upgrades.upgrade(new_class_hash);
}
}

#[abi(embed_v0)]
impl TrustedIssuersRegistryImpl of ITrustedIssuersRegistry<ContractState> {
fn add_trusted_issuer(
ref self: ContractState, trusted_issuer: ContractAddress, claim_topics: Span<felt252>,
) {
self.ownable.assert_only_owner();
assert(trusted_issuer.is_non_zero(), 'Zero Address: Trusted Issuer');
let trusted_issuer_claim_topics_storage_path = self
.trusted_issuer_claim_topics
.entry(trusted_issuer);
assert(
trusted_issuer_claim_topics_storage_path.len().is_zero(),
'Trusted Issuer already exists',
);
let claim_topics_len = claim_topics.len();
assert(claim_topics_len.is_non_zero(), 'Claim topics cannot be empty');
assert(claim_topics_len <= 15, 'Max 15 claim topics');
let trusted_issuers_storage_path = self.trusted_issuers.deref();
assert(trusted_issuers_storage_path.len() < 50, 'Max 50 trusted issuers');
trusted_issuers_storage_path.append().write(trusted_issuer);

for claim_topic in claim_topics {
trusted_issuer_claim_topics_storage_path.append().write(*claim_topic);
self
.claim_topics_to_trusted_issuers
.entry(*claim_topic)
.append()
.write(trusted_issuer);
};

self.emit(TrustedIssuerAdded { trusted_issuer, claim_topics })
}

fn remove_trusted_issuer(ref self: ContractState, trusted_issuer: ContractAddress) {
self.ownable.assert_only_owner();
assert(trusted_issuer.is_non_zero(), 'Zero Address: Trusted Issuer');
let claim_topics_storage_path = self.trusted_issuer_claim_topics.entry(trusted_issuer);
assert(claim_topics_storage_path.len().is_non_zero(), 'Trusted Issuer not exists');

/// Remove from trusted issuers vec
let trusted_issuers_storage_path = self.trusted_issuers.deref();
for i in 0..trusted_issuers_storage_path.len() {
if trusted_issuers_storage_path.at(i).read() == trusted_issuer {
trusted_issuers_storage_path.delete(i);
break;
}
};

/// Clear claim topics to trusted issuers
for i in 0..claim_topics_storage_path.len() {
let claim_topic = claim_topics_storage_path.at(i).read();
let claim_topic_trusted_issuers = self
.claim_topics_to_trusted_issuers
.entry(claim_topic);
for j in 0..claim_topic_trusted_issuers.len() {
let trusted_issuer_at_j = claim_topic_trusted_issuers.at(j).read();
if trusted_issuer_at_j == trusted_issuer {
claim_topic_trusted_issuers.delete(j);
break;
}
};
};

/// Clear trusted issuer claim topics
/// .clear() method leaves the storage dirty and just set len to 0.
self.trusted_issuer_claim_topics.entry(trusted_issuer).clear();
self.emit(TrustedIssuerRemoved { trusted_issuer });
}

/// NOTE: This method first clears all the claim topics and related data then populates
/// again with newer data. inefficient for unchanging data.
fn update_issuer_claim_topics(
ref self: ContractState, trusted_issuer: ContractAddress, claim_topics: Span<felt252>,
) {
self.ownable.assert_only_owner();
assert(trusted_issuer.is_non_zero(), 'Zero Address: Trusted Issuer');
let claim_topics_storage_path = self.trusted_issuer_claim_topics.entry(trusted_issuer);
assert(claim_topics_storage_path.len().is_non_zero(), 'Trusted Issuer not exists');
let claim_topics_len = claim_topics.len();
assert(claim_topics_len.is_non_zero(), 'Claim topics cannot be empty');
assert(claim_topics_len <= 15, 'Max 15 claim topics');

let claim_topics_storage_path = self.trusted_issuer_claim_topics.entry(trusted_issuer);
/// Deletes claim topics to
for i in 0..claim_topics_storage_path.len() {
let claim_topic = claim_topics_storage_path.at(i).read();
let claim_topic_trusted_issuers = self
.claim_topics_to_trusted_issuers
.entry(claim_topic);
for j in 0..claim_topic_trusted_issuers.len() {
if claim_topic_trusted_issuers.at(j).read() == trusted_issuer {
claim_topic_trusted_issuers.delete(i);
break;
}
};
};

claim_topics_storage_path.clear();
/// Update trusted_issuer_claim_topics and claim_topics_to_trusted_issuers
for claim_topic in claim_topics {
claim_topics_storage_path.append().write(*claim_topic);
self
.claim_topics_to_trusted_issuers
.entry(*claim_topic)
.append()
.write(trusted_issuer);
};

self.emit(ClaimTopicsUpdated { trusted_issuer, claim_topics });
}

fn has_claim_topic(
self: @ContractState, issuer: ContractAddress, claim_topic: felt252,
) -> bool {
let mut has_topic = false;
let claim_topics_storage_path = self.trusted_issuer_claim_topics.entry(issuer);
for i in 0..claim_topics_storage_path.len() {
if claim_topics_storage_path.at(i).read() == claim_topic {
has_topic = true;
break;
}
};
has_topic
}

fn is_trusted_issuer(self: @ContractState, issuer: ContractAddress) -> bool {
self.trusted_issuer_claim_topics.entry(issuer).len().is_non_zero()
}

fn get_trusted_issuers(self: @ContractState) -> Span<ContractAddress> {
ContractAddressVecInto::into(self.trusted_issuers.deref()).span()
}

fn get_trusted_issuers_for_claim_topic(
self: @ContractState, claim_topic: felt252,
) -> Span<ContractAddress> {
ContractAddressVecInto::into(self.claim_topics_to_trusted_issuers.entry(claim_topic))
.span()
}

fn get_trusted_issuer_claim_topics(
self: @ContractState, trusted_issuer: ContractAddress,
) -> Span<felt252> {
FeltVecInto::into(self.trusted_issuer_claim_topics.entry(trusted_issuer)).span()
}
}
}

0 comments on commit 6fc4863

Please sign in to comment.