listExchangesDetailed to getExchangeDetailedInfo & ageRestriction taken from the denoms
This commit is contained in:
parent
49c9279c1e
commit
1e00724a0d
@ -190,7 +190,6 @@ export interface TransactionWithdrawal extends TransactionCommon {
|
|||||||
export interface PeerInfoShort {
|
export interface PeerInfoShort {
|
||||||
expiration: TalerProtocolTimestamp | undefined;
|
expiration: TalerProtocolTimestamp | undefined;
|
||||||
summary: string | undefined;
|
summary: string | undefined;
|
||||||
completed: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -568,12 +568,12 @@ export interface DepositInfo {
|
|||||||
ageCommitmentProof?: AgeCommitmentProof;
|
ageCommitmentProof?: AgeCommitmentProof;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ExchangesListRespose {
|
export interface ExchangesListResponse {
|
||||||
exchanges: ExchangeListItem[];
|
exchanges: ExchangeListItem[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ExchangeDetailledListRespose {
|
export interface ExchangeDetailedResponse {
|
||||||
exchanges: ExchangeFullDetailsListItem[];
|
exchange: ExchangeFullDetails;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface WalletCoreVersion {
|
export interface WalletCoreVersion {
|
||||||
@ -733,7 +733,7 @@ export interface DenominationInfo {
|
|||||||
stampExpireDeposit: TalerProtocolTimestamp;
|
stampExpireDeposit: TalerProtocolTimestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ExchangeFullDetailsListItem {
|
export interface ExchangeFullDetails {
|
||||||
exchangeBaseUrl: string;
|
exchangeBaseUrl: string;
|
||||||
currency: string;
|
currency: string;
|
||||||
paytoUris: string[];
|
paytoUris: string[];
|
||||||
@ -771,9 +771,9 @@ const codecForExchangeTos = (): Codec<ExchangeTos> =>
|
|||||||
.property("content", codecOptional(codecForString()))
|
.property("content", codecOptional(codecForString()))
|
||||||
.build("ExchangeTos");
|
.build("ExchangeTos");
|
||||||
|
|
||||||
export const codecForExchangeFullDetailsListItem =
|
export const codecForExchangeFullDetails =
|
||||||
(): Codec<ExchangeFullDetailsListItem> =>
|
(): Codec<ExchangeFullDetails> =>
|
||||||
buildCodecForObject<ExchangeFullDetailsListItem>()
|
buildCodecForObject<ExchangeFullDetails>()
|
||||||
.property("currency", codecForString())
|
.property("currency", codecForString())
|
||||||
.property("exchangeBaseUrl", codecForString())
|
.property("exchangeBaseUrl", codecForString())
|
||||||
.property("paytoUris", codecForList(codecForString()))
|
.property("paytoUris", codecForList(codecForString()))
|
||||||
@ -791,10 +791,10 @@ export const codecForExchangeListItem = (): Codec<ExchangeListItem> =>
|
|||||||
.property("tos", codecForExchangeTos())
|
.property("tos", codecForExchangeTos())
|
||||||
.build("ExchangeListItem");
|
.build("ExchangeListItem");
|
||||||
|
|
||||||
export const codecForExchangesListResponse = (): Codec<ExchangesListRespose> =>
|
export const codecForExchangesListResponse = (): Codec<ExchangesListResponse> =>
|
||||||
buildCodecForObject<ExchangesListRespose>()
|
buildCodecForObject<ExchangesListResponse>()
|
||||||
.property("exchanges", codecForList(codecForExchangeFullDetailsListItem()))
|
.property("exchanges", codecForList(codecForExchangeListItem()))
|
||||||
.build("ExchangesListRespose");
|
.build("ExchangesListResponse");
|
||||||
|
|
||||||
export interface AcceptManualWithdrawalResult {
|
export interface AcceptManualWithdrawalResult {
|
||||||
/**
|
/**
|
||||||
@ -965,6 +965,7 @@ export const codecForGetWithdrawalDetailsForAmountRequest =
|
|||||||
buildCodecForObject<GetWithdrawalDetailsForAmountRequest>()
|
buildCodecForObject<GetWithdrawalDetailsForAmountRequest>()
|
||||||
.property("exchangeBaseUrl", codecForString())
|
.property("exchangeBaseUrl", codecForString())
|
||||||
.property("amount", codecForString())
|
.property("amount", codecForString())
|
||||||
|
.property("restrictAge", codecOptional(codecForNumber()))
|
||||||
.build("GetWithdrawalDetailsForAmountRequest");
|
.build("GetWithdrawalDetailsForAmountRequest");
|
||||||
|
|
||||||
export interface AcceptExchangeTosRequest {
|
export interface AcceptExchangeTosRequest {
|
||||||
@ -1022,6 +1023,7 @@ export interface GetExchangeWithdrawalInfo {
|
|||||||
exchangeBaseUrl: string;
|
exchangeBaseUrl: string;
|
||||||
amount: AmountJson;
|
amount: AmountJson;
|
||||||
tosAcceptedFormat?: string[];
|
tosAcceptedFormat?: string[];
|
||||||
|
ageRestricted?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const codecForGetExchangeWithdrawalInfo =
|
export const codecForGetExchangeWithdrawalInfo =
|
||||||
|
@ -82,10 +82,15 @@ export async function prepareTip(
|
|||||||
|
|
||||||
logger.trace("new tip, creating tip record");
|
logger.trace("new tip, creating tip record");
|
||||||
await updateExchangeFromUrl(ws, tipPickupStatus.exchange_url);
|
await updateExchangeFromUrl(ws, tipPickupStatus.exchange_url);
|
||||||
|
|
||||||
|
//FIXME: is this needed? withdrawDetails is not used
|
||||||
|
// * if the intention is to update the exchange information in the database
|
||||||
|
// maybe we can use another name. `get` seems like a pure-function
|
||||||
const withdrawDetails = await getExchangeWithdrawalInfo(
|
const withdrawDetails = await getExchangeWithdrawalInfo(
|
||||||
ws,
|
ws,
|
||||||
tipPickupStatus.exchange_url,
|
tipPickupStatus.exchange_url,
|
||||||
amount,
|
amount,
|
||||||
|
undefined
|
||||||
);
|
);
|
||||||
|
|
||||||
const walletTipId = encodeCrock(getRandomBytes(32));
|
const walletTipId = encodeCrock(getRandomBytes(32));
|
||||||
|
@ -161,7 +161,6 @@ export async function getTransactions(
|
|||||||
info: {
|
info: {
|
||||||
expiration: pi.contractTerms.purse_expiration,
|
expiration: pi.contractTerms.purse_expiration,
|
||||||
summary: pi.contractTerms.summary,
|
summary: pi.contractTerms.summary,
|
||||||
completed: Amounts.isZero(amount),
|
|
||||||
},
|
},
|
||||||
frozen: false,
|
frozen: false,
|
||||||
pending: !pi.purseCreated,
|
pending: !pi.purseCreated,
|
||||||
@ -199,7 +198,6 @@ export async function getTransactions(
|
|||||||
info: {
|
info: {
|
||||||
expiration: pi.contractTerms.purse_expiration,
|
expiration: pi.contractTerms.purse_expiration,
|
||||||
summary: pi.contractTerms.summary,
|
summary: pi.contractTerms.summary,
|
||||||
completed: pi.paid
|
|
||||||
},
|
},
|
||||||
timestamp: pi.timestampCreated,
|
timestamp: pi.timestampCreated,
|
||||||
transactionId: makeEventId(
|
transactionId: makeEventId(
|
||||||
@ -234,7 +232,6 @@ export async function getTransactions(
|
|||||||
info: {
|
info: {
|
||||||
expiration: wsr.wgInfo.contractTerms.purse_expiration,
|
expiration: wsr.wgInfo.contractTerms.purse_expiration,
|
||||||
summary: wsr.wgInfo.contractTerms.summary,
|
summary: wsr.wgInfo.contractTerms.summary,
|
||||||
completed: !!wsr.timestampFinish
|
|
||||||
},
|
},
|
||||||
talerUri: constructPayPullUri({
|
talerUri: constructPayPullUri({
|
||||||
exchangeBaseUrl: wsr.exchangeBaseUrl,
|
exchangeBaseUrl: wsr.exchangeBaseUrl,
|
||||||
@ -259,7 +256,6 @@ export async function getTransactions(
|
|||||||
info: {
|
info: {
|
||||||
expiration: wsr.wgInfo.contractTerms.purse_expiration,
|
expiration: wsr.wgInfo.contractTerms.purse_expiration,
|
||||||
summary: wsr.wgInfo.contractTerms.summary,
|
summary: wsr.wgInfo.contractTerms.summary,
|
||||||
completed: !!wsr.timestampFinish,
|
|
||||||
},
|
},
|
||||||
pending: !wsr.timestampFinish,
|
pending: !wsr.timestampFinish,
|
||||||
timestamp: wsr.timestampStart,
|
timestamp: wsr.timestampStart,
|
||||||
|
@ -192,6 +192,13 @@ export interface ExchangeWithdrawDetails {
|
|||||||
* Amount that will actually be added to the wallet's balance.
|
* Amount that will actually be added to the wallet's balance.
|
||||||
*/
|
*/
|
||||||
withdrawalAmountEffective: AmountString;
|
withdrawalAmountEffective: AmountString;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the exchange supports age-restricted coins it will return
|
||||||
|
* the array of ages.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
ageRestrictionOptions?: number[],
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -242,7 +249,7 @@ export function selectWithdrawalDenominations(
|
|||||||
for (const d of denoms) {
|
for (const d of denoms) {
|
||||||
let count = 0;
|
let count = 0;
|
||||||
const cost = Amounts.add(d.value, d.feeWithdraw).amount;
|
const cost = Amounts.add(d.value, d.feeWithdraw).amount;
|
||||||
for (;;) {
|
for (; ;) {
|
||||||
if (Amounts.cmp(remaining, cost) < 0) {
|
if (Amounts.cmp(remaining, cost) < 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -903,8 +910,7 @@ export async function updateWithdrawalDenoms(
|
|||||||
denom.verificationStatus === DenominationVerificationStatus.Unverified
|
denom.verificationStatus === DenominationVerificationStatus.Unverified
|
||||||
) {
|
) {
|
||||||
logger.trace(
|
logger.trace(
|
||||||
`Validating denomination (${current + 1}/${
|
`Validating denomination (${current + 1}/${denominations.length
|
||||||
denominations.length
|
|
||||||
}) signature of ${denom.denomPubHash}`,
|
}) signature of ${denom.denomPubHash}`,
|
||||||
);
|
);
|
||||||
let valid = false;
|
let valid = false;
|
||||||
@ -1031,7 +1037,7 @@ async function queryReserve(
|
|||||||
if (
|
if (
|
||||||
resp.status === 404 &&
|
resp.status === 404 &&
|
||||||
result.talerErrorResponse.code ===
|
result.talerErrorResponse.code ===
|
||||||
TalerErrorCode.EXCHANGE_RESERVES_STATUS_UNKNOWN
|
TalerErrorCode.EXCHANGE_RESERVES_STATUS_UNKNOWN
|
||||||
) {
|
) {
|
||||||
ws.notify({
|
ws.notify({
|
||||||
type: NotificationType.ReserveNotYetFound,
|
type: NotificationType.ReserveNotYetFound,
|
||||||
@ -1255,10 +1261,13 @@ async function processWithdrawGroupImpl(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const AGE_MASK_GROUPS = "8:10:12:14:16:18".split(":").map(n => parseInt(n, 10))
|
||||||
|
|
||||||
export async function getExchangeWithdrawalInfo(
|
export async function getExchangeWithdrawalInfo(
|
||||||
ws: InternalWalletState,
|
ws: InternalWalletState,
|
||||||
exchangeBaseUrl: string,
|
exchangeBaseUrl: string,
|
||||||
instructedAmount: AmountJson,
|
instructedAmount: AmountJson,
|
||||||
|
ageRestricted: number | undefined,
|
||||||
): Promise<ExchangeWithdrawDetails> {
|
): Promise<ExchangeWithdrawDetails> {
|
||||||
const { exchange, exchangeDetails } =
|
const { exchange, exchangeDetails } =
|
||||||
await ws.exchangeOps.updateExchangeFromUrl(ws, exchangeBaseUrl);
|
await ws.exchangeOps.updateExchangeFromUrl(ws, exchangeBaseUrl);
|
||||||
@ -1287,6 +1296,8 @@ export async function getExchangeWithdrawalInfo(
|
|||||||
exchange,
|
exchange,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let hasDenomWithAgeRestriction = false
|
||||||
|
|
||||||
let earliestDepositExpiration: TalerProtocolTimestamp | undefined;
|
let earliestDepositExpiration: TalerProtocolTimestamp | undefined;
|
||||||
for (let i = 0; i < selectedDenoms.selectedDenoms.length; i++) {
|
for (let i = 0; i < selectedDenoms.selectedDenoms.length; i++) {
|
||||||
const ds = selectedDenoms.selectedDenoms[i];
|
const ds = selectedDenoms.selectedDenoms[i];
|
||||||
@ -1310,6 +1321,7 @@ export async function getExchangeWithdrawalInfo(
|
|||||||
) {
|
) {
|
||||||
earliestDepositExpiration = expireDeposit;
|
earliestDepositExpiration = expireDeposit;
|
||||||
}
|
}
|
||||||
|
hasDenomWithAgeRestriction = hasDenomWithAgeRestriction || denom.denomPub.age_mask > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
checkLogicInvariant(!!earliestDepositExpiration);
|
checkLogicInvariant(!!earliestDepositExpiration);
|
||||||
@ -1337,7 +1349,7 @@ export async function getExchangeWithdrawalInfo(
|
|||||||
) {
|
) {
|
||||||
logger.warn(
|
logger.warn(
|
||||||
`wallet's support for exchange protocol version ${WALLET_EXCHANGE_PROTOCOL_VERSION} might be outdated ` +
|
`wallet's support for exchange protocol version ${WALLET_EXCHANGE_PROTOCOL_VERSION} might be outdated ` +
|
||||||
`(exchange has ${exchangeDetails.protocolVersion}), checking for updates`,
|
`(exchange has ${exchangeDetails.protocolVersion}), checking for updates`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1370,6 +1382,9 @@ export async function getExchangeWithdrawalInfo(
|
|||||||
termsOfServiceAccepted: tosAccepted,
|
termsOfServiceAccepted: tosAccepted,
|
||||||
withdrawalAmountEffective: Amounts.stringify(selectedDenoms.totalCoinValue),
|
withdrawalAmountEffective: Amounts.stringify(selectedDenoms.totalCoinValue),
|
||||||
withdrawalAmountRaw: Amounts.stringify(instructedAmount),
|
withdrawalAmountRaw: Amounts.stringify(instructedAmount),
|
||||||
|
// TODO: remove hardcoding, this should be calculated from the denominations info
|
||||||
|
// force enabled for testing
|
||||||
|
ageRestrictionOptions: hasDenomWithAgeRestriction ? AGE_MASK_GROUPS : undefined
|
||||||
};
|
};
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,7 @@ import {
|
|||||||
CreateDepositGroupRequest,
|
CreateDepositGroupRequest,
|
||||||
CreateDepositGroupResponse,
|
CreateDepositGroupResponse,
|
||||||
DeleteTransactionRequest,
|
DeleteTransactionRequest,
|
||||||
ExchangesListRespose,
|
ExchangesListResponse,
|
||||||
ForceRefreshRequest,
|
ForceRefreshRequest,
|
||||||
GetExchangeTosRequest,
|
GetExchangeTosRequest,
|
||||||
GetExchangeTosResult,
|
GetExchangeTosResult,
|
||||||
@ -227,7 +227,7 @@ export type WalletOperations = {
|
|||||||
};
|
};
|
||||||
[WalletApiOperation.ListExchanges]: {
|
[WalletApiOperation.ListExchanges]: {
|
||||||
request: {};
|
request: {};
|
||||||
response: ExchangesListRespose;
|
response: ExchangesListResponse;
|
||||||
};
|
};
|
||||||
[WalletApiOperation.AddExchange]: {
|
[WalletApiOperation.AddExchange]: {
|
||||||
request: AddExchangeRequest;
|
request: AddExchangeRequest;
|
||||||
|
@ -72,8 +72,8 @@ import {
|
|||||||
Duration,
|
Duration,
|
||||||
durationFromSpec,
|
durationFromSpec,
|
||||||
durationMin,
|
durationMin,
|
||||||
ExchangeFullDetailsListItem,
|
ExchangeFullDetails,
|
||||||
ExchangesListRespose,
|
ExchangesListResponse,
|
||||||
GetExchangeTosResult,
|
GetExchangeTosResult,
|
||||||
j2s,
|
j2s,
|
||||||
KnownBankAccounts,
|
KnownBankAccounts,
|
||||||
@ -232,8 +232,9 @@ async function getWithdrawalDetailsForAmount(
|
|||||||
ws: InternalWalletState,
|
ws: InternalWalletState,
|
||||||
exchangeBaseUrl: string,
|
exchangeBaseUrl: string,
|
||||||
amount: AmountJson,
|
amount: AmountJson,
|
||||||
|
restrictAge: number | undefined,
|
||||||
): Promise<ManualWithdrawalDetails> {
|
): Promise<ManualWithdrawalDetails> {
|
||||||
const wi = await getExchangeWithdrawalInfo(ws, exchangeBaseUrl, amount);
|
const wi = await getExchangeWithdrawalInfo(ws, exchangeBaseUrl, amount, restrictAge);
|
||||||
const paytoUris = wi.exchangeDetails.wireInfo.accounts.map(
|
const paytoUris = wi.exchangeDetails.wireInfo.accounts.map(
|
||||||
(x) => x.payto_uri,
|
(x) => x.payto_uri,
|
||||||
);
|
);
|
||||||
@ -568,7 +569,7 @@ async function listKnownBankAccounts(
|
|||||||
|
|
||||||
async function getExchanges(
|
async function getExchanges(
|
||||||
ws: InternalWalletState,
|
ws: InternalWalletState,
|
||||||
): Promise<ExchangesListRespose> {
|
): Promise<ExchangesListResponse> {
|
||||||
const exchanges: ExchangeListItem[] = [];
|
const exchanges: ExchangeListItem[] = [];
|
||||||
await ws.db
|
await ws.db
|
||||||
.mktx((x) => ({
|
.mktx((x) => ({
|
||||||
@ -613,54 +614,56 @@ async function getExchanges(
|
|||||||
return { exchanges };
|
return { exchanges };
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getExchangesDetailled(
|
async function getExchangeDetailedInfo(
|
||||||
ws: InternalWalletState,
|
ws: InternalWalletState,
|
||||||
): Promise<ExchangesListRespose> {
|
exchangeBaseurl: string,
|
||||||
const exchanges: ExchangeFullDetailsListItem[] = [];
|
): Promise<ExchangeFullDetails> {
|
||||||
await ws.db
|
//TODO: should we use the forceUpdate parameter?
|
||||||
|
const exchange = await ws.db
|
||||||
.mktx((x) => ({
|
.mktx((x) => ({
|
||||||
exchanges: x.exchanges,
|
exchanges: x.exchanges,
|
||||||
exchangeDetails: x.exchangeDetails,
|
exchangeDetails: x.exchangeDetails,
|
||||||
denominations: x.denominations,
|
denominations: x.denominations,
|
||||||
}))
|
}))
|
||||||
.runReadOnly(async (tx) => {
|
.runReadOnly(async (tx) => {
|
||||||
const exchangeRecords = await tx.exchanges.iter().toArray();
|
const ex = await tx.exchanges.get(exchangeBaseurl)
|
||||||
for (const r of exchangeRecords) {
|
const dp = ex?.detailsPointer;
|
||||||
const dp = r.detailsPointer;
|
if (!dp) {
|
||||||
if (!dp) {
|
return;
|
||||||
continue;
|
}
|
||||||
}
|
const { currency } = dp;
|
||||||
const { currency } = dp;
|
const exchangeDetails = await getExchangeDetails(tx, ex.baseUrl);
|
||||||
const exchangeDetails = await getExchangeDetails(tx, r.baseUrl);
|
if (!exchangeDetails) {
|
||||||
if (!exchangeDetails) {
|
return;
|
||||||
continue;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const denominations = await tx.denominations.indexes.byExchangeBaseUrl
|
const denominations = await tx.denominations.indexes.byExchangeBaseUrl
|
||||||
.iter(r.baseUrl)
|
.iter(ex.baseUrl)
|
||||||
.toArray();
|
.toArray();
|
||||||
|
|
||||||
if (!denominations) {
|
if (!denominations) {
|
||||||
continue;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
exchanges.push({
|
return {
|
||||||
exchangeBaseUrl: r.baseUrl,
|
exchangeBaseUrl: ex.baseUrl,
|
||||||
currency,
|
currency,
|
||||||
tos: {
|
tos: {
|
||||||
acceptedVersion: exchangeDetails.termsOfServiceAcceptedEtag,
|
acceptedVersion: exchangeDetails.termsOfServiceAcceptedEtag,
|
||||||
currentVersion: exchangeDetails.termsOfServiceLastEtag,
|
currentVersion: exchangeDetails.termsOfServiceLastEtag,
|
||||||
contentType: exchangeDetails.termsOfServiceContentType,
|
contentType: exchangeDetails.termsOfServiceContentType,
|
||||||
content: exchangeDetails.termsOfServiceText,
|
content: exchangeDetails.termsOfServiceText,
|
||||||
},
|
},
|
||||||
paytoUris: exchangeDetails.wireInfo.accounts.map((x) => x.payto_uri),
|
paytoUris: exchangeDetails.wireInfo.accounts.map((x) => x.payto_uri),
|
||||||
auditors: exchangeDetails.auditors,
|
auditors: exchangeDetails.auditors,
|
||||||
wireInfo: exchangeDetails.wireInfo,
|
wireInfo: exchangeDetails.wireInfo,
|
||||||
denominations: denominations,
|
denominations: denominations,
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return { exchanges };
|
if (!exchange) {
|
||||||
|
throw Error(`exchange with base url "${exchangeBaseurl}" not found`)
|
||||||
|
}
|
||||||
|
return exchange;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function setCoinSuspended(
|
async function setCoinSuspended(
|
||||||
@ -834,8 +837,9 @@ async function dispatchRequestInternal(
|
|||||||
case "listExchanges": {
|
case "listExchanges": {
|
||||||
return await getExchanges(ws);
|
return await getExchanges(ws);
|
||||||
}
|
}
|
||||||
case "listExchangesDetailled": {
|
case "getExchangeDetailedInfo": {
|
||||||
return await getExchangesDetailled(ws);
|
const req = codecForAddExchangeRequest().decode(payload);
|
||||||
|
return await getExchangeDetailedInfo(ws, req.exchangeBaseUrl);
|
||||||
}
|
}
|
||||||
case "listKnownBankAccounts": {
|
case "listKnownBankAccounts": {
|
||||||
const req = codecForListKnownBankAccounts().decode(payload);
|
const req = codecForListKnownBankAccounts().decode(payload);
|
||||||
@ -852,6 +856,7 @@ async function dispatchRequestInternal(
|
|||||||
ws,
|
ws,
|
||||||
req.exchangeBaseUrl,
|
req.exchangeBaseUrl,
|
||||||
req.amount,
|
req.amount,
|
||||||
|
req.ageRestricted,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
case "acceptManualWithdrawal": {
|
case "acceptManualWithdrawal": {
|
||||||
@ -870,6 +875,7 @@ async function dispatchRequestInternal(
|
|||||||
ws,
|
ws,
|
||||||
req.exchangeBaseUrl,
|
req.exchangeBaseUrl,
|
||||||
Amounts.parseOrThrow(req.amount),
|
Amounts.parseOrThrow(req.amount),
|
||||||
|
req.restrictAge
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
case "getBalances": {
|
case "getBalances": {
|
||||||
@ -1067,6 +1073,7 @@ async function dispatchRequestInternal(
|
|||||||
ws,
|
ws,
|
||||||
req.exchange,
|
req.exchange,
|
||||||
amount,
|
amount,
|
||||||
|
undefined
|
||||||
);
|
);
|
||||||
const wres = await createManualWithdrawal(ws, {
|
const wres = await createManualWithdrawal(ws, {
|
||||||
amount: amount,
|
amount: amount,
|
||||||
|
@ -30,7 +30,7 @@ export function useComponentState(
|
|||||||
const [subject, setSubject] = useState("");
|
const [subject, setSubject] = useState("");
|
||||||
const [talerUri, setTalerUri] = useState("")
|
const [talerUri, setTalerUri] = useState("")
|
||||||
|
|
||||||
const hook = useAsyncAsHook(api.listExchangesDetailled);
|
const hook = useAsyncAsHook(api.listExchanges);
|
||||||
const [exchangeIdx, setExchangeIdx] = useState("0")
|
const [exchangeIdx, setExchangeIdx] = useState("0")
|
||||||
const [operationError, setOperationError] = useState<TalerErrorDetail | undefined>(undefined)
|
const [operationError, setOperationError] = useState<TalerErrorDetail | undefined>(undefined)
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ export function useComponentStateFromParams(
|
|||||||
|
|
||||||
const [ageRestricted, setAgeRestricted] = useState(0);
|
const [ageRestricted, setAgeRestricted] = useState(0);
|
||||||
|
|
||||||
const exchangeHook = useAsyncAsHook(api.listExchangesDetailled);
|
const exchangeHook = useAsyncAsHook(api.listExchanges);
|
||||||
|
|
||||||
const exchangeHookDep =
|
const exchangeHookDep =
|
||||||
!exchangeHook || exchangeHook.hasError || !exchangeHook.response
|
!exchangeHook || exchangeHook.hasError || !exchangeHook.response
|
||||||
@ -65,6 +65,7 @@ export function useComponentStateFromParams(
|
|||||||
exchangeBaseUrl: exchange.exchangeBaseUrl,
|
exchangeBaseUrl: exchange.exchangeBaseUrl,
|
||||||
amount: chosenAmount,
|
amount: chosenAmount,
|
||||||
tosAcceptedFormat: ["text/xml"],
|
tosAcceptedFormat: ["text/xml"],
|
||||||
|
ageRestricted,
|
||||||
});
|
});
|
||||||
|
|
||||||
const withdrawAmount = {
|
const withdrawAmount = {
|
||||||
@ -72,7 +73,7 @@ export function useComponentStateFromParams(
|
|||||||
effective: Amounts.parseOrThrow(info.withdrawalAmountEffective),
|
effective: Amounts.parseOrThrow(info.withdrawalAmountEffective),
|
||||||
}
|
}
|
||||||
|
|
||||||
return { amount: withdrawAmount };
|
return { amount: withdrawAmount, ageRestrictionOptions: info.ageRestrictionOptions };
|
||||||
}, [exchangeHookDep]);
|
}, [exchangeHookDep]);
|
||||||
|
|
||||||
const [reviewing, setReviewing] = useState<boolean>(false);
|
const [reviewing, setReviewing] = useState<boolean>(false);
|
||||||
@ -172,16 +173,16 @@ export function useComponentStateFromParams(
|
|||||||
termsState !== undefined &&
|
termsState !== undefined &&
|
||||||
(termsState.status === "changed" || termsState.status === "new");
|
(termsState.status === "changed" || termsState.status === "new");
|
||||||
|
|
||||||
const ageRestrictionOptions: Record<string, string> | undefined = "6:12:18"
|
const ageRestrictionOptions = amountHook.response.
|
||||||
.split(":")
|
ageRestrictionOptions?.
|
||||||
.reduce((p, c) => ({ ...p, [c]: `under ${c}` }), {});
|
reduce((p, c) => ({ ...p, [c]: `under ${c}` }), {} as Record<string, string>)
|
||||||
|
|
||||||
if (ageRestrictionOptions) {
|
const ageRestrictionEnabled = ageRestrictionOptions !== undefined
|
||||||
|
if (ageRestrictionEnabled) {
|
||||||
ageRestrictionOptions["0"] = "Not restricted";
|
ageRestrictionOptions["0"] = "Not restricted";
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: calculate based on exchange info
|
//TODO: calculate based on exchange info
|
||||||
const ageRestrictionEnabled = false;
|
|
||||||
const ageRestriction = ageRestrictionEnabled ? {
|
const ageRestriction = ageRestrictionEnabled ? {
|
||||||
list: ageRestrictionOptions,
|
list: ageRestrictionOptions,
|
||||||
value: String(ageRestricted),
|
value: String(ageRestricted),
|
||||||
@ -269,6 +270,7 @@ export function useComponentStateFromURI(
|
|||||||
exchangeBaseUrl: uriHookDep?.thisExchange,
|
exchangeBaseUrl: uriHookDep?.thisExchange,
|
||||||
amount: Amounts.parseOrThrow(uriHookDep.amount),
|
amount: Amounts.parseOrThrow(uriHookDep.amount),
|
||||||
tosAcceptedFormat: ["text/xml"],
|
tosAcceptedFormat: ["text/xml"],
|
||||||
|
ageRestricted,
|
||||||
});
|
});
|
||||||
|
|
||||||
const withdrawAmount = {
|
const withdrawAmount = {
|
||||||
@ -276,7 +278,7 @@ export function useComponentStateFromURI(
|
|||||||
effective: Amounts.parseOrThrow(info.withdrawalAmountEffective),
|
effective: Amounts.parseOrThrow(info.withdrawalAmountEffective),
|
||||||
}
|
}
|
||||||
|
|
||||||
return { amount: withdrawAmount };
|
return { amount: withdrawAmount, ageRestrictionOptions: info.ageRestrictionOptions };
|
||||||
}, [uriHookDep]);
|
}, [uriHookDep]);
|
||||||
|
|
||||||
const [reviewing, setReviewing] = useState<boolean>(false);
|
const [reviewing, setReviewing] = useState<boolean>(false);
|
||||||
@ -385,16 +387,16 @@ export function useComponentStateFromURI(
|
|||||||
termsState !== undefined &&
|
termsState !== undefined &&
|
||||||
(termsState.status === "changed" || termsState.status === "new");
|
(termsState.status === "changed" || termsState.status === "new");
|
||||||
|
|
||||||
const ageRestrictionOptions: Record<string, string> | undefined = "6:12:18"
|
const ageRestrictionOptions = amountHook.response.
|
||||||
.split(":")
|
ageRestrictionOptions?.
|
||||||
.reduce((p, c) => ({ ...p, [c]: `under ${c}` }), {});
|
reduce((p, c) => ({ ...p, [c]: `under ${c}` }), {} as Record<string, string>)
|
||||||
|
|
||||||
if (ageRestrictionOptions) {
|
const ageRestrictionEnabled = ageRestrictionOptions !== undefined
|
||||||
|
if (ageRestrictionEnabled) {
|
||||||
ageRestrictionOptions["0"] = "Not restricted";
|
ageRestrictionOptions["0"] = "Not restricted";
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: calculate based on exchange info
|
//TODO: calculate based on exchange info
|
||||||
const ageRestrictionEnabled = false;
|
|
||||||
const ageRestriction = ageRestrictionEnabled ? {
|
const ageRestriction = ageRestrictionEnabled ? {
|
||||||
list: ageRestrictionOptions,
|
list: ageRestrictionOptions,
|
||||||
value: String(ageRestricted),
|
value: String(ageRestricted),
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
Amounts,
|
Amounts,
|
||||||
ExchangeFullDetailsListItem,
|
ExchangeFullDetails,
|
||||||
ExchangeListItem,
|
ExchangeListItem,
|
||||||
GetExchangeTosResult,
|
GetExchangeTosResult,
|
||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
@ -30,7 +30,7 @@ import { expect } from "chai";
|
|||||||
import { mountHook } from "../../test-utils.js";
|
import { mountHook } from "../../test-utils.js";
|
||||||
import { useComponentStateFromURI } from "./state.js";
|
import { useComponentStateFromURI } from "./state.js";
|
||||||
|
|
||||||
const exchanges: ExchangeFullDetailsListItem[] = [
|
const exchanges: ExchangeFullDetails[] = [
|
||||||
{
|
{
|
||||||
currency: "ARS",
|
currency: "ARS",
|
||||||
exchangeBaseUrl: "http://exchange.demo.taler.net",
|
exchangeBaseUrl: "http://exchange.demo.taler.net",
|
||||||
|
@ -171,7 +171,7 @@ export function SelectCurrency({
|
|||||||
}): VNode {
|
}): VNode {
|
||||||
const { i18n } = useTranslationContext();
|
const { i18n } = useTranslationContext();
|
||||||
|
|
||||||
const hook = useAsyncAsHook(wxApi.listExchangesDetailled);
|
const hook = useAsyncAsHook(wxApi.listExchanges);
|
||||||
|
|
||||||
if (!hook) {
|
if (!hook) {
|
||||||
return <Loading />;
|
return <Loading />;
|
||||||
|
@ -45,7 +45,7 @@ export function DeveloperPage(): VNode {
|
|||||||
const response = useAsyncAsHook(async () => {
|
const response = useAsyncAsHook(async () => {
|
||||||
const op = await wxApi.getPendingOperations();
|
const op = await wxApi.getPendingOperations();
|
||||||
const c = await wxApi.dumpCoins();
|
const c = await wxApi.dumpCoins();
|
||||||
const ex = await wxApi.listExchangesDetailled();
|
const ex = await wxApi.listExchanges();
|
||||||
return {
|
return {
|
||||||
operations: op.pendingOperations,
|
operations: op.pendingOperations,
|
||||||
coins: c.coins,
|
coins: c.coins,
|
||||||
|
@ -36,7 +36,7 @@ export function ExchangeAddPage({ currency, onBack }: Props): VNode {
|
|||||||
{ url: string; config: TalerConfigResponse } | undefined
|
{ url: string; config: TalerConfigResponse } | undefined
|
||||||
>(undefined);
|
>(undefined);
|
||||||
|
|
||||||
const knownExchangesResponse = useAsyncAsHook(wxApi.listExchangesDetailled);
|
const knownExchangesResponse = useAsyncAsHook(wxApi.listExchanges);
|
||||||
const knownExchanges = !knownExchangesResponse
|
const knownExchanges = !knownExchangesResponse
|
||||||
? []
|
? []
|
||||||
: knownExchangesResponse.hasError
|
: knownExchangesResponse.hasError
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ExchangeFullDetailsListItem,
|
ExchangeFullDetails,
|
||||||
ExchangeListItem,
|
ExchangeListItem,
|
||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
|
|
||||||
@ -24,7 +24,7 @@ import {
|
|||||||
* @author Sebastian Javier Marchano (sebasjm)
|
* @author Sebastian Javier Marchano (sebasjm)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export const bitcoinExchanges: ExchangeFullDetailsListItem[] = [
|
export const bitcoinExchanges: ExchangeFullDetails[] = [
|
||||||
{
|
{
|
||||||
exchangeBaseUrl: "https://bitcoin1.ice.bfh.ch/",
|
exchangeBaseUrl: "https://bitcoin1.ice.bfh.ch/",
|
||||||
currency: "BITCOINBTC",
|
currency: "BITCOINBTC",
|
||||||
@ -11781,7 +11781,7 @@ export const bitcoinExchanges: ExchangeFullDetailsListItem[] = [
|
|||||||
},
|
},
|
||||||
] as any;
|
] as any;
|
||||||
|
|
||||||
export const kudosExchanges: ExchangeFullDetailsListItem[] = [
|
export const kudosExchanges: ExchangeFullDetails[] = [
|
||||||
{
|
{
|
||||||
exchangeBaseUrl: "https://exchange1.demo.taler.net/",
|
exchangeBaseUrl: "https://exchange1.demo.taler.net/",
|
||||||
currency: "KUDOS",
|
currency: "KUDOS",
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { AbsoluteTime, AmountJson, ExchangeFullDetailsListItem } from "@gnu-taler/taler-util";
|
import { AbsoluteTime, AmountJson, ExchangeFullDetails } from "@gnu-taler/taler-util";
|
||||||
import { Loading } from "../../components/Loading.js";
|
import { Loading } from "../../components/Loading.js";
|
||||||
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
||||||
import { ButtonHandler, SelectFieldHandler } from "../../mui/handlers.js";
|
import { ButtonHandler, SelectFieldHandler } from "../../mui/handlers.js";
|
||||||
@ -52,7 +52,7 @@ export namespace State {
|
|||||||
|
|
||||||
export interface BaseInfo {
|
export interface BaseInfo {
|
||||||
exchanges: SelectFieldHandler;
|
exchanges: SelectFieldHandler;
|
||||||
selected: ExchangeFullDetailsListItem;
|
selected: ExchangeFullDetails;
|
||||||
nextFeeUpdate: AbsoluteTime;
|
nextFeeUpdate: AbsoluteTime;
|
||||||
error: undefined;
|
error: undefined;
|
||||||
}
|
}
|
||||||
|
@ -25,11 +25,21 @@ export function useComponentState(
|
|||||||
{ onCancel, onSelection, currency }: Props,
|
{ onCancel, onSelection, currency }: Props,
|
||||||
api: typeof wxApi,
|
api: typeof wxApi,
|
||||||
): State {
|
): State {
|
||||||
const hook = useAsyncAsHook(api.listExchangesDetailled);
|
|
||||||
|
|
||||||
const initialValue = 0
|
const initialValue = 0
|
||||||
const [value, setValue] = useState(String(initialValue));
|
const [value, setValue] = useState(String(initialValue));
|
||||||
|
|
||||||
|
const hook = useAsyncAsHook(async () => {
|
||||||
|
const { exchanges } = await api.listExchanges()
|
||||||
|
|
||||||
|
const selectedIdx = parseInt(value, 10)
|
||||||
|
const selectedExchange = exchanges.length == 0 ? undefined : exchanges[selectedIdx]
|
||||||
|
const selected = !selectedExchange ? undefined : await api.getExchangeDetailedInfo(selectedExchange.exchangeBaseUrl)
|
||||||
|
|
||||||
|
const initialExchange = selectedIdx === initialValue ? undefined : exchanges[initialValue]
|
||||||
|
const original = !initialExchange ? undefined : await api.getExchangeDetailedInfo(initialExchange.exchangeBaseUrl)
|
||||||
|
return { exchanges, selected, original }
|
||||||
|
});
|
||||||
|
|
||||||
if (!hook) {
|
if (!hook) {
|
||||||
return {
|
return {
|
||||||
status: "loading",
|
status: "loading",
|
||||||
@ -43,18 +53,16 @@ export function useComponentState(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const exchanges = hook.response.exchanges;
|
const { exchanges, selected, original } = hook.response;
|
||||||
|
|
||||||
if (exchanges.length === 0) {
|
if (!selected) {
|
||||||
|
//!selected <=> exchanges.length === 0
|
||||||
return {
|
return {
|
||||||
status: "no-exchanges",
|
status: "no-exchanges",
|
||||||
error: undefined
|
error: undefined
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const original = exchanges[initialValue];
|
|
||||||
const selected = exchanges[Number(value)];
|
|
||||||
|
|
||||||
let nextFeeUpdate = TalerProtocolTimestamp.never();
|
let nextFeeUpdate = TalerProtocolTimestamp.never();
|
||||||
|
|
||||||
nextFeeUpdate = Object.values(selected.wireInfo.feesForType).reduce(
|
nextFeeUpdate = Object.values(selected.wireInfo.feesForType).reduce(
|
||||||
@ -97,7 +105,8 @@ export function useComponentState(
|
|||||||
|
|
||||||
const exchangeMap = exchanges.reduce((prev, cur, idx) => ({ ...prev, [cur.exchangeBaseUrl]: String(idx) }), {} as Record<string, string>)
|
const exchangeMap = exchanges.reduce((prev, cur, idx) => ({ ...prev, [cur.exchangeBaseUrl]: String(idx) }), {} as Record<string, string>)
|
||||||
|
|
||||||
if (original === selected) {
|
if (!original) {
|
||||||
|
// !original <=> selected == original
|
||||||
return {
|
return {
|
||||||
status: "ready",
|
status: "ready",
|
||||||
exchanges: {
|
exchanges: {
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
* @author Sebastian Javier Marchano (sebasjm)
|
* @author Sebastian Javier Marchano (sebasjm)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { ExchangeFullDetailsListItem, ExchangeListItem } from "@gnu-taler/taler-util";
|
import { ExchangeFullDetails, ExchangeListItem } from "@gnu-taler/taler-util";
|
||||||
import { createExample } from "../../test-utils.js";
|
import { createExample } from "../../test-utils.js";
|
||||||
import { bitcoinExchanges, kudosExchanges } from "./example.js";
|
import { bitcoinExchanges, kudosExchanges } from "./example.js";
|
||||||
import { FeeDescription, FeeDescriptionPair, OperationMap } from "./index.js";
|
import { FeeDescription, FeeDescriptionPair, OperationMap } from "./index.js";
|
||||||
@ -34,7 +34,7 @@ export default {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function timelineForExchange(
|
function timelineForExchange(
|
||||||
ex: ExchangeFullDetailsListItem,
|
ex: ExchangeFullDetails,
|
||||||
): OperationMap<FeeDescription[]> {
|
): OperationMap<FeeDescription[]> {
|
||||||
return {
|
return {
|
||||||
deposit: createDenominationTimeline(
|
deposit: createDenominationTimeline(
|
||||||
@ -61,8 +61,8 @@ function timelineForExchange(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function timelinePairForExchange(
|
function timelinePairForExchange(
|
||||||
ex1: ExchangeFullDetailsListItem,
|
ex1: ExchangeFullDetails,
|
||||||
ex2: ExchangeFullDetailsListItem,
|
ex2: ExchangeFullDetails,
|
||||||
): OperationMap<FeeDescriptionPair[]> {
|
): OperationMap<FeeDescriptionPair[]> {
|
||||||
const om1 = timelineForExchange(ex1);
|
const om1 = timelineForExchange(ex1);
|
||||||
const om2 = timelineForExchange(ex2);
|
const om2 = timelineForExchange(ex2);
|
||||||
|
@ -50,7 +50,7 @@ export function ManualWithdrawPage({ amount, onCancel }: Props): VNode {
|
|||||||
>(undefined);
|
>(undefined);
|
||||||
const [error, setError] = useState<string | undefined>(undefined);
|
const [error, setError] = useState<string | undefined>(undefined);
|
||||||
|
|
||||||
const state = useAsyncAsHook(wxApi.listExchangesDetailled);
|
const state = useAsyncAsHook(wxApi.listExchanges);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
return wxApi.onUpdateNotification([NotificationType.ExchangeAdded], () => {
|
return wxApi.onUpdateNotification([NotificationType.ExchangeAdded], () => {
|
||||||
state?.retry();
|
state?.retry();
|
||||||
|
@ -49,7 +49,7 @@ export function SettingsPage(): VNode {
|
|||||||
const webex = platform.getWalletWebExVersion();
|
const webex = platform.getWalletWebExVersion();
|
||||||
|
|
||||||
const exchangesHook = useAsyncAsHook(async () => {
|
const exchangesHook = useAsyncAsHook(async () => {
|
||||||
const list = await wxApi.listExchangesDetailled();
|
const list = await wxApi.listExchanges();
|
||||||
const version = await wxApi.getVersion();
|
const version = await wxApi.getVersion();
|
||||||
return { exchanges: list.exchanges, version };
|
return { exchanges: list.exchanges, version };
|
||||||
});
|
});
|
||||||
|
@ -563,7 +563,7 @@ export const InvoiceCreditComplete = createExample(TestedComponent, {
|
|||||||
export const InvoiceCreditIncomplete = createExample(TestedComponent, {
|
export const InvoiceCreditIncomplete = createExample(TestedComponent, {
|
||||||
transaction: {
|
transaction: {
|
||||||
...exampleData.pull_credit,
|
...exampleData.pull_credit,
|
||||||
info: { ...exampleData.pull_credit.info, completed: false },
|
pending: true,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -581,9 +581,6 @@ export const TransferDebitComplete = createExample(TestedComponent, {
|
|||||||
export const TransferDebitIncomplete = createExample(TestedComponent, {
|
export const TransferDebitIncomplete = createExample(TestedComponent, {
|
||||||
transaction: {
|
transaction: {
|
||||||
...exampleData.push_debit,
|
...exampleData.push_debit,
|
||||||
info: {
|
pending: true,
|
||||||
...exampleData.push_debit.info,
|
|
||||||
completed: false,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -167,6 +167,8 @@ export function TransactionView({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const SHOWING_RETRY_THRESHOLD_SECS = 30;
|
||||||
|
|
||||||
const { i18n } = useTranslationContext();
|
const { i18n } = useTranslationContext();
|
||||||
|
|
||||||
function TransactionTemplate({
|
function TransactionTemplate({
|
||||||
@ -174,15 +176,16 @@ export function TransactionView({
|
|||||||
}: {
|
}: {
|
||||||
children: ComponentChildren;
|
children: ComponentChildren;
|
||||||
}): VNode {
|
}): VNode {
|
||||||
const showSend =
|
const showSend = false;
|
||||||
(transaction.type === TransactionType.PeerPullCredit ||
|
// (transaction.type === TransactionType.PeerPullCredit ||
|
||||||
transaction.type === TransactionType.PeerPushDebit) &&
|
// transaction.type === TransactionType.PeerPushDebit) &&
|
||||||
!transaction.info.completed;
|
// !transaction.info.completed;
|
||||||
const showRetry =
|
const showRetry =
|
||||||
transaction.error !== undefined ||
|
transaction.error !== undefined ||
|
||||||
transaction.timestamp.t_s === "never" ||
|
transaction.timestamp.t_s === "never" ||
|
||||||
(transaction.pending &&
|
(transaction.pending &&
|
||||||
differenceInSeconds(new Date(), transaction.timestamp.t_s * 1000) > 10);
|
differenceInSeconds(new Date(), transaction.timestamp.t_s * 1000) >
|
||||||
|
SHOWING_RETRY_THRESHOLD_SECS);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
@ -624,7 +627,7 @@ export function TransactionView({
|
|||||||
text={transaction.exchangeBaseUrl}
|
text={transaction.exchangeBaseUrl}
|
||||||
kind="neutral"
|
kind="neutral"
|
||||||
/>
|
/>
|
||||||
{!transaction.info.completed && (
|
{transaction.pending && (
|
||||||
<Part
|
<Part
|
||||||
title={<i18n.Translate>URI</i18n.Translate>}
|
title={<i18n.Translate>URI</i18n.Translate>}
|
||||||
text={<ShowQrWithCopy text={transaction.talerUri} />}
|
text={<ShowQrWithCopy text={transaction.talerUri} />}
|
||||||
@ -710,7 +713,7 @@ export function TransactionView({
|
|||||||
text={transaction.exchangeBaseUrl}
|
text={transaction.exchangeBaseUrl}
|
||||||
kind="neutral"
|
kind="neutral"
|
||||||
/>
|
/>
|
||||||
{!transaction.info.completed && (
|
{transaction.pending && (
|
||||||
<Part
|
<Part
|
||||||
title={<i18n.Translate>URI</i18n.Translate>}
|
title={<i18n.Translate>URI</i18n.Translate>}
|
||||||
text={<ShowQrWithCopy text={transaction.talerUri} />}
|
text={<ShowQrWithCopy text={transaction.talerUri} />}
|
||||||
|
@ -42,7 +42,7 @@ import {
|
|||||||
CreateDepositGroupRequest,
|
CreateDepositGroupRequest,
|
||||||
CreateDepositGroupResponse,
|
CreateDepositGroupResponse,
|
||||||
DeleteTransactionRequest,
|
DeleteTransactionRequest,
|
||||||
ExchangesListRespose,
|
ExchangesListResponse,
|
||||||
GetExchangeTosResult,
|
GetExchangeTosResult,
|
||||||
GetExchangeWithdrawalInfo,
|
GetExchangeWithdrawalInfo,
|
||||||
GetFeeForDepositRequest,
|
GetFeeForDepositRequest,
|
||||||
@ -67,7 +67,7 @@ import {
|
|||||||
WalletDiagnostics,
|
WalletDiagnostics,
|
||||||
WalletCoreVersion,
|
WalletCoreVersion,
|
||||||
WithdrawUriInfoResponse,
|
WithdrawUriInfoResponse,
|
||||||
ExchangeDetailledListRespose,
|
ExchangeFullDetails,
|
||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
import {
|
import {
|
||||||
AddBackupProviderRequest,
|
AddBackupProviderRequest,
|
||||||
@ -253,12 +253,14 @@ export function listKnownCurrencies(): Promise<ListOfKnownCurrencies> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function listExchanges(): Promise<ExchangesListRespose> {
|
export function listExchanges(): Promise<ExchangesListResponse> {
|
||||||
return callBackend("listExchanges", {});
|
return callBackend("listExchanges", {});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function listExchangesDetailled(): Promise<ExchangeDetailledListRespose> {
|
export function getExchangeDetailedInfo(exchangeBaseUrl: string): Promise<ExchangeFullDetails> {
|
||||||
return callBackend("listExchangesDetailled", {});
|
return callBackend("getExchangeDetailedInfo", {
|
||||||
|
exchangeBaseUrl
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getVersion(): Promise<WalletCoreVersion> {
|
export function getVersion(): Promise<WalletCoreVersion> {
|
||||||
|
Loading…
Reference in New Issue
Block a user