add restricted option to manual withdraw

This commit is contained in:
Sebastian 2022-05-04 16:11:12 -03:00
parent f16d2e52d5
commit 4491118494
No known key found for this signature in database
GPG Key ID: BE4FF68352439FC1
6 changed files with 59 additions and 5 deletions

View File

@ -664,7 +664,6 @@ export function hashDenomPub(pub: DenominationPubKey): Uint8Array {
const hashInputBuf = new ArrayBuffer(pubBuf.length + 4 + 4); const hashInputBuf = new ArrayBuffer(pubBuf.length + 4 + 4);
const uint8ArrayBuf = new Uint8Array(hashInputBuf); const uint8ArrayBuf = new Uint8Array(hashInputBuf);
const dv = new DataView(hashInputBuf); const dv = new DataView(hashInputBuf);
logger.info("age_mask", pub.age_mask);
dv.setUint32(0, pub.age_mask ?? 0); dv.setUint32(0, pub.age_mask ?? 0);
dv.setUint32(4, DenomKeyType.toIntTag(pub.cipher)); dv.setUint32(4, DenomKeyType.toIntTag(pub.cipher));
uint8ArrayBuf.set(pubBuf, 8); uint8ArrayBuf.set(pubBuf, 8);
@ -680,8 +679,7 @@ export function hashDenomPub(pub: DenominationPubKey): Uint8Array {
return nacl.hash(uint8ArrayBuf); return nacl.hash(uint8ArrayBuf);
} else { } else {
throw Error( throw Error(
`unsupported cipher (${ `unsupported cipher (${(pub as DenominationPubKey).cipher
(pub as DenominationPubKey).cipher
}), unable to hash`, }), unable to hash`,
); );
} }

View File

@ -47,7 +47,7 @@ import {
} from "./time.js"; } from "./time.js";
import { codecForAmountString } from "./amounts.js"; import { codecForAmountString } from "./amounts.js";
import { strcmp } from "./helpers.js"; import { strcmp } from "./helpers.js";
import { Edx25519PublicKey } from "./talerCrypto.js"; import { AgeCommitmentProof, Edx25519PublicKey } from "./talerCrypto.js";
/** /**
* Denomination as found in the /keys response from the exchange. * Denomination as found in the /keys response from the exchange.
@ -954,6 +954,11 @@ export interface CoinDumpJson {
* Suspended coins are not considered for payments. * Suspended coins are not considered for payments.
*/ */
coin_suspended: boolean; coin_suspended: boolean;
/**
* Information about the age restriction
*/
ageCommitmentProof: AgeCommitmentProof | undefined;
}>; }>;
} }

View File

@ -738,6 +738,7 @@ export const codecForGetExchangeTosRequest = (): Codec<GetExchangeTosRequest> =>
export interface AcceptManualWithdrawalRequest { export interface AcceptManualWithdrawalRequest {
exchangeBaseUrl: string; exchangeBaseUrl: string;
amount: string; amount: string;
restrictAge?: number,
} }
export const codecForAcceptManualWithdrawalRequet = export const codecForAcceptManualWithdrawalRequet =
@ -745,6 +746,7 @@ export const codecForAcceptManualWithdrawalRequet =
buildCodecForObject<AcceptManualWithdrawalRequest>() buildCodecForObject<AcceptManualWithdrawalRequest>()
.property("exchangeBaseUrl", codecForString()) .property("exchangeBaseUrl", codecForString())
.property("amount", codecForString()) .property("amount", codecForString())
.property("restrictAge", codecOptional(codecForNumber()))
.build("AcceptManualWithdrawalRequest"); .build("AcceptManualWithdrawalRequest");
export interface GetWithdrawalDetailsForAmountRequest { export interface GetWithdrawalDetailsForAmountRequest {

View File

@ -775,6 +775,7 @@ advancedCli
.requiredOption("amount", ["--amount"], clk.STRING, { .requiredOption("amount", ["--amount"], clk.STRING, {
help: "Amount to withdraw", help: "Amount to withdraw",
}) })
.maybeOption("restrictAge", ["--restrict-age"], clk.INT)
.action(async (args) => { .action(async (args) => {
await withWallet(args, async (wallet) => { await withWallet(args, async (wallet) => {
const exchangeBaseUrl = args.withdrawManually.exchange; const exchangeBaseUrl = args.withdrawManually.exchange;
@ -796,6 +797,7 @@ advancedCli
{ {
amount, amount,
exchangeBaseUrl, exchangeBaseUrl,
restrictAge: parseInt(String(args.withdrawManually.restrictAge), 10),
}, },
); );
const reservePub = resp.reservePub; const reservePub = resp.reservePub;

View File

@ -43,6 +43,20 @@ function fakeAci(current: string, feeDeposit: string): AvailableCoinInfo {
}; };
} }
function fakeAciWithAgeRestriction(current: string, feeDeposit: string): AvailableCoinInfo {
return {
availableAmount: a(current),
coinPub: "foobar",
denomPub: {
cipher: DenomKeyType.Rsa,
rsa_public_key: "foobar",
age_mask: 2446657,
},
feeDeposit: a(feeDeposit),
exchangeBaseUrl: "https://example.com/",
};
}
test("it should be able to pay if merchant takes the fees", (t) => { test("it should be able to pay if merchant takes the fees", (t) => {
const acis: AvailableCoinInfo[] = [ const acis: AvailableCoinInfo[] = [
fakeAci("EUR:1.0", "EUR:0.1"), fakeAci("EUR:1.0", "EUR:0.1"),
@ -267,3 +281,31 @@ test("coin selection 9", (t) => {
); );
t.pass(); t.pass();
}); });
test("it should be able to use unrestricted coins for age restricted contract", (t) => {
const acis: AvailableCoinInfo[] = [
fakeAciWithAgeRestriction("EUR:1.0", "EUR:0.2"),
fakeAciWithAgeRestriction("EUR:0.2", "EUR:0.2"),
];
const res = selectPayCoins({
candidates: {
candidateCoins: acis,
wireFeesPerExchange: {},
},
contractTermsAmount: a("EUR:1.2"),
depositFeeLimit: a("EUR:0.4"),
wireFeeLimit: a("EUR:0"),
wireFeeAmortization: 1,
requiredMinimumAge: 13
});
if (!res) {
t.fail();
return;
}
t.true(res.coinContributions.length === 2);
t.true(
Amounts.cmp(Amounts.sum(res.coinContributions).amount, "EUR:1.2") === 0,
);
t.pass();
});

View File

@ -454,11 +454,14 @@ async function acceptManualWithdrawal(
ws: InternalWalletState, ws: InternalWalletState,
exchangeBaseUrl: string, exchangeBaseUrl: string,
amount: AmountJson, amount: AmountJson,
restrictAge?: number,
): Promise<AcceptManualWithdrawalResult> { ): Promise<AcceptManualWithdrawalResult> {
try { try {
const resp = await createReserve(ws, { const resp = await createReserve(ws, {
amount, amount,
exchange: exchangeBaseUrl, exchange: exchangeBaseUrl,
restrictAge
}); });
const exchangePaytoUris = await ws.db const exchangePaytoUris = await ws.db
.mktx((x) => ({ .mktx((x) => ({
@ -690,6 +693,7 @@ async function dumpCoins(ws: InternalWalletState): Promise<CoinDumpJson> {
remaining_value: Amounts.stringify(c.currentAmount), remaining_value: Amounts.stringify(c.currentAmount),
withdrawal_reserve_pub: withdrawalReservePub, withdrawal_reserve_pub: withdrawalReservePub,
coin_suspended: c.suspended, coin_suspended: c.suspended,
ageCommitmentProof: c.ageCommitmentProof,
}); });
} }
}); });
@ -801,6 +805,7 @@ async function dispatchRequestInternal(
ws, ws,
req.exchangeBaseUrl, req.exchangeBaseUrl,
Amounts.parseOrThrow(req.amount), Amounts.parseOrThrow(req.amount),
req.restrictAge
); );
return res; return res;
} }