taler-docs

Documentation for GNU Taler components, APIs and protocols
Log | Files | Refs | README | LICENSE

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:
Mcore/api-merchant.rst | 238++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Mdesign-documents/046-mumimo-contracts.rst | 70++++++++++++++++++++++++++++++++++++----------------------------------
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.