From c2c35925bb953bf07e32c005dbe312d220b45749 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Fri, 6 Jan 2023 11:08:45 +0100 Subject: wallet-core: allow failure result in peer payment coin selection --- .../taler-wallet-core/src/operations/pay-peer.ts | 63 +++++++++++++--------- 1 file changed, 38 insertions(+), 25 deletions(-) (limited to 'packages/taler-wallet-core/src/operations/pay-peer.ts') diff --git a/packages/taler-wallet-core/src/operations/pay-peer.ts b/packages/taler-wallet-core/src/operations/pay-peer.ts index cc859f243..3d03c46db 100644 --- a/packages/taler-wallet-core/src/operations/pay-peer.ts +++ b/packages/taler-wallet-core/src/operations/pay-peer.ts @@ -18,7 +18,6 @@ * Imports. */ import { - AbsoluteTime, AcceptPeerPullPaymentRequest, AcceptPeerPullPaymentResponse, AcceptPeerPushPaymentRequest, @@ -41,7 +40,6 @@ import { constructPayPushUri, ContractTermsUtil, decodeCrock, - Duration, eddsaGetPublic, encodeCrock, ExchangePurseDeposits, @@ -56,6 +54,7 @@ import { Logger, parsePayPullUri, parsePayPushUri, + PayPeerInsufficientBalanceDetails, PeerContractTerms, PreparePeerPullPaymentRequest, PreparePeerPullPaymentResponse, @@ -132,6 +131,12 @@ interface CoinInfo { ageCommitmentProof?: AgeCommitmentProof; } +export type SelectPeerCoinsResult = + | { type: "success"; result: PeerCoinSelection } + | { + type: "failure"; + }; + export async function selectPeerCoins( ws: InternalWalletState, tx: GetReadOnlyAccess<{ @@ -140,7 +145,7 @@ export async function selectPeerCoins( coins: typeof WalletStoresV1.coins; }>, instructedAmount: AmountJson, -): Promise { +): Promise { const exchanges = await tx.exchanges.iter().toArray(); for (const exch of exchanges) { if (exch.detailsPointer?.currency !== instructedAmount.currency) { @@ -218,11 +223,11 @@ export async function selectPeerCoins( coins: resCoins, depositFees: depositFeesAcc, }; - return res; + return { type: "success", result: res }; } continue; } - return undefined; + return { type: "failure" }; } export async function preparePeerPushPayment( @@ -258,7 +263,7 @@ export async function initiatePeerToPeerPush( pursePub: pursePair.pub, }); - const coinSelRes: PeerCoinSelection | undefined = await ws.db + const coinSelRes: SelectPeerCoinsResult = await ws.db .mktx((x) => [ x.exchanges, x.contractTerms, @@ -270,11 +275,13 @@ export async function initiatePeerToPeerPush( x.peerPushPaymentInitiations, ]) .runReadWrite(async (tx) => { - const sel = await selectPeerCoins(ws, tx, instructedAmount); - if (!sel) { - return undefined; + const selRes = await selectPeerCoins(ws, tx, instructedAmount); + if (selRes.type === "failure") { + return selRes; } + const sel = selRes.result; + await spendCoins(ws, tx, { allocationId: `txn:peer-push-debit:${pursePair.pub}`, coinPubs: sel.coins.map((x) => x.coinPub), @@ -304,11 +311,12 @@ export async function initiatePeerToPeerPush( contractTermsRaw: contractTerms, }); - return sel; + return selRes; }); logger.info(`selected p2p coins (push): ${j2s(coinSelRes)}`); - if (!coinSelRes) { + if (coinSelRes.type !== "success") { + // FIXME: use error code with details here throw Error("insufficient balance"); } @@ -322,14 +330,14 @@ export async function initiatePeerToPeerPush( }); const depositSigsResp = await ws.cryptoApi.signPurseDeposits({ - exchangeBaseUrl: coinSelRes.exchangeBaseUrl, + exchangeBaseUrl: coinSelRes.result.exchangeBaseUrl, pursePub: pursePair.pub, - coins: coinSelRes.coins, + coins: coinSelRes.result.coins, }); const createPurseUrl = new URL( `purses/${pursePair.pub}/create`, - coinSelRes.exchangeBaseUrl, + coinSelRes.result.exchangeBaseUrl, ); const httpResp = await ws.http.postJson(createPurseUrl.href, { @@ -355,9 +363,9 @@ export async function initiatePeerToPeerPush( contractPriv: econtractResp.contractPriv, mergePriv: mergePair.priv, pursePub: pursePair.pub, - exchangeBaseUrl: coinSelRes.exchangeBaseUrl, + exchangeBaseUrl: coinSelRes.result.exchangeBaseUrl, talerUri: constructPayPushUri({ - exchangeBaseUrl: coinSelRes.exchangeBaseUrl, + exchangeBaseUrl: coinSelRes.result.exchangeBaseUrl, contractPriv: econtractResp.contractPriv, }), transactionId: makeTransactionId( @@ -627,7 +635,7 @@ export async function acceptPeerPullPayment( const instructedAmount = Amounts.parseOrThrow( peerPullInc.contractTerms.amount, ); - const coinSelRes: PeerCoinSelection | undefined = await ws.db + const coinSelRes: SelectPeerCoinsResult = await ws.db .mktx((x) => [ x.exchanges, x.coins, @@ -637,11 +645,13 @@ export async function acceptPeerPullPayment( x.coinAvailability, ]) .runReadWrite(async (tx) => { - const sel = await selectPeerCoins(ws, tx, instructedAmount); - if (!sel) { - return undefined; + const selRes = await selectPeerCoins(ws, tx, instructedAmount); + if (selRes.type !== "success") { + return selRes; } + const sel = selRes.result; + await spendCoins(ws, tx, { allocationId: `txn:peer-pull-debit:${req.peerPullPaymentIncomingId}`, coinPubs: sel.coins.map((x) => x.coinPub), @@ -660,25 +670,27 @@ export async function acceptPeerPullPayment( pi.status = PeerPullPaymentIncomingStatus.Accepted; await tx.peerPullPaymentIncoming.put(pi); - return sel; + return selRes; }); logger.info(`selected p2p coins (pull): ${j2s(coinSelRes)}`); - if (!coinSelRes) { + if (coinSelRes.type !== "success") { throw Error("insufficient balance"); } const pursePub = peerPullInc.pursePub; + const coinSel = coinSelRes.result; + const depositSigsResp = await ws.cryptoApi.signPurseDeposits({ - exchangeBaseUrl: coinSelRes.exchangeBaseUrl, + exchangeBaseUrl: coinSel.exchangeBaseUrl, pursePub, - coins: coinSelRes.coins, + coins: coinSel.coins, }); const purseDepositUrl = new URL( `purses/${pursePub}/deposit`, - coinSelRes.exchangeBaseUrl, + coinSel.exchangeBaseUrl, ); const depositPayload: ExchangePurseDeposits = { @@ -770,6 +782,7 @@ export async function preparePeerPullPayment( amountRaw: req.amount, }; } + /** * Initiate a peer pull payment. */ -- cgit v1.2.3