-get p2p pull integration test to run through
This commit is contained in:
parent
bc434ebb83
commit
d32d2895ce
@ -1945,3 +1945,8 @@ export interface ExchangeReservePurseRequest {
|
|||||||
// if it has not been paid.
|
// if it has not been paid.
|
||||||
purse_expiration: TalerProtocolTimestamp;
|
purse_expiration: TalerProtocolTimestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ExchangePurseDeposits {
|
||||||
|
// Array of coins to deposit into the purse.
|
||||||
|
deposits: PurseDeposit[];
|
||||||
|
}
|
||||||
|
@ -1940,7 +1940,7 @@ export class WalletCli {
|
|||||||
`wallet-${self.name}`,
|
`wallet-${self.name}`,
|
||||||
`taler-wallet-cli ${
|
`taler-wallet-cli ${
|
||||||
self.timetravelArg ?? ""
|
self.timetravelArg ?? ""
|
||||||
} --no-throttle -LTRACE --wallet-db '${
|
} --no-throttle -LTRACE --skip-defaults --wallet-db '${
|
||||||
self.dbfile
|
self.dbfile
|
||||||
}' api '${op}' ${shellWrap(JSON.stringify(payload))}`,
|
}' api '${op}' ${shellWrap(JSON.stringify(payload))}`,
|
||||||
);
|
);
|
||||||
@ -1990,6 +1990,7 @@ export class WalletCli {
|
|||||||
"--no-throttle",
|
"--no-throttle",
|
||||||
...this.timetravelArgArr,
|
...this.timetravelArgArr,
|
||||||
"-LTRACE",
|
"-LTRACE",
|
||||||
|
"--skip-defaults",
|
||||||
"--wallet-db",
|
"--wallet-db",
|
||||||
this.dbfile,
|
this.dbfile,
|
||||||
"run-until-done",
|
"run-until-done",
|
||||||
@ -2005,6 +2006,7 @@ export class WalletCli {
|
|||||||
"taler-wallet-cli",
|
"taler-wallet-cli",
|
||||||
[
|
[
|
||||||
"--no-throttle",
|
"--no-throttle",
|
||||||
|
"--skip-defaults",
|
||||||
"-LTRACE",
|
"-LTRACE",
|
||||||
...this.timetravelArgArr,
|
...this.timetravelArgArr,
|
||||||
"--wallet-db",
|
"--wallet-db",
|
||||||
|
@ -197,6 +197,9 @@ export const walletCli = clk
|
|||||||
})
|
})
|
||||||
.flag("verbose", ["-V", "--verbose"], {
|
.flag("verbose", ["-V", "--verbose"], {
|
||||||
help: "Enable verbose output.",
|
help: "Enable verbose output.",
|
||||||
|
})
|
||||||
|
.flag("skipDefaults", ["--skip-defaults"], {
|
||||||
|
help: "Skip configuring default exchanges.",
|
||||||
});
|
});
|
||||||
|
|
||||||
type WalletCliArgsType = clk.GetArgType<typeof walletCli>;
|
type WalletCliArgsType = clk.GetArgType<typeof walletCli>;
|
||||||
@ -233,7 +236,9 @@ async function withWallet<T>(
|
|||||||
ws: wallet,
|
ws: wallet,
|
||||||
client: wallet.client,
|
client: wallet.client,
|
||||||
};
|
};
|
||||||
await wallet.handleCoreApiRequest("initWallet", "native-init", {});
|
await wallet.handleCoreApiRequest("initWallet", "native-init", {
|
||||||
|
skipDefaults: walletCliArgs.wallet.skipDefaults,
|
||||||
|
});
|
||||||
const ret = await f(w);
|
const ret = await f(w);
|
||||||
return ret;
|
return ret;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -1159,10 +1164,7 @@ testCli
|
|||||||
|
|
||||||
const salt = getRandomBytes(32);
|
const salt = getRandomBytes(32);
|
||||||
tDerive.start();
|
tDerive.start();
|
||||||
const deriv = await AgeRestriction.commitmentDerive(
|
const deriv = await AgeRestriction.commitmentDerive(commitProof, salt);
|
||||||
commitProof,
|
|
||||||
salt,
|
|
||||||
);
|
|
||||||
tDerive.stop();
|
tDerive.stop();
|
||||||
|
|
||||||
tCompare.start();
|
tCompare.start();
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
/**
|
/**
|
||||||
* Imports.
|
* Imports.
|
||||||
*/
|
*/
|
||||||
|
import { j2s } from "@gnu-taler/taler-util";
|
||||||
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||||
import { GlobalTestState } from "../harness/harness.js";
|
import { GlobalTestState } from "../harness/harness.js";
|
||||||
import {
|
import {
|
||||||
@ -57,6 +58,8 @@ export async function runPeerToPeerPullTest(t: GlobalTestState) {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
console.log(`checkResp: ${j2s(checkResp)}`);
|
||||||
|
|
||||||
const acceptResp = await wallet.client.call(
|
const acceptResp = await wallet.client.call(
|
||||||
WalletApiOperation.AcceptPeerPullPayment,
|
WalletApiOperation.AcceptPeerPullPayment,
|
||||||
{
|
{
|
||||||
@ -64,6 +67,10 @@ export async function runPeerToPeerPullTest(t: GlobalTestState) {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const txs = await wallet.client.call(WalletApiOperation.GetTransactions, {});
|
||||||
|
|
||||||
|
console.log(`transactions: ${j2s(txs)}`);
|
||||||
|
|
||||||
await wallet.runUntilDone();
|
await wallet.runUntilDone();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1669,13 +1669,27 @@ export interface PeerPushPaymentIncomingRecord {
|
|||||||
|
|
||||||
contractPriv: string;
|
contractPriv: string;
|
||||||
|
|
||||||
timestampAccepted: TalerProtocolTimestamp;
|
timestamp: TalerProtocolTimestamp;
|
||||||
|
|
||||||
contractTerms: PeerContractTerms;
|
contractTerms: PeerContractTerms;
|
||||||
|
|
||||||
// FIXME: add status etc.
|
// FIXME: add status etc.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface PeerPullPaymentIncomingRecord {
|
||||||
|
peerPullPaymentIncomingId: string;
|
||||||
|
|
||||||
|
pursePub: string;
|
||||||
|
|
||||||
|
exchangeBaseUrl: string;
|
||||||
|
|
||||||
|
contractTerms: PeerContractTerms;
|
||||||
|
|
||||||
|
timestamp: TalerProtocolTimestamp;
|
||||||
|
|
||||||
|
contractPriv: string;
|
||||||
|
}
|
||||||
|
|
||||||
export const WalletStoresV1 = {
|
export const WalletStoresV1 = {
|
||||||
coins: describeStore(
|
coins: describeStore(
|
||||||
describeContents<CoinRecord>("coins", {
|
describeContents<CoinRecord>("coins", {
|
||||||
@ -1853,6 +1867,17 @@ export const WalletStoresV1 = {
|
|||||||
]),
|
]),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
peerPullPaymentIncoming: describeStore(
|
||||||
|
describeContents<PeerPullPaymentIncomingRecord>("peerPullPaymentIncoming", {
|
||||||
|
keyPath: "peerPullPaymentIncomingId",
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
byExchangeAndPurse: describeIndex("byExchangeAndPurse", [
|
||||||
|
"exchangeBaseUrl",
|
||||||
|
"pursePub",
|
||||||
|
]),
|
||||||
|
},
|
||||||
|
),
|
||||||
peerPullPaymentInitiation: describeStore(
|
peerPullPaymentInitiation: describeStore(
|
||||||
describeContents<PeerPullPaymentInitiationRecord>(
|
describeContents<PeerPullPaymentInitiationRecord>(
|
||||||
"peerPushPaymentInitiation",
|
"peerPushPaymentInitiation",
|
||||||
|
@ -132,6 +132,7 @@ export async function getDefaultNodeWallet2(
|
|||||||
});
|
});
|
||||||
// Atomically move the temporary file onto the DB path.
|
// Atomically move the temporary file onto the DB path.
|
||||||
fs.renameSync(tmpPath, args.persistentStoragePath);
|
fs.renameSync(tmpPath, args.persistentStoragePath);
|
||||||
|
logger.trace("committing database done");
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,7 +179,7 @@ export async function getDefaultNodeWallet2(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const timer = new SetTimeoutTimerAPI()
|
const timer = new SetTimeoutTimerAPI();
|
||||||
|
|
||||||
const w = await Wallet.create(myDb, myHttpLib, timer, workerFactory);
|
const w = await Wallet.create(myDb, myHttpLib, timer, workerFactory);
|
||||||
|
|
||||||
|
@ -65,10 +65,7 @@ import {
|
|||||||
} from "../util/http.js";
|
} from "../util/http.js";
|
||||||
import { DbAccess, GetReadOnlyAccess } from "../util/query.js";
|
import { DbAccess, GetReadOnlyAccess } from "../util/query.js";
|
||||||
import { RetryInfo } from "../util/retries.js";
|
import { RetryInfo } from "../util/retries.js";
|
||||||
import {
|
import { WALLET_EXCHANGE_PROTOCOL_VERSION } from "../versions.js";
|
||||||
WALLET_CACHE_BREAKER_CLIENT_VERSION,
|
|
||||||
WALLET_EXCHANGE_PROTOCOL_VERSION,
|
|
||||||
} from "../versions.js";
|
|
||||||
import { guardOperationException } from "./common.js";
|
import { guardOperationException } from "./common.js";
|
||||||
|
|
||||||
const logger = new Logger("exchanges.ts");
|
const logger = new Logger("exchanges.ts");
|
||||||
@ -169,7 +166,6 @@ export async function downloadExchangeWithTermsOfService(
|
|||||||
contentType: string,
|
contentType: string,
|
||||||
): Promise<ExchangeTosDownloadResult> {
|
): Promise<ExchangeTosDownloadResult> {
|
||||||
const reqUrl = new URL("terms", exchangeBaseUrl);
|
const reqUrl = new URL("terms", exchangeBaseUrl);
|
||||||
reqUrl.searchParams.set("cacheBreaker", WALLET_CACHE_BREAKER_CLIENT_VERSION);
|
|
||||||
const headers = {
|
const headers = {
|
||||||
Accept: contentType,
|
Accept: contentType,
|
||||||
};
|
};
|
||||||
@ -352,7 +348,6 @@ async function downloadExchangeWireInfo(
|
|||||||
timeout: Duration,
|
timeout: Duration,
|
||||||
): Promise<ExchangeWireJson> {
|
): Promise<ExchangeWireJson> {
|
||||||
const reqUrl = new URL("wire", exchangeBaseUrl);
|
const reqUrl = new URL("wire", exchangeBaseUrl);
|
||||||
reqUrl.searchParams.set("cacheBreaker", WALLET_CACHE_BREAKER_CLIENT_VERSION);
|
|
||||||
|
|
||||||
const resp = await http.get(reqUrl.href, {
|
const resp = await http.get(reqUrl.href, {
|
||||||
timeout,
|
timeout,
|
||||||
@ -439,7 +434,6 @@ async function downloadExchangeKeysInfo(
|
|||||||
timeout: Duration,
|
timeout: Duration,
|
||||||
): Promise<ExchangeKeysDownloadResult> {
|
): Promise<ExchangeKeysDownloadResult> {
|
||||||
const keysUrl = new URL("keys", baseUrl);
|
const keysUrl = new URL("keys", baseUrl);
|
||||||
keysUrl.searchParams.set("cacheBreaker", WALLET_CACHE_BREAKER_CLIENT_VERSION);
|
|
||||||
|
|
||||||
const resp = await http.get(keysUrl.href, {
|
const resp = await http.get(keysUrl.href, {
|
||||||
timeout,
|
timeout,
|
||||||
@ -449,9 +443,6 @@ async function downloadExchangeKeysInfo(
|
|||||||
codecForExchangeKeysJson(),
|
codecForExchangeKeysJson(),
|
||||||
);
|
);
|
||||||
|
|
||||||
logger.trace("received /keys response");
|
|
||||||
logger.trace(`${j2s(exchangeKeysJsonUnchecked)}`);
|
|
||||||
|
|
||||||
if (exchangeKeysJsonUnchecked.denoms.length === 0) {
|
if (exchangeKeysJsonUnchecked.denoms.length === 0) {
|
||||||
throw TalerError.fromDetail(
|
throw TalerError.fromDetail(
|
||||||
TalerErrorCode.WALLET_EXCHANGE_DENOMINATIONS_INSUFFICIENT,
|
TalerErrorCode.WALLET_EXCHANGE_DENOMINATIONS_INSUFFICIENT,
|
||||||
|
@ -19,23 +19,30 @@
|
|||||||
*/
|
*/
|
||||||
import {
|
import {
|
||||||
AbsoluteTime,
|
AbsoluteTime,
|
||||||
|
AcceptPeerPullPaymentRequest,
|
||||||
AcceptPeerPushPaymentRequest,
|
AcceptPeerPushPaymentRequest,
|
||||||
AmountJson,
|
AmountJson,
|
||||||
|
AmountLike,
|
||||||
Amounts,
|
Amounts,
|
||||||
AmountString,
|
AmountString,
|
||||||
buildCodecForObject,
|
buildCodecForObject,
|
||||||
|
CheckPeerPullPaymentRequest,
|
||||||
|
CheckPeerPullPaymentResponse,
|
||||||
CheckPeerPushPaymentRequest,
|
CheckPeerPushPaymentRequest,
|
||||||
CheckPeerPushPaymentResponse,
|
CheckPeerPushPaymentResponse,
|
||||||
Codec,
|
Codec,
|
||||||
codecForAmountString,
|
codecForAmountString,
|
||||||
codecForAny,
|
codecForAny,
|
||||||
codecForExchangeGetContractResponse,
|
codecForExchangeGetContractResponse,
|
||||||
|
CoinPublicKey,
|
||||||
|
constructPayPullUri,
|
||||||
constructPayPushUri,
|
constructPayPushUri,
|
||||||
ContractTermsUtil,
|
ContractTermsUtil,
|
||||||
decodeCrock,
|
decodeCrock,
|
||||||
Duration,
|
Duration,
|
||||||
eddsaGetPublic,
|
eddsaGetPublic,
|
||||||
encodeCrock,
|
encodeCrock,
|
||||||
|
ExchangePurseDeposits,
|
||||||
ExchangePurseMergeRequest,
|
ExchangePurseMergeRequest,
|
||||||
ExchangeReservePurseRequest,
|
ExchangeReservePurseRequest,
|
||||||
getRandomBytes,
|
getRandomBytes,
|
||||||
@ -45,7 +52,9 @@ import {
|
|||||||
InitiatePeerPushPaymentResponse,
|
InitiatePeerPushPaymentResponse,
|
||||||
j2s,
|
j2s,
|
||||||
Logger,
|
Logger,
|
||||||
|
parsePayPullUri,
|
||||||
parsePayPushUri,
|
parsePayPushUri,
|
||||||
|
RefreshReason,
|
||||||
strcmp,
|
strcmp,
|
||||||
TalerProtocolTimestamp,
|
TalerProtocolTimestamp,
|
||||||
UnblindedSignature,
|
UnblindedSignature,
|
||||||
@ -54,14 +63,15 @@ import {
|
|||||||
import {
|
import {
|
||||||
CoinStatus,
|
CoinStatus,
|
||||||
MergeReserveInfo,
|
MergeReserveInfo,
|
||||||
OperationStatus,
|
|
||||||
ReserveRecordStatus,
|
ReserveRecordStatus,
|
||||||
WithdrawalGroupRecord,
|
WalletStoresV1,
|
||||||
} from "../db.js";
|
} from "../db.js";
|
||||||
import { readSuccessResponseJsonOrThrow } from "../util/http.js";
|
import { readSuccessResponseJsonOrThrow } from "../util/http.js";
|
||||||
import { InternalWalletState } from "../internal-wallet-state.js";
|
import { InternalWalletState } from "../internal-wallet-state.js";
|
||||||
import { checkDbInvariant } from "../util/invariants.js";
|
import { checkDbInvariant } from "../util/invariants.js";
|
||||||
import { internalCreateWithdrawalGroup } from "./withdraw.js";
|
import { internalCreateWithdrawalGroup } from "./withdraw.js";
|
||||||
|
import { GetReadOnlyAccess } from "../util/query.js";
|
||||||
|
import { createRefreshGroup } from "./refresh.js";
|
||||||
|
|
||||||
const logger = new Logger("operations/peer-to-peer.ts");
|
const logger = new Logger("operations/peer-to-peer.ts");
|
||||||
|
|
||||||
@ -105,18 +115,15 @@ interface CoinInfo {
|
|||||||
denomSig: UnblindedSignature;
|
denomSig: UnblindedSignature;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function initiatePeerToPeerPush(
|
export async function selectPeerCoins(
|
||||||
ws: InternalWalletState,
|
ws: InternalWalletState,
|
||||||
req: InitiatePeerPushPaymentRequest,
|
tx: GetReadOnlyAccess<{
|
||||||
): Promise<InitiatePeerPushPaymentResponse> {
|
exchanges: typeof WalletStoresV1.exchanges;
|
||||||
const instructedAmount = Amounts.parseOrThrow(req.amount);
|
denominations: typeof WalletStoresV1.denominations;
|
||||||
const coinSelRes: PeerCoinSelection | undefined = await ws.db
|
coins: typeof WalletStoresV1.coins;
|
||||||
.mktx((x) => ({
|
}>,
|
||||||
exchanges: x.exchanges,
|
instructedAmount: AmountJson,
|
||||||
coins: x.coins,
|
): Promise<PeerCoinSelection | undefined> {
|
||||||
denominations: x.denominations,
|
|
||||||
}))
|
|
||||||
.runReadOnly(async (tx) => {
|
|
||||||
const exchanges = await tx.exchanges.iter().toArray();
|
const exchanges = await tx.exchanges.iter().toArray();
|
||||||
for (const exch of exchanges) {
|
for (const exch of exchanges) {
|
||||||
if (exch.detailsPointer?.currency !== instructedAmount.currency) {
|
if (exch.detailsPointer?.currency !== instructedAmount.currency) {
|
||||||
@ -192,6 +199,41 @@ export async function initiatePeerToPeerPush(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function initiatePeerToPeerPush(
|
||||||
|
ws: InternalWalletState,
|
||||||
|
req: InitiatePeerPushPaymentRequest,
|
||||||
|
): Promise<InitiatePeerPushPaymentResponse> {
|
||||||
|
// FIXME: actually create a record for retries here!
|
||||||
|
const instructedAmount = Amounts.parseOrThrow(req.amount);
|
||||||
|
const coinSelRes: PeerCoinSelection | undefined = await ws.db
|
||||||
|
.mktx((x) => ({
|
||||||
|
exchanges: x.exchanges,
|
||||||
|
coins: x.coins,
|
||||||
|
denominations: x.denominations,
|
||||||
|
refreshGroups: x.refreshGroups,
|
||||||
|
}))
|
||||||
|
.runReadWrite(async (tx) => {
|
||||||
|
const sel = await selectPeerCoins(ws, tx, instructedAmount);
|
||||||
|
if (!sel) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const pubs: CoinPublicKey[] = [];
|
||||||
|
for (const c of sel.coins) {
|
||||||
|
const coin = await tx.coins.get(c.coinPub);
|
||||||
|
checkDbInvariant(!!coin);
|
||||||
|
coin.currentAmount = Amounts.sub(
|
||||||
|
coin.currentAmount,
|
||||||
|
Amounts.parseOrThrow(c.contribution),
|
||||||
|
).amount;
|
||||||
|
await tx.coins.put(coin);
|
||||||
|
}
|
||||||
|
|
||||||
|
await createRefreshGroup(ws, tx, pubs, RefreshReason.Pay);
|
||||||
|
|
||||||
|
return sel;
|
||||||
});
|
});
|
||||||
logger.info(`selected p2p coins: ${j2s(coinSelRes)}`);
|
logger.info(`selected p2p coins: ${j2s(coinSelRes)}`);
|
||||||
|
|
||||||
@ -339,7 +381,7 @@ export async function checkPeerPushPayment(
|
|||||||
exchangeBaseUrl: exchangeBaseUrl,
|
exchangeBaseUrl: exchangeBaseUrl,
|
||||||
mergePriv: dec.mergePriv,
|
mergePriv: dec.mergePriv,
|
||||||
pursePub: pursePub,
|
pursePub: pursePub,
|
||||||
timestampAccepted: TalerProtocolTimestamp.now(),
|
timestamp: TalerProtocolTimestamp.now(),
|
||||||
contractTerms: dec.contractTerms,
|
contractTerms: dec.contractTerms,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -478,6 +520,148 @@ export async function acceptPeerPushPayment(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FIXME: Bad name!
|
||||||
|
*/
|
||||||
|
export async function acceptPeerPullPayment(
|
||||||
|
ws: InternalWalletState,
|
||||||
|
req: AcceptPeerPullPaymentRequest,
|
||||||
|
) {
|
||||||
|
const peerPullInc = await ws.db
|
||||||
|
.mktx((x) => ({ peerPullPaymentIncoming: x.peerPullPaymentIncoming }))
|
||||||
|
.runReadOnly(async (tx) => {
|
||||||
|
return tx.peerPullPaymentIncoming.get(req.peerPullPaymentIncomingId);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!peerPullInc) {
|
||||||
|
throw Error(
|
||||||
|
`can't accept unknown incoming p2p pull payment (${req.peerPullPaymentIncomingId})`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const instructedAmount = Amounts.parseOrThrow(
|
||||||
|
peerPullInc.contractTerms.amount,
|
||||||
|
);
|
||||||
|
const coinSelRes: PeerCoinSelection | undefined = await ws.db
|
||||||
|
.mktx((x) => ({
|
||||||
|
exchanges: x.exchanges,
|
||||||
|
coins: x.coins,
|
||||||
|
denominations: x.denominations,
|
||||||
|
refreshGroups: x.refreshGroups,
|
||||||
|
}))
|
||||||
|
.runReadWrite(async (tx) => {
|
||||||
|
const sel = await selectPeerCoins(ws, tx, instructedAmount);
|
||||||
|
if (!sel) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const pubs: CoinPublicKey[] = [];
|
||||||
|
for (const c of sel.coins) {
|
||||||
|
const coin = await tx.coins.get(c.coinPub);
|
||||||
|
checkDbInvariant(!!coin);
|
||||||
|
coin.currentAmount = Amounts.sub(
|
||||||
|
coin.currentAmount,
|
||||||
|
Amounts.parseOrThrow(c.contribution),
|
||||||
|
).amount;
|
||||||
|
await tx.coins.put(coin);
|
||||||
|
}
|
||||||
|
|
||||||
|
await createRefreshGroup(ws, tx, pubs, RefreshReason.Pay);
|
||||||
|
|
||||||
|
return sel;
|
||||||
|
});
|
||||||
|
logger.info(`selected p2p coins: ${j2s(coinSelRes)}`);
|
||||||
|
|
||||||
|
if (!coinSelRes) {
|
||||||
|
throw Error("insufficient balance");
|
||||||
|
}
|
||||||
|
|
||||||
|
const pursePub = peerPullInc.pursePub;
|
||||||
|
|
||||||
|
const depositSigsResp = await ws.cryptoApi.signPurseDeposits({
|
||||||
|
exchangeBaseUrl: coinSelRes.exchangeBaseUrl,
|
||||||
|
pursePub,
|
||||||
|
coins: coinSelRes.coins,
|
||||||
|
});
|
||||||
|
|
||||||
|
const purseDepositUrl = new URL(
|
||||||
|
`purses/${pursePub}/deposit`,
|
||||||
|
coinSelRes.exchangeBaseUrl,
|
||||||
|
);
|
||||||
|
|
||||||
|
const depositPayload: ExchangePurseDeposits = {
|
||||||
|
deposits: depositSigsResp.deposits,
|
||||||
|
};
|
||||||
|
|
||||||
|
const httpResp = await ws.http.postJson(purseDepositUrl.href, depositPayload);
|
||||||
|
const resp = await readSuccessResponseJsonOrThrow(httpResp, codecForAny());
|
||||||
|
logger.trace(`purse deposit response: ${j2s(resp)}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function checkPeerPullPayment(
|
||||||
|
ws: InternalWalletState,
|
||||||
|
req: CheckPeerPullPaymentRequest,
|
||||||
|
): Promise<CheckPeerPullPaymentResponse> {
|
||||||
|
const uri = parsePayPullUri(req.talerUri);
|
||||||
|
|
||||||
|
if (!uri) {
|
||||||
|
throw Error("got invalid taler://pay-push URI");
|
||||||
|
}
|
||||||
|
|
||||||
|
const exchangeBaseUrl = uri.exchangeBaseUrl;
|
||||||
|
const contractPriv = uri.contractPriv;
|
||||||
|
const contractPub = encodeCrock(eddsaGetPublic(decodeCrock(contractPriv)));
|
||||||
|
|
||||||
|
const getContractUrl = new URL(`contracts/${contractPub}`, exchangeBaseUrl);
|
||||||
|
|
||||||
|
const contractHttpResp = await ws.http.get(getContractUrl.href);
|
||||||
|
|
||||||
|
const contractResp = await readSuccessResponseJsonOrThrow(
|
||||||
|
contractHttpResp,
|
||||||
|
codecForExchangeGetContractResponse(),
|
||||||
|
);
|
||||||
|
|
||||||
|
const pursePub = contractResp.purse_pub;
|
||||||
|
|
||||||
|
const dec = await ws.cryptoApi.decryptContractForDeposit({
|
||||||
|
ciphertext: contractResp.econtract,
|
||||||
|
contractPriv: contractPriv,
|
||||||
|
pursePub: pursePub,
|
||||||
|
});
|
||||||
|
|
||||||
|
const getPurseUrl = new URL(`purses/${pursePub}/merge`, exchangeBaseUrl);
|
||||||
|
|
||||||
|
const purseHttpResp = await ws.http.get(getPurseUrl.href);
|
||||||
|
|
||||||
|
const purseStatus = await readSuccessResponseJsonOrThrow(
|
||||||
|
purseHttpResp,
|
||||||
|
codecForExchangePurseStatus(),
|
||||||
|
);
|
||||||
|
|
||||||
|
const peerPullPaymentIncomingId = encodeCrock(getRandomBytes(32));
|
||||||
|
|
||||||
|
await ws.db
|
||||||
|
.mktx((x) => ({
|
||||||
|
peerPullPaymentIncoming: x.peerPullPaymentIncoming,
|
||||||
|
}))
|
||||||
|
.runReadWrite(async (tx) => {
|
||||||
|
await tx.peerPullPaymentIncoming.add({
|
||||||
|
peerPullPaymentIncomingId,
|
||||||
|
contractPriv: contractPriv,
|
||||||
|
exchangeBaseUrl: exchangeBaseUrl,
|
||||||
|
pursePub: pursePub,
|
||||||
|
timestamp: TalerProtocolTimestamp.now(),
|
||||||
|
contractTerms: dec.contractTerms,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
amount: purseStatus.balance,
|
||||||
|
contractTerms: dec.contractTerms,
|
||||||
|
peerPullPaymentIncomingId,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export async function initiatePeerRequestForPay(
|
export async function initiatePeerRequestForPay(
|
||||||
ws: InternalWalletState,
|
ws: InternalWalletState,
|
||||||
req: InitiatePeerPullPaymentRequest,
|
req: InitiatePeerPullPaymentRequest,
|
||||||
@ -580,10 +764,18 @@ export async function initiatePeerRequestForPay(
|
|||||||
|
|
||||||
logger.info(`reserve merge response: ${j2s(resp)}`);
|
logger.info(`reserve merge response: ${j2s(resp)}`);
|
||||||
|
|
||||||
// FIXME: Now create a withdrawal operation!
|
await internalCreateWithdrawalGroup(ws, {
|
||||||
|
amount: Amounts.parseOrThrow(req.amount),
|
||||||
|
exchangeBaseUrl: req.exchangeBaseUrl,
|
||||||
|
reserveStatus: ReserveRecordStatus.QueryingStatus,
|
||||||
|
reserveKeyPair: {
|
||||||
|
priv: mergeReserveInfo.reservePriv,
|
||||||
|
pub: mergeReserveInfo.reservePub,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
talerUri: constructPayPushUri({
|
talerUri: constructPayPullUri({
|
||||||
exchangeBaseUrl: req.exchangeBaseUrl,
|
exchangeBaseUrl: req.exchangeBaseUrl,
|
||||||
contractPriv: econtractResp.contractPriv,
|
contractPriv: econtractResp.contractPriv,
|
||||||
}),
|
}),
|
||||||
|
@ -34,12 +34,3 @@ export const WALLET_MERCHANT_PROTOCOL_VERSION = "2:0:1";
|
|||||||
* Uses libtool's current:revision:age versioning.
|
* Uses libtool's current:revision:age versioning.
|
||||||
*/
|
*/
|
||||||
export const WALLET_BANK_INTEGRATION_PROTOCOL_VERSION = "0:0:0";
|
export const WALLET_BANK_INTEGRATION_PROTOCOL_VERSION = "0:0:0";
|
||||||
|
|
||||||
/**
|
|
||||||
* Cache breaker that is appended to queries such as /keys and /wire
|
|
||||||
* to break through caching, if it has been accidentally/badly configured
|
|
||||||
* by the exchange.
|
|
||||||
*
|
|
||||||
* This is only a temporary measure.
|
|
||||||
*/
|
|
||||||
export const WALLET_CACHE_BREAKER_CLIENT_VERSION = "5";
|
|
||||||
|
@ -39,6 +39,7 @@ import {
|
|||||||
codecForAny,
|
codecForAny,
|
||||||
codecForApplyRefundFromPurchaseIdRequest,
|
codecForApplyRefundFromPurchaseIdRequest,
|
||||||
codecForApplyRefundRequest,
|
codecForApplyRefundRequest,
|
||||||
|
codecForCheckPeerPullPaymentRequest,
|
||||||
codecForCheckPeerPushPaymentRequest,
|
codecForCheckPeerPushPaymentRequest,
|
||||||
codecForConfirmPayRequest,
|
codecForConfirmPayRequest,
|
||||||
codecForCreateDepositGroupRequest,
|
codecForCreateDepositGroupRequest,
|
||||||
@ -150,7 +151,9 @@ import {
|
|||||||
processPurchasePay,
|
processPurchasePay,
|
||||||
} from "./operations/pay.js";
|
} from "./operations/pay.js";
|
||||||
import {
|
import {
|
||||||
|
acceptPeerPullPayment,
|
||||||
acceptPeerPushPayment,
|
acceptPeerPushPayment,
|
||||||
|
checkPeerPullPayment,
|
||||||
checkPeerPushPayment,
|
checkPeerPushPayment,
|
||||||
initiatePeerRequestForPay,
|
initiatePeerRequestForPay,
|
||||||
initiatePeerToPeerPush,
|
initiatePeerToPeerPush,
|
||||||
@ -728,7 +731,12 @@ async function dispatchRequestInternal(
|
|||||||
switch (operation) {
|
switch (operation) {
|
||||||
case "initWallet": {
|
case "initWallet": {
|
||||||
ws.initCalled = true;
|
ws.initCalled = true;
|
||||||
|
if (typeof payload === "object" && (payload as any).skipDefaults) {
|
||||||
|
logger.info("skipping defaults");
|
||||||
|
} else {
|
||||||
|
logger.info("filling defaults");
|
||||||
await fillDefaults(ws);
|
await fillDefaults(ws);
|
||||||
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
case "withdrawTestkudos": {
|
case "withdrawTestkudos": {
|
||||||
@ -1047,6 +1055,15 @@ async function dispatchRequestInternal(
|
|||||||
const req = codecForInitiatePeerPullPaymentRequest().decode(payload);
|
const req = codecForInitiatePeerPullPaymentRequest().decode(payload);
|
||||||
return await initiatePeerRequestForPay(ws, req);
|
return await initiatePeerRequestForPay(ws, req);
|
||||||
}
|
}
|
||||||
|
case "checkPeerPullPayment": {
|
||||||
|
const req = codecForCheckPeerPullPaymentRequest().decode(payload);
|
||||||
|
return await checkPeerPullPayment(ws, req);
|
||||||
|
}
|
||||||
|
case "acceptPeerPullPayment": {
|
||||||
|
const req = codecForAcceptPeerPullPaymentRequest().decode(payload);
|
||||||
|
await acceptPeerPullPayment(ws, req);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
throw TalerError.fromDetail(
|
throw TalerError.fromDetail(
|
||||||
TalerErrorCode.WALLET_CORE_API_OPERATION_UNKNOWN,
|
TalerErrorCode.WALLET_CORE_API_OPERATION_UNKNOWN,
|
||||||
@ -1239,10 +1256,8 @@ class InternalWalletStateImpl implements InternalWalletState {
|
|||||||
const key = `${exchangeBaseUrl}:${denomPubHash}`;
|
const key = `${exchangeBaseUrl}:${denomPubHash}`;
|
||||||
const cached = this.denomCache[key];
|
const cached = this.denomCache[key];
|
||||||
if (cached) {
|
if (cached) {
|
||||||
logger.trace("using cached denom");
|
|
||||||
return cached;
|
return cached;
|
||||||
}
|
}
|
||||||
logger.trace("looking up denom denom");
|
|
||||||
const d = await tx.denominations.get([exchangeBaseUrl, denomPubHash]);
|
const d = await tx.denominations.get([exchangeBaseUrl, denomPubHash]);
|
||||||
if (d) {
|
if (d) {
|
||||||
this.denomCache[key] = d;
|
this.denomCache[key] = d;
|
||||||
|
@ -68,7 +68,6 @@ function timeout<T>(ms: number, promise: Promise<T>): Promise<T> {
|
|||||||
|
|
||||||
export async function queryToSlashKeys<T>(url: string): Promise<T> {
|
export async function queryToSlashKeys<T>(url: string): Promise<T> {
|
||||||
const endpoint = new URL("keys", url);
|
const endpoint = new URL("keys", url);
|
||||||
endpoint.searchParams.set("cacheBreaker", new Date().getTime() + "");
|
|
||||||
|
|
||||||
const query = fetch(endpoint.href)
|
const query = fetch(endpoint.href)
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
|
Loading…
Reference in New Issue
Block a user