wallet-core: put taler:// URIs in transactions list

This commit is contained in:
Florian Dold 2022-08-24 22:42:30 +02:00
parent a11ac57535
commit f3231ccdf9
No known key found for this signature in database
GPG Key ID: D2E4F00F29D02A4B
5 changed files with 131 additions and 41 deletions

View File

@ -187,6 +187,9 @@ export interface TransactionWithdrawal extends TransactionCommon {
withdrawalDetails: WithdrawalDetails;
}
/**
* Credit because we were paid for a P2P invoice we created.
*/
export interface TransactionPeerPullCredit extends TransactionCommon {
type: TransactionType.PeerPullCredit;
@ -204,8 +207,16 @@ export interface TransactionPeerPullCredit extends TransactionCommon {
* Amount that actually was (or will be) added to the wallet's balance.
*/
amountEffective: AmountString;
/**
* URI to send to the other party.
*/
talerUri: string;
}
/**
* Debit because we paid someone's invoice.
*/
export interface TransactionPeerPullDebit extends TransactionCommon {
type: TransactionType.PeerPullDebit;
@ -219,6 +230,9 @@ export interface TransactionPeerPullDebit extends TransactionCommon {
amountEffective: AmountString;
}
/**
* We sent money via a P2P payment.
*/
export interface TransactionPeerPushDebit extends TransactionCommon {
type: TransactionType.PeerPushDebit;
@ -236,8 +250,16 @@ export interface TransactionPeerPushDebit extends TransactionCommon {
* Amount that actually was (or will be) added to the wallet's balance.
*/
amountEffective: AmountString;
/**
* URI to accept the payment.
*/
talerUri: string;
}
/**
* We received money via a P2P payment.
*/
export interface TransactionPeerPushCredit extends TransactionCommon {
type: TransactionType.PeerPushCredit;

View File

@ -1226,6 +1226,39 @@ export const enum WithdrawalRecordType {
PeerPushCredit = "peer-push-credit",
}
export interface WgInfoBankIntegrated {
withdrawalType: WithdrawalRecordType.BankIntegrated;
/**
* Extra state for when this is a withdrawal involving
* a Taler-integrated bank.
*/
bankInfo: ReserveBankInfo;
}
export interface WgInfoBankManual {
withdrawalType: WithdrawalRecordType.BankManual;
}
export interface WgInfoBankPeerPull {
withdrawalType: WithdrawalRecordType.PeerPullCredit;
/**
* Needed to quickly construct the taler:// URI for the counterparty
* without a join.
*/
contractPriv: string;
}
export interface WgInfoBankPeerPush {
withdrawalType: WithdrawalRecordType.PeerPushCredit;
}
export type WgInfo =
| WgInfoBankIntegrated
| WgInfoBankManual
| WgInfoBankPeerPull
| WgInfoBankPeerPush;
/**
* Group of withdrawal operations that need to be executed.
* (Either for a normal withdrawal or from a tip.)
@ -1239,7 +1272,7 @@ export interface WithdrawalGroupRecord {
*/
withdrawalGroupId: string;
withdrawalType: WithdrawalRecordType;
wgInfo: WgInfo;
/**
* Secret seed used to derive planchets.
@ -1301,12 +1334,6 @@ export interface WithdrawalGroupRecord {
*/
restrictAge?: number;
/**
* Extra state for when this is a withdrawal involving
* a Taler-integrated bank.
*/
bankInfo?: ReserveBankInfo;
/**
* Amount including fees (i.e. the amount subtracted from the
* reserve to withdraw all coins in this withdrawal session).

View File

@ -534,7 +534,9 @@ export async function acceptPeerPushPayment(
await internalCreateWithdrawalGroup(ws, {
amount,
withdrawalType: WithdrawalRecordType.PeerPushCredit,
wgInfo: {
withdrawalType: WithdrawalRecordType.PeerPushCredit,
},
exchangeBaseUrl: peerInc.exchangeBaseUrl,
reserveStatus: ReserveRecordStatus.QueryingStatus,
reserveKeyPair: {
@ -804,7 +806,10 @@ export async function initiatePeerRequestForPay(
await internalCreateWithdrawalGroup(ws, {
amount: Amounts.parseOrThrow(req.amount),
withdrawalType: WithdrawalRecordType.PeerPullCredit,
wgInfo: {
withdrawalType: WithdrawalRecordType.PeerPullCredit,
contractPriv: econtractResp.contractPriv,
},
exchangeBaseUrl: req.exchangeBaseUrl,
reserveStatus: ReserveRecordStatus.QueryingStatus,
reserveKeyPair: {

View File

@ -21,6 +21,8 @@ import {
AbsoluteTime,
AmountJson,
Amounts,
constructPayPullUri,
constructPayPushUri,
Logger,
OrderShortInfo,
PaymentStatus,
@ -156,6 +158,10 @@ export async function getTransactions(
frozen: false,
pending: !pi.purseCreated,
timestamp: pi.timestampCreated,
talerUri: constructPayPushUri({
exchangeBaseUrl: pi.exchangeBaseUrl,
contractPriv: pi.contractPriv,
}),
transactionId: makeEventId(
TransactionType.PeerPushDebit,
pi.pursePub,
@ -203,7 +209,7 @@ export async function getTransactions(
return;
}
let withdrawalDetails: WithdrawalDetails;
if (wsr.withdrawalType === WithdrawalRecordType.PeerPullCredit) {
if (wsr.wgInfo.withdrawalType === WithdrawalRecordType.PeerPullCredit) {
transactions.push({
type: TransactionType.PeerPullCredit,
amountEffective: Amounts.stringify(wsr.denomsSel.totalCoinValue),
@ -211,6 +217,10 @@ export async function getTransactions(
exchangeBaseUrl: wsr.exchangeBaseUrl,
pending: !wsr.timestampFinish,
timestamp: wsr.timestampStart,
talerUri: constructPayPullUri({
exchangeBaseUrl: wsr.exchangeBaseUrl,
contractPriv: wsr.wgInfo.contractPriv,
}),
transactionId: makeEventId(
TransactionType.PeerPullCredit,
wsr.withdrawalGroupId,
@ -219,7 +229,9 @@ export async function getTransactions(
...(wsr.lastError ? { error: wsr.lastError } : {}),
});
return;
} else if (wsr.withdrawalType === WithdrawalRecordType.PeerPushCredit) {
} else if (
wsr.wgInfo.withdrawalType === WithdrawalRecordType.PeerPushCredit
) {
transactions.push({
type: TransactionType.PeerPushCredit,
amountEffective: Amounts.stringify(wsr.denomsSel.totalCoinValue),
@ -235,12 +247,16 @@ export async function getTransactions(
...(wsr.lastError ? { error: wsr.lastError } : {}),
});
return;
} else if (wsr.bankInfo) {
} else if (
wsr.wgInfo.withdrawalType === WithdrawalRecordType.BankIntegrated
) {
withdrawalDetails = {
type: WithdrawalType.TalerBankIntegrationApi,
confirmed: wsr.bankInfo.timestampBankConfirmed ? true : false,
confirmed: wsr.wgInfo.bankInfo.timestampBankConfirmed
? true
: false,
reservePub: wsr.reservePub,
bankConfirmationUrl: wsr.bankInfo.confirmUrl,
bankConfirmationUrl: wsr.wgInfo.bankInfo.confirmUrl,
};
} else {
const exchangeDetails = await getExchangeDetails(

View File

@ -73,6 +73,7 @@ import {
ReserveBankInfo,
ReserveRecordStatus,
WalletStoresV1,
WgInfo,
WithdrawalGroupRecord,
WithdrawalRecordType,
} from "../db.js";
@ -1531,7 +1532,12 @@ async function registerReserveWithBank(
default:
return;
}
const bankInfo = withdrawalGroup.bankInfo;
if (
withdrawalGroup.wgInfo.withdrawalType != WithdrawalRecordType.BankIntegrated
) {
throw Error();
}
const bankInfo = withdrawalGroup.wgInfo.bankInfo;
if (!bankInfo) {
return;
}
@ -1566,10 +1572,10 @@ async function registerReserveWithBank(
default:
return;
}
if (!r.bankInfo) {
if (r.wgInfo.withdrawalType !== WithdrawalRecordType.BankIntegrated) {
throw Error("invariant failed");
}
r.bankInfo.timestampReserveInfoPosted = AbsoluteTime.toTimestamp(
r.wgInfo.bankInfo.timestampReserveInfoPosted = AbsoluteTime.toTimestamp(
AbsoluteTime.now(),
);
r.reserveStatus = ReserveRecordStatus.WaitConfirmBank;
@ -1595,12 +1601,18 @@ async function processReserveBankStatus(
default:
return;
}
if (!withdrawalGroup.bankInfo) {
if (
withdrawalGroup.wgInfo.withdrawalType != WithdrawalRecordType.BankIntegrated
) {
throw Error();
}
const bankInfo = withdrawalGroup.wgInfo.bankInfo;
if (!bankInfo) {
return;
}
const bankStatusUrl = getBankStatusUrl(
withdrawalGroup.bankInfo.talerWithdrawUri,
);
const bankStatusUrl = getBankStatusUrl(bankInfo.talerWithdrawUri);
const statusResp = await ws.http.get(bankStatusUrl, {
timeout: getReserveRequestTimeout(withdrawalGroup),
@ -1628,11 +1640,11 @@ async function processReserveBankStatus(
default:
return;
}
if (!r.bankInfo) {
if (r.wgInfo.withdrawalType !== WithdrawalRecordType.BankIntegrated) {
throw Error("invariant failed");
}
const now = AbsoluteTime.toTimestamp(AbsoluteTime.now());
r.bankInfo.timestampBankConfirmed = now;
r.wgInfo.bankInfo.timestampBankConfirmed = now;
r.reserveStatus = ReserveRecordStatus.BankAborted;
r.operationStatus = OperationStatus.Finished;
r.retryInfo = RetryInfo.reset();
@ -1670,21 +1682,19 @@ async function processReserveBankStatus(
default:
return;
}
if (r.wgInfo.withdrawalType !== WithdrawalRecordType.BankIntegrated) {
throw Error("invariant failed");
}
if (status.transfer_done) {
logger.info("withdrawal: transfer confirmed by bank.");
const now = AbsoluteTime.toTimestamp(AbsoluteTime.now());
if (!r.bankInfo) {
throw Error("invariant failed");
}
r.bankInfo.timestampBankConfirmed = now;
r.wgInfo.bankInfo.timestampBankConfirmed = now;
r.reserveStatus = ReserveRecordStatus.QueryingStatus;
r.operationStatus = OperationStatus.Pending;
r.retryInfo = RetryInfo.reset();
} else {
logger.info("withdrawal: transfer not yet confirmed by bank");
if (r.bankInfo) {
r.bankInfo.confirmUrl = status.confirm_transfer_url;
}
r.wgInfo.bankInfo.confirmUrl = status.confirm_transfer_url;
r.retryInfo = RetryInfo.increment(r.retryInfo);
}
await tx.withdrawalGroups.put(r);
@ -1701,7 +1711,7 @@ export async function internalCreateWithdrawalGroup(
forcedDenomSel?: ForcedDenomSel;
reserveKeyPair?: EddsaKeypair;
restrictAge?: number;
withdrawalType: WithdrawalRecordType;
wgInfo: WgInfo;
},
): Promise<WithdrawalGroupRecord> {
const reserveKeyPair =
@ -1743,11 +1753,10 @@ export async function internalCreateWithdrawalGroup(
reserveStatus: args.reserveStatus,
retryInfo: RetryInfo.reset(),
withdrawalGroupId,
bankInfo: args.bankInfo,
restrictAge: args.restrictAge,
senderWire: undefined,
timestampFinish: undefined,
withdrawalType: args.withdrawalType,
wgInfo: args.wgInfo,
};
const exchangeInfo = await updateExchangeFromUrl(ws, canonExchange);
@ -1802,9 +1811,16 @@ export async function acceptWithdrawalFromUri(
});
if (existingWithdrawalGroup) {
let url: string | undefined;
if (
existingWithdrawalGroup.wgInfo.withdrawalType ===
WithdrawalRecordType.BankIntegrated
) {
url = existingWithdrawalGroup.wgInfo.bankInfo.confirmUrl;
}
return {
reservePub: existingWithdrawalGroup.reservePub,
confirmTransferUrl: existingWithdrawalGroup.bankInfo?.confirmUrl,
confirmTransferUrl: url,
};
}
@ -1822,14 +1838,16 @@ export async function acceptWithdrawalFromUri(
const withdrawalGroup = await internalCreateWithdrawalGroup(ws, {
amount: withdrawInfo.amount,
exchangeBaseUrl: req.selectedExchange,
withdrawalType: WithdrawalRecordType.BankIntegrated,
wgInfo: {
withdrawalType: WithdrawalRecordType.BankIntegrated,
bankInfo: {
exchangePaytoUri,
talerWithdrawUri: req.talerWithdrawUri,
confirmUrl: withdrawInfo.confirmTransferUrl,
},
},
forcedDenomSel: req.forcedDenomSel,
reserveStatus: ReserveRecordStatus.RegisteringBank,
bankInfo: {
exchangePaytoUri,
talerWithdrawUri: req.talerWithdrawUri,
confirmUrl: withdrawInfo.confirmTransferUrl,
},
});
const withdrawalGroupId = withdrawalGroup.withdrawalGroupId;
@ -1881,7 +1899,9 @@ export async function createManualWithdrawal(
): Promise<AcceptManualWithdrawalResult> {
const withdrawalGroup = await internalCreateWithdrawalGroup(ws, {
amount: Amounts.jsonifyAmount(req.amount),
withdrawalType: WithdrawalRecordType.BankManual,
wgInfo: {
withdrawalType: WithdrawalRecordType.BankManual,
},
exchangeBaseUrl: req.exchangeBaseUrl,
bankInfo: undefined,
forcedDenomSel: req.forcedDenomSel,