use ave_identity::{DigestIdentifier, PublicKey};
use borsh::{BorshDeserialize, BorshSerialize};
use serde::{Deserialize, Deserializer, Serialize};
use std::collections::BTreeSet;
use crate::{Namespace, SchemaType, ValueWrapper};
#[derive(
Debug,
Clone,
Serialize,
Deserialize,
Eq,
PartialEq,
BorshSerialize,
BorshDeserialize,
)]
pub enum EventRequest {
Create(CreateRequest),
Fact(FactRequest),
Transfer(TransferRequest),
Confirm(ConfirmRequest),
Reject(RejectRequest),
EOL(EOLRequest),
}
impl EventRequest {
pub fn check_request_signature(
&self,
signer: &PublicKey,
owner: &PublicKey,
new_owner: &Option<PublicKey>,
) -> bool {
match self {
Self::Create(..) | Self::Transfer(..) | Self::EOL(..) => {
signer == owner
}
Self::Confirm(..) | Self::Reject(..) => {
new_owner.as_ref() == Some(signer)
}
Self::Fact(..) => true,
}
}
pub const fn is_create_event(&self) -> bool {
matches!(self, Self::Create(_create_request))
}
pub const fn is_fact_event(&self) -> bool {
matches!(self, Self::Fact(_fact_request))
}
pub fn get_subject_id(&self) -> DigestIdentifier {
match self {
Self::Create(_create_request) => DigestIdentifier::default(),
Self::Fact(fact_request) => fact_request.subject_id.clone(),
Self::Transfer(transfer_request) => {
transfer_request.subject_id.clone()
}
Self::Confirm(confirm_request) => {
confirm_request.subject_id.clone()
}
Self::Reject(reject_request) => reject_request.subject_id.clone(),
Self::EOL(eolrequest) => eolrequest.subject_id.clone(),
}
}
}
#[derive(
Debug,
Clone,
Serialize,
Deserialize,
Eq,
PartialEq,
BorshSerialize,
BorshDeserialize,
)]
pub struct CreateRequest {
pub name: Option<String>,
pub description: Option<String>,
pub governance_id: DigestIdentifier,
pub schema_id: SchemaType,
pub namespace: Namespace,
}
#[derive(
Debug,
Clone,
Serialize,
Deserialize,
Eq,
PartialEq,
BorshSerialize,
BorshDeserialize,
)]
pub struct FactRequest {
pub subject_id: DigestIdentifier,
pub payload: ValueWrapper,
#[serde(default)]
#[serde(deserialize_with = "deserialize_unique_viewpoints")]
pub viewpoints: BTreeSet<String>,
}
fn deserialize_unique_viewpoints<'de, D>(
deserializer: D,
) -> Result<BTreeSet<String>, D::Error>
where
D: Deserializer<'de>,
{
let viewpoints =
<Vec<String> as serde::Deserialize>::deserialize(deserializer)?;
let mut unique: BTreeSet<String> = BTreeSet::new();
for viewpoint in viewpoints {
if !unique.insert(viewpoint.clone()) {
return Err(serde::de::Error::custom(format!(
"duplicated viewpoint '{viewpoint}'"
)));
}
}
Ok(unique)
}
#[derive(
Debug,
Clone,
Serialize,
Deserialize,
Eq,
PartialEq,
BorshSerialize,
BorshDeserialize,
)]
pub struct TransferRequest {
pub subject_id: DigestIdentifier,
pub new_owner: PublicKey,
}
#[derive(
Debug,
Clone,
Serialize,
Deserialize,
Eq,
PartialEq,
BorshSerialize,
BorshDeserialize,
)]
pub struct ConfirmRequest {
pub subject_id: DigestIdentifier,
pub name_old_owner: Option<String>,
}
#[derive(
Debug,
Clone,
Serialize,
Deserialize,
Eq,
PartialEq,
BorshSerialize,
BorshDeserialize,
)]
pub struct EOLRequest {
pub subject_id: DigestIdentifier,
}
#[derive(
Debug,
Clone,
Serialize,
Deserialize,
Eq,
PartialEq,
BorshSerialize,
BorshDeserialize,
)]
pub struct RejectRequest {
pub subject_id: DigestIdentifier,
}
#[cfg(test)]
mod tests {
use super::FactRequest;
use ave_identity::DigestIdentifier;
use serde_json::json;
use std::collections::BTreeSet;
#[test]
fn test_fact_request_defaults_missing_viewpoints_to_empty() {
let subject_id = DigestIdentifier::default().to_string();
let request = serde_json::from_value::<FactRequest>(json!({
"subject_id": subject_id,
"payload": { "ModOne": { "data": 1 } }
}))
.unwrap();
assert_eq!(request.viewpoints, BTreeSet::new());
}
#[test]
fn test_fact_request_rejects_duplicated_viewpoints() {
let subject_id = DigestIdentifier::default().to_string();
let error = serde_json::from_value::<FactRequest>(json!({
"subject_id": subject_id,
"payload": { "ModOne": { "data": 1 } },
"viewpoints": ["agua", "agua"]
}))
.unwrap_err();
assert!(error.to_string().contains("duplicated viewpoint"));
}
}