concordium_base/
cis4_types.rs

1pub use crate::cis2_types::MetadataUrl;
2use crate::{
3    contracts_common::{self, self as concordium_std},
4    web3id::*,
5};
6
7/// Credential type is a string that corresponds to the value of the "name"
8/// attribute of the credential schema.
9#[derive(
10    contracts_common::Serialize, PartialEq, Eq, Clone, Debug, serde::Serialize, serde::Deserialize,
11)]
12#[serde(transparent)]
13pub struct CredentialType {
14    #[concordium(size_length = 1)]
15    pub credential_type: String,
16}
17
18// TODO: make field above private, add TryFrom/Into instances
19
20/// A schema reference is a schema URL pointing to the JSON
21/// schema for a verifiable credential.
22#[derive(
23    contracts_common::Serialize, PartialEq, Eq, Clone, Debug, serde::Serialize, serde::Deserialize,
24)]
25#[serde(transparent)]
26pub struct SchemaRef {
27    pub schema_ref: MetadataUrl,
28}
29
30#[derive(
31    serde::Serialize, serde::Deserialize, contracts_common::Serialize, PartialEq, Eq, Clone, Debug,
32)]
33#[serde(rename_all = "camelCase")]
34pub struct CredentialInfo {
35    /// The holder's identifier.
36    pub holder_id: CredentialHolderId,
37    /// Whether the holder is allowed to revoke the credential or not.
38    pub holder_revocable: bool,
39    /// The date from which the credential is considered valid.
40    pub valid_from: contracts_common::Timestamp,
41    /// After this date, the credential becomes expired. `None` corresponds to a
42    /// credential that cannot expire.
43    pub valid_until: Option<contracts_common::Timestamp>,
44    /// Metadata URL of the credential.
45    pub metadata_url: MetadataUrl,
46}
47
48/// Response to a credential data query.
49#[derive(serde::Serialize, serde::Deserialize, contracts_common::Serialize, Clone, Debug)]
50#[serde(rename_all = "camelCase")]
51pub struct CredentialEntry {
52    pub credential_info: CredentialInfo,
53    /// A schema URL or DID address pointing to the JSON schema for a verifiable
54    /// credential.
55    pub schema_ref: SchemaRef,
56    /// The nonce is used to avoid replay attacks when checking the holder's
57    /// signature on a revocation message. This is the nonce that should be used
58    /// when signing a revocation.
59    pub revocation_nonce: u64,
60}
61
62#[derive(
63    serde::Serialize,
64    serde::Deserialize,
65    contracts_common::Serialize,
66    PartialOrd,
67    Ord,
68    Hash,
69    PartialEq,
70    Eq,
71    Clone,
72    Copy,
73    Debug,
74    derive_more::Display,
75)]
76#[serde(rename_all = "camelCase")]
77/// The current status of a credential.
78pub enum CredentialStatus {
79    /// The credential is active.
80    #[display(fmt = "Active")]
81    Active,
82    /// The credential has been revoked.
83    #[display(fmt = "Revoked")]
84    Revoked,
85    /// The credential validity has expired.
86    #[display(fmt = "Expired")]
87    Expired,
88    /// The credential is not yet valid, that is, it is before the valid period.
89    #[display(fmt = "NotActivated")]
90    NotActivated,
91}
92
93#[doc(hidden)]
94pub enum RevocationKeyRole {}
95
96pub type RevocationKey = Ed25519PublicKey<RevocationKeyRole>;
97
98#[derive(contracts_common::Serialize, Debug)]
99/// Revocation key together with a nonce that needs to be used for signing the
100/// next revocation transaction.
101pub struct RevocationKeyWithNonce {
102    pub key: RevocationKey,
103    pub nonce: u64,
104}
105
106/// A response type for the registry metadata request.
107#[derive(contracts_common::Serialize, Debug, Clone)]
108pub struct RegistryMetadata {
109    /// A reference to the issuer's metadata.
110    pub issuer_metadata: MetadataUrl,
111    /// The type of credentials used.
112    pub credential_type: CredentialType,
113    /// A reference to the JSON schema corresponding to this type.
114    pub credential_schema: SchemaRef,
115}
116
117#[doc(hidden)]
118pub enum IssuerKeyRole {}
119
120/// Public key of an issuer.
121pub type IssuerKey = Ed25519PublicKey<IssuerKeyRole>;
122
123/// Data for events of registering and updating a credential.
124#[derive(contracts_common::Serialize, Debug, Clone)]
125pub struct CredentialEventData {
126    /// A public key of the credential's holder.
127    pub holder_id: CredentialHolderId,
128    /// A reference to the credential JSON schema.
129    pub schema_ref: SchemaRef,
130    /// Type of the credential.
131    pub credential_type: CredentialType,
132    /// The metadata URL of the newly registered credential.
133    pub metadata_url: MetadataUrl,
134}
135
136/// A type for specifying who is revoking a credential, when registering a
137/// revocation event.
138#[derive(contracts_common::Serialize, Debug, Clone)]
139pub enum Revoker {
140    Issuer,
141    Holder,
142    /// `Other` is used for the cases when the revoker is not the issuer or
143    /// holder. In this contract it is a revocation authority, which is
144    /// identified using ther public key.
145    Other(RevocationKey),
146}
147
148/// An untagged revocation event.
149#[derive(contracts_common::Serialize, Debug, Clone)]
150pub struct RevokeCredentialEvent {
151    /// A public key of the credential's holder.
152    pub holder_id: CredentialHolderId,
153    /// Who revokes the credential.
154    pub revoker: Revoker,
155    /// An optional text clarifying the revocation reasons.
156    /// The issuer can use this field to comment on the revocation, so the
157    /// holder can observe it in the wallet.
158    pub reason: Option<Reason>,
159}
160
161#[derive(Debug, contracts_common::Serialize, Clone)]
162/// An event emitted when the issuer metadata is set, either
163/// initially or when it is updated.
164pub struct IssuerMetadataEvent {
165    /// The location of the metadata.
166    pub metadata_url: MetadataUrl,
167}
168
169/// The schema reference has been updated for the credential type.
170#[derive(contracts_common::Serialize, Debug, Clone)]
171pub struct CredentialSchemaRefEvent {
172    pub r#type: CredentialType,
173    pub schema_ref: SchemaRef,
174}
175
176#[derive(Debug, Clone, contracts_common::Serialize)]
177pub struct CredentialMetadataEvent {
178    pub credential_id: CredentialHolderId,
179    pub metadata_url: MetadataUrl,
180}
181
182#[derive(contracts_common::Serialize, Debug, Clone)]
183pub enum RevocationKeyAction {
184    Register,
185    Remove,
186}
187
188/// An untagged revocation key event.
189/// Emitted when keys are registered and removed.
190/// For a tagged version use `CredentialEvent`.
191#[derive(contracts_common::Serialize, Debug, Clone)]
192pub struct RevocationKeyEvent {
193    /// The public key that is registered/removed
194    pub key: RevocationKey,
195    /// A register/remove action.
196    pub action: RevocationKeyAction,
197}
198
199/// An event specified by CIS4 standard.
200#[derive(Debug, Clone)]
201pub enum CredentialEvent {
202    /// Credential registration event. Logged when an entry in the registry is
203    /// created for the first time.
204    Register(CredentialEventData),
205    /// Credential revocation event.
206    Revoke(RevokeCredentialEvent),
207    /// Issuer's metadata changes, including the contract deployment.
208    IssuerMetadata(MetadataUrl),
209    /// Credential's metadata changes.
210    CredentialMetadata(CredentialMetadataEvent),
211    /// Credential's schema changes.
212    Schema(CredentialSchemaRefEvent),
213    /// Revocation key changes
214    RevocationKey(RevocationKeyEvent),
215    /// Event is not part of the CIS4 specification.
216    Unknown,
217}
218
219impl contracts_common::Deserial for CredentialEvent {
220    fn deserial<R: contracts_common::Read>(source: &mut R) -> contracts_common::ParseResult<Self> {
221        use contracts_common::Get;
222        match source.get()? {
223            249u8 => Ok(Self::Register(source.get()?)),
224            248u8 => Ok(Self::Revoke(source.get()?)),
225            247u8 => Ok(Self::IssuerMetadata(source.get()?)),
226            246u8 => Ok(Self::CredentialMetadata(source.get()?)),
227            245u8 => Ok(Self::Schema(source.get()?)),
228            244u8 => Ok(Self::RevocationKey(source.get()?)),
229            _ => Ok(Self::Unknown),
230        }
231    }
232}
233
234/// Attempt to convert the event to a [`CredentialEvent`]. Return [`None`] in
235/// case the event is not one specified by a CIS4 standard.
236impl<'a> TryFrom<&'a crate::smart_contracts::ContractEvent> for CredentialEvent {
237    type Error = crate::contracts_common::ParseError;
238
239    fn try_from(value: &'a crate::smart_contracts::ContractEvent) -> Result<Self, Self::Error> {
240        use crate::contracts_common::Get;
241        let data = value.as_ref();
242        let mut cursor = crate::contracts_common::Cursor::new(data);
243        let event = cursor.get()?;
244        // In case of a recognized event make sure that all of the input was consumed.
245        if cursor.offset == data.len() || matches!(event, CredentialEvent::Unknown) {
246            Ok(event)
247        } else {
248            Err(crate::contracts_common::ParseError {})
249        }
250    }
251}
252
253/// A short comment on a reason of revoking or restoring a credential.
254/// The string is of a limited size of 256 bytes in order to fit into a single
255/// log entry along with other data.
256#[derive(contracts_common::Serialize, Clone, Debug)]
257pub struct Reason {
258    #[concordium(size_length = 1)]
259    reason: String,
260}