Skip to content

Commit

Permalink
Update consent message error types
Browse files Browse the repository at this point in the history
This updates the ICRC-21 types to be in line with the recent changes
to the draft standard.
  • Loading branch information
Frederik Rothenberger committed Dec 14, 2023
1 parent 15ce096 commit da157bf
Show file tree
Hide file tree
Showing 9 changed files with 69 additions and 90 deletions.
10 changes: 5 additions & 5 deletions demos/vc_issuer/app/generated/vc_issuer_idl.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,12 @@ export const idlFactory = ({ IDL }) => {
'consent_message' : IDL.Text,
'language' : IDL.Text,
});
const Icrc21ErrorInfo = IDL.Record({
'description' : IDL.Text,
'error_code' : IDL.Nat64,
});
const Icrc21ErrorInfo = IDL.Record({ 'description' : IDL.Text });
const Icrc21Error = IDL.Variant({
'GenericError' : Icrc21ErrorInfo,
'GenericError' : IDL.Record({
'description' : IDL.Text,
'error_code' : IDL.Nat,
}),
'UnsupportedCanisterCall' : Icrc21ErrorInfo,
'ConsentMessageUnavailable' : Icrc21ErrorInfo,
});
Expand Down
9 changes: 4 additions & 5 deletions demos/vc_issuer/app/generated/vc_issuer_types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,12 @@ export interface Icrc21ConsentInfo {
export type Icrc21ConsentMessageResponse = { 'Ok' : Icrc21ConsentInfo } |
{ 'Err' : Icrc21Error };
export interface Icrc21ConsentPreferences { 'language' : string }
export type Icrc21Error = { 'GenericError' : Icrc21ErrorInfo } |
export type Icrc21Error = {
'GenericError' : { 'description' : string, 'error_code' : bigint }
} |
{ 'UnsupportedCanisterCall' : Icrc21ErrorInfo } |
{ 'ConsentMessageUnavailable' : Icrc21ErrorInfo };
export interface Icrc21ErrorInfo {
'description' : string,
'error_code' : bigint,
}
export interface Icrc21ErrorInfo { 'description' : string }
export interface Icrc21VcConsentMessageRequest {
'preferences' : Icrc21ConsentPreferences,
'credential_spec' : CredentialSpec,
Expand Down
30 changes: 13 additions & 17 deletions demos/vc_issuer/src/consent_message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ use std::collections::HashMap;
use std::fmt::{Display, Formatter};
use strfmt::strfmt;
use vc_util::issuer_api::{
Icrc21ConsentInfo, Icrc21ConsentMessageResponse, Icrc21ConsentPreferences, Icrc21Error,
Icrc21ErrorInfo,
Icrc21ConsentInfo, Icrc21ConsentPreferences, Icrc21Error, Icrc21ErrorInfo,
};
use SupportedLanguage::{English, German};

Expand Down Expand Up @@ -127,29 +126,26 @@ impl Display for SupportedLanguage {
pub fn get_vc_consent_message(
credential_type: &SupportedCredentialType,
language: &SupportedLanguage,
) -> Icrc21ConsentMessageResponse {
match render_consent_message(credential_type, language) {
Ok(message) => Icrc21ConsentMessageResponse::Ok(Icrc21ConsentInfo {
consent_message: message,
language: format!("{}", language),
}),
Err(err) => Icrc21ConsentMessageResponse::Err(Icrc21Error::GenericError(err)),
}
) -> Result<Icrc21ConsentInfo, Icrc21Error> {
render_consent_message(credential_type, language).map(|message| Icrc21ConsentInfo {
consent_message: message,
language: format!("{}", language),
})
}

fn render_consent_message(
credential: &SupportedCredentialType,
language: &SupportedLanguage,
) -> Result<String, Icrc21ErrorInfo> {
) -> Result<String, Icrc21Error> {
let template = CONSENT_MESSAGE_TEMPLATES
.get(&(CredentialTemplateType::from(credential), language.clone()))
.ok_or(Icrc21ErrorInfo {
error_code: 0,
.ok_or(Icrc21Error::ConsentMessageUnavailable(Icrc21ErrorInfo {
description: "Consent message template not found".to_string(),
})?;
}))?;

strfmt(template, &HashMap::from([credential.to_param_tuple()])).map_err(|e| Icrc21ErrorInfo {
error_code: 0,
description: e.to_string(),
strfmt(template, &HashMap::from([credential.to_param_tuple()])).map_err(|e| {
Icrc21Error::ConsentMessageUnavailable(Icrc21ErrorInfo {
description: e.to_string(),
})
})
}
21 changes: 10 additions & 11 deletions demos/vc_issuer/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ use std::borrow::Cow;
use std::cell::RefCell;
use std::collections::HashSet;
use vc_util::issuer_api::{
ArgumentValue, CredentialSpec, GetCredentialRequest, GetCredentialResponse,
Icrc21ConsentMessageResponse, Icrc21Error, Icrc21ErrorInfo, Icrc21VcConsentMessageRequest,
IssueCredentialError, IssuedCredentialData, PrepareCredentialRequest,
PrepareCredentialResponse, PreparedCredentialData, SignedIdAlias,
ArgumentValue, CredentialSpec, GetCredentialRequest, GetCredentialResponse, Icrc21ConsentInfo,
Icrc21Error, Icrc21ErrorInfo, Icrc21VcConsentMessageRequest, IssueCredentialError,
IssuedCredentialData, PrepareCredentialRequest, PrepareCredentialResponse,
PreparedCredentialData, SignedIdAlias,
};
use vc_util::{
did_for_principal, get_verified_id_alias_from_jws, vc_jwt_to_jws, vc_signing_input,
Expand Down Expand Up @@ -291,16 +291,15 @@ fn get_credential(req: GetCredentialRequest) -> GetCredentialResponse {

#[update]
#[candid_method]
async fn vc_consent_message(req: Icrc21VcConsentMessageRequest) -> Icrc21ConsentMessageResponse {
async fn vc_consent_message(
req: Icrc21VcConsentMessageRequest,
) -> Result<Icrc21ConsentInfo, Icrc21Error> {
let credential_type = match verify_credential_spec(&req.credential_spec) {
Ok(credential_type) => credential_type,
Err(err) => {
return Icrc21ConsentMessageResponse::Err(Icrc21Error::UnsupportedCanisterCall(
Icrc21ErrorInfo {
error_code: 0,
description: err,
},
));
return Err(Icrc21Error::UnsupportedCanisterCall(Icrc21ErrorInfo {
description: err,
}));
}
};
get_vc_consent_message(&credential_type, &SupportedLanguage::from(req.preferences))
Expand Down
50 changes: 20 additions & 30 deletions demos/vc_issuer/tests/issue_credential.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,8 @@ use std::path::PathBuf;
use std::time::{Duration, UNIX_EPOCH};
use vc_util::issuer_api::{
ArgumentValue, CredentialSpec, GetCredentialRequest, GetCredentialResponse,
Icrc21ConsentMessageResponse, Icrc21ConsentPreferences, Icrc21Error,
Icrc21VcConsentMessageRequest, IssueCredentialError, PrepareCredentialRequest,
PrepareCredentialResponse, SignedIdAlias as SignedIssuerIdAlias,
Icrc21ConsentPreferences, Icrc21Error, Icrc21VcConsentMessageRequest, IssueCredentialError,
PrepareCredentialRequest, PrepareCredentialResponse, SignedIdAlias as SignedIssuerIdAlias,
};
use vc_util::{
did_for_principal, get_verified_id_alias_from_jws, verify_credential_jws_with_canister_id,
Expand Down Expand Up @@ -92,6 +91,7 @@ pub fn install_issuer(env: &StateMachine, init: &IssuerInit) -> CanisterId {

mod api {
use super::*;
use vc_util::issuer_api::Icrc21ConsentInfo;

pub fn configure(
env: &StateMachine,
Expand All @@ -106,7 +106,7 @@ mod api {
canister_id: CanisterId,
sender: Principal,
consent_message_request: &Icrc21VcConsentMessageRequest,
) -> Result<Option<Icrc21ConsentMessageResponse>, CallError> {
) -> Result<Result<Icrc21ConsentInfo, Icrc21Error>, CallError> {
call_candid_as(
env,
canister_id,
Expand Down Expand Up @@ -204,11 +204,12 @@ fn should_return_vc_consent_message_for_employment_vc() {
let response =
api::vc_consent_message(&env, canister_id, principal_1(), &consent_message_request)
.expect("API call failed")
.expect("Got 'None' from vc_consent_message");
.expect("Consent message error");

match_value!(response, Icrc21ConsentMessageResponse::Ok(info));
assert_eq!(info.language, actual_language);
assert!(info.consent_message.starts_with(consent_message_snippet));
assert_eq!(response.language, actual_language);
assert!(response
.consent_message
.starts_with(consent_message_snippet));
}
}

Expand Down Expand Up @@ -238,10 +239,11 @@ fn should_return_vc_consent_message_for_adult_vc() {
let response =
api::vc_consent_message(&env, canister_id, principal_1(), &consent_message_request)
.expect("API call failed")
.expect("Got 'None' from vc_consent_message");
match_value!(response, Icrc21ConsentMessageResponse::Ok(info));
assert_eq!(info.language, actual_language);
assert!(info.consent_message.starts_with(consent_message_snippet));
.expect("Consent message error");
assert_eq!(response.language, actual_language);
assert!(response
.consent_message
.starts_with(consent_message_snippet));
}
}

Expand All @@ -262,12 +264,8 @@ fn should_fail_vc_consent_message_if_not_supported() {

let response =
api::vc_consent_message(&env, canister_id, principal_1(), &consent_message_request)
.expect("API call failed")
.expect("Got 'None' from vc_consent_message");
assert_matches!(
response,
Icrc21ConsentMessageResponse::Err(Icrc21Error::UnsupportedCanisterCall(_))
);
.expect("API call failed");
assert_matches!(response, Err(Icrc21Error::UnsupportedCanisterCall(_)));
}

#[test]
Expand All @@ -287,12 +285,8 @@ fn should_fail_vc_consent_message_if_missing_arguments() {

let response =
api::vc_consent_message(&env, canister_id, principal_1(), &consent_message_request)
.expect("API call failed")
.expect("Got 'None' from vc_consent_message");
assert_matches!(
response,
Icrc21ConsentMessageResponse::Err(Icrc21Error::UnsupportedCanisterCall(_))
);
.expect("API call failed");
assert_matches!(response, Err(Icrc21Error::UnsupportedCanisterCall(_)));
}

#[test]
Expand All @@ -315,12 +309,8 @@ fn should_fail_vc_consent_message_if_missing_required_argument() {

let response =
api::vc_consent_message(&env, canister_id, principal_1(), &consent_message_request)
.expect("API call failed")
.expect("Got 'None' from vc_consent_message");
assert_matches!(
response,
Icrc21ConsentMessageResponse::Err(Icrc21Error::UnsupportedCanisterCall(_))
);
.expect("API call failed");
assert_matches!(response, Err(Icrc21Error::UnsupportedCanisterCall(_)));
}

fn employee_credential_spec() -> CredentialSpec {
Expand Down
6 changes: 3 additions & 3 deletions demos/vc_issuer/vc_demo_issuer.did
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ type Icrc21ConsentMessageResponse = variant {
};
type Icrc21ConsentPreferences = record { language : text };
type Icrc21Error = variant {
GenericError : Icrc21ErrorInfo;
GenericError : record { description : text; error_code : nat };
UnsupportedCanisterCall : Icrc21ErrorInfo;
ConsentMessageUnavailable : Icrc21ErrorInfo;
ConsentMessageUnavailable : Icrc21ErrorInfo
};
type Icrc21ErrorInfo = record { description : text; error_code : nat64 };
type Icrc21ErrorInfo = record { description : text };
type Icrc21VcConsentMessageRequest = record {
preferences : Icrc21ConsentPreferences;
credential_spec : CredentialSpec;
Expand Down
10 changes: 5 additions & 5 deletions src/frontend/generated/vc_issuer_idl.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,12 @@ export const idlFactory = ({ IDL }) => {
'consent_message' : IDL.Text,
'language' : IDL.Text,
});
const Icrc21ErrorInfo = IDL.Record({
'description' : IDL.Text,
'error_code' : IDL.Nat64,
});
const Icrc21ErrorInfo = IDL.Record({ 'description' : IDL.Text });
const Icrc21Error = IDL.Variant({
'GenericError' : Icrc21ErrorInfo,
'GenericError' : IDL.Record({
'description' : IDL.Text,
'error_code' : IDL.Nat,
}),
'UnsupportedCanisterCall' : Icrc21ErrorInfo,
'ConsentMessageUnavailable' : Icrc21ErrorInfo,
});
Expand Down
9 changes: 4 additions & 5 deletions src/frontend/generated/vc_issuer_types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,12 @@ export interface Icrc21ConsentInfo {
export type Icrc21ConsentMessageResponse = { 'Ok' : Icrc21ConsentInfo } |
{ 'Err' : Icrc21Error };
export interface Icrc21ConsentPreferences { 'language' : string }
export type Icrc21Error = { 'GenericError' : Icrc21ErrorInfo } |
export type Icrc21Error = {
'GenericError' : { 'description' : string, 'error_code' : bigint }
} |
{ 'UnsupportedCanisterCall' : Icrc21ErrorInfo } |
{ 'ConsentMessageUnavailable' : Icrc21ErrorInfo };
export interface Icrc21ErrorInfo {
'description' : string,
'error_code' : bigint,
}
export interface Icrc21ErrorInfo { 'description' : string }
export interface Icrc21VcConsentMessageRequest {
'preferences' : Icrc21ConsentPreferences,
'credential_spec' : CredentialSpec,
Expand Down
14 changes: 5 additions & 9 deletions src/vc_util/src/issuer_api.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use candid::{CandidType, Deserialize};
use candid::{CandidType, Deserialize, Nat};
use serde_bytes::ByteBuf;
use std::collections::HashMap;
use std::fmt::{Display, Formatter};
Expand Down Expand Up @@ -101,15 +101,17 @@ pub struct Icrc21ConsentPreferences {

#[derive(Clone, Debug, CandidType, Deserialize, Eq, PartialEq)]
pub struct Icrc21ErrorInfo {
pub error_code: u64,
pub description: String,
}

#[derive(Clone, Debug, CandidType, Deserialize, Eq, PartialEq)]
pub enum Icrc21Error {
UnsupportedCanisterCall(Icrc21ErrorInfo),
ConsentMessageUnavailable(Icrc21ErrorInfo),
GenericError(Icrc21ErrorInfo),
GenericError {
error_code: Nat,
description: String,
},
}

#[derive(Clone, Debug, CandidType, Deserialize, Eq, PartialEq)]
Expand All @@ -118,12 +120,6 @@ pub struct Icrc21ConsentInfo {
pub language: String,
}

#[derive(Clone, Debug, CandidType, Deserialize, Eq, PartialEq)]
pub enum Icrc21ConsentMessageResponse {
Ok(Icrc21ConsentInfo),
Err(Icrc21Error),
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down

0 comments on commit da157bf

Please sign in to comment.