Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
173 changes: 173 additions & 0 deletions ICRCs/ICRC-21/ICRC-21.did
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
// Canister interface specification for ICRC-21.
// See https://github.com/dfinity/wg-identity-authentication/blob/main/topics/ICRC-21/icrc_21_consent_msg.md

type icrc21_consent_message_metadata = record {
// BCP-47 language tag. See https://www.rfc-editor.org/rfc/bcp/bcp47.txt
language: text;

// The users local timezone offset in minutes from UTC.
// Applicable when converting timestamps to human-readable format.
//
// If absent in the request, the canister should fallback to the UTC timezone when creating the consent message.
// If absent in the response, the canister is indicating that the consent message is not timezone sensitive.
utc_offset_minutes: opt int16;
};

type icrc21_consent_message_spec = record {
// Metadata of the consent message.
metadata: icrc21_consent_message_metadata;

// Information about the device responsible for presenting the consent message to the user.
// If absent in the request, the canister should fallback to one of the values defined in this spec (ICRC-21).
device_spec: opt variant {
// A generic display able to handle large documents and do line wrapping and pagination / scrolling.
// Text must be Markdown formatted, no external resources (e.g. images) are allowed.
GenericDisplay;
// A simple display able to handle multiple fields with a title and content.
// It's able to do line wrapping and splits fields into multiple pages if they're too long.
// Text must be plain text without any embedded formatting elements.
FieldsDisplay;
};
};

type icrc21_consent_message_request = record {
// Method name of the canister call.
method: text;
// Argument of the canister call.
arg: blob;
// User preferences with regards to the consent message presented to the end-user.
user_preferences: icrc21_consent_message_spec;
};

type TokenAmount = record {
decimals: nat8;
amount: nat64;
symbol: text;
};

type TimestampSeconds = record {
amount: nat64;
};

type DurationSeconds = record {
amount: nat64;
};

type TextValue = record {
content: text;
};

type Value = variant {
TokenAmount: TokenAmount;
TimestampSeconds: TimestampSeconds;
DurationSeconds: DurationSeconds;
Text: TextValue;
};

type icrc21_consent_message = variant {
// Message for a generic display able to handle large documents and do proper line wrapping and pagination / scrolling.
// Uses Markdown formatting, no external resources (e.g. images) are allowed.
GenericDisplayMessage: text;
// Message for a simple display able to handle multiple fields title and content.
// It's able to do line wrapping and splits fields into multiple pages if they're too long.
// Uses plain text, without any embedded formatting elements.
FieldsDisplayMessage: record {
// Context and type of canister call, accurate and concise e.g. Send ICP
intent: text;
// Canister call fields for review e.g. Amount 234.73 ICP
fields: vec record { text; Value };
};
};

type icrc21_consent_info = record {
// Consent message describing in a human-readable format what the call will do.
//
// The message should adhere as close as possible to the user_preferences specified in the consent_message_spec
// of the icrc21_consent_message_request.
// If the message is not available for the given user_preferences any fallback message should be used. Providing a
// message should be preferred over sending an icrc21_error.
// The metadata must match the consent_message provided.
//
// The message should be short and concise.
// It should only contain information that is:
// * relevant to the user
// * relevant given the canister call argument
//
// The message must fit the following context shown to
// the user on the signer UI:
// ┌─────────────────────────────────┐
// │ Approve the following action? │
// │ ┌───────────────────────────┐ │
// │ │ <consent_message> │ │
// │ └───────────────────────────┘ │
// │ ┌───────────┐ ┌───────────┐ │
// │ │ Reject │ │ Approve │ │
// │ └───────────┘ └───────────┘ │
// └─────────────────────────────────┘
consent_message: icrc21_consent_message;
// Metadata of the consent_message.
metadata: icrc21_consent_message_metadata;
};

type icrc21_error_info = record {
// Human readable technical description of the error intended for developers, not the end-user.
description: text;
};

type icrc21_error = variant {
// The canister does not support this call (i.e. it will lead to a rejection or error response).
// Reasons might be (non-exhaustive list):
// * the canister call is malformed (e.g. wrong method name, argument cannot be decoded)
// * the arguments exceed certain bounds
//
// The developer should provide more information about the error using the description in icrc21_error_info.
UnsupportedCanisterCall: icrc21_error_info;

// The canister cannot produce a consent message for this call.
// Reasons might be (non-exhaustive list):
// * it is an internal call not intended for end-users
// * the canister developer has not yet implemented a consent message for this call
//
// The developer should provide more information about the error using the description in icrc21_error_info.
ConsentMessageUnavailable: icrc21_error_info;

// The canister did not provide a consent message for because payment was missing or insufficient.
//
// This error is used to account for payment extensions to be added in the future:
// While small consent messages are easy and cheap to provide, this might not generally be the case for all consent
// messages. To avoid future breaking changes, when introducing a payment flow, this error is already introduced
// even though there no standardized payment flow yet.
InsufficientPayment: icrc21_error_info;

// Any error not covered by the above variants.
GenericError: record {
// Machine parsable error. Can be chosen by the target canister but should indicate the error category.
error_code: nat;
// Human readable technical description of the error intended for developers, not the end-user.
description: text;
};
};

type icrc21_consent_message_response = variant {
// The call is ok, consent message is provided.
Ok: icrc21_consent_info;
// The call is not ok, error is provided.
Err: icrc21_error;
};

service : {
// Returns a human-readable consent message for the given canister call.
//
// This call must not require authentication (i.e. must be available for the anonymous sender).
// If the call is made with a non-anonymous identity, the response may be tailored to the identity.
//
// This is currently an update call. As soon as secure (replicated) query calls are available, this will be changed to such a replicated query call.
icrc21_canister_call_consent_message: (icrc21_consent_message_request) -> (icrc21_consent_message_response);

// Returns a list of supported standards that this canister implements.
// The result must include an entry for ICRC-21:
// record { name = "ICRC-21"; url = "https://github.com/dfinity/ICRC/blob/main/ICRCs/ICRC-21/ICRC-21.md" }
//
// See ICRC-10 for more information: https://github.com/dfinity/ICRC/blob/main/ICRCs/ICRC-10/ICRC-10.md
icrc10_supported_standards : () -> (vec record { name : text; url : text }) query;
}
Loading
Loading