wallet-core, wallet-cli: add status to exchange list, add detail query to CLI
This commit is contained in:
parent
d98d49aa58
commit
fbb7dd9e7e
@ -905,13 +905,27 @@ export enum ExchangeTosStatus {
|
|||||||
Accepted = "accepted",
|
Accepted = "accepted",
|
||||||
Changed = "changed",
|
Changed = "changed",
|
||||||
NotFound = "not-found",
|
NotFound = "not-found",
|
||||||
|
Unknown = "unknown",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum ExchangeEntryStatus {
|
||||||
|
Unknown = "unknown",
|
||||||
|
Outdated = "outdated",
|
||||||
|
Ok = "ok",
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: This should probably include some error status.
|
||||||
export interface ExchangeListItem {
|
export interface ExchangeListItem {
|
||||||
exchangeBaseUrl: string;
|
exchangeBaseUrl: string;
|
||||||
currency: string;
|
currency: string | undefined;
|
||||||
paytoUris: string[];
|
paytoUris: string[];
|
||||||
tosStatus: ExchangeTosStatus;
|
tosStatus: ExchangeTosStatus;
|
||||||
|
exchangeStatus: ExchangeEntryStatus;
|
||||||
|
/**
|
||||||
|
* Permanently added to the wallet, as opposed to just
|
||||||
|
* temporarily queried.
|
||||||
|
*/
|
||||||
|
permanent: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const codecForAuditorDenomSig = (): Codec<AuditorDenomSig> =>
|
const codecForAuditorDenomSig = (): Codec<AuditorDenomSig> =>
|
||||||
@ -984,6 +998,8 @@ export const codecForExchangeListItem = (): Codec<ExchangeListItem> =>
|
|||||||
.property("exchangeBaseUrl", codecForString())
|
.property("exchangeBaseUrl", codecForString())
|
||||||
.property("paytoUris", codecForList(codecForString()))
|
.property("paytoUris", codecForList(codecForString()))
|
||||||
.property("tosStatus", codecForAny())
|
.property("tosStatus", codecForAny())
|
||||||
|
.property("exchangeStatus", codecForAny())
|
||||||
|
.property("permanent", codecForBoolean())
|
||||||
.build("ExchangeListItem");
|
.build("ExchangeListItem");
|
||||||
|
|
||||||
export const codecForExchangesListResponse = (): Codec<ExchangesListResponse> =>
|
export const codecForExchangesListResponse = (): Codec<ExchangesListResponse> =>
|
||||||
|
@ -549,6 +549,25 @@ exchangesCli
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
exchangesCli
|
||||||
|
.subcommand("exchangesShowCmd", "show", {
|
||||||
|
help: "Show exchange details",
|
||||||
|
})
|
||||||
|
.requiredArgument("url", clk.STRING, {
|
||||||
|
help: "Base URL of the exchange.",
|
||||||
|
})
|
||||||
|
.action(async (args) => {
|
||||||
|
await withWallet(args, async (wallet) => {
|
||||||
|
const resp = await wallet.client.call(
|
||||||
|
WalletApiOperation.GetExchangeDetailedInfo,
|
||||||
|
{
|
||||||
|
exchangeBaseUrl: args.exchangesShowCmd.url,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
console.log(JSON.stringify(resp, undefined, 2));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
exchangesCli
|
exchangesCli
|
||||||
.subcommand("exchangesAddCmd", "add", {
|
.subcommand("exchangesAddCmd", "add", {
|
||||||
help: "Add an exchange by base URL.",
|
help: "Add an exchange by base URL.",
|
||||||
|
@ -17,45 +17,42 @@
|
|||||||
/**
|
/**
|
||||||
* Imports.
|
* Imports.
|
||||||
*/
|
*/
|
||||||
|
import { Event, IDBDatabase } from "@gnu-taler/idb-bridge";
|
||||||
import {
|
import {
|
||||||
describeStore,
|
AgeCommitmentProof,
|
||||||
describeContents,
|
|
||||||
describeIndex,
|
|
||||||
} from "./util/query.js";
|
|
||||||
import {
|
|
||||||
AmountJson,
|
AmountJson,
|
||||||
AmountString,
|
AmountString,
|
||||||
ExchangeAuditor,
|
CoinEnvelope,
|
||||||
CoinDepositPermission,
|
CoinRefreshRequest,
|
||||||
|
CoinStatus,
|
||||||
ContractTerms,
|
ContractTerms,
|
||||||
|
DenominationInfo,
|
||||||
DenominationPubKey,
|
DenominationPubKey,
|
||||||
ExchangeSignKeyJson,
|
DenomSelectionState,
|
||||||
|
EddsaPublicKeyString,
|
||||||
|
EddsaSignatureString,
|
||||||
|
ExchangeAuditor,
|
||||||
|
ExchangeGlobalFees,
|
||||||
InternationalizedString,
|
InternationalizedString,
|
||||||
|
Location,
|
||||||
MerchantInfo,
|
MerchantInfo,
|
||||||
|
PayCoinSelection,
|
||||||
|
PeerContractTerms,
|
||||||
Product,
|
Product,
|
||||||
RefreshReason,
|
RefreshReason,
|
||||||
TalerErrorDetail,
|
TalerErrorDetail,
|
||||||
UnblindedSignature,
|
|
||||||
CoinEnvelope,
|
|
||||||
TalerProtocolTimestamp,
|
|
||||||
TalerProtocolDuration,
|
TalerProtocolDuration,
|
||||||
AgeCommitmentProof,
|
TalerProtocolTimestamp,
|
||||||
PayCoinSelection,
|
|
||||||
PeerContractTerms,
|
|
||||||
Location,
|
|
||||||
WireInfo,
|
|
||||||
DenominationInfo,
|
|
||||||
GlobalFees,
|
|
||||||
ExchangeGlobalFees,
|
|
||||||
DenomSelectionState,
|
|
||||||
TransactionIdStr,
|
TransactionIdStr,
|
||||||
CoinRefreshRequest,
|
UnblindedSignature,
|
||||||
CoinStatus,
|
WireInfo,
|
||||||
EddsaPublicKeyString,
|
|
||||||
EddsaSignatureString,
|
|
||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
|
import {
|
||||||
|
describeContents,
|
||||||
|
describeIndex,
|
||||||
|
describeStore,
|
||||||
|
} from "./util/query.js";
|
||||||
import { RetryInfo, RetryTags } from "./util/retries.js";
|
import { RetryInfo, RetryTags } from "./util/retries.js";
|
||||||
import { Event, IDBDatabase } from "@gnu-taler/idb-bridge";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file contains the database schema of the Taler wallet together
|
* This file contains the database schema of the Taler wallet together
|
||||||
@ -354,8 +351,6 @@ export interface DenominationRecord {
|
|||||||
* Was this denomination still offered by the exchange the last time
|
* Was this denomination still offered by the exchange the last time
|
||||||
* we checked?
|
* we checked?
|
||||||
* Only false when the exchange redacts a previously published denomination.
|
* Only false when the exchange redacts a previously published denomination.
|
||||||
*
|
|
||||||
* FIXME: Consider rolling this and isRevoked into some bitfield?
|
|
||||||
*/
|
*/
|
||||||
isOffered: boolean;
|
isOffered: boolean;
|
||||||
|
|
||||||
@ -526,6 +521,8 @@ export interface ExchangeRecord {
|
|||||||
* Should usually not change. Only changes when the
|
* Should usually not change. Only changes when the
|
||||||
* exchange advertises a different master public key and/or
|
* exchange advertises a different master public key and/or
|
||||||
* currency.
|
* currency.
|
||||||
|
*
|
||||||
|
* FIXME: Use a rowId here?
|
||||||
*/
|
*/
|
||||||
detailsPointer: ExchangeDetailsPointer | undefined;
|
detailsPointer: ExchangeDetailsPointer | undefined;
|
||||||
|
|
||||||
@ -1168,8 +1165,6 @@ export interface PurchaseRecord {
|
|||||||
/**
|
/**
|
||||||
* Timestamp of the first time that sending a payment to the merchant
|
* Timestamp of the first time that sending a payment to the merchant
|
||||||
* for this purchase was successful.
|
* for this purchase was successful.
|
||||||
*
|
|
||||||
* FIXME: Does this need to be a timestamp, doesn't boolean suffice?
|
|
||||||
*/
|
*/
|
||||||
timestampFirstSuccessfulPay: TalerProtocolTimestamp | undefined;
|
timestampFirstSuccessfulPay: TalerProtocolTimestamp | undefined;
|
||||||
|
|
||||||
@ -1369,6 +1364,8 @@ export interface WithdrawalGroupRecord {
|
|||||||
/**
|
/**
|
||||||
* Wire information (as payto URI) for the bank account that
|
* Wire information (as payto URI) for the bank account that
|
||||||
* transferred funds for this reserve.
|
* transferred funds for this reserve.
|
||||||
|
*
|
||||||
|
* FIXME: Doesn't this belong to the bankAccounts object store?
|
||||||
*/
|
*/
|
||||||
senderWire?: string;
|
senderWire?: string;
|
||||||
|
|
||||||
@ -1604,7 +1601,7 @@ export interface GhostDepositGroupRecord {
|
|||||||
|
|
||||||
export interface TombstoneRecord {
|
export interface TombstoneRecord {
|
||||||
/**
|
/**
|
||||||
* Tombstone ID, with the syntax "<type>:<key>".
|
* Tombstone ID, with the syntax "tmb:<type>:<key>".
|
||||||
*/
|
*/
|
||||||
id: string;
|
id: string;
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,8 @@ import {
|
|||||||
Amounts,
|
Amounts,
|
||||||
CoinRefreshRequest,
|
CoinRefreshRequest,
|
||||||
CoinStatus,
|
CoinStatus,
|
||||||
|
ExchangeEntryStatus,
|
||||||
|
ExchangeListItem,
|
||||||
ExchangeTosStatus,
|
ExchangeTosStatus,
|
||||||
j2s,
|
j2s,
|
||||||
Logger,
|
Logger,
|
||||||
@ -32,7 +34,12 @@ import {
|
|||||||
TransactionIdStr,
|
TransactionIdStr,
|
||||||
TransactionType,
|
TransactionType,
|
||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
import { WalletStoresV1, CoinRecord, ExchangeDetailsRecord } from "../db.js";
|
import {
|
||||||
|
WalletStoresV1,
|
||||||
|
CoinRecord,
|
||||||
|
ExchangeDetailsRecord,
|
||||||
|
ExchangeRecord,
|
||||||
|
} from "../db.js";
|
||||||
import { makeErrorDetail, TalerError } from "../errors.js";
|
import { makeErrorDetail, TalerError } from "../errors.js";
|
||||||
import { InternalWalletState } from "../internal-wallet-state.js";
|
import { InternalWalletState } from "../internal-wallet-state.js";
|
||||||
import { checkDbInvariant, checkLogicInvariant } from "../util/invariants.js";
|
import { checkDbInvariant, checkLogicInvariant } from "../util/invariants.js";
|
||||||
@ -320,3 +327,29 @@ export function getExchangeTosStatus(
|
|||||||
}
|
}
|
||||||
return ExchangeTosStatus.Changed;
|
return ExchangeTosStatus.Changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function makeExchangeListItem(
|
||||||
|
r: ExchangeRecord,
|
||||||
|
exchangeDetails: ExchangeDetailsRecord | undefined,
|
||||||
|
): ExchangeListItem {
|
||||||
|
if (!exchangeDetails) {
|
||||||
|
return {
|
||||||
|
exchangeBaseUrl: r.baseUrl,
|
||||||
|
currency: undefined,
|
||||||
|
tosStatus: ExchangeTosStatus.Unknown,
|
||||||
|
paytoUris: [],
|
||||||
|
exchangeStatus: ExchangeEntryStatus.Unknown,
|
||||||
|
permanent: r.permanent,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
let exchangeStatus;
|
||||||
|
exchangeStatus = ExchangeEntryStatus.Ok;
|
||||||
|
return {
|
||||||
|
exchangeBaseUrl: r.baseUrl,
|
||||||
|
currency: exchangeDetails.currency,
|
||||||
|
tosStatus: getExchangeTosStatus(exchangeDetails),
|
||||||
|
paytoUris: exchangeDetails.wireInfo.accounts.map((x) => x.payto_uri),
|
||||||
|
exchangeStatus,
|
||||||
|
permanent: r.permanent,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
@ -705,8 +705,6 @@ export async function updateExchangeFromUrlHandler(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
await tx.exchanges.put(r);
|
await tx.exchanges.put(r);
|
||||||
logger.info(`existing details ${j2s(existingDetails)}`);
|
|
||||||
logger.info(`inserting new details ${j2s(newDetails)}`);
|
|
||||||
const drRowId = await tx.exchangeDetails.put(newDetails);
|
const drRowId = await tx.exchangeDetails.put(newDetails);
|
||||||
checkDbInvariant(typeof drRowId.key === "number");
|
checkDbInvariant(typeof drRowId.key === "number");
|
||||||
|
|
||||||
|
@ -85,6 +85,7 @@ import { InternalWalletState } from "../internal-wallet-state.js";
|
|||||||
import {
|
import {
|
||||||
getExchangeTosStatus,
|
getExchangeTosStatus,
|
||||||
makeCoinAvailable,
|
makeCoinAvailable,
|
||||||
|
makeExchangeListItem,
|
||||||
runOperationWithErrorReporting,
|
runOperationWithErrorReporting,
|
||||||
} from "../operations/common.js";
|
} from "../operations/common.js";
|
||||||
import { walletCoreDebugFlags } from "../util/debugFlags.js";
|
import { walletCoreDebugFlags } from "../util/debugFlags.js";
|
||||||
@ -1367,18 +1368,7 @@ export async function getWithdrawalDetailsForUri(
|
|||||||
.iter(r.baseUrl)
|
.iter(r.baseUrl)
|
||||||
.toArray();
|
.toArray();
|
||||||
if (exchangeDetails && denominations) {
|
if (exchangeDetails && denominations) {
|
||||||
const tosRecord = await tx.exchangeTos.get([
|
exchanges.push(makeExchangeListItem(r, exchangeDetails));
|
||||||
exchangeDetails.exchangeBaseUrl,
|
|
||||||
exchangeDetails.tosCurrentEtag,
|
|
||||||
]);
|
|
||||||
exchanges.push({
|
|
||||||
exchangeBaseUrl: exchangeDetails.exchangeBaseUrl,
|
|
||||||
currency: exchangeDetails.currency,
|
|
||||||
paytoUris: exchangeDetails.wireInfo.accounts.map(
|
|
||||||
(x) => x.payto_uri,
|
|
||||||
),
|
|
||||||
tosStatus: getExchangeTosStatus(exchangeDetails),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -49,7 +49,6 @@ export enum OperationAttemptResultType {
|
|||||||
Longpoll = "longpoll",
|
Longpoll = "longpoll",
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: not part of DB!
|
|
||||||
export type OperationAttemptResult<TSuccess = unknown, TPending = unknown> =
|
export type OperationAttemptResult<TSuccess = unknown, TPending = unknown> =
|
||||||
| OperationAttemptFinishedResult<TSuccess>
|
| OperationAttemptFinishedResult<TSuccess>
|
||||||
| OperationAttemptErrorResult
|
| OperationAttemptErrorResult
|
||||||
|
@ -48,6 +48,7 @@ import {
|
|||||||
CreateDepositGroupRequest,
|
CreateDepositGroupRequest,
|
||||||
CreateDepositGroupResponse,
|
CreateDepositGroupResponse,
|
||||||
DeleteTransactionRequest,
|
DeleteTransactionRequest,
|
||||||
|
ExchangeDetailedResponse,
|
||||||
ExchangesListResponse,
|
ExchangesListResponse,
|
||||||
ForceRefreshRequest,
|
ForceRefreshRequest,
|
||||||
GetExchangeTosRequest,
|
GetExchangeTosRequest,
|
||||||
@ -109,6 +110,7 @@ export enum WalletApiOperation {
|
|||||||
ApplyRefund = "applyRefund",
|
ApplyRefund = "applyRefund",
|
||||||
AcceptBankIntegratedWithdrawal = "acceptBankIntegratedWithdrawal",
|
AcceptBankIntegratedWithdrawal = "acceptBankIntegratedWithdrawal",
|
||||||
GetExchangeTos = "getExchangeTos",
|
GetExchangeTos = "getExchangeTos",
|
||||||
|
GetExchangeDetailedInfo = "getExchangeDetailedInfo",
|
||||||
RetryPendingNow = "retryPendingNow",
|
RetryPendingNow = "retryPendingNow",
|
||||||
AbortFailedPayWithRefund = "abortFailedPayWithRefund",
|
AbortFailedPayWithRefund = "abortFailedPayWithRefund",
|
||||||
ConfirmPay = "confirmPay",
|
ConfirmPay = "confirmPay",
|
||||||
@ -333,6 +335,15 @@ export type GetExchangeTosOp = {
|
|||||||
response: GetExchangeTosResult;
|
response: GetExchangeTosResult;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current terms of a service of an exchange.
|
||||||
|
*/
|
||||||
|
export type GetExchangeDetailedInfoOp = {
|
||||||
|
op: WalletApiOperation.GetExchangeDetailedInfo;
|
||||||
|
request: AddExchangeRequest;
|
||||||
|
response: ExchangeDetailedResponse;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List currencies known to the wallet.
|
* List currencies known to the wallet.
|
||||||
*/
|
*/
|
||||||
@ -661,6 +672,7 @@ export type WalletOperations = {
|
|||||||
[WalletApiOperation.AddExchange]: AddExchangeOp;
|
[WalletApiOperation.AddExchange]: AddExchangeOp;
|
||||||
[WalletApiOperation.SetExchangeTosAccepted]: SetExchangeTosAcceptedOp;
|
[WalletApiOperation.SetExchangeTosAccepted]: SetExchangeTosAcceptedOp;
|
||||||
[WalletApiOperation.GetExchangeTos]: GetExchangeTosOp;
|
[WalletApiOperation.GetExchangeTos]: GetExchangeTosOp;
|
||||||
|
[WalletApiOperation.GetExchangeDetailedInfo]: GetExchangeDetailedInfoOp;
|
||||||
[WalletApiOperation.TrackDepositGroup]: TrackDepositGroupOp;
|
[WalletApiOperation.TrackDepositGroup]: TrackDepositGroupOp;
|
||||||
[WalletApiOperation.CreateDepositGroup]: CreateDepositGroupOp;
|
[WalletApiOperation.CreateDepositGroup]: CreateDepositGroupOp;
|
||||||
[WalletApiOperation.SetWalletDeviceId]: SetWalletDeviceIdOp;
|
[WalletApiOperation.SetWalletDeviceId]: SetWalletDeviceIdOp;
|
||||||
|
@ -97,6 +97,8 @@ import {
|
|||||||
ExchangeTosStatusDetails,
|
ExchangeTosStatusDetails,
|
||||||
CoinRefreshRequest,
|
CoinRefreshRequest,
|
||||||
CoinStatus,
|
CoinStatus,
|
||||||
|
ExchangeEntryStatus,
|
||||||
|
ExchangeTosStatus,
|
||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
import { TalerCryptoInterface } from "./crypto/cryptoImplementation.js";
|
import { TalerCryptoInterface } from "./crypto/cryptoImplementation.js";
|
||||||
import {
|
import {
|
||||||
@ -146,7 +148,11 @@ import {
|
|||||||
} from "./operations/backup/index.js";
|
} from "./operations/backup/index.js";
|
||||||
import { setWalletDeviceId } from "./operations/backup/state.js";
|
import { setWalletDeviceId } from "./operations/backup/state.js";
|
||||||
import { getBalances } from "./operations/balance.js";
|
import { getBalances } from "./operations/balance.js";
|
||||||
import { getExchangeTosStatus, runOperationWithErrorReporting } from "./operations/common.js";
|
import {
|
||||||
|
getExchangeTosStatus,
|
||||||
|
makeExchangeListItem,
|
||||||
|
runOperationWithErrorReporting,
|
||||||
|
} from "./operations/common.js";
|
||||||
import {
|
import {
|
||||||
createDepositGroup,
|
createDepositGroup,
|
||||||
getFeeForDeposit,
|
getFeeForDeposit,
|
||||||
@ -645,32 +651,8 @@ async function getExchanges(
|
|||||||
.runReadOnly(async (tx) => {
|
.runReadOnly(async (tx) => {
|
||||||
const exchangeRecords = await tx.exchanges.iter().toArray();
|
const exchangeRecords = await tx.exchanges.iter().toArray();
|
||||||
for (const r of exchangeRecords) {
|
for (const r of exchangeRecords) {
|
||||||
const dp = r.detailsPointer;
|
|
||||||
if (!dp) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const { currency } = dp;
|
|
||||||
const exchangeDetails = await getExchangeDetails(tx, r.baseUrl);
|
const exchangeDetails = await getExchangeDetails(tx, r.baseUrl);
|
||||||
if (!exchangeDetails) {
|
exchanges.push(makeExchangeListItem(r, exchangeDetails));
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const denominations = await tx.denominations.indexes.byExchangeBaseUrl
|
|
||||||
.iter(r.baseUrl)
|
|
||||||
.toArray();
|
|
||||||
|
|
||||||
if (!denominations) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const tos = await getExchangeTosStatusDetails(tx, exchangeDetails);
|
|
||||||
|
|
||||||
exchanges.push({
|
|
||||||
exchangeBaseUrl: r.baseUrl,
|
|
||||||
currency,
|
|
||||||
tosStatus: getExchangeTosStatus(exchangeDetails),
|
|
||||||
paytoUris: exchangeDetails.wireInfo.accounts.map((x) => x.payto_uri),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return { exchanges };
|
return { exchanges };
|
||||||
|
@ -185,7 +185,11 @@ export function SelectCurrency({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
const list: Record<string, string> = {};
|
const list: Record<string, string> = {};
|
||||||
hook.response.exchanges.forEach((e) => (list[e.currency] = e.currency));
|
hook.response.exchanges.forEach((e) => {
|
||||||
|
if (e.currency) {
|
||||||
|
list[e.currency] = e.currency;
|
||||||
|
}
|
||||||
|
});
|
||||||
list[""] = "Select a currency";
|
list[""] = "Select a currency";
|
||||||
return <SelectCurrencyView onChange={onChange} list={list} />;
|
return <SelectCurrencyView onChange={onChange} list={list} />;
|
||||||
}
|
}
|
||||||
|
@ -112,7 +112,7 @@ export function ManualWithdrawPage({ amount, onCancel }: Props): VNode {
|
|||||||
const exchangeList = state.response.exchanges.reduce(
|
const exchangeList = state.response.exchanges.reduce(
|
||||||
(p, c) => ({
|
(p, c) => ({
|
||||||
...p,
|
...p,
|
||||||
[c.exchangeBaseUrl]: c.currency,
|
[c.exchangeBaseUrl]: c.currency || "??",
|
||||||
}),
|
}),
|
||||||
{} as Record<string, string>,
|
{} as Record<string, string>,
|
||||||
);
|
);
|
||||||
|
@ -204,6 +204,14 @@ export function SettingsView({
|
|||||||
<i18n.Translate>not accepted</i18n.Translate>
|
<i18n.Translate>not accepted</i18n.Translate>
|
||||||
</DestructiveText>
|
</DestructiveText>
|
||||||
);
|
);
|
||||||
|
case ExchangeTosStatus.Unknown:
|
||||||
|
return (
|
||||||
|
<DestructiveText>
|
||||||
|
<i18n.Translate>
|
||||||
|
unknown (exchange status should be updated)
|
||||||
|
</i18n.Translate>
|
||||||
|
</DestructiveText>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
|
Loading…
Reference in New Issue
Block a user