From ce97b1076b7e4a53b84d3fd34bf2047580ddeb22 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Thu, 27 Apr 2017 04:06:48 +0200 Subject: [PATCH] fix signature checks, add wire fee --- src/cryptoWorker.ts | 4 ++-- src/emscriptif.ts | 4 ++-- src/types.ts | 19 +++++++++++++++++-- src/wallet.ts | 36 ++++++++++++++++++++++++++++++++++-- 4 files changed, 55 insertions(+), 8 deletions(-) diff --git a/src/cryptoWorker.ts b/src/cryptoWorker.ts index 4275d659b..55c08d4b5 100644 --- a/src/cryptoWorker.ts +++ b/src/cryptoWorker.ts @@ -113,8 +113,8 @@ namespace RpcFunctions { export function isValidWireFee(type: string, wf: WireFee, masterPub: string): boolean { let p = new native.MasterWireFeePS({ h_wire_method: native.ByteArray.fromStringWithNull(type).hash(), - start_date: native.AbsoluteTimeNbo.fromStamp(wf.startStamp), - end_date: native.AbsoluteTimeNbo.fromStamp(wf.endStamp), + start_date: native.AbsoluteTimeNbo.fromStampSeconds(wf.startStamp), + end_date: native.AbsoluteTimeNbo.fromStampSeconds(wf.endStamp), wire_fee: (new native.Amount(wf.wireFee)).toNbo(), closing_fee: (new native.Amount(wf.closingFee)).toNbo(), }); diff --git a/src/emscriptif.ts b/src/emscriptif.ts index 3f23476aa..347ee54a0 100644 --- a/src/emscriptif.ts +++ b/src/emscriptif.ts @@ -1038,11 +1038,11 @@ export class AbsoluteTimeNbo extends PackedArenaObject { return x; } - static fromStamp(stamp: number): AbsoluteTimeNbo { + static fromStampSeconds(stamp: number): AbsoluteTimeNbo { let x = new AbsoluteTimeNbo(); x.alloc(); // XXX: This only works up to 54 bit numbers. - set64(x.nativePtr, stamp); + set64(x.nativePtr, stamp * 1000000); return x; } diff --git a/src/types.ts b/src/types.ts index c6111bd09..5d53f8db0 100644 --- a/src/types.ts +++ b/src/types.ts @@ -526,10 +526,10 @@ export class Contract { fulfillment_url: string; @Checkable.Number - wire_fee_amortization: number; + wire_fee_amortization?: number; @Checkable.Value(AmountJson) - max_wire_fee: AmountJson; + max_wire_fee?: AmountJson; @Checkable.Any extra: any; @@ -661,6 +661,21 @@ export namespace Amounts { } } + export function divide(a: AmountJson, n: number): AmountJson { + if (n == 0) { + throw Error(`Division by 0`); + } + if (n == 1) { + return {value: a.value, fraction: a.fraction, currency: a.currency}; + } + let r = a.value % n; + return { + currency: a.currency, + value: Math.floor(a.value / n), + fraction: Math.floor(((r * fractionalBase) + a.fraction) / n), + } + } + export function isNonZero(a: AmountJson) { return a.value > 0 || a.fraction > 0; } diff --git a/src/wallet.ts b/src/wallet.ts index 8b220ec4f..982801f43 100644 --- a/src/wallet.ts +++ b/src/wallet.ts @@ -601,7 +601,11 @@ export class Wallet { * but only if the sum the coins' remaining value exceeds the payment amount. */ private async getCoinsForPayment(paymentAmount: AmountJson, + wireMethod: string, + wireFeeTime: number, depositFeeLimit: AmountJson, + wireFeeLimit: AmountJson, + wireFeeAmortization: number, allowedExchanges: ExchangeHandle[], allowedAuditors: Auditor[]): Promise { @@ -610,7 +614,6 @@ export class Wallet { for (let exchange of exchanges) { let isOkay: boolean = false; - // is the exchange explicitly allowed? for (let allowedExchange of allowedExchanges) { if (allowedExchange.master_pub == exchange.masterPublicKey) { @@ -677,6 +680,27 @@ export class Wallet { cds.push({coin, denom}); } + let fees = await this.q().get(Stores.exchangeWireFees, exchange.baseUrl); + if (!fees) { + console.error("no fees found for exchange", exchange); + continue; + } + + let wireFee: AmountJson|undefined = undefined; + for (let fee of (fees.feesForType[wireMethod] || [])) { + if (fee.startStamp >= wireFeeTime && fee.endStamp <= wireFeeTime) { + wireFee = fee.wireFee; + break; + } + } + + if (wireFee) { + let amortizedWireFee = Amounts.divide(wireFee, wireFeeAmortization); + if (Amounts.cmp(wireFeeLimit, amortizedWireFee) < 0) { + paymentAmount = Amounts.add(amortizedWireFee, paymentAmount).amount; + } + } + let res = selectCoins(cds, paymentAmount, depositFeeLimit); if (res) { return { @@ -766,7 +790,11 @@ export class Wallet { } let res = await this.getCoinsForPayment(offer.contract.amount, + offer.contract.wire_method, + getTalerStampSec(offer.contract.timestamp) || 0, offer.contract.max_fee, + offer.contract.max_wire_fee || Amounts.getZero(offer.contract.amount.currency), + offer.contract.wire_fee_amortization || 1, offer.contract.exchanges, offer.contract.auditors); @@ -802,7 +830,11 @@ export class Wallet { // If not already payed, check if we could pay for it. let res = await this.getCoinsForPayment(offer.contract.amount, + offer.contract.wire_method, + getTalerStampSec(offer.contract.timestamp) || 0, offer.contract.max_fee, + offer.contract.max_wire_fee || Amounts.getZero(offer.contract.amount.currency), + offer.contract.wire_fee_amortization || 1, offer.contract.exchanges, offer.contract.auditors); @@ -1427,7 +1459,7 @@ export class Wallet { let valid: boolean = await this.cryptoApi.isValidWireFee(detail.type, wf, exchangeInfo.masterPublicKey); if (!valid) { console.error("fee signature invalid", fee); - continue; + throw Error("fee signature invalid"); } fees.push(wf); }