wallet-core: use batch deposit API
This commit is contained in:
parent
a437605eba
commit
ee8993f11c
@ -1889,42 +1889,58 @@ export interface ExchangeRefreshRevealRequest {
|
|||||||
old_age_commitment?: Edx25519PublicKeyEnc[];
|
old_age_commitment?: Edx25519PublicKeyEnc[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DepositSuccess {
|
interface DepositConfirmationSignature {
|
||||||
|
// The EdDSA signature of `TALER_DepositConfirmationPS` using a current
|
||||||
|
// `signing key of the exchange <sign-key-priv>` affirming the successful
|
||||||
|
// deposit and that the exchange will transfer the funds after the refund
|
||||||
|
// deadline, or as soon as possible if the refund deadline is zero.
|
||||||
|
exchange_sig: EddsaSignatureString;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BatchDepositSuccess {
|
||||||
// Optional base URL of the exchange for looking up wire transfers
|
// Optional base URL of the exchange for looking up wire transfers
|
||||||
// associated with this transaction. If not given,
|
// associated with this transaction. If not given,
|
||||||
// the base URL is the same as the one used for this request.
|
// the base URL is the same as the one used for this request.
|
||||||
// Can be used if the base URL for /transactions/ differs from that
|
// Can be used if the base URL for ``/transactions/`` differs from that
|
||||||
// for /coins/, i.e. for load balancing. Clients SHOULD
|
// for ``/coins/``, i.e. for load balancing. Clients SHOULD
|
||||||
// respect the transaction_base_url if provided. Any HTTP server
|
// respect the ``transaction_base_url`` if provided. Any HTTP server
|
||||||
// belonging to an exchange MUST generate a 307 or 308 redirection
|
// belonging to an exchange MUST generate a 307 or 308 redirection
|
||||||
// to the correct base URL should a client uses the wrong base
|
// to the correct base URL should a client uses the wrong base
|
||||||
// URL, or if the base URL has changed since the deposit.
|
// URL, or if the base URL has changed since the deposit.
|
||||||
transaction_base_url?: string;
|
transaction_base_url?: string;
|
||||||
|
|
||||||
// timestamp when the deposit was received by the exchange.
|
// Timestamp when the deposit was received by the exchange.
|
||||||
exchange_timestamp: TalerProtocolTimestamp;
|
exchange_timestamp: TalerProtocolTimestamp;
|
||||||
|
|
||||||
// the EdDSA signature of TALER_DepositConfirmationPS using a current
|
// `Public EdDSA key of the exchange <sign-key-pub>` that was used to
|
||||||
// signing key of the exchange affirming the successful
|
|
||||||
// deposit and that the exchange will transfer the funds after the refund
|
|
||||||
// deadline, or as soon as possible if the refund deadline is zero.
|
|
||||||
exchange_sig: string;
|
|
||||||
|
|
||||||
// public EdDSA key of the exchange that was used to
|
|
||||||
// generate the signature.
|
// generate the signature.
|
||||||
// Should match one of the exchange's signing keys from /keys. It is given
|
// Should match one of the exchange's signing keys from ``/keys``. It is given
|
||||||
// explicitly as the client might otherwise be confused by clock skew as to
|
// explicitly as the client might otherwise be confused by clock skew as to
|
||||||
// which signing key was used.
|
// which signing key was used.
|
||||||
exchange_pub: string;
|
exchange_pub: EddsaPublicKeyString;
|
||||||
|
|
||||||
|
// Array of deposit confirmation signatures from the exchange
|
||||||
|
// Entries must be in the same order the coins were given
|
||||||
|
// in the batch deposit request.
|
||||||
|
exchange_sigs: DepositConfirmationSignature[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export const codecForDepositSuccess = (): Codec<DepositSuccess> =>
|
export const codecForDepositConfirmationSignature =
|
||||||
buildCodecForObject<DepositSuccess>()
|
(): Codec<DepositConfirmationSignature> =>
|
||||||
|
buildCodecForObject<DepositConfirmationSignature>()
|
||||||
|
.property("exchange_sig", codecForString())
|
||||||
|
.build("DepositConfirmationSignature");
|
||||||
|
|
||||||
|
export const codecForBatchDepositSuccess = (): Codec<BatchDepositSuccess> =>
|
||||||
|
buildCodecForObject<BatchDepositSuccess>()
|
||||||
.property("exchange_pub", codecForString())
|
.property("exchange_pub", codecForString())
|
||||||
.property("exchange_sig", codecForString())
|
.property(
|
||||||
|
"exchange_sigs",
|
||||||
|
codecForList(codecForDepositConfirmationSignature()),
|
||||||
|
)
|
||||||
.property("exchange_timestamp", codecForTimestamp)
|
.property("exchange_timestamp", codecForTimestamp)
|
||||||
.property("transaction_base_url", codecOptional(codecForString()))
|
.property("transaction_base_url", codecOptional(codecForString()))
|
||||||
.build("DepositSuccess");
|
.build("BatchDepositSuccess");
|
||||||
|
|
||||||
export interface TrackTransactionWired {
|
export interface TrackTransactionWired {
|
||||||
// Raw wire transfer identifier of the deposit.
|
// Raw wire transfer identifier of the deposit.
|
||||||
@ -2148,6 +2164,9 @@ export interface ExchangePurseDeposits {
|
|||||||
deposits: PurseDeposit[];
|
deposits: PurseDeposit[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated batch deposit should be used.
|
||||||
|
*/
|
||||||
export interface ExchangeDepositRequest {
|
export interface ExchangeDepositRequest {
|
||||||
// Amount to be deposited, can be a fraction of the
|
// Amount to be deposited, can be a fraction of the
|
||||||
// coin's total value.
|
// coin's total value.
|
||||||
@ -2210,6 +2229,67 @@ export interface ExchangeDepositRequest {
|
|||||||
h_age_commitment?: string;
|
h_age_commitment?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type WireSalt = string;
|
||||||
|
|
||||||
|
export interface ExchangeBatchDepositRequest {
|
||||||
|
// The merchant's account details.
|
||||||
|
merchant_payto_uri: string;
|
||||||
|
|
||||||
|
// The salt is used to hide the ``payto_uri`` from customers
|
||||||
|
// when computing the ``h_wire`` of the merchant.
|
||||||
|
wire_salt: WireSalt;
|
||||||
|
|
||||||
|
// SHA-512 hash of the contract of the merchant with the customer. Further
|
||||||
|
// details are never disclosed to the exchange.
|
||||||
|
h_contract_terms: HashCodeString;
|
||||||
|
|
||||||
|
// The list of coins that are going to be deposited with this Request.
|
||||||
|
coins: BatchDepositRequestCoin[];
|
||||||
|
|
||||||
|
// Timestamp when the contract was finalized.
|
||||||
|
timestamp: TalerProtocolTimestamp;
|
||||||
|
|
||||||
|
// Indicative time by which the exchange undertakes to transfer the funds to
|
||||||
|
// the merchant, in case of successful payment. A wire transfer deadline of 'never'
|
||||||
|
// is not allowed.
|
||||||
|
wire_transfer_deadline: TalerProtocolTimestamp;
|
||||||
|
|
||||||
|
// EdDSA `public key of the merchant <merchant-pub>`, so that the client can identify the
|
||||||
|
// merchant for refund requests.
|
||||||
|
merchant_pub: EddsaPublicKeyString;
|
||||||
|
|
||||||
|
// Date until which the merchant can issue a refund to the customer via the
|
||||||
|
// exchange, to be omitted if refunds are not allowed.
|
||||||
|
//
|
||||||
|
// THIS FIELD WILL BE DEPRICATED, once the refund mechanism becomes a
|
||||||
|
// policy via extension.
|
||||||
|
refund_deadline?: TalerProtocolTimestamp;
|
||||||
|
|
||||||
|
// CAVEAT: THIS IS WORK IN PROGRESS
|
||||||
|
// (Optional) policy for the batch-deposit.
|
||||||
|
// This might be a refund, auction or escrow policy.
|
||||||
|
policy?: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BatchDepositRequestCoin {
|
||||||
|
// EdDSA public key of the coin being deposited.
|
||||||
|
coin_pub: EddsaPublicKeyString;
|
||||||
|
|
||||||
|
// Hash of denomination RSA key with which the coin is signed.
|
||||||
|
denom_pub_hash: HashCodeString;
|
||||||
|
|
||||||
|
// Exchange's unblinded RSA signature of the coin.
|
||||||
|
ub_sig: UnblindedSignature;
|
||||||
|
|
||||||
|
// Amount to be deposited, can be a fraction of the
|
||||||
|
// coin's total value.
|
||||||
|
contribution: Amounts;
|
||||||
|
|
||||||
|
// Signature over `TALER_DepositRequestPS`, made by the customer with the
|
||||||
|
// `coin's private key <coin-priv>`.
|
||||||
|
coin_sig: EddsaSignatureString;
|
||||||
|
}
|
||||||
|
|
||||||
export interface WalletKycUuid {
|
export interface WalletKycUuid {
|
||||||
// UUID that the wallet should use when initiating
|
// UUID that the wallet should use when initiating
|
||||||
// the KYC check.
|
// the KYC check.
|
||||||
|
@ -1657,6 +1657,8 @@ export interface DepositGroupRecord {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Verbatim contract terms.
|
* Verbatim contract terms.
|
||||||
|
*
|
||||||
|
* FIXME: Move this to the contract terms object store!
|
||||||
*/
|
*/
|
||||||
contractTermsRaw: MerchantContractTerms;
|
contractTermsRaw: MerchantContractTerms;
|
||||||
|
|
||||||
|
@ -21,70 +21,69 @@ import {
|
|||||||
AbsoluteTime,
|
AbsoluteTime,
|
||||||
AmountJson,
|
AmountJson,
|
||||||
Amounts,
|
Amounts,
|
||||||
|
BatchDepositRequestCoin,
|
||||||
CancellationToken,
|
CancellationToken,
|
||||||
canonicalJson,
|
|
||||||
codecForDepositSuccess,
|
|
||||||
codecForTackTransactionAccepted,
|
|
||||||
codecForTackTransactionWired,
|
|
||||||
CoinRefreshRequest,
|
CoinRefreshRequest,
|
||||||
CreateDepositGroupRequest,
|
CreateDepositGroupRequest,
|
||||||
CreateDepositGroupResponse,
|
CreateDepositGroupResponse,
|
||||||
DepositGroupFees,
|
DepositGroupFees,
|
||||||
durationFromSpec,
|
Duration,
|
||||||
encodeCrock,
|
ExchangeBatchDepositRequest,
|
||||||
ExchangeDepositRequest,
|
|
||||||
ExchangeRefundRequest,
|
ExchangeRefundRequest,
|
||||||
getRandomBytes,
|
|
||||||
hashTruncate32,
|
|
||||||
hashWire,
|
|
||||||
HttpStatusCode,
|
HttpStatusCode,
|
||||||
j2s,
|
|
||||||
Logger,
|
Logger,
|
||||||
MerchantContractTerms,
|
MerchantContractTerms,
|
||||||
NotificationType,
|
NotificationType,
|
||||||
parsePaytoUri,
|
|
||||||
PayCoinSelection,
|
PayCoinSelection,
|
||||||
PrepareDepositRequest,
|
PrepareDepositRequest,
|
||||||
PrepareDepositResponse,
|
PrepareDepositResponse,
|
||||||
RefreshReason,
|
RefreshReason,
|
||||||
stringToBytes,
|
TalerError,
|
||||||
TalerErrorCode,
|
TalerErrorCode,
|
||||||
TalerProtocolTimestamp,
|
|
||||||
TalerPreciseTimestamp,
|
TalerPreciseTimestamp,
|
||||||
|
TalerProtocolTimestamp,
|
||||||
TrackTransaction,
|
TrackTransaction,
|
||||||
|
TransactionAction,
|
||||||
TransactionMajorState,
|
TransactionMajorState,
|
||||||
TransactionMinorState,
|
TransactionMinorState,
|
||||||
TransactionState,
|
TransactionState,
|
||||||
TransactionType,
|
TransactionType,
|
||||||
URL,
|
URL,
|
||||||
WireFee,
|
WireFee,
|
||||||
TransactionAction,
|
canonicalJson,
|
||||||
Duration,
|
codecForBatchDepositSuccess,
|
||||||
|
codecForTackTransactionAccepted,
|
||||||
|
codecForTackTransactionWired,
|
||||||
|
durationFromSpec,
|
||||||
|
encodeCrock,
|
||||||
|
getRandomBytes,
|
||||||
|
hashTruncate32,
|
||||||
|
hashWire,
|
||||||
|
j2s,
|
||||||
|
parsePaytoUri,
|
||||||
|
stringToBytes,
|
||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
|
import { readSuccessResponseJsonOrThrow } from "@gnu-taler/taler-util/http";
|
||||||
|
import { DepositElementStatus, DepositGroupRecord } from "../db.js";
|
||||||
import {
|
import {
|
||||||
DenominationRecord,
|
|
||||||
DepositGroupRecord,
|
|
||||||
DepositElementStatus,
|
|
||||||
} from "../db.js";
|
|
||||||
import { TalerError } from "@gnu-taler/taler-util";
|
|
||||||
import {
|
|
||||||
createRefreshGroup,
|
|
||||||
DepositOperationStatus,
|
DepositOperationStatus,
|
||||||
DepositTrackingInfo,
|
DepositTrackingInfo,
|
||||||
getTotalRefreshCost,
|
|
||||||
KycPendingInfo,
|
KycPendingInfo,
|
||||||
KycUserType,
|
|
||||||
PendingTaskType,
|
PendingTaskType,
|
||||||
RefreshOperationStatus,
|
RefreshOperationStatus,
|
||||||
|
createRefreshGroup,
|
||||||
|
getTotalRefreshCost,
|
||||||
} from "../index.js";
|
} from "../index.js";
|
||||||
import { InternalWalletState } from "../internal-wallet-state.js";
|
import { InternalWalletState } from "../internal-wallet-state.js";
|
||||||
import { readSuccessResponseJsonOrThrow } from "@gnu-taler/taler-util/http";
|
import { assertUnreachable } from "../util/assertUnreachable.js";
|
||||||
|
import { selectPayCoinsNew } from "../util/coinSelection.js";
|
||||||
|
import { checkDbInvariant, checkLogicInvariant } from "../util/invariants.js";
|
||||||
import {
|
import {
|
||||||
constructTaskIdentifier,
|
|
||||||
TaskRunResult,
|
TaskRunResult,
|
||||||
|
TombstoneTag,
|
||||||
|
constructTaskIdentifier,
|
||||||
runLongpollAsync,
|
runLongpollAsync,
|
||||||
spendCoins,
|
spendCoins,
|
||||||
TombstoneTag,
|
|
||||||
} from "./common.js";
|
} from "./common.js";
|
||||||
import { getExchangeDetails } from "./exchanges.js";
|
import { getExchangeDetails } from "./exchanges.js";
|
||||||
import {
|
import {
|
||||||
@ -92,15 +91,12 @@ import {
|
|||||||
generateDepositPermissions,
|
generateDepositPermissions,
|
||||||
getTotalPaymentCost,
|
getTotalPaymentCost,
|
||||||
} from "./pay-merchant.js";
|
} from "./pay-merchant.js";
|
||||||
import { selectPayCoinsNew } from "../util/coinSelection.js";
|
|
||||||
import {
|
import {
|
||||||
constructTransactionIdentifier,
|
constructTransactionIdentifier,
|
||||||
notifyTransition,
|
notifyTransition,
|
||||||
parseTransactionIdentifier,
|
parseTransactionIdentifier,
|
||||||
stopLongpolling,
|
stopLongpolling,
|
||||||
} from "./transactions.js";
|
} from "./transactions.js";
|
||||||
import { checkDbInvariant, checkLogicInvariant } from "../util/invariants.js";
|
|
||||||
import { assertUnreachable } from "../util/assertUnreachable.js";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logger.
|
* Logger.
|
||||||
@ -169,6 +165,10 @@ export function computeDepositTransactionStatus(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute the possible actions possible on a deposit transaction
|
||||||
|
* based on the current transaction state.
|
||||||
|
*/
|
||||||
export function computeDepositTransactionActions(
|
export function computeDepositTransactionActions(
|
||||||
dg: DepositGroupRecord,
|
dg: DepositGroupRecord,
|
||||||
): TransactionAction[] {
|
): TransactionAction[] {
|
||||||
@ -200,6 +200,11 @@ export function computeDepositTransactionActions(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Put a deposit group in a suspended state.
|
||||||
|
* While the deposit group is suspended, no network requests
|
||||||
|
* will be made to advance the transaction status.
|
||||||
|
*/
|
||||||
export async function suspendDepositGroup(
|
export async function suspendDepositGroup(
|
||||||
ws: InternalWalletState,
|
ws: InternalWalletState,
|
||||||
depositGroupId: string,
|
depositGroupId: string,
|
||||||
@ -406,46 +411,6 @@ export async function deleteDepositGroup(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Check KYC status with the exchange, throw an appropriate exception when KYC
|
|
||||||
* is required.
|
|
||||||
*
|
|
||||||
* FIXME: Why does this throw an exception when KYC is required?
|
|
||||||
* Should we not return some proper result record here?
|
|
||||||
*/
|
|
||||||
async function checkDepositKycStatus(
|
|
||||||
ws: InternalWalletState,
|
|
||||||
exchangeUrl: string,
|
|
||||||
kycInfo: KycPendingInfo,
|
|
||||||
userType: KycUserType,
|
|
||||||
): Promise<void> {
|
|
||||||
const url = new URL(
|
|
||||||
`kyc-check/${kycInfo.requirementRow}/${kycInfo.paytoHash}/${userType}`,
|
|
||||||
exchangeUrl,
|
|
||||||
);
|
|
||||||
logger.info(`kyc url ${url.href}`);
|
|
||||||
const kycStatusReq = await ws.http.fetch(url.href, {
|
|
||||||
method: "GET",
|
|
||||||
});
|
|
||||||
if (kycStatusReq.status === HttpStatusCode.Ok) {
|
|
||||||
logger.warn("kyc requested, but already fulfilled");
|
|
||||||
return;
|
|
||||||
} else if (kycStatusReq.status === HttpStatusCode.Accepted) {
|
|
||||||
const kycStatus = await kycStatusReq.json();
|
|
||||||
logger.info(`kyc status: ${j2s(kycStatus)}`);
|
|
||||||
// FIXME: This error code is totally wrong
|
|
||||||
throw TalerError.fromDetail(
|
|
||||||
TalerErrorCode.WALLET_WITHDRAWAL_KYC_REQUIRED,
|
|
||||||
{
|
|
||||||
kycUrl: kycStatus.kyc_url,
|
|
||||||
},
|
|
||||||
`KYC check required for deposit`,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
throw Error(`unexpected response from kyc-check (${kycStatusReq.status})`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check whether the refresh associated with the
|
* Check whether the refresh associated with the
|
||||||
* aborting deposit group is done.
|
* aborting deposit group is done.
|
||||||
@ -940,38 +905,58 @@ async function processDepositGroupPendingDeposit(
|
|||||||
contractData,
|
contractData,
|
||||||
);
|
);
|
||||||
|
|
||||||
for (let i = 0; i < depositPermissions.length; i++) {
|
// Exchanges involved in the deposit
|
||||||
const perm = depositPermissions[i];
|
const exchanges: Set<string> = new Set();
|
||||||
|
|
||||||
if (depositGroup.statusPerCoin[i] !== DepositElementStatus.DepositPending) {
|
for (const dp of depositPermissions) {
|
||||||
continue;
|
exchanges.add(dp.exchange_url);
|
||||||
}
|
}
|
||||||
|
|
||||||
const requestBody: ExchangeDepositRequest = {
|
// We need to do one batch per exchange.
|
||||||
contribution: Amounts.stringify(perm.contribution),
|
for (const exchangeUrl of exchanges.values()) {
|
||||||
merchant_payto_uri: depositGroup.wire.payto_uri,
|
const coins: BatchDepositRequestCoin[] = [];
|
||||||
wire_salt: depositGroup.wire.salt,
|
const batchIndexes: number[] = [];
|
||||||
|
|
||||||
|
const batchReq: ExchangeBatchDepositRequest = {
|
||||||
|
coins,
|
||||||
h_contract_terms: depositGroup.contractTermsHash,
|
h_contract_terms: depositGroup.contractTermsHash,
|
||||||
ub_sig: perm.ub_sig,
|
merchant_payto_uri: depositGroup.wire.payto_uri,
|
||||||
|
merchant_pub: depositGroup.contractTermsRaw.merchant_pub,
|
||||||
timestamp: depositGroup.contractTermsRaw.timestamp,
|
timestamp: depositGroup.contractTermsRaw.timestamp,
|
||||||
|
wire_salt: depositGroup.wire.salt,
|
||||||
wire_transfer_deadline:
|
wire_transfer_deadline:
|
||||||
depositGroup.contractTermsRaw.wire_transfer_deadline,
|
depositGroup.contractTermsRaw.wire_transfer_deadline,
|
||||||
refund_deadline: depositGroup.contractTermsRaw.refund_deadline,
|
refund_deadline: depositGroup.contractTermsRaw.refund_deadline,
|
||||||
coin_sig: perm.coin_sig,
|
|
||||||
denom_pub_hash: perm.h_denom,
|
|
||||||
merchant_pub: depositGroup.merchantPub,
|
|
||||||
h_age_commitment: perm.h_age_commitment,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
for (let i = 0; i < depositPermissions.length; i++) {
|
||||||
|
const perm = depositPermissions[i];
|
||||||
|
if (perm.exchange_url != exchangeUrl) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
coins.push({
|
||||||
|
coin_pub: perm.coin_pub,
|
||||||
|
coin_sig: perm.coin_sig,
|
||||||
|
contribution: Amounts.stringify(perm.contribution),
|
||||||
|
denom_pub_hash: perm.h_denom,
|
||||||
|
ub_sig: perm.ub_sig,
|
||||||
|
});
|
||||||
|
batchIndexes.push(i);
|
||||||
|
}
|
||||||
|
|
||||||
// Check for cancellation before making network request.
|
// Check for cancellation before making network request.
|
||||||
cancellationToken?.throwIfCancelled();
|
cancellationToken?.throwIfCancelled();
|
||||||
const url = new URL(`coins/${perm.coin_pub}/deposit`, perm.exchange_url);
|
const url = new URL(`batch-deposit`, exchangeUrl);
|
||||||
logger.info(`depositing to ${url}`);
|
logger.info(`depositing to ${url}`);
|
||||||
const httpResp = await ws.http.fetch(url.href, {
|
const httpResp = await ws.http.fetch(url.href, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: requestBody,
|
body: batchReq,
|
||||||
cancellationToken: cancellationToken,
|
cancellationToken: cancellationToken,
|
||||||
});
|
});
|
||||||
await readSuccessResponseJsonOrThrow(httpResp, codecForDepositSuccess());
|
await readSuccessResponseJsonOrThrow(
|
||||||
|
httpResp,
|
||||||
|
codecForBatchDepositSuccess(),
|
||||||
|
);
|
||||||
|
|
||||||
await ws.db
|
await ws.db
|
||||||
.mktx((x) => [x.depositGroups])
|
.mktx((x) => [x.depositGroups])
|
||||||
@ -980,11 +965,13 @@ async function processDepositGroupPendingDeposit(
|
|||||||
if (!dg) {
|
if (!dg) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const coinStatus = dg.statusPerCoin[i];
|
for (const batchIndex of batchIndexes) {
|
||||||
switch (coinStatus) {
|
const coinStatus = dg.statusPerCoin[batchIndex];
|
||||||
case DepositElementStatus.DepositPending:
|
switch (coinStatus) {
|
||||||
dg.statusPerCoin[i] = DepositElementStatus.Tracking;
|
case DepositElementStatus.DepositPending:
|
||||||
await tx.depositGroups.put(dg);
|
dg.statusPerCoin[batchIndex] = DepositElementStatus.Tracking;
|
||||||
|
await tx.depositGroups.put(dg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -1538,10 +1525,7 @@ async function getTotalFeesForDepositAmount(
|
|||||||
const allDenoms = await tx.denominations.indexes.byExchangeBaseUrl
|
const allDenoms = await tx.denominations.indexes.byExchangeBaseUrl
|
||||||
.iter(coin.exchangeBaseUrl)
|
.iter(coin.exchangeBaseUrl)
|
||||||
.filter((x) =>
|
.filter((x) =>
|
||||||
Amounts.isSameCurrency(
|
Amounts.isSameCurrency(x.value, pcs.coinContributions[i]),
|
||||||
x.value,
|
|
||||||
pcs.coinContributions[i],
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
const amountLeft = Amounts.sub(
|
const amountLeft = Amounts.sub(
|
||||||
denom.value,
|
denom.value,
|
||||||
|
Loading…
Reference in New Issue
Block a user