commit a4f2424c65d2fa67b2c69549d9b9a7b3c60152ce
parent e8f307fe6911fdb53793e21168618c63b88b435e
Author: Christian Blättler <blatc2@bfh.ch>
Date: Fri, 15 Mar 2024 09:46:48 +0100
Merge branch 'feature/tokens'
Diffstat:
2 files changed, 273 insertions(+), 35 deletions(-)
diff --git a/core/api-merchant.rst b/core/api-merchant.rst
@@ -3127,7 +3127,7 @@ Adding webhooks
The creation of the webhook is successsful.
:http:statuscode:`404 Not found`:
- The merchant instance is unknowm or it not in our data.
+ The merchant instance is unknown or it not in our data.
.. ts:def:: WebhookAddDetails
@@ -3288,6 +3288,242 @@ Removing webhook
+----------------------------------------
+Token Families: Subscriptions, Discounts
+----------------------------------------
+
+This API provides functionalities for the issuance, management, and revocation
+of token families. Tokens facilitate the implementation of subscriptions and
+discounts, engaging solely the merchant and the user. Each token family
+encapsulates details pertaining to its respective tokens, guiding the merchant's
+backend on the appropriate processing and handling.
+
+
+Creating token families
+-----------------------
+
+.. http:post:: [/instances/$INSTANCES]/private/tokenfamilies
+
+ This is used to create a token family.
+
+ **Request:**
+
+ The request must be a `TokenFamilyCreateRequest`.
+
+ **Response:**
+
+ :http:statuscode:`204 No content`:
+ The token family was created successfully.
+
+ :http:statuscode:`404 Not found`:
+ The merchant backend is unaware of the instance.
+
+ .. ts:def:: TokenFamilyCreateRequest
+
+ interface TokenFamilyCreateRequest {
+
+ // Identifier for the token family consisting of unreserved characters
+ // according to RFC 3986.
+ slug: string;
+
+ // Human-readable name for the token family.
+ name: string;
+
+ // Human-readable description for the token family.
+ description: string;
+
+ // Optional map from IETF BCP 47 language tags to localized descriptions.
+ description_i18n?: { [lang_tag: string]: string };
+
+ // Start time of the token family's validity period.
+ // If not specified, merchant backend will use the current time.
+ valid_after?: Timestamp;
+
+ // End time of the token family's validity period.
+ valid_before: Timestamp;
+
+ // Validity duration of an issued token.
+ duration: RelativeTime;
+
+ // Kind of the token family.
+ kind: TokenFamilyKind;
+
+ }
+
+ .. ts:def:: TokenFamilyKind
+
+ enum TokenFamilyKind {
+ Discount = "discount",
+ Subscription = "subscription",
+ }
+
+
+Updating token families
+-----------------------
+
+.. http:patch:: [/instances/$INSTANCES]/private/tokenfamilies/$TOKEN_FAMILY_SLUG
+
+ This is used to update a token family.
+
+ **Request:**
+
+ The request must be a `TokenFamilyUpdateRequest`.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The token family was successsful updated. Returns a `TokenFamilyDetails`.
+
+ :http:statuscode:`404 Not found`:
+ The merchant backend is unaware of the token family or instance.
+
+ .. ts:def:: TokenFamilyUpdateRequest
+
+ interface TokenFamilyUpdateRequest {
+
+ // Human-readable name for the token family.
+ name: string;
+
+ // Human-readable description for the token family.
+ description: string;
+
+ // Optional map from IETF BCP 47 language tags to localized descriptions.
+ description_i18n: { [lang_tag: string]: string };
+
+ // Start time of the token family's validity period.
+ valid_after: Timestamp;
+
+ // End time of the token family's validity period.
+ valid_before: Timestamp;
+
+ // Validity duration of an issued token.
+ duration: RelativeTime;
+
+ }
+
+
+
+Inspecting token families
+-------------------------
+
+.. http:get:: [/instances/$INSTANCES]/private/tokenfamilies
+
+ This is used to list all configured token families for an instance.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The merchant backend has successfully returned all token families.
+ Returns a `TokenFamiliesList`.
+
+ :http:statuscode:`404 Not found`:
+ The merchant backend is unaware of the instance.
+
+ .. ts:def:: TokenFamiliesList
+
+ // TODO: Add pagination
+
+ interface TokenFamiliesList {
+
+ // All configured token families of this instance.
+ token_families: TokenFamilySummary[];
+
+ }
+
+ .. ts:def:: TokenFamilySummary
+
+ interface TokenFamilySummary {
+ // Identifier for the token family consisting of unreserved characters
+ // according to RFC 3986.
+ slug: string;
+
+ // Human-readable name for the token family.
+ name: string;
+
+ // Start time of the token family's validity period.
+ valid_after: Timestamp;
+
+ // End time of the token family's validity period.
+ valid_before: Timestamp;
+
+ // Kind of the token family.
+ kind: TokenFamilyKind;
+ }
+
+
+.. http:get:: [/instances/$INSTANCES]/private/tokenfamilies/$TOKEN_FAMILY_SLUG
+
+ This is used to get detailed information about a specific token family.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The merchant backend has successfully returned the detailed information
+ about a specific token family. Returns a `TokenFamilyDetails`.
+
+ :http:statuscode:`404 Not found`:
+ The merchant backend is unaware of the token family or instance.
+
+
+ The `TokenFamilyDetails` object describes a configured token family.
+
+ .. ts:def:: TokenFamilyDetails
+
+ interface TokenFamilyDetails {
+
+ // Identifier for the token family consisting of unreserved characters
+ // according to RFC 3986.
+ slug: string;
+
+ // Human-readable name for the token family.
+ name: string;
+
+ // Human-readable description for the token family.
+ description: string;
+
+ // Optional map from IETF BCP 47 language tags to localized descriptions.
+ description_i18n?: { [lang_tag: string]: string };
+
+ // Start time of the token family's validity period.
+ valid_after: Timestamp;
+
+ // End time of the token family's validity period.
+ valid_before: Timestamp;
+
+ // Validity duration of an issued token.
+ duration: RelativeTime;
+
+ // Kind of the token family.
+ kind: TokenFamilyKind;
+
+ // How many tokens have been issued for this family.
+ issued: Integer;
+
+ // How many tokens have been redeemed for this family.
+ redeemed: Integer;
+
+ }
+
+
+
+Deleting token families
+-----------------------
+
+.. http:delete:: [/instances/$INSTANCES]/private/tokenfamilies/$TOKEN_FAMILY_SLUG
+
+ This is used to delete a token family. Issued tokens of this family will not
+ be spendable anymore.
+
+ **Response:**
+
+ :http:statuscode:`204 No content`:
+ The backend has successfully deleted the token family.
+
+ :http:statuscode:`404 Not found`:
+ The merchant backend is unaware of the token family or instance.
+
+
+
------------------
The Contract Terms
------------------
diff --git a/design-documents/046-mumimo-contracts.rst b/design-documents/046-mumimo-contracts.rst
@@ -62,8 +62,6 @@ We want Taler to support various interesting use-cases:
acquired (i.e., not brought from home or stolen from a stack of dirty items)
and incentivizes return after use.
-TODO: add more use-cases here!
-
Proposed Solution
=================
@@ -190,7 +188,7 @@ The contract terms v1 will have the following structure:
extra?: any;
// Fee limits and wire account details by currency.
- limits: { [currency:string] : CurrencyLimit };
+ limits: { [currency: string]: CurrencyLimit };
}
.. ts:def:: CurrencyLimit
@@ -212,7 +210,7 @@ The contract terms v1 will have the following structure:
// Maximum wire fee accepted by the merchant (customer share to be
// divided by the ``wire_fee_amortization`` factor, and further reduced
// if deposit fees are below ``max_fee``). Default if missing is zero.
- max_wire_fee: Amount;
+ max_wire_fee?: Amount;
// Over how many customer transactions does the merchant expect to
// amortize wire fees on average? If the exchange's wire fee is
@@ -222,7 +220,7 @@ The contract terms v1 will have the following structure:
// between the ``max_fee`` and the sum of the actual deposit fees.
// Optional, default value if missing is 1. 0 and negative values are
// invalid and also interpreted as 1.
- wire_fee_amortization: number;
+ wire_fee_amortization?: number;
// Exchanges that the merchant accepts for this currency.
exchanges: Exchange[];
@@ -271,15 +269,15 @@ The contract terms v1 will have the following structure:
// Map from authority labels to meta data abou the
// respective token authority.
- token_types: { [authority_label: TokenAuthority };
+ token_types: { [authority_label: string]: TokenAuthority };
}
.. ts:def:: ContractInput
type ContractInput =
- | ContractInputRation
- | ContractInputToken;
+ ContractInputRation |
+ ContractInputToken;
.. ts:def:: ContractInputRation
@@ -305,9 +303,9 @@ The contract terms v1 will have the following structure:
type: "token";
- // Hash over the public key used to sign the
- // type of subscription token required.
- h_issuer: HashCode;
+ // Label of the token authority in the
+ // 'token_types' map on the top-level.
+ authority_label: string;
// Number of tokens of this type required.
// Defaults to one if the field is not provided.
@@ -318,17 +316,17 @@ The contract terms v1 will have the following structure:
.. ts:def:: ContractOutput
type ContractOutput =
- | ContractOutputCurrency
- | ContractOutputTaxReceipt
- | ContractOutputToken;
+ ContractOutputCoin |
+ ContractOutputTaxReceipt |
+ ContractOutputToken;
-.. ts:def:: ContractOutputCurrency
+.. ts:def:: ContractOutputCoin
- interface ContractOutputCurrency {
+ interface ContractOutputCoin {
- type: "currency";
+ type: "coins";
- // Amount of currency that will be yielded.
+ // Amount of coins that will be yielded.
// This excludes any applicable withdraw fees.
brutto_yield: Amount;
@@ -360,24 +358,21 @@ The contract terms v1 will have the following structure:
// 'token_types' map on the top-level.
authority_label: string;
- // Must a wallet understand this token type to
- // process contracts that consume or yield it?
- critical: boolean;
+ // Number of tokens to be yelded.
+ // Defaults to one if the field is not provided.
+ number?: Integer;
- // Information about the class of token that will
- // be yielded.
- details: OutputTokenClass;
}
-.. ts:def:: OutputTokenClass
+.. ts:def:: TokenClass
- type OutputTokenClass =
- | OutputTokenClassSubscription
- | OutputTokenClassDiscount
+ type TokenClass =
+ TokenClassSubscription
+ | TokenClassDiscount
-.. ts:def:: OutputTokenClassSubscription
+.. ts:def:: TokenClassSubscription
- interface OutputTokenClassSubscription {
+ interface TokenClassSubscription {
class: "subscription";
@@ -396,9 +391,9 @@ The contract terms v1 will have the following structure:
};
-.. ts:def:: OutputTokenClassDiscount
+.. ts:def:: TokenClassDiscount
- interface OutputTokenClassDiscount {
+ interface TokenClassDiscount {
class: "discount";
@@ -433,6 +428,13 @@ The contract terms v1 will have the following structure:
// When will tokens signed by this key expire?
token_expiration: Timestamp;
+ // Class-specific information of the token
+ details: TokenClass;
+
+ // Must a wallet understand this token type to
+ // process contracts that consume or yield it?
+ critical: boolean;
+
// Number of tokens issued according to ASS authority
// FIXME: this is still rather speculative in the design...
ass?: Integer;
@@ -452,8 +454,8 @@ The contract terms v1 will have the following structure:
.. ts:def:: TokenSignerPublicKey
type TokenSignerPublicKey =
- | DenomGroupRsa
- | DenomGroupCs;
+ DenomGroupRsa |
+ DenomGroupCs;
TODO: may want to do a deep copy and rename
DenomGroup* to TokenSignerPublicKey* here.