From 592ecda944bf5b32e86f6c42ee8e1f17d9c86451 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Sat, 14 Oct 2023 01:19:30 -0300 Subject: [PATCH] complet bank api --- .../{core-bank.ts => bank-core.ts} | 52 +- .../src/http-client/bank-integration.ts | 44 ++ .../src/http-client/bank-revenue.ts | 32 + .../taler-util/src/http-client/bank-wire.ts | 98 +++ packages/taler-util/src/http-client/types.ts | 592 ++++++++++++++++-- packages/taler-util/src/http-client/utils.ts | 12 +- 6 files changed, 728 insertions(+), 102 deletions(-) rename packages/taler-util/src/http-client/{core-bank.ts => bank-core.ts} (94%) create mode 100644 packages/taler-util/src/http-client/bank-integration.ts create mode 100644 packages/taler-util/src/http-client/bank-revenue.ts create mode 100644 packages/taler-util/src/http-client/bank-wire.ts diff --git a/packages/taler-util/src/http-client/core-bank.ts b/packages/taler-util/src/http-client/bank-core.ts similarity index 94% rename from packages/taler-util/src/http-client/core-bank.ts rename to packages/taler-util/src/http-client/bank-core.ts index 765348e42..c77f9ddda 100644 --- a/packages/taler-util/src/http-client/core-bank.ts +++ b/packages/taler-util/src/http-client/bank-core.ts @@ -27,6 +27,9 @@ import { } from "@gnu-taler/taler-util/http"; import { AccessToken, codecForAccountData, codecForBankAccountCreateWithdrawalResponse, codecForBankAccountGetWithdrawalResponse, codecForBankAccountTransactionInfo, codecForBankAccountTransactionsResponse, codecForCashoutConversionResponse, codecForCashoutPending, codecForCashouts, codecForCashoutStatusResponse, codecForConversionRatesResponse, codecForCoreBankConfig, codecForGlobalCashouts, codecForListBankAccountsResponse, codecForMonitorResponse, codecForPublicAccountsResponse, codecForTokenSuccessResponse, TalerAuthentication, TalerCorebankApi } from "./types.js"; import { addPaginationParams, makeBasicAuthHeader, makeBearerTokenAuthHeader, PaginationParams, UserAndPassword, UserAndToken } from "./utils.js"; +import { TalerRevenueHttpClient } from "./bank-revenue.js"; +import { TalerWireGatewayHttpClient } from "./bank-wire.js"; +import { TalerBankIntegrationHttpClient } from "./bank-integration.js"; const logger = new Logger("http-client/core-bank.ts"); @@ -465,18 +468,18 @@ export class TalerCoreBankHttpClient { } /** - * https://docs.taler.net/core/api-corebank.html#taler-bank-integration-api - * - */ + * https://docs.taler.net/core/api-corebank.html#taler-bank-integration-api + * + */ getWireGatewayAPI(username: string): TalerWireGatewayHttpClient { const url = new URL(`accounts/${username}/taler-wire-gateway`, this.baseUrl); return new TalerWireGatewayHttpClient(url.href, username, this.httpLib) } /** -* https://docs.taler.net/core/api-corebank.html#taler-bank-integration-api -* -*/ + * https://docs.taler.net/core/api-corebank.html#taler-bank-integration-api + * + */ getRevenueAPI(username: string): TalerRevenueHttpClient { const url = new URL(`accounts/${username}/taler-revenue`, this.baseUrl); return new TalerRevenueHttpClient(url.href, username, this.httpLib,) @@ -484,40 +487,3 @@ export class TalerCoreBankHttpClient { } -export class TalerBankIntegrationHttpClient { - httpLib: HttpRequestLibrary; - - constructor( - private baseUrl: string, - httpClient?: HttpRequestLibrary, - ) { - this.httpLib = httpClient ?? createPlatformHttpLib(); - } - -} - -export class TalerWireGatewayHttpClient { - httpLib: HttpRequestLibrary; - - constructor( - private baseUrl: string, - private username: string, - httpClient?: HttpRequestLibrary, - ) { - this.httpLib = httpClient ?? createPlatformHttpLib(); - } - -} - -export class TalerRevenueHttpClient { - httpLib: HttpRequestLibrary; - - constructor( - private baseUrl: string, - private username: string, - httpClient?: HttpRequestLibrary, - ) { - this.httpLib = httpClient ?? createPlatformHttpLib(); - } - -} \ No newline at end of file diff --git a/packages/taler-util/src/http-client/bank-integration.ts b/packages/taler-util/src/http-client/bank-integration.ts new file mode 100644 index 000000000..cdba66fa5 --- /dev/null +++ b/packages/taler-util/src/http-client/bank-integration.ts @@ -0,0 +1,44 @@ +import { HttpRequestLibrary, readSuccessResponseJsonOrThrow } from "../http-common.js"; +import { createPlatformHttpLib } from "../http.js"; +import { codecForBankWithdrawalOperationPostResponse } from "../taler-types.js"; +import { TalerBankIntegrationApi, codecForBankVersion, codecForBankWithdrawalOperationStatus } from "./types.js"; + +export class TalerBankIntegrationHttpClient { + httpLib: HttpRequestLibrary; + + constructor( + private baseUrl: string, + httpClient?: HttpRequestLibrary, + ) { + this.httpLib = httpClient ?? createPlatformHttpLib(); + } + + /** + * https://docs.taler.net/core/api-bank-integration.html#get-$BANK_API_BASE_URL-withdrawal-operation-$wopid + * + */ + async getWithdrawalOperationById(woid: string, timeoutMs?: number): Promise { + const url = new URL(`withdrawal-operation/${woid}`, this.baseUrl); + if (timeoutMs) { + url.searchParams.set("long_poll_ms", String(timeoutMs)) + } + const resp = await this.httpLib.fetch(url.href, { + method: "GET" + }); + return readSuccessResponseJsonOrThrow(resp, codecForBankWithdrawalOperationStatus()); + } + + /** + * https://docs.taler.net/core/api-bank-integration.html#post-$BANK_API_BASE_URL-withdrawal-operation-$wopid + * + */ + async completeWithdrawalOperationById(woid: string): Promise { + const url = new URL(`withdrawal-operation/${woid}`, this.baseUrl); + const resp = await this.httpLib.fetch(url.href, { + method: "POST", + }); + return readSuccessResponseJsonOrThrow(resp, codecForBankWithdrawalOperationPostResponse()); + } + +} + diff --git a/packages/taler-util/src/http-client/bank-revenue.ts b/packages/taler-util/src/http-client/bank-revenue.ts new file mode 100644 index 000000000..99ff71457 --- /dev/null +++ b/packages/taler-util/src/http-client/bank-revenue.ts @@ -0,0 +1,32 @@ +import { HttpRequestLibrary, makeBasicAuthHeader, readSuccessResponseJsonOrThrow } from "../http-common.js"; +import { createPlatformHttpLib } from "../http.js"; +import { TalerRevenueApi, codecForMerchantIncomingHistory } from "./types.js"; +import { UserAndPassword } from "./utils.js"; + +export class TalerRevenueHttpClient { + httpLib: HttpRequestLibrary; + + constructor( + private baseUrl: string, + private username: string, + httpClient?: HttpRequestLibrary, + ) { + this.httpLib = httpClient ?? createPlatformHttpLib(); + } + + /** + * https://docs.taler.net/core/api-bank-revenue.html#get-$BASE_URL-history + * + * @returns + */ + async getHistory(auth: string): Promise { + const url = new URL(`history`, this.baseUrl); + const resp = await this.httpLib.fetch(url.href, { + method: "GET", + headers: { + Authorization: makeBasicAuthHeader(this.username, auth), + } + }); + return readSuccessResponseJsonOrThrow(resp, codecForMerchantIncomingHistory()); + } +} \ No newline at end of file diff --git a/packages/taler-util/src/http-client/bank-wire.ts b/packages/taler-util/src/http-client/bank-wire.ts new file mode 100644 index 000000000..9f2b859ed --- /dev/null +++ b/packages/taler-util/src/http-client/bank-wire.ts @@ -0,0 +1,98 @@ +import { HttpRequestLibrary, makeBasicAuthHeader, readSuccessResponseJsonOrThrow } from "../http-common.js"; +import { createPlatformHttpLib } from "../http.js"; +import { TalerWireGatewayApi, codecForAddIncomingResponse, codecForIncomingHistory, codecForOutgoingHistory, codecForTransferResponse } from "./types.js"; +import { PaginationParams, UserAndPassword, addPaginationParams } from "./utils.js"; + +/** + * The API is used by the exchange to trigger transactions and query + * incoming transactions, as well as by the auditor to query incoming + * and outgoing transactions. + * + * https://docs.taler.net/core/api-bank-wire.html + */ +export class TalerWireGatewayHttpClient { + httpLib: HttpRequestLibrary; + + constructor( + private baseUrl: string, + private username: string, + httpClient?: HttpRequestLibrary, + ) { + this.httpLib = httpClient ?? createPlatformHttpLib(); + } + + /** + * https://docs.taler.net/core/api-bank-wire.html#post-$BASE_URL-transfer + * + */ + async transfer( + auth: string, + body: TalerWireGatewayApi.TransferRequest, + ): Promise { + const url = new URL(`transfer`, this.baseUrl); + const resp = await this.httpLib.fetch(url.href, { + method: "POST", + headers: { + Authorization: makeBasicAuthHeader(this.username, auth), + }, + body + }); + return readSuccessResponseJsonOrThrow(resp, codecForTransferResponse()); + } + + /** + * https://docs.taler.net/core/api-bank-wire.html#get-$BASE_URL-history-incoming + * + */ + async getHistoryIncoming( + auth: string, + pagination?: PaginationParams + ): Promise { + const url = new URL(`history/incoming`, this.baseUrl); + addPaginationParams(url, pagination) + const resp = await this.httpLib.fetch(url.href, { + method: "GET", + headers: { + Authorization: makeBasicAuthHeader(this.username, auth), + } + }); + return readSuccessResponseJsonOrThrow(resp, codecForIncomingHistory()); + } + /** + * https://docs.taler.net/core/api-bank-wire.html#get-$BASE_URL-history-outgoing + * + */ + async getHistoryOutgoing( + auth: string, + pagination?: PaginationParams + ): Promise { + const url = new URL(`history/outgoing`, this.baseUrl); + addPaginationParams(url, pagination) + const resp = await this.httpLib.fetch(url.href, { + method: "GET", + headers: { + Authorization: makeBasicAuthHeader(this.username, auth), + } + }); + return readSuccessResponseJsonOrThrow(resp, codecForOutgoingHistory()); + } + /** + * https://docs.taler.net/core/api-bank-wire.html#post-$BASE_URL-admin-add-incoming + * + */ + async addIncoming( + auth: string, + body: TalerWireGatewayApi.AddIncomingRequest, + ): Promise { + const url = new URL(`admin/add-incoming`, this.baseUrl); + const resp = await this.httpLib.fetch(url.href, { + method: "POST", + headers: { + Authorization: makeBasicAuthHeader(this.username, auth), + }, + body + }); + return readSuccessResponseJsonOrThrow(resp, codecForAddIncomingResponse()); + } +} + diff --git a/packages/taler-util/src/http-client/types.ts b/packages/taler-util/src/http-client/types.ts index 047f2fe8e..5f899dd5a 100644 --- a/packages/taler-util/src/http-client/types.ts +++ b/packages/taler-util/src/http-client/types.ts @@ -1,42 +1,120 @@ -import { codecForAmountJson, codecForAmountString } from "../amounts.js"; -import { TalerCorebankApiClient } from "../bank-api-client.js"; -import { Codec, buildCodecForObject, codecForAny, codecForBoolean, codecForConstString, codecForEither, codecForList, codecForMap, codecForNumber, codecForString, codecOptional } from "../codec.js"; +import { codecForAmountString } from "../amounts.js"; +import { Codec, buildCodecForObject, buildCodecForUnion, codecForBoolean, codecForConstString, codecForEither, codecForList, codecForMap, codecForNumber, codecForString, codecOptional } from "../codec.js"; import { codecForTimestamp } from "../time.js"; +/// +/// HASH +/// + +// 64-byte hash code. type HashCode = string; + +// 32-byte hash code. +type ShortHashCode = string; + +// 16-byte salt. +type WireSalt = string; + +type SHA256HashCode = ShortHashCode; + +type SHA512HashCode = HashCode; + +// 32-byte nonce value, must only be used once. +type CSNonce = string; + +// 32-byte nonce value, must only be used once. +type RefreshMasterSeed = string; + +// 32-byte value representing a point on Curve25519. +type Cs25519Point = string; + +// 32-byte value representing a scalar multiplier +// for scalar operations on points on Curve25519. +type Cs25519Scalar = string; + +/// +/// KEYS +/// + +// 16-byte access token used to authorize access. +type ClaimToken = string; + +// EdDSA and ECDHE public keys always point on Curve25519 +// and represented using the standard 256 bits Ed25519 compact format, +// converted to Crockford Base32. type EddsaPublicKey = string; -type EddsaSignature = string; + +// EdDSA and ECDHE public keys always point on Curve25519 +// and represented using the standard 256 bits Ed25519 compact format, +// converted to Crockford Base32. +type EddsaPrivateKey = string; + +// Edx25519 public keys are points on Curve25519 and represented using the +// standard 256 bits Ed25519 compact format converted to Crockford +// Base32. +type Edx25519PublicKey = string; + +// Edx25519 private keys are always points on Curve25519 +// and represented using the standard 256 bits Ed25519 compact format, +// converted to Crockford Base32. +type Edx25519PrivateKey = string; + +// EdDSA and ECDHE public keys always point on Curve25519 +// and represented using the standard 256 bits Ed25519 compact format, +// converted to Crockford Base32. +type EcdhePublicKey = string; + +// Point on Curve25519 represented using the standard 256 bits Ed25519 compact format, +// converted to Crockford Base32. +type CsRPublic = string; + +// EdDSA and ECDHE public keys always point on Curve25519 +// and represented using the standard 256 bits Ed25519 compact format, +// converted to Crockford Base32. +type EcdhePrivateKey = string; + +type CoinPublicKey = EddsaPublicKey; + +// RSA public key converted to Crockford Base32. +type RsaPublicKey = string; + +type Integer = number; + type WireTransferIdentifierRawP = string; -type RelativeTime = { - d_us: number | "forever" -}; +// Subset of numbers: Integers in the +// inclusive range 0 .. (2^53 - 1). +type SafeUint64 = number; + +// The string must be a data URL according to RFC 2397 +// with explicit mediatype and base64 parameters. +// +// data:;base64, +// +// Supported mediatypes are image/jpeg and image/png. +// Invalid strings will be rejected by the wallet. type ImageDataUrl = string; -interface WithId { - id: string; -} + +// :. +type Amount = string; + +type WadId = string; interface Timestamp { - // Milliseconds since epoch, or the special - // value "forever" to represent an event that will + // Seconds since epoch, or the special + // value "never" to represent an event that will // never happen. t_s: number | "never"; } -interface Duration { + +interface RelativeTime { + // Duration in microseconds or "forever" + // to represent an infinite duration. Numeric + // values are capped at 2^53 - 1 inclusive. d_us: number | "forever"; } -interface WithId { - id: string; -} - -type UUID = string; -type Integer = number; - -type Amount = string; - - export interface LoginToken { token: AccessToken, expiration: Timestamp, @@ -78,7 +156,7 @@ export namespace TalerAuthentication { } } -interface CurrencySpecification { +export interface CurrencySpecification { // Name of the currency. name: string; @@ -262,53 +340,173 @@ export const codecForGlobalCashouts = export const codecForGlobalCashoutInfo = (): Codec => buildCodecForObject() - .property("cashout_id", codecForString()) - .property("username", codecForString()) - .property("status", codecForEither(codecForConstString("pending"), codecForConstString("confirmed"),)) + .property("cashout_id", codecForString()) + .property("username", codecForString()) + .property("status", codecForEither(codecForConstString("pending"), codecForConstString("confirmed"),)) .build("TalerCorebankApi.GlobalCashoutInfo"); export const codecForCashoutStatusResponse = (): Codec => buildCodecForObject() - .property("amount_credit", codecForAmountString()) - .property("amount_debit", codecForAmountString()) - .property("confirmation_time", codecForTimestamp) - .property("creation_time", codecForTimestamp) - .property("credit_payto_uri", codecForPaytoURI()) - .property("status", codecForEither(codecForConstString("pending"), codecForConstString("confirmed"))) - .property("subject", codecForString()) - .build("TalerCorebankApi.CashoutStatusResponse"); + .property("amount_credit", codecForAmountString()) + .property("amount_debit", codecForAmountString()) + .property("confirmation_time", codecForTimestamp) + .property("creation_time", codecForTimestamp) + .property("credit_payto_uri", codecForPaytoURI()) + .property("status", codecForEither(codecForConstString("pending"), codecForConstString("confirmed"))) + .property("subject", codecForString()) + .build("TalerCorebankApi.CashoutStatusResponse"); export const codecForConversionRatesResponse = (): Codec => buildCodecForObject() - .property("buy_at_ratio", codecForDecimalNumber()) - .property("buy_in_fee", codecForDecimalNumber()) - .property("sell_at_ratio", codecForDecimalNumber()) - .property("sell_out_fee", codecForDecimalNumber()) - .build("TalerCorebankApi.ConversionRatesResponse"); + .property("buy_at_ratio", codecForDecimalNumber()) + .property("buy_in_fee", codecForDecimalNumber()) + .property("sell_at_ratio", codecForDecimalNumber()) + .property("sell_out_fee", codecForDecimalNumber()) + .build("TalerCorebankApi.ConversionRatesResponse"); export const codecForMonitorResponse = (): Codec => buildCodecForObject() - .property("cashinCount", codecForNumber()) - .property("cashinExternalVolume", codecForAmountString()) - .property("cashoutCount", codecForNumber()) - .property("cashoutExternalVolume", codecForAmountString()) - .property("talerPayoutCount", codecForNumber()) - .property("talerPayoutInternalVolume", codecForAmountString()) - .build("TalerCorebankApi.MonitorResponse"); + .property("cashinCount", codecForNumber()) + .property("cashinExternalVolume", codecForAmountString()) + .property("cashoutCount", codecForNumber()) + .property("cashoutExternalVolume", codecForAmountString()) + .property("talerPayoutCount", codecForNumber()) + .property("talerPayoutInternalVolume", codecForAmountString()) + .build("TalerCorebankApi.MonitorResponse"); + +export const codecForBankVersion = + (): Codec => + buildCodecForObject() + .property("currency", codecForCurrencyName()) + .property("currency_specification", codecForCurrencySpecificiation()) + .property("name", codecForConstString("taler-bank-integration")) + .property("version", codecForLibtoolVersion()) + .build("TalerBankIntegrationApi.BankVersion"); + +export const codecForBankWithdrawalOperationStatus = + (): Codec => + buildCodecForObject() + .property("aborted", codecForBoolean()) + .property("amount", codecForAmountString()) + .property("confirm_transfer_url", codecOptional(codecForURL())) + .property("selection_done", codecForBoolean()) + .property("sender_wire", codecForPaytoURI()) + .property("suggested_exchange", codecOptional(codecForString())) + .property("transfer_done", codecForBoolean()) + .property("wire_types", codecForList(codecForString())) + .build("TalerBankIntegrationApi.BankWithdrawalOperationStatus"); + +export const codecForBankWithdrawalOperationPostResponse = + (): Codec => + buildCodecForObject() + .property("confirm_transfer_url", codecForURL()) + .property("transfer_done", codecForBoolean()) + .build("TalerBankIntegrationApi.BankWithdrawalOperationPostResponse"); + +export const codecForMerchantIncomingHistory = + (): Codec => + buildCodecForObject() + .property("credit_account", codecForPaytoURI()) + .property("incoming_transactions", codecForList(codecForMerchantIncomingBankTransaction())) + .build("TalerRevenueApi.MerchantIncomingHistory"); + +export const codecForMerchantIncomingBankTransaction = + (): Codec => + buildCodecForObject() + .property("amount", codecForAmountString()) + .property("date", codecForTimestamp) + .property("debit_account", codecForPaytoURI()) + .property("exchange_url", codecForURL()) + .property("row_id", codecForNumber()) + .property("wtid", codecForString()) + .build("TalerRevenueApi.MerchantIncomingBankTransaction"); + +export const codecForTransferResponse = + (): Codec => + buildCodecForObject() + .property("row_id", codecForNumber()) + .property("timestamp", codecForTimestamp) + .build("TalerWireGatewayApi.TransferResponse"); + +export const codecForIncomingHistory = + (): Codec => + buildCodecForObject() + .property("credit_account", codecForString()) + .property("incoming_transactions", codecForList(codecForIncomingBankTransaction())) + .build("TalerWireGatewayApi.IncomingHistory"); + +export const codecForIncomingBankTransaction = (): Codec => buildCodecForUnion() + .discriminateOn("type") + .alternative("RESERVE", codecForIncomingReserveTransaction()) + .alternative("WAD", codecForIncomingWadTransaction()) + .build("TalerWireGatewayApi.IncomingBankTransaction"); + +export const codecForIncomingReserveTransaction = + (): Codec => + buildCodecForObject() + .property("amount", codecForAmountString()) + .property("date", codecForTimestamp) + .property("debit_account", codecForPaytoURI()) + .property("reserve_pub", codecForString()) + .property("row_id", codecForNumber()) + .property("type", codecForConstString("RESERVE")) + .build("TalerWireGatewayApi.IncomingReserveTransaction"); + +export const codecForIncomingWadTransaction = + (): Codec => + buildCodecForObject() + .property("amount", codecForAmountString()) + .property("credit_account", codecForPaytoURI()) + .property("date", codecForTimestamp) + .property("debit_account", codecForPaytoURI()) + .property("origin_exchange_url", codecForURL()) + .property("row_id", codecForNumber()) + .property("type", codecForConstString("WAD")) + .property("wad_id", codecForString()) + .build("TalerWireGatewayApi.IncomingWadTransaction"); + +export const codecForOutgoingHistory = + (): Codec => + buildCodecForObject() + .property("debit_account", codecForString()) + .property("outgoing_transactions", codecForList(codecForOutgoingBankTransaction())) + .build("TalerWireGatewayApi.OutgoingHistory"); + +export const codecForOutgoingBankTransaction = + (): Codec => + buildCodecForObject() + .property("amount", codecForAmountString()) + .property("credit_account", codecForPaytoURI()) + .property("date", codecForTimestamp) + .property("exchange_base_url", codecForURL()) + .property("row_id", codecForNumber()) + .property("wtid", codecForString()) + .build("TalerWireGatewayApi.OutgoingBankTransaction"); + +export const codecForAddIncomingResponse = + (): Codec => + buildCodecForObject() + .property("row_id", codecForNumber()) + .property("timestamp", codecForTimestamp) + .build("TalerWireGatewayApi.AddIncomingResponse"); // export const codecFor = -// (): Codec => -// buildCodecForObject() +// (): Codec => +// buildCodecForObject() // .property("", codecForString()) -// .build("TalerCorebankApi.PublicAccountsResponse"); +// .build("TalerWireGatewayApi.PublicAccountsResponse"); + type EmailAddress = string; type PhoneNumber = string; type DecimalNumber = string; +const codecForURL = codecForString +const codecForLibtoolVersion = codecForString +const codecForCurrencyName = codecForString const codecForPaytoURI = codecForString const codecForTalerWithdrawalURI = codecForString const codecForDecimalNumber = codecForString @@ -319,7 +517,289 @@ enum TanChannel { FILE = "file" } +export namespace TalerWireGatewayApi { + export interface TransferResponse { + + // Timestamp that indicates when the wire transfer will be executed. + // In cases where the wire transfer gateway is unable to know when + // the wire transfer will be executed, the time at which the request + // has been received and stored will be returned. + // The purpose of this field is for debugging (humans trying to find + // the transaction) as well as for taxation (determining which + // time period a transaction belongs to). + timestamp: Timestamp; + + // Opaque ID of the transaction that the bank has made. + row_id: SafeUint64; + } + + export interface TransferRequest { + // Nonce to make the request idempotent. Requests with the same + // transaction_uid that differ in any of the other fields + // are rejected. + request_uid: HashCode; + + // Amount to transfer. + amount: Amount; + + // Base URL of the exchange. Shall be included by the bank gateway + // in the appropriate section of the wire transfer details. + exchange_base_url: string; + + // Wire transfer identifier chosen by the exchange, + // used by the merchant to identify the Taler order(s) + // associated with this wire transfer. + wtid: ShortHashCode; + + // The recipient's account identifier as a payto URI. + credit_account: string; + } + + export interface IncomingHistory { + + // Array of incoming transactions. + incoming_transactions: IncomingBankTransaction[]; + + // Payto URI to identify the receiver of funds. + // This must be one of the exchange's bank accounts. + // Credit account is shared by all incoming transactions + // as per the nature of the request. + credit_account: string; + + } + + // Union discriminated by the "type" field. + export type IncomingBankTransaction = + | IncomingReserveTransaction + | IncomingWadTransaction; + + export interface IncomingReserveTransaction { + type: "RESERVE"; + + // Opaque identifier of the returned record. + row_id: SafeUint64; + + // Date of the transaction. + date: Timestamp; + + // Amount transferred. + amount: Amount; + + // Payto URI to identify the sender of funds. + debit_account: string; + + // The reserve public key extracted from the transaction details. + reserve_pub: EddsaPublicKey; + + } + + export interface IncomingWadTransaction { + type: "WAD"; + + // Opaque identifier of the returned record. + row_id: SafeUint64; + + // Date of the transaction. + date: Timestamp; + + // Amount transferred. + amount: Amount; + + // Payto URI to identify the receiver of funds. + // This must be one of the exchange's bank accounts. + credit_account: string; + + // Payto URI to identify the sender of funds. + debit_account: string; + + // Base URL of the exchange that originated the wad. + origin_exchange_url: string; + + // The reserve public key extracted from the transaction details. + wad_id: WadId; + } + + + export interface OutgoingHistory { + + // Array of outgoing transactions. + outgoing_transactions: OutgoingBankTransaction[]; + + // Payto URI to identify the sender of funds. + // This must be one of the exchange's bank accounts. + // Credit account is shared by all incoming transactions + // as per the nature of the request. + debit_account: string; + + } + + export interface OutgoingBankTransaction { + + // Opaque identifier of the returned record. + row_id: SafeUint64; + + // Date of the transaction. + date: Timestamp; + + // Amount transferred. + amount: Amount; + + // Payto URI to identify the receiver of funds. + credit_account: string; + + // The wire transfer ID in the outgoing transaction. + wtid: ShortHashCode; + + // Base URL of the exchange. + exchange_base_url: string; + } + + export interface AddIncomingRequest { + // Amount to transfer. + amount: Amount; + + // Reserve public key that is included in the wire transfer details + // to identify the reserve that is being topped up. + reserve_pub: EddsaPublicKey; + + // Account (as payto URI) that makes the wire transfer to the exchange. + // Usually this account must be created by the test harness before this API is + // used. An exception is the "exchange-fakebank", where any debit account can be + // specified, as it is automatically created. + debit_account: string; + } + + export interface AddIncomingResponse { + + // Timestamp that indicates when the wire transfer will be executed. + // In cases where the wire transfer gateway is unable to know when + // the wire transfer will be executed, the time at which the request + // has been received and stored will be returned. + // The purpose of this field is for debugging (humans trying to find + // the transaction) as well as for taxation (determining which + // time period a transaction belongs to). + timestamp: Timestamp; + + // Opaque ID of the transaction that the bank has made. + row_id: SafeUint64; + } + + + +} + +export namespace TalerRevenueApi { + export interface MerchantIncomingHistory { + + // Array of incoming transactions. + incoming_transactions: MerchantIncomingBankTransaction[]; + + // Payto URI to identify the receiver of funds. + // This must be one of the merchant's bank accounts. + // Credit account is shared by all incoming transactions + // as per the nature of the request. + credit_account: string; + + } + + export interface MerchantIncomingBankTransaction { + + // Opaque identifier of the returned record. + row_id: SafeUint64; + + // Date of the transaction. + date: Timestamp; + + // Amount transferred. + amount: Amount; + + // Payto URI to identify the sender of funds. + debit_account: string; + + // Base URL of the exchange where the transfer originated form. + exchange_url: string; + + // The wire transfer identifier. + wtid: WireTransferIdentifierRawP; + } +} + +export namespace TalerBankIntegrationApi { + export interface BankVersion { + // libtool-style representation of the Bank protocol version, see + // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning + // The format is "current:revision:age". + version: string; + + // Currency used by this bank. + currency: string; + + // How the bank SPA should render this currency. + currency_specification: CurrencySpecification; + + // Name of the API. + name: "taler-bank-integration"; + } + + export interface BankWithdrawalOperationStatus { + // Indicates whether the withdrawal was aborted. + aborted: boolean; + + // Has the wallet selected parameters for the withdrawal operation + // (exchange and reserve public key) and successfully sent it + // to the bank? + selection_done: boolean; + + // The transfer has been confirmed and registered by the bank. + // Does not guarantee that the funds have arrived at the exchange already. + transfer_done: boolean; + + // Amount that will be withdrawn with this operation + // (raw amount without fee considerations). + amount: Amount; + + // Bank account of the customer that is withdrawing, as a + // payto URI. + sender_wire?: string; + + // Suggestion for an exchange given by the bank. + suggested_exchange?: string; + + // URL that the user needs to navigate to in order to + // complete some final confirmation (e.g. 2FA). + // It may contain withdrawal operation id + confirm_transfer_url?: string; + + // Wire transfer types supported by the bank. + wire_types: string[]; + } + + export interface BankWithdrawalOperationPostRequest { + + // Reserve public key. + reserve_pub: string; + + // Payto address of the exchange selected for the withdrawal. + selected_exchange: string; + } + + export interface BankWithdrawalOperationPostResponse { + + // The transfer has been confirmed and registered by the bank. + // Does not guarantee that the funds have arrived at the exchange already. + transfer_done: boolean; + + // URL that the user needs to navigate to in order to + // complete some final confirmation (e.g. 2FA). + // + // Only applicable when transfer_done is false. + // It may contain withdrawal operation id + confirm_transfer_url?: string; + } + + +} export namespace TalerCorebankApi { export interface Config { @@ -648,21 +1128,21 @@ export namespace TalerCorebankApi { // Exchange rate to buy the local currency from the external one buy_at_ratio: DecimalNumber; - + // Exchange rate to sell the local currency for the external one sell_at_ratio: DecimalNumber; - + // Fee to subtract after applying the buy ratio. buy_in_fee: DecimalNumber; - + // Fee to subtract after applying the sell ratio. sell_out_fee: DecimalNumber; } - - export enum MonitorTimeframeParam{ + + export enum MonitorTimeframeParam { hour, day, month, year, decade, } - + export interface MonitorResponse { // This number identifies how many cashin operations diff --git a/packages/taler-util/src/http-client/utils.ts b/packages/taler-util/src/http-client/utils.ts index ecb4d14c4..4588f945c 100644 --- a/packages/taler-util/src/http-client/utils.ts +++ b/packages/taler-util/src/http-client/utils.ts @@ -31,9 +31,10 @@ export function addPaginationParams(url: URL, pagination?: PaginationParams) { if (pagination.offset) { url.searchParams.set("start", pagination.offset) } - if (pagination.limit) { - url.searchParams.set("delta", String(pagination.limit)) - } + const order = !pagination || pagination.order === "asc" ? 1 : -1 + const limit = !pagination || !pagination.limit || pagination.limit === 0 ? 5 : Math.abs(pagination.limit) + //always send delta + url.searchParams.set("delta", String(order * limit)) } export type UserAndPassword = { @@ -53,10 +54,15 @@ export type PaginationParams = { offset?: string, /** * max number of element in the result response + * always greater than 0 */ limit?: number, /** * milliseconds the server should wait for at least one result to be shown */ timoutMs?: number, + /** + * order + */ + order: "asc" | "dec" }