tos
This commit is contained in:
parent
99bccae9fe
commit
6415564b92
@ -26,12 +26,20 @@ import {
|
||||
} from "../headless/helpers";
|
||||
import { openPromise, OpenedPromise } from "../util/promiseUtils";
|
||||
import fs = require("fs");
|
||||
import { HttpRequestLibrary, HttpResponse, HttpRequestOptions } from "../util/http";
|
||||
import {
|
||||
HttpRequestLibrary,
|
||||
HttpResponse,
|
||||
HttpRequestOptions,
|
||||
Headers,
|
||||
} from "../util/http";
|
||||
|
||||
// @ts-ignore: special built-in module
|
||||
//import akono = require("akono");
|
||||
|
||||
export { handleWorkerError, handleWorkerMessage } from "../crypto/workers/nodeThreadWorker";
|
||||
export {
|
||||
handleWorkerError,
|
||||
handleWorkerMessage,
|
||||
} from "../crypto/workers/nodeThreadWorker";
|
||||
|
||||
export class AndroidHttpLib implements HttpRequestLibrary {
|
||||
useNfcTunnel: boolean = false;
|
||||
@ -66,7 +74,11 @@ export class AndroidHttpLib implements HttpRequestLibrary {
|
||||
}
|
||||
}
|
||||
|
||||
postJson(url: string, body: any, opt?: HttpRequestOptions): Promise<import("../util/http").HttpResponse> {
|
||||
postJson(
|
||||
url: string,
|
||||
body: any,
|
||||
opt?: HttpRequestOptions,
|
||||
): Promise<import("../util/http").HttpResponse> {
|
||||
if (this.useNfcTunnel) {
|
||||
const myId = this.requestId++;
|
||||
const p = openPromise<HttpResponse>();
|
||||
@ -89,11 +101,14 @@ export class AndroidHttpLib implements HttpRequestLibrary {
|
||||
const myId = msg.id;
|
||||
const p = this.requestMap[myId];
|
||||
if (!p) {
|
||||
console.error(`no matching request for tunneled HTTP response, id=${myId}`);
|
||||
console.error(
|
||||
`no matching request for tunneled HTTP response, id=${myId}`,
|
||||
);
|
||||
}
|
||||
const headers = new Headers();
|
||||
if (msg.status != 0) {
|
||||
const resp: HttpResponse = {
|
||||
headers: {},
|
||||
headers,
|
||||
status: msg.status,
|
||||
json: async () => JSON.parse(msg.responseText),
|
||||
text: async () => msg.responseText,
|
||||
@ -146,7 +161,7 @@ export function installAndroidWalletListener() {
|
||||
};
|
||||
const w = await getDefaultNodeWallet(walletArgs);
|
||||
maybeWallet = w;
|
||||
w.runRetryLoop().catch((e) => {
|
||||
w.runRetryLoop().catch(e => {
|
||||
console.error("Error during wallet retry loop", e);
|
||||
});
|
||||
wp.resolve(w);
|
||||
@ -191,7 +206,10 @@ export function installAndroidWalletListener() {
|
||||
}
|
||||
case "confirmPay": {
|
||||
const wallet = await wp.promise;
|
||||
result = await wallet.confirmPay(msg.args.proposalId, msg.args.sessionId);
|
||||
result = await wallet.confirmPay(
|
||||
msg.args.proposalId,
|
||||
msg.args.sessionId,
|
||||
);
|
||||
break;
|
||||
}
|
||||
case "startTunnel": {
|
||||
@ -206,14 +224,28 @@ export function installAndroidWalletListener() {
|
||||
httpLib.handleTunnelResponse(msg.args);
|
||||
break;
|
||||
}
|
||||
case "getWithdrawalInfo": {
|
||||
case "getWithdrawDetailsForUri": {
|
||||
const wallet = await wp.promise;
|
||||
result = await wallet.getWithdrawalInfo(msg.args.talerWithdrawUri);
|
||||
result = await wallet.getWithdrawDetailsForUri(
|
||||
msg.args.talerWithdrawUri,
|
||||
msg.args.selectedExchange,
|
||||
);
|
||||
break;
|
||||
}
|
||||
case "acceptExchangeTermsOfService": {
|
||||
const wallet = await wp.promise;
|
||||
result = await wallet.acceptExchangeTermsOfService(
|
||||
msg.args.exchangeBaseUrl,
|
||||
msg.args.etag,
|
||||
);
|
||||
break;
|
||||
}
|
||||
case "acceptWithdrawal": {
|
||||
const wallet = await wp.promise;
|
||||
result = await wallet.acceptWithdrawal(msg.args.talerWithdrawUri, msg.args.selectedExchange);
|
||||
result = await wallet.acceptWithdrawal(
|
||||
msg.args.talerWithdrawUri,
|
||||
msg.args.selectedExchange,
|
||||
);
|
||||
break;
|
||||
}
|
||||
case "reset": {
|
||||
@ -234,7 +266,7 @@ export function installAndroidWalletListener() {
|
||||
maybeWallet = undefined;
|
||||
const w = await getDefaultNodeWallet(walletArgs);
|
||||
maybeWallet = w;
|
||||
w.runRetryLoop().catch((e) => {
|
||||
w.runRetryLoop().catch(e => {
|
||||
console.error("Error during wallet retry loop", e);
|
||||
});
|
||||
wp.resolve(w);
|
||||
|
@ -455,9 +455,10 @@ export interface ExchangeDetails {
|
||||
lastUpdateTime: Timestamp;
|
||||
}
|
||||
|
||||
export enum ExchangeUpdateStatus {
|
||||
export const enum ExchangeUpdateStatus {
|
||||
FETCH_KEYS = "fetch_keys",
|
||||
FETCH_WIRE = "fetch_wire",
|
||||
FETCH_TERMS = "fetch_terms",
|
||||
FINISHED = "finished",
|
||||
}
|
||||
|
||||
@ -494,6 +495,26 @@ export interface ExchangeRecord {
|
||||
*/
|
||||
timestampAdded: Timestamp;
|
||||
|
||||
/**
|
||||
* Terms of service text or undefined if not downloaded yet.
|
||||
*/
|
||||
termsOfServiceText: string | undefined;
|
||||
|
||||
/**
|
||||
* ETag for last terms of service download.
|
||||
*/
|
||||
termsOfServiceLastEtag: string | undefined;
|
||||
|
||||
/**
|
||||
* ETag for last terms of service download.
|
||||
*/
|
||||
termsOfServiceAcceptedEtag: string | undefined;
|
||||
|
||||
/**
|
||||
* ETag for last terms of service download.
|
||||
*/
|
||||
termsOfServiceAcceptedTimestamp: Timestamp | undefined;
|
||||
|
||||
/**
|
||||
* Time when the update to the exchange has been started or
|
||||
* undefined if no update is in progress.
|
||||
|
@ -28,6 +28,7 @@ import Axios, { AxiosPromise, AxiosResponse } from "axios";
|
||||
import {
|
||||
HttpRequestLibrary,
|
||||
HttpRequestOptions,
|
||||
Headers,
|
||||
} from "../util/http";
|
||||
import * as amounts from "../util/amounts";
|
||||
import { Bank } from "./bank";
|
||||
@ -83,8 +84,12 @@ export class NodeHttpLib implements HttpRequestLibrary {
|
||||
}
|
||||
return responseJson;
|
||||
};
|
||||
const headers = new Headers();
|
||||
for (const hn of Object.keys(resp.headers)) {
|
||||
headers.set(hn, resp.headers[hn]);
|
||||
}
|
||||
return {
|
||||
headers: resp.headers,
|
||||
headers,
|
||||
status: resp.status,
|
||||
text: async () => resp.data,
|
||||
json: makeJson,
|
||||
|
@ -230,8 +230,8 @@ walletCli
|
||||
break;
|
||||
case TalerUriType.TalerWithdraw:
|
||||
{
|
||||
const withdrawInfo = await wallet.getWithdrawalInfo(uri);
|
||||
const selectedExchange = withdrawInfo.suggestedExchange;
|
||||
const withdrawInfo = await wallet.getWithdrawDetailsForUri(uri);
|
||||
const selectedExchange = withdrawInfo.bankWithdrawDetails.suggestedExchange;
|
||||
if (!selectedExchange) {
|
||||
console.error("no suggested exchange!");
|
||||
process.exit(1);
|
||||
|
@ -24,7 +24,7 @@
|
||||
*/
|
||||
export interface HttpResponse {
|
||||
status: number;
|
||||
headers: { [name: string]: string };
|
||||
headers: Headers;
|
||||
json(): Promise<any>;
|
||||
text(): Promise<string>;
|
||||
}
|
||||
@ -33,6 +33,31 @@ export interface HttpRequestOptions {
|
||||
headers?: { [name: string]: string };
|
||||
}
|
||||
|
||||
/**
|
||||
* Headers, roughly modeled after the fetch API's headers object.
|
||||
*/
|
||||
export class Headers {
|
||||
private headerMap = new Map<string, string>();
|
||||
|
||||
get(name: string): string | null {
|
||||
const r = this.headerMap.get(name.toLowerCase());
|
||||
if (r) {
|
||||
return r;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
set(name: string, value: string): void {
|
||||
const normalizedName = name.toLowerCase();
|
||||
const existing = this.headerMap.get(normalizedName);
|
||||
if (existing !== undefined) {
|
||||
this.headerMap.set(normalizedName, existing + "," + value);
|
||||
} else {
|
||||
this.headerMap.set(normalizedName, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The request library is bundled into an interface to m responseJson: object & any;ake mocking easy.
|
||||
*/
|
||||
@ -103,12 +128,12 @@ export class BrowserHttpLib implements HttpRequestLibrary {
|
||||
const arr = headers.trim().split(/[\r\n]+/);
|
||||
|
||||
// Create a map of header names to values
|
||||
const headerMap: { [name: string]: string } = {};
|
||||
const headerMap = new Headers();
|
||||
arr.forEach(function(line) {
|
||||
const parts = line.split(": ");
|
||||
const header = parts.shift();
|
||||
const value = parts.join(": ");
|
||||
headerMap[header!] = value;
|
||||
headerMap.set(header!, value);
|
||||
});
|
||||
const resp: HttpResponse = {
|
||||
status: myRequest.status,
|
||||
|
@ -16,11 +16,7 @@
|
||||
|
||||
import { InternalWalletState } from "./state";
|
||||
import { WALLET_CACHE_BREAKER_CLIENT_VERSION } from "../wallet";
|
||||
import {
|
||||
KeysJson,
|
||||
Denomination,
|
||||
ExchangeWireJson,
|
||||
} from "../talerTypes";
|
||||
import { KeysJson, Denomination, ExchangeWireJson } from "../talerTypes";
|
||||
import { getTimestampNow, OperationError } from "../walletTypes";
|
||||
import {
|
||||
ExchangeRecord,
|
||||
@ -222,6 +218,62 @@ async function updateExchangeWithKeys(
|
||||
);
|
||||
}
|
||||
|
||||
async function updateExchangeWithTermsOfService(
|
||||
ws: InternalWalletState,
|
||||
exchangeBaseUrl: string,
|
||||
) {
|
||||
const exchange = await oneShotGet(ws.db, Stores.exchanges, exchangeBaseUrl);
|
||||
if (!exchange) {
|
||||
return;
|
||||
}
|
||||
if (exchange.updateStatus != ExchangeUpdateStatus.FETCH_TERMS) {
|
||||
return;
|
||||
}
|
||||
const reqUrl = new URL("terms", exchangeBaseUrl);
|
||||
reqUrl.searchParams.set("cacheBreaker", WALLET_CACHE_BREAKER_CLIENT_VERSION);
|
||||
const headers = {
|
||||
Accept: "text/plain",
|
||||
};
|
||||
|
||||
const resp = await ws.http.get(reqUrl.href, { headers });
|
||||
if (resp.status !== 200) {
|
||||
throw Error(`/terms response has unexpected status code (${resp.status})`);
|
||||
}
|
||||
|
||||
const tosText = await resp.text();
|
||||
const tosEtag = resp.headers.get("etag") || undefined;
|
||||
|
||||
await runWithWriteTransaction(ws.db, [Stores.exchanges], async tx => {
|
||||
const r = await tx.get(Stores.exchanges, exchangeBaseUrl);
|
||||
if (!r) {
|
||||
return;
|
||||
}
|
||||
if (r.updateStatus != ExchangeUpdateStatus.FETCH_TERMS) {
|
||||
return;
|
||||
}
|
||||
r.termsOfServiceText = tosText;
|
||||
r.termsOfServiceLastEtag = tosEtag;
|
||||
r.updateStatus = ExchangeUpdateStatus.FINISHED;
|
||||
await tx.put(Stores.exchanges, r);
|
||||
});
|
||||
}
|
||||
|
||||
export async function acceptExchangeTermsOfService(
|
||||
ws: InternalWalletState,
|
||||
exchangeBaseUrl: string,
|
||||
etag: string | undefined,
|
||||
) {
|
||||
await runWithWriteTransaction(ws.db, [Stores.exchanges], async tx => {
|
||||
const r = await tx.get(Stores.exchanges, exchangeBaseUrl);
|
||||
if (!r) {
|
||||
return;
|
||||
}
|
||||
r.termsOfServiceAcceptedEtag = etag;
|
||||
r.termsOfServiceAcceptedTimestamp = getTimestampNow();
|
||||
await tx.put(Stores.exchanges, r);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch wire information for an exchange and store it in the database.
|
||||
*
|
||||
@ -309,7 +361,7 @@ async function updateExchangeWithWireInfo(
|
||||
accounts: wireInfo.accounts,
|
||||
feesForType: feesForType,
|
||||
};
|
||||
r.updateStatus = ExchangeUpdateStatus.FINISHED;
|
||||
r.updateStatus = ExchangeUpdateStatus.FETCH_TERMS;
|
||||
r.lastError = undefined;
|
||||
await tx.put(Stores.exchanges, r);
|
||||
});
|
||||
@ -350,6 +402,10 @@ async function updateExchangeFromUrlImpl(
|
||||
updateStarted: now,
|
||||
updateReason: "initial",
|
||||
timestampAdded: getTimestampNow(),
|
||||
termsOfServiceAcceptedEtag: undefined,
|
||||
termsOfServiceAcceptedTimestamp: undefined,
|
||||
termsOfServiceLastEtag: undefined,
|
||||
termsOfServiceText: undefined,
|
||||
};
|
||||
await oneShotPut(ws.db, Stores.exchanges, newExchangeRecord);
|
||||
} else {
|
||||
@ -373,6 +429,7 @@ async function updateExchangeFromUrlImpl(
|
||||
|
||||
await updateExchangeWithKeys(ws, baseUrl);
|
||||
await updateExchangeWithWireInfo(ws, baseUrl);
|
||||
await updateExchangeWithTermsOfService(ws, baseUrl);
|
||||
|
||||
const updatedExchange = await oneShotGet(ws.db, Stores.exchanges, baseUrl);
|
||||
|
||||
|
@ -22,7 +22,7 @@ import { TipStatus, getTimestampNow, OperationError, NotificationType } from "..
|
||||
import { TipPickupGetResponse, TipPlanchetDetail, TipResponse } from "../talerTypes";
|
||||
import * as Amounts from "../util/amounts";
|
||||
import { Stores, PlanchetRecord, WithdrawalSessionRecord, initRetryInfo, updateRetryInfoTimeout } from "../dbTypes";
|
||||
import { getWithdrawDetailsForAmount, getVerifiedWithdrawDenomList, processWithdrawSession } from "./withdraw";
|
||||
import { getExchangeWithdrawalInfo, getVerifiedWithdrawDenomList, processWithdrawSession } from "./withdraw";
|
||||
import { getTalerStampSec, extractTalerStampOrThrow } from "../util/helpers";
|
||||
import { updateExchangeFromUrl } from "./exchanges";
|
||||
import { getRandomBytes, encodeCrock } from "../crypto/talerCrypto";
|
||||
@ -58,7 +58,7 @@ export async function getTipStatus(
|
||||
]);
|
||||
|
||||
if (!tipRecord) {
|
||||
const withdrawDetails = await getWithdrawDetailsForAmount(
|
||||
const withdrawDetails = await getExchangeWithdrawalInfo(
|
||||
ws,
|
||||
tipPickupStatus.exchange_url,
|
||||
amount,
|
||||
|
@ -29,8 +29,8 @@ import * as Amounts from "../util/amounts";
|
||||
import {
|
||||
getTimestampNow,
|
||||
AcceptWithdrawalResponse,
|
||||
DownloadedWithdrawInfo,
|
||||
ReserveCreationInfo,
|
||||
BankWithdrawDetails,
|
||||
ExchangeWithdrawDetails,
|
||||
WithdrawDetails,
|
||||
OperationError,
|
||||
NotificationType,
|
||||
@ -106,12 +106,12 @@ export function getWithdrawDenomList(
|
||||
|
||||
/**
|
||||
* Get information about a withdrawal from
|
||||
* a taler://withdraw URI.
|
||||
* a taler://withdraw URI by asking the bank.
|
||||
*/
|
||||
export async function getWithdrawalInfo(
|
||||
async function getBankWithdrawalInfo(
|
||||
ws: InternalWalletState,
|
||||
talerWithdrawUri: string,
|
||||
): Promise<DownloadedWithdrawInfo> {
|
||||
): Promise<BankWithdrawDetails> {
|
||||
const uriResult = parseWithdrawUri(talerWithdrawUri);
|
||||
if (!uriResult) {
|
||||
throw Error("can't parse URL");
|
||||
@ -140,7 +140,7 @@ export async function acceptWithdrawal(
|
||||
talerWithdrawUri: string,
|
||||
selectedExchange: string,
|
||||
): Promise<AcceptWithdrawalResponse> {
|
||||
const withdrawInfo = await getWithdrawalInfo(ws, talerWithdrawUri);
|
||||
const withdrawInfo = await getBankWithdrawalInfo(ws, talerWithdrawUri);
|
||||
const exchangeWire = await getExchangePaytoUri(
|
||||
ws,
|
||||
selectedExchange,
|
||||
@ -572,11 +572,11 @@ async function processWithdrawSessionImpl(
|
||||
return;
|
||||
}
|
||||
|
||||
export async function getWithdrawDetailsForAmount(
|
||||
export async function getExchangeWithdrawalInfo(
|
||||
ws: InternalWalletState,
|
||||
baseUrl: string,
|
||||
amount: AmountJson,
|
||||
): Promise<ReserveCreationInfo> {
|
||||
): Promise<ExchangeWithdrawDetails> {
|
||||
const exchangeInfo = await updateExchangeFromUrl(ws, baseUrl);
|
||||
const exchangeDetails = exchangeInfo.details;
|
||||
if (!exchangeDetails) {
|
||||
@ -650,7 +650,15 @@ export async function getWithdrawDetailsForAmount(
|
||||
}
|
||||
}
|
||||
|
||||
const ret: ReserveCreationInfo = {
|
||||
let tosAccepted = false;
|
||||
|
||||
if (exchangeInfo.termsOfServiceAcceptedTimestamp) {
|
||||
if (exchangeInfo.termsOfServiceAcceptedEtag == exchangeInfo.termsOfServiceLastEtag) {
|
||||
tosAccepted = true;
|
||||
}
|
||||
}
|
||||
|
||||
const ret: ExchangeWithdrawDetails = {
|
||||
earliestDepositExpiration,
|
||||
exchangeInfo,
|
||||
exchangeWireAccounts,
|
||||
@ -665,6 +673,7 @@ export async function getWithdrawDetailsForAmount(
|
||||
walletVersion: WALLET_PROTOCOL_VERSION,
|
||||
wireFees: exchangeWireInfo,
|
||||
withdrawFee: acc,
|
||||
termsOfServiceAccepted: tosAccepted,
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
@ -674,17 +683,17 @@ export async function getWithdrawDetailsForUri(
|
||||
talerWithdrawUri: string,
|
||||
maybeSelectedExchange?: string,
|
||||
): Promise<WithdrawDetails> {
|
||||
const info = await getWithdrawalInfo(ws, talerWithdrawUri);
|
||||
let rci: ReserveCreationInfo | undefined = undefined;
|
||||
const info = await getBankWithdrawalInfo(ws, talerWithdrawUri);
|
||||
let rci: ExchangeWithdrawDetails | undefined = undefined;
|
||||
if (maybeSelectedExchange) {
|
||||
rci = await getWithdrawDetailsForAmount(
|
||||
rci = await getExchangeWithdrawalInfo(
|
||||
ws,
|
||||
maybeSelectedExchange,
|
||||
info.amount,
|
||||
);
|
||||
}
|
||||
return {
|
||||
withdrawInfo: info,
|
||||
reserveCreationInfo: rci,
|
||||
bankWithdrawDetails: info,
|
||||
exchangeWithdrawDetails: rci,
|
||||
};
|
||||
}
|
||||
|
@ -37,9 +37,8 @@ import * as Amounts from "./util/amounts";
|
||||
|
||||
import {
|
||||
acceptWithdrawal,
|
||||
getWithdrawalInfo,
|
||||
getWithdrawDetailsForUri,
|
||||
getWithdrawDetailsForAmount,
|
||||
getExchangeWithdrawalInfo,
|
||||
} from "./wallet-impl/withdraw";
|
||||
|
||||
import {
|
||||
@ -79,7 +78,7 @@ import {
|
||||
TipStatus,
|
||||
WalletBalance,
|
||||
PreparePayResult,
|
||||
DownloadedWithdrawInfo,
|
||||
BankWithdrawDetails,
|
||||
WithdrawDetails,
|
||||
AcceptWithdrawalResponse,
|
||||
PurchaseDetails,
|
||||
@ -88,6 +87,7 @@ import {
|
||||
HistoryQuery,
|
||||
WalletNotification,
|
||||
NotificationType,
|
||||
ExchangeWithdrawDetails,
|
||||
} from "./walletTypes";
|
||||
import { Logger } from "./util/logging";
|
||||
|
||||
@ -97,6 +97,7 @@ import {
|
||||
updateExchangeFromUrl,
|
||||
getExchangeTrust,
|
||||
getExchangePaytoUri,
|
||||
acceptExchangeTermsOfService,
|
||||
} from "./wallet-impl/exchanges";
|
||||
import { processReserve } from "./wallet-impl/reserves";
|
||||
|
||||
@ -167,8 +168,11 @@ export class Wallet {
|
||||
return getExchangePaytoUri(this.ws, exchangeBaseUrl, supportedTargetTypes);
|
||||
}
|
||||
|
||||
getWithdrawDetailsForAmount(baseUrl: any, amount: AmountJson): any {
|
||||
return getWithdrawDetailsForAmount(this.ws, baseUrl, amount);
|
||||
getWithdrawDetailsForAmount(
|
||||
exchangeBaseUrl: string,
|
||||
amount: AmountJson,
|
||||
): Promise<ExchangeWithdrawDetails> {
|
||||
return getExchangeWithdrawalInfo(this.ws, exchangeBaseUrl, amount);
|
||||
}
|
||||
|
||||
addNotificationListener(f: (n: WalletNotification) => void): void {
|
||||
@ -194,13 +198,21 @@ export class Wallet {
|
||||
await updateExchangeFromUrl(this.ws, pending.exchangeBaseUrl, forceNow);
|
||||
break;
|
||||
case "refresh":
|
||||
await processRefreshSession(this.ws, pending.refreshSessionId, forceNow);
|
||||
await processRefreshSession(
|
||||
this.ws,
|
||||
pending.refreshSessionId,
|
||||
forceNow,
|
||||
);
|
||||
break;
|
||||
case "reserve":
|
||||
await processReserve(this.ws, pending.reservePub, forceNow);
|
||||
break;
|
||||
case "withdraw":
|
||||
await processWithdrawSession(this.ws, pending.withdrawSessionId, forceNow);
|
||||
await processWithdrawSession(
|
||||
this.ws,
|
||||
pending.withdrawSessionId,
|
||||
forceNow,
|
||||
);
|
||||
break;
|
||||
case "proposal-choice":
|
||||
// Nothing to do, user needs to accept/reject
|
||||
@ -524,6 +536,13 @@ export class Wallet {
|
||||
);
|
||||
}
|
||||
|
||||
async acceptExchangeTermsOfService(
|
||||
exchangeBaseUrl: string,
|
||||
etag: string | undefined,
|
||||
) {
|
||||
return acceptExchangeTermsOfService(this.ws, exchangeBaseUrl, etag);
|
||||
}
|
||||
|
||||
async getDenoms(exchangeUrl: string): Promise<DenominationRecord[]> {
|
||||
const denoms = await oneShotIterIndex(
|
||||
this.db,
|
||||
@ -663,6 +682,10 @@ export class Wallet {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inform the wallet that the status of a reserve has changed (e.g. due to a
|
||||
* confirmation from the bank.).
|
||||
*/
|
||||
public async handleNotifyReserve() {
|
||||
const reserves = await oneShotIter(this.db, Stores.reserves).toArray();
|
||||
for (const r of reserves) {
|
||||
@ -687,20 +710,6 @@ export class Wallet {
|
||||
// strategy to test it.
|
||||
}
|
||||
|
||||
/**
|
||||
* Get information about a withdrawal from
|
||||
* a taler://withdraw URI.
|
||||
*/
|
||||
async getWithdrawalInfo(
|
||||
talerWithdrawUri: string,
|
||||
): Promise<DownloadedWithdrawInfo> {
|
||||
try {
|
||||
return getWithdrawalInfo(this.ws, talerWithdrawUri);
|
||||
} finally {
|
||||
this.latch.trigger();
|
||||
}
|
||||
}
|
||||
|
||||
async acceptWithdrawal(
|
||||
talerWithdrawUri: string,
|
||||
selectedExchange: string,
|
||||
|
@ -70,7 +70,7 @@ export class CreateReserveResponse {
|
||||
*
|
||||
* Sent to the wallet frontend to be rendered and shown to the user.
|
||||
*/
|
||||
export interface ReserveCreationInfo {
|
||||
export interface ExchangeWithdrawDetails {
|
||||
/**
|
||||
* Exchange that the reserve will be created at.
|
||||
*/
|
||||
@ -107,6 +107,11 @@ export interface ReserveCreationInfo {
|
||||
*/
|
||||
isAudited: boolean;
|
||||
|
||||
/**
|
||||
* Did the user already accept the current terms of service for the exchange?
|
||||
*/
|
||||
termsOfServiceAccepted: boolean;
|
||||
|
||||
/**
|
||||
* The exchange is trusted directly.
|
||||
*/
|
||||
@ -148,8 +153,8 @@ export interface ReserveCreationInfo {
|
||||
}
|
||||
|
||||
export interface WithdrawDetails {
|
||||
withdrawInfo: DownloadedWithdrawInfo;
|
||||
reserveCreationInfo: ReserveCreationInfo | undefined;
|
||||
bankWithdrawDetails: BankWithdrawDetails;
|
||||
exchangeWithdrawDetails: ExchangeWithdrawDetails | undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -449,7 +454,7 @@ export interface PreparePayResultPaid {
|
||||
nextUrl: string;
|
||||
}
|
||||
|
||||
export interface DownloadedWithdrawInfo {
|
||||
export interface BankWithdrawDetails {
|
||||
selectionDone: boolean;
|
||||
transferDone: boolean;
|
||||
amount: AmountJson;
|
||||
|
@ -75,7 +75,7 @@ export interface MessageMap {
|
||||
};
|
||||
"reserve-creation-info": {
|
||||
request: { baseUrl: string; amount: AmountJson };
|
||||
response: walletTypes.ReserveCreationInfo;
|
||||
response: walletTypes.ExchangeWithdrawDetails;
|
||||
};
|
||||
"get-history": {
|
||||
request: {};
|
||||
|
@ -57,9 +57,9 @@ function NewExchangeSelection(props: { talerWithdrawUri: string }) {
|
||||
return;
|
||||
}
|
||||
console.log("got withdrawDetails", d);
|
||||
if (!selectedExchange && d.withdrawInfo.suggestedExchange) {
|
||||
if (!selectedExchange && d.bankWithdrawDetails.suggestedExchange) {
|
||||
console.log("setting selected exchange");
|
||||
setSelectedExchange(d.withdrawInfo.suggestedExchange);
|
||||
setSelectedExchange(d.bankWithdrawDetails.suggestedExchange);
|
||||
}
|
||||
setDetails(d);
|
||||
};
|
||||
@ -101,7 +101,7 @@ function NewExchangeSelection(props: { talerWithdrawUri: string }) {
|
||||
}
|
||||
|
||||
if (selecting) {
|
||||
const bankSuggestion = details && details.withdrawInfo.suggestedExchange;
|
||||
const bankSuggestion = details && details.bankWithdrawDetails.suggestedExchange;
|
||||
return (
|
||||
<div>
|
||||
{i18n.str`Please select an exchange. You can review the details before after your selection.`}
|
||||
@ -157,7 +157,7 @@ function NewExchangeSelection(props: { talerWithdrawUri: string }) {
|
||||
<div>
|
||||
<i18n.Translate wrap="p">
|
||||
You are about to withdraw{" "}
|
||||
<strong>{renderAmount(details.withdrawInfo.amount)}</strong> from your
|
||||
<strong>{renderAmount(details.bankWithdrawDetails.amount)}</strong> from your
|
||||
bank account into your wallet.
|
||||
</i18n.Translate>
|
||||
<div>
|
||||
@ -188,8 +188,8 @@ function NewExchangeSelection(props: { talerWithdrawUri: string }) {
|
||||
</span>
|
||||
</p>
|
||||
|
||||
{details.reserveCreationInfo ? (
|
||||
<WithdrawDetailView rci={details.reserveCreationInfo} />
|
||||
{details.exchangeWithdrawDetails ? (
|
||||
<WithdrawDetailView rci={details.exchangeWithdrawDetails} />
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -26,7 +26,7 @@
|
||||
import { AmountJson } from "../util/amounts";
|
||||
import * as Amounts from "../util/amounts";
|
||||
import { DenominationRecord } from "../dbTypes";
|
||||
import { ReserveCreationInfo } from "../walletTypes";
|
||||
import { ExchangeWithdrawDetails } from "../walletTypes";
|
||||
import * as moment from "moment";
|
||||
import * as i18n from "../i18n";
|
||||
import React from "react";
|
||||
@ -126,7 +126,7 @@ export class Collapsible extends React.Component<
|
||||
}
|
||||
|
||||
function AuditorDetailsView(props: {
|
||||
rci: ReserveCreationInfo | null;
|
||||
rci: ExchangeWithdrawDetails | null;
|
||||
}): JSX.Element {
|
||||
const rci = props.rci;
|
||||
console.log("rci", rci);
|
||||
@ -163,7 +163,7 @@ function AuditorDetailsView(props: {
|
||||
}
|
||||
|
||||
function FeeDetailsView(props: {
|
||||
rci: ReserveCreationInfo | null;
|
||||
rci: ExchangeWithdrawDetails | null;
|
||||
}): JSX.Element {
|
||||
const rci = props.rci;
|
||||
if (!rci) {
|
||||
@ -271,7 +271,7 @@ function FeeDetailsView(props: {
|
||||
* Shows details about a withdraw request.
|
||||
*/
|
||||
export function WithdrawDetailView(props: {
|
||||
rci: ReserveCreationInfo | null;
|
||||
rci: ExchangeWithdrawDetails | null;
|
||||
}): JSX.Element {
|
||||
const rci = props.rci;
|
||||
return (
|
||||
|
@ -34,7 +34,7 @@ import {
|
||||
import {
|
||||
BenchmarkResult,
|
||||
ConfirmPayResult,
|
||||
ReserveCreationInfo,
|
||||
ExchangeWithdrawDetails,
|
||||
SenderWireInfos,
|
||||
TipStatus,
|
||||
WalletBalance,
|
||||
@ -102,7 +102,7 @@ async function callBackend<T extends MessageType>(
|
||||
* from a given reserve.
|
||||
*/
|
||||
export function getReserveCreationInfo(baseUrl: string,
|
||||
amount: AmountJson): Promise<ReserveCreationInfo> {
|
||||
amount: AmountJson): Promise<ExchangeWithdrawDetails> {
|
||||
return callBackend("reserve-creation-info", { baseUrl, amount });
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user