Skip to content

Commit

Permalink
Merge branch 'nhaimerl-add-icrc21-endpoints' into 'master'
Browse files Browse the repository at this point in the history
feat(ICP-Ledger): FI-1176: add icrc21 endpoints

This MR proposes the following changes:
1. Add requests and response types for the [ICRC21](https://github.com/dfinity/wg-identity-authentication/blob/main/topics/ICRC-21/icrc_21_consent_msg.md) standard
2. Add the two endpoints of the ICRC21 standard to the ICP-Ledger canister
3. Add the two endpoints of the ICRC21 standard to the ICP-ledger candid file

The endpoints do not yet serve any functionality. The endpoint `icrc21_canister_call_consent_message` returns an error upon being called and the endpoint `icrc10_supported_standards` is a wrapper call to `icrc1_supported_standards`. The standard will be added to the list of supported standards once it is fully implemented. 

See merge request dfinity-lab/public/ic!19256
  • Loading branch information
NikolasHai committed May 16, 2024
2 parents c633c38 + 039a942 commit 1985ccf
Show file tree
Hide file tree
Showing 7 changed files with 161 additions and 2 deletions.
18 changes: 18 additions & 0 deletions packages/icrc-ledger-types/src/icrc21/errors.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use candid::{CandidType, Deserialize, Nat};
use serde::Serialize;

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

#[derive(Debug, CandidType, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum Icrc21Error {
UnsupportedCanisterCall(ErrorInfo),
ConsentMessageUnavailable(ErrorInfo),
InsufficientPayment(ErrorInfo),
GenericError {
error_code: Nat,
description: String,
},
}
3 changes: 3 additions & 0 deletions packages/icrc-ledger-types/src/icrc21/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub mod errors;
pub mod requests;
pub mod responses;
29 changes: 29 additions & 0 deletions packages/icrc-ledger-types/src/icrc21/requests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use candid::{CandidType, Deserialize};
use serde::Serialize;

#[derive(Debug, CandidType, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct ConsentMessageMetadata {
pub language: String,
}

#[derive(Debug, CandidType, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum DisplayMessageType {
GenericDisplay,
LineDisplay {
characters_per_line: u16,
lines_per_page: u16,
},
}

#[derive(Debug, CandidType, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct ConsentMessageSpec {
pub metadata: ConsentMessageMetadata,
pub device_spec: Option<DisplayMessageType>,
}

#[derive(Debug, CandidType, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct ConsentMessageRequest {
pub method: String,
pub arg: Vec<u8>,
pub user_preferences: ConsentMessageSpec,
}
20 changes: 20 additions & 0 deletions packages/icrc-ledger-types/src/icrc21/responses.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use super::requests::ConsentMessageMetadata;
use candid::{CandidType, Deserialize};
use serde::Serialize;

#[derive(Debug, CandidType, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct Page {
pub lines: Vec<String>,
}

#[derive(Debug, CandidType, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum ConsentMessage {
GenericDisplayMessage(String),
LineDisplayMessage { pages: Vec<Page> },
}

#[derive(Debug, CandidType, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct ConsentInfo {
pub consent_message: ConsentMessage,
pub metadata: ConsentMessageMetadata,
}
1 change: 1 addition & 0 deletions packages/icrc-ledger-types/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pub mod icrc;
pub mod icrc1;
pub mod icrc2;
pub mod icrc21;
pub mod icrc3;
59 changes: 59 additions & 0 deletions rs/rosetta-api/icp_ledger/ledger.did
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,62 @@ type TransferFromError = variant {
GenericError : record { error_code : nat; message : text };
};

type icrc21_consent_message_metadata = record {
language: text;
};

type icrc21_consent_message_spec = record {
metadata: icrc21_consent_message_metadata;
device_spec: opt variant {
GenericDisplay;
LineDisplay: record {
characters_per_line: nat16;
lines_per_page: nat16;
};
};
};

type icrc21_consent_message_request = record {
method: text;
arg: blob;
user_preferences: icrc21_consent_message_spec;
};

type icrc21_consent_message = variant {
GenericDisplayMessage: text;
LineDisplayMessage: record {
pages: vec record {
lines: vec text;
};
};
};

type icrc21_consent_info = record {
consent_message: icrc21_consent_message;
metadata: icrc21_consent_message_metadata;
};

type icrc21_error_info = record {
description: text;
};

type icrc21_error = variant {
UnsupportedCanisterCall: icrc21_error_info;
ConsentMessageUnavailable: icrc21_error_info;
InsufficientPayment: icrc21_error_info;

// Any error not covered by the above variants.
GenericError: record {
error_code: nat;
description: text;
};
};

type icrc21_consent_message_response = variant {
Ok: icrc21_consent_info;
Err: icrc21_error;
};

service: (LedgerCanisterPayload) -> {
// Transfers tokens from a subaccount of the caller to the destination address.
// The source address is computed from the principal of the caller and the specified subaccount.
Expand Down Expand Up @@ -476,4 +532,7 @@ service: (LedgerCanisterPayload) -> {
icrc2_approve : (ApproveArgs) -> (ApproveResult);
icrc2_allowance : (AllowanceArgs) -> (Allowance) query;
icrc2_transfer_from : (TransferFromArgs) -> (TransferFromResult);

icrc21_canister_call_consent_message: (icrc21_consent_message_request) -> (icrc21_consent_message_response);
icrc10_supported_standards : () -> (vec record { name : text; url : text }) query;
}
33 changes: 31 additions & 2 deletions rs/rosetta-api/icp_ledger/ledger/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,6 @@ use icp_ledger::{
TotalSupplyArgs, Transaction, TransferArgs, TransferError, TransferFee, TransferFeeArgs,
MAX_BLOCKS_PER_REQUEST, MEMO_SIZE_BYTES,
};
use icrc_ledger_types::icrc1::transfer::TransferArg;
use icrc_ledger_types::icrc1::transfer::TransferError as Icrc1TransferError;
use icrc_ledger_types::icrc2::allowance::{Allowance, AllowanceArgs};
use icrc_ledger_types::icrc2::approve::{ApproveArgs, ApproveError};
use icrc_ledger_types::{
Expand All @@ -45,6 +43,13 @@ use icrc_ledger_types::{
icrc1::account::Account, icrc2::transfer_from::TransferFromArgs,
icrc2::transfer_from::TransferFromError,
};
use icrc_ledger_types::{
icrc1::transfer::TransferArg,
icrc21::{errors::Icrc21Error, requests::ConsentMessageRequest, responses::ConsentInfo},
};
use icrc_ledger_types::{
icrc1::transfer::TransferError as Icrc1TransferError, icrc21::errors::ErrorInfo,
};
use ledger_canister::{Ledger, LEDGER, MAX_MESSAGE_SIZE_BYTES};
use num_traits::cast::ToPrimitive;
#[allow(unused_imports)]
Expand Down Expand Up @@ -1502,6 +1507,30 @@ fn icrc2_allowance_candid() {
over(candid_one, icrc2_allowance)
}

#[candid_method(update, rename = "icrc21_canister_call_consent_message")]
fn icrc21_canister_call_consent_message(
_request: ConsentMessageRequest,
) -> Result<ConsentInfo, Icrc21Error> {
Err(Icrc21Error::ConsentMessageUnavailable(ErrorInfo {
description: "Consent message is not available".to_string(),
}))
}

#[export_name = "canister_query icrc21_canister_call_consent_message"]
fn icrc21_canister_call_consent_message_candid() {
over(candid_one, icrc21_canister_call_consent_message)
}

#[candid_method(query, rename = "icrc10_supported_standards")]
fn icrc10_supported_standards() -> Vec<StandardRecord> {
icrc1_supported_standards()
}

#[export_name = "canister_query icrc10_supported_standards"]
fn icrc10_supported_standards_candid() {
over(candid_one, |()| icrc10_supported_standards())
}

candid::export_service!();

#[export_name = "canister_query __get_candid_interface_tmp_hack"]
Expand Down

0 comments on commit 1985ccf

Please sign in to comment.