diff options
Diffstat (limited to 'packages/taler-util')
-rw-r--r-- | packages/taler-util/src/http-client/bank-conversion.ts | 30 | ||||
-rw-r--r-- | packages/taler-util/src/http-client/bank-core.ts | 88 | ||||
-rw-r--r-- | packages/taler-util/src/http-client/bank-integration.ts | 14 | ||||
-rw-r--r-- | packages/taler-util/src/http-client/bank-revenue.ts | 2 | ||||
-rw-r--r-- | packages/taler-util/src/http-client/bank-wire.ts | 19 | ||||
-rw-r--r-- | packages/taler-util/src/http-client/types.ts | 197 |
6 files changed, 232 insertions, 118 deletions
diff --git a/packages/taler-util/src/http-client/bank-conversion.ts b/packages/taler-util/src/http-client/bank-conversion.ts index f53b6a661..2bc9fdb79 100644 --- a/packages/taler-util/src/http-client/bank-conversion.ts +++ b/packages/taler-util/src/http-client/bank-conversion.ts @@ -2,14 +2,18 @@ import { AmountJson, Amounts } from "../amounts.js"; import { HttpRequestLibrary } from "../http-common.js"; import { HttpStatusCode } from "../http-status-codes.js"; import { createPlatformHttpLib } from "../http.js"; -import { FailCasesByMethod, ResultByMethod, opKnownFailure, opSuccess, opUnknownFailure } from "../operation.js"; +import { FailCasesByMethod, ResultByMethod, opEmptySuccess, opKnownFailure, opSuccess, opUnknownFailure } from "../operation.js"; import { TalerErrorCode } from "../taler-error-codes.js"; import { codecForTalerErrorDetail } from "../wallet-types.js"; import { + AccessToken, + TalerBankConversionApi, + UserAndToken, codecForCashinConversionResponse, codecForCashoutConversionResponse, codecForConversionBankConfig } from "./types.js"; +import { makeBearerTokenAuthHeader } from "./utils.js"; export type TalerBankConversionResultByMethod<prop extends keyof TalerBankConversionHttpClient> = ResultByMethod<TalerBankConversionHttpClient, prop> export type TalerBankConversionErrorsByMethod<prop extends keyof TalerBankConversionHttpClient> = FailCasesByMethod<TalerBankConversionHttpClient, prop> @@ -70,7 +74,7 @@ export class TalerBankConversionHttpClient { } } case HttpStatusCode.Conflict: return opKnownFailure("amount-too-small", resp); - case HttpStatusCode.NotImplemented: return opKnownFailure("cashout-not-supported", resp); + case HttpStatusCode.NotImplemented: return opKnownFailure("conversion-not-supported", resp); default: return opUnknownFailure(resp, await resp.text()) } } @@ -103,11 +107,31 @@ export class TalerBankConversionHttpClient { } } case HttpStatusCode.Conflict: return opKnownFailure("amount-too-small", resp); - case HttpStatusCode.NotImplemented: return opKnownFailure("cashout-not-supported", resp); + case HttpStatusCode.NotImplemented: return opKnownFailure("conversion-not-supported", resp); default: return opUnknownFailure(resp, await resp.text()) } } + /** + * https://docs.taler.net/core/api-bank-conversion-info.html#post--conversion-rate + * + */ + async updateConversionRate(auth: AccessToken, body: TalerBankConversionApi.ConversionRate) { + const url = new URL(`conversion-rate`, this.baseUrl); + const resp = await this.httpLib.fetch(url.href, { + method: "POST", + headers: { + Authorization: makeBearerTokenAuthHeader(auth) + }, + body + }); + switch (resp.status) { + case HttpStatusCode.NoContent: return opEmptySuccess() + case HttpStatusCode.Unauthorized: return opKnownFailure("unauthorized", resp); + case HttpStatusCode.NotImplemented: return opKnownFailure("conversion-not-supported", resp); + default: return opUnknownFailure(resp, await resp.text()) + } + } } diff --git a/packages/taler-util/src/http-client/bank-core.ts b/packages/taler-util/src/http-client/bank-core.ts index 83adb6370..4557a34e4 100644 --- a/packages/taler-util/src/http-client/bank-core.ts +++ b/packages/taler-util/src/http-client/bank-core.ts @@ -15,8 +15,6 @@ */ import { - AmountJson, - Amounts, HttpStatusCode, LibtoolVersion, TalerErrorCode, @@ -28,12 +26,12 @@ import { } from "@gnu-taler/taler-util/http"; import { FailCasesByMethod, ResultByMethod, opEmptySuccess, opFixedSuccess, opKnownFailure, opSuccess, opUnknownFailure } from "../operation.js"; import { TalerAuthenticationHttpClient } from "./authentication.js"; +import { TalerBankConversionHttpClient } from "./bank-conversion.js"; import { TalerBankIntegrationHttpClient } from "./bank-integration.js"; import { TalerRevenueHttpClient } from "./bank-revenue.js"; import { TalerWireGatewayHttpClient } from "./bank-wire.js"; -import { AccessToken, PaginationParams, TalerCorebankApi, UserAndToken, codecForAccountData, codecForBankAccountCreateWithdrawalResponse, codecForBankAccountGetWithdrawalResponse, codecForBankAccountTransactionInfo, codecForBankAccountTransactionsResponse, codecForCashinConversionResponse, codecForCashoutConversionResponse, codecForCashoutPending, codecForCashoutStatusResponse, codecForCashouts, codecForCoreBankConfig, codecForGlobalCashouts, codecForListBankAccountsResponse, codecForMonitorResponse, codecForPublicAccountsResponse, codecForRegisterAccountResponse } from "./types.js"; +import { AccessToken, PaginationParams, TalerCorebankApi, UserAndToken, codecForAccountData, codecForBankAccountCreateWithdrawalResponse, codecForBankAccountTransactionInfo, codecForBankAccountTransactionsResponse, codecForCashoutPending, codecForCashoutStatusResponse, codecForCashouts, codecForCoreBankConfig, codecForCreateTransactionResponse, codecForGlobalCashouts, codecForListBankAccountsResponse, codecForMonitorResponse, codecForPublicAccountsResponse, codecForRegisterAccountResponse, codecForWithdrawalPublicInfo } from "./types.js"; import { addPaginationParams, makeBearerTokenAuthHeader } from "./utils.js"; -import { TalerBankConversionHttpClient } from "./bank-conversion.js"; export type TalerCoreBankResultByMethod<prop extends keyof TalerCoreBankHttpClient> = ResultByMethod<TalerCoreBankHttpClient, prop> @@ -62,7 +60,7 @@ export class TalerCoreBankHttpClient { } /** - * https://docs.taler.net/core/api-corebank.html#get--accounts-$USERNAME + * https://docs.taler.net/core/api-corebank.html#config * */ async getConfig() { @@ -157,10 +155,16 @@ export class TalerCoreBankHttpClient { case HttpStatusCode.NoContent: return opEmptySuccess() case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp); case HttpStatusCode.Unauthorized: return opKnownFailure("unauthorized", resp); - //FIXME: missing error code for cases: - // * change legal name - // * admin tries to change its own account - case HttpStatusCode.Forbidden: return opKnownFailure("cant-change-legal-name-or-admin", resp); + case HttpStatusCode.Conflict: { + const body = await resp.json() + const details = codecForTalerErrorDetail().decode(body) + switch (details.code) { + case TalerErrorCode.BANK_PATCH_ADMIN_EXCHANGE: return opKnownFailure("admin-cant-be-exchange", resp); + case TalerErrorCode.BANK_NON_ADMIN_PATCH_LEGAL_NAME: return opKnownFailure("user-cant-change-name", resp); + case TalerErrorCode.BANK_NON_ADMIN_PATCH_DEBT_LIMIT: return opKnownFailure("user-cant-change-debt", resp); + default: return opUnknownFailure(resp, body) + } + } default: return opUnknownFailure(resp, await resp.text()) } } @@ -182,25 +186,31 @@ export class TalerCoreBankHttpClient { case HttpStatusCode.NoContent: return opEmptySuccess() case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp); case HttpStatusCode.Unauthorized: return opKnownFailure("unauthorized", resp); - //FIXME: add code to split cases - // * An admin account tried to make its account an exchange - // * A non-admin user tried to change properties reserved for the admin - case HttpStatusCode.Forbidden: return opKnownFailure("old-password-invalid-or-not-allowed", resp); + case HttpStatusCode.Conflict: { + const body = await resp.json() + const details = codecForTalerErrorDetail().decode(body) + switch (details.code) { + case TalerErrorCode.BANK_NON_ADMIN_PATCH_MISSING_OLD_PASSWORD: return opKnownFailure("user-require-old-password", resp); + case TalerErrorCode.BANK_PATCH_BAD_OLD_PASSWORD: return opKnownFailure("wrong-old-password", resp); + default: return opUnknownFailure(resp, body) + } + } default: return opUnknownFailure(resp, await resp.text()) } } /** - * https://docs.taler.net/core/get-$BANK_API_BASE_URL-public-accounts + * https://docs.taler.net/core/api-corebank.html#get--public-accounts * */ - async getPublicAccounts(pagination?: PaginationParams) { + async getPublicAccounts(filter: { account?: string } = {}, pagination?: PaginationParams) { const url = new URL(`public-accounts`, this.baseUrl); addPaginationParams(url, pagination) + if (filter.account !== undefined) { + url.searchParams.set("filter_name", filter.account) + } const resp = await this.httpLib.fetch(url.href, { method: "GET", - headers: { - }, }); switch (resp.status) { case HttpStatusCode.Ok: return opSuccess(resp, codecForPublicAccountsResponse()) @@ -217,7 +227,7 @@ export class TalerCoreBankHttpClient { async getAccounts(auth: AccessToken, filter: { account?: string } = {}, pagination?: PaginationParams) { const url = new URL(`accounts`, this.baseUrl); addPaginationParams(url, pagination) - if (filter.account) { + if (filter.account !== undefined) { url.searchParams.set("filter_name", filter.account) } const resp = await this.httpLib.fetch(url.href, { @@ -259,7 +269,7 @@ export class TalerCoreBankHttpClient { // /** - * https://docs.taler.net/core/api-corebank.html#get-$BANK_API_BASE_URL-accounts-$account_name-transactions + * https://docs.taler.net/core/api-corebank.html#get--accounts-$USERNAME-transactions * */ async getTransactions(auth: UserAndToken, pagination?: PaginationParams) { @@ -274,14 +284,14 @@ export class TalerCoreBankHttpClient { switch (resp.status) { case HttpStatusCode.Ok: return opSuccess(resp, codecForBankAccountTransactionsResponse()) case HttpStatusCode.NoContent: return opFixedSuccess({ transactions: [] }) - case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp); case HttpStatusCode.Unauthorized: return opKnownFailure("unauthorized", resp); + case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp); default: return opUnknownFailure(resp, await resp.text()) } } /** - * https://docs.taler.net/core/api-corebank.html#get-$BANK_API_BASE_URL-accounts-$account_name-transactions-$transaction_id + * https://docs.taler.net/core/api-corebank.html#get--accounts-$USERNAME-transactions-$TRANSACTION_ID * */ async getTransactionById(auth: UserAndToken, txid: number) { @@ -301,10 +311,10 @@ export class TalerCoreBankHttpClient { } /** - * https://docs.taler.net/core/api-corebank.html#post-$BANK_API_BASE_URL-accounts-$account_name-transactions + * https://docs.taler.net/core/api-corebank.html#post--accounts-$USERNAME-transactions * */ - async createTransaction(auth: UserAndToken, body: TalerCorebankApi.CreateBankAccountTransactionCreate) { + async createTransaction(auth: UserAndToken, body: TalerCorebankApi.CreateTransactionRequest) { const url = new URL(`accounts/${auth.username}/transactions`, this.baseUrl); const resp = await this.httpLib.fetch(url.href, { method: "POST", @@ -314,8 +324,7 @@ export class TalerCoreBankHttpClient { body, }); switch (resp.status) { - //FIXME: expect txid as response - case HttpStatusCode.NoContent: return opEmptySuccess() + case HttpStatusCode.Ok: return opSuccess(resp, codecForCreateTransactionResponse()) case HttpStatusCode.BadRequest: return opKnownFailure("invalid-input", resp); case HttpStatusCode.Unauthorized: return opKnownFailure("unauthorized", resp); case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp); @@ -338,7 +347,7 @@ export class TalerCoreBankHttpClient { // /** - * https://docs.taler.net/core/api-corebank.html#post-$BANK_API_BASE_URL-accounts-$account_name-withdrawals + * https://docs.taler.net/core/api-corebank.html#post--accounts-$USERNAME-withdrawals * */ async createWithdrawal(auth: UserAndToken, body: TalerCorebankApi.BankAccountCreateWithdrawalRequest) { @@ -360,13 +369,16 @@ export class TalerCoreBankHttpClient { } /** - * https://docs.taler.net/core/api-corebank.html#post-$BANK_API_BASE_URL-withdrawals-$withdrawal_id-abort + * https://docs.taler.net/core/api-corebank.html#post--accounts-$USERNAME-withdrawals-$WITHDRAWAL_ID-abort * */ - async abortWithdrawalById(wid: string) { - const url = new URL(`withdrawals/${wid}/abort`, this.baseUrl); + async abortWithdrawalById(auth: UserAndToken, wid: string) { + const url = new URL(`accounts/${auth.username}/withdrawals/${wid}/abort`, this.baseUrl); const resp = await this.httpLib.fetch(url.href, { method: "POST", + headers: { + Authorization: makeBearerTokenAuthHeader(auth.token) + }, }); switch (resp.status) { case HttpStatusCode.NoContent: return opEmptySuccess() @@ -379,13 +391,16 @@ export class TalerCoreBankHttpClient { } /** - * https://docs.taler.net/core/api-corebank.html#post-$BANK_API_BASE_URL-withdrawals-$withdrawal_id-confirm + * https://docs.taler.net/core/api-corebank.html#post--accounts-$USERNAME-withdrawals-$WITHDRAWAL_ID-confirm * */ - async confirmWithdrawalById(wid: string) { - const url = new URL(`withdrawals/${wid}/confirm`, this.baseUrl); + async confirmWithdrawalById(auth: UserAndToken, wid: string) { + const url = new URL(`accounts/${auth.username}/withdrawals/${wid}/confirm`, this.baseUrl); const resp = await this.httpLib.fetch(url.href, { method: "POST", + headers: { + Authorization: makeBearerTokenAuthHeader(auth.token) + }, }); switch (resp.status) { case HttpStatusCode.NoContent: return opEmptySuccess() @@ -396,9 +411,9 @@ export class TalerCoreBankHttpClient { const body = await resp.json() const details = codecForTalerErrorDetail().decode(body) switch (details.code) { - case TalerErrorCode.BANK_UNALLOWED_DEBIT: return opKnownFailure("insufficient-funds", resp); - case TalerErrorCode.BANK_CONFIRM_INCOMPLETE: return opKnownFailure("no-exchange-or-reserve-selected", resp); case TalerErrorCode.BANK_CONFIRM_ABORT_CONFLICT: return opKnownFailure("previously-aborted", resp); + case TalerErrorCode.BANK_CONFIRM_INCOMPLETE: return opKnownFailure("no-exchange-or-reserve-selected", resp); + case TalerErrorCode.BANK_UNALLOWED_DEBIT: return opKnownFailure("insufficient-funds", resp); default: return opUnknownFailure(resp, body) } } @@ -407,7 +422,7 @@ export class TalerCoreBankHttpClient { } /** - * https://docs.taler.net/core/api-corebank.html#post-$BANK_API_BASE_URL-accounts-$account_name-withdrawals + * https://docs.taler.net/core/api-corebank.html#get--withdrawals-$WITHDRAWAL_ID * */ async getWithdrawalById(wid: string) { @@ -416,7 +431,7 @@ export class TalerCoreBankHttpClient { method: "GET", }); switch (resp.status) { - case HttpStatusCode.Ok: return opSuccess(resp, codecForBankAccountGetWithdrawalResponse()) + case HttpStatusCode.Ok: return opSuccess(resp, codecForWithdrawalPublicInfo()) //FIXME: missing in docs case HttpStatusCode.BadRequest: return opKnownFailure("invalid-id", resp) case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp) @@ -477,7 +492,6 @@ export class TalerCoreBankHttpClient { case HttpStatusCode.NoContent: return opEmptySuccess() case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp); case HttpStatusCode.Conflict: return opKnownFailure("already-confirmed", resp); - //FIXME: should be 404 ? case HttpStatusCode.NotImplemented: return opKnownFailure("cashout-not-supported", resp); default: return opUnknownFailure(resp, await resp.text()) } diff --git a/packages/taler-util/src/http-client/bank-integration.ts b/packages/taler-util/src/http-client/bank-integration.ts index b526805df..d552d3b76 100644 --- a/packages/taler-util/src/http-client/bank-integration.ts +++ b/packages/taler-util/src/http-client/bank-integration.ts @@ -43,13 +43,17 @@ export class TalerBankIntegrationHttpClient { } /** - * https://docs.taler.net/core/api-bank-integration.html#get-$BANK_API_BASE_URL-withdrawal-operation-$wopid + * https://docs.taler.net/core/api-bank-integration.html#get--withdrawal-operation-$WITHDRAWAL_ID * */ - async getWithdrawalOperationById(woid: string, timeoutMs?: number) { + async getWithdrawalOperationById(woid: string, wait?: { + old_state?: "pending" | "selected" | "aborted" | "confirmed", + timeoutMs: number + }) { const url = new URL(`withdrawal-operation/${woid}`, this.baseUrl); - if (timeoutMs) { - url.searchParams.set("long_poll_ms", String(timeoutMs)) + if (wait) { + url.searchParams.set("long_poll_ms", String(wait.timeoutMs)) + url.searchParams.set("old_state", !wait.old_state ? "pending" : wait.old_state) } const resp = await this.httpLib.fetch(url.href, { method: "GET" @@ -80,7 +84,7 @@ export class TalerBankIntegrationHttpClient { switch (details.code) { case TalerErrorCode.BANK_WITHDRAWAL_OPERATION_RESERVE_SELECTION_CONFLICT: return opKnownFailure("already-selected", resp); case TalerErrorCode.BANK_DUPLICATE_RESERVE_PUB_SUBJECT: return opKnownFailure("duplicated-reserve-id", resp); - // case TalerErrorCode.BANK_ACCOUNT_NOT_FOUND: return opKnownFailure("account-not-found", resp); + case TalerErrorCode.BANK_UNKNOWN_ACCOUNT: return opKnownFailure("account-not-found", resp); case TalerErrorCode.BANK_ACCOUNT_IS_NOT_EXCHANGE: return opKnownFailure("account-not-exchange", resp); default: return opUnknownFailure(resp, body) } diff --git a/packages/taler-util/src/http-client/bank-revenue.ts b/packages/taler-util/src/http-client/bank-revenue.ts index 14d93fbe6..040ad8dd2 100644 --- a/packages/taler-util/src/http-client/bank-revenue.ts +++ b/packages/taler-util/src/http-client/bank-revenue.ts @@ -24,7 +24,7 @@ export class TalerRevenueHttpClient { } /** - * https://docs.taler.net/core/api-bank-revenue.html#get-$BASE_URL-history + * https://docs.taler.net/core/api-bank-revenue.html#get--history * * @returns */ diff --git a/packages/taler-util/src/http-client/bank-wire.ts b/packages/taler-util/src/http-client/bank-wire.ts index 0d312704e..7e3c00637 100644 --- a/packages/taler-util/src/http-client/bank-wire.ts +++ b/packages/taler-util/src/http-client/bank-wire.ts @@ -27,12 +27,10 @@ export class TalerWireGatewayHttpClient { } /** - * https://docs.taler.net/core/api-bank-wire.html#post-$BASE_URL-transfer + * https://docs.taler.net/core/api-bank-wire.html#post--transfer * */ - async transfer( - auth: string, - body: TalerWireGatewayApi.TransferRequest, + async transfer(auth: string, body: TalerWireGatewayApi.TransferRequest, ) { const url = new URL(`transfer`, this.baseUrl); const resp = await this.httpLib.fetch(url.href, { @@ -53,7 +51,7 @@ export class TalerWireGatewayHttpClient { } /** - * https://docs.taler.net/core/api-bank-wire.html#get-$BASE_URL-history-incoming + * https://docs.taler.net/core/api-bank-wire.html#get--history-incoming * */ async getHistoryIncoming(auth: string, pagination?: PaginationParams) { @@ -67,7 +65,7 @@ export class TalerWireGatewayHttpClient { }); switch (resp.status) { case HttpStatusCode.Ok: return opSuccess(resp, codecForIncomingHistory()) - case HttpStatusCode.NoContent: return opFixedSuccess({ incoming_transactions: [], credit_account: "" }) + case HttpStatusCode.NoContent: return opFixedSuccess({ incoming_transactions: [] }) case HttpStatusCode.BadRequest: return opKnownFailure("invalid-input", resp); case HttpStatusCode.Unauthorized: return opKnownFailure("unauthorized", resp); case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp); @@ -75,8 +73,9 @@ export class TalerWireGatewayHttpClient { } // return readSuccessResponseJsonOrThrow(resp, codecForIncomingHistory()); } + /** - * https://docs.taler.net/core/api-bank-wire.html#get-$BASE_URL-history-outgoing + * https://docs.taler.net/core/api-bank-wire.html#get--history-outgoing * */ async getHistoryOutgoing(auth: string, pagination?: PaginationParams) { @@ -90,15 +89,16 @@ export class TalerWireGatewayHttpClient { }); switch (resp.status) { case HttpStatusCode.Ok: return opSuccess(resp, codecForOutgoingHistory()) - case HttpStatusCode.NoContent: return opFixedSuccess({ outgoing_transactions: [], debit_account: "" }) + case HttpStatusCode.NoContent: return opFixedSuccess({ outgoing_transactions: [] }) case HttpStatusCode.BadRequest: return opKnownFailure("invalid-input", resp); case HttpStatusCode.Unauthorized: return opKnownFailure("unauthorized", resp); case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp); default: return opUnknownFailure(resp, await resp.text()) } } + /** - * https://docs.taler.net/core/api-bank-wire.html#post-$BASE_URL-admin-add-incoming + * https://docs.taler.net/core/api-bank-wire.html#post--admin-add-incoming * */ async addIncoming(auth: string, body: TalerWireGatewayApi.AddIncomingRequest,) { @@ -112,7 +112,6 @@ export class TalerWireGatewayHttpClient { }); switch (resp.status) { case HttpStatusCode.Ok: return opSuccess(resp, codecForAddIncomingResponse()) - case HttpStatusCode.NoContent: return opFixedSuccess({ outgoing_transactions: [], debit_account: "" }) case HttpStatusCode.BadRequest: return opKnownFailure("invalid-input", resp); case HttpStatusCode.Unauthorized: return opKnownFailure("unauthorized", resp); case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp); diff --git a/packages/taler-util/src/http-client/types.ts b/packages/taler-util/src/http-client/types.ts index 153cb340c..d9cc8ec90 100644 --- a/packages/taler-util/src/http-client/types.ts +++ b/packages/taler-util/src/http-client/types.ts @@ -264,6 +264,7 @@ export const codecForIntegrationBankConfig = .property("name", codecForConstString("taler-bank-integration")) .property("version", codecForString()) .property("currency", codecForString()) + .property("currency_specification", codecForCurrencySpecificiation()) .build("TalerCorebankApi.IntegrationConfig"); export const codecForCoreBankConfig = (): Codec<TalerCorebankApi.Config> => @@ -353,6 +354,12 @@ export const codecForChallengeContactData = .property("phone", codecOptional(codecForString())) .build("TalerCorebankApi.ChallengeContactData"); +export const codecForWithdrawalPublicInfo = + (): Codec<TalerCorebankApi.WithdrawalPublicInfo> => + buildCodecForObject<TalerCorebankApi.WithdrawalPublicInfo>() + .property("username", codecForString(),) + .build("TalerCorebankApi.WithdrawalPublicInfo"); + export const codecForBankAccountTransactionsResponse = (): Codec<TalerCorebankApi.BankAccountTransactionsResponse> => buildCodecForObject<TalerCorebankApi.BankAccountTransactionsResponse>() @@ -381,6 +388,12 @@ export const codecForBankAccountTransactionInfo = .build("TalerCorebankApi.BankAccountTransactionInfo"); +export const codecForCreateTransactionResponse = + (): Codec<TalerCorebankApi.CreateTransactionResponse> => + buildCodecForObject<TalerCorebankApi.CreateTransactionResponse>() + .property("row_id", codecForNumber()) + .build("TalerCorebankApi.CreateTransactionResponse"); + export const codecForRegisterAccountResponse = (): Codec<TalerCorebankApi.RegisterAccountResponse> => buildCodecForObject<TalerCorebankApi.RegisterAccountResponse>() @@ -395,19 +408,19 @@ export const codecForBankAccountCreateWithdrawalResponse = .property("withdrawal_id", codecForString()) .build("TalerCorebankApi.BankAccountCreateWithdrawalResponse"); -export const codecForBankAccountGetWithdrawalResponse = - (): Codec<TalerCorebankApi.BankAccountGetWithdrawalResponse> => - buildCodecForObject<TalerCorebankApi.BankAccountGetWithdrawalResponse>() - .property("amount", codecForAmountString()) - .property("aborted", codecForBoolean()) - .property("confirmation_done", codecForBoolean()) - .property( - "selected_exchange_account", - codecOptional(codecForPaytoString()), - ) - .property("selected_reserve_pub", codecOptional(codecForString())) - .property("selection_done", codecForBoolean()) - .build("TalerCorebankApi.BankAccountGetWithdrawalResponse"); +// export const codecForBankAccountGetWithdrawalResponse = +// (): Codec<TalerCorebankApi.BankAccountGetWithdrawalResponse> => +// buildCodecForObject<TalerCorebankApi.BankAccountGetWithdrawalResponse>() +// .property("amount", codecForAmountString()) +// .property("aborted", codecForBoolean()) +// .property("confirmation_done", codecForBoolean()) +// .property( +// "selected_exchange_account", +// codecOptional(codecForPaytoString()), +// ) +// .property("selected_reserve_pub", codecOptional(codecForString())) +// .property("selection_done", codecForBoolean()) +// .build("TalerCorebankApi.BankAccountGetWithdrawalResponse"); export const codecForCashoutPending = (): Codec<TalerCorebankApi.CashoutPending> => @@ -484,7 +497,15 @@ export const codecForCashoutStatusResponse = codecForConstString("confirmed"), ), ) + .property( + "tan_channel", + codecForEither( + codecForConstString(TanChannel.SMS), + codecForConstString(TanChannel.EMAIL), + ), + ) .property("subject", codecForString()) + .property("tan_info", codecForString()) .build("TalerCorebankApi.CashoutStatusResponse"); export const codecForConversionRatesResponse = @@ -542,21 +563,30 @@ export const codecForBankVersion = export const codecForBankWithdrawalOperationStatus = (): Codec<TalerBankIntegrationApi.BankWithdrawalOperationStatus> => buildCodecForObject<TalerBankIntegrationApi.BankWithdrawalOperationStatus>() - .property("aborted", codecForBoolean()) - .property("selection_done", codecForBoolean()) - .property("transfer_done", codecForBoolean()) + .property("status", codecForEither( + codecForConstString("pending"), + codecForConstString("selected"), + codecForConstString("aborted"), + codecForConstString("confirmed") + )) .property("amount", codecForAmountString()) .property("sender_wire", codecOptional(codecForPaytoString())) .property("suggested_exchange", codecOptional(codecForString())) .property("confirm_transfer_url", codecOptional(codecForURL())) .property("wire_types", codecForList(codecForString())) + .property("selected_reserve_pub", codecOptional(codecForString())) + .property("selected_exchange_account", codecOptional(codecForString())) .build("TalerBankIntegrationApi.BankWithdrawalOperationStatus"); export const codecForBankWithdrawalOperationPostResponse = (): Codec<TalerBankIntegrationApi.BankWithdrawalOperationPostResponse> => buildCodecForObject<TalerBankIntegrationApi.BankWithdrawalOperationPostResponse>() + .property("status", codecForEither( + codecForConstString("selected"), + codecForConstString("aborted"), + codecForConstString("confirmed") + )) .property("confirm_transfer_url", codecOptional(codecForURL())) - .property("transfer_done", codecForBoolean()) .build("TalerBankIntegrationApi.BankWithdrawalOperationPostResponse"); export const codecForMerchantIncomingHistory = @@ -890,7 +920,9 @@ export namespace TalerWireGatewayApi { // 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: PaytoString; + + // undefined if incoming transaction is empty + credit_account?: PaytoString; } // Union discriminated by the "type" field. @@ -951,7 +983,9 @@ export namespace TalerWireGatewayApi { // 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: PaytoString; + + // undefined if outgoing transactions is empty + debit_account?: PaytoString; } export interface OutgoingBankTransaction { @@ -1113,6 +1147,40 @@ export namespace TalerBankConversionApi { // bank account, according to 'amount_debit'. amount_credit: AmountString; } + + export type RoundingMode = "zero" | "up" | "nearest"; + + export interface ConversionRate { + // Exchange rate to buy regional currency from fiat + cashin_ratio: DecimalNumber; + + // Fee to subtract after applying the cashin ratio. + cashin_fee: AmountString; + + // Minimum amount authorised for cashin, in fiat before conversion + cashin_min_amount: AmountString; + + // Smallest possible regional amount, converted amount is rounded to this amount + cashin_tiny_amount: AmountString; + + // Rounding mode used during cashin conversion + cashin_rounding_mode: RoundingMode; + + // Exchange rate to sell regional currency for fiat + cashout_ratio: DecimalNumber; + + // Fee to subtract after applying the cashout ratio. + cashout_fee: AmountString; + + // Minimum amount authorised for cashout, in regional before conversion + cashout_min_amount: AmountString; + + // Smallest possible fiat amount, converted amount is rounded to this amount + cashout_tiny_amount: AmountString; + + // Rounding mode used during cashout conversion + cashout_rounding_mode: RoundingMode; + } } export namespace TalerBankIntegrationApi { export interface BankVersion { @@ -1131,18 +1199,15 @@ export namespace TalerBankIntegrationApi { name: "taler-bank-integration"; } + export type WithdrawalOperationStatus = "pending" | "selected" | "aborted" | "confirmed" 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; + // Current status of the operation + // pending: the operation is pending parameters selection (exchange and reserve public key) + // selected: the operations has been selected and is pending confirmation + // aborted: the operation has been aborted + // confirmed: the transfer has been confirmed and registered by the bank + status: WithdrawalOperationStatus; - // 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). @@ -1162,6 +1227,14 @@ export namespace TalerBankIntegrationApi { // Wire transfer types supported by the bank. wire_types: string[]; + + // Reserve public key selected by the exchange, + // only non-null if status is selected or confirmed. + selected_reserve_pub?: string; + + // Exchange account selected by the wallet + // only non-null if status is selected or confirmed. + selected_exchange_account?: string; } export interface BankWithdrawalOperationPostRequest { @@ -1173,14 +1246,17 @@ export namespace TalerBankIntegrationApi { } 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; + // Current status of the operation + // pending: the operation is pending parameters selection (exchange and reserve public key) + // selected: the operations has been selected and is pending confirmation + // aborted: the operation has been aborted + // confirmed: the transfer has been confirmed and registered by the bank + status: Omit<"pending", WithdrawalOperationStatus>; // 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. + // Only applicable when status is selected. // It may contain withdrawal operation id confirm_transfer_url?: string; } @@ -1192,7 +1268,10 @@ export namespace TalerCorebankApi { // The format is "current:revision:age". version: string; - currency: String; + currency: string; + + // How the bank SPA should render this currency. + currency_specification: CurrencySpecification; // Name of the API. name: "taler-bank-integration"; @@ -1235,31 +1314,12 @@ export namespace TalerCorebankApi { // URI that can be passed to the wallet to initiate the withdrawal. taler_withdraw_uri: TalerActionString; } - export interface BankAccountGetWithdrawalResponse { - // Amount that will be withdrawn with this withdrawal operation. - amount: AmountString; - - // Was the withdrawal aborted? - aborted: boolean; - - // Has the withdrawal been confirmed by the bank? - // The wire transfer for a withdrawal is only executed once - // both confirmation_done is true and selection_done is true. - confirmation_done: boolean; - - // Did the wallet select reserve details? - selection_done: boolean; - - // Reserve public key selected by the exchange, - // only non-null if selection_done is true. - selected_reserve_pub: string | undefined; - - // Exchange account selected by the wallet, or by the bank - // (with the default exchange) in case the wallet did not provide one - // through the Integration API. - selected_exchange_account: PaytoString | undefined; + export interface WithdrawalPublicInfo { + // Account username + username: string; } + export interface BankAccountTransactionsResponse { transactions: BankAccountTransactionInfo[]; } @@ -1279,7 +1339,7 @@ export namespace TalerCorebankApi { date: Timestamp; } - export interface CreateBankAccountTransactionCreate { + export interface CreateTransactionRequest { // Address in the Payto format of the wire transfer receiver. // It needs at least the 'message' query string parameter. payto_uri: PaytoString; @@ -1291,6 +1351,11 @@ export namespace TalerCorebankApi { amount?: AmountString; } + export interface CreateTransactionResponse { + // ID identifying the transaction being created + row_id: Integer; + } + export interface RegisterAccountResponse { // Internal payto URI of this bank account. internal_payto_uri: PaytoString; @@ -1324,17 +1389,17 @@ export namespace TalerCorebankApi { // as well. challenge_contact_data?: ChallengeContactData; - // 'payto' address pointing a bank account - // external to the libeufin-bank. + // 'payto' address of a fiat bank account. // Payments will be sent to this bank account - // when the user wants to convert the local currency - // back to fiat currency outside libeufin-bank. + // when the user wants to convert the regional currency + // back to fiat currency outside bank. cashout_payto_uri?: PaytoString; // Internal payto URI of this bank account. // Used mostly for testing. internal_payto_uri?: PaytoString; } + export interface ChallengeContactData { // E-Mail address email?: EmailAddress; @@ -1525,6 +1590,14 @@ export namespace TalerCorebankApi { // Time when the cashout was confirmed via its TAN. // Missing when the operation wasn't confirmed yet. confirmation_time?: Timestamp; + + // Channel of the last successful transmission of the TAN challenge. + // Missing when all transmissions failed. + tan_channel?: TanChannel; + + // Info of the last successful transmission of the TAN challenge. + // Missing when all transmissions failed. + tan_info?: string; } export interface ConversionRatesResponse { |