gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-wallet-core] branch master updated: exchange api


From: gnunet
Subject: [taler-wallet-core] branch master updated: exchange api
Date: Mon, 26 Aug 2024 14:34:10 +0200

This is an automated email from the git hooks/post-receive script.

sebasjm pushed a commit to branch master
in repository wallet-core.

The following commit(s) were added to refs/heads/master by this push:
     new 1f3aac3b5 exchange api
1f3aac3b5 is described below

commit 1f3aac3b57af7f99de6d78fd43acea0b4cfdfcb1
Author: Sebastian <sebasjm@gmail.com>
AuthorDate: Mon Aug 26 09:33:48 2024 -0300

    exchange api
---
 packages/kyc-ui/src/Routing.tsx                 |   2 -
 packages/kyc-ui/src/pages/Start.tsx             |   2 +-
 packages/taler-util/src/http-client/exchange.ts | 693 ++++++++++++++++++------
 packages/taler-util/src/types-taler-exchange.ts | 554 +++++++++++++++----
 4 files changed, 977 insertions(+), 274 deletions(-)

diff --git a/packages/kyc-ui/src/Routing.tsx b/packages/kyc-ui/src/Routing.tsx
index 193efe8e4..8dcfa24a4 100644
--- a/packages/kyc-ui/src/Routing.tsx
+++ b/packages/kyc-ui/src/Routing.tsx
@@ -27,8 +27,6 @@ import { useErrorBoundary } from "preact/hooks";
 import { CallengeCompleted } from "./pages/CallengeCompleted.js";
 import { Frame } from "./pages/Frame.js";
 import { Start } from "./pages/Start.js";
-import { FillForm } from "./pages/FillForm.js";
-import { SaveToken } from "./pages/SaveToken.js";
 
 export function Routing(): VNode {
   // check session and defined if this is
diff --git a/packages/kyc-ui/src/pages/Start.tsx 
b/packages/kyc-ui/src/pages/Start.tsx
index 9813d5ff9..7bdbbf80f 100644
--- a/packages/kyc-ui/src/pages/Start.tsx
+++ b/packages/kyc-ui/src/pages/Start.tsx
@@ -226,7 +226,7 @@ function RequirementRow({
     ? undefined
     : withErrorHandler(
         async () => {
-          return lib.exchange.startKycProcess(reqId);
+          return lib.exchange.startExternalKycProcess(reqId);
         },
         (res) => {
           window.open(res.body.redirect_url, "_blank");
diff --git a/packages/taler-util/src/http-client/exchange.ts 
b/packages/taler-util/src/http-client/exchange.ts
index 9b7635cb4..c9d2975d1 100644
--- a/packages/taler-util/src/http-client/exchange.ts
+++ b/packages/taler-util/src/http-client/exchange.ts
@@ -17,8 +17,9 @@ import {
   opKnownAlternativeFailure,
   opKnownHttpFailure,
   opSuccessFromHttp,
-  opUnknownFailure
+  opUnknownFailure,
 } from "../operation.js";
+import { Codec, codecForAny } from "../codec.js";
 import {
   TalerSignaturePurpose,
   buildSigPS,
@@ -26,7 +27,7 @@ import {
   eddsaSign,
   encodeCrock,
   stringToBytes,
-  timestampRoundedToBuffer
+  timestampRoundedToBuffer,
 } from "../taler-crypto.js";
 import {
   AccessToken,
@@ -35,10 +36,12 @@ import {
   PaginationParams,
   ReserveAccount,
   SigningKey,
-  codecForTalerCommonConfigResponse
+  codecForTalerCommonConfigResponse,
 } from "../types-taler-common.js";
 import {
   AmlDecisionRequest,
+  BatchWithdrawResponse,
+  ExchangeBatchWithdrawRequest,
   ExchangeVersionResponse,
   KycRequirementInformationId,
   WalletKycRequest,
@@ -52,9 +55,13 @@ import {
   codecForExchangeKeys,
   codecForKycProcessClientInformation,
   codecForKycProcessStartInformation,
-  codecForLegitimizationNeededResponse
+  codecForLegitimizationNeededResponse,
 } from "../types-taler-exchange.js";
-import { CacheEvictor, addMerchantPaginationParams, nullEvictor } from 
"./utils.js";
+import {
+  CacheEvictor,
+  addMerchantPaginationParams,
+  nullEvictor,
+} from "./utils.js";
 
 import { TalerError } from "../errors.js";
 import { TalerErrorCode } from "../taler-error-codes.js";
@@ -71,6 +78,8 @@ export enum TalerExchangeCacheEviction {
   CREATE_DESCISION,
 }
 
+declare const __pubId: unique symbol;
+export type ReservePub = string & { [__pubId]: true };
 /**
  */
 export class TalerExchangeHttpClient {
@@ -91,6 +100,20 @@ export class TalerExchangeHttpClient {
     const compare = LibtoolVersion.compare(this.PROTOCOL_VERSION, version);
     return compare?.compatible ?? false;
   }
+
+  // TERMS
+
+  /**
+   * https://docs.taler.net/core/api-exchange.html#get--seed
+   *
+   */
+  /**
+   * https://docs.taler.net/core/api-exchange.html#get--seed
+   *
+   */
+
+  // EXCHANGE INFORMATION
+
   /**
    * https://docs.taler.net/core/api-exchange.html#get--seed
    *
@@ -163,6 +186,7 @@ export class TalerExchangeHttpClient {
         return opUnknownFailure(resp, await readTalerErrorResponse(resp));
     }
   }
+
   /**
    * https://docs.taler.net/core/api-merchant.html#get--config
    *
@@ -181,10 +205,390 @@ export class TalerExchangeHttpClient {
     }
   }
 
-  // TERMS
+  //
+  // MANAGEMENT
+  //
 
+  /**
+   * https://docs.taler.net/core/api-exchange.html#get--management-keys
+   *
+   */
+  async getFutureKeys(): Promise<never> {
+    throw Error("not yet implemented");
+  }
+
+  /**
+   * https://docs.taler.net/core/api-exchange.html#post--management-keys
+   *
+   */
+  async signFutureKeys(): Promise<never> {
+    throw Error("not yet implemented");
+  }
+
+  /**
+   * 
https://docs.taler.net/core/api-exchange.html#post--management-denominations-$H_DENOM_PUB-revoke
+   *
+   */
+  async revokeFutureDenominationKeys(): Promise<never> {
+    throw Error("not yet implemented");
+  }
+  /**
+   * 
https://docs.taler.net/core/api-exchange.html#post--management-signkeys-$EXCHANGE_PUB-revoke
+   *
+   */
+  async revokeFutureSigningKeys(): Promise<never> {
+    throw Error("not yet implemented");
+  }
+
+  /**
+   * https://docs.taler.net/core/api-exchange.html#post--management-auditors
+   *
+   */
+  async enableAuditor(): Promise<never> {
+    throw Error("not yet implemented");
+  }
+
+  /**
+   * 
https://docs.taler.net/core/api-exchange.html#post--management-auditors-$AUDITOR_PUB-disable
+   *
+   */
+  async disableAuditor(): Promise<never> {
+    throw Error("not yet implemented");
+  }
+
+  /**
+   * https://docs.taler.net/core/api-exchange.html#post--management-wire-fee
+   *
+   */
+  async configWireFee(): Promise<never> {
+    throw Error("not yet implemented");
+  }
+
+  /**
+   * https://docs.taler.net/core/api-exchange.html#post--management-global-fees
+   *
+   */
+  async configGlobalFees(): Promise<never> {
+    throw Error("not yet implemented");
+  }
+
+  /**
+   * https://docs.taler.net/core/api-exchange.html#post--management-wire
+   *
+   */
+  async enableWireMethod(): Promise<never> {
+    throw Error("not yet implemented");
+  }
+
+  /**
+   * 
https://docs.taler.net/core/api-exchange.html#post--management-wire-disable
+   *
+   */
+  async disableWireMethod(): Promise<never> {
+    throw Error("not yet implemented");
+  }
+
+  /**
+   * https://docs.taler.net/core/api-exchange.html#post--management-drain
+   *
+   */
+  async drainProfits(): Promise<never> {
+    throw Error("not yet implemented");
+  }
+
+  /**
+   * 
https://docs.taler.net/core/api-exchange.html#post--management-aml-officers
+   *
+   */
+  async updateOfficer(): Promise<never> {
+    throw Error("not yet implemented");
+  }
+
+  /**
+   * https://docs.taler.net/core/api-exchange.html#post--management-partners
+   *
+   */
+  async enablePartner(): Promise<never> {
+    throw Error("not yet implemented");
+  }
+
+  //
+  // AUDITOR
+  //
+
+  /**
+   * 
https://docs.taler.net/core/api-exchange.html#post--auditors-$AUDITOR_PUB-$H_DENOM_PUB
+   *
+   */
+  async addAuditor(): Promise<never> {
+    throw Error("not yet implemented");
+  }
+
+  //
+  // WITHDRAWAL
+  //
+
+  /**
+   * https://docs.taler.net/core/api-exchange.html#get--reserves-$RESERVE_PUB
+   *
+   */
+  async getReserveInfo(): Promise<never> {
+    throw Error("not yet implemented");
+  }
+
+  /**
+   * https://docs.taler.net/core/api-exchange.html#post--csr-withdraw
+   *
+   */
+  async prepareCsrWithdawal(): Promise<never> {
+    throw Error("not yet implemented");
+  }
+
+  /**
+   * 
https://docs.taler.net/core/api-exchange.html#post--reserves-$RESERVE_PUB-batch-withdraw
+   *
+   */
+  async withdraw(rid: ReservePub, body: ExchangeBatchWithdrawRequest) {
+    const url = new URL(`reserves/${rid}/batch-withdraw`, this.baseUrl);
+
+    const resp = await this.httpLib.fetch(url.href, {
+      method: "POST",
+      body,
+    });
+
+    switch (resp.status) {
+      case HttpStatusCode.Ok:
+        return opSuccessFromHttp(
+          resp,
+          codecForAny() as Codec<BatchWithdrawResponse>,
+        );
+      case HttpStatusCode.Forbidden:
+        return opKnownHttpFailure(resp.status, resp);
+      case HttpStatusCode.BadRequest:
+        return opKnownHttpFailure(resp.status, resp);
+      case HttpStatusCode.NotFound:
+        return opKnownHttpFailure(resp.status, resp);
+      case HttpStatusCode.Conflict:
+        return opKnownHttpFailure(resp.status, resp);
+      case HttpStatusCode.Gone:
+        return opKnownHttpFailure(resp.status, resp);
+      case HttpStatusCode.UnavailableForLegalReasons:
+        return opKnownAlternativeFailure(
+          resp,
+          resp.status,
+          codecForLegitimizationNeededResponse(),
+        );
+      default:
+        return opUnknownFailure(resp, await readTalerErrorResponse(resp));
+    }
+  }
+
+  /**
+   * 
https://docs.taler.net/core/api-exchange.html#withdraw-with-age-restriction
+   *
+   */
+  async withdrawWithAge(): Promise<never> {
+    throw Error("not yet implemented");
+  }
+
+  /**
+   * 
https://docs.taler.net/core/api-exchange.html#post--age-withdraw-$ACH-reveal
+   *
+   */
+  async revealCoinsForAge(): Promise<never> {
+    throw Error("not yet implemented");
+  }
+
+  //
+  // RESERVE HISTORY
+  //
+
+  /**
+   * 
https://docs.taler.net/core/api-exchange.html#get--reserves-$RESERVE_PUB-history
+   *
+   */
+  async getResverveHistory(): Promise<never> {
+    throw Error("not yet implemented");
+  }
+
+  //
+  // COIN HISTORY
   //
-  // KYC operations
+
+  /**
+   * https://docs.taler.net/core/api-exchange.html#get--coins-$COIN_PUB-history
+   *
+   */
+  async getCoinHistory(): Promise<never> {
+    throw Error("not yet implemented");
+  }
+
+  //
+  // DEPOSIT
+  //
+
+  /**
+   * https://docs.taler.net/core/api-exchange.html#post--batch-deposit
+   *
+   */
+  async deposit(): Promise<never> {
+    throw Error("not yet implemented");
+  }
+
+  //
+  // REFRESH
+  //
+
+  /**
+   * https://docs.taler.net/core/api-exchange.html#post--csr-melt
+   *
+   */
+  async prepareCsrMelt(): Promise<never> {
+    throw Error("not yet implemented");
+  }
+
+  /**
+   * https://docs.taler.net/core/api-exchange.html#post--coins-$COIN_PUB-melt
+   *
+   */
+  async meltCoin(): Promise<never> {
+    throw Error("not yet implemented");
+  }
+
+  /**
+   * https://docs.taler.net/core/api-exchange.html#post--refreshes-$RCH-reveal
+   *
+   */
+  async releaveCoin(): Promise<never> {
+    throw Error("not yet implemented");
+  }
+
+  /**
+   * https://docs.taler.net/core/api-exchange.html#get--coins-$COIN_PUB-link
+   *
+   */
+  async linkCoin(): Promise<never> {
+    throw Error("not yet implemented");
+  }
+
+  //
+  // RECOUP
+  //
+
+  /**
+   * https://docs.taler.net/core/api-exchange.html#post--coins-$COIN_PUB-recoup
+   *
+   */
+  async recoupReserveCoin(): Promise<never> {
+    throw Error("not yet implemented");
+  }
+
+  /**
+   * 
https://docs.taler.net/core/api-exchange.html#post--coins-$COIN_PUB-recoup-refresh
+   *
+   */
+  async recoupRefreshCoin(): Promise<never> {
+    throw Error("not yet implemented");
+  }
+
+  // WIRE TRANSFER
+
+  /**
+   * https://docs.taler.net/core/api-exchange.html#get--transfers-$WTID
+   *
+   */
+  async getWireTransferInfo(): Promise<never> {
+    throw Error("not yet implemented");
+  }
+
+  /**
+   * 
https://docs.taler.net/core/api-exchange.html#get--deposits-$H_WIRE-$MERCHANT_PUB-$H_CONTRACT_TERMS-$COIN_PUB
+   *
+   */
+  async getWireTransferIdForDeposit(): Promise<never> {
+    throw Error("not yet implemented");
+  }
+
+  // REFUND
+
+  /**
+   * https://docs.taler.net/core/api-exchange.html#post--coins-$COIN_PUB-refund
+   *
+   */
+  async refund(): Promise<never> {
+    throw Error("not yet implemented");
+  }
+
+  // WALLET TO WALLET
+
+  /**
+   * https://docs.taler.net/core/api-exchange.html#get--purses-$PURSE_PUB-merge
+   *
+   */
+  async getPurseInfoAtMerge(): Promise<never> {
+    throw Error("not yet implemented");
+  }
+
+  /**
+   * 
https://docs.taler.net/core/api-exchange.html#get--purses-$PURSE_PUB-deposit
+   *
+   */
+  async getPurseInfoAtDeposit(): Promise<never> {
+    throw Error("not yet implemented");
+  }
+
+  /**
+   * 
https://docs.taler.net/core/api-exchange.html#post--purses-$PURSE_PUB-create
+   *
+   */
+  async createPurseFromDeposit(): Promise<never> {
+    throw Error("not yet implemented");
+  }
+
+  /**
+   * https://docs.taler.net/core/api-exchange.html#delete--purses-$PURSE_PUB
+   *
+   */
+  async deletePurse(): Promise<never> {
+    throw Error("not yet implemented");
+  }
+
+  /**
+   * 
https://docs.taler.net/core/api-exchange.html#post--purses-$PURSE_PUB-merge
+   *
+   */
+  async mergePurse(): Promise<never> {
+    throw Error("not yet implemented");
+  }
+
+  /**
+   * 
https://docs.taler.net/core/api-exchange.html#post--reserves-$RESERVE_PUB-purse
+   *
+   */
+  async createPurseFromReserve(): Promise<never> {
+    throw Error("not yet implemented");
+  }
+
+  /**
+   * 
https://docs.taler.net/core/api-exchange.html#post--purses-$PURSE_PUB-deposit
+   *
+   */
+  async depositIntoPurse(): Promise<never> {
+    throw Error("not yet implemented");
+  }
+
+  // WADS
+
+  /**
+   * https://docs.taler.net/core/api-exchange.html#get--wads-$WAD_ID
+   *
+   */
+  async getWadInfo(): Promise<never> {
+    throw Error("not yet implemented");
+  }
+
+  //
+  // KYC
   //
 
   /**
@@ -198,7 +602,7 @@ export class TalerExchangeHttpClient {
       balance,
       reserve_pub: account.id,
       reserve_sig: encodeCrock(account.signingKey),
-    }
+    };
 
     const resp = await this.httpLib.fetch(url.href, {
       method: "POST",
@@ -213,7 +617,11 @@ export class TalerExchangeHttpClient {
       case HttpStatusCode.Forbidden:
         return opKnownHttpFailure(resp.status, resp);
       case HttpStatusCode.UnavailableForLegalReasons:
-        return opKnownAlternativeFailure(resp, resp.status, 
codecForLegitimizationNeededResponse());
+        return opKnownAlternativeFailure(
+          resp,
+          resp.status,
+          codecForLegitimizationNeededResponse(),
+        );
       default:
         return opUnknownFailure(resp, await readTalerErrorResponse(resp));
     }
@@ -223,9 +631,13 @@ export class TalerExchangeHttpClient {
    * https://docs.taler.net/core/api-exchange.html#post--kyc-wallet
    *
    */
-  async checkKycStatus(account: ReserveAccount, requirementId: number, params: 
{
-    timeout?: number,
-  } = {}) {
+  async checkKycStatus(
+    account: ReserveAccount,
+    requirementId: number,
+    params: {
+      timeout?: number;
+    } = {},
+  ) {
     const url = new URL(`kyc-check/${String(requirementId)}`, this.baseUrl);
 
     if (params.timeout !== undefined) {
@@ -243,7 +655,11 @@ export class TalerExchangeHttpClient {
       case HttpStatusCode.Ok:
         return opSuccessFromHttp(resp, codecForAccountKycStatus());
       case HttpStatusCode.Accepted:
-        return opKnownAlternativeFailure(resp, resp.status, 
codecForAccountKycStatus());
+        return opKnownAlternativeFailure(
+          resp,
+          resp.status,
+          codecForAccountKycStatus(),
+        );
       case HttpStatusCode.NoContent:
         return opEmptySuccess(resp);
       case HttpStatusCode.Forbidden:
@@ -258,12 +674,16 @@ export class TalerExchangeHttpClient {
   }
 
   /**
-     * 
https://docs.taler.net/core/api-exchange.html#get--kyc-info-$ACCESS_TOKEN
-     *
-     */
-  async checkKycInfo(token: AccessToken, known: KycRequirementInformationId[], 
params: {
-    timeout?: number,
-  } = {}) {
+   * https://docs.taler.net/core/api-exchange.html#get--kyc-info-$ACCESS_TOKEN
+   *
+   */
+  async checkKycInfo(
+    token: AccessToken,
+    known: KycRequirementInformationId[],
+    params: {
+      timeout?: number;
+    } = {},
+  ) {
     const url = new URL(`kyc-info/${token}`, this.baseUrl);
 
     if (params.timeout !== undefined) {
@@ -273,15 +693,19 @@ export class TalerExchangeHttpClient {
     const resp = await this.httpLib.fetch(url.href, {
       method: "GET",
       headers: {
-        "If-None-Match": known.length ? known.join(",") : undefined
-      }
+        "If-None-Match": known.length ? known.join(",") : undefined,
+      },
     });
 
     switch (resp.status) {
       case HttpStatusCode.Ok:
         return opSuccessFromHttp(resp, codecForKycProcessClientInformation());
       case HttpStatusCode.NoContent:
-        return opKnownAlternativeFailure(resp, HttpStatusCode.NoContent, 
codecForEmptyObject());
+        return opKnownAlternativeFailure(
+          resp,
+          HttpStatusCode.NoContent,
+          codecForEmptyObject(),
+        );
       case HttpStatusCode.NotModified:
         return opKnownHttpFailure(resp.status, resp);
       default:
@@ -289,7 +713,6 @@ export class TalerExchangeHttpClient {
     }
   }
 
-
   /**
    * https://docs.taler.net/core/api-exchange.html#post--kyc-upload-$ID
    *
@@ -320,13 +743,15 @@ export class TalerExchangeHttpClient {
    * https://docs.taler.net/core/api-exchange.html#post--kyc-start-$ID
    *
    */
-  async startKycProcess(requirement: KycRequirementInformationId, body: object 
= {}) {
+  async startExternalKycProcess(
+    requirement: KycRequirementInformationId,
+    body: object = {},
+  ) {
     const url = new URL(`kyc-start/${requirement}`, this.baseUrl);
 
-
     const resp = await this.httpLib.fetch(url.href, {
       method: "POST",
-      body
+      body,
     });
 
     switch (resp.status) {
@@ -343,118 +768,16 @@ export class TalerExchangeHttpClient {
     }
   }
 
+  /**
+   * 
https://docs.taler.net/core/api-exchange.html#get--kyc-proof-$PROVIDER_NAME?state=$H_PAYTO
+   *
+   */
+  async completeExternalKycProcess(provider: string, state: string) {}
+
   //
   // AML operations
   //
 
-  /**
-   * 
https://docs.taler.net/core/api-exchange.html#get--aml-$OFFICER_PUB-decisions-$STATE
-   *
-   */
-  // async getDecisionsByState(
-  //   auth: OfficerAccount,
-  //   state: TalerExchangeApi.AmlState,
-  //   pagination?: PaginationParams,
-  // ) {
-  //   const url = new URL(
-  //     `aml/${auth.id}/decisions/${TalerExchangeApi.AmlState[state]}`,
-  //     this.baseUrl,
-  //   );
-  //   addPaginationParams(url, pagination);
-
-  //   const resp = await this.httpLib.fetch(url.href, {
-  //     method: "GET",
-  //     headers: {
-  //       "Taler-AML-Officer-Signature": buildQuerySignature(auth.signingKey),
-  //     },
-  //   });
-
-  //   switch (resp.status) {
-  //     case HttpStatusCode.Ok:
-  //       return opSuccessFromHttp(resp, codecForAmlRecords());
-  //     case HttpStatusCode.NoContent:
-  //       return opFixedSuccess({ records: [] });
-  //     //this should be unauthorized
-  //     case HttpStatusCode.Forbidden:
-  //       return opKnownHttpFailure(resp.status, resp);
-  //     case HttpStatusCode.Unauthorized:
-  //       return opKnownHttpFailure(resp.status, resp);
-  //     case HttpStatusCode.NotFound:
-  //       return opKnownHttpFailure(resp.status, resp);
-  //     case HttpStatusCode.Conflict:
-  //       return opKnownHttpFailure(resp.status, resp);
-  //     default:
-  //       return opUnknownFailure(resp, await readTalerErrorResponse(resp));
-  //   }
-  // }
-
-  // /**
-  //  * 
https://docs.taler.net/core/api-exchange.html#get--aml-$OFFICER_PUB-decision-$H_PAYTO
-  //  *
-  //  */
-  // async getDecisionDetails(auth: OfficerAccount, account: string) {
-  //   const url = new URL(`aml/${auth.id}/decision/${account}`, this.baseUrl);
-
-  //   const resp = await this.httpLib.fetch(url.href, {
-  //     method: "GET",
-  //     headers: {
-  //       "Taler-AML-Officer-Signature": buildQuerySignature(auth.signingKey),
-  //     },
-  //   });
-
-  //   switch (resp.status) {
-  //     case HttpStatusCode.Ok:
-  //       return opSuccessFromHttp(resp, codecForAmlDecisionDetails());
-  //     case HttpStatusCode.NoContent:
-  //       return opFixedSuccess({ aml_history: [], kyc_attributes: [] });
-  //     //this should be unauthorized
-  //     case HttpStatusCode.Forbidden:
-  //       return opKnownHttpFailure(resp.status, resp);
-  //     case HttpStatusCode.Unauthorized:
-  //       return opKnownHttpFailure(resp.status, resp);
-  //     case HttpStatusCode.NotFound:
-  //       return opKnownHttpFailure(resp.status, resp);
-  //     case HttpStatusCode.Conflict:
-  //       return opKnownHttpFailure(resp.status, resp);
-  //     default:
-  //       return opUnknownFailure(resp, await readTalerErrorResponse(resp));
-  //   }
-  // }
-
-  // /**
-  //  * 
https://docs.taler.net/core/api-exchange.html#post--aml-$OFFICER_PUB-decision
-  //  *
-  //  */
-  // async addDecisionDetails(
-  //   auth: OfficerAccount,
-  //   decision: Omit<TalerExchangeApi.AmlDecision, "officer_sig">,
-  // ) {
-  //   const url = new URL(`aml/${auth.id}/decision`, this.baseUrl);
-
-  //   const body = buildDecisionSignature(auth.signingKey, decision);
-  //   const resp = await this.httpLib.fetch(url.href, {
-  //     method: "POST",
-  //     body,
-  //   });
-
-  //   switch (resp.status) {
-  //     case HttpStatusCode.NoContent:
-  //       return opEmptySuccess(resp);
-  //     //FIXME: this should be unauthorized
-  //     case HttpStatusCode.Forbidden:
-  //       return opKnownHttpFailure(resp.status, resp);
-  //     case HttpStatusCode.Unauthorized:
-  //       return opKnownHttpFailure(resp.status, resp);
-  //     //FIXME: this two need to be split by error code
-  //     case HttpStatusCode.NotFound:
-  //       return opKnownHttpFailure(resp.status, resp);
-  //     case HttpStatusCode.Conflict:
-  //       return opKnownHttpFailure(resp.status, resp);
-  //     default:
-  //       return opUnknownFailure(resp, await readTalerErrorResponse(resp));
-  //   }
-  // }
-
   /**
    * 
https://docs.taler.net/core/api-exchange.html#get--aml-$OFFICER_PUB-measures
    *
@@ -481,26 +804,23 @@ export class TalerExchangeHttpClient {
    * 
https://docs.taler.net/core/api-exchange.html#get--aml-$OFFICER_PUB-measures
    *
    */
-  async getAmlKycStatistics(auth: OfficerAccount, name: string, filter: {
-    since?: Date
-    until?: Date
-  } = {}) {
+  async getAmlKycStatistics(
+    auth: OfficerAccount,
+    name: string,
+    filter: {
+      since?: Date;
+      until?: Date;
+    } = {},
+  ) {
     const url = new URL(`aml/${auth.id}/kyc-statistics/${name}`, this.baseUrl);
 
     if (filter.since !== undefined) {
-      url.searchParams.set(
-        "start_date",
-        String(filter.since.getTime())
-      );
+      url.searchParams.set("start_date", String(filter.since.getTime()));
     }
     if (filter.until !== undefined) {
-      url.searchParams.set(
-        "end_date",
-        String(filter.until.getTime())
-      );
+      url.searchParams.set("end_date", String(filter.until.getTime()));
     }
 
-
     const resp = await this.httpLib.fetch(url.href, {
       method: "GET",
       headers: {
@@ -519,11 +839,14 @@ export class TalerExchangeHttpClient {
    * 
https://docs.taler.net/core/api-exchange.html#get--aml-$OFFICER_PUB-decisions
    *
    */
-  async getAmlDecisions(auth: OfficerAccount, params: PaginationParams & {
-    account?: string,
-    active?: boolean,
-    investigation?: boolean,
-  } = {}) {
+  async getAmlDecisions(
+    auth: OfficerAccount,
+    params: PaginationParams & {
+      account?: string;
+      active?: boolean;
+      investigation?: boolean;
+    } = {},
+  ) {
     const url = new URL(`aml/${auth.id}/decisions`, this.baseUrl);
 
     addMerchantPaginationParams(url, params);
@@ -534,7 +857,10 @@ export class TalerExchangeHttpClient {
       url.searchParams.set("active", params.active ? "YES" : "NO");
     }
     if (params.investigation !== undefined) {
-      url.searchParams.set("investigation", params.investigation ? "YES" : 
"NO");
+      url.searchParams.set(
+        "investigation",
+        params.investigation ? "YES" : "NO",
+      );
     }
 
     const resp = await this.httpLib.fetch(url.href, {
@@ -564,7 +890,11 @@ export class TalerExchangeHttpClient {
    * 
https://docs.taler.net/core/api-exchange.html#get--aml-$OFFICER_PUB-attributes-$H_PAYTO
    *
    */
-  async getAmlAttributesForAccount(auth: OfficerAccount, account: string, 
params: PaginationParams = {}) {
+  async getAmlAttributesForAccount(
+    auth: OfficerAccount,
+    account: string,
+    params: PaginationParams = {},
+  ) {
     const url = new URL(`aml/${auth.id}/attributes/${account}`, this.baseUrl);
 
     addMerchantPaginationParams(url, params);
@@ -591,12 +921,14 @@ export class TalerExchangeHttpClient {
     }
   }
 
-
   /**
    * 
https://docs.taler.net/core/api-exchange.html#get--aml-$OFFICER_PUB-attributes-$H_PAYTO
    *
    */
-  async makeAmlDesicion(auth: OfficerAccount, decision: 
Omit<AmlDecisionRequest, "officer_sig">) {
+  async makeAmlDesicion(
+    auth: OfficerAccount,
+    decision: Omit<AmlDecisionRequest, "officer_sig">,
+  ) {
     const url = new URL(`aml/${auth.id}/decision`, this.baseUrl);
 
     const body = buildAMLDecisionSignature(auth.signingKey, decision);
@@ -622,20 +954,57 @@ export class TalerExchangeHttpClient {
     }
   }
 
+  // RESERVE control
+
+  /**
+   * 
https://docs.taler.net/core/api-exchange.html#post--reserves-$RESERVE_PUB-open
+   *
+   */
+  async reserveOpen(): Promise<never> {
+    throw Error("not yet implemented");
+  }
+
+  /**
+   * 
https://docs.taler.net/core/api-exchange.html#get--reserves-attest-$RESERVE_PUB
+   *
+   */
+  async getReserveAttributes(): Promise<never> {
+    throw Error("not yet implemented");
+  }
+
+  /**
+   * 
https://docs.taler.net/core/api-exchange.html#post--reserves-attest-$RESERVE_PUB
+   *
+   */
+  async signReserveAttributes(): Promise<never> {
+    throw Error("not yet implemented");
+  }
+
+  /**
+   * 
https://docs.taler.net/core/api-exchange.html#post--reserves-$RESERVE_PUB-close
+   *
+   */
+  async closeReserve(): Promise<never> {
+    throw Error("not yet implemented");
+  }
+
+  /**
+   * 
https://docs.taler.net/core/api-exchange.html#delete--reserves-$RESERVE_PUB
+   *
+   */
+  async deleteReserve(): Promise<never> {
+    throw Error("not yet implemented");
+  }
 }
 
 function buildKYCQuerySignature(key: SigningKey): string {
-  const sigBlob = buildSigPS(
-    TalerSignaturePurpose.AML_QUERY,
-  ).build();
+  const sigBlob = buildSigPS(TalerSignaturePurpose.AML_QUERY).build();
 
   return encodeCrock(eddsaSign(sigBlob, key));
 }
 
 function buildAMLQuerySignature(key: SigningKey): string {
-  const sigBlob = buildSigPS(
-    TalerSignaturePurpose.AML_QUERY,
-  ).build();
+  const sigBlob = buildSigPS(TalerSignaturePurpose.AML_QUERY).build();
 
   return encodeCrock(eddsaSign(sigBlob, key));
 }
diff --git a/packages/taler-util/src/types-taler-exchange.ts 
b/packages/taler-util/src/types-taler-exchange.ts
index 0cd722239..e9c80e045 100644
--- a/packages/taler-util/src/types-taler-exchange.ts
+++ b/packages/taler-util/src/types-taler-exchange.ts
@@ -573,11 +573,6 @@ export interface DenomGroupCommon {
 
   // Fee charged by the exchange for refunding a coin of this denomination.
   fee_refund: AmountString;
-
-  // XOR of all the SHA-512 hash values of the denominations' public keys
-  // in this group.  Note that for hashing, the binary format of the
-  // public keys is used, and not their base32 encoding.
-  hash: HashCodeString;
 }
 
 export interface DenomCommon {
@@ -933,18 +928,18 @@ export namespace DenomKeyType {
   }
 }
 
-export interface RsaBlindedDenominationSignature {
-  cipher: DenomKeyType.Rsa;
-  blinded_rsa_signature: string;
-}
+// export interface RsaBlindedDenominationSignature {
+//   cipher: DenomKeyType.Rsa;
+//   blinded_rsa_signature: string;
+// }
 
-export interface CSBlindedDenominationSignature {
-  cipher: DenomKeyType.ClauseSchnorr;
-}
+// export interface CSBlindedDenominationSignature {
+//   cipher: DenomKeyType.ClauseSchnorr;
+// }
 
-export type BlindedDenominationSignature =
-  | RsaBlindedDenominationSignature
-  | CSBlindedDenominationSignature;
+// export type BlindedDenominationSignature =
+//   | RsaBlindedDenominationSignature
+//   | CSBlindedDenominationSignature;
 
 export const codecForRsaBlindedDenominationSignature = () =>
   buildCodecForObject<RsaBlindedDenominationSignature>()
@@ -1952,6 +1947,8 @@ export enum AmlState {
   pending = 1,
   frozen = 2,
 }
+type Float = number;
+
 export interface ExchangeKeysResponse {
   // libtool-style representation of the Exchange protocol version, see
   // 
https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning
@@ -1969,100 +1966,95 @@ export interface ExchangeKeysResponse {
    */
 
   // How wallets should render this currency.
-  // currency_specification: CurrencySpecification;
-
-  // // Absolute cost offset for the STEFAN curve used
-  // // to (over) approximate fees payable by amount.
-  // stefan_abs: AmountString;
-
-  // // Factor to multiply the logarithm of the amount
-  // // with to (over) approximate fees payable by amount.
-  // // Note that the total to be paid is first to be
-  // // divided by the smallest denomination to obtain
-  // // the value that the logarithm is to be taken of.
-  // stefan_log: AmountString;
-
-  // // Linear cost factor for the STEFAN curve used
-  // // to (over) approximate fees payable by amount.
-  // //
-  // // Note that this is a scalar, as it is multiplied
-  // // with the actual amount.
-  // stefan_lin: Float;
-
-  // // Type of the asset. "fiat", "crypto", "regional"
-  // // or "stock".  Wallets should adjust their UI/UX
-  // // based on this value.
-  // asset_type: string;
-
-  // // Array of wire accounts operated by the exchange for
-  // // incoming wire transfers.
-  // accounts: WireAccount[];
-
-  // // Object mapping names of wire methods (i.e. "iban" or "x-taler-bank")
-  // // to wire fees.
-  // wire_fees: { method: AggregateTransferFee[] };
-
-  // // List of exchanges that this exchange is partnering
-  // // with to enable wallet-to-wallet transfers.
-  // wads: ExchangePartner[];
-
-  // // Set to true if this exchange allows the use
-  // // of reserves for rewards.
-  // // @deprecated in protocol v18.
-  // rewards_allowed: false;
-
-  // // EdDSA master public key of the exchange, used to sign entries
-  // // in denoms and signkeys.
-  // master_public_key: EddsaPublicKey;
-
-  // // Relative duration until inactive reserves are closed;
-  // // not signed (!), can change without notice.
-  // reserve_closing_delay: RelativeTime;
-
-  // // Threshold amounts beyond which wallet should
-  // // trigger the KYC process of the issuing
-  // // exchange.  Optional option, if not given there is no limit.
-  // // Currency must match currency.
-  // wallet_balance_limit_without_kyc?: AmountString[];
-
-  // // Denominations offered by this exchange
-  // denominations: DenomGroup[];
-
-  // // Compact EdDSA signature (binary-only) over the
-  // // contatentation of all of the master_sigs (in reverse
-  // // chronological order by group) in the arrays under
-  // // "denominations".  Signature of TALER_ExchangeKeySetPS
-  // exchange_sig: EddsaSignature;
-
-  // // Public EdDSA key of the exchange that was used to generate the 
signature.
-  // // Should match one of the exchange's signing keys from signkeys.  It is 
given
-  // // explicitly as the client might otherwise be confused by clock skew as 
to
-  // // which signing key was used for the exchange_sig.
-  // exchange_pub: EddsaPublicKey;
-
-  // // Denominations for which the exchange currently offers/requests recoup.
-  // recoup: Recoup[];
-
-  // // Array of globally applicable fees by time range.
-  // global_fees: GlobalFees[];
-
-  // // The date when the denomination keys were last updated.
-  // list_issue_date: Timestamp;
-
-  // // Auditors of the exchange.
-  // auditors: AuditorKeys[];
-
-  // // The exchange's signing keys.
-  // signkeys: SignKey[];
-
-  // // Optional field with a dictionary of (name, object) pairs defining the
-  // // supported and enabled extensions, such as age_restriction.
-  // extensions?: { name: ExtensionManifest };
-
-  // // Signature by the exchange master key of the SHA-256 hash of the
-  // // normalized JSON-object of field extensions, if it was set.
-  // // The signature has purpose TALER_SIGNATURE_MASTER_EXTENSIONS.
-  // extensions_sig?: EddsaSignature;
+  currency_specification: CurrencySpecification;
+
+  // Absolute cost offset for the STEFAN curve used
+  // to (over) approximate fees payable by amount.
+  stefan_abs: AmountString;
+
+  // Factor to multiply the logarithm of the amount
+  // with to (over) approximate fees payable by amount.
+  // Note that the total to be paid is first to be
+  // divided by the smallest denomination to obtain
+  // the value that the logarithm is to be taken of.
+  stefan_log: AmountString;
+
+  // Linear cost factor for the STEFAN curve used
+  // to (over) approximate fees payable by amount.
+  //
+  // Note that this is a scalar, as it is multiplied
+  // with the actual amount.
+  stefan_lin: Float;
+
+  // Type of the asset. "fiat", "crypto", "regional"
+  // or "stock".  Wallets should adjust their UI/UX
+  // based on this value.
+  asset_type: string;
+
+  // Array of wire accounts operated by the exchange for
+  // incoming wire transfers.
+  accounts: WireAccount[];
+
+  // Object mapping names of wire methods (i.e. "iban" or "x-taler-bank")
+  // to wire fees.
+  wire_fees: { method: AggregateTransferFee[] };
+
+  // List of exchanges that this exchange is partnering
+  // with to enable wallet-to-wallet transfers.
+  wads: ExchangePartner[];
+
+  // EdDSA master public key of the exchange, used to sign entries
+  // in denoms and signkeys.
+  master_public_key: EddsaPublicKey;
+
+  // Relative duration until inactive reserves are closed;
+  // not signed (!), can change without notice.
+  reserve_closing_delay: RelativeTime;
+
+  // Threshold amounts beyond which wallet should
+  // trigger the KYC process of the issuing
+  // exchange.  Optional option, if not given there is no limit.
+  // Currency must match currency.
+  wallet_balance_limit_without_kyc?: AmountString[];
+
+  // Denominations offered by this exchange
+  denominations: DenomGroup[];
+
+  // Compact EdDSA signature (binary-only) over the
+  // contatentation of all of the master_sigs (in reverse
+  // chronological order by group) in the arrays under
+  // "denominations".  Signature of TALER_ExchangeKeySetPS
+  exchange_sig: EddsaSignature;
+
+  // Public EdDSA key of the exchange that was used to generate the signature.
+  // Should match one of the exchange's signing keys from signkeys.  It is 
given
+  // explicitly as the client might otherwise be confused by clock skew as to
+  // which signing key was used for the exchange_sig.
+  exchange_pub: EddsaPublicKey;
+
+  // Denominations for which the exchange currently offers/requests recoup.
+  recoup: Recoup[];
+
+  // Array of globally applicable fees by time range.
+  global_fees: GlobalFees[];
+
+  // The date when the denomination keys were last updated.
+  list_issue_date: Timestamp;
+
+  // Auditors of the exchange.
+  auditors: AuditorKeys[];
+
+  // The exchange's signing keys.
+  signkeys: SignKey[];
+
+  // Optional field with a dictionary of (name, object) pairs defining the
+  // supported and enabled extensions, such as age_restriction.
+  extensions?: { name: ExtensionManifest };
+
+  // Signature by the exchange master key of the SHA-256 hash of the
+  // normalized JSON-object of field extensions, if it was set.
+  // The signature has purpose TALER_SIGNATURE_MASTER_EXTENSIONS.
+  extensions_sig?: EddsaSignature;
 }
 
 interface ExtensionManifest {
@@ -2273,6 +2265,28 @@ export const codecForExchangeKeys = (): 
Codec<ExchangeKeysResponse> =>
     .property("version", codecForString())
     .property("base_url", codecForString())
     .property("currency", codecForString())
+    .property("accounts", codecForAny())
+    .property("asset_type", codecForAny())
+    .property("auditors", codecForAny())
+    .property("currency_specification", codecForAny())
+    .property("denominations", codecForAny())
+    .property("exchange_pub", codecForAny())
+    .property("exchange_sig", codecForAny())
+    .property("extensions", codecForAny())
+    .property("extensions_sig", codecForAny())
+    .property("global_fees", codecForAny())
+    .property("list_issue_date", codecForAny())
+    .property("master_public_key", codecForAny())
+    .property("recoup", codecForAny())
+    .property("reserve_closing_delay", codecForAny())
+    .property("signkeys", codecForAny())
+    .property("stefan_abs", codecForAny())
+    .property("stefan_lin", codecForAny())
+    .property("stefan_log", codecForAny())
+    .property("wads", codecForAny())
+    .property("wallet_balance_limit_without_kyc", codecForAny())
+    .property("wire_fees", codecForAny())
+
     .build("TalerExchangeApi.ExchangeKeysResponse");
 
 export const codecForEventCounter = (): Codec<EventCounter> =>
@@ -2493,3 +2507,325 @@ export const codecForKycProcessStartInformation =
     buildCodecForObject<KycProcessStartInformation>()
       .property("redirect_url", codecForURLString())
       .build("TalerExchangeApi.KycProcessStartInformation");
+
+export interface BatchWithdrawResponse {
+  // Array of blinded signatures, in the same order as was
+  // given in the request.
+  ev_sigs: WithdrawResponse[];
+}
+export interface WithdrawResponse {
+  // The blinded signature over the 'coin_ev', affirms the coin's
+  // validity after unblinding.
+  ev_sig: BlindedDenominationSignature;
+}
+export type BlindedDenominationSignature =
+  | RsaBlindedDenominationSignature
+  | CSBlindedDenominationSignature;
+
+export interface RsaBlindedDenominationSignature {
+  cipher: DenomKeyType.Rsa;
+
+  // (blinded) RSA signature
+  blinded_rsa_signature: BlindedRsaSignature;
+}
+
+export interface CSBlindedDenominationSignature {
+  cipher: DenomKeyType.ClauseSchnorr;
+
+  // Signer chosen bit value, 0 or 1, used
+  // in Clause Blind Schnorr to make the
+  // ROS problem harder.
+  b: Integer;
+
+  // Blinded scalar calculated from c_b.
+  s: Cs25519Scalar;
+}
+
+type BlindedRsaSignature = string;
+type Cs25519Scalar = string;
+type HashCode = string;
+type EddsaSignature = string;
+type EddsaPublicKey = string;
+type Amount = AmountString;
+type Base32 = string;
+
+export interface WithdrawError {
+  // Text describing the error.
+  hint: string;
+
+  // Detailed error code.
+  code: Integer;
+
+  // Amount left in the reserve.
+  balance: AmountString;
+
+  // History of the reserve's activity, in the same format
+  // as returned by /reserve/$RID/history.
+  history: TransactionHistoryItem[];
+}
+export type TransactionHistoryItem =
+  | AccountSetupTransaction
+  | ReserveWithdrawTransaction
+  | ReserveAgeWithdrawTransaction
+  | ReserveCreditTransaction
+  | ReserveClosingTransaction
+  | ReserveOpenRequestTransaction
+  | ReserveCloseRequestTransaction
+  | PurseMergeTransaction;
+
+enum TransactionHistoryType {
+  setup = "SETUP",
+  withdraw = "WITHDRAW",
+  ageWithdraw = "AGEWITHDRAW",
+  credit = "CREDIT",
+  closing = "CLOSING",
+  open = "OPEN",
+  close = "CLOSE",
+  merge = "MERGE",
+}
+interface AccountSetupTransaction {
+  type: TransactionHistoryType.setup;
+
+  // Offset of this entry in the reserve history.
+  // Useful to request incremental histories via
+  // the "start" query parameter.
+  history_offset: Integer;
+
+  // KYC fee agreed to by the reserve owner.
+  kyc_fee: AmountString;
+
+  // Time when the KYC was triggered.
+  kyc_timestamp: Timestamp;
+
+  // Hash of the wire details of the account.
+  // Note that this hash is unsalted and potentially
+  // private (as it could be inverted), hence access
+  // to this endpoint must be authorized using the
+  // private key of the reserve.
+  h_wire: HashCode;
+
+  // Signature created with the reserve's private key.
+  // Must be of purpose TALER_SIGNATURE_ACCOUNT_SETUP_REQUEST over
+  // a TALER_AccountSetupRequestSignaturePS.
+  reserve_sig: EddsaSignature;
+}
+interface ReserveWithdrawTransaction {
+  type: "WITHDRAW";
+
+  // Offset of this entry in the reserve history.
+  // Useful to request incremental histories via
+  // the "start" query parameter.
+  history_offset: Integer;
+
+  // Amount withdrawn.
+  amount: Amount;
+
+  // Hash of the denomination public key of the coin.
+  h_denom_pub: HashCode;
+
+  // Hash of the blinded coin to be signed.
+  h_coin_envelope: HashCode;
+
+  // Signature over a TALER_WithdrawRequestPS
+  // with purpose TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW
+  // created with the reserve's private key.
+  reserve_sig: EddsaSignature;
+
+  // Fee that is charged for withdraw.
+  withdraw_fee: Amount;
+}
+interface ReserveAgeWithdrawTransaction {
+  type: "AGEWITHDRAW";
+
+  // Offset of this entry in the reserve history.
+  // Useful to request incremental histories via
+  // the "start" query parameter.
+  history_offset: Integer;
+
+  // Total Amount withdrawn.
+  amount: Amount;
+
+  // Commitment of all n*kappa blinded coins.
+  h_commitment: HashCode;
+
+  // Signature over a TALER_AgeWithdrawRequestPS
+  // with purpose TALER_SIGNATURE_WALLET_RESERVE_AGE_WITHDRAW
+  // created with the reserve's private key.
+  reserve_sig: EddsaSignature;
+
+  // Fee that is charged for withdraw.
+  withdraw_fee: Amount;
+}
+interface ReserveCreditTransaction {
+  type: "CREDIT";
+
+  // Offset of this entry in the reserve history.
+  // Useful to request incremental histories via
+  // the "start" query parameter.
+  history_offset: Integer;
+
+  // Amount deposited.
+  amount: Amount;
+
+  // Sender account payto:// URL.
+  sender_account_url: string;
+
+  // Opaque identifier internal to the exchange that
+  // uniquely identifies the wire transfer that credited the reserve.
+  wire_reference: Integer;
+
+  // Timestamp of the incoming wire transfer.
+  timestamp: Timestamp;
+}
+interface ReserveClosingTransaction {
+  type: "CLOSING";
+
+  // Offset of this entry in the reserve history.
+  // Useful to request incremental histories via
+  // the "start" query parameter.
+  history_offset: Integer;
+
+  // Closing balance.
+  amount: Amount;
+
+  // Closing fee charged by the exchange.
+  closing_fee: Amount;
+
+  // Wire transfer subject.
+  wtid: Base32;
+
+  // payto:// URI of the wire account into which the funds were returned to.
+  receiver_account_details: string;
+
+  // This is a signature over a
+  // struct TALER_ReserveCloseConfirmationPS with purpose
+  // TALER_SIGNATURE_EXCHANGE_RESERVE_CLOSED.
+  exchange_sig: EddsaSignature;
+
+  // Public key used to create 'exchange_sig'.
+  exchange_pub: EddsaPublicKey;
+
+  // Time when the reserve was closed.
+  timestamp: Timestamp;
+}
+interface ReserveOpenRequestTransaction {
+  type: "OPEN";
+
+  // Offset of this entry in the reserve history.
+  // Useful to request incremental histories via
+  // the "start" query parameter.
+  history_offset: Integer;
+
+  // Open fee paid from the reserve.
+  open_fee: Amount;
+
+  // This is a signature over
+  // a struct TALER_ReserveOpenPS with purpose
+  // TALER_SIGNATURE_WALLET_RESERVE_OPEN.
+  reserve_sig: EddsaSignature;
+
+  // Timestamp of the open request.
+  request_timestamp: Timestamp;
+
+  // Requested expiration.
+  requested_expiration: Timestamp;
+
+  // Requested number of free open purses.
+  requested_min_purses: Integer;
+}
+interface ReserveCloseRequestTransaction {
+  type: "CLOSE";
+
+  // Offset of this entry in the reserve history.
+  // Useful to request incremental histories via
+  // the "start" query parameter.
+  history_offset: Integer;
+
+  // This is a signature over
+  // a struct TALER_ReserveClosePS with purpose
+  // TALER_SIGNATURE_WALLET_RESERVE_CLOSE.
+  reserve_sig: EddsaSignature;
+
+  // Target account payto://, optional.
+  h_payto?: PaytoHash;
+
+  // Timestamp of the close request.
+  request_timestamp: Timestamp;
+}
+interface PurseMergeTransaction {
+  type: "MERGE";
+
+  // Offset of this entry in the reserve history.
+  // Useful to request incremental histories via
+  // the "start" query parameter.
+  history_offset: Integer;
+
+  // SHA-512 hash of the contact of the purse.
+  h_contract_terms: HashCode;
+
+  // EdDSA public key used to approve merges of this purse.
+  merge_pub: EddsaPublicKey;
+
+  // Minimum age required for all coins deposited into the purse.
+  min_age: Integer;
+
+  // Number that identifies who created the purse
+  // and how it was paid for.
+  flags: Integer;
+
+  // Purse public key.
+  purse_pub: EddsaPublicKey;
+
+  // EdDSA signature of the account/reserve affirming the merge
+  // over a TALER_AccountMergeSignaturePS.
+  // Must be of purpose TALER_SIGNATURE_ACCOUNT_MERGE
+  reserve_sig: EddsaSignature;
+
+  // Client-side timestamp of when the merge request was made.
+  merge_timestamp: Timestamp;
+
+  // Indicative time by which the purse should expire
+  // if it has not been merged into an account. At this
+  // point, all of the deposits made should be
+  // auto-refunded.
+  purse_expiration: Timestamp;
+
+  // Purse fee the reserve owner paid for the purse creation.
+  purse_fee: Amount;
+
+  // Total amount merged into the reserve.
+  // (excludes fees).
+  amount: Amount;
+
+  // True if the purse was actually merged.
+  // If false, only the purse_fee has an impact
+  // on the reserve balance!
+  merged: boolean;
+}
+
+interface DenominationExpiredMessage {
+  // Taler error code.  Note that beyond
+  // expiration this message format is also
+  // used if the key is not yet valid, or
+  // has been revoked.
+  code: number;
+
+  // Signature by the exchange over a
+  // TALER_DenominationExpiredAffirmationPS.
+  // Must have purpose TALER_SIGNATURE_EXCHANGE_AFFIRM_DENOM_EXPIRED.
+  exchange_sig: EddsaSignature;
+
+  // Public key of the exchange used to create
+  // the 'exchange_sig.
+  exchange_pub: EddsaPublicKey;
+
+  // Hash of the denomination public key that is unknown.
+  h_denom_pub: HashCode;
+
+  // When was the signature created.
+  timestamp: Timestamp;
+
+  // What kind of operation was requested that now
+  // failed?
+  oper: string;
+}

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]