aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian <sebasjm@gmail.com>2023-01-20 15:41:08 -0300
committerSebastian <sebasjm@gmail.com>2023-01-20 15:41:55 -0300
commit7ea8321ddd2d56f43dceaa18340f1d1c39a83e76 (patch)
tree9873eeb8fa836778d9c7fce1c6a778e7e8b6acaf
parent81dda3b6b1500ed11b6ae539ce52a6c7e9a58951 (diff)
downloadwallet-core-7ea8321ddd2d56f43dceaa18340f1d1c39a83e76.tar.xz
introducing getBalanceDetail for getting all depositable/transferable amount for a currency
-rw-r--r--packages/taler-util/src/wallet-types.ts21
-rw-r--r--packages/taler-wallet-core/src/operations/balance.ts50
-rw-r--r--packages/taler-wallet-core/src/operations/deposits.ts1
-rw-r--r--packages/taler-wallet-core/src/wallet-api-types.ts21
-rw-r--r--packages/taler-wallet-core/src/wallet.ts21
-rw-r--r--packages/taler-wallet-webextension/src/wallet/DestinationSelection/index.ts1
-rw-r--r--packages/taler-wallet-webextension/src/wallet/DestinationSelection/state.ts20
-rw-r--r--packages/taler-wallet-webextension/src/wallet/DestinationSelection/stories.tsx2
-rw-r--r--packages/taler-wallet-webextension/src/wallet/DestinationSelection/test.ts10
-rw-r--r--packages/taler-wallet-webextension/src/wallet/DestinationSelection/views.tsx11
-rw-r--r--packages/taler-wallet-webextension/src/wallet/History.tsx4
-rw-r--r--packages/taler-wallet-webextension/src/wxApi.ts4
-rw-r--r--packages/taler-wallet-webextension/src/wxBackend.ts14
13 files changed, 146 insertions, 34 deletions
diff --git a/packages/taler-util/src/wallet-types.ts b/packages/taler-util/src/wallet-types.ts
index fc383acb0..50cb50f30 100644
--- a/packages/taler-util/src/wallet-types.ts
+++ b/packages/taler-util/src/wallet-types.ts
@@ -105,6 +105,16 @@ export class CreateReserveResponse {
reservePub: string;
}
+export interface GetBalanceDetailRequest {
+ currency: string;
+}
+
+export const codecForGetBalanceDetailRequest = (): Codec<GetBalanceDetailRequest> =>
+ buildCodecForObject<GetBalanceDetailRequest>()
+ .property("currency", codecForString())
+ .build("GetBalanceDetailRequest");
+
+
export interface Balance {
available: AmountString;
pendingIncoming: AmountString;
@@ -215,11 +225,11 @@ export interface CoinDumpJson {
withdrawal_reserve_pub: string | undefined;
coin_status: CoinStatus;
spend_allocation:
- | {
- id: string;
- amount: string;
- }
- | undefined;
+ | {
+ id: string;
+ amount: string;
+ }
+ | undefined;
/**
* Information about the age restriction
*/
@@ -1792,6 +1802,7 @@ export const codecForUserAttentionsRequest = (): Codec<UserAttentionsRequest> =>
)
.build("UserAttentionsRequest");
+
export interface UserAttentionsRequest {
priority?: AttentionPriority;
}
diff --git a/packages/taler-wallet-core/src/operations/balance.ts b/packages/taler-wallet-core/src/operations/balance.ts
index 27b801804..50613d0aa 100644
--- a/packages/taler-wallet-core/src/operations/balance.ts
+++ b/packages/taler-wallet-core/src/operations/balance.ts
@@ -48,14 +48,12 @@
*/
import {
AmountJson,
- BalancesResponse,
Amounts,
- Logger,
- AuditorHandle,
- ExchangeHandle,
+ BalancesResponse,
canonicalizeBaseUrl,
+ GetBalanceDetailRequest,
+ Logger,
parsePaytoUri,
- TalerErrorCode,
} from "@gnu-taler/taler-util";
import {
AllowedAuditorInfo,
@@ -63,11 +61,10 @@ import {
RefreshGroupRecord,
WalletStoresV1,
} from "../db.js";
-import { GetReadOnlyAccess } from "../util/query.js";
import { InternalWalletState } from "../internal-wallet-state.js";
-import { getExchangeDetails } from "./exchanges.js";
import { checkLogicInvariant } from "../util/invariants.js";
-import { TalerError } from "../errors.js";
+import { GetReadOnlyAccess } from "../util/query.js";
+import { getExchangeDetails } from "./exchanges.js";
/**
* Logger.
@@ -429,6 +426,43 @@ export async function getMerchantPaymentBalanceDetails(
return d;
}
+export async function getBalanceDetail(
+ ws: InternalWalletState,
+ req: GetBalanceDetailRequest,
+): Promise<MerchantPaymentBalanceDetails> {
+ const exchanges: { exchangeBaseUrl: string; exchangePub: string }[] = [];
+ const wires = new Array<string>();
+ await ws.db
+ .mktx((x) => [x.exchanges, x.exchangeDetails])
+ .runReadOnly(async (tx) => {
+ const allExchanges = await tx.exchanges.iter().toArray();
+ for (const e of allExchanges) {
+ const details = await getExchangeDetails(tx, e.baseUrl);
+ if (!details || req.currency !== details.currency) {
+ continue;
+ }
+ details.wireInfo.accounts.forEach((a) => {
+ const payto = parsePaytoUri(a.payto_uri);
+ if (payto && !wires.includes(payto.targetType)) {
+ wires.push(payto.targetType);
+ }
+ });
+ exchanges.push({
+ exchangePub: details.masterPublicKey,
+ exchangeBaseUrl: e.baseUrl,
+ });
+ }
+ });
+
+ return await getMerchantPaymentBalanceDetails(ws, {
+ currency: req.currency,
+ acceptedAuditors: [],
+ acceptedExchanges: exchanges,
+ acceptedWireMethods: wires,
+ minAge: 0,
+ });
+}
+
export interface PeerPaymentRestrictionsForBalance {
currency: string;
restrictExchangeTo?: string;
diff --git a/packages/taler-wallet-core/src/operations/deposits.ts b/packages/taler-wallet-core/src/operations/deposits.ts
index f3ec81686..e97738b55 100644
--- a/packages/taler-wallet-core/src/operations/deposits.ts
+++ b/packages/taler-wallet-core/src/operations/deposits.ts
@@ -457,7 +457,6 @@ export async function prepareDepositGroup(
};
}
-
export async function createDepositGroup(
ws: InternalWalletState,
req: CreateDepositGroupRequest,
diff --git a/packages/taler-wallet-core/src/wallet-api-types.ts b/packages/taler-wallet-core/src/wallet-api-types.ts
index 88ae3a5c1..f14018401 100644
--- a/packages/taler-wallet-core/src/wallet-api-types.ts
+++ b/packages/taler-wallet-core/src/wallet-api-types.ts
@@ -24,7 +24,7 @@
* Imports.
*/
import {
- AbortTransactionRequest as AbortTransactionRequest,
+ AbortTransactionRequest,
AcceptBankIntegratedWithdrawalRequest,
AcceptExchangeTosRequest,
AcceptManualWithdrawalRequest,
@@ -56,6 +56,7 @@ import {
ExchangesListResponse,
ForceRefreshRequest,
ForgetKnownBankAccountsRequest,
+ GetBalanceDetailRequest,
GetContractTermsDetailsRequest,
GetExchangeTosRequest,
GetExchangeTosResult,
@@ -66,14 +67,12 @@ import {
InitiatePeerPullPaymentResponse,
InitiatePeerPushPaymentRequest,
InitiatePeerPushPaymentResponse,
+ InitRequest,
InitResponse,
IntegrationTestArgs,
KnownBankAccounts,
ListKnownBankAccountsRequest,
ManualWithdrawalDetails,
- UserAttentionsCountResponse,
- UserAttentionsRequest,
- UserAttentionsResponse,
PrepareDepositRequest,
PrepareDepositResponse,
PreparePayRequest,
@@ -99,14 +98,16 @@ import {
TransactionByIdRequest,
TransactionsRequest,
TransactionsResponse,
+ UserAttentionByIdRequest,
+ UserAttentionsCountResponse,
+ UserAttentionsRequest,
+ UserAttentionsResponse,
WalletBackupContentV1,
WalletCoreVersion,
WalletCurrencyInfo,
WithdrawFakebankRequest,
WithdrawTestBalanceRequest,
WithdrawUriInfoResponse,
- UserAttentionByIdRequest,
- InitRequest,
} from "@gnu-taler/taler-util";
import { WalletContractData } from "./db.js";
import {
@@ -116,6 +117,7 @@ import {
RemoveBackupProviderRequest,
RunBackupCycleRequest,
} from "./operations/backup/index.js";
+import { MerchantPaymentBalanceDetails } from "./operations/balance.js";
import { PendingOperationsResponse as PendingTasksResponse } from "./pending-types.js";
export enum WalletApiOperation {
@@ -138,6 +140,7 @@ export enum WalletApiOperation {
GetWithdrawalDetailsForAmount = "getWithdrawalDetailsForAmount",
AcceptManualWithdrawal = "acceptManualWithdrawal",
GetBalances = "getBalances",
+ GetBalanceDetail = "getBalanceDetail",
GetUserAttentionRequests = "getUserAttentionRequests",
GetUserAttentionUnreadCount = "getUserAttentionUnreadCount",
MarkAttentionRequestAsRead = "markAttentionRequestAsRead",
@@ -221,6 +224,11 @@ export type GetBalancesOp = {
request: EmptyObject;
response: BalancesResponse;
};
+export type GetBalancesDetailOp = {
+ op: WalletApiOperation.GetBalanceDetail;
+ request: GetBalanceDetailRequest;
+ response: MerchantPaymentBalanceDetails;
+};
// group: Managing Transactions
@@ -831,6 +839,7 @@ export type WalletOperations = {
[WalletApiOperation.ConfirmPay]: ConfirmPayOp;
[WalletApiOperation.AbortTransaction]: AbortTransactionOp;
[WalletApiOperation.GetBalances]: GetBalancesOp;
+ [WalletApiOperation.GetBalanceDetail]: GetBalancesDetailOp;
[WalletApiOperation.GetTransactions]: GetTransactionsOp;
[WalletApiOperation.GetTransactionById]: GetTransactionByIdOp;
[WalletApiOperation.RetryPendingNow]: RetryPendingNowOp;
diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts
index 24c7f7b9e..f1ed592bd 100644
--- a/packages/taler-wallet-core/src/wallet.ts
+++ b/packages/taler-wallet-core/src/wallet.ts
@@ -45,6 +45,7 @@ import {
codecForDeleteTransactionRequest,
codecForForceRefreshRequest,
codecForForgetKnownBankAccounts,
+ codecForGetBalanceDetailRequest,
codecForGetContractTermsDetails,
codecForGetExchangeTosRequest,
codecForGetFeeForDeposit,
@@ -87,6 +88,7 @@ import {
ExchangesListResponse,
ExchangeTosStatusDetails,
FeeDescription,
+ GetBalanceDetailRequest,
GetExchangeTosResult,
InitResponse,
j2s,
@@ -154,7 +156,11 @@ import {
runBackupCycle,
} from "./operations/backup/index.js";
import { setWalletDeviceId } from "./operations/backup/state.js";
-import { getBalances } from "./operations/balance.js";
+import {
+ getBalanceDetail,
+ getBalances,
+ getMerchantPaymentBalanceDetails,
+} from "./operations/balance.js";
import {
getExchangeTosStatus,
makeExchangeListItem,
@@ -948,9 +954,9 @@ async function dumpCoins(ws: InternalWalletState): Promise<CoinDumpJson> {
ageCommitmentProof: c.ageCommitmentProof,
spend_allocation: c.spendAllocation
? {
- amount: c.spendAllocation.amount,
- id: c.spendAllocation.id,
- }
+ amount: c.spendAllocation.amount,
+ id: c.spendAllocation.id,
+ }
: undefined,
});
}
@@ -1111,6 +1117,10 @@ async function dispatchRequestInternal<Op extends WalletApiOperation>(
case WalletApiOperation.GetBalances: {
return await getBalances(ws);
}
+ case WalletApiOperation.GetBalanceDetail: {
+ const req = codecForGetBalanceDetailRequest().decode(payload);
+ return await getBalanceDetail(ws, req);
+ }
case WalletApiOperation.GetUserAttentionRequests: {
const req = codecForUserAttentionsRequest().decode(payload);
return await getUserAttentions(ws, req);
@@ -1350,7 +1360,8 @@ async function dispatchRequestInternal<Op extends WalletApiOperation>(
{
amount: Amounts.stringify(amount),
reserve_pub: wres.reservePub,
- debit_account: "payto://x-taler-bank/localhost/testdebtor?receiver-name=Foo",
+ debit_account:
+ "payto://x-taler-bank/localhost/testdebtor?receiver-name=Foo",
},
);
const fbResp = await readSuccessResponseJsonOrThrow(fbReq, codecForAny());
diff --git a/packages/taler-wallet-webextension/src/wallet/DestinationSelection/index.ts b/packages/taler-wallet-webextension/src/wallet/DestinationSelection/index.ts
index bd6b32e78..9a0ba1d88 100644
--- a/packages/taler-wallet-webextension/src/wallet/DestinationSelection/index.ts
+++ b/packages/taler-wallet-webextension/src/wallet/DestinationSelection/index.ts
@@ -66,6 +66,7 @@ export namespace State {
error: undefined;
type: Props["type"];
selectCurrency: ButtonHandler;
+ sendAll: ButtonHandler;
previous: Contact[];
goToBank: ButtonHandler;
goToWallet: ButtonHandler;
diff --git a/packages/taler-wallet-webextension/src/wallet/DestinationSelection/state.ts b/packages/taler-wallet-webextension/src/wallet/DestinationSelection/state.ts
index d5015ae1d..a921d32cb 100644
--- a/packages/taler-wallet-webextension/src/wallet/DestinationSelection/state.ts
+++ b/packages/taler-wallet-webextension/src/wallet/DestinationSelection/state.ts
@@ -27,10 +27,21 @@ import { Contact, Props, State } from "./index.js";
export function useComponentState(props: Props): RecursiveState<State> {
const api = useBackendContext();
const { pushAlertOnError } = useAlertContext();
+
const parsedInitialAmount = !props.amount
? undefined
: Amounts.parse(props.amount);
+ const hook = useAsyncAsHook(async () => {
+ if (!parsedInitialAmount) return undefined;
+ const resp = await api.wallet.call(WalletApiOperation.GetBalanceDetail, {
+ currency: parsedInitialAmount.currency,
+ });
+ return resp;
+ });
+
+ const total = hook && !hook.hasError ? hook.response : undefined;
+
// const initialCurrency = parsedInitialAmount?.currency;
const [amount, setAmount] = useState(
@@ -120,6 +131,14 @@ export function useComponentState(props: Props): RecursiveState<State> {
props.goToWalletBankDeposit(currencyAndAmount);
}),
},
+ sendAll: {
+ onClick:
+ total === undefined
+ ? undefined
+ : pushAlertOnError(async () => {
+ setAmount(total.balanceMerchantDepositable);
+ }),
+ },
goToWallet: {
onClick: invalid
? undefined
@@ -143,6 +162,7 @@ export function useComponentState(props: Props): RecursiveState<State> {
setAmount(undefined);
}),
},
+ sendAll: {},
goToBank: {
onClick: invalid
? undefined
diff --git a/packages/taler-wallet-webextension/src/wallet/DestinationSelection/stories.tsx b/packages/taler-wallet-webextension/src/wallet/DestinationSelection/stories.tsx
index 111f47776..247affec6 100644
--- a/packages/taler-wallet-webextension/src/wallet/DestinationSelection/stories.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/DestinationSelection/stories.tsx
@@ -35,6 +35,7 @@ export const GetCash = tests.createExample(ReadyView, {
},
},
goToBank: {},
+ sendAll: {},
goToWallet: {},
previous: [],
selectCurrency: {},
@@ -49,6 +50,7 @@ export const SendCash = tests.createExample(ReadyView, {
},
},
goToBank: {},
+ sendAll: {},
goToWallet: {},
previous: [],
selectCurrency: {},
diff --git a/packages/taler-wallet-webextension/src/wallet/DestinationSelection/test.ts b/packages/taler-wallet-webextension/src/wallet/DestinationSelection/test.ts
index b079ef0e8..c6a57270b 100644
--- a/packages/taler-wallet-webextension/src/wallet/DestinationSelection/test.ts
+++ b/packages/taler-wallet-webextension/src/wallet/DestinationSelection/test.ts
@@ -122,6 +122,16 @@ describe("Destination selection states", () => {
Amounts.parseOrThrow("ARS:2"),
);
},
+ (state) => {
+ if (state.status !== "ready") expect.fail();
+ if (state.error) expect.fail();
+ expect(state.goToBank.onClick).not.eq(undefined);
+ expect(state.goToWallet.onClick).not.eq(undefined);
+
+ expect(state.amountHandler.value).deep.eq(
+ Amounts.parseOrThrow("ARS:2"),
+ );
+ },
],
TestingContext,
);
diff --git a/packages/taler-wallet-webextension/src/wallet/DestinationSelection/views.tsx b/packages/taler-wallet-webextension/src/wallet/DestinationSelection/views.tsx
index 8a7a1fa97..0649fd12f 100644
--- a/packages/taler-wallet-webextension/src/wallet/DestinationSelection/views.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/DestinationSelection/views.tsx
@@ -17,6 +17,7 @@
import { styled } from "@linaria/react";
import { Fragment, h, VNode } from "preact";
import { AmountField } from "../../components/AmountField.js";
+import { JustInDevMode } from "../../components/JustInDevMode.js";
import { SelectList } from "../../components/SelectList.js";
import {
Input,
@@ -283,6 +284,7 @@ export function ReadySendView({
goToBank,
goToWallet,
previous,
+ sendAll,
}: State.Ready): VNode {
const { i18n } = useTranslationContext();
@@ -292,13 +294,18 @@ export function ReadySendView({
<i18n.Translate>Specify the amount and the destination</i18n.Translate>
</h1>
- <div>
+ <Grid container columns={2} justifyContent="space-between">
<AmountField
label={i18n.str`Amount`}
required
handler={amountHandler}
/>
- </div>
+ <JustInDevMode>
+ <Button onClick={sendAll.onClick}>
+ <i18n.Translate>Send all</i18n.Translate>
+ </Button>
+ </JustInDevMode>
+ </Grid>
<Grid container spacing={1} columns={1}>
{previous.length > 0 ? (
diff --git a/packages/taler-wallet-webextension/src/wallet/History.tsx b/packages/taler-wallet-webextension/src/wallet/History.tsx
index 1d51f835a..f2a239f83 100644
--- a/packages/taler-wallet-webextension/src/wallet/History.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/History.tsx
@@ -111,8 +111,10 @@ export function HistoryView({
balances: Balance[];
}): VNode {
const { i18n } = useTranslationContext();
- const currencies = balances.map((b) => b.available.split(":")[0]);
const { pushAlertOnError } = useAlertContext();
+ const currencies = balances
+ .filter((b) => Amounts.isNonZero(b.available))
+ .map((b) => b.available.split(":")[0]);
const defaultCurrencyIndex = currencies.findIndex(
(c) => c === defaultCurrency,
diff --git a/packages/taler-wallet-webextension/src/wxApi.ts b/packages/taler-wallet-webextension/src/wxApi.ts
index 001f77934..c064d7111 100644
--- a/packages/taler-wallet-webextension/src/wxApi.ts
+++ b/packages/taler-wallet-webextension/src/wxApi.ts
@@ -88,8 +88,8 @@ export interface BackgroundOperations {
};
setLoggingLevel: {
request: {
- tag?: string,
- level: LogLevel
+ tag?: string;
+ level: LogLevel;
};
response: void;
};
diff --git a/packages/taler-wallet-webextension/src/wxBackend.ts b/packages/taler-wallet-webextension/src/wxBackend.ts
index 1bfee1064..2055953e3 100644
--- a/packages/taler-wallet-webextension/src/wxBackend.ts
+++ b/packages/taler-wallet-webextension/src/wxBackend.ts
@@ -186,12 +186,18 @@ const backendHandlers: BackendHandlerType = {
setLoggingLevel,
};
-async function setLoggingLevel({ tag, level }: { tag?: string, level: LogLevel }): Promise<void> {
- logger.info(`setting ${tag} to ${level}`)
+async function setLoggingLevel({
+ tag,
+ level,
+}: {
+ tag?: string;
+ level: LogLevel;
+}): Promise<void> {
+ logger.info(`setting ${tag} to ${level}`);
if (!tag) {
- setGlobalLogLevelFromString(level)
+ setGlobalLogLevelFromString(level);
} else {
- setLogLevelFromString(tag, level)
+ setLogLevelFromString(tag, level);
}
}