-re-add missing fields, fix types
This commit is contained in:
parent
3cf6d15eae
commit
43ae414a55
@ -2097,7 +2097,7 @@ export interface WalletClientArgs {
|
||||
|
||||
export class WalletClient {
|
||||
remoteWallet: RemoteWallet | undefined = undefined;
|
||||
waiter: WalletNotificationWaiter = makeNotificationWaiter();
|
||||
private waiter: WalletNotificationWaiter = makeNotificationWaiter();
|
||||
|
||||
constructor(private args: WalletClientArgs) {}
|
||||
|
||||
|
@ -99,6 +99,8 @@ export interface EnvOptions {
|
||||
/**
|
||||
* Run a test case with a simple TESTKUDOS Taler environment, consisting
|
||||
* of one exchange, one bank and one merchant.
|
||||
*
|
||||
* @deprecated use {@link createSimpleTestkudosEnvironmentV2} instead
|
||||
*/
|
||||
export async function createSimpleTestkudosEnvironment(
|
||||
t: GlobalTestState,
|
||||
@ -505,6 +507,11 @@ export interface WithdrawViaBankResult {
|
||||
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(
|
||||
t: GlobalTestState,
|
||||
p: {
|
||||
@ -550,6 +557,8 @@ export async function withdrawViaBankV2(
|
||||
|
||||
/**
|
||||
* Withdraw balance.
|
||||
*
|
||||
* @deprecated use {@link withdrawViaBankV2 instead}
|
||||
*/
|
||||
export async function withdrawViaBank(
|
||||
t: GlobalTestState,
|
||||
|
@ -17,11 +17,12 @@
|
||||
/**
|
||||
* Imports.
|
||||
*/
|
||||
import { NotificationType, TransactionState } from "@gnu-taler/taler-util";
|
||||
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||
import { GlobalTestState, getPayto } from "../harness/harness.js";
|
||||
import {
|
||||
createSimpleTestkudosEnvironment,
|
||||
withdrawViaBank,
|
||||
createSimpleTestkudosEnvironmentV2,
|
||||
withdrawViaBankV2,
|
||||
} from "../harness/helpers.js";
|
||||
|
||||
/**
|
||||
@ -30,16 +31,27 @@ import {
|
||||
export async function runDepositTest(t: GlobalTestState) {
|
||||
// Set up test environment
|
||||
|
||||
const { wallet, bank, exchange, merchant } =
|
||||
await createSimpleTestkudosEnvironment(t);
|
||||
const { walletClient, bank, exchange } =
|
||||
await createSimpleTestkudosEnvironmentV2(t);
|
||||
|
||||
// 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,
|
||||
{
|
||||
amount: "TESTKUDOS:10",
|
||||
@ -47,9 +59,7 @@ export async function runDepositTest(t: GlobalTestState) {
|
||||
},
|
||||
);
|
||||
|
||||
await wallet.runUntilDone();
|
||||
|
||||
const transactions = await wallet.client.call(
|
||||
const transactions = await walletClient.client.call(
|
||||
WalletApiOperation.GetTransactions,
|
||||
{},
|
||||
);
|
||||
|
@ -22,6 +22,7 @@
|
||||
/**
|
||||
* Imports.
|
||||
*/
|
||||
import { TransactionState, TransactionSubstate } from "./transactions-types.js";
|
||||
import { TalerErrorDetail } from "./wallet-types.js";
|
||||
|
||||
export enum NotificationType {
|
||||
@ -67,6 +68,16 @@ export enum NotificationType {
|
||||
WithdrawalGroupReserveReady = "withdrawal-group-reserve-ready",
|
||||
PeerPullCreditReady = "peer-pull-credit-ready",
|
||||
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 {
|
||||
@ -327,4 +338,5 @@ export type WalletNotification =
|
||||
| KycRequestedNotification
|
||||
| WithdrawalGroupBankConfirmed
|
||||
| WithdrawalGroupReserveReadyNotification
|
||||
| PeerPullCreditReadyNotification;
|
||||
| PeerPullCreditReadyNotification
|
||||
| TransactionStateTransitionNotification;
|
||||
|
@ -1722,6 +1722,7 @@ export const codecForPrepareDepositRequest = (): Codec<PrepareDepositRequest> =>
|
||||
export interface PrepareDepositResponse {
|
||||
totalDepositCost: AmountString;
|
||||
effectiveDepositAmount: AmountString;
|
||||
fees: DepositGroupFees;
|
||||
}
|
||||
|
||||
export const codecForCreateDepositGroupRequest =
|
||||
|
@ -57,12 +57,13 @@ import {
|
||||
WireFee,
|
||||
} from "@gnu-taler/taler-util";
|
||||
import {
|
||||
DenominationRecord,
|
||||
DepositGroupRecord,
|
||||
OperationStatus,
|
||||
TransactionStatus,
|
||||
} from "../db.js";
|
||||
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 { readSuccessResponseJsonOrThrow } from "@gnu-taler/taler-util/http";
|
||||
import { OperationAttemptResult } from "../util/retries.js";
|
||||
@ -556,9 +557,17 @@ export async function prepareDepositGroup(
|
||||
payCoinSel.coinSel,
|
||||
);
|
||||
|
||||
const fees = await getTotalFeesForDepositAmount(
|
||||
ws,
|
||||
p.targetType,
|
||||
amount,
|
||||
payCoinSel.coinSel,
|
||||
);
|
||||
|
||||
return {
|
||||
totalDepositCost: Amounts.stringify(totalDepositCost),
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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",
|
||||
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
|
||||
const hook = useAsyncAsHook(async () => {
|
||||
const fee = await api.wallet.call(WalletApiOperation.GetFeeForDeposit, {
|
||||
const fee = await api.wallet.call(WalletApiOperation.PrepareDeposit, {
|
||||
amount: amountStr,
|
||||
depositPaytoUri,
|
||||
});
|
||||
@ -181,7 +181,7 @@ export function useComponentState({
|
||||
|
||||
const totalFee =
|
||||
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);
|
||||
|
||||
const totalToDeposit =
|
||||
|
@ -23,6 +23,7 @@ import {
|
||||
Amounts,
|
||||
DepositGroupFees,
|
||||
parsePaytoUri,
|
||||
PrepareDepositResponse,
|
||||
ScopeType,
|
||||
stringifyPaytoUri,
|
||||
} from "@gnu-taler/taler-util";
|
||||
@ -36,16 +37,24 @@ import { useComponentState } from "./state.js";
|
||||
|
||||
const currency = "EUR";
|
||||
const amount = `${currency}:0`;
|
||||
const withoutFee = (): DepositGroupFees => ({
|
||||
coin: Amounts.stringify(`${currency}:0`),
|
||||
wire: Amounts.stringify(`${currency}:0`),
|
||||
refresh: Amounts.stringify(`${currency}:0`),
|
||||
const withoutFee = (): PrepareDepositResponse => ({
|
||||
effectiveDepositAmount: `${currency}:5`,
|
||||
totalDepositCost: `${currency}:5`,
|
||||
fees: {
|
||||
coin: Amounts.stringify(`${currency}:0`),
|
||||
wire: Amounts.stringify(`${currency}:0`),
|
||||
refresh: Amounts.stringify(`${currency}:0`),
|
||||
},
|
||||
});
|
||||
|
||||
const withSomeFee = (): DepositGroupFees => ({
|
||||
coin: Amounts.stringify(`${currency}:1`),
|
||||
wire: Amounts.stringify(`${currency}:1`),
|
||||
refresh: Amounts.stringify(`${currency}:1`),
|
||||
const withSomeFee = (): PrepareDepositResponse => ({
|
||||
effectiveDepositAmount: `${currency}:5`,
|
||||
totalDepositCost: `${currency}:5`,
|
||||
fees: {
|
||||
coin: Amounts.stringify(`${currency}:1`),
|
||||
wire: Amounts.stringify(`${currency}:1`),
|
||||
refresh: Amounts.stringify(`${currency}:1`),
|
||||
},
|
||||
});
|
||||
|
||||
describe("DepositPage states", () => {
|
||||
@ -182,7 +191,7 @@ describe("DepositPage states", () => {
|
||||
},
|
||||
);
|
||||
handler.addWalletCallResponse(
|
||||
WalletApiOperation.GetFeeForDeposit,
|
||||
WalletApiOperation.PrepareDeposit,
|
||||
undefined,
|
||||
withoutFee(),
|
||||
);
|
||||
@ -241,13 +250,13 @@ describe("DepositPage states", () => {
|
||||
},
|
||||
);
|
||||
handler.addWalletCallResponse(
|
||||
WalletApiOperation.GetFeeForDeposit,
|
||||
WalletApiOperation.PrepareDeposit,
|
||||
undefined,
|
||||
withoutFee(),
|
||||
);
|
||||
|
||||
handler.addWalletCallResponse(
|
||||
WalletApiOperation.GetFeeForDeposit,
|
||||
WalletApiOperation.PrepareDeposit,
|
||||
undefined,
|
||||
withoutFee(),
|
||||
);
|
||||
@ -330,17 +339,17 @@ describe("DepositPage states", () => {
|
||||
},
|
||||
);
|
||||
handler.addWalletCallResponse(
|
||||
WalletApiOperation.GetFeeForDeposit,
|
||||
WalletApiOperation.PrepareDeposit,
|
||||
undefined,
|
||||
withoutFee(),
|
||||
);
|
||||
handler.addWalletCallResponse(
|
||||
WalletApiOperation.GetFeeForDeposit,
|
||||
WalletApiOperation.PrepareDeposit,
|
||||
undefined,
|
||||
withSomeFee(),
|
||||
);
|
||||
handler.addWalletCallResponse(
|
||||
WalletApiOperation.GetFeeForDeposit,
|
||||
WalletApiOperation.PrepareDeposit,
|
||||
undefined,
|
||||
withSomeFee(),
|
||||
);
|
||||
|
@ -34,6 +34,8 @@ import {
|
||||
TransactionPeerPushDebit,
|
||||
TransactionRefresh,
|
||||
TransactionRefund,
|
||||
TransactionState,
|
||||
TransactionSubstate,
|
||||
TransactionTip,
|
||||
TransactionType,
|
||||
TransactionWithdrawal,
|
||||
@ -68,6 +70,8 @@ const commonTransaction = {
|
||||
transactionId: "txn:deposit:12",
|
||||
frozen: undefined as any as boolean, //deprecated
|
||||
type: TransactionType.Deposit,
|
||||
txState: TransactionState.Unknown,
|
||||
txSubstate: TransactionSubstate.None,
|
||||
} as TransactionCommon;
|
||||
|
||||
import merchantIcon from "../../static-dev/merchant-icon.jpeg";
|
||||
|
Loading…
Reference in New Issue
Block a user