mint->exchange
This commit is contained in:
parent
65eabbf6da
commit
9a197d619c
@ -45,7 +45,6 @@ var TalerNotify;
|
|||||||
amount: JSON.stringify(e.detail.amount),
|
amount: JSON.stringify(e.detail.amount),
|
||||||
callback_url: URI(e.detail.callback_url).absoluteTo(document.location.href),
|
callback_url: URI(e.detail.callback_url).absoluteTo(document.location.href),
|
||||||
bank_url: document.location.href,
|
bank_url: document.location.href,
|
||||||
suggested_mint: e.detail.suggested_mint,
|
|
||||||
};
|
};
|
||||||
var uri = URI(chrome.extension.getURL("pages/confirm-create-reserve.html"));
|
var uri = URI(chrome.extension.getURL("pages/confirm-create-reserve.html"));
|
||||||
document.location.href = uri.query(params).href();
|
document.location.href = uri.query(params).href();
|
||||||
|
@ -8472,7 +8472,7 @@ function _TALER_WRALL_sign_deposit_permission($h_contract,$h_wire,$timestamp,$re
|
|||||||
}
|
}
|
||||||
return (0)|0;
|
return (0)|0;
|
||||||
}
|
}
|
||||||
function _TALER_WR_verify_confirmation($h_contract,$h_wire,$timestamp,$refund,$0,$1,$amount_minus_fee,$coin_pub,$merchant_pub,$sig,$mint_pub) {
|
function _TALER_WR_verify_confirmation($h_contract,$h_wire,$timestamp,$refund,$0,$1,$amount_minus_fee,$coin_pub,$merchant_pub,$sig,$exchange_pub) {
|
||||||
$h_contract = $h_contract|0;
|
$h_contract = $h_contract|0;
|
||||||
$h_wire = $h_wire|0;
|
$h_wire = $h_wire|0;
|
||||||
$timestamp = $timestamp|0;
|
$timestamp = $timestamp|0;
|
||||||
@ -8483,7 +8483,7 @@ function _TALER_WR_verify_confirmation($h_contract,$h_wire,$timestamp,$refund,$0
|
|||||||
$coin_pub = $coin_pub|0;
|
$coin_pub = $coin_pub|0;
|
||||||
$merchant_pub = $merchant_pub|0;
|
$merchant_pub = $merchant_pub|0;
|
||||||
$sig = $sig|0;
|
$sig = $sig|0;
|
||||||
$mint_pub = $mint_pub|0;
|
$exchange_pub = $exchange_pub|0;
|
||||||
var $10 = 0, $11 = 0, $12 = 0, $13 = 0, $14 = 0, $15 = 0, $16 = 0, $17 = 0, $18 = 0, $19 = 0, $2 = 0, $20 = 0, $21 = 0, $22 = 0, $23 = 0, $24 = 0, $25 = 0, $26 = 0, $27 = 0, $28 = 0;
|
var $10 = 0, $11 = 0, $12 = 0, $13 = 0, $14 = 0, $15 = 0, $16 = 0, $17 = 0, $18 = 0, $19 = 0, $2 = 0, $20 = 0, $21 = 0, $22 = 0, $23 = 0, $24 = 0, $25 = 0, $26 = 0, $27 = 0, $28 = 0;
|
||||||
var $29 = 0, $3 = 0, $30 = 0, $31 = 0, $32 = 0, $33 = 0, $34 = 0, $35 = 0, $36 = 0, $37 = 0, $38 = 0, $39 = 0, $4 = 0, $40 = 0, $41 = 0, $42 = 0, $43 = 0, $44 = 0, $45 = 0, $46 = 0;
|
var $29 = 0, $3 = 0, $30 = 0, $31 = 0, $32 = 0, $33 = 0, $34 = 0, $35 = 0, $36 = 0, $37 = 0, $38 = 0, $39 = 0, $4 = 0, $40 = 0, $41 = 0, $42 = 0, $43 = 0, $44 = 0, $45 = 0, $46 = 0;
|
||||||
var $47 = 0, $48 = 0, $49 = 0, $5 = 0, $50 = 0, $51 = 0, $52 = 0, $53 = 0, $54 = 0, $55 = 0, $56 = 0, $57 = 0, $58 = 0, $59 = 0, $6 = 0, $60 = 0, $61 = 0, $62 = 0, $63 = 0, $64 = 0;
|
var $47 = 0, $48 = 0, $49 = 0, $5 = 0, $50 = 0, $51 = 0, $52 = 0, $53 = 0, $54 = 0, $55 = 0, $56 = 0, $57 = 0, $58 = 0, $59 = 0, $6 = 0, $60 = 0, $61 = 0, $62 = 0, $63 = 0, $64 = 0;
|
||||||
@ -8514,7 +8514,7 @@ function _TALER_WR_verify_confirmation($h_contract,$h_wire,$timestamp,$refund,$0
|
|||||||
$9 = $coin_pub;
|
$9 = $coin_pub;
|
||||||
$10 = $merchant_pub;
|
$10 = $merchant_pub;
|
||||||
$11 = $sig;
|
$11 = $sig;
|
||||||
$12 = $mint_pub;
|
$12 = $exchange_pub;
|
||||||
$19 = ((($dc)) + 8|0);
|
$19 = ((($dc)) + 8|0);
|
||||||
$20 = $3;
|
$20 = $3;
|
||||||
dest=$19; src=$20; stop=dest+64|0; do { HEAP8[dest>>0]=HEAP8[src>>0]|0; dest=dest+1|0; src=src+1|0; } while ((dest|0) < (stop|0));
|
dest=$19; src=$20; stop=dest+64|0; do { HEAP8[dest>>0]=HEAP8[src>>0]|0; dest=dest+1|0; src=src+1|0; } while ((dest|0) < (stop|0));
|
||||||
|
@ -101,7 +101,7 @@ namespace RpcFunctions {
|
|||||||
coinPub: coinPub.toCrock(),
|
coinPub: coinPub.toCrock(),
|
||||||
coinPriv: coinPriv.toCrock(),
|
coinPriv: coinPriv.toCrock(),
|
||||||
denomPub: denomPub.encode().toCrock(),
|
denomPub: denomPub.encode().toCrock(),
|
||||||
mintBaseUrl: reserve.mint_base_url,
|
exchangeBaseUrl: reserve.exchange_base_url,
|
||||||
withdrawSig: sig.toCrock(),
|
withdrawSig: sig.toCrock(),
|
||||||
coinEv: ev.toCrock(),
|
coinEv: ev.toCrock(),
|
||||||
coinValue: denom.value
|
coinValue: denom.value
|
||||||
|
@ -45,12 +45,12 @@ export function openTalerDb(): Promise<IDBDatabase> {
|
|||||||
console.log("DB: upgrade needed: oldVersion = " + e.oldVersion);
|
console.log("DB: upgrade needed: oldVersion = " + e.oldVersion);
|
||||||
switch (e.oldVersion) {
|
switch (e.oldVersion) {
|
||||||
case 0: // DB does not exist yet
|
case 0: // DB does not exist yet
|
||||||
const mints = db.createObjectStore("mints", {keyPath: "baseUrl"});
|
const exchanges = db.createObjectStore("exchanges", {keyPath: "baseUrl"});
|
||||||
mints.createIndex("pubKey", "masterPublicKey");
|
exchanges.createIndex("pubKey", "masterPublicKey");
|
||||||
db.createObjectStore("reserves", {keyPath: "reserve_pub"});
|
db.createObjectStore("reserves", {keyPath: "reserve_pub"});
|
||||||
db.createObjectStore("denoms", {keyPath: "denomPub"});
|
db.createObjectStore("denoms", {keyPath: "denomPub"});
|
||||||
const coins = db.createObjectStore("coins", {keyPath: "coinPub"});
|
const coins = db.createObjectStore("coins", {keyPath: "coinPub"});
|
||||||
coins.createIndex("mintBaseUrl", "mintBaseUrl");
|
coins.createIndex("exchangeBaseUrl", "exchangeBaseUrl");
|
||||||
const transactions = db.createObjectStore("transactions",
|
const transactions = db.createObjectStore("transactions",
|
||||||
{keyPath: "contractHash"});
|
{keyPath: "contractHash"});
|
||||||
transactions.createIndex("repurchase",
|
transactions.createIndex("repurchase",
|
||||||
|
@ -36,7 +36,7 @@ export function amountToPretty(amount: AmountJson): string {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Canonicalize a base url, typically for the mint.
|
* Canonicalize a base url, typically for the exchange.
|
||||||
*
|
*
|
||||||
* See http://api.taler.net/wallet.html#general
|
* See http://api.taler.net/wallet.html#general
|
||||||
*/
|
*/
|
||||||
@ -62,4 +62,4 @@ export function parsePrettyAmount(pretty: string): AmountJson {
|
|||||||
fraction: res[2] ? (parseFloat(`0.${res[2]}`) * 1e-6) : 0,
|
fraction: res[2] ? (parseFloat(`0.${res[2]}`) * 1e-6) : 0,
|
||||||
currency: res[3]
|
currency: res[3]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,11 +43,11 @@ export class AmountJson {
|
|||||||
@Checkable.Class
|
@Checkable.Class
|
||||||
export class CreateReserveResponse {
|
export class CreateReserveResponse {
|
||||||
/**
|
/**
|
||||||
* Mint URL where the bank should create the reserve.
|
* Exchange URL where the bank should create the reserve.
|
||||||
* The URL is canonicalized in the response.
|
* The URL is canonicalized in the response.
|
||||||
*/
|
*/
|
||||||
@Checkable.String
|
@Checkable.String
|
||||||
mint: string;
|
exchange: string;
|
||||||
|
|
||||||
@Checkable.String
|
@Checkable.String
|
||||||
reservePub: string;
|
reservePub: string;
|
||||||
@ -95,14 +95,14 @@ export class Denomination {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export interface IMintInfo {
|
export interface IExchangeInfo {
|
||||||
baseUrl: string;
|
baseUrl: string;
|
||||||
masterPublicKey: string;
|
masterPublicKey: string;
|
||||||
denoms: Denomination[];
|
denoms: Denomination[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ReserveCreationInfo {
|
export interface ReserveCreationInfo {
|
||||||
mintInfo: IMintInfo;
|
exchangeInfo: IExchangeInfo;
|
||||||
selectedDenoms: Denomination[];
|
selectedDenoms: Denomination[];
|
||||||
withdrawFee: AmountJson;
|
withdrawFee: AmountJson;
|
||||||
overhead: AmountJson;
|
overhead: AmountJson;
|
||||||
@ -117,13 +117,13 @@ export interface PreCoin {
|
|||||||
blindingKey: string;
|
blindingKey: string;
|
||||||
withdrawSig: string;
|
withdrawSig: string;
|
||||||
coinEv: string;
|
coinEv: string;
|
||||||
mintBaseUrl: string;
|
exchangeBaseUrl: string;
|
||||||
coinValue: AmountJson;
|
coinValue: AmountJson;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export interface Reserve {
|
export interface Reserve {
|
||||||
mint_base_url: string
|
exchange_base_url: string
|
||||||
reserve_priv: string;
|
reserve_priv: string;
|
||||||
reserve_pub: string;
|
reserve_pub: string;
|
||||||
}
|
}
|
||||||
@ -144,7 +144,7 @@ export interface Coin {
|
|||||||
denomPub: string;
|
denomPub: string;
|
||||||
denomSig: string;
|
denomSig: string;
|
||||||
currentAmount: AmountJson;
|
currentAmount: AmountJson;
|
||||||
mintBaseUrl: string;
|
exchangeBaseUrl: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -266,4 +266,4 @@ export interface CheckRepurchaseResult {
|
|||||||
|
|
||||||
export interface Notifier {
|
export interface Notifier {
|
||||||
notify();
|
notify();
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
* @author Florian Dold
|
* @author Florian Dold
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {AmountJson, CreateReserveResponse, IMintInfo, Denomination, Notifier} from "./types";
|
import {AmountJson, CreateReserveResponse, IExchangeInfo, Denomination, Notifier} from "./types";
|
||||||
import {HttpResponse, RequestException} from "./http";
|
import {HttpResponse, RequestException} from "./http";
|
||||||
import {Query} from "./query";
|
import {Query} from "./query";
|
||||||
import {Checkable} from "./checkable";
|
import {Checkable} from "./checkable";
|
||||||
@ -70,7 +70,7 @@ export class KeysJson {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class MintInfo implements IMintInfo {
|
class ExchangeInfo implements IExchangeInfo {
|
||||||
baseUrl: string;
|
baseUrl: string;
|
||||||
masterPublicKey: string;
|
masterPublicKey: string;
|
||||||
denoms: Denomination[];
|
denoms: Denomination[];
|
||||||
@ -89,15 +89,15 @@ class MintInfo implements IMintInfo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static fresh(baseUrl: string): MintInfo {
|
static fresh(baseUrl: string): ExchangeInfo {
|
||||||
return new MintInfo({baseUrl});
|
return new ExchangeInfo({baseUrl});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Merge new key information into the mint info.
|
* Merge new key information into the exchange info.
|
||||||
* If the new key information is invalid (missing fields,
|
* If the new key information is invalid (missing fields,
|
||||||
* invalid signatures), an exception is thrown, but the
|
* invalid signatures), an exception is thrown, but the
|
||||||
* mint info is updated with the new information up until
|
* exchange info is updated with the new information up until
|
||||||
* the first error.
|
* the first error.
|
||||||
*/
|
*/
|
||||||
mergeKeys(newKeys: KeysJson, cryptoApi: CryptoApi): Promise<void> {
|
mergeKeys(newKeys: KeysJson, cryptoApi: CryptoApi): Promise<void> {
|
||||||
@ -160,10 +160,10 @@ export class CreateReserveRequest {
|
|||||||
amount: AmountJson;
|
amount: AmountJson;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mint URL where the bank should create the reserve.
|
* Exchange URL where the bank should create the reserve.
|
||||||
*/
|
*/
|
||||||
@Checkable.String
|
@Checkable.String
|
||||||
mint: string;
|
exchange: string;
|
||||||
|
|
||||||
static checked: (obj: any) => CreateReserveRequest;
|
static checked: (obj: any) => CreateReserveRequest;
|
||||||
}
|
}
|
||||||
@ -183,14 +183,14 @@ export class ConfirmReserveRequest {
|
|||||||
|
|
||||||
|
|
||||||
@Checkable.Class
|
@Checkable.Class
|
||||||
export class MintHandle {
|
export class ExchangeHandle {
|
||||||
@Checkable.String
|
@Checkable.String
|
||||||
master_pub: string;
|
master_pub: string;
|
||||||
|
|
||||||
@Checkable.String
|
@Checkable.String
|
||||||
url: string;
|
url: string;
|
||||||
|
|
||||||
static checked: (obj: any) => MintHandle;
|
static checked: (obj: any) => ExchangeHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -220,8 +220,8 @@ export class Contract {
|
|||||||
@Checkable.String
|
@Checkable.String
|
||||||
merchant_pub: string;
|
merchant_pub: string;
|
||||||
|
|
||||||
@Checkable.List(Checkable.Value(MintHandle))
|
@Checkable.List(Checkable.Value(ExchangeHandle))
|
||||||
mints: MintHandle[];
|
exchanges: ExchangeHandle[];
|
||||||
|
|
||||||
@Checkable.List(Checkable.AnyObject)
|
@Checkable.List(Checkable.AnyObject)
|
||||||
products: any[];
|
products: any[];
|
||||||
@ -264,8 +264,8 @@ interface ConfirmPayRequest {
|
|||||||
offer: Offer;
|
offer: Offer;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface MintCoins {
|
interface ExchangeCoins {
|
||||||
[mintUrl: string]: CoinWithDenom[];
|
[exchangeUrl: string]: CoinWithDenom[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -402,22 +402,22 @@ export class Wallet {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get mints and associated coins that are still spendable,
|
* Get exchanges and associated coins that are still spendable,
|
||||||
* but only if the sum the coins' remaining value exceeds the payment amount.
|
* but only if the sum the coins' remaining value exceeds the payment amount.
|
||||||
*/
|
*/
|
||||||
private getPossibleMintCoins(paymentAmount: AmountJson,
|
private getPossibleExchangeCoins(paymentAmount: AmountJson,
|
||||||
depositFeeLimit: AmountJson,
|
depositFeeLimit: AmountJson,
|
||||||
allowedMints: MintHandle[]): Promise<MintCoins> {
|
allowedExchanges: ExchangeHandle[]): Promise<ExchangeCoins> {
|
||||||
// Mapping from mint base URL to list of coins together with their
|
// Mapping from exchange base URL to list of coins together with their
|
||||||
// denomination
|
// denomination
|
||||||
let m: MintCoins = {};
|
let m: ExchangeCoins = {};
|
||||||
|
|
||||||
function storeMintCoin(mc) {
|
function storeExchangeCoin(mc) {
|
||||||
let mint: IMintInfo = mc[0];
|
let exchange: IExchangeInfo = mc[0];
|
||||||
let coin: Coin = mc[1];
|
let coin: Coin = mc[1];
|
||||||
let cd = {
|
let cd = {
|
||||||
coin: coin,
|
coin: coin,
|
||||||
denom: mint.denoms.find((e) => e.denom_pub === coin.denomPub)
|
denom: exchange.denoms.find((e) => e.denom_pub === coin.denomPub)
|
||||||
};
|
};
|
||||||
if (!cd.denom) {
|
if (!cd.denom) {
|
||||||
throw Error("denom not found (database inconsistent)");
|
throw Error("denom not found (database inconsistent)");
|
||||||
@ -426,36 +426,36 @@ export class Wallet {
|
|||||||
console.warn("same pubkey for different currencies");
|
console.warn("same pubkey for different currencies");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let x = m[mint.baseUrl];
|
let x = m[exchange.baseUrl];
|
||||||
if (!x) {
|
if (!x) {
|
||||||
m[mint.baseUrl] = [cd];
|
m[exchange.baseUrl] = [cd];
|
||||||
} else {
|
} else {
|
||||||
x.push(cd);
|
x.push(cd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let ps = allowedMints.map((info) => {
|
let ps = allowedExchanges.map((info) => {
|
||||||
console.log("Checking for merchant's mint", JSON.stringify(info));
|
console.log("Checking for merchant's exchange", JSON.stringify(info));
|
||||||
return Query(this.db)
|
return Query(this.db)
|
||||||
.iter("mints", {indexName: "pubKey", only: info.master_pub})
|
.iter("exchanges", {indexName: "pubKey", only: info.master_pub})
|
||||||
.indexJoin("coins", "mintBaseUrl", (mint) => mint.baseUrl)
|
.indexJoin("coins", "exchangeBaseUrl", (exchange) => exchange.baseUrl)
|
||||||
.reduce(storeMintCoin);
|
.reduce(storeExchangeCoin);
|
||||||
});
|
});
|
||||||
|
|
||||||
return Promise.all(ps).then(() => {
|
return Promise.all(ps).then(() => {
|
||||||
let ret: MintCoins = {};
|
let ret: ExchangeCoins = {};
|
||||||
|
|
||||||
if (Object.keys(m).length == 0) {
|
if (Object.keys(m).length == 0) {
|
||||||
console.log("not suitable mints found");
|
console.log("not suitable exchanges found");
|
||||||
}
|
}
|
||||||
|
|
||||||
console.dir(m);
|
console.dir(m);
|
||||||
|
|
||||||
// We try to find the first mint where we have
|
// We try to find the first exchange where we have
|
||||||
// enough coins to cover the paymentAmount with fees
|
// enough coins to cover the paymentAmount with fees
|
||||||
// under depositFeeLimit
|
// under depositFeeLimit
|
||||||
|
|
||||||
nextMint:
|
nextExchange:
|
||||||
for (let key in m) {
|
for (let key in m) {
|
||||||
let coins = m[key];
|
let coins = m[key];
|
||||||
// Sort by ascending deposit fee
|
// Sort by ascending deposit fee
|
||||||
@ -479,12 +479,12 @@ export class Wallet {
|
|||||||
// FIXME: if the fees are too high, we have
|
// FIXME: if the fees are too high, we have
|
||||||
// to cover them ourselves ....
|
// to cover them ourselves ....
|
||||||
console.log("too much fees");
|
console.log("too much fees");
|
||||||
continue nextMint;
|
continue nextExchange;
|
||||||
}
|
}
|
||||||
usableCoins.push(coins[i]);
|
usableCoins.push(coins[i]);
|
||||||
if (Amounts.cmp(accAmount, minAmount) >= 0) {
|
if (Amounts.cmp(accAmount, minAmount) >= 0) {
|
||||||
ret[key] = usableCoins;
|
ret[key] = usableCoins;
|
||||||
continue nextMint;
|
continue nextExchange;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -499,14 +499,14 @@ export class Wallet {
|
|||||||
*/
|
*/
|
||||||
private recordConfirmPay(offer: Offer,
|
private recordConfirmPay(offer: Offer,
|
||||||
payCoinInfo: PayCoinInfo,
|
payCoinInfo: PayCoinInfo,
|
||||||
chosenMint: string): Promise<void> {
|
chosenExchange: string): Promise<void> {
|
||||||
let payReq = {};
|
let payReq = {};
|
||||||
payReq["amount"] = offer.contract.amount;
|
payReq["amount"] = offer.contract.amount;
|
||||||
payReq["coins"] = payCoinInfo.map((x) => x.sig);
|
payReq["coins"] = payCoinInfo.map((x) => x.sig);
|
||||||
payReq["H_contract"] = offer.H_contract;
|
payReq["H_contract"] = offer.H_contract;
|
||||||
payReq["max_fee"] = offer.contract.max_fee;
|
payReq["max_fee"] = offer.contract.max_fee;
|
||||||
payReq["merchant_sig"] = offer.merchant_sig;
|
payReq["merchant_sig"] = offer.merchant_sig;
|
||||||
payReq["mint"] = URI(chosenMint).href();
|
payReq["exchange"] = URI(chosenExchange).href();
|
||||||
payReq["refund_deadline"] = offer.contract.refund_deadline;
|
payReq["refund_deadline"] = offer.contract.refund_deadline;
|
||||||
payReq["timestamp"] = offer.contract.timestamp;
|
payReq["timestamp"] = offer.contract.timestamp;
|
||||||
payReq["transaction_id"] = offer.contract.transaction_id;
|
payReq["transaction_id"] = offer.contract.transaction_id;
|
||||||
@ -549,9 +549,9 @@ export class Wallet {
|
|||||||
confirmPay(offer: Offer): Promise<any> {
|
confirmPay(offer: Offer): Promise<any> {
|
||||||
console.log("executing confirmPay");
|
console.log("executing confirmPay");
|
||||||
return Promise.resolve().then(() => {
|
return Promise.resolve().then(() => {
|
||||||
return this.getPossibleMintCoins(offer.contract.amount,
|
return this.getPossibleExchangeCoins(offer.contract.amount,
|
||||||
offer.contract.max_fee,
|
offer.contract.max_fee,
|
||||||
offer.contract.mints)
|
offer.contract.exchanges)
|
||||||
}).then((mcs) => {
|
}).then((mcs) => {
|
||||||
if (Object.keys(mcs).length == 0) {
|
if (Object.keys(mcs).length == 0) {
|
||||||
console.log("not confirming payment, insufficient coins");
|
console.log("not confirming payment, insufficient coins");
|
||||||
@ -559,10 +559,10 @@ export class Wallet {
|
|||||||
error: "coins-insufficient",
|
error: "coins-insufficient",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
let mintUrl = Object.keys(mcs)[0];
|
let exchangeUrl = Object.keys(mcs)[0];
|
||||||
|
|
||||||
return this.cryptoApi.signDeposit(offer, mcs[mintUrl])
|
return this.cryptoApi.signDeposit(offer, mcs[exchangeUrl])
|
||||||
.then((ds) => this.recordConfirmPay(offer, ds, mintUrl))
|
.then((ds) => this.recordConfirmPay(offer, ds, exchangeUrl))
|
||||||
.then(() => ({}));
|
.then(() => ({}));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -599,11 +599,11 @@ export class Wallet {
|
|||||||
* then deplete the reserve, withdrawing coins until it is empty.
|
* then deplete the reserve, withdrawing coins until it is empty.
|
||||||
*/
|
*/
|
||||||
private initReserve(reserveRecord) {
|
private initReserve(reserveRecord) {
|
||||||
this.updateMintFromUrl(reserveRecord.mint_base_url)
|
this.updateExchangeFromUrl(reserveRecord.exchange_base_url)
|
||||||
.then((mint) =>
|
.then((exchange) =>
|
||||||
this.updateReserve(reserveRecord.reserve_pub, mint)
|
this.updateReserve(reserveRecord.reserve_pub, exchange)
|
||||||
.then((reserve) => this.depleteReserve(reserve,
|
.then((reserve) => this.depleteReserve(reserve,
|
||||||
mint)))
|
exchange)))
|
||||||
.then(() => {
|
.then(() => {
|
||||||
let depleted = {
|
let depleted = {
|
||||||
type: "depleted-reserve",
|
type: "depleted-reserve",
|
||||||
@ -627,12 +627,12 @@ export class Wallet {
|
|||||||
createReserve(req: CreateReserveRequest): Promise<CreateReserveResponse> {
|
createReserve(req: CreateReserveRequest): Promise<CreateReserveResponse> {
|
||||||
return this.cryptoApi.createEddsaKeypair().then((keypair) => {
|
return this.cryptoApi.createEddsaKeypair().then((keypair) => {
|
||||||
const now = (new Date).getTime();
|
const now = (new Date).getTime();
|
||||||
const canonMint = canonicalizeBaseUrl(req.mint);
|
const canonExchange = canonicalizeBaseUrl(req.exchange);
|
||||||
|
|
||||||
const reserveRecord = {
|
const reserveRecord = {
|
||||||
reserve_pub: keypair.pub,
|
reserve_pub: keypair.pub,
|
||||||
reserve_priv: keypair.priv,
|
reserve_priv: keypair.priv,
|
||||||
mint_base_url: canonMint,
|
exchange_base_url: canonExchange,
|
||||||
created: now,
|
created: now,
|
||||||
last_query: null,
|
last_query: null,
|
||||||
current_amount: null,
|
current_amount: null,
|
||||||
@ -656,7 +656,7 @@ export class Wallet {
|
|||||||
.finish()
|
.finish()
|
||||||
.then(() => {
|
.then(() => {
|
||||||
let r: CreateReserveResponse = {
|
let r: CreateReserveResponse = {
|
||||||
mint: canonMint,
|
exchange: canonExchange,
|
||||||
reservePub: keypair.pub,
|
reservePub: keypair.pub,
|
||||||
};
|
};
|
||||||
return r;
|
return r;
|
||||||
@ -668,7 +668,7 @@ export class Wallet {
|
|||||||
/**
|
/**
|
||||||
* Mark an existing reserve as confirmed. The wallet will start trying
|
* Mark an existing reserve as confirmed. The wallet will start trying
|
||||||
* to withdraw from that reserve. This may not immediately succeed,
|
* to withdraw from that reserve. This may not immediately succeed,
|
||||||
* since the mint might not know about the reserve yet, even though the
|
* since the exchange might not know about the reserve yet, even though the
|
||||||
* bank confirmed its creation.
|
* bank confirmed its creation.
|
||||||
*
|
*
|
||||||
* A confirmed reserve should be shown to the user in the UI, while
|
* A confirmed reserve should be shown to the user in the UI, while
|
||||||
@ -708,7 +708,7 @@ export class Wallet {
|
|||||||
wd.reserve_pub = pc.reservePub;
|
wd.reserve_pub = pc.reservePub;
|
||||||
wd.reserve_sig = pc.withdrawSig;
|
wd.reserve_sig = pc.withdrawSig;
|
||||||
wd.coin_ev = pc.coinEv;
|
wd.coin_ev = pc.coinEv;
|
||||||
let reqUrl = URI("reserve/withdraw").absoluteTo(r.mint_base_url);
|
let reqUrl = URI("reserve/withdraw").absoluteTo(r.exchange_base_url);
|
||||||
return this.http.postJson(reqUrl, wd);
|
return this.http.postJson(reqUrl, wd);
|
||||||
})
|
})
|
||||||
.then(resp => {
|
.then(resp => {
|
||||||
@ -727,7 +727,7 @@ export class Wallet {
|
|||||||
denomPub: pc.denomPub,
|
denomPub: pc.denomPub,
|
||||||
denomSig: denomSig,
|
denomSig: denomSig,
|
||||||
currentAmount: pc.coinValue,
|
currentAmount: pc.coinValue,
|
||||||
mintBaseUrl: pc.mintBaseUrl,
|
exchangeBaseUrl: pc.exchangeBaseUrl,
|
||||||
};
|
};
|
||||||
return coin;
|
return coin;
|
||||||
|
|
||||||
@ -775,8 +775,8 @@ export class Wallet {
|
|||||||
/**
|
/**
|
||||||
* Withdraw coins from a reserve until it is empty.
|
* Withdraw coins from a reserve until it is empty.
|
||||||
*/
|
*/
|
||||||
private depleteReserve(reserve, mint: MintInfo): Promise<void> {
|
private depleteReserve(reserve, exchange: ExchangeInfo): Promise<void> {
|
||||||
let denomsAvailable: Denomination[] = copy(mint.denoms);
|
let denomsAvailable: Denomination[] = copy(exchange.denoms);
|
||||||
let denomsForWithdraw = getWithdrawDenomList(reserve.current_amount,
|
let denomsForWithdraw = getWithdrawDenomList(reserve.current_amount,
|
||||||
denomsAvailable);
|
denomsAvailable);
|
||||||
|
|
||||||
@ -793,13 +793,13 @@ export class Wallet {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the information about a reserve that is stored in the wallet
|
* Update the information about a reserve that is stored in the wallet
|
||||||
* by quering the reserve's mint.
|
* by quering the reserve's exchange.
|
||||||
*/
|
*/
|
||||||
private updateReserve(reservePub: string, mint: MintInfo): Promise<Reserve> {
|
private updateReserve(reservePub: string, exchange: ExchangeInfo): Promise<Reserve> {
|
||||||
return Query(this.db)
|
return Query(this.db)
|
||||||
.get("reserves", reservePub)
|
.get("reserves", reservePub)
|
||||||
.then((reserve) => {
|
.then((reserve) => {
|
||||||
let reqUrl = URI("reserve/status").absoluteTo(mint.baseUrl);
|
let reqUrl = URI("reserve/status").absoluteTo(exchange.baseUrl);
|
||||||
reqUrl.query({'reserve_pub': reservePub});
|
reqUrl.query({'reserve_pub': reservePub});
|
||||||
return this.http.get(reqUrl).then(resp => {
|
return this.http.get(reqUrl).then(resp => {
|
||||||
if (resp.status != 200) {
|
if (resp.status != 200) {
|
||||||
@ -832,10 +832,10 @@ export class Wallet {
|
|||||||
|
|
||||||
getReserveCreationInfo(baseUrl: string,
|
getReserveCreationInfo(baseUrl: string,
|
||||||
amount: AmountJson): Promise<ReserveCreationInfo> {
|
amount: AmountJson): Promise<ReserveCreationInfo> {
|
||||||
return this.updateMintFromUrl(baseUrl)
|
return this.updateExchangeFromUrl(baseUrl)
|
||||||
.then((mintInfo: IMintInfo) => {
|
.then((exchangeInfo: IExchangeInfo) => {
|
||||||
let selectedDenoms = getWithdrawDenomList(amount,
|
let selectedDenoms = getWithdrawDenomList(amount,
|
||||||
mintInfo.denoms);
|
exchangeInfo.denoms);
|
||||||
|
|
||||||
let acc = Amounts.getZero(amount.currency);
|
let acc = Amounts.getZero(amount.currency);
|
||||||
for (let d of selectedDenoms) {
|
for (let d of selectedDenoms) {
|
||||||
@ -846,7 +846,7 @@ export class Wallet {
|
|||||||
d.fee_withdraw).amount)
|
d.fee_withdraw).amount)
|
||||||
.reduce((a, b) => Amounts.add(a, b).amount);
|
.reduce((a, b) => Amounts.add(a, b).amount);
|
||||||
let ret: ReserveCreationInfo = {
|
let ret: ReserveCreationInfo = {
|
||||||
mintInfo,
|
exchangeInfo,
|
||||||
selectedDenoms,
|
selectedDenoms,
|
||||||
withdrawFee: acc,
|
withdrawFee: acc,
|
||||||
overhead: Amounts.sub(amount, actualCoinCost).amount,
|
overhead: Amounts.sub(amount, actualCoinCost).amount,
|
||||||
@ -857,37 +857,37 @@ export class Wallet {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update or add mint DB entry by fetching the /keys information.
|
* Update or add exchange DB entry by fetching the /keys information.
|
||||||
* Optionally link the reserve entry to the new or existing
|
* Optionally link the reserve entry to the new or existing
|
||||||
* mint entry in then DB.
|
* exchange entry in then DB.
|
||||||
*/
|
*/
|
||||||
updateMintFromUrl(baseUrl): Promise<MintInfo> {
|
updateExchangeFromUrl(baseUrl): Promise<ExchangeInfo> {
|
||||||
baseUrl = canonicalizeBaseUrl(baseUrl);
|
baseUrl = canonicalizeBaseUrl(baseUrl);
|
||||||
let reqUrl = URI("keys").absoluteTo(baseUrl);
|
let reqUrl = URI("keys").absoluteTo(baseUrl);
|
||||||
return this.http.get(reqUrl).then((resp) => {
|
return this.http.get(reqUrl).then((resp) => {
|
||||||
if (resp.status != 200) {
|
if (resp.status != 200) {
|
||||||
throw Error("/keys request failed");
|
throw Error("/keys request failed");
|
||||||
}
|
}
|
||||||
let mintKeysJson = KeysJson.checked(JSON.parse(resp.responseText));
|
let exchangeKeysJson = KeysJson.checked(JSON.parse(resp.responseText));
|
||||||
|
|
||||||
return Query(this.db).get("mints", baseUrl).then((r) => {
|
return Query(this.db).get("exchanges", baseUrl).then((r) => {
|
||||||
let mintInfo;
|
let exchangeInfo;
|
||||||
console.dir(r);
|
console.dir(r);
|
||||||
|
|
||||||
if (!r) {
|
if (!r) {
|
||||||
mintInfo = MintInfo.fresh(baseUrl);
|
exchangeInfo = ExchangeInfo.fresh(baseUrl);
|
||||||
console.log("making fresh mint");
|
console.log("making fresh exchange");
|
||||||
} else {
|
} else {
|
||||||
mintInfo = new MintInfo(r);
|
exchangeInfo = new ExchangeInfo(r);
|
||||||
console.log("using old mint");
|
console.log("using old exchange");
|
||||||
}
|
}
|
||||||
|
|
||||||
return mintInfo.mergeKeys(mintKeysJson, this.cryptoApi)
|
return exchangeInfo.mergeKeys(exchangeKeysJson, this.cryptoApi)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
return Query(this.db)
|
return Query(this.db)
|
||||||
.put("mints", mintInfo)
|
.put("exchanges", exchangeInfo)
|
||||||
.finish()
|
.finish()
|
||||||
.then(() => mintInfo);
|
.then(() => exchangeInfo);
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
@ -954,4 +954,4 @@ export class Wallet {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -60,7 +60,7 @@ function makeHandlers(db: IDBDatabase,
|
|||||||
},
|
},
|
||||||
["create-reserve"]: function(detail) {
|
["create-reserve"]: function(detail) {
|
||||||
const d = {
|
const d = {
|
||||||
mint: detail.mint,
|
exchange: detail.exchange,
|
||||||
amount: detail.amount,
|
amount: detail.amount,
|
||||||
};
|
};
|
||||||
const req = CreateReserveRequest.checked(d);
|
const req = CreateReserveRequest.checked(d);
|
||||||
@ -96,11 +96,11 @@ function makeHandlers(db: IDBDatabase,
|
|||||||
["execute-payment"]: function(detail) {
|
["execute-payment"]: function(detail) {
|
||||||
return wallet.executePayment(detail.H_contract);
|
return wallet.executePayment(detail.H_contract);
|
||||||
},
|
},
|
||||||
["mint-info"]: function(detail) {
|
["exchange-info"]: function(detail) {
|
||||||
if (!detail.baseUrl) {
|
if (!detail.baseUrl) {
|
||||||
return Promise.resolve({error: "bad url"});
|
return Promise.resolve({error: "bad url"});
|
||||||
}
|
}
|
||||||
return wallet.updateMintFromUrl(detail.baseUrl);
|
return wallet.updateExchangeFromUrl(detail.baseUrl);
|
||||||
},
|
},
|
||||||
["reserve-creation-info"]: function(detail) {
|
["reserve-creation-info"]: function(detail) {
|
||||||
if (!detail.baseUrl || typeof detail.baseUrl !== "string") {
|
if (!detail.baseUrl || typeof detail.baseUrl !== "string") {
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
|
|
||||||
<section id="main">
|
<section id="main">
|
||||||
<article>
|
<article>
|
||||||
<div class="fade" id="mint-selection"></div>
|
<div class="fade" id="exchange-selection"></div>
|
||||||
</article>
|
</article>
|
||||||
</section>
|
</section>
|
||||||
</body>
|
</body>
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
import {amountToPretty, canonicalizeBaseUrl} from "../lib/wallet/helpers";
|
import {amountToPretty, canonicalizeBaseUrl} from "../lib/wallet/helpers";
|
||||||
import {AmountJson, CreateReserveResponse} from "../lib/wallet/types";
|
import {AmountJson, CreateReserveResponse} from "../lib/wallet/types";
|
||||||
import m from "mithril";
|
import m from "mithril";
|
||||||
import {IMintInfo} from "../lib/wallet/types";
|
import {IExchangeInfo} from "../lib/wallet/types";
|
||||||
import {ReserveCreationInfo, Amounts} from "../lib/wallet/types";
|
import {ReserveCreationInfo, Amounts} from "../lib/wallet/types";
|
||||||
import MithrilComponent = _mithril.MithrilComponent;
|
import MithrilComponent = _mithril.MithrilComponent;
|
||||||
import {Denomination} from "../lib/wallet/types";
|
import {Denomination} from "../lib/wallet/types";
|
||||||
@ -60,7 +60,7 @@ class DelayTimer {
|
|||||||
class Controller {
|
class Controller {
|
||||||
url = m.prop<string>();
|
url = m.prop<string>();
|
||||||
statusString = null;
|
statusString = null;
|
||||||
isValidMint = false;
|
isValidExchange = false;
|
||||||
reserveCreationInfo: ReserveCreationInfo = null;
|
reserveCreationInfo: ReserveCreationInfo = null;
|
||||||
private timer: DelayTimer;
|
private timer: DelayTimer;
|
||||||
private request: XMLHttpRequest;
|
private request: XMLHttpRequest;
|
||||||
@ -68,12 +68,12 @@ class Controller {
|
|||||||
callbackUrl: string;
|
callbackUrl: string;
|
||||||
detailCollapsed = m.prop<boolean>(true);
|
detailCollapsed = m.prop<boolean>(true);
|
||||||
|
|
||||||
constructor(initialMintUrl: string, amount: AmountJson, callbackUrl: string) {
|
constructor(initialExchangeUrl: string, amount: AmountJson, callbackUrl: string) {
|
||||||
console.log("creating main controller");
|
console.log("creating main controller");
|
||||||
this.amount = amount;
|
this.amount = amount;
|
||||||
this.callbackUrl = callbackUrl;
|
this.callbackUrl = callbackUrl;
|
||||||
this.timer = new DelayTimer(800, () => this.update());
|
this.timer = new DelayTimer(800, () => this.update());
|
||||||
this.url(initialMintUrl);
|
this.url(initialExchangeUrl);
|
||||||
this.update();
|
this.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,19 +93,19 @@ class Controller {
|
|||||||
|
|
||||||
m.redraw(true);
|
m.redraw(true);
|
||||||
|
|
||||||
console.log("doing get mint info");
|
console.log("doing get exchange info");
|
||||||
|
|
||||||
getReserveCreationInfo(this.url(), this.amount)
|
getReserveCreationInfo(this.url(), this.amount)
|
||||||
.then((r: ReserveCreationInfo) => {
|
.then((r: ReserveCreationInfo) => {
|
||||||
console.log("get mint info resolved");
|
console.log("get exchange info resolved");
|
||||||
this.isValidMint = true;
|
this.isValidExchange = true;
|
||||||
this.reserveCreationInfo = r;
|
this.reserveCreationInfo = r;
|
||||||
console.dir(r);
|
console.dir(r);
|
||||||
this.statusString = "The mint base URL is valid!";
|
this.statusString = "The exchange base URL is valid!";
|
||||||
m.endComputation();
|
m.endComputation();
|
||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
console.log("get mint info rejected");
|
console.log("get exchange info rejected");
|
||||||
if (e.hasOwnProperty("httpStatus")) {
|
if (e.hasOwnProperty("httpStatus")) {
|
||||||
this.statusString = `request failed with status ${this.request.status}`;
|
this.statusString = `request failed with status ${this.request.status}`;
|
||||||
} else {
|
} else {
|
||||||
@ -122,7 +122,7 @@ class Controller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
reset() {
|
reset() {
|
||||||
this.isValidMint = false;
|
this.isValidExchange = false;
|
||||||
this.statusString = null;
|
this.statusString = null;
|
||||||
this.reserveCreationInfo = null;
|
this.reserveCreationInfo = null;
|
||||||
if (this.request) {
|
if (this.request) {
|
||||||
@ -131,8 +131,8 @@ class Controller {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
confirmReserve(mint: string, amount: AmountJson, callback_url: string) {
|
confirmReserve(exchange: string, amount: AmountJson, callback_url: string) {
|
||||||
const d = {mint, amount};
|
const d = {exchange, amount};
|
||||||
const cb = (rawResp) => {
|
const cb = (rawResp) => {
|
||||||
if (!rawResp) {
|
if (!rawResp) {
|
||||||
throw Error("empty response");
|
throw Error("empty response");
|
||||||
@ -140,7 +140,7 @@ class Controller {
|
|||||||
if (!rawResp.error) {
|
if (!rawResp.error) {
|
||||||
const resp = CreateReserveResponse.checked(rawResp);
|
const resp = CreateReserveResponse.checked(rawResp);
|
||||||
let q = {
|
let q = {
|
||||||
mint: resp.mint,
|
exchange: resp.exchange,
|
||||||
reserve_pub: resp.reservePub,
|
reserve_pub: resp.reservePub,
|
||||||
amount_value: amount.value,
|
amount_value: amount.value,
|
||||||
amount_fraction: amount.fraction,
|
amount_fraction: amount.fraction,
|
||||||
@ -190,7 +190,7 @@ function view(ctrl: Controller) {
|
|||||||
onclick: () => ctrl.confirmReserve(ctrl.url(),
|
onclick: () => ctrl.confirmReserve(ctrl.url(),
|
||||||
ctrl.amount,
|
ctrl.amount,
|
||||||
ctrl.callbackUrl),
|
ctrl.callbackUrl),
|
||||||
disabled: !ctrl.isValidMint
|
disabled: !ctrl.isValidExchange
|
||||||
},
|
},
|
||||||
"Confirm exchange selection");
|
"Confirm exchange selection");
|
||||||
|
|
||||||
@ -256,30 +256,30 @@ function renderReserveCreationDetails(rci: ReserveCreationInfo) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
interface MintProbeResult {
|
interface ExchangeProbeResult {
|
||||||
keyInfo?: any;
|
keyInfo?: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
function probeMint(mintBaseUrl: string): Promise<MintProbeResult> {
|
function probeExchange(exchangeBaseUrl: string): Promise<ExchangeProbeResult> {
|
||||||
throw Error("not implemented");
|
throw Error("not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function getSuggestedMint(currency: string): Promise<string> {
|
function getSuggestedExchange(currency: string): Promise<string> {
|
||||||
// TODO: make this request go to the wallet backend
|
// TODO: make this request go to the wallet backend
|
||||||
// Right now, this is a stub.
|
// Right now, this is a stub.
|
||||||
const defaultMint = {
|
const defaultExchange = {
|
||||||
"KUDOS": "http://exchange.demo.taler.net",
|
"KUDOS": "http://exchange.demo.taler.net",
|
||||||
"PUDOS": "http://exchange.test.taler.net",
|
"PUDOS": "http://exchange.test.taler.net",
|
||||||
};
|
};
|
||||||
|
|
||||||
let mint = defaultMint[currency];
|
let exchange = defaultExchange[currency];
|
||||||
|
|
||||||
if (!mint) {
|
if (!exchange) {
|
||||||
mint = ""
|
exchange = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
return Promise.resolve(mint);
|
return Promise.resolve(exchange);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -290,11 +290,11 @@ export function main() {
|
|||||||
const callback_url = query.callback_url;
|
const callback_url = query.callback_url;
|
||||||
const bank_url = query.bank_url;
|
const bank_url = query.bank_url;
|
||||||
|
|
||||||
getSuggestedMint(amount.currency)
|
getSuggestedExchange(amount.currency)
|
||||||
.then((suggestedMintUrl) => {
|
.then((suggestedExchangeUrl) => {
|
||||||
const controller = () => new Controller(suggestedMintUrl, amount, callback_url);
|
const controller = () => new Controller(suggestedExchangeUrl, amount, callback_url);
|
||||||
var MintSelection = {controller, view};
|
var ExchangeSelection = {controller, view};
|
||||||
m.mount(document.getElementById("mint-selection"), MintSelection);
|
m.mount(document.getElementById("exchange-selection"), ExchangeSelection);
|
||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
// TODO: provide more context information, maybe factor it out into a
|
// TODO: provide more context information, maybe factor it out into a
|
||||||
|
Loading…
Reference in New Issue
Block a user