aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortg(x) <*@tg-x.net>2016-02-22 23:15:43 +0100
committertg(x) <*@tg-x.net>2016-02-22 23:15:43 +0100
commit4e0362878ea04c0701449b8453f1781271ab1c7b (patch)
tree6257108377d6467b69763eb017da23ba52ffa66e
parentc4446d02d541b4c4ea2234170520874cf64c4bc7 (diff)
parent82742861d29a9d75da4de90322a128bcad5da503 (diff)
downloadwallet-core-4e0362878ea04c0701449b8453f1781271ab1c7b.tar.xz
Merge branch 'master' of taler.net:/var/git/wallet
-rw-r--r--extension/background/main.ts16
-rw-r--r--extension/lib/wallet/cryptoApi.ts93
-rw-r--r--extension/lib/wallet/cryptoLib.ts91
-rw-r--r--extension/lib/wallet/types.ts145
-rw-r--r--extension/lib/wallet/wallet.ts339
-rw-r--r--extension/manifest.json1
-rw-r--r--extension/pages/confirm-create-reserve.js42
-rw-r--r--extension/pages/confirm-create-reserve.tsx45
-rw-r--r--extension/tsconfig.json1
9 files changed, 490 insertions, 283 deletions
diff --git a/extension/background/main.ts b/extension/background/main.ts
index 4ec2c4d5d..746d81a60 100644
--- a/extension/background/main.ts
+++ b/extension/background/main.ts
@@ -26,22 +26,6 @@ System.config({
defaultJSExtensions: true,
});
-// We expect that in the manifest, the emscripten js is loaded
-// becore the background page.
-// Currently it is not possible to use SystemJS to load the emscripten js.
-declare var Module: any;
-if ("object" !== typeof Module) {
- throw Error("emscripten not loaded, no 'Module' defined");
-}
-
-// Manually register the emscripten js as a SystemJS, so that
-// we can use it from TypeScript by importing it.
-{
- let mod = System.newModule({Module: Module});
- let modName = System.normalizeSync("../lib/emscripten/emsc");
- console.log("registering", modName);
- System.set(modName, mod);
-}
System.import("../lib/wallet/wxMessaging")
.then((wxMessaging) => {
diff --git a/extension/lib/wallet/cryptoApi.ts b/extension/lib/wallet/cryptoApi.ts
new file mode 100644
index 000000000..300b928db
--- /dev/null
+++ b/extension/lib/wallet/cryptoApi.ts
@@ -0,0 +1,93 @@
+/*
+ This file is part of TALER
+ (C) 2016 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+ */
+
+
+import {PreCoin} from "./types";
+import {Reserve} from "./types";
+import {Denomination} from "./types";
+import {Offer} from "./wallet";
+import {CoinWithDenom} from "./wallet";
+import {PayCoinInfo} from "./types";
+export class CryptoApi {
+ private nextRpcId: number = 1;
+ private rpcRegistry = {};
+ private cryptoWorker: Worker;
+
+
+ constructor() {
+ this.cryptoWorker = new Worker("/lib/wallet/cryptoWorker.js");
+
+ this.cryptoWorker.onmessage = (msg: MessageEvent) => {
+ let id = msg.data.id;
+ if (typeof id !== "number") {
+ console.error("rpc id must be number");
+ return;
+ }
+ if (!this.rpcRegistry[id]) {
+ console.error(`RPC with id ${id} has no registry entry`);
+ return;
+ }
+ let {resolve, reject} = this.rpcRegistry[id];
+ resolve(msg.data.result);
+ }
+ }
+
+
+ private registerRpcId(resolve, reject): number {
+ let id = this.nextRpcId++;
+ this.rpcRegistry[id] = {resolve, reject};
+ return id;
+ }
+
+
+ private doRpc<T>(methodName: string, ...args): Promise<T> {
+ return new Promise<T>((resolve, reject) => {
+ let msg = {
+ operation: methodName,
+ id: this.registerRpcId(resolve, reject),
+ args: args,
+ };
+ this.cryptoWorker.postMessage(msg);
+ });
+ }
+
+
+ createPreCoin(denom: Denomination, reserve: Reserve): Promise<PreCoin> {
+ return this.doRpc("createPreCoin", denom, reserve);
+ }
+
+ hashRsaPub(rsaPub: string): Promise<string> {
+ return this.doRpc("hashRsaPub", rsaPub);
+ }
+
+ isValidDenom(denom: Denomination,
+ masterPub: string): Promise<boolean> {
+ return this.doRpc("isValidDenom", denom, masterPub);
+ }
+
+ signDeposit(offer: Offer,
+ cds: CoinWithDenom[]): Promise<PayCoinInfo> {
+ return this.doRpc("signDeposit", offer, cds);
+ }
+
+ createEddsaKeypair(): Promise<{priv: string, pub: string}> {
+ return this.doRpc("createEddsaKeypair");
+ }
+
+ rsaUnblind(sig: string, bk: string, pk: string): Promise<string> {
+ return this.doRpc("rsaUnblind", sig, bk, pk);
+ }
+} \ No newline at end of file
diff --git a/extension/lib/wallet/cryptoLib.ts b/extension/lib/wallet/cryptoLib.ts
index 2c32b3a63..869ddbaff 100644
--- a/extension/lib/wallet/cryptoLib.ts
+++ b/extension/lib/wallet/cryptoLib.ts
@@ -23,8 +23,11 @@ import {Denomination} from "./types";
"use strict";
import * as native from "./emscriptif";
-import {PreCoin, Reserve} from "./types";
+import {PreCoin, Reserve, PayCoinInfo} from "./types";
import create = chrome.alarms.create;
+import {Offer} from "./wallet";
+import {CoinWithDenom} from "./wallet";
+import {CoinPaySig} from "./types";
export function main(worker: Worker) {
@@ -58,7 +61,8 @@ namespace RpcFunctions {
* Create a pre-coin of the given denomination to be withdrawn from then given
* reserve.
*/
- export function createPreCoin(denom: Denomination, reserve: Reserve): PreCoin {
+ export function createPreCoin(denom: Denomination,
+ reserve: Reserve): PreCoin {
let reservePriv = new native.EddsaPrivateKey();
reservePriv.loadCrock(reserve.reserve_priv);
let reservePub = new native.EddsaPublicKey();
@@ -107,7 +111,7 @@ namespace RpcFunctions {
export function isValidDenom(denom: Denomination,
- masterPub: string): boolean {
+ masterPub: string): boolean {
let p = new native.DenominationKeyValidityPS({
master: native.EddsaPublicKey.fromCrock(masterPub),
denom_hash: native.RsaPublicKey.fromCrock(denom.denom_pub)
@@ -134,4 +138,85 @@ namespace RpcFunctions {
nativePub);
}
+
+
+ export function hashRsaPub(rsaPub: string): string {
+ return native.RsaPublicKey.fromCrock(rsaPub)
+ .encode()
+ .hash()
+ .toCrock();
+ }
+
+
+ export function createEddsaKeypair(): {priv: string, pub: string} {
+ const priv = native.EddsaPrivateKey.create();
+ const pub = priv.getPublicKey();
+ return {priv: priv.toCrock(), pub: pub.toCrock()};
+ }
+
+
+ export function rsaUnblind(sig, bk, pk): string {
+ let denomSig = native.rsaUnblind(native.RsaSignature.fromCrock(sig),
+ native.RsaBlindingKey.fromCrock(bk),
+ native.RsaPublicKey.fromCrock(pk));
+ return denomSig.encode().toCrock()
+ }
+
+
+ /**
+ * Generate updated coins (to store in the database)
+ * and deposit permissions for each given coin.
+ */
+ export function signDeposit(offer: Offer,
+ cds: CoinWithDenom[]): PayCoinInfo {
+ let ret = [];
+ let amountSpent = native.Amount.getZero(cds[0].coin.currentAmount.currency);
+ let amountRemaining = new native.Amount(offer.contract.amount);
+ for (let cd of cds) {
+ let coinSpend;
+
+ if (amountRemaining.value == 0 && amountRemaining.fraction == 0) {
+ break;
+ }
+
+ if (amountRemaining.cmp(new native.Amount(cd.coin.currentAmount)) < 0) {
+ coinSpend = new native.Amount(amountRemaining.toJson());
+ } else {
+ coinSpend = new native.Amount(cd.coin.currentAmount);
+ }
+
+ amountSpent.add(coinSpend);
+ amountRemaining.sub(coinSpend);
+
+ let newAmount = new native.Amount(cd.coin.currentAmount);
+ newAmount.sub(coinSpend);
+ cd.coin.currentAmount = newAmount.toJson();
+
+ let d = new native.DepositRequestPS({
+ h_contract: native.HashCode.fromCrock(offer.H_contract),
+ h_wire: native.HashCode.fromCrock(offer.contract.H_wire),
+ amount_with_fee: coinSpend.toNbo(),
+ coin_pub: native.EddsaPublicKey.fromCrock(cd.coin.coinPub),
+ deposit_fee: new native.Amount(cd.denom.fee_deposit).toNbo(),
+ merchant: native.EddsaPublicKey.fromCrock(offer.contract.merchant_pub),
+ refund_deadline: native.AbsoluteTimeNbo.fromTalerString(offer.contract.refund_deadline),
+ timestamp: native.AbsoluteTimeNbo.fromTalerString(offer.contract.timestamp),
+ transaction_id: native.UInt64.fromNumber(offer.contract.transaction_id),
+ });
+
+ let coinSig = native.eddsaSign(d.toPurpose(),
+ native.EddsaPrivateKey.fromCrock(cd.coin.coinPriv))
+ .toCrock();
+
+ let s: CoinPaySig = {
+ coin_sig: coinSig,
+ coin_pub: cd.coin.coinPub,
+ ub_sig: cd.coin.denomSig,
+ denom_pub: cd.coin.denomPub,
+ f: coinSpend.toJson(),
+ };
+ ret.push({sig: s, updatedCoin: cd.coin});
+ }
+ return ret;
+ }
}
diff --git a/extension/lib/wallet/types.ts b/extension/lib/wallet/types.ts
index d18bd95f4..8151bf41a 100644
--- a/extension/lib/wallet/types.ts
+++ b/extension/lib/wallet/types.ts
@@ -105,6 +105,7 @@ export interface ReserveCreationInfo {
mintInfo: IMintInfo;
selectedDenoms: Denomination[];
withdrawFee: AmountJson;
+ overhead: AmountJson;
}
@@ -120,12 +121,156 @@ export interface PreCoin {
coinValue: AmountJson;
}
+
export interface Reserve {
mint_base_url: string
reserve_priv: string;
reserve_pub: string;
}
+
+export interface CoinPaySig {
+ coin_sig: string;
+ coin_pub: string;
+ ub_sig: string;
+ denom_pub: string;
+ f: AmountJson;
+}
+
+
+export interface Coin {
+ coinPub: string;
+ coinPriv: string;
+ denomPub: string;
+ denomSig: string;
+ currentAmount: AmountJson;
+ mintBaseUrl: string;
+}
+
+
+export type PayCoinInfo = Array<{ updatedCoin: Coin, sig: CoinPaySig }>;
+
+
+export namespace Amounts {
+ export interface Result {
+ amount: AmountJson;
+ // Was there an over-/underflow?
+ saturated: boolean;
+ }
+
+ function getMaxAmount(currency: string): AmountJson {
+ return {
+ currency,
+ value: Number.MAX_SAFE_INTEGER,
+ fraction: 2**32,
+ }
+ }
+
+ export function getZero(currency: string): AmountJson {
+ return {
+ currency,
+ value: 0,
+ fraction: 0,
+ }
+ }
+
+ export function add(first: AmountJson, ...rest: AmountJson[]): Result {
+ const doit = () => {
+ let currency = first.currency;
+ let value = first.value + Math.floor(first.fraction / 1e6);
+ if (value > Number.MAX_SAFE_INTEGER) {
+ return {amount: getMaxAmount(currency), saturated: true};
+ }
+ let fraction = first.fraction % 1e6;
+ for (let x of rest) {
+ if (x.currency !== currency) {
+ throw Error(`Mismatched currency: ${x.currency} and ${currency}`);
+ }
+
+ value = value + x.value + Math.floor((fraction + x.fraction) / 1e6);
+ fraction = (fraction + x.fraction) % 1e6;
+ if (value > Number.MAX_SAFE_INTEGER) {
+ return {amount: getMaxAmount(currency), saturated: true};
+ }
+ }
+ return {amount: {currency, value, fraction}, saturated: false};
+ };
+ console.log("adding", first, "and", rest);
+ let ret = doit();
+ console.log("result is", ret);
+ return ret;
+ }
+
+
+ export function sub(a: AmountJson, b: AmountJson): Result {
+ if (a.currency !== b.currency) {
+ throw Error(`Mismatched currency: ${a.currency} and ${b.currency}`);
+ }
+ let currency = a.currency;
+ let value = a.value;
+ let fraction = a.fraction;
+ if (fraction < b.fraction) {
+ if (value < 1) {
+ return {amount: {currency, value: 0, fraction: 0}, saturated: true};
+ }
+ value--;
+ fraction += 1e6;
+ }
+ console.assert(fraction >= b.fraction);
+ fraction -= b.fraction;
+ if (value < b.value) {
+ return {amount: {currency, value: 0, fraction: 0}, saturated: true};
+ }
+ value -= b.value;
+ return {amount: {currency, value, fraction}, saturated: false};
+ }
+
+ export function cmp(a: AmountJson, b: AmountJson): number {
+ const doit = () => {
+ if (a.currency !== b.currency) {
+ throw Error(`Mismatched currency: ${a.currency} and ${b.currency}`);
+ }
+ let av = a.value + Math.floor(a.fraction / 1e6);
+ let af = a.fraction % 1e6;
+ let bv = b.value + Math.floor(b.fraction / 1e6);
+ let bf = b.fraction % 1e6;
+ switch (true) {
+ case av < bv:
+ return -1;
+ case av > bv:
+ return 1;
+ case af < bf:
+ return -1;
+ case af > bf:
+ return 1;
+ case af == bf:
+ return 0;
+ default:
+ throw Error("assertion failed");
+ }
+ };
+
+ console.log("comparing", a, "and", b);
+ let res = doit();
+ console.log("result:", res);
+ return res;
+
+ }
+
+ export function copy(a: AmountJson): AmountJson {
+ return {
+ value: a.value,
+ fraction: a.fraction,
+ currency: a.currency,
+ }
+ }
+
+ export function isNonZero(a: AmountJson) {
+ return a.value > 0 || a.fraction > 0;
+ }
+}
+
+
export interface Notifier {
notify();
} \ No newline at end of file
diff --git a/extension/lib/wallet/wallet.ts b/extension/lib/wallet/wallet.ts
index 8e7f63b12..76339fe5d 100644
--- a/extension/lib/wallet/wallet.ts
+++ b/extension/lib/wallet/wallet.ts
@@ -21,15 +21,17 @@
* @author Florian Dold
*/
-import * as native from "./emscriptif";
import {AmountJson, CreateReserveResponse, IMintInfo, Denomination, Notifier} from "./types";
import {HttpResponse, RequestException} from "./http";
import {Query} from "./query";
import {Checkable} from "./checkable";
import {canonicalizeBaseUrl} from "./helpers";
-import {ReserveCreationInfo} from "./types";
+import {ReserveCreationInfo, Amounts} from "./types";
import {PreCoin} from "./types";
import {Reserve} from "./types";
+import {CryptoApi} from "./cryptoApi";
+import {Coin} from "./types";
+import {PayCoinInfo} from "./types";
"use strict";
@@ -67,16 +69,6 @@ export class KeysJson {
}
-export interface Coin {
- coinPub: string;
- coinPriv: string;
- denomPub: string;
- denomSig: string;
- currentAmount: AmountJson;
- mintBaseUrl: string;
-}
-
-
class MintInfo implements IMintInfo {
baseUrl: string;
masterPublicKey: string;
@@ -107,7 +99,7 @@ class MintInfo implements IMintInfo {
* mint info is updated with the new information up until
* the first error.
*/
- mergeKeys(newKeys: KeysJson, wallet: Wallet): Promise<void> {
+ mergeKeys(newKeys: KeysJson, cryptoApi: CryptoApi): Promise<void> {
if (!this.masterPublicKey) {
this.masterPublicKey = newKeys.master_public_key;
}
@@ -140,20 +132,17 @@ class MintInfo implements IMintInfo {
return Promise.resolve();
}
- return wallet.isValidDenom(newDenom, this.masterPublicKey)
- .then((valid) => {
- if (!valid) {
- throw Error("signature on denomination invalid");
- }
-
- let d: Denomination = Object.assign({}, newDenom);
- d.pub_hash = native.RsaPublicKey.fromCrock(d.denom_pub)
- .encode()
- .hash()
- .toCrock();
- this.denoms.push(d);
-
- });
+ return cryptoApi
+ .isValidDenom(newDenom, this.masterPublicKey)
+ .then((valid) => {
+ if (!valid) {
+ throw Error("signature on denomination invalid");
+ }
+ return cryptoApi.hashRsaPub(newDenom.denom_pub);
+ })
+ .then((h) => {
+ this.denoms.push(Object.assign({}, newDenom, {pub_hash: h}));
+ });
});
return Promise.all(ps).then(() => void 0);
@@ -300,8 +289,6 @@ export interface Badge {
setColor(c: string): void;
}
-type PayCoinInfo = Array<{ updatedCoin: Coin, sig: CoinPaySig }>;
-
function deepEquals(x, y) {
if (x === y) {
@@ -357,29 +344,21 @@ function copy(o) {
/**
- * Rank two denomination by how desireable it is to withdraw them,
- * based on their fees and value.
- */
-function rankDenom(denom1: any, denom2: any) {
- // Slow ... we should find a better way than to convert it evert time.
- let v1 = new native.Amount(denom1.value);
- let v2 = new native.Amount(denom2.value);
- return (-1) * v1.cmp(v2);
-}
-
-
-/**
* Get a list of denominations (with repetitions possible)
* whose total value is as close as possible to the available
* amount, but never larger.
*/
function getWithdrawDenomList(amountAvailable: AmountJson,
denoms: Denomination[]): Denomination[] {
- let remaining = new native.Amount(amountAvailable);
+ let remaining = Amounts.copy(amountAvailable);
let ds: Denomination[] = [];
denoms = denoms.filter(isWithdrawableDenom);
- denoms.sort(rankDenom);
+ denoms.sort((d1, d2) => Amounts.cmp(d2.value, d1.value));
+
+ console.log("ranked denoms");
+ console.dir(denoms);
+
// This is an arbitrary number of coins
// we can withdraw in one go. It's not clear if this limit
@@ -387,17 +366,17 @@ function getWithdrawDenomList(amountAvailable: AmountJson,
for (let i = 0; i < 1000; i++) {
let found = false;
for (let d of denoms) {
- let cost = new native.Amount(d.value);
- cost.add(new native.Amount(d.fee_withdraw));
- if (remaining.cmp(cost) < 0) {
+ let cost = Amounts.add(d.value, d.fee_withdraw).amount;
+ if (Amounts.cmp(remaining, cost) < 0) {
continue;
}
found = true;
- remaining.sub(cost);
+ remaining = Amounts.sub(remaining, cost).amount;
ds.push(d);
+ break;
}
if (!found) {
- console.log("did not find coins for remaining ", remaining.toJson());
+ console.log("did not find coins for remaining ", remaining);
break;
}
}
@@ -410,9 +389,7 @@ export class Wallet {
private http: HttpRequestLibrary;
private badge: Badge;
private notifier: Notifier;
- private cryptoWorker: Worker;
- private nextRpcId: number = 1;
- private rpcRegistry = {};
+ public cryptoApi: CryptoApi;
constructor(db: IDBDatabase,
@@ -423,80 +400,7 @@ export class Wallet {
this.http = http;
this.badge = badge;
this.notifier = notifier;
- this.cryptoWorker = new Worker("/lib/wallet/cryptoWorker.js");
-
- this.cryptoWorker.onmessage = (msg: MessageEvent) => {
- let id = msg.data.id;
- if (typeof id !== "number") {
- console.error("rpc id must be number");
- return;
- }
- if (!this.rpcRegistry[id]) {
- console.error(`RPC with id ${id} has no registry entry`);
- return;
- }
- let {resolve, reject} = this.rpcRegistry[id];
- resolve(msg.data.result);
- }
- }
-
-
- /**
- * Generate updated coins (to store in the database)
- * and deposit permissions for each given coin.
- */
- private static signDeposit(offer: Offer,
- cds: CoinWithDenom[]): PayCoinInfo {
- let ret = [];
- let amountSpent = native.Amount.getZero(cds[0].coin.currentAmount.currency);
- let amountRemaining = new native.Amount(offer.contract.amount);
- cds = copy(cds);
- for (let cd of cds) {
- let coinSpend;
-
- if (amountRemaining.value == 0 && amountRemaining.fraction == 0) {
- break;
- }
-
- if (amountRemaining.cmp(new native.Amount(cd.coin.currentAmount)) < 0) {
- coinSpend = new native.Amount(amountRemaining.toJson());
- } else {
- coinSpend = new native.Amount(cd.coin.currentAmount);
- }
-
- amountSpent.add(coinSpend);
- amountRemaining.sub(coinSpend);
-
- let newAmount = new native.Amount(cd.coin.currentAmount);
- newAmount.sub(coinSpend);
- cd.coin.currentAmount = newAmount.toJson();
-
- let d = new native.DepositRequestPS({
- h_contract: native.HashCode.fromCrock(offer.H_contract),
- h_wire: native.HashCode.fromCrock(offer.contract.H_wire),
- amount_with_fee: coinSpend.toNbo(),
- coin_pub: native.EddsaPublicKey.fromCrock(cd.coin.coinPub),
- deposit_fee: new native.Amount(cd.denom.fee_deposit).toNbo(),
- merchant: native.EddsaPublicKey.fromCrock(offer.contract.merchant_pub),
- refund_deadline: native.AbsoluteTimeNbo.fromTalerString(offer.contract.refund_deadline),
- timestamp: native.AbsoluteTimeNbo.fromTalerString(offer.contract.timestamp),
- transaction_id: native.UInt64.fromNumber(offer.contract.transaction_id),
- });
-
- let coinSig = native.eddsaSign(d.toPurpose(),
- native.EddsaPrivateKey.fromCrock(cd.coin.coinPriv))
- .toCrock();
-
- let s: CoinPaySig = {
- coin_sig: coinSig,
- coin_pub: cd.coin.coinPub,
- ub_sig: cd.coin.denomSig,
- denom_pub: cd.coin.denomPub,
- f: coinSpend.toJson(),
- };
- ret.push({sig: s, updatedCoin: cd.coin});
- }
- return ret;
+ this.cryptoApi = new CryptoApi();
}
@@ -556,34 +460,32 @@ export class Wallet {
nextMint:
for (let key in m) {
- let coins = m[key].map((x) => ({
- a: new native.Amount(x.denom.fee_deposit),
- c: x
- }));
+ let coins = m[key];
// Sort by ascending deposit fee
- coins.sort((o1, o2) => o1.a.cmp(o2.a));
- let maxFee = new native.Amount(depositFeeLimit);
- let minAmount = new native.Amount(paymentAmount);
- let accFee = new native.Amount(coins[0].c.denom.fee_deposit);
- let accAmount = native.Amount.getZero(coins[0].c.coin.currentAmount.currency);
+ coins.sort((o1, o2) => Amounts.cmp(o1.denom.fee_deposit,
+ o2.denom.fee_deposit));
+ let maxFee = Amounts.copy(depositFeeLimit);
+ let minAmount = Amounts.copy(paymentAmount);
+ let accFee = Amounts.copy(coins[0].denom.fee_deposit);
+ let accAmount = Amounts.getZero(coins[0].coin.currentAmount.currency);
let usableCoins: CoinWithDenom[] = [];
nextCoin:
for (let i = 0; i < coins.length; i++) {
- let coinAmount = new native.Amount(coins[i].c.coin.currentAmount);
- let coinFee = coins[i].a;
- if (coinAmount.cmp(coinFee) <= 0) {
+ let coinAmount = Amounts.copy(coins[i].coin.currentAmount);
+ let coinFee = coins[i].denom.fee_deposit;
+ if (Amounts.cmp(coinAmount, coinFee) <= 0) {
continue nextCoin;
}
- accFee.add(coinFee);
- accAmount.add(coinAmount);
- if (accFee.cmp(maxFee) >= 0) {
+ accFee = Amounts.add(accFee, coinFee).amount;
+ accAmount = Amounts.add(accAmount, coinAmount).amount;
+ if (Amounts.cmp(accFee, maxFee) >= 0) {
// FIXME: if the fees are too high, we have
// to cover them ourselves ....
console.log("too much fees");
continue nextMint;
}
- usableCoins.push(coins[i].c);
- if (accAmount.cmp(minAmount) >= 0) {
+ usableCoins.push(coins[i]);
+ if (Amounts.cmp(accAmount, minAmount) >= 0) {
ret[key] = usableCoins;
continue nextMint;
}
@@ -661,9 +563,10 @@ export class Wallet {
}
console.log("about to record ...");
let mintUrl = Object.keys(mcs)[0];
- let ds = Wallet.signDeposit(offer, mcs[mintUrl]);
- return this.recordConfirmPay(offer, ds, mintUrl)
- .then((() => ({})));
+
+ return this.cryptoApi.signDeposit(offer, mcs[mintUrl])
+ .then((ds) => this.recordConfirmPay(offer, ds, mintUrl))
+ .then(() => ({}));
});
}
@@ -725,44 +628,43 @@ export class Wallet {
* Create a reserve, but do not flag it as confirmed yet.
*/
createReserve(req: CreateReserveRequest): Promise<CreateReserveResponse> {
- const reservePriv = native.EddsaPrivateKey.create();
- const reservePub = reservePriv.getPublicKey();
-
- const now = (new Date).getTime();
- const canonMint = canonicalizeBaseUrl(req.mint);
-
- const reserveRecord = {
- reserve_pub: reservePub.toCrock(),
- reserve_priv: reservePriv.toCrock(),
- mint_base_url: canonMint,
- created: now,
- last_query: null,
- current_amount: null,
- requested_amount: req.amount,
- confirmed: false,
- };
+ return this.cryptoApi.createEddsaKeypair().then((keypair) => {
+ const now = (new Date).getTime();
+ const canonMint = canonicalizeBaseUrl(req.mint);
+
+ const reserveRecord = {
+ reserve_pub: keypair.pub,
+ reserve_priv: keypair.priv,
+ mint_base_url: canonMint,
+ created: now,
+ last_query: null,
+ current_amount: null,
+ requested_amount: req.amount,
+ confirmed: false,
+ };
- const historyEntry = {
- type: "create-reserve",
- timestamp: now,
- detail: {
- requestedAmount: req.amount,
- reservePub: reserveRecord.reserve_pub,
- }
- };
+ const historyEntry = {
+ type: "create-reserve",
+ timestamp: now,
+ detail: {
+ requestedAmount: req.amount,
+ reservePub: reserveRecord.reserve_pub,
+ }
+ };
- return Query(this.db)
- .put("reserves", reserveRecord)
- .put("history", historyEntry)
- .finish()
- .then(() => {
- let r: CreateReserveResponse = {
- mint: canonMint,
- reservePub: reservePub.toCrock(),
- };
- return r;
- });
+ return Query(this.db)
+ .put("reserves", reserveRecord)
+ .put("history", historyEntry)
+ .finish()
+ .then(() => {
+ let r: CreateReserveResponse = {
+ mint: canonMint,
+ reservePub: keypair.pub,
+ };
+ return r;
+ });
+ });
}
@@ -820,18 +722,19 @@ export class Wallet {
});
}
let r = JSON.parse(resp.responseText);
- let denomSig = native.rsaUnblind(native.RsaSignature.fromCrock(r.ev_sig),
- native.RsaBlindingKey.fromCrock(pc.blindingKey),
- native.RsaPublicKey.fromCrock(pc.denomPub));
- let coin: Coin = {
- coinPub: pc.coinPub,
- coinPriv: pc.coinPriv,
- denomPub: pc.denomPub,
- denomSig: denomSig.encode().toCrock(),
- currentAmount: pc.coinValue,
- mintBaseUrl: pc.mintBaseUrl,
- };
- return coin;
+ return this.cryptoApi.rsaUnblind(r.ev_sig, pc.blindingKey, pc.denomPub)
+ .then((denomSig) => {
+ let coin: Coin = {
+ coinPub: pc.coinPub,
+ coinPriv: pc.coinPriv,
+ denomPub: pc.denomPub,
+ denomSig: denomSig,
+ currentAmount: pc.coinValue,
+ mintBaseUrl: pc.mintBaseUrl,
+ };
+ return coin;
+
+ });
});
}
@@ -859,7 +762,8 @@ export class Wallet {
*/
private withdraw(denom: Denomination, reserve: Reserve): Promise<void> {
console.log("creating pre coin at", new Date());
- return this.createPreCoin(denom, reserve)
+ return this.cryptoApi
+ .createPreCoin(denom, reserve)
.then((preCoin) => {
return Query(this.db)
.put("precoins", preCoin)
@@ -936,14 +840,21 @@ export class Wallet {
let selectedDenoms = getWithdrawDenomList(amount,
mintInfo.denoms);
- let acc = native.Amount.getZero(amount.currency);
+ let acc = Amounts.getZero(amount.currency);
for (let d of selectedDenoms) {
- acc.add(new native.Amount(d.fee_withdraw));
+ acc = Amounts.add(acc, d.fee_withdraw).amount;
}
+ let actualCoinCost = selectedDenoms
+ .map((d: Denomination) => Amounts.add(d.value,
+ d.fee_withdraw).amount)
+ .reduce((a, b) => Amounts.add(a, b).amount);
+ console.log("actual coin cost", actualCoinCost);
+ console.log("amount", amount);
let ret: ReserveCreationInfo = {
mintInfo,
selectedDenoms,
- withdrawFee: acc.toJson(),
+ withdrawFee: acc,
+ overhead: Amounts.sub(amount, actualCoinCost).amount,
};
return ret;
});
@@ -978,7 +889,7 @@ export class Wallet {
console.log("using old mint");
}
- return mintInfo.mergeKeys(mintKeysJson, this)
+ return mintInfo.mergeKeys(mintKeysJson, this.cryptoApi)
.then(() => {
return Query(this.db)
.put("mints", mintInfo)
@@ -999,11 +910,10 @@ export class Wallet {
function collectBalances(c: Coin, byCurrency) {
let acc: AmountJson = byCurrency[c.currentAmount.currency];
if (!acc) {
- acc = native.Amount.getZero(c.currentAmount.currency).toJson();
+ acc = Amounts.getZero(c.currentAmount.currency);
}
- let am = new native.Amount(c.currentAmount);
- am.add(new native.Amount(acc));
- byCurrency[c.currentAmount.currency] = am.toJson();
+ byCurrency[c.currentAmount.currency] = Amounts.add(c.currentAmount,
+ acc).amount;
return byCurrency;
}
@@ -1026,31 +936,4 @@ export class Wallet {
.iter("history", {indexName: "timestamp"})
.reduce(collect, [])
}
-
- registerRpcId(resolve, reject): number {
- let id = this.nextRpcId++;
- this.rpcRegistry[id] = {resolve, reject};
- return id;
- }
-
- private doRpc<T>(methodName: string, ...args): Promise<T> {
- return new Promise<T>((resolve, reject) => {
- let msg = {
- operation: methodName,
- id: this.registerRpcId(resolve, reject),
- args: args,
- };
- this.cryptoWorker.postMessage(msg);
- });
- }
-
-
- createPreCoin(denom: Denomination, reserve: Reserve): Promise<PreCoin> {
- return this.doRpc("createPreCoin", denom, reserve);
- }
-
- isValidDenom(denom: Denomination,
- masterPub: string): Promise<boolean> {
- return this.doRpc("isValidDenom", denom, masterPub);
- }
} \ No newline at end of file
diff --git a/extension/manifest.json b/extension/manifest.json
index c4c2de987..6ed8f0948 100644
--- a/extension/manifest.json
+++ b/extension/manifest.json
@@ -43,7 +43,6 @@
"scripts": [
"lib/vendor/URI.js",
"lib/vendor/lodash.core.min.js",
- "lib/emscripten/libwrapper.js",
"lib/vendor/system-csp-production.src.js",
"background/main.js"
]
diff --git a/extension/pages/confirm-create-reserve.js b/extension/pages/confirm-create-reserve.js
index 610697246..97b2314ff 100644
--- a/extension/pages/confirm-create-reserve.js
+++ b/extension/pages/confirm-create-reserve.js
@@ -16,7 +16,7 @@
System.register(["../lib/wallet/helpers", "../lib/wallet/types", "mithril", "../lib/wallet/wxApi"], function(exports_1, context_1) {
"use strict";
var __moduleName = context_1 && context_1.id;
- var helpers_1, types_1, mithril_1, wxApi_1;
+ var helpers_1, types_1, mithril_1, types_2, wxApi_1;
var DelayTimer, Controller;
function view(ctrl) {
var controls = [];
@@ -46,28 +46,29 @@ System.register(["../lib/wallet/helpers", "../lib/wallet/types", "mithril", "../
mx("p", "Checking URL, please wait ...");
}
if (ctrl.reserveCreationInfo) {
- var withdrawFeeStr = helpers_1.amountToPretty(ctrl.reserveCreationInfo.withdrawFee);
- mx("p", "Fee for withdrawal: " + withdrawFeeStr);
+ var totalCost = types_2.Amounts.add(ctrl.reserveCreationInfo.overhead, ctrl.reserveCreationInfo.withdrawFee).amount;
+ mx("p", "Withdraw cost: " + helpers_1.amountToPretty(totalCost));
if (ctrl.detailCollapsed()) {
mx("button.linky", {
onclick: function () {
ctrl.detailCollapsed(false);
}
- }, "show more");
+ }, "show more details");
}
else {
mx("button.linky", {
onclick: function () {
ctrl.detailCollapsed(true);
}
- }, "show less");
- mx("div", {}, renderCoinTable(ctrl.reserveCreationInfo.selectedDenoms));
+ }, "hide details");
+ mx("div", {}, renderReserveCreationDetails(ctrl.reserveCreationInfo));
}
}
return mithril_1.default("div", controls);
var _a;
}
- function renderCoinTable(denoms) {
+ function renderReserveCreationDetails(rci) {
+ var denoms = rci.selectedDenoms;
function row(denom) {
return mithril_1.default("tr", [
mithril_1.default("td", denom.pub_hash.substr(0, 5) + "..."),
@@ -77,16 +78,22 @@ System.register(["../lib/wallet/helpers", "../lib/wallet/types", "mithril", "../
mithril_1.default("td", helpers_1.amountToPretty(denom.fee_deposit)),
]);
}
- return mithril_1.default("table", [
- mithril_1.default("tr", [
- mithril_1.default("th", "Key Hash"),
- mithril_1.default("th", "Value"),
- mithril_1.default("th", "Withdraw Fee"),
- mithril_1.default("th", "Refresh Fee"),
- mithril_1.default("th", "Deposit Fee"),
- ]),
- denoms.map(row)
- ]);
+ var withdrawFeeStr = helpers_1.amountToPretty(rci.withdrawFee);
+ var overheadStr = helpers_1.amountToPretty(rci.overhead);
+ return [
+ mithril_1.default("p", "Fee for withdrawal: " + withdrawFeeStr),
+ mithril_1.default("p", "Overhead: " + overheadStr),
+ mithril_1.default("table", [
+ mithril_1.default("tr", [
+ mithril_1.default("th", "Key Hash"),
+ mithril_1.default("th", "Value"),
+ mithril_1.default("th", "Withdraw Fee"),
+ mithril_1.default("th", "Refresh Fee"),
+ mithril_1.default("th", "Deposit Fee"),
+ ]),
+ denoms.map(row)
+ ])
+ ];
}
function probeMint(mintBaseUrl) {
throw Error("not implemented");
@@ -131,6 +138,7 @@ System.register(["../lib/wallet/helpers", "../lib/wallet/types", "mithril", "../
},
function (types_1_1) {
types_1 = types_1_1;
+ types_2 = types_1_1;
},
function (mithril_1_1) {
mithril_1 = mithril_1_1;
diff --git a/extension/pages/confirm-create-reserve.tsx b/extension/pages/confirm-create-reserve.tsx
index 9ae2938f3..2c42813a1 100644
--- a/extension/pages/confirm-create-reserve.tsx
+++ b/extension/pages/confirm-create-reserve.tsx
@@ -20,7 +20,7 @@ import {amountToPretty, canonicalizeBaseUrl} from "../lib/wallet/helpers";
import {AmountJson, CreateReserveResponse} from "../lib/wallet/types";
import m from "mithril";
import {IMintInfo} from "../lib/wallet/types";
-import {ReserveCreationInfo} from "../lib/wallet/types";
+import {ReserveCreationInfo, Amounts} from "../lib/wallet/types";
import MithrilComponent = _mithril.MithrilComponent;
import {Denomination} from "../lib/wallet/types";
import {getReserveCreationInfo} from "../lib/wallet/wxApi";
@@ -201,22 +201,22 @@ function view(ctrl: Controller) {
}
if (ctrl.reserveCreationInfo) {
- let withdrawFeeStr = amountToPretty(ctrl.reserveCreationInfo.withdrawFee);
- mx("p", `Fee for withdrawal: ${withdrawFeeStr}`);
-
+ let totalCost = Amounts.add(ctrl.reserveCreationInfo.overhead,
+ ctrl.reserveCreationInfo.withdrawFee).amount;
+ mx("p", `Withdraw cost: ${amountToPretty(totalCost)}`);
if (ctrl.detailCollapsed()) {
mx("button.linky", {
onclick: () => {
ctrl.detailCollapsed(false);
}
- }, "show more");
+ }, "show more details");
} else {
mx("button.linky", {
onclick: () => {
ctrl.detailCollapsed(true);
}
- }, "show less");
- mx("div", {}, renderCoinTable(ctrl.reserveCreationInfo.selectedDenoms))
+ }, "hide details");
+ mx("div", {}, renderReserveCreationDetails(ctrl.reserveCreationInfo))
}
}
@@ -224,7 +224,9 @@ function view(ctrl: Controller) {
}
-function renderCoinTable(denoms: Denomination[]) {
+function renderReserveCreationDetails(rci: ReserveCreationInfo) {
+ let denoms = rci.selectedDenoms;
+
function row(denom: Denomination) {
return m("tr", [
m("td", denom.pub_hash.substr(0, 5) + "..."),
@@ -234,16 +236,23 @@ function renderCoinTable(denoms: Denomination[]) {
m("td", amountToPretty(denom.fee_deposit)),
]);
}
- return m("table", [
- m("tr", [
- m("th", "Key Hash"),
- m("th", "Value"),
- m("th", "Withdraw Fee"),
- m("th", "Refresh Fee"),
- m("th", "Deposit Fee"),
- ]),
- denoms.map(row)
- ]);
+
+ let withdrawFeeStr = amountToPretty(rci.withdrawFee);
+ let overheadStr = amountToPretty(rci.overhead);
+ return [
+ m("p", `Fee for withdrawal: ${withdrawFeeStr}`),
+ m("p", `Overhead: ${overheadStr}`),
+ m("table", [
+ m("tr", [
+ m("th", "Key Hash"),
+ m("th", "Value"),
+ m("th", "Withdraw Fee"),
+ m("th", "Refresh Fee"),
+ m("th", "Deposit Fee"),
+ ]),
+ denoms.map(row)
+ ])
+ ];
}
diff --git a/extension/tsconfig.json b/extension/tsconfig.json
index f11267a0c..0e6337d86 100644
--- a/extension/tsconfig.json
+++ b/extension/tsconfig.json
@@ -13,6 +13,7 @@
"lib/i18n.ts",
"lib/refs.ts",
"lib/wallet/checkable.ts",
+ "lib/wallet/cryptoApi.ts",
"lib/wallet/cryptoLib.ts",
"lib/wallet/cryptoWorker.ts",
"lib/wallet/db.ts",