-re-add missing fields, fix types
This commit is contained in:
parent
3cf6d15eae
commit
43ae414a55
packages
taler-harness/src
taler-util/src
taler-wallet-core/src/operations
taler-wallet-webextension/src
@ -2097,7 +2097,7 @@ export interface WalletClientArgs {
|
|||||||
|
|
||||||
export class WalletClient {
|
export class WalletClient {
|
||||||
remoteWallet: RemoteWallet | undefined = undefined;
|
remoteWallet: RemoteWallet | undefined = undefined;
|
||||||
waiter: WalletNotificationWaiter = makeNotificationWaiter();
|
private waiter: WalletNotificationWaiter = makeNotificationWaiter();
|
||||||
|
|
||||||
constructor(private args: WalletClientArgs) {}
|
constructor(private args: WalletClientArgs) {}
|
||||||
|
|
||||||
|
@ -99,6 +99,8 @@ export interface EnvOptions {
|
|||||||
/**
|
/**
|
||||||
* Run a test case with a simple TESTKUDOS Taler environment, consisting
|
* Run a test case with a simple TESTKUDOS Taler environment, consisting
|
||||||
* of one exchange, one bank and one merchant.
|
* of one exchange, one bank and one merchant.
|
||||||
|
*
|
||||||
|
* @deprecated use {@link createSimpleTestkudosEnvironmentV2} instead
|
||||||
*/
|
*/
|
||||||
export async function createSimpleTestkudosEnvironment(
|
export async function createSimpleTestkudosEnvironment(
|
||||||
t: GlobalTestState,
|
t: GlobalTestState,
|
||||||
@ -505,6 +507,11 @@ export interface WithdrawViaBankResult {
|
|||||||
withdrawalFinishedCond: Promise<WithdrawalGroupFinishedNotification>;
|
withdrawalFinishedCond: Promise<WithdrawalGroupFinishedNotification>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Withdraw via a bank with the testing API enabled.
|
||||||
|
* Uses the new notification-based mechanism to wait for the
|
||||||
|
* operation to finish.
|
||||||
|
*/
|
||||||
export async function withdrawViaBankV2(
|
export async function withdrawViaBankV2(
|
||||||
t: GlobalTestState,
|
t: GlobalTestState,
|
||||||
p: {
|
p: {
|
||||||
@ -550,6 +557,8 @@ export async function withdrawViaBankV2(
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Withdraw balance.
|
* Withdraw balance.
|
||||||
|
*
|
||||||
|
* @deprecated use {@link withdrawViaBankV2 instead}
|
||||||
*/
|
*/
|
||||||
export async function withdrawViaBank(
|
export async function withdrawViaBank(
|
||||||
t: GlobalTestState,
|
t: GlobalTestState,
|
||||||
|
@ -17,11 +17,12 @@
|
|||||||
/**
|
/**
|
||||||
* Imports.
|
* Imports.
|
||||||
*/
|
*/
|
||||||
|
import { NotificationType, TransactionState } from "@gnu-taler/taler-util";
|
||||||
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||||
import { GlobalTestState, getPayto } from "../harness/harness.js";
|
import { GlobalTestState, getPayto } from "../harness/harness.js";
|
||||||
import {
|
import {
|
||||||
createSimpleTestkudosEnvironment,
|
createSimpleTestkudosEnvironmentV2,
|
||||||
withdrawViaBank,
|
withdrawViaBankV2,
|
||||||
} from "../harness/helpers.js";
|
} from "../harness/helpers.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -30,16 +31,27 @@ import {
|
|||||||
export async function runDepositTest(t: GlobalTestState) {
|
export async function runDepositTest(t: GlobalTestState) {
|
||||||
// Set up test environment
|
// Set up test environment
|
||||||
|
|
||||||
const { wallet, bank, exchange, merchant } =
|
const { walletClient, bank, exchange } =
|
||||||
await createSimpleTestkudosEnvironment(t);
|
await createSimpleTestkudosEnvironmentV2(t);
|
||||||
|
|
||||||
// Withdraw digital cash into the wallet.
|
// Withdraw digital cash into the wallet.
|
||||||
|
|
||||||
await withdrawViaBank(t, { wallet, bank, exchange, amount: "TESTKUDOS:20" });
|
const withdrawalResult = await withdrawViaBankV2(t, {
|
||||||
|
walletClient,
|
||||||
|
bank,
|
||||||
|
exchange,
|
||||||
|
amount: "TESTKUDOS:20",
|
||||||
|
});
|
||||||
|
|
||||||
await wallet.runUntilDone();
|
await withdrawalResult.withdrawalFinishedCond;
|
||||||
|
|
||||||
const { depositGroupId } = await wallet.client.call(
|
const depositDone = await walletClient.waitForNotificationCond(
|
||||||
|
(n) =>
|
||||||
|
n.type == NotificationType.TransactionStateTransition &&
|
||||||
|
n.newTxState == TransactionState.Done,
|
||||||
|
);
|
||||||
|
|
||||||
|
const depositGroupResult = await walletClient.client.call(
|
||||||
WalletApiOperation.CreateDepositGroup,
|
WalletApiOperation.CreateDepositGroup,
|
||||||
{
|
{
|
||||||
amount: "TESTKUDOS:10",
|
amount: "TESTKUDOS:10",
|
||||||
@ -47,9 +59,7 @@ export async function runDepositTest(t: GlobalTestState) {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
await wallet.runUntilDone();
|
const transactions = await walletClient.client.call(
|
||||||
|
|
||||||
const transactions = await wallet.client.call(
|
|
||||||
WalletApiOperation.GetTransactions,
|
WalletApiOperation.GetTransactions,
|
||||||
{},
|
{},
|
||||||
);
|
);
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
/**
|
/**
|
||||||
* Imports.
|
* Imports.
|
||||||
*/
|
*/
|
||||||
|
import { TransactionState, TransactionSubstate } from "./transactions-types.js";
|
||||||
import { TalerErrorDetail } from "./wallet-types.js";
|
import { TalerErrorDetail } from "./wallet-types.js";
|
||||||
|
|
||||||
export enum NotificationType {
|
export enum NotificationType {
|
||||||
@ -67,6 +68,16 @@ export enum NotificationType {
|
|||||||
WithdrawalGroupReserveReady = "withdrawal-group-reserve-ready",
|
WithdrawalGroupReserveReady = "withdrawal-group-reserve-ready",
|
||||||
PeerPullCreditReady = "peer-pull-credit-ready",
|
PeerPullCreditReady = "peer-pull-credit-ready",
|
||||||
DepositOperationError = "deposit-operation-error",
|
DepositOperationError = "deposit-operation-error",
|
||||||
|
TransactionStateTransition = "transaction-state-transition",
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TransactionStateTransitionNotification {
|
||||||
|
type: NotificationType.TransactionStateTransition;
|
||||||
|
transactionId: string;
|
||||||
|
oldTxState: TransactionState;
|
||||||
|
oldTxSubstate: TransactionSubstate;
|
||||||
|
newTxState: TransactionState;
|
||||||
|
newTxSubstate: TransactionSubstate;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ProposalAcceptedNotification {
|
export interface ProposalAcceptedNotification {
|
||||||
@ -327,4 +338,5 @@ export type WalletNotification =
|
|||||||
| KycRequestedNotification
|
| KycRequestedNotification
|
||||||
| WithdrawalGroupBankConfirmed
|
| WithdrawalGroupBankConfirmed
|
||||||
| WithdrawalGroupReserveReadyNotification
|
| WithdrawalGroupReserveReadyNotification
|
||||||
| PeerPullCreditReadyNotification;
|
| PeerPullCreditReadyNotification
|
||||||
|
| TransactionStateTransitionNotification;
|
||||||
|
@ -1722,6 +1722,7 @@ export const codecForPrepareDepositRequest = (): Codec<PrepareDepositRequest> =>
|
|||||||
export interface PrepareDepositResponse {
|
export interface PrepareDepositResponse {
|
||||||
totalDepositCost: AmountString;
|
totalDepositCost: AmountString;
|
||||||
effectiveDepositAmount: AmountString;
|
effectiveDepositAmount: AmountString;
|
||||||
|
fees: DepositGroupFees;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const codecForCreateDepositGroupRequest =
|
export const codecForCreateDepositGroupRequest =
|
||||||
|
@ -57,12 +57,13 @@ import {
|
|||||||
WireFee,
|
WireFee,
|
||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
import {
|
import {
|
||||||
|
DenominationRecord,
|
||||||
DepositGroupRecord,
|
DepositGroupRecord,
|
||||||
OperationStatus,
|
OperationStatus,
|
||||||
TransactionStatus,
|
TransactionStatus,
|
||||||
} from "../db.js";
|
} from "../db.js";
|
||||||
import { TalerError } from "@gnu-taler/taler-util";
|
import { TalerError } from "@gnu-taler/taler-util";
|
||||||
import { KycPendingInfo, KycUserType } from "../index.js";
|
import { getTotalRefreshCost, KycPendingInfo, KycUserType } from "../index.js";
|
||||||
import { InternalWalletState } from "../internal-wallet-state.js";
|
import { InternalWalletState } from "../internal-wallet-state.js";
|
||||||
import { readSuccessResponseJsonOrThrow } from "@gnu-taler/taler-util/http";
|
import { readSuccessResponseJsonOrThrow } from "@gnu-taler/taler-util/http";
|
||||||
import { OperationAttemptResult } from "../util/retries.js";
|
import { OperationAttemptResult } from "../util/retries.js";
|
||||||
@ -556,9 +557,17 @@ export async function prepareDepositGroup(
|
|||||||
payCoinSel.coinSel,
|
payCoinSel.coinSel,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const fees = await getTotalFeesForDepositAmount(
|
||||||
|
ws,
|
||||||
|
p.targetType,
|
||||||
|
amount,
|
||||||
|
payCoinSel.coinSel,
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
totalDepositCost: Amounts.stringify(totalDepositCost),
|
totalDepositCost: Amounts.stringify(totalDepositCost),
|
||||||
effectiveDepositAmount: Amounts.stringify(effectiveDepositAmount),
|
effectiveDepositAmount: Amounts.stringify(effectiveDepositAmount),
|
||||||
|
fees,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -774,3 +783,83 @@ export async function getCounterpartyEffectiveDepositAmount(
|
|||||||
});
|
});
|
||||||
return Amounts.sub(Amounts.sum(amt).amount, Amounts.sum(fees).amount).amount;
|
return Amounts.sub(Amounts.sum(amt).amount, Amounts.sum(fees).amount).amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the fee amount that will be charged when trying to deposit the
|
||||||
|
* specified amount using the selected coins and the wire method.
|
||||||
|
*/
|
||||||
|
export async function getTotalFeesForDepositAmount(
|
||||||
|
ws: InternalWalletState,
|
||||||
|
wireType: string,
|
||||||
|
total: AmountJson,
|
||||||
|
pcs: PayCoinSelection,
|
||||||
|
): Promise<DepositGroupFees> {
|
||||||
|
const wireFee: AmountJson[] = [];
|
||||||
|
const coinFee: AmountJson[] = [];
|
||||||
|
const refreshFee: AmountJson[] = [];
|
||||||
|
const exchangeSet: Set<string> = new Set();
|
||||||
|
|
||||||
|
await ws.db
|
||||||
|
.mktx((x) => [x.coins, x.denominations, x.exchanges, x.exchangeDetails])
|
||||||
|
.runReadOnly(async (tx) => {
|
||||||
|
for (let i = 0; i < pcs.coinPubs.length; i++) {
|
||||||
|
const coin = await tx.coins.get(pcs.coinPubs[i]);
|
||||||
|
if (!coin) {
|
||||||
|
throw Error("can't calculate deposit amount, coin not found");
|
||||||
|
}
|
||||||
|
const denom = await ws.getDenomInfo(
|
||||||
|
ws,
|
||||||
|
tx,
|
||||||
|
coin.exchangeBaseUrl,
|
||||||
|
coin.denomPubHash,
|
||||||
|
);
|
||||||
|
if (!denom) {
|
||||||
|
throw Error("can't find denomination to calculate deposit amount");
|
||||||
|
}
|
||||||
|
coinFee.push(Amounts.parseOrThrow(denom.feeDeposit));
|
||||||
|
exchangeSet.add(coin.exchangeBaseUrl);
|
||||||
|
|
||||||
|
const allDenoms = await tx.denominations.indexes.byExchangeBaseUrl
|
||||||
|
.iter(coin.exchangeBaseUrl)
|
||||||
|
.filter((x) =>
|
||||||
|
Amounts.isSameCurrency(
|
||||||
|
DenominationRecord.getValue(x),
|
||||||
|
pcs.coinContributions[i],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
const amountLeft = Amounts.sub(
|
||||||
|
denom.value,
|
||||||
|
pcs.coinContributions[i],
|
||||||
|
).amount;
|
||||||
|
const refreshCost = getTotalRefreshCost(allDenoms, denom, amountLeft);
|
||||||
|
refreshFee.push(refreshCost);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const exchangeUrl of exchangeSet.values()) {
|
||||||
|
const exchangeDetails = await getExchangeDetails(tx, exchangeUrl);
|
||||||
|
if (!exchangeDetails) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const fee = exchangeDetails.wireInfo.feesForType[wireType]?.find(
|
||||||
|
(x) => {
|
||||||
|
return AbsoluteTime.isBetween(
|
||||||
|
AbsoluteTime.now(),
|
||||||
|
AbsoluteTime.fromTimestamp(x.startStamp),
|
||||||
|
AbsoluteTime.fromTimestamp(x.endStamp),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
)?.wireFee;
|
||||||
|
if (fee) {
|
||||||
|
wireFee.push(Amounts.parseOrThrow(fee));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
coin: Amounts.stringify(Amounts.sumOrZero(total.currency, coinFee).amount),
|
||||||
|
wire: Amounts.stringify(Amounts.sumOrZero(total.currency, wireFee).amount),
|
||||||
|
refresh: Amounts.stringify(
|
||||||
|
Amounts.sumOrZero(total.currency, refreshFee).amount,
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
@ -74,6 +74,11 @@ describe("Deposit CTA states", () => {
|
|||||||
{
|
{
|
||||||
effectiveDepositAmount: "EUR:1",
|
effectiveDepositAmount: "EUR:1",
|
||||||
totalDepositCost: "EUR:1.2",
|
totalDepositCost: "EUR:1.2",
|
||||||
|
fees: {
|
||||||
|
coin: "EUR:0",
|
||||||
|
refresh: "EUR:0.2",
|
||||||
|
wire: "EUR:0",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -151,7 +151,7 @@ export function useComponentState({
|
|||||||
|
|
||||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||||
const hook = useAsyncAsHook(async () => {
|
const hook = useAsyncAsHook(async () => {
|
||||||
const fee = await api.wallet.call(WalletApiOperation.GetFeeForDeposit, {
|
const fee = await api.wallet.call(WalletApiOperation.PrepareDeposit, {
|
||||||
amount: amountStr,
|
amount: amountStr,
|
||||||
depositPaytoUri,
|
depositPaytoUri,
|
||||||
});
|
});
|
||||||
@ -181,7 +181,7 @@ export function useComponentState({
|
|||||||
|
|
||||||
const totalFee =
|
const totalFee =
|
||||||
fee !== undefined
|
fee !== undefined
|
||||||
? Amounts.sum([fee.wire, fee.coin, fee.refresh]).amount
|
? Amounts.sum([fee.fees.wire, fee.fees.coin, fee.fees.refresh]).amount
|
||||||
: Amounts.zeroOfCurrency(currency);
|
: Amounts.zeroOfCurrency(currency);
|
||||||
|
|
||||||
const totalToDeposit =
|
const totalToDeposit =
|
||||||
|
@ -23,6 +23,7 @@ import {
|
|||||||
Amounts,
|
Amounts,
|
||||||
DepositGroupFees,
|
DepositGroupFees,
|
||||||
parsePaytoUri,
|
parsePaytoUri,
|
||||||
|
PrepareDepositResponse,
|
||||||
ScopeType,
|
ScopeType,
|
||||||
stringifyPaytoUri,
|
stringifyPaytoUri,
|
||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
@ -36,16 +37,24 @@ import { useComponentState } from "./state.js";
|
|||||||
|
|
||||||
const currency = "EUR";
|
const currency = "EUR";
|
||||||
const amount = `${currency}:0`;
|
const amount = `${currency}:0`;
|
||||||
const withoutFee = (): DepositGroupFees => ({
|
const withoutFee = (): PrepareDepositResponse => ({
|
||||||
|
effectiveDepositAmount: `${currency}:5`,
|
||||||
|
totalDepositCost: `${currency}:5`,
|
||||||
|
fees: {
|
||||||
coin: Amounts.stringify(`${currency}:0`),
|
coin: Amounts.stringify(`${currency}:0`),
|
||||||
wire: Amounts.stringify(`${currency}:0`),
|
wire: Amounts.stringify(`${currency}:0`),
|
||||||
refresh: Amounts.stringify(`${currency}:0`),
|
refresh: Amounts.stringify(`${currency}:0`),
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const withSomeFee = (): DepositGroupFees => ({
|
const withSomeFee = (): PrepareDepositResponse => ({
|
||||||
|
effectiveDepositAmount: `${currency}:5`,
|
||||||
|
totalDepositCost: `${currency}:5`,
|
||||||
|
fees: {
|
||||||
coin: Amounts.stringify(`${currency}:1`),
|
coin: Amounts.stringify(`${currency}:1`),
|
||||||
wire: Amounts.stringify(`${currency}:1`),
|
wire: Amounts.stringify(`${currency}:1`),
|
||||||
refresh: Amounts.stringify(`${currency}:1`),
|
refresh: Amounts.stringify(`${currency}:1`),
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("DepositPage states", () => {
|
describe("DepositPage states", () => {
|
||||||
@ -182,7 +191,7 @@ describe("DepositPage states", () => {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
handler.addWalletCallResponse(
|
handler.addWalletCallResponse(
|
||||||
WalletApiOperation.GetFeeForDeposit,
|
WalletApiOperation.PrepareDeposit,
|
||||||
undefined,
|
undefined,
|
||||||
withoutFee(),
|
withoutFee(),
|
||||||
);
|
);
|
||||||
@ -241,13 +250,13 @@ describe("DepositPage states", () => {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
handler.addWalletCallResponse(
|
handler.addWalletCallResponse(
|
||||||
WalletApiOperation.GetFeeForDeposit,
|
WalletApiOperation.PrepareDeposit,
|
||||||
undefined,
|
undefined,
|
||||||
withoutFee(),
|
withoutFee(),
|
||||||
);
|
);
|
||||||
|
|
||||||
handler.addWalletCallResponse(
|
handler.addWalletCallResponse(
|
||||||
WalletApiOperation.GetFeeForDeposit,
|
WalletApiOperation.PrepareDeposit,
|
||||||
undefined,
|
undefined,
|
||||||
withoutFee(),
|
withoutFee(),
|
||||||
);
|
);
|
||||||
@ -330,17 +339,17 @@ describe("DepositPage states", () => {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
handler.addWalletCallResponse(
|
handler.addWalletCallResponse(
|
||||||
WalletApiOperation.GetFeeForDeposit,
|
WalletApiOperation.PrepareDeposit,
|
||||||
undefined,
|
undefined,
|
||||||
withoutFee(),
|
withoutFee(),
|
||||||
);
|
);
|
||||||
handler.addWalletCallResponse(
|
handler.addWalletCallResponse(
|
||||||
WalletApiOperation.GetFeeForDeposit,
|
WalletApiOperation.PrepareDeposit,
|
||||||
undefined,
|
undefined,
|
||||||
withSomeFee(),
|
withSomeFee(),
|
||||||
);
|
);
|
||||||
handler.addWalletCallResponse(
|
handler.addWalletCallResponse(
|
||||||
WalletApiOperation.GetFeeForDeposit,
|
WalletApiOperation.PrepareDeposit,
|
||||||
undefined,
|
undefined,
|
||||||
withSomeFee(),
|
withSomeFee(),
|
||||||
);
|
);
|
||||||
|
@ -34,6 +34,8 @@ import {
|
|||||||
TransactionPeerPushDebit,
|
TransactionPeerPushDebit,
|
||||||
TransactionRefresh,
|
TransactionRefresh,
|
||||||
TransactionRefund,
|
TransactionRefund,
|
||||||
|
TransactionState,
|
||||||
|
TransactionSubstate,
|
||||||
TransactionTip,
|
TransactionTip,
|
||||||
TransactionType,
|
TransactionType,
|
||||||
TransactionWithdrawal,
|
TransactionWithdrawal,
|
||||||
@ -68,6 +70,8 @@ const commonTransaction = {
|
|||||||
transactionId: "txn:deposit:12",
|
transactionId: "txn:deposit:12",
|
||||||
frozen: undefined as any as boolean, //deprecated
|
frozen: undefined as any as boolean, //deprecated
|
||||||
type: TransactionType.Deposit,
|
type: TransactionType.Deposit,
|
||||||
|
txState: TransactionState.Unknown,
|
||||||
|
txSubstate: TransactionSubstate.None,
|
||||||
} as TransactionCommon;
|
} as TransactionCommon;
|
||||||
|
|
||||||
import merchantIcon from "../../static-dev/merchant-icon.jpeg";
|
import merchantIcon from "../../static-dev/merchant-icon.jpeg";
|
||||||
|
Loading…
Reference in New Issue
Block a user