wallet-core: do not rely on reserve history for withdrawals
This commit is contained in:
parent
1607c728bc
commit
9d66078852
@ -43,15 +43,9 @@ export interface ReserveStatus {
|
||||
* Balance left in the reserve.
|
||||
*/
|
||||
balance: AmountString;
|
||||
|
||||
/**
|
||||
* Transaction history for the reserve.
|
||||
*/
|
||||
history: ReserveTransaction[];
|
||||
}
|
||||
|
||||
export const codecForReserveStatus = (): Codec<ReserveStatus> =>
|
||||
buildCodecForObject<ReserveStatus>()
|
||||
.property("balance", codecForString())
|
||||
.property("history", codecForList(codecForReserveTransaction()))
|
||||
.build("ReserveStatus");
|
||||
|
@ -597,9 +597,6 @@ export interface PlanchetRecord {
|
||||
|
||||
denomPubHash: string;
|
||||
|
||||
// FIXME: maybe too redundant?
|
||||
denomPub: DenominationPubKey;
|
||||
|
||||
blindingKey: string;
|
||||
|
||||
withdrawSig: string;
|
||||
@ -607,10 +604,6 @@ export interface PlanchetRecord {
|
||||
coinEv: CoinEnvelope;
|
||||
|
||||
coinEvHash: string;
|
||||
|
||||
coinValue: AmountJson;
|
||||
|
||||
isFromTip: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -685,11 +678,6 @@ export interface CoinRecord {
|
||||
*/
|
||||
coinPriv: string;
|
||||
|
||||
/**
|
||||
* Key used by the exchange used to sign the coin.
|
||||
*/
|
||||
denomPub: DenominationPubKey;
|
||||
|
||||
/**
|
||||
* Hash of the public key that signs the coin.
|
||||
*/
|
||||
@ -1378,6 +1366,8 @@ export interface WithdrawalGroupRecord {
|
||||
|
||||
/**
|
||||
* When was the withdrawal operation completed?
|
||||
*
|
||||
* FIXME: We should probably drop this and introduce an OperationStatus field.
|
||||
*/
|
||||
timestampFinish?: Timestamp;
|
||||
|
||||
|
@ -419,7 +419,6 @@ export async function importBackup(
|
||||
coinPub: compCoin.coinPub,
|
||||
suspended: false,
|
||||
exchangeBaseUrl: backupExchangeDetails.base_url,
|
||||
denomPub: backupDenomination.denom_pub,
|
||||
denomPubHash,
|
||||
status: backupCoin.fresh
|
||||
? CoinStatus.Fresh
|
||||
|
@ -315,7 +315,7 @@ export async function getCandidatePayCoins(
|
||||
candidateCoins.push({
|
||||
availableAmount: coin.currentAmount,
|
||||
coinPub: coin.coinPub,
|
||||
denomPub: coin.denomPub,
|
||||
denomPub: denom.denomPub,
|
||||
feeDeposit: denom.feeDeposit,
|
||||
exchangeBaseUrl: denom.exchangeBaseUrl,
|
||||
});
|
||||
@ -1397,7 +1397,7 @@ export async function generateDepositPermissions(
|
||||
coinPub: coin.coinPub,
|
||||
contractTermsHash: contractData.contractTermsHash,
|
||||
denomPubHash: coin.denomPubHash,
|
||||
denomKeyType: coin.denomPub.cipher,
|
||||
denomKeyType: denom.denomPub.cipher,
|
||||
denomSig: coin.denomSig,
|
||||
exchangeBaseUrl: coin.exchangeBaseUrl,
|
||||
feeDeposit: denom.feeDeposit,
|
||||
|
@ -164,18 +164,34 @@ async function recoupWithdrawCoin(
|
||||
cs: WithdrawCoinSource,
|
||||
): Promise<void> {
|
||||
const reservePub = cs.reservePub;
|
||||
const reserve = await ws.db
|
||||
const d = await ws.db
|
||||
.mktx((x) => ({
|
||||
reserves: x.reserves,
|
||||
denominations: x.denominations,
|
||||
}))
|
||||
.runReadOnly(async (tx) => {
|
||||
return tx.reserves.get(reservePub);
|
||||
const reserve = await tx.reserves.get(reservePub);
|
||||
if (!reserve) {
|
||||
return;
|
||||
}
|
||||
const denomInfo = await ws.getDenomInfo(
|
||||
ws,
|
||||
tx,
|
||||
reserve.exchangeBaseUrl,
|
||||
coin.denomPubHash,
|
||||
);
|
||||
if (!denomInfo) {
|
||||
return;
|
||||
}
|
||||
return { reserve, denomInfo };
|
||||
});
|
||||
if (!reserve) {
|
||||
if (!d) {
|
||||
// FIXME: We should at least emit some pending operation / warning for this?
|
||||
return;
|
||||
}
|
||||
|
||||
const { reserve, denomInfo } = d;
|
||||
|
||||
ws.notify({
|
||||
type: NotificationType.RecoupStarted,
|
||||
});
|
||||
@ -184,7 +200,7 @@ async function recoupWithdrawCoin(
|
||||
blindingKey: coin.blindingKey,
|
||||
coinPriv: coin.coinPriv,
|
||||
coinPub: coin.coinPub,
|
||||
denomPub: coin.denomPub,
|
||||
denomPub: denomInfo.denomPub,
|
||||
denomPubHash: coin.denomPubHash,
|
||||
denomSig: coin.denomSig,
|
||||
});
|
||||
@ -253,6 +269,28 @@ async function recoupRefreshCoin(
|
||||
coin: CoinRecord,
|
||||
cs: RefreshCoinSource,
|
||||
): Promise<void> {
|
||||
const d = await ws.db
|
||||
.mktx((x) => ({
|
||||
coins: x.coins,
|
||||
denominations: x.denominations,
|
||||
}))
|
||||
.runReadOnly(async (tx) => {
|
||||
const denomInfo = await ws.getDenomInfo(
|
||||
ws,
|
||||
tx,
|
||||
coin.exchangeBaseUrl,
|
||||
coin.denomPubHash,
|
||||
);
|
||||
if (!denomInfo) {
|
||||
return;
|
||||
}
|
||||
return { denomInfo };
|
||||
});
|
||||
if (!d) {
|
||||
// FIXME: We should at least emit some pending operation / warning for this?
|
||||
return;
|
||||
}
|
||||
|
||||
ws.notify({
|
||||
type: NotificationType.RecoupStarted,
|
||||
});
|
||||
@ -261,7 +299,7 @@ async function recoupRefreshCoin(
|
||||
blindingKey: coin.blindingKey,
|
||||
coinPriv: coin.coinPriv,
|
||||
coinPub: coin.coinPub,
|
||||
denomPub: coin.denomPub,
|
||||
denomPub: d.denomInfo.denomPub,
|
||||
denomPubHash: coin.denomPubHash,
|
||||
denomSig: coin.denomSig,
|
||||
});
|
||||
|
@ -395,7 +395,7 @@ async function refreshMelt(
|
||||
oldCoin.exchangeBaseUrl,
|
||||
);
|
||||
let meltReqBody: any;
|
||||
if (oldCoin.denomPub.cipher === DenomKeyType.Rsa) {
|
||||
if (oldDenom.denomPub.cipher === DenomKeyType.Rsa) {
|
||||
meltReqBody = {
|
||||
coin_pub: oldCoin.coinPub,
|
||||
confirm_sig: derived.confirmSig,
|
||||
@ -671,7 +671,6 @@ async function refreshReveal(
|
||||
coinPriv: pc.coinPriv,
|
||||
coinPub: pc.coinPub,
|
||||
currentAmount: denom.value,
|
||||
denomPub: denom.denomPub,
|
||||
denomPubHash: denom.denomPubHash,
|
||||
denomSig: {
|
||||
cipher: DenomKeyType.Rsa,
|
||||
|
@ -587,8 +587,8 @@ async function updateReserve(
|
||||
logger.trace(`got reserve status ${j2s(result.response)}`);
|
||||
|
||||
const reserveInfo = result.response;
|
||||
const balance = Amounts.parseOrThrow(reserveInfo.balance);
|
||||
const currency = balance.currency;
|
||||
const reserveBalance = Amounts.parseOrThrow(reserveInfo.balance);
|
||||
const currency = reserveBalance.currency;
|
||||
|
||||
await updateWithdrawalDenoms(ws, reserve.exchangeBaseUrl);
|
||||
const denoms = await getCandidateWithdrawalDenoms(
|
||||
@ -598,73 +598,50 @@ async function updateReserve(
|
||||
|
||||
const newWithdrawalGroup = await ws.db
|
||||
.mktx((x) => ({
|
||||
coins: x.coins,
|
||||
planchets: x.planchets,
|
||||
withdrawalGroups: x.withdrawalGroups,
|
||||
reserves: x.reserves,
|
||||
denominations: x.denominations,
|
||||
}))
|
||||
.runReadWrite(async (tx) => {
|
||||
const newReserve = await tx.reserves.get(reserve.reservePub);
|
||||
if (!newReserve) {
|
||||
return;
|
||||
}
|
||||
let amountReservePlus = Amounts.getZero(currency);
|
||||
let amountReservePlus = reserveBalance;
|
||||
let amountReserveMinus = Amounts.getZero(currency);
|
||||
|
||||
// Subtract withdrawal groups for this reserve from the available amount.
|
||||
// Subtract amount allocated in unfinished withdrawal groups
|
||||
// for this reserve from the available amount.
|
||||
await tx.withdrawalGroups.indexes.byReservePub
|
||||
.iter(reservePub)
|
||||
.forEach((wg) => {
|
||||
const cost = wg.denomsSel.totalWithdrawCost;
|
||||
amountReserveMinus = Amounts.add(amountReserveMinus, cost).amount;
|
||||
});
|
||||
|
||||
for (const entry of reserveInfo.history) {
|
||||
switch (entry.type) {
|
||||
case ReserveTransactionType.Credit:
|
||||
amountReservePlus = Amounts.add(
|
||||
amountReservePlus,
|
||||
Amounts.parseOrThrow(entry.amount),
|
||||
).amount;
|
||||
break;
|
||||
case ReserveTransactionType.Recoup:
|
||||
amountReservePlus = Amounts.add(
|
||||
amountReservePlus,
|
||||
Amounts.parseOrThrow(entry.amount),
|
||||
).amount;
|
||||
break;
|
||||
case ReserveTransactionType.Closing:
|
||||
amountReserveMinus = Amounts.add(
|
||||
amountReserveMinus,
|
||||
Amounts.parseOrThrow(entry.amount),
|
||||
).amount;
|
||||
break;
|
||||
case ReserveTransactionType.Withdraw: {
|
||||
// Now we check if the withdrawal transaction
|
||||
// is part of any withdrawal known to this wallet.
|
||||
const planchet = await tx.planchets.indexes.byCoinEvHash.get(
|
||||
entry.h_coin_envelope,
|
||||
);
|
||||
if (planchet) {
|
||||
// Amount is already accounted in some withdrawal session
|
||||
break;
|
||||
}
|
||||
const coin = await tx.coins.indexes.byCoinEvHash.get(
|
||||
entry.h_coin_envelope,
|
||||
);
|
||||
if (coin) {
|
||||
// Amount is already accounted in some withdrawal session
|
||||
break;
|
||||
}
|
||||
// Amount has been claimed by some withdrawal we don't know about
|
||||
amountReserveMinus = Amounts.add(
|
||||
amountReserveMinus,
|
||||
Amounts.parseOrThrow(entry.amount),
|
||||
).amount;
|
||||
break;
|
||||
.forEachAsync(async (wg) => {
|
||||
if (wg.timestampFinish) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
await tx.planchets.indexes.byGroup
|
||||
.iter(wg.withdrawalGroupId)
|
||||
.forEachAsync(async (pr) => {
|
||||
if (pr.withdrawalDone) {
|
||||
return;
|
||||
}
|
||||
const denomInfo = await ws.getDenomInfo(
|
||||
ws,
|
||||
tx,
|
||||
wg.exchangeBaseUrl,
|
||||
pr.denomPubHash,
|
||||
);
|
||||
if (!denomInfo) {
|
||||
logger.error(`no denom info found for ${pr.denomPubHash}`);
|
||||
return;
|
||||
}
|
||||
amountReserveMinus = Amounts.add(
|
||||
amountReserveMinus,
|
||||
denomInfo.value,
|
||||
denomInfo.feeWithdraw,
|
||||
).amount;
|
||||
});
|
||||
});
|
||||
|
||||
const remainingAmount = Amounts.sub(
|
||||
amountReservePlus,
|
||||
|
@ -374,7 +374,6 @@ async function processTipImpl(
|
||||
walletTipId: walletTipId,
|
||||
},
|
||||
currentAmount: denom.value,
|
||||
denomPub: denom.denomPub,
|
||||
denomPubHash: denom.denomPubHash,
|
||||
denomSig: { cipher: DenomKeyType.Rsa, rsa_signature: denomSigRsa },
|
||||
exchangeBaseUrl: tipRecord.exchangeBaseUrl,
|
||||
|
@ -418,10 +418,7 @@ async function processPlanchetGenerate(
|
||||
coinIdx,
|
||||
coinPriv: r.coinPriv,
|
||||
coinPub: r.coinPub,
|
||||
coinValue: r.coinValue,
|
||||
denomPub: r.denomPub,
|
||||
denomPubHash: r.denomPubHash,
|
||||
isFromTip: false,
|
||||
reservePub: r.reservePub,
|
||||
withdrawalDone: false,
|
||||
withdrawSig: r.withdrawSig,
|
||||
@ -557,6 +554,7 @@ async function processPlanchetVerifyAndStoreCoin(
|
||||
.mktx((x) => ({
|
||||
withdrawalGroups: x.withdrawalGroups,
|
||||
planchets: x.planchets,
|
||||
denominations: x.denominations,
|
||||
}))
|
||||
.runReadOnly(async (tx) => {
|
||||
let planchet = await tx.planchets.indexes.byGroupAndIndex.get([
|
||||
@ -570,16 +568,29 @@ async function processPlanchetVerifyAndStoreCoin(
|
||||
logger.warn("processPlanchet: planchet already withdrawn");
|
||||
return;
|
||||
}
|
||||
return { planchet, exchangeBaseUrl: withdrawalGroup.exchangeBaseUrl };
|
||||
const denomInfo = await ws.getDenomInfo(
|
||||
ws,
|
||||
tx,
|
||||
withdrawalGroup.exchangeBaseUrl,
|
||||
planchet.denomPubHash,
|
||||
);
|
||||
if (!denomInfo) {
|
||||
return;
|
||||
}
|
||||
return {
|
||||
planchet,
|
||||
denomInfo,
|
||||
exchangeBaseUrl: withdrawalGroup.exchangeBaseUrl,
|
||||
};
|
||||
});
|
||||
|
||||
if (!d) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { planchet, exchangeBaseUrl } = d;
|
||||
const { planchet, denomInfo } = d;
|
||||
|
||||
const planchetDenomPub = planchet.denomPub;
|
||||
const planchetDenomPub = denomInfo.denomPub;
|
||||
if (planchetDenomPub.cipher !== DenomKeyType.Rsa) {
|
||||
throw Error(`cipher (${planchetDenomPub.cipher}) not supported`);
|
||||
}
|
||||
@ -623,9 +634,9 @@ async function processPlanchetVerifyAndStoreCoin(
|
||||
}
|
||||
|
||||
let denomSig: UnblindedSignature;
|
||||
if (planchet.denomPub.cipher === DenomKeyType.Rsa) {
|
||||
if (planchetDenomPub.cipher === DenomKeyType.Rsa) {
|
||||
denomSig = {
|
||||
cipher: planchet.denomPub.cipher,
|
||||
cipher: planchetDenomPub.cipher,
|
||||
rsa_signature: denomSigRsa,
|
||||
};
|
||||
} else {
|
||||
@ -636,12 +647,11 @@ async function processPlanchetVerifyAndStoreCoin(
|
||||
blindingKey: planchet.blindingKey,
|
||||
coinPriv: planchet.coinPriv,
|
||||
coinPub: planchet.coinPub,
|
||||
currentAmount: planchet.coinValue,
|
||||
denomPub: planchet.denomPub,
|
||||
currentAmount: denomInfo.value,
|
||||
denomPubHash: planchet.denomPubHash,
|
||||
denomSig,
|
||||
coinEvHash: planchet.coinEvHash,
|
||||
exchangeBaseUrl: exchangeBaseUrl,
|
||||
exchangeBaseUrl: d.exchangeBaseUrl,
|
||||
status: CoinStatus.Fresh,
|
||||
coinSource: {
|
||||
type: CoinSourceType.Withdraw,
|
||||
|
@ -77,6 +77,8 @@ export interface AvailableCoinInfo {
|
||||
|
||||
/**
|
||||
* Coin's denomination public key.
|
||||
*
|
||||
* FIXME: We should only need the denomPubHash here, if at all.
|
||||
*/
|
||||
denomPub: DenominationPubKey;
|
||||
|
||||
|
@ -24,23 +24,62 @@
|
||||
*/
|
||||
import {
|
||||
AcceptManualWithdrawalResult,
|
||||
AcceptWithdrawalResponse, AmountJson, Amounts, BalancesResponse, codecForAbortPayWithRefundRequest,
|
||||
AcceptWithdrawalResponse,
|
||||
AmountJson,
|
||||
Amounts,
|
||||
BalancesResponse,
|
||||
codecForAbortPayWithRefundRequest,
|
||||
codecForAcceptBankIntegratedWithdrawalRequest,
|
||||
codecForAcceptExchangeTosRequest,
|
||||
codecForAcceptManualWithdrawalRequet,
|
||||
codecForAcceptTipRequest,
|
||||
codecForAddExchangeRequest, codecForAny, codecForApplyRefundRequest,
|
||||
codecForAddExchangeRequest,
|
||||
codecForAny,
|
||||
codecForApplyRefundRequest,
|
||||
codecForConfirmPayRequest,
|
||||
codecForCreateDepositGroupRequest, codecForDeleteTransactionRequest, codecForForceRefreshRequest,
|
||||
codecForGetExchangeTosRequest, codecForGetExchangeWithdrawalInfo, codecForGetFeeForDeposit, codecForGetWithdrawalDetailsForAmountRequest,
|
||||
codecForGetWithdrawalDetailsForUri, codecForImportDbRequest, codecForIntegrationTestArgs, codecForListKnownBankAccounts, codecForPreparePayRequest,
|
||||
codecForPrepareTipRequest, codecForRetryTransactionRequest, codecForSetCoinSuspendedRequest, codecForSetWalletDeviceIdRequest, codecForTestPayArgs,
|
||||
codecForTrackDepositGroupRequest, codecForTransactionsRequest, codecForWithdrawFakebankRequest, codecForWithdrawTestBalance, CoinDumpJson, CoreApiResponse, durationFromSpec,
|
||||
durationMin, ExchangeListItem,
|
||||
ExchangesListRespose, getDurationRemaining, GetExchangeTosResult, isTimestampExpired,
|
||||
j2s, KnownBankAccounts, Logger, ManualWithdrawalDetails, NotificationType, parsePaytoUri, PaytoUri, RefreshReason, TalerErrorCode,
|
||||
codecForCreateDepositGroupRequest,
|
||||
codecForDeleteTransactionRequest,
|
||||
codecForForceRefreshRequest,
|
||||
codecForGetExchangeTosRequest,
|
||||
codecForGetExchangeWithdrawalInfo,
|
||||
codecForGetFeeForDeposit,
|
||||
codecForGetWithdrawalDetailsForAmountRequest,
|
||||
codecForGetWithdrawalDetailsForUri,
|
||||
codecForImportDbRequest,
|
||||
codecForIntegrationTestArgs,
|
||||
codecForListKnownBankAccounts,
|
||||
codecForPreparePayRequest,
|
||||
codecForPrepareTipRequest,
|
||||
codecForRetryTransactionRequest,
|
||||
codecForSetCoinSuspendedRequest,
|
||||
codecForSetWalletDeviceIdRequest,
|
||||
codecForTestPayArgs,
|
||||
codecForTrackDepositGroupRequest,
|
||||
codecForTransactionsRequest,
|
||||
codecForWithdrawFakebankRequest,
|
||||
codecForWithdrawTestBalance,
|
||||
CoinDumpJson,
|
||||
CoreApiResponse,
|
||||
durationFromSpec,
|
||||
durationMin,
|
||||
ExchangeListItem,
|
||||
ExchangesListRespose,
|
||||
getDurationRemaining,
|
||||
GetExchangeTosResult,
|
||||
isTimestampExpired,
|
||||
j2s,
|
||||
KnownBankAccounts,
|
||||
Logger,
|
||||
ManualWithdrawalDetails,
|
||||
NotificationType,
|
||||
parsePaytoUri,
|
||||
PaytoUri,
|
||||
RefreshReason,
|
||||
TalerErrorCode,
|
||||
Timestamp,
|
||||
timestampMin, URL, WalletNotification
|
||||
timestampMin,
|
||||
URL,
|
||||
WalletNotification,
|
||||
} from "@gnu-taler/taler-util";
|
||||
import {
|
||||
DenomInfo,
|
||||
@ -50,7 +89,7 @@ import {
|
||||
MerchantOperations,
|
||||
NotificationListener,
|
||||
RecoupOperations,
|
||||
ReserveOperations
|
||||
ReserveOperations,
|
||||
} from "./common.js";
|
||||
import { CryptoApi, CryptoWorkerFactory } from "./crypto/workers/cryptoApi.js";
|
||||
import {
|
||||
@ -59,12 +98,12 @@ import {
|
||||
exportDb,
|
||||
importDb,
|
||||
ReserveRecordStatus,
|
||||
WalletStoresV1
|
||||
WalletStoresV1,
|
||||
} from "./db.js";
|
||||
import {
|
||||
makeErrorDetails,
|
||||
OperationFailedAndReportedError,
|
||||
OperationFailedError
|
||||
OperationFailedError,
|
||||
} from "./errors.js";
|
||||
import { exportBackup } from "./operations/backup/export.js";
|
||||
import {
|
||||
@ -77,7 +116,7 @@ import {
|
||||
loadBackupRecovery,
|
||||
processBackupForProvider,
|
||||
removeBackupProvider,
|
||||
runBackupCycle
|
||||
runBackupCycle,
|
||||
} from "./operations/backup/index.js";
|
||||
import { setWalletDeviceId } from "./operations/backup/state.js";
|
||||
import { getBalances } from "./operations/balance.js";
|
||||
@ -85,7 +124,7 @@ import {
|
||||
createDepositGroup,
|
||||
getFeeForDeposit,
|
||||
processDepositGroup,
|
||||
trackDepositGroup
|
||||
trackDepositGroup,
|
||||
} from "./operations/deposits.js";
|
||||
import {
|
||||
acceptExchangeTermsOfService,
|
||||
@ -94,62 +133,64 @@ import {
|
||||
getExchangeRequestTimeout,
|
||||
getExchangeTrust,
|
||||
updateExchangeFromUrl,
|
||||
updateExchangeTermsOfService
|
||||
updateExchangeTermsOfService,
|
||||
} from "./operations/exchanges.js";
|
||||
import { getMerchantInfo } from "./operations/merchants.js";
|
||||
import {
|
||||
confirmPay,
|
||||
preparePayForUri,
|
||||
processDownloadProposal,
|
||||
processPurchasePay
|
||||
processPurchasePay,
|
||||
} from "./operations/pay.js";
|
||||
import { getPendingOperations } from "./operations/pending.js";
|
||||
import { createRecoupGroup, processRecoupGroup } from "./operations/recoup.js";
|
||||
import {
|
||||
autoRefresh,
|
||||
createRefreshGroup,
|
||||
processRefreshGroup
|
||||
processRefreshGroup,
|
||||
} from "./operations/refresh.js";
|
||||
import {
|
||||
abortFailedPayWithRefund,
|
||||
applyRefund,
|
||||
processPurchaseQueryRefund
|
||||
processPurchaseQueryRefund,
|
||||
} from "./operations/refund.js";
|
||||
import {
|
||||
createReserve,
|
||||
createTalerWithdrawReserve,
|
||||
getFundingPaytoUris,
|
||||
processReserve
|
||||
processReserve,
|
||||
} from "./operations/reserves.js";
|
||||
import {
|
||||
runIntegrationTest,
|
||||
testPay,
|
||||
withdrawTestBalance
|
||||
withdrawTestBalance,
|
||||
} from "./operations/testing.js";
|
||||
import { acceptTip, prepareTip, processTip } from "./operations/tip.js";
|
||||
import {
|
||||
deleteTransaction,
|
||||
getTransactions,
|
||||
retryTransaction
|
||||
retryTransaction,
|
||||
} from "./operations/transactions.js";
|
||||
import {
|
||||
getExchangeWithdrawalInfo,
|
||||
getWithdrawalDetailsForUri,
|
||||
processWithdrawGroup
|
||||
processWithdrawGroup,
|
||||
} from "./operations/withdraw.js";
|
||||
import {
|
||||
PendingOperationsResponse, PendingTaskInfo, PendingTaskType
|
||||
PendingOperationsResponse,
|
||||
PendingTaskInfo,
|
||||
PendingTaskType,
|
||||
} from "./pending-types.js";
|
||||
import { assertUnreachable } from "./util/assertUnreachable.js";
|
||||
import { AsyncOpMemoMap, AsyncOpMemoSingle } from "./util/asyncMemo.js";
|
||||
import {
|
||||
HttpRequestLibrary,
|
||||
readSuccessResponseJsonOrThrow
|
||||
readSuccessResponseJsonOrThrow,
|
||||
} from "./util/http.js";
|
||||
import {
|
||||
AsyncCondition,
|
||||
OpenedPromise,
|
||||
openPromise
|
||||
openPromise,
|
||||
} from "./util/promiseUtils.js";
|
||||
import { DbAccess, GetReadWriteAccess } from "./util/query.js";
|
||||
import { TimerGroup } from "./util/timer.js";
|
||||
@ -455,7 +496,10 @@ async function getExchangeTos(
|
||||
) {
|
||||
throw Error("exchange is in invalid state");
|
||||
}
|
||||
if (acceptedFormat && acceptedFormat.findIndex(f => f === contentType) !== -1) {
|
||||
if (
|
||||
acceptedFormat &&
|
||||
acceptedFormat.findIndex((f) => f === contentType) !== -1
|
||||
) {
|
||||
return {
|
||||
acceptedEtag: exchangeDetails.termsOfServiceAcceptedEtag,
|
||||
currentEtag,
|
||||
@ -464,7 +508,12 @@ async function getExchangeTos(
|
||||
};
|
||||
}
|
||||
|
||||
const tosDownload = await downloadTosFromAcceptedFormat(ws, exchangeBaseUrl, getExchangeRequestTimeout(), acceptedFormat);
|
||||
const tosDownload = await downloadTosFromAcceptedFormat(
|
||||
ws,
|
||||
exchangeBaseUrl,
|
||||
getExchangeRequestTimeout(),
|
||||
acceptedFormat,
|
||||
);
|
||||
|
||||
if (tosDownload.tosContentType === contentType) {
|
||||
return {
|
||||
@ -474,7 +523,7 @@ async function getExchangeTos(
|
||||
contentType,
|
||||
};
|
||||
}
|
||||
await updateExchangeTermsOfService(ws, exchangeBaseUrl, tosDownload)
|
||||
await updateExchangeTermsOfService(ws, exchangeBaseUrl, tosDownload);
|
||||
|
||||
return {
|
||||
acceptedEtag: exchangeDetails.termsOfServiceAcceptedEtag,
|
||||
@ -482,7 +531,6 @@ async function getExchangeTos(
|
||||
content: tosDownload.tosText,
|
||||
contentType: tosDownload.tosContentType,
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
async function listKnownBankAccounts(
|
||||
@ -641,9 +689,15 @@ async function dumpCoins(ws: InternalWalletState): Promise<CoinDumpJson> {
|
||||
}
|
||||
withdrawalReservePub = ws.reservePub;
|
||||
}
|
||||
const denomInfo = await ws.getDenomInfo(
|
||||
ws,
|
||||
tx,
|
||||
c.exchangeBaseUrl,
|
||||
c.denomPubHash,
|
||||
);
|
||||
coinsJson.coins.push({
|
||||
coin_pub: c.coinPub,
|
||||
denom_pub: c.denomPub,
|
||||
denom_pub: denomInfo?.denomPub!,
|
||||
denom_pub_hash: c.denomPubHash,
|
||||
denom_value: Amounts.stringify(denom.value),
|
||||
exchange_base_url: c.exchangeBaseUrl,
|
||||
@ -1030,7 +1084,7 @@ export async function handleCoreApiRequest(
|
||||
try {
|
||||
logger.error("Caught unexpected exception:");
|
||||
logger.error(e.stack);
|
||||
} catch (e) { }
|
||||
} catch (e) {}
|
||||
return {
|
||||
type: "error",
|
||||
operation,
|
||||
@ -1236,7 +1290,10 @@ class InternalWalletStateImpl implements InternalWalletState {
|
||||
* Run an async function after acquiring a list of locks, identified
|
||||
* by string tokens.
|
||||
*/
|
||||
async runSequentialized<T>(tokens: string[], f: () => Promise<T>): Promise<T> {
|
||||
async runSequentialized<T>(
|
||||
tokens: string[],
|
||||
f: () => Promise<T>,
|
||||
): Promise<T> {
|
||||
// Make sure locks are always acquired in the same order
|
||||
tokens = [...tokens].sort();
|
||||
|
||||
@ -1269,4 +1326,3 @@ class InternalWalletStateImpl implements InternalWalletState {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user