summaryrefslogtreecommitdiff
path: root/packages
diff options
context:
space:
mode:
authorFlorian Dold <florian@dold.me>2023-09-12 13:48:52 +0200
committerFlorian Dold <florian@dold.me>2023-09-12 13:49:24 +0200
commit4b0680eefa0dcb2e9b00342949393e4b166eecb2 (patch)
tree0681abaeacd7d1707d77677426f4f9f37831846a /packages
parentee8993f11cf81721cc30b4473e40124c2fee0dff (diff)
downloadwallet-core-4b0680eefa0dcb2e9b00342949393e4b166eecb2.tar.gz
wallet-core-4b0680eefa0dcb2e9b00342949393e4b166eecb2.tar.bz2
wallet-core-4b0680eefa0dcb2e9b00342949393e4b166eecb2.zip
wallet-core: move contract terms to object store
Diffstat (limited to 'packages')
-rw-r--r--packages/taler-wallet-core/src/db.ts21
-rw-r--r--packages/taler-wallet-core/src/dbless.ts24
-rw-r--r--packages/taler-wallet-core/src/operations/deposits.ts35
-rw-r--r--packages/taler-wallet-core/src/operations/pay-peer-pull-debit.ts117
-rw-r--r--packages/taler-wallet-core/src/operations/transactions.ts42
5 files changed, 142 insertions, 97 deletions
diff --git a/packages/taler-wallet-core/src/db.ts b/packages/taler-wallet-core/src/db.ts
index 04c3ce723..9bf9a29cc 100644
--- a/packages/taler-wallet-core/src/db.ts
+++ b/packages/taler-wallet-core/src/db.ts
@@ -28,6 +28,7 @@ import {
} from "@gnu-taler/idb-bridge";
import {
AgeCommitmentProof,
+ AmountJson,
AmountString,
Amounts,
AttentionInfo,
@@ -1640,6 +1641,15 @@ export interface DepositTrackingInfo {
export interface DepositGroupRecord {
depositGroupId: string;
+ currency: string;
+
+ /**
+ * Instructed amount.
+ */
+ amount: AmountString;
+
+ wireTransferDeadline: TalerProtocolTimestamp;
+
merchantPub: string;
merchantPriv: string;
@@ -1655,13 +1665,6 @@ export interface DepositGroupRecord {
salt: string;
};
- /**
- * Verbatim contract terms.
- *
- * FIXME: Move this to the contract terms object store!
- */
- contractTermsRaw: MerchantContractTerms;
-
contractTermsHash: string;
payCoinSelection: PayCoinSelection;
@@ -1981,7 +1984,9 @@ export interface PeerPullPaymentIncomingRecord {
exchangeBaseUrl: string;
- contractTerms: PeerContractTerms;
+ amount: AmountString;
+
+ contractTermsHash: string;
timestampCreated: TalerPreciseTimestamp;
diff --git a/packages/taler-wallet-core/src/dbless.ts b/packages/taler-wallet-core/src/dbless.ts
index 11c6c0f74..65c293bdf 100644
--- a/packages/taler-wallet-core/src/dbless.ts
+++ b/packages/taler-wallet-core/src/dbless.ts
@@ -33,12 +33,13 @@ import {
AmountString,
codecForAny,
codecForBankWithdrawalOperationPostResponse,
- codecForDepositSuccess,
+ codecForBatchDepositSuccess,
codecForExchangeMeltResponse,
codecForExchangeRevealResponse,
codecForWithdrawResponse,
DenominationPubKey,
encodeCrock,
+ ExchangeBatchDepositRequest,
ExchangeMeltRequest,
ExchangeProtocolVersion,
ExchangeWithdrawRequest,
@@ -256,22 +257,27 @@ export async function depositCoin(args: {
refundDeadline: refundDeadline,
wireInfoHash: hashWire(depositPayto, wireSalt),
});
- const requestBody = {
- contribution: Amounts.stringify(dp.contribution),
+ const requestBody: ExchangeBatchDepositRequest = {
+ coins: [
+ {
+ contribution: Amounts.stringify(dp.contribution),
+ coin_pub: dp.coin_pub,
+ coin_sig: dp.coin_sig,
+ denom_pub_hash: dp.h_denom,
+ ub_sig: dp.ub_sig,
+ },
+ ],
merchant_payto_uri: depositPayto,
wire_salt: wireSalt,
h_contract_terms: contractTermsHash,
- ub_sig: coin.denomSig,
timestamp: depositTimestamp,
wire_transfer_deadline: wireTransferDeadline,
refund_deadline: refundDeadline,
- coin_sig: dp.coin_sig,
- denom_pub_hash: dp.h_denom,
merchant_pub: merchantPub,
};
- const url = new URL(`coins/${dp.coin_pub}/deposit`, dp.exchange_url);
- const httpResp = await http.postJson(url.href, requestBody);
- await readSuccessResponseJsonOrThrow(httpResp, codecForDepositSuccess());
+ const url = new URL(`batch-deposit`, dp.exchange_url);
+ const httpResp = await http.fetch(url.href, { body: requestBody });
+ await readSuccessResponseJsonOrThrow(httpResp, codecForBatchDepositSuccess());
}
export async function refreshCoin(req: {
diff --git a/packages/taler-wallet-core/src/operations/deposits.ts b/packages/taler-wallet-core/src/operations/deposits.ts
index a3483a332..2de8f30a1 100644
--- a/packages/taler-wallet-core/src/operations/deposits.ts
+++ b/packages/taler-wallet-core/src/operations/deposits.ts
@@ -884,8 +884,18 @@ async function processDepositGroupPendingDeposit(
): Promise<TaskRunResult> {
logger.info("processing deposit group in pending(deposit)");
const depositGroupId = depositGroup.depositGroupId;
+ const contractTermsRec = await ws.db
+ .mktx((x) => [x.contractTerms])
+ .runReadOnly(async (tx) => {
+ return tx.contractTerms.get(depositGroup.contractTermsHash);
+ });
+ if (!contractTermsRec) {
+ throw Error("contract terms for deposit not found in database");
+ }
+ const contractTerms: MerchantContractTerms =
+ contractTermsRec.contractTermsRaw;
const contractData = extractContractData(
- depositGroup.contractTermsRaw,
+ contractTermsRec.contractTermsRaw,
depositGroup.contractTermsHash,
"",
);
@@ -921,12 +931,11 @@ async function processDepositGroupPendingDeposit(
coins,
h_contract_terms: depositGroup.contractTermsHash,
merchant_payto_uri: depositGroup.wire.payto_uri,
- merchant_pub: depositGroup.contractTermsRaw.merchant_pub,
- timestamp: depositGroup.contractTermsRaw.timestamp,
+ merchant_pub: contractTerms.merchant_pub,
+ timestamp: contractTerms.timestamp,
wire_salt: depositGroup.wire.salt,
- wire_transfer_deadline:
- depositGroup.contractTermsRaw.wire_transfer_deadline,
- refund_deadline: depositGroup.contractTermsRaw.refund_deadline,
+ wire_transfer_deadline: contractTerms.wire_transfer_deadline,
+ refund_deadline: contractTerms.refund_deadline,
};
for (let i = 0; i < depositPermissions.length; i++) {
@@ -1086,7 +1095,10 @@ async function trackDeposit(
coinPub: string,
exchangeUrl: string,
): Promise<TrackTransaction> {
- const wireHash = depositGroup.contractTermsRaw.h_wire;
+ const wireHash = hashWire(
+ depositGroup.wire.payto_uri,
+ depositGroup.wire.salt,
+ );
const url = new URL(
`deposits/${wireHash}/${depositGroup.merchantPub}/${depositGroup.contractTermsHash}/${coinPub}`,
@@ -1358,8 +1370,9 @@ export async function createDepositGroup(
const depositGroup: DepositGroupRecord = {
contractTermsHash,
- contractTermsRaw: contractTerms,
depositGroupId,
+ currency: Amounts.currencyOf(totalDepositCost),
+ amount: contractData.amount,
noncePriv: noncePair.priv,
noncePub: noncePair.pub,
timestampCreated: AbsoluteTime.toPreciseTimestamp(now),
@@ -1375,6 +1388,7 @@ export async function createDepositGroup(
counterpartyEffectiveDepositAmount: Amounts.stringify(
counterpartyEffectiveDepositAmount,
),
+ wireTransferDeadline: contractTerms.wire_transfer_deadline,
wire: {
payto_uri: req.depositPaytoUri,
salt: wireSalt,
@@ -1395,6 +1409,7 @@ export async function createDepositGroup(
x.denominations,
x.refreshGroups,
x.coinAvailability,
+ x.contractTerms,
])
.runReadWrite(async (tx) => {
await spendCoins(ws, tx, {
@@ -1406,6 +1421,10 @@ export async function createDepositGroup(
refreshReason: RefreshReason.PayDeposit,
});
await tx.depositGroups.put(depositGroup);
+ await tx.contractTerms.put({
+ contractTermsRaw: contractTerms,
+ h: contractTermsHash,
+ });
return computeDepositTransactionStatus(depositGroup);
});
diff --git a/packages/taler-wallet-core/src/operations/pay-peer-pull-debit.ts b/packages/taler-wallet-core/src/operations/pay-peer-pull-debit.ts
index f357c41d5..5bcfa3418 100644
--- a/packages/taler-wallet-core/src/operations/pay-peer-pull-debit.ts
+++ b/packages/taler-wallet-core/src/operations/pay-peer-pull-debit.ts
@@ -19,6 +19,7 @@ import {
Amounts,
CoinRefreshRequest,
ConfirmPeerPullDebitRequest,
+ ContractTermsUtil,
ExchangePurseDeposits,
HttpStatusCode,
Logger,
@@ -103,9 +104,7 @@ async function handlePurseCreationConflict(
throw new TalerProtocolViolationError();
}
- const instructedAmount = Amounts.parseOrThrow(
- peerPullInc.contractTerms.amount,
- );
+ const instructedAmount = Amounts.parseOrThrow(peerPullInc.amount);
const sel = peerPullInc.coinSel;
if (!sel) {
@@ -142,9 +141,7 @@ async function handlePurseCreationConflict(
await ws.db
.mktx((x) => [x.peerPullDebit])
.runReadWrite(async (tx) => {
- const myPpi = await tx.peerPullDebit.get(
- peerPullInc.peerPullDebitId,
- );
+ const myPpi = await tx.peerPullDebit.get(peerPullInc.peerPullDebitId);
if (!myPpi) {
return;
}
@@ -220,9 +217,7 @@ async function processPeerPullDebitPendingDeposit(
const transitionInfo = await ws.db
.mktx((x) => [x.peerPullDebit])
.runReadWrite(async (tx) => {
- const pi = await tx.peerPullDebit.get(
- peerPullDebitId,
- );
+ const pi = await tx.peerPullDebit.get(peerPullDebitId);
if (!pi) {
throw Error("peer pull payment not found anymore");
}
@@ -248,9 +243,7 @@ async function processPeerPullDebitPendingDeposit(
x.coins,
])
.runReadWrite(async (tx) => {
- const pi = await tx.peerPullDebit.get(
- peerPullDebitId,
- );
+ const pi = await tx.peerPullDebit.get(peerPullDebitId);
if (!pi) {
throw Error("peer pull payment not found anymore");
}
@@ -335,9 +328,7 @@ async function processPeerPullDebitAbortingRefresh(
}
}
if (newOpState) {
- const newDg = await tx.peerPullDebit.get(
- peerPullDebitId,
- );
+ const newDg = await tx.peerPullDebit.get(peerPullDebitId);
if (!newDg) {
return;
}
@@ -391,9 +382,7 @@ export async function confirmPeerPullDebit(
} else if (req.peerPullDebitId) {
peerPullDebitId = req.peerPullDebitId;
} else {
- throw Error(
- "invalid request, transactionId or peerPullDebitId required",
- );
+ throw Error("invalid request, transactionId or peerPullDebitId required");
}
const peerPullInc = await ws.db
@@ -408,9 +397,7 @@ export async function confirmPeerPullDebit(
);
}
- const instructedAmount = Amounts.parseOrThrow(
- peerPullInc.contractTerms.amount,
- );
+ const instructedAmount = Amounts.parseOrThrow(peerPullInc.amount);
const coinSelRes = await selectPeerCoins(ws, { instructedAmount });
logger.info(`selected p2p coins (pull): ${j2s(coinSelRes)}`);
@@ -454,9 +441,7 @@ export async function confirmPeerPullDebit(
refreshReason: RefreshReason.PayPeerPull,
});
- const pi = await tx.peerPullDebit.get(
- peerPullDebitId,
- );
+ const pi = await tx.peerPullDebit.get(peerPullDebitId);
if (!pi) {
throw Error();
}
@@ -498,27 +483,36 @@ export async function preparePeerPullDebit(
throw Error("got invalid taler://pay-pull URI");
}
- const existingPullIncomingRecord = await ws.db
- .mktx((x) => [x.peerPullDebit])
+ const existing = await ws.db
+ .mktx((x) => [x.peerPullDebit, x.contractTerms])
.runReadOnly(async (tx) => {
- return tx.peerPullDebit.indexes.byExchangeAndContractPriv.get([
- uri.exchangeBaseUrl,
- uri.contractPriv,
- ]);
+ const peerPullDebitRecord =
+ await tx.peerPullDebit.indexes.byExchangeAndContractPriv.get([
+ uri.exchangeBaseUrl,
+ uri.contractPriv,
+ ]);
+ if (!peerPullDebitRecord) {
+ return;
+ }
+ const contractTerms = await tx.contractTerms.get(
+ peerPullDebitRecord.contractTermsHash,
+ );
+ if (!contractTerms) {
+ return;
+ }
+ return { peerPullDebitRecord, contractTerms };
});
- if (existingPullIncomingRecord) {
+ if (existing) {
return {
- amount: existingPullIncomingRecord.contractTerms.amount,
- amountRaw: existingPullIncomingRecord.contractTerms.amount,
- amountEffective: existingPullIncomingRecord.totalCostEstimated,
- contractTerms: existingPullIncomingRecord.contractTerms,
- peerPullDebitId:
- existingPullIncomingRecord.peerPullDebitId,
+ amount: existing.peerPullDebitRecord.amount,
+ amountRaw: existing.peerPullDebitRecord.amount,
+ amountEffective: existing.peerPullDebitRecord.totalCostEstimated,
+ contractTerms: existing.contractTerms.contractTermsRaw,
+ peerPullDebitId: existing.peerPullDebitRecord.peerPullDebitId,
transactionId: constructTransactionIdentifier({
tag: TransactionType.PeerPullDebit,
- peerPullDebitId:
- existingPullIncomingRecord.peerPullDebitId,
+ peerPullDebitId: existing.peerPullDebitRecord.peerPullDebitId,
}),
};
}
@@ -566,6 +560,8 @@ export async function preparePeerPullDebit(
throw Error("pull payments without contract terms not supported yet");
}
+ const contractTermsHash = ContractTermsUtil.hashContractTerms(contractTerms);
+
// FIXME: Why don't we compute the totalCost here?!
const instructedAmount = Amounts.parseOrThrow(contractTerms.amount);
@@ -588,18 +584,23 @@ export async function preparePeerPullDebit(
);
await ws.db
- .mktx((x) => [x.peerPullDebit])
+ .mktx((x) => [x.peerPullDebit, x.contractTerms])
.runReadWrite(async (tx) => {
- await tx.peerPullDebit.add({
- peerPullDebitId,
- contractPriv: contractPriv,
- exchangeBaseUrl: exchangeBaseUrl,
- pursePub: pursePub,
- timestampCreated: TalerPreciseTimestamp.now(),
- contractTerms,
- status: PeerPullDebitRecordStatus.DialogProposed,
- totalCostEstimated: Amounts.stringify(totalAmount),
- });
+ await tx.contractTerms.put({
+ h: contractTermsHash,
+ contractTermsRaw: contractTerms,
+ }),
+ await tx.peerPullDebit.add({
+ peerPullDebitId,
+ contractPriv: contractPriv,
+ exchangeBaseUrl: exchangeBaseUrl,
+ pursePub: pursePub,
+ timestampCreated: TalerPreciseTimestamp.now(),
+ contractTermsHash,
+ amount: contractTerms.amount,
+ status: PeerPullDebitRecordStatus.DialogProposed,
+ totalCostEstimated: Amounts.stringify(totalAmount),
+ });
});
return {
@@ -631,9 +632,7 @@ export async function suspendPeerPullDebitTransaction(
const transitionInfo = await ws.db
.mktx((x) => [x.peerPullDebit])
.runReadWrite(async (tx) => {
- const pullDebitRec = await tx.peerPullDebit.get(
- peerPullDebitId,
- );
+ const pullDebitRec = await tx.peerPullDebit.get(peerPullDebitId);
if (!pullDebitRec) {
logger.warn(`peer pull debit ${peerPullDebitId} not found`);
return;
@@ -692,9 +691,7 @@ export async function abortPeerPullDebitTransaction(
const transitionInfo = await ws.db
.mktx((x) => [x.peerPullDebit])
.runReadWrite(async (tx) => {
- const pullDebitRec = await tx.peerPullDebit.get(
- peerPullDebitId,
- );
+ const pullDebitRec = await tx.peerPullDebit.get(peerPullDebitId);
if (!pullDebitRec) {
logger.warn(`peer pull debit ${peerPullDebitId} not found`);
return;
@@ -753,9 +750,7 @@ export async function failPeerPullDebitTransaction(
const transitionInfo = await ws.db
.mktx((x) => [x.peerPullDebit])
.runReadWrite(async (tx) => {
- const pullDebitRec = await tx.peerPullDebit.get(
- peerPullDebitId,
- );
+ const pullDebitRec = await tx.peerPullDebit.get(peerPullDebitId);
if (!pullDebitRec) {
logger.warn(`peer pull debit ${peerPullDebitId} not found`);
return;
@@ -814,9 +809,7 @@ export async function resumePeerPullDebitTransaction(
const transitionInfo = await ws.db
.mktx((x) => [x.peerPullDebit])
.runReadWrite(async (tx) => {
- const pullDebitRec = await tx.peerPullDebit.get(
- peerPullDebitId,
- );
+ const pullDebitRec = await tx.peerPullDebit.get(peerPullDebitId);
if (!pullDebitRec) {
logger.warn(`peer pull debit ${peerPullDebitId} not found`);
return;
diff --git a/packages/taler-wallet-core/src/operations/transactions.ts b/packages/taler-wallet-core/src/operations/transactions.ts
index 31655ad71..d7b277faf 100644
--- a/packages/taler-wallet-core/src/operations/transactions.ts
+++ b/packages/taler-wallet-core/src/operations/transactions.ts
@@ -346,11 +346,19 @@ export async function getTransactionById(
}
case TransactionType.PeerPullDebit: {
return await ws.db
- .mktx((x) => [x.peerPullDebit])
+ .mktx((x) => [x.peerPullDebit, x.contractTerms])
.runReadWrite(async (tx) => {
const debit = await tx.peerPullDebit.get(parsedTx.peerPullDebitId);
if (!debit) throw Error("not found");
- return buildTransactionForPullPaymentDebit(debit);
+ const contractTermsRec = await tx.contractTerms.get(
+ debit.contractTermsHash,
+ );
+ if (!contractTermsRec)
+ throw Error("contract terms for peer-pull-debit not found");
+ return buildTransactionForPullPaymentDebit(
+ debit,
+ contractTermsRec.contractTermsRaw,
+ );
});
}
@@ -477,6 +485,7 @@ function buildTransactionForPushPaymentDebit(
function buildTransactionForPullPaymentDebit(
pi: PeerPullPaymentIncomingRecord,
+ contractTerms: PeerContractTerms,
ort?: OperationRetryRecord,
): Transaction {
return {
@@ -485,12 +494,12 @@ function buildTransactionForPullPaymentDebit(
txActions: computePeerPullDebitTransactionActions(pi),
amountEffective: pi.coinSel?.totalCost
? pi.coinSel?.totalCost
- : Amounts.stringify(pi.contractTerms.amount),
- amountRaw: Amounts.stringify(pi.contractTerms.amount),
+ : Amounts.stringify(pi.amount),
+ amountRaw: Amounts.stringify(pi.amount),
exchangeBaseUrl: pi.exchangeBaseUrl,
info: {
- expiration: pi.contractTerms.purse_expiration,
- summary: pi.contractTerms.summary,
+ expiration: contractTerms.purse_expiration,
+ summary: contractTerms.summary,
},
timestamp: pi.timestampCreated,
transactionId: constructTransactionIdentifier({
@@ -805,7 +814,7 @@ function buildTransactionForDeposit(
amountEffective: Amounts.stringify(dg.totalPayCost),
timestamp: dg.timestampCreated,
targetPaytoUri: dg.wire.payto_uri,
- wireTransferDeadline: dg.contractTermsRaw.wire_transfer_deadline,
+ wireTransferDeadline: dg.wireTransferDeadline,
transactionId: constructTransactionIdentifier({
tag: TransactionType.Deposit,
depositGroupId: dg.depositGroupId,
@@ -980,7 +989,7 @@ export async function getTransactions(
});
await iterRecordsForPeerPullDebit(tx, filter, async (pi) => {
- const amount = Amounts.parseOrThrow(pi.contractTerms.amount);
+ const amount = Amounts.parseOrThrow(pi.amount);
if (shouldSkipCurrency(transactionsRequest, amount.currency)) {
return;
}
@@ -991,10 +1000,23 @@ export async function getTransactions(
pi.status !== PeerPullDebitRecordStatus.PendingDeposit &&
pi.status !== PeerPullDebitRecordStatus.Done
) {
+ // FIXME: Why?!
return;
}
- transactions.push(buildTransactionForPullPaymentDebit(pi));
+ const contractTermsRec = await tx.contractTerms.get(
+ pi.contractTermsHash,
+ );
+ if (!contractTermsRec) {
+ return;
+ }
+
+ transactions.push(
+ buildTransactionForPullPaymentDebit(
+ pi,
+ contractTermsRec.contractTermsRaw,
+ ),
+ );
});
await iterRecordsForPeerPushCredit(tx, filter, async (pi) => {
@@ -1158,7 +1180,7 @@ export async function getTransactions(
});
await iterRecordsForDeposit(tx, filter, async (dg) => {
- const amount = Amounts.parseOrThrow(dg.contractTermsRaw.amount);
+ const amount = Amounts.parseOrThrow(dg.amount);
if (shouldSkipCurrency(transactionsRequest, amount.currency)) {
return;
}