documentation and tslint settings to check for docs
This commit is contained in:
parent
08bd3dc0e8
commit
e7fa87bcc0
@ -30,33 +30,37 @@ function rAF(cb: (ts: number) => void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Badge for Chrome that renders a Taler logo with a rotating ring if some
|
||||||
|
* background activity is happening.
|
||||||
|
*/
|
||||||
export class ChromeBadge implements Badge {
|
export class ChromeBadge implements Badge {
|
||||||
canvas: HTMLCanvasElement;
|
private canvas: HTMLCanvasElement;
|
||||||
ctx: CanvasRenderingContext2D;
|
private ctx: CanvasRenderingContext2D;
|
||||||
/**
|
/**
|
||||||
* True if animation running. The animation
|
* True if animation running. The animation
|
||||||
* might still be running even if we're not busy anymore,
|
* might still be running even if we're not busy anymore,
|
||||||
* just to transition to the "normal" state in a animated way.
|
* just to transition to the "normal" state in a animated way.
|
||||||
*/
|
*/
|
||||||
animationRunning: boolean = false;
|
private animationRunning: boolean = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is the wallet still busy? Note that we do not stop the
|
* Is the wallet still busy? Note that we do not stop the
|
||||||
* animation immediately when the wallet goes idle, but
|
* animation immediately when the wallet goes idle, but
|
||||||
* instead slowly close the gap.
|
* instead slowly close the gap.
|
||||||
*/
|
*/
|
||||||
isBusy: boolean = false;
|
private isBusy: boolean = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Current rotation angle, ranges from 0 to rotationAngleMax.
|
* Current rotation angle, ranges from 0 to rotationAngleMax.
|
||||||
*/
|
*/
|
||||||
rotationAngle: number = 0;
|
private rotationAngle: number = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* While animating, how wide is the current gap in the circle?
|
* While animating, how wide is the current gap in the circle?
|
||||||
* Ranges from 0 to openMax.
|
* Ranges from 0 to openMax.
|
||||||
*/
|
*/
|
||||||
gapWidth: number = 0;
|
private gapWidth: number = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maximum value for our rotationAngle, corresponds to 2 Pi.
|
* Maximum value for our rotationAngle, corresponds to 2 Pi.
|
||||||
@ -207,14 +211,6 @@ export class ChromeBadge implements Badge {
|
|||||||
rAF(step);
|
rAF(step);
|
||||||
}
|
}
|
||||||
|
|
||||||
setText(s: string) {
|
|
||||||
chrome.browserAction.setBadgeText({text: s});
|
|
||||||
}
|
|
||||||
|
|
||||||
setColor(c: string) {
|
|
||||||
chrome.browserAction.setBadgeBackgroundColor({color: c});
|
|
||||||
}
|
|
||||||
|
|
||||||
startBusy() {
|
startBusy() {
|
||||||
if (this.isBusy) {
|
if (this.isBusy) {
|
||||||
return;
|
return;
|
||||||
|
@ -37,7 +37,7 @@ export interface StateHolder<T> {
|
|||||||
* but has multiple state holders.
|
* but has multiple state holders.
|
||||||
*/
|
*/
|
||||||
export abstract class ImplicitStateComponent<PropType> extends React.Component<PropType, any> {
|
export abstract class ImplicitStateComponent<PropType> extends React.Component<PropType, any> {
|
||||||
_implicit = {needsUpdate: false, didMount: false};
|
private _implicit = {needsUpdate: false, didMount: false};
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this._implicit.didMount = true;
|
this._implicit.didMount = true;
|
||||||
if (this._implicit.needsUpdate) {
|
if (this._implicit.needsUpdate) {
|
||||||
|
@ -108,6 +108,10 @@ namespace RpcFunctions {
|
|||||||
return preCoin;
|
return preCoin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create and sign a message to request payback for a coin.
|
||||||
|
*/
|
||||||
export function createPaybackRequest(coin: CoinRecord): PaybackRequest {
|
export function createPaybackRequest(coin: CoinRecord): PaybackRequest {
|
||||||
const p = new native.PaybackRequestPS({
|
const p = new native.PaybackRequestPS({
|
||||||
coin_blind: native.RsaBlindingKeySecret.fromCrock(coin.blindingKey),
|
coin_blind: native.RsaBlindingKeySecret.fromCrock(coin.blindingKey),
|
||||||
@ -127,6 +131,9 @@ namespace RpcFunctions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a payment signature is valid.
|
||||||
|
*/
|
||||||
export function isValidPaymentSignature(sig: string, contractHash: string, merchantPub: string): boolean {
|
export function isValidPaymentSignature(sig: string, contractHash: string, merchantPub: string): boolean {
|
||||||
const p = new native.PaymentSignaturePS({
|
const p = new native.PaymentSignaturePS({
|
||||||
contract_hash: native.HashCode.fromCrock(contractHash),
|
contract_hash: native.HashCode.fromCrock(contractHash),
|
||||||
@ -140,6 +147,9 @@ namespace RpcFunctions {
|
|||||||
nativePub);
|
nativePub);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a wire fee is correctly signed.
|
||||||
|
*/
|
||||||
export function isValidWireFee(type: string, wf: WireFee, masterPub: string): boolean {
|
export function isValidWireFee(type: string, wf: WireFee, masterPub: string): boolean {
|
||||||
const p = new native.MasterWireFeePS({
|
const p = new native.MasterWireFeePS({
|
||||||
closing_fee: (new native.Amount(wf.closingFee)).toNbo(),
|
closing_fee: (new native.Amount(wf.closingFee)).toNbo(),
|
||||||
@ -160,6 +170,9 @@ namespace RpcFunctions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the signature of a denomination is valid.
|
||||||
|
*/
|
||||||
export function isValidDenom(denom: DenominationRecord,
|
export function isValidDenom(denom: DenominationRecord,
|
||||||
masterPub: string): boolean {
|
masterPub: string): boolean {
|
||||||
const p = new native.DenominationKeyValidityPS({
|
const p = new native.DenominationKeyValidityPS({
|
||||||
@ -189,6 +202,9 @@ namespace RpcFunctions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new EdDSA key pair.
|
||||||
|
*/
|
||||||
export function createEddsaKeypair(): {priv: string, pub: string} {
|
export function createEddsaKeypair(): {priv: string, pub: string} {
|
||||||
const priv = native.EddsaPrivateKey.create();
|
const priv = native.EddsaPrivateKey.create();
|
||||||
const pub = priv.getPublicKey();
|
const pub = priv.getPublicKey();
|
||||||
@ -196,6 +212,9 @@ namespace RpcFunctions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unblind a blindly signed value.
|
||||||
|
*/
|
||||||
export function rsaUnblind(sig: string, bk: string, pk: string): string {
|
export function rsaUnblind(sig: string, bk: string, pk: string): string {
|
||||||
const denomSig = native.rsaUnblind(native.RsaSignature.fromCrock(sig),
|
const denomSig = native.rsaUnblind(native.RsaSignature.fromCrock(sig),
|
||||||
native.RsaBlindingKeySecret.fromCrock(bk),
|
native.RsaBlindingKeySecret.fromCrock(bk),
|
||||||
@ -278,6 +297,9 @@ namespace RpcFunctions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new refresh session.
|
||||||
|
*/
|
||||||
export function createRefreshSession(exchangeBaseUrl: string,
|
export function createRefreshSession(exchangeBaseUrl: string,
|
||||||
kappa: number,
|
kappa: number,
|
||||||
meltCoin: CoinRecord,
|
meltCoin: CoinRecord,
|
||||||
@ -398,6 +420,9 @@ namespace RpcFunctions {
|
|||||||
return b.hash().toCrock();
|
return b.hash().toCrock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hash a denomination public key.
|
||||||
|
*/
|
||||||
export function hashDenomPub(denomPub: string): string {
|
export function hashDenomPub(denomPub: string): string {
|
||||||
return native.RsaPublicKey.fromCrock(denomPub).encode().hash().toCrock();
|
return native.RsaPublicKey.fromCrock(denomPub).encode().hash().toCrock();
|
||||||
}
|
}
|
||||||
|
@ -259,7 +259,7 @@ interface Arena {
|
|||||||
* Arena that must be manually destroyed.
|
* Arena that must be manually destroyed.
|
||||||
*/
|
*/
|
||||||
class SimpleArena implements Arena {
|
class SimpleArena implements Arena {
|
||||||
heap: ArenaObject[];
|
protected heap: ArenaObject[];
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.heap = [];
|
this.heap = [];
|
||||||
@ -774,7 +774,7 @@ export class EccSignaturePurpose extends PackedArenaObject {
|
|||||||
return this.payloadSize + 8;
|
return this.payloadSize + 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
payloadSize: number;
|
private payloadSize: number;
|
||||||
|
|
||||||
constructor(purpose: SignaturePurpose,
|
constructor(purpose: SignaturePurpose,
|
||||||
payload: PackedArenaObject,
|
payload: PackedArenaObject,
|
||||||
|
@ -22,10 +22,22 @@ const fork = require("child_process").fork;
|
|||||||
|
|
||||||
const nodeWorkerEntry = path.join(__dirname, "nodeWorkerEntry.js");
|
const nodeWorkerEntry = path.join(__dirname, "nodeWorkerEntry.js");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Worker implementation that uses node subprocesses.
|
||||||
|
*/
|
||||||
export class Worker {
|
export class Worker {
|
||||||
child: any;
|
private child: any;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function to be called when we receive a message from the worker thread.
|
||||||
|
*/
|
||||||
onmessage: undefined | ((m: any) => void);
|
onmessage: undefined | ((m: any) => void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function to be called when we receive an error from the worker thread.
|
||||||
|
*/
|
||||||
onerror: undefined | ((m: any) => void);
|
onerror: undefined | ((m: any) => void);
|
||||||
|
|
||||||
constructor(scriptFilename: string) {
|
constructor(scriptFilename: string) {
|
||||||
this.child = fork(nodeWorkerEntry);
|
this.child = fork(nodeWorkerEntry);
|
||||||
this.onerror = undefined;
|
this.onerror = undefined;
|
||||||
@ -55,6 +67,9 @@ export class Worker {
|
|||||||
this.child.send({scriptFilename, cwd: process.cwd()});
|
this.child.send({scriptFilename, cwd: process.cwd()});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an event listener for either an "error" or "message" event.
|
||||||
|
*/
|
||||||
addEventListener(event: "message" | "error", fn: (x: any) => void): void {
|
addEventListener(event: "message" | "error", fn: (x: any) => void): void {
|
||||||
switch (event) {
|
switch (event) {
|
||||||
case "message":
|
case "message":
|
||||||
@ -66,10 +81,16 @@ export class Worker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a message to the worker thread.
|
||||||
|
*/
|
||||||
postMessage (msg: any) {
|
postMessage (msg: any) {
|
||||||
this.child.send(JSON.stringify({data: msg}));
|
this.child.send(JSON.stringify({data: msg}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Forcibly terminate the worker thread.
|
||||||
|
*/
|
||||||
terminate () {
|
terminate () {
|
||||||
this.child.kill("SIGINT");
|
this.child.kill("SIGINT");
|
||||||
}
|
}
|
||||||
|
@ -83,6 +83,10 @@ export function canonicalJson(obj: any): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check for deep equality of two objects.
|
||||||
|
* Only arrays, objects and primitives are supported.
|
||||||
|
*/
|
||||||
export function deepEquals(x: any, y: any): boolean {
|
export function deepEquals(x: any, y: any): boolean {
|
||||||
if (x === y) {
|
if (x === y) {
|
||||||
return true;
|
return true;
|
||||||
@ -98,6 +102,10 @@ export function deepEquals(x: any, y: any): boolean {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map from a collection to a list or results and then
|
||||||
|
* concatenate the results.
|
||||||
|
*/
|
||||||
export function flatMap<T, U>(xs: T[], f: (x: T) => U[]): U[] {
|
export function flatMap<T, U>(xs: T[], f: (x: T) => U[]): U[] {
|
||||||
return xs.reduce((acc: U[], next: T) => [...f(next), ...acc], []);
|
return xs.reduce((acc: U[], next: T) => [...f(next), ...acc], []);
|
||||||
}
|
}
|
||||||
|
@ -15,9 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configurable logging.
|
* Configurable logging. Allows to log persistently to a database.
|
||||||
*
|
|
||||||
* @author Florian Dold
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@ -26,8 +24,14 @@ import {
|
|||||||
openPromise,
|
openPromise,
|
||||||
} from "./query";
|
} from "./query";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Supported log levels.
|
||||||
|
*/
|
||||||
export type Level = "error" | "debug" | "info" | "warn";
|
export type Level = "error" | "debug" | "info" | "warn";
|
||||||
|
|
||||||
|
// Right now, our debug/info/warn/debug loggers just use the console based
|
||||||
|
// loggers. This might change in the future.
|
||||||
|
|
||||||
function makeInfo() {
|
function makeInfo() {
|
||||||
return console.info.bind(console, "%o");
|
return console.info.bind(console, "%o");
|
||||||
}
|
}
|
||||||
@ -44,6 +48,9 @@ function makeDebug() {
|
|||||||
return console.log.bind(console, "%o");
|
return console.log.bind(console, "%o");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log a message using the configurable logger.
|
||||||
|
*/
|
||||||
export async function log(msg: string, level: Level = "info"): Promise<void> {
|
export async function log(msg: string, level: Level = "info"): Promise<void> {
|
||||||
const ci = getCallInfo(2);
|
const ci = getCallInfo(2);
|
||||||
return record(level, msg, undefined, ci.file, ci.line, ci.column);
|
return record(level, msg, undefined, ci.file, ci.line, ci.column);
|
||||||
@ -122,17 +129,50 @@ function parseStackLine(stackLine: string): Frame {
|
|||||||
|
|
||||||
let db: IDBDatabase|undefined;
|
let db: IDBDatabase|undefined;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A structured log entry as stored in the database.
|
||||||
|
*/
|
||||||
export interface LogEntry {
|
export interface LogEntry {
|
||||||
|
/**
|
||||||
|
* Soure code column where the error occured.
|
||||||
|
*/
|
||||||
col?: number;
|
col?: number;
|
||||||
|
/**
|
||||||
|
* Additional detail for the log statement.
|
||||||
|
*/
|
||||||
detail?: string;
|
detail?: string;
|
||||||
|
/**
|
||||||
|
* Id of the log entry, used as primary
|
||||||
|
* key for the database.
|
||||||
|
*/
|
||||||
id?: number;
|
id?: number;
|
||||||
|
/**
|
||||||
|
* Log level, see [[Level}}.
|
||||||
|
*/
|
||||||
level: string;
|
level: string;
|
||||||
|
/**
|
||||||
|
* Line where the log was created from.
|
||||||
|
*/
|
||||||
line?: number;
|
line?: number;
|
||||||
|
/**
|
||||||
|
* The actual log message.
|
||||||
|
*/
|
||||||
msg: string;
|
msg: string;
|
||||||
|
/**
|
||||||
|
* The source file where the log enctry
|
||||||
|
* was created from.
|
||||||
|
*/
|
||||||
source?: string;
|
source?: string;
|
||||||
|
/**
|
||||||
|
* Time when the log entry was created.
|
||||||
|
*/
|
||||||
timestamp: number;
|
timestamp: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all logs. Only use for debugging, since this returns all logs ever made
|
||||||
|
* at once without pagination.
|
||||||
|
*/
|
||||||
export async function getLogs(): Promise<LogEntry[]> {
|
export async function getLogs(): Promise<LogEntry[]> {
|
||||||
if (!db) {
|
if (!db) {
|
||||||
db = await openLoggingDb();
|
db = await openLoggingDb();
|
||||||
@ -147,6 +187,9 @@ export async function getLogs(): Promise<LogEntry[]> {
|
|||||||
*/
|
*/
|
||||||
let barrier: any;
|
let barrier: any;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Record an exeption in the log.
|
||||||
|
*/
|
||||||
export async function recordException(msg: string, e: any): Promise<void> {
|
export async function recordException(msg: string, e: any): Promise<void> {
|
||||||
let stack: string|undefined;
|
let stack: string|undefined;
|
||||||
let frame: Frame|undefined;
|
let frame: Frame|undefined;
|
||||||
@ -165,6 +208,9 @@ export async function recordException(msg: string, e: any): Promise<void> {
|
|||||||
return record("error", e.toString(), stack, frame.file, frame.line, frame.column);
|
return record("error", e.toString(), stack, frame.file, frame.line, frame.column);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Record a log entry in the database.
|
||||||
|
*/
|
||||||
export async function record(level: Level,
|
export async function record(level: Level,
|
||||||
msg: string,
|
msg: string,
|
||||||
detail?: string,
|
detail?: string,
|
||||||
@ -215,6 +261,10 @@ const loggingDbVersion = 1;
|
|||||||
|
|
||||||
const logsStore: Store<LogEntry> = new Store<LogEntry>("logs");
|
const logsStore: Store<LogEntry> = new Store<LogEntry>("logs");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a handle to the IndexedDB used to store
|
||||||
|
* logs.
|
||||||
|
*/
|
||||||
export function openLoggingDb(): Promise<IDBDatabase> {
|
export function openLoggingDb(): Promise<IDBDatabase> {
|
||||||
return new Promise<IDBDatabase>((resolve, reject) => {
|
return new Promise<IDBDatabase>((resolve, reject) => {
|
||||||
const req = indexedDB.open("taler-logging", loggingDbVersion);
|
const req = indexedDB.open("taler-logging", loggingDbVersion);
|
||||||
@ -238,7 +288,22 @@ export function openLoggingDb(): Promise<IDBDatabase> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log a message at severity info.
|
||||||
|
*/
|
||||||
export const info = makeInfo();
|
export const info = makeInfo();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log a message at severity debug.
|
||||||
|
*/
|
||||||
export const debug = makeDebug();
|
export const debug = makeDebug();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log a message at severity warn.
|
||||||
|
*/
|
||||||
export const warn = makeWarn();
|
export const warn = makeWarn();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log a message at severity error.
|
||||||
|
*/
|
||||||
export const error = makeError();
|
export const error = makeError();
|
||||||
|
95
src/query.ts
95
src/query.ts
@ -53,6 +53,9 @@ export class Store<T> {
|
|||||||
* Definition of an index.
|
* Definition of an index.
|
||||||
*/
|
*/
|
||||||
export class Index<S extends IDBValidKey, T> {
|
export class Index<S extends IDBValidKey, T> {
|
||||||
|
/**
|
||||||
|
* Name of the store that this index is associated with.
|
||||||
|
*/
|
||||||
storeName: string;
|
storeName: string;
|
||||||
|
|
||||||
constructor(s: Store<T>, public indexName: string, public keyPath: string | string[]) {
|
constructor(s: Store<T>, public indexName: string, public keyPath: string | string[]) {
|
||||||
@ -127,16 +130,26 @@ export interface QueryStream<T> {
|
|||||||
* Query result that consists of at most one value.
|
* Query result that consists of at most one value.
|
||||||
*/
|
*/
|
||||||
export interface QueryValue<T> {
|
export interface QueryValue<T> {
|
||||||
|
/**
|
||||||
|
* Apply a function to a query value.
|
||||||
|
*/
|
||||||
map<S>(f: (x: T) => S): QueryValue<S>;
|
map<S>(f: (x: T) => S): QueryValue<S>;
|
||||||
|
/**
|
||||||
|
* Conditionally execute either of two queries based
|
||||||
|
* on a property of this query value.
|
||||||
|
*
|
||||||
|
* Useful to properly implement complex queries within a transaction (as
|
||||||
|
* opposed to just computing the conditional and then executing either
|
||||||
|
* branch). This is necessary since IndexedDB does not allow long-lived
|
||||||
|
* transactions.
|
||||||
|
*/
|
||||||
cond<R>(f: (x: T) => boolean, onTrue: (r: QueryRoot) => R, onFalse: (r: QueryRoot) => R): Promise<void>;
|
cond<R>(f: (x: T) => boolean, onTrue: (r: QueryRoot) => R, onFalse: (r: QueryRoot) => R): Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
abstract class BaseQueryValue<T> implements QueryValue<T> {
|
abstract class BaseQueryValue<T> implements QueryValue<T> {
|
||||||
root: QueryRoot;
|
|
||||||
|
|
||||||
constructor(root: QueryRoot) {
|
constructor(public root: QueryRoot) {
|
||||||
this.root = root;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
map<S>(f: (x: T) => S): QueryValue<S> {
|
map<S>(f: (x: T) => S): QueryValue<S> {
|
||||||
@ -160,8 +173,9 @@ abstract class BaseQueryValue<T> implements QueryValue<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class FirstQueryValue<T> extends BaseQueryValue<T> {
|
class FirstQueryValue<T> extends BaseQueryValue<T> {
|
||||||
gotValue = false;
|
private gotValue = false;
|
||||||
s: QueryStreamBase<T>;
|
private s: QueryStreamBase<T>;
|
||||||
|
|
||||||
constructor(stream: QueryStreamBase<T>) {
|
constructor(stream: QueryStreamBase<T>) {
|
||||||
super(stream.root);
|
super(stream.root);
|
||||||
this.s = stream;
|
this.s = stream;
|
||||||
@ -183,13 +197,8 @@ class FirstQueryValue<T> extends BaseQueryValue<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class MapQueryValue<T, S> extends BaseQueryValue<S> {
|
class MapQueryValue<T, S> extends BaseQueryValue<S> {
|
||||||
mapFn: (x: T) => S;
|
constructor(private v: BaseQueryValue<T>, private mapFn: (x: T) => S) {
|
||||||
v: BaseQueryValue<T>;
|
|
||||||
|
|
||||||
constructor(v: BaseQueryValue<T>, mapFn: (x: T) => S) {
|
|
||||||
super(v.root);
|
super(v.root);
|
||||||
this.v = v;
|
|
||||||
this.mapFn = mapFn;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
subscribeOne(f: SubscribeOneFn): void {
|
subscribeOne(f: SubscribeOneFn): void {
|
||||||
@ -226,11 +235,7 @@ abstract class QueryStreamBase<T> implements QueryStream<T>, PromiseLike<void> {
|
|||||||
abstract subscribe(f: (isDone: boolean,
|
abstract subscribe(f: (isDone: boolean,
|
||||||
value: any,
|
value: any,
|
||||||
tx: IDBTransaction) => void): void;
|
tx: IDBTransaction) => void): void;
|
||||||
|
constructor(public root: QueryRoot) {
|
||||||
root: QueryRoot;
|
|
||||||
|
|
||||||
constructor(root: QueryRoot) {
|
|
||||||
this.root = root;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
first(): QueryValue<T> {
|
first(): QueryValue<T> {
|
||||||
@ -313,13 +318,8 @@ type SubscribeOneFn = (value: any, tx: IDBTransaction) => void;
|
|||||||
type FlatMapFn<T> = (v: T) => T[];
|
type FlatMapFn<T> = (v: T) => T[];
|
||||||
|
|
||||||
class QueryStreamFilter<T> extends QueryStreamBase<T> {
|
class QueryStreamFilter<T> extends QueryStreamBase<T> {
|
||||||
s: QueryStreamBase<T>;
|
constructor(public s: QueryStreamBase<T>, public filterFn: FilterFn) {
|
||||||
filterFn: FilterFn;
|
|
||||||
|
|
||||||
constructor(s: QueryStreamBase<T>, filterFn: FilterFn) {
|
|
||||||
super(s.root);
|
super(s.root);
|
||||||
this.s = s;
|
|
||||||
this.filterFn = filterFn;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
subscribe(f: SubscribeFn) {
|
subscribe(f: SubscribeFn) {
|
||||||
@ -337,13 +337,8 @@ class QueryStreamFilter<T> extends QueryStreamBase<T> {
|
|||||||
|
|
||||||
|
|
||||||
class QueryStreamFlatMap<T, S> extends QueryStreamBase<S> {
|
class QueryStreamFlatMap<T, S> extends QueryStreamBase<S> {
|
||||||
s: QueryStreamBase<T>;
|
constructor(public s: QueryStreamBase<T>, public flatMapFn: (v: T) => S[]) {
|
||||||
flatMapFn: (v: T) => S[];
|
|
||||||
|
|
||||||
constructor(s: QueryStreamBase<T>, flatMapFn: (v: T) => S[]) {
|
|
||||||
super(s.root);
|
super(s.root);
|
||||||
this.s = s;
|
|
||||||
this.flatMapFn = flatMapFn;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
subscribe(f: SubscribeFn) {
|
subscribe(f: SubscribeFn) {
|
||||||
@ -362,13 +357,8 @@ class QueryStreamFlatMap<T, S> extends QueryStreamBase<S> {
|
|||||||
|
|
||||||
|
|
||||||
class QueryStreamMap<S, T> extends QueryStreamBase<T> {
|
class QueryStreamMap<S, T> extends QueryStreamBase<T> {
|
||||||
s: QueryStreamBase<S>;
|
constructor(public s: QueryStreamBase<S>, public mapFn: (v: S) => T) {
|
||||||
mapFn: (v: S) => T;
|
|
||||||
|
|
||||||
constructor(s: QueryStreamBase<S>, mapFn: (v: S) => T) {
|
|
||||||
super(s.root);
|
super(s.root);
|
||||||
this.s = s;
|
|
||||||
this.mapFn = mapFn;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
subscribe(f: SubscribeFn) {
|
subscribe(f: SubscribeFn) {
|
||||||
@ -385,18 +375,9 @@ class QueryStreamMap<S, T> extends QueryStreamBase<T> {
|
|||||||
|
|
||||||
|
|
||||||
class QueryStreamIndexJoin<T, S> extends QueryStreamBase<JoinResult<T, S>> {
|
class QueryStreamIndexJoin<T, S> extends QueryStreamBase<JoinResult<T, S>> {
|
||||||
s: QueryStreamBase<T>;
|
constructor(public s: QueryStreamBase<T>, public storeName: string, public indexName: string,
|
||||||
storeName: string;
|
public key: any) {
|
||||||
key: any;
|
|
||||||
indexName: string;
|
|
||||||
|
|
||||||
constructor(s: QueryStreamBase<T>, storeName: string, indexName: string,
|
|
||||||
key: any) {
|
|
||||||
super(s.root);
|
super(s.root);
|
||||||
this.s = s;
|
|
||||||
this.storeName = storeName;
|
|
||||||
this.key = key;
|
|
||||||
this.indexName = indexName;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
subscribe(f: SubscribeFn) {
|
subscribe(f: SubscribeFn) {
|
||||||
@ -420,18 +401,9 @@ class QueryStreamIndexJoin<T, S> extends QueryStreamBase<JoinResult<T, S>> {
|
|||||||
|
|
||||||
|
|
||||||
class QueryStreamIndexJoinLeft<T, S> extends QueryStreamBase<JoinLeftResult<T, S>> {
|
class QueryStreamIndexJoinLeft<T, S> extends QueryStreamBase<JoinLeftResult<T, S>> {
|
||||||
s: QueryStreamBase<T>;
|
constructor(public s: QueryStreamBase<T>, public storeName: string, public indexName: string,
|
||||||
storeName: string;
|
public key: any) {
|
||||||
key: any;
|
|
||||||
indexName: string;
|
|
||||||
|
|
||||||
constructor(s: QueryStreamBase<T>, storeName: string, indexName: string,
|
|
||||||
key: any) {
|
|
||||||
super(s.root);
|
super(s.root);
|
||||||
this.s = s;
|
|
||||||
this.storeName = storeName;
|
|
||||||
this.key = key;
|
|
||||||
this.indexName = indexName;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
subscribe(f: SubscribeFn) {
|
subscribe(f: SubscribeFn) {
|
||||||
@ -461,16 +433,9 @@ class QueryStreamIndexJoinLeft<T, S> extends QueryStreamBase<JoinLeftResult<T, S
|
|||||||
|
|
||||||
|
|
||||||
class QueryStreamKeyJoin<T, S> extends QueryStreamBase<JoinResult<T, S>> {
|
class QueryStreamKeyJoin<T, S> extends QueryStreamBase<JoinResult<T, S>> {
|
||||||
s: QueryStreamBase<T>;
|
constructor(public s: QueryStreamBase<T>, public storeName: string,
|
||||||
storeName: string;
|
public key: any) {
|
||||||
key: any;
|
|
||||||
|
|
||||||
constructor(s: QueryStreamBase<T>, storeName: string,
|
|
||||||
key: any) {
|
|
||||||
super(s.root);
|
super(s.root);
|
||||||
this.s = s;
|
|
||||||
this.storeName = storeName;
|
|
||||||
this.key = key;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
subscribe(f: SubscribeFn) {
|
subscribe(f: SubscribeFn) {
|
||||||
|
527
src/types.ts
527
src/types.ts
@ -28,32 +28,77 @@
|
|||||||
*/
|
*/
|
||||||
import { Checkable } from "./checkable";
|
import { Checkable } from "./checkable";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Non-negative financial amount. Fractional values are expressed as multiples
|
||||||
|
* of 1e-8.
|
||||||
|
*/
|
||||||
@Checkable.Class()
|
@Checkable.Class()
|
||||||
export class AmountJson {
|
export class AmountJson {
|
||||||
|
/**
|
||||||
|
* Value, must be an integer.
|
||||||
|
*/
|
||||||
@Checkable.Number
|
@Checkable.Number
|
||||||
value: number;
|
readonly value: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fraction, must be an integer. Represent 1/1e8 of a unit.
|
||||||
|
*/
|
||||||
@Checkable.Number
|
@Checkable.Number
|
||||||
fraction: number;
|
readonly fraction: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Currency of the amount.
|
||||||
|
*/
|
||||||
@Checkable.String
|
@Checkable.String
|
||||||
currency: string;
|
readonly currency: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify that a value matches the schema of this class and convert it into a
|
||||||
|
* member.
|
||||||
|
*/
|
||||||
static checked: (obj: any) => AmountJson;
|
static checked: (obj: any) => AmountJson;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Amount with a sign.
|
||||||
|
*/
|
||||||
export interface SignedAmountJson {
|
export interface SignedAmountJson {
|
||||||
|
/**
|
||||||
|
* The absolute amount.
|
||||||
|
*/
|
||||||
amount: AmountJson;
|
amount: AmountJson;
|
||||||
|
/**
|
||||||
|
* Sign.
|
||||||
|
*/
|
||||||
isNegative: boolean;
|
isNegative: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A reserve record as stored in the wallet's database.
|
||||||
|
*/
|
||||||
export interface ReserveRecord {
|
export interface ReserveRecord {
|
||||||
|
/**
|
||||||
|
* The reserve public key.
|
||||||
|
*/
|
||||||
reserve_pub: string;
|
reserve_pub: string;
|
||||||
|
/**
|
||||||
|
* The reserve private key.
|
||||||
|
*/
|
||||||
reserve_priv: string;
|
reserve_priv: string;
|
||||||
|
/**
|
||||||
|
* The exchange base URL.
|
||||||
|
*/
|
||||||
exchange_base_url: string;
|
exchange_base_url: string;
|
||||||
|
/**
|
||||||
|
* Time when the reserve was created.
|
||||||
|
*/
|
||||||
created: number;
|
created: number;
|
||||||
|
/**
|
||||||
|
* Time when the reserve was last queried,
|
||||||
|
* or 'null' if it was never queried.
|
||||||
|
*/
|
||||||
last_query: number | null;
|
last_query: number | null;
|
||||||
/**
|
/**
|
||||||
* Current amount left in the reserve
|
* Current amount left in the reserve
|
||||||
@ -65,17 +110,16 @@ export interface ReserveRecord {
|
|||||||
* be higher than the requested_amount
|
* be higher than the requested_amount
|
||||||
*/
|
*/
|
||||||
requested_amount: AmountJson;
|
requested_amount: AmountJson;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* What's the current amount that sits
|
* What's the current amount that sits
|
||||||
* in precoins?
|
* in precoins?
|
||||||
*/
|
*/
|
||||||
precoin_amount: AmountJson;
|
precoin_amount: AmountJson;
|
||||||
|
/**
|
||||||
|
* The bank conformed that the reserve will eventually
|
||||||
|
* be filled with money.
|
||||||
|
*/
|
||||||
confirmed: boolean;
|
confirmed: boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* We got some payback to this reserve. We'll cease to automatically
|
* We got some payback to this reserve. We'll cease to automatically
|
||||||
* withdraw money from it.
|
* withdraw money from it.
|
||||||
@ -106,6 +150,9 @@ export interface CurrencyRecord {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Response for the create reserve request to the wallet.
|
||||||
|
*/
|
||||||
@Checkable.Class()
|
@Checkable.Class()
|
||||||
export class CreateReserveResponse {
|
export class CreateReserveResponse {
|
||||||
/**
|
/**
|
||||||
@ -115,52 +162,114 @@ export class CreateReserveResponse {
|
|||||||
@Checkable.String
|
@Checkable.String
|
||||||
exchange: string;
|
exchange: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reserve public key of the newly created reserve.
|
||||||
|
*/
|
||||||
@Checkable.String
|
@Checkable.String
|
||||||
reservePub: string;
|
reservePub: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify that a value matches the schema of this class and convert it into a
|
||||||
|
* member.
|
||||||
|
*/
|
||||||
static checked: (obj: any) => CreateReserveResponse;
|
static checked: (obj: any) => CreateReserveResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Status of a denomination.
|
||||||
|
*/
|
||||||
export enum DenominationStatus {
|
export enum DenominationStatus {
|
||||||
|
/**
|
||||||
|
* Verification was delayed.
|
||||||
|
*/
|
||||||
Unverified,
|
Unverified,
|
||||||
|
/**
|
||||||
|
* Verified as valid.
|
||||||
|
*/
|
||||||
VerifiedGood,
|
VerifiedGood,
|
||||||
|
/**
|
||||||
|
* Verified as invalid.
|
||||||
|
*/
|
||||||
VerifiedBad,
|
VerifiedBad,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Denomination record as stored in the wallet's database.
|
||||||
|
*/
|
||||||
|
@Checkable.Class()
|
||||||
export class DenominationRecord {
|
export class DenominationRecord {
|
||||||
|
/**
|
||||||
|
* Value of one coin of the denomination.
|
||||||
|
*/
|
||||||
@Checkable.Value(AmountJson)
|
@Checkable.Value(AmountJson)
|
||||||
value: AmountJson;
|
value: AmountJson;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The denomination public key.
|
||||||
|
*/
|
||||||
@Checkable.String
|
@Checkable.String
|
||||||
denomPub: string;
|
denomPub: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hash of the denomination public key.
|
||||||
|
* Stored in the database for faster lookups.
|
||||||
|
*/
|
||||||
@Checkable.String
|
@Checkable.String
|
||||||
denomPubHash: string;
|
denomPubHash: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fee for withdrawing.
|
||||||
|
*/
|
||||||
@Checkable.Value(AmountJson)
|
@Checkable.Value(AmountJson)
|
||||||
feeWithdraw: AmountJson;
|
feeWithdraw: AmountJson;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fee for depositing.
|
||||||
|
*/
|
||||||
@Checkable.Value(AmountJson)
|
@Checkable.Value(AmountJson)
|
||||||
feeDeposit: AmountJson;
|
feeDeposit: AmountJson;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fee for refreshing.
|
||||||
|
*/
|
||||||
@Checkable.Value(AmountJson)
|
@Checkable.Value(AmountJson)
|
||||||
feeRefresh: AmountJson;
|
feeRefresh: AmountJson;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fee for refunding.
|
||||||
|
*/
|
||||||
@Checkable.Value(AmountJson)
|
@Checkable.Value(AmountJson)
|
||||||
feeRefund: AmountJson;
|
feeRefund: AmountJson;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validity start date of the denomination.
|
||||||
|
*/
|
||||||
@Checkable.String
|
@Checkable.String
|
||||||
stampStart: string;
|
stampStart: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date after which the currency can't be withdrawn anymore.
|
||||||
|
*/
|
||||||
@Checkable.String
|
@Checkable.String
|
||||||
stampExpireWithdraw: string;
|
stampExpireWithdraw: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date after the denomination officially doesn't exist anymore.
|
||||||
|
*/
|
||||||
@Checkable.String
|
@Checkable.String
|
||||||
stampExpireLegal: string;
|
stampExpireLegal: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data after which coins of this denomination can't be deposited anymore.
|
||||||
|
*/
|
||||||
@Checkable.String
|
@Checkable.String
|
||||||
stampExpireDeposit: string;
|
stampExpireDeposit: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signature by the exchange's master key over the denomination
|
||||||
|
* information.
|
||||||
|
*/
|
||||||
@Checkable.String
|
@Checkable.String
|
||||||
masterSig: string;
|
masterSig: string;
|
||||||
|
|
||||||
@ -178,9 +287,16 @@ export class DenominationRecord {
|
|||||||
@Checkable.Boolean
|
@Checkable.Boolean
|
||||||
isOffered: boolean;
|
isOffered: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base URL of the exchange.
|
||||||
|
*/
|
||||||
@Checkable.String
|
@Checkable.String
|
||||||
exchangeBaseUrl: string;
|
exchangeBaseUrl: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify that a value matches the schema of this class and convert it into a
|
||||||
|
* member.
|
||||||
|
*/
|
||||||
static checked: (obj: any) => Denomination;
|
static checked: (obj: any) => Denomination;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,59 +305,124 @@ export class DenominationRecord {
|
|||||||
*/
|
*/
|
||||||
@Checkable.Class()
|
@Checkable.Class()
|
||||||
export class Denomination {
|
export class Denomination {
|
||||||
|
/**
|
||||||
|
* Value of one coin of the denomination.
|
||||||
|
*/
|
||||||
@Checkable.Value(AmountJson)
|
@Checkable.Value(AmountJson)
|
||||||
value: AmountJson;
|
value: AmountJson;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Public signing key of the denomination.
|
||||||
|
*/
|
||||||
@Checkable.String
|
@Checkable.String
|
||||||
denom_pub: string;
|
denom_pub: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fee for withdrawing.
|
||||||
|
*/
|
||||||
@Checkable.Value(AmountJson)
|
@Checkable.Value(AmountJson)
|
||||||
fee_withdraw: AmountJson;
|
fee_withdraw: AmountJson;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fee for depositing.
|
||||||
|
*/
|
||||||
@Checkable.Value(AmountJson)
|
@Checkable.Value(AmountJson)
|
||||||
fee_deposit: AmountJson;
|
fee_deposit: AmountJson;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fee for refreshing.
|
||||||
|
*/
|
||||||
@Checkable.Value(AmountJson)
|
@Checkable.Value(AmountJson)
|
||||||
fee_refresh: AmountJson;
|
fee_refresh: AmountJson;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fee for refunding.
|
||||||
|
*/
|
||||||
@Checkable.Value(AmountJson)
|
@Checkable.Value(AmountJson)
|
||||||
fee_refund: AmountJson;
|
fee_refund: AmountJson;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start date from which withdraw is allowed.
|
||||||
|
*/
|
||||||
@Checkable.String
|
@Checkable.String
|
||||||
stamp_start: string;
|
stamp_start: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* End date for withdrawing.
|
||||||
|
*/
|
||||||
@Checkable.String
|
@Checkable.String
|
||||||
stamp_expire_withdraw: string;
|
stamp_expire_withdraw: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expiration date after which the exchange can forget about
|
||||||
|
* the currency.
|
||||||
|
*/
|
||||||
@Checkable.String
|
@Checkable.String
|
||||||
stamp_expire_legal: string;
|
stamp_expire_legal: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date after which the coins of this denomination can't be
|
||||||
|
* deposited anymore.
|
||||||
|
*/
|
||||||
@Checkable.String
|
@Checkable.String
|
||||||
stamp_expire_deposit: string;
|
stamp_expire_deposit: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signature over the denomination information by the exchange's master
|
||||||
|
* signing key.
|
||||||
|
*/
|
||||||
@Checkable.String
|
@Checkable.String
|
||||||
master_sig: string;
|
master_sig: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify that a value matches the schema of this class and convert it into a
|
||||||
|
* member.
|
||||||
|
*/
|
||||||
static checked: (obj: any) => Denomination;
|
static checked: (obj: any) => Denomination;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auditor information.
|
||||||
|
*/
|
||||||
export interface Auditor {
|
export interface Auditor {
|
||||||
// official name
|
/**
|
||||||
|
* Official name.
|
||||||
|
*/
|
||||||
name: string;
|
name: string;
|
||||||
|
|
||||||
// Auditor's public key
|
/**
|
||||||
|
* Auditor's public key.
|
||||||
|
*/
|
||||||
auditor_pub: string;
|
auditor_pub: string;
|
||||||
|
|
||||||
// Base URL of the auditor
|
/**
|
||||||
|
* Base URL of the auditor.
|
||||||
|
*/
|
||||||
url: string;
|
url: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exchange record as stored in the wallet's database.
|
||||||
|
*/
|
||||||
export interface ExchangeRecord {
|
export interface ExchangeRecord {
|
||||||
|
/**
|
||||||
|
* Base url of the exchange.
|
||||||
|
*/
|
||||||
baseUrl: string;
|
baseUrl: string;
|
||||||
|
/**
|
||||||
|
* Master public key of the exchange.
|
||||||
|
*/
|
||||||
masterPublicKey: string;
|
masterPublicKey: string;
|
||||||
|
/**
|
||||||
|
* Auditors (partially) auditing the exchange.
|
||||||
|
*/
|
||||||
auditors: Auditor[];
|
auditors: Auditor[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Currency that the exchange offers.
|
||||||
|
*/
|
||||||
currency: string;
|
currency: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -282,14 +463,36 @@ export interface PreCoinRecord {
|
|||||||
coinValue: AmountJson;
|
coinValue: AmountJson;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Planchet for a coin during refrehs.
|
||||||
|
*/
|
||||||
export interface RefreshPreCoinRecord {
|
export interface RefreshPreCoinRecord {
|
||||||
|
/**
|
||||||
|
* Public key for the coin.
|
||||||
|
*/
|
||||||
publicKey: string;
|
publicKey: string;
|
||||||
|
/**
|
||||||
|
* Private key for the coin.
|
||||||
|
*/
|
||||||
privateKey: string;
|
privateKey: string;
|
||||||
|
/**
|
||||||
|
* Blinded public key.
|
||||||
|
*/
|
||||||
coinEv: string;
|
coinEv: string;
|
||||||
|
/**
|
||||||
|
* Blinding key used.
|
||||||
|
*/
|
||||||
blindingKey: string;
|
blindingKey: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request that we send to the exchange to get a payback.
|
||||||
|
*/
|
||||||
export interface PaybackRequest {
|
export interface PaybackRequest {
|
||||||
|
/**
|
||||||
|
* Denomination public key of the coin we want to get
|
||||||
|
* paid back.
|
||||||
|
*/
|
||||||
denom_pub: string;
|
denom_pub: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -297,13 +500,26 @@ export interface PaybackRequest {
|
|||||||
*/
|
*/
|
||||||
denom_sig: string;
|
denom_sig: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Coin public key of the coin we want to refund.
|
||||||
|
*/
|
||||||
coin_pub: string;
|
coin_pub: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Blinding key that was used during withdraw,
|
||||||
|
* used to prove that we were actually withdrawing the coin.
|
||||||
|
*/
|
||||||
coin_blind_key_secret: string;
|
coin_blind_key_secret: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signature made by the coin, authorizing the payback.
|
||||||
|
*/
|
||||||
coin_sig: string;
|
coin_sig: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Response that we get from the exchange for a payback request.
|
||||||
|
*/
|
||||||
@Checkable.Class()
|
@Checkable.Class()
|
||||||
export class PaybackConfirmation {
|
export class PaybackConfirmation {
|
||||||
/**
|
/**
|
||||||
@ -344,6 +560,10 @@ export class PaybackConfirmation {
|
|||||||
@Checkable.String
|
@Checkable.String
|
||||||
exchange_pub: string;
|
exchange_pub: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify that a value matches the schema of this class and convert it into a
|
||||||
|
* member.
|
||||||
|
*/
|
||||||
static checked: (obj: any) => PaybackConfirmation;
|
static checked: (obj: any) => PaybackConfirmation;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -378,15 +598,19 @@ export interface RefreshSessionRecord {
|
|||||||
*/
|
*/
|
||||||
newDenoms: string[];
|
newDenoms: string[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Precoins for each cut-and-choose instance.
|
||||||
|
*/
|
||||||
preCoinsForGammas: RefreshPreCoinRecord[][];
|
preCoinsForGammas: RefreshPreCoinRecord[][];
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The transfer keys, kappa of them.
|
* The transfer keys, kappa of them.
|
||||||
*/
|
*/
|
||||||
transferPubs: string[];
|
transferPubs: string[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private keys for the transfer public keys.
|
||||||
|
*/
|
||||||
transferPrivs: string[];
|
transferPrivs: string[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -399,23 +623,73 @@ export interface RefreshSessionRecord {
|
|||||||
*/
|
*/
|
||||||
hash: string;
|
hash: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base URL for the exchange we're doing the refresh with.
|
||||||
|
*/
|
||||||
exchangeBaseUrl: string;
|
exchangeBaseUrl: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this session finished?
|
||||||
|
*/
|
||||||
finished: boolean;
|
finished: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deposit permission for a single coin.
|
||||||
|
*/
|
||||||
export interface CoinPaySig {
|
export interface CoinPaySig {
|
||||||
|
/**
|
||||||
|
* Signature by the coin.
|
||||||
|
*/
|
||||||
coin_sig: string;
|
coin_sig: string;
|
||||||
|
/**
|
||||||
|
* Public key of the coin being spend.
|
||||||
|
*/
|
||||||
coin_pub: string;
|
coin_pub: string;
|
||||||
|
/**
|
||||||
|
* Signature made by the denomination public key.
|
||||||
|
*/
|
||||||
ub_sig: string;
|
ub_sig: string;
|
||||||
|
/**
|
||||||
|
* The denomination public key associated with this coin.
|
||||||
|
*/
|
||||||
denom_pub: string;
|
denom_pub: string;
|
||||||
|
/**
|
||||||
|
* The amount that is subtracted from this coin with this payment.
|
||||||
|
*/
|
||||||
f: AmountJson;
|
f: AmountJson;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Status of a coin.
|
||||||
|
*/
|
||||||
export enum CoinStatus {
|
export enum CoinStatus {
|
||||||
Fresh, TransactionPending, Dirty, Refreshed, PaybackPending, PaybackDone,
|
/**
|
||||||
|
* Withdrawn and never shown to anybody.
|
||||||
|
*/
|
||||||
|
Fresh,
|
||||||
|
/**
|
||||||
|
* Currently planned to be sent to a merchant for a transaction.
|
||||||
|
*/
|
||||||
|
TransactionPending,
|
||||||
|
/**
|
||||||
|
* Used for a completed transaction and now dirty.
|
||||||
|
*/
|
||||||
|
Dirty,
|
||||||
|
/**
|
||||||
|
* A coin that was refreshed.
|
||||||
|
*/
|
||||||
|
Refreshed,
|
||||||
|
/**
|
||||||
|
* Coin marked to be paid back, but payback not finished.
|
||||||
|
*/
|
||||||
|
PaybackPending,
|
||||||
|
/**
|
||||||
|
* Coin fully paid back.
|
||||||
|
*/
|
||||||
|
PaybackDone,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -462,6 +736,10 @@ export interface CoinRecord {
|
|||||||
*/
|
*/
|
||||||
suspended?: boolean;
|
suspended?: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Blinding key used when withdrawing the coin.
|
||||||
|
* Potentionally sed again during payback.
|
||||||
|
*/
|
||||||
blindingKey: string;
|
blindingKey: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -477,29 +755,70 @@ export interface CoinRecord {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Information about an exchange as stored inside a
|
||||||
|
* merchant's contract terms.
|
||||||
|
*/
|
||||||
@Checkable.Class()
|
@Checkable.Class()
|
||||||
export class ExchangeHandle {
|
export class ExchangeHandle {
|
||||||
|
/**
|
||||||
|
* Master public signing key of the exchange.
|
||||||
|
*/
|
||||||
@Checkable.String
|
@Checkable.String
|
||||||
master_pub: string;
|
master_pub: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base URL of the exchange.
|
||||||
|
*/
|
||||||
@Checkable.String
|
@Checkable.String
|
||||||
url: string;
|
url: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify that a value matches the schema of this class and convert it into a
|
||||||
|
* member.
|
||||||
|
*/
|
||||||
static checked: (obj: any) => ExchangeHandle;
|
static checked: (obj: any) => ExchangeHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface WalletBalance {
|
|
||||||
[currency: string]: WalletBalanceEntry;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mapping from currency names to detailed balance
|
||||||
|
* information for that particular currency.
|
||||||
|
*/
|
||||||
|
export interface WalletBalance {
|
||||||
|
/**
|
||||||
|
* Mapping from currency name to defailed balance info.
|
||||||
|
*/
|
||||||
|
[currency: string]: WalletBalanceEntry;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detailed wallet balance for a particular currency.
|
||||||
|
*/
|
||||||
export interface WalletBalanceEntry {
|
export interface WalletBalanceEntry {
|
||||||
|
/**
|
||||||
|
* Directly available amount.
|
||||||
|
*/
|
||||||
available: AmountJson;
|
available: AmountJson;
|
||||||
|
/**
|
||||||
|
* Amount that we're waiting for (refresh, withdrawal).
|
||||||
|
*/
|
||||||
pendingIncoming: AmountJson;
|
pendingIncoming: AmountJson;
|
||||||
|
/**
|
||||||
|
* Amount that's marked for a pending payment.
|
||||||
|
*/
|
||||||
pendingPayment: AmountJson;
|
pendingPayment: AmountJson;
|
||||||
|
/**
|
||||||
|
* Amount that was paid back and we could withdraw again.
|
||||||
|
*/
|
||||||
paybackAmount: AmountJson;
|
paybackAmount: AmountJson;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Information about a merchant.
|
||||||
|
*/
|
||||||
interface Merchant {
|
interface Merchant {
|
||||||
/**
|
/**
|
||||||
* label for a location with the business address of the merchant
|
* label for a location with the business address of the merchant
|
||||||
@ -524,108 +843,235 @@ interface Merchant {
|
|||||||
instance?: string;
|
instance?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contract terms from a merchant.
|
||||||
|
*/
|
||||||
@Checkable.Class({validate: true})
|
@Checkable.Class({validate: true})
|
||||||
export class Contract {
|
export class Contract {
|
||||||
|
private validate() {
|
||||||
validate() {
|
|
||||||
if (this.exchanges.length === 0) {
|
if (this.exchanges.length === 0) {
|
||||||
throw Error("no exchanges in contract");
|
throw Error("no exchanges in contract");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hash of the merchant's wire details.
|
||||||
|
*/
|
||||||
@Checkable.String
|
@Checkable.String
|
||||||
H_wire: string;
|
H_wire: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wire method the merchant wants to use.
|
||||||
|
*/
|
||||||
@Checkable.String
|
@Checkable.String
|
||||||
wire_method: string;
|
wire_method: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Human-readable short summary of the contract.
|
||||||
|
*/
|
||||||
@Checkable.Optional(Checkable.String)
|
@Checkable.Optional(Checkable.String)
|
||||||
summary?: string;
|
summary?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nonce used to ensure freshness.
|
||||||
|
*/
|
||||||
@Checkable.Optional(Checkable.String)
|
@Checkable.Optional(Checkable.String)
|
||||||
nonce?: string;
|
nonce?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Total amount payable.
|
||||||
|
*/
|
||||||
@Checkable.Value(AmountJson)
|
@Checkable.Value(AmountJson)
|
||||||
amount: AmountJson;
|
amount: AmountJson;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auditors accepted by the merchant.
|
||||||
|
*/
|
||||||
@Checkable.List(Checkable.AnyObject)
|
@Checkable.List(Checkable.AnyObject)
|
||||||
auditors: any[];
|
auditors: any[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deadline to pay for the contract.
|
||||||
|
*/
|
||||||
@Checkable.Optional(Checkable.String)
|
@Checkable.Optional(Checkable.String)
|
||||||
pay_deadline: string;
|
pay_deadline: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delivery locations.
|
||||||
|
*/
|
||||||
@Checkable.Any
|
@Checkable.Any
|
||||||
locations: any;
|
locations: any;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maximum deposit fee covered by the merchant.
|
||||||
|
*/
|
||||||
@Checkable.Value(AmountJson)
|
@Checkable.Value(AmountJson)
|
||||||
max_fee: AmountJson;
|
max_fee: AmountJson;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Information about the merchant.
|
||||||
|
*/
|
||||||
@Checkable.Any
|
@Checkable.Any
|
||||||
merchant: any;
|
merchant: any;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Public key of the merchant.
|
||||||
|
*/
|
||||||
@Checkable.String
|
@Checkable.String
|
||||||
merchant_pub: string;
|
merchant_pub: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of accepted exchanges.
|
||||||
|
*/
|
||||||
@Checkable.List(Checkable.Value(ExchangeHandle))
|
@Checkable.List(Checkable.Value(ExchangeHandle))
|
||||||
exchanges: ExchangeHandle[];
|
exchanges: ExchangeHandle[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Products that are sold in this contract.
|
||||||
|
*/
|
||||||
@Checkable.List(Checkable.AnyObject)
|
@Checkable.List(Checkable.AnyObject)
|
||||||
products: any[];
|
products: any[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deadline for refunds.
|
||||||
|
*/
|
||||||
@Checkable.String
|
@Checkable.String
|
||||||
refund_deadline: string;
|
refund_deadline: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Time when the contract was generated by the merchant.
|
||||||
|
*/
|
||||||
@Checkable.String
|
@Checkable.String
|
||||||
timestamp: string;
|
timestamp: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Order id to uniquely identify the purchase within
|
||||||
|
* one merchant instance.
|
||||||
|
*/
|
||||||
@Checkable.String
|
@Checkable.String
|
||||||
order_id: string;
|
order_id: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* URL to post the payment to.
|
||||||
|
*/
|
||||||
@Checkable.String
|
@Checkable.String
|
||||||
pay_url: string;
|
pay_url: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fulfillment URL to view the product or
|
||||||
|
* delivery status.
|
||||||
|
*/
|
||||||
@Checkable.String
|
@Checkable.String
|
||||||
fulfillment_url: string;
|
fulfillment_url: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Share of the wire fee that must be settled with one payment.
|
||||||
|
*/
|
||||||
@Checkable.Optional(Checkable.Number)
|
@Checkable.Optional(Checkable.Number)
|
||||||
wire_fee_amortization?: number;
|
wire_fee_amortization?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maximum wire fee that the merchant agrees to pay for.
|
||||||
|
*/
|
||||||
@Checkable.Optional(Checkable.Value(AmountJson))
|
@Checkable.Optional(Checkable.Value(AmountJson))
|
||||||
max_wire_fee?: AmountJson;
|
max_wire_fee?: AmountJson;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extra data, interpreted by the mechant only.
|
||||||
|
*/
|
||||||
@Checkable.Any
|
@Checkable.Any
|
||||||
extra: any;
|
extra: any;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify that a value matches the schema of this class and convert it into a
|
||||||
|
* member.
|
||||||
|
*/
|
||||||
static checked: (obj: any) => Contract;
|
static checked: (obj: any) => Contract;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wire fee for one wire method as stored in the
|
||||||
|
* wallet's database.
|
||||||
|
*/
|
||||||
export interface WireFee {
|
export interface WireFee {
|
||||||
|
/**
|
||||||
|
* Fee for wire transfers.
|
||||||
|
*/
|
||||||
wireFee: AmountJson;
|
wireFee: AmountJson;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fees to close and refund a reserve.
|
||||||
|
*/
|
||||||
closingFee: AmountJson;
|
closingFee: AmountJson;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start date of the fee.
|
||||||
|
*/
|
||||||
startStamp: number;
|
startStamp: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* End date of the fee.
|
||||||
|
*/
|
||||||
endStamp: number;
|
endStamp: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signature made by the exchange master key.
|
||||||
|
*/
|
||||||
sig: string;
|
sig: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wire fees for an exchange.
|
||||||
|
*/
|
||||||
export interface ExchangeWireFeesRecord {
|
export interface ExchangeWireFeesRecord {
|
||||||
|
/**
|
||||||
|
* Base URL of the exchange.
|
||||||
|
*/
|
||||||
exchangeBaseUrl: string;
|
exchangeBaseUrl: string;
|
||||||
feesForType: { [type: string]: WireFee[] };
|
|
||||||
|
/**
|
||||||
|
* Mapping from wire method type to the wire fee.
|
||||||
|
*/
|
||||||
|
feesForType: { [wireMethod: string]: WireFee[] };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Coins used for a payment, with signatures authorizing the payment and the
|
||||||
|
* coins with remaining value updated to accomodate for a payment.
|
||||||
|
*/
|
||||||
export type PayCoinInfo = Array<{ updatedCoin: CoinRecord, sig: CoinPaySig }>;
|
export type PayCoinInfo = Array<{ updatedCoin: CoinRecord, sig: CoinPaySig }>;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Amount helpers.
|
||||||
|
*/
|
||||||
export namespace Amounts {
|
export namespace Amounts {
|
||||||
|
/**
|
||||||
|
* Number of fractional units that one value unit represents.
|
||||||
|
*/
|
||||||
export const fractionalBase = 1e8;
|
export const fractionalBase = 1e8;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Result of a possibly overflowing operation.
|
||||||
|
*/
|
||||||
export interface Result {
|
export interface Result {
|
||||||
|
/**
|
||||||
|
* Resulting, possibly saturated amount.
|
||||||
|
*/
|
||||||
amount: AmountJson;
|
amount: AmountJson;
|
||||||
// Was there an over-/underflow?
|
/**
|
||||||
|
* Was there an over-/underflow?
|
||||||
|
*/
|
||||||
saturated: boolean;
|
saturated: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the largest amount that is safely representable.
|
||||||
|
*/
|
||||||
export function getMaxAmount(currency: string): AmountJson {
|
export function getMaxAmount(currency: string): AmountJson {
|
||||||
return {
|
return {
|
||||||
currency,
|
currency,
|
||||||
@ -634,6 +1080,9 @@ export namespace Amounts {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an amount that represents zero units of a currency.
|
||||||
|
*/
|
||||||
export function getZero(currency: string): AmountJson {
|
export function getZero(currency: string): AmountJson {
|
||||||
return {
|
return {
|
||||||
currency,
|
currency,
|
||||||
@ -642,6 +1091,13 @@ export namespace Amounts {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add two amounts. Return the result and whether
|
||||||
|
* the addition overflowed. The overflow is always handled
|
||||||
|
* by saturating and never by wrapping.
|
||||||
|
*
|
||||||
|
* Throws when currencies don't match.
|
||||||
|
*/
|
||||||
export function add(first: AmountJson, ...rest: AmountJson[]): Result {
|
export function add(first: AmountJson, ...rest: AmountJson[]): Result {
|
||||||
const currency = first.currency;
|
const currency = first.currency;
|
||||||
let value = first.value + Math.floor(first.fraction / fractionalBase);
|
let value = first.value + Math.floor(first.fraction / fractionalBase);
|
||||||
@ -663,7 +1119,13 @@ export namespace Amounts {
|
|||||||
return { amount: { currency, value, fraction }, saturated: false };
|
return { amount: { currency, value, fraction }, saturated: false };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subtract two amounts. Return the result and whether
|
||||||
|
* the subtraction overflowed. The overflow is always handled
|
||||||
|
* by saturating and never by wrapping.
|
||||||
|
*
|
||||||
|
* Throws when currencies don't match.
|
||||||
|
*/
|
||||||
export function sub(a: AmountJson, ...rest: AmountJson[]): Result {
|
export function sub(a: AmountJson, ...rest: AmountJson[]): Result {
|
||||||
const currency = a.currency;
|
const currency = a.currency;
|
||||||
let value = a.value;
|
let value = a.value;
|
||||||
@ -691,6 +1153,10 @@ export namespace Amounts {
|
|||||||
return { amount: { currency, value, fraction }, saturated: false };
|
return { amount: { currency, value, fraction }, saturated: false };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compare two amounts. Returns 0 when equal, -1 when a < b
|
||||||
|
* and +1 when a > b. Throws when currencies don't match.
|
||||||
|
*/
|
||||||
export function cmp(a: AmountJson, b: AmountJson): number {
|
export function cmp(a: AmountJson, b: AmountJson): number {
|
||||||
if (a.currency !== b.currency) {
|
if (a.currency !== b.currency) {
|
||||||
throw Error(`Mismatched currency: ${a.currency} and ${b.currency}`);
|
throw Error(`Mismatched currency: ${a.currency} and ${b.currency}`);
|
||||||
@ -715,6 +1181,9 @@ export namespace Amounts {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a copy of an amount.
|
||||||
|
*/
|
||||||
export function copy(a: AmountJson): AmountJson {
|
export function copy(a: AmountJson): AmountJson {
|
||||||
return {
|
return {
|
||||||
currency: a.currency,
|
currency: a.currency,
|
||||||
@ -723,6 +1192,9 @@ export namespace Amounts {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Divide an amount. Throws on division by zero.
|
||||||
|
*/
|
||||||
export function divide(a: AmountJson, n: number): AmountJson {
|
export function divide(a: AmountJson, n: number): AmountJson {
|
||||||
if (n === 0) {
|
if (n === 0) {
|
||||||
throw Error(`Division by 0`);
|
throw Error(`Division by 0`);
|
||||||
@ -738,7 +1210,10 @@ export namespace Amounts {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isNonZero(a: AmountJson) {
|
/**
|
||||||
|
* Check if an amount is non-zero.
|
||||||
|
*/
|
||||||
|
export function isNonZero(a: AmountJson): boolean {
|
||||||
return a.value > 0 || a.fraction > 0;
|
return a.value > 0 || a.fraction > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -759,7 +1234,13 @@ export namespace Amounts {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listener for notifications from the wallet.
|
||||||
|
*/
|
||||||
export interface Notifier {
|
export interface Notifier {
|
||||||
|
/**
|
||||||
|
* Called when a new notification arrives.
|
||||||
|
*/
|
||||||
notify(): void;
|
notify(): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ test("coin selection 1", (t) => {
|
|||||||
fakeCwd("EUR:1.0", "EUR:1.0", "EUR:0.0"),
|
fakeCwd("EUR:1.0", "EUR:1.0", "EUR:0.0"),
|
||||||
];
|
];
|
||||||
|
|
||||||
const res = wallet.selectCoins(cds, a("EUR:2.0"), a("EUR:0.1"));
|
const res = wallet.selectPayCoins(cds, a("EUR:2.0"), a("EUR:0.1"));
|
||||||
if (!res) {
|
if (!res) {
|
||||||
t.fail();
|
t.fail();
|
||||||
return;
|
return;
|
||||||
@ -86,7 +86,7 @@ test("coin selection 2", (t) => {
|
|||||||
// Merchant covers the fee, this one shouldn't be used
|
// Merchant covers the fee, this one shouldn't be used
|
||||||
fakeCwd("EUR:1.0", "EUR:1.0", "EUR:0.0"),
|
fakeCwd("EUR:1.0", "EUR:1.0", "EUR:0.0"),
|
||||||
];
|
];
|
||||||
const res = wallet.selectCoins(cds, a("EUR:2.0"), a("EUR:0.5"));
|
const res = wallet.selectPayCoins(cds, a("EUR:2.0"), a("EUR:0.5"));
|
||||||
if (!res) {
|
if (!res) {
|
||||||
t.fail();
|
t.fail();
|
||||||
return;
|
return;
|
||||||
@ -103,7 +103,7 @@ test("coin selection 3", (t) => {
|
|||||||
// this coin should be selected instead of previous one with fee
|
// this coin should be selected instead of previous one with fee
|
||||||
fakeCwd("EUR:1.0", "EUR:1.0", "EUR:0.0"),
|
fakeCwd("EUR:1.0", "EUR:1.0", "EUR:0.0"),
|
||||||
];
|
];
|
||||||
const res = wallet.selectCoins(cds, a("EUR:2.0"), a("EUR:0.5"));
|
const res = wallet.selectPayCoins(cds, a("EUR:2.0"), a("EUR:0.5"));
|
||||||
if (!res) {
|
if (!res) {
|
||||||
t.fail();
|
t.fail();
|
||||||
return;
|
return;
|
||||||
@ -119,7 +119,7 @@ test("coin selection 4", (t) => {
|
|||||||
fakeCwd("EUR:1.0", "EUR:1.0", "EUR:0.5"),
|
fakeCwd("EUR:1.0", "EUR:1.0", "EUR:0.5"),
|
||||||
fakeCwd("EUR:1.0", "EUR:1.0", "EUR:0.5"),
|
fakeCwd("EUR:1.0", "EUR:1.0", "EUR:0.5"),
|
||||||
];
|
];
|
||||||
const res = wallet.selectCoins(cds, a("EUR:2.0"), a("EUR:0.2"));
|
const res = wallet.selectPayCoins(cds, a("EUR:2.0"), a("EUR:0.2"));
|
||||||
if (!res) {
|
if (!res) {
|
||||||
t.fail();
|
t.fail();
|
||||||
return;
|
return;
|
||||||
@ -135,7 +135,7 @@ test("coin selection 5", (t) => {
|
|||||||
fakeCwd("EUR:1.0", "EUR:1.0", "EUR:0.5"),
|
fakeCwd("EUR:1.0", "EUR:1.0", "EUR:0.5"),
|
||||||
fakeCwd("EUR:1.0", "EUR:1.0", "EUR:0.5"),
|
fakeCwd("EUR:1.0", "EUR:1.0", "EUR:0.5"),
|
||||||
];
|
];
|
||||||
const res = wallet.selectCoins(cds, a("EUR:4.0"), a("EUR:0.2"));
|
const res = wallet.selectPayCoins(cds, a("EUR:4.0"), a("EUR:0.2"));
|
||||||
t.true(!res);
|
t.true(!res);
|
||||||
t.pass();
|
t.pass();
|
||||||
});
|
});
|
||||||
@ -146,7 +146,7 @@ test("coin selection 6", (t) => {
|
|||||||
fakeCwd("EUR:1.0", "EUR:1.0", "EUR:0.5"),
|
fakeCwd("EUR:1.0", "EUR:1.0", "EUR:0.5"),
|
||||||
fakeCwd("EUR:1.0", "EUR:1.0", "EUR:0.5"),
|
fakeCwd("EUR:1.0", "EUR:1.0", "EUR:0.5"),
|
||||||
];
|
];
|
||||||
const res = wallet.selectCoins(cds, a("EUR:2.0"), a("EUR:0.2"));
|
const res = wallet.selectPayCoins(cds, a("EUR:2.0"), a("EUR:0.2"));
|
||||||
t.true(!res);
|
t.true(!res);
|
||||||
t.pass();
|
t.pass();
|
||||||
});
|
});
|
||||||
|
181
src/wallet.ts
181
src/wallet.ts
@ -81,7 +81,14 @@ import URI = require("urijs");
|
|||||||
* Named tuple of coin and denomination.
|
* Named tuple of coin and denomination.
|
||||||
*/
|
*/
|
||||||
export interface CoinWithDenom {
|
export interface CoinWithDenom {
|
||||||
|
/**
|
||||||
|
* A coin. Must have the same denomination public key as the associated
|
||||||
|
* denomination.
|
||||||
|
*/
|
||||||
coin: CoinRecord;
|
coin: CoinRecord;
|
||||||
|
/**
|
||||||
|
* An associated denomination.
|
||||||
|
*/
|
||||||
denom: DenominationRecord;
|
denom: DenominationRecord;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,6 +99,9 @@ export interface CoinWithDenom {
|
|||||||
*/
|
*/
|
||||||
@Checkable.Class()
|
@Checkable.Class()
|
||||||
export class Payback {
|
export class Payback {
|
||||||
|
/**
|
||||||
|
* The hash of the denomination public key for which the payback is offered.
|
||||||
|
*/
|
||||||
@Checkable.String
|
@Checkable.String
|
||||||
h_denom_pub: string;
|
h_denom_pub: string;
|
||||||
}
|
}
|
||||||
@ -102,67 +112,123 @@ export class Payback {
|
|||||||
*/
|
*/
|
||||||
@Checkable.Class({extra: true})
|
@Checkable.Class({extra: true})
|
||||||
export class KeysJson {
|
export class KeysJson {
|
||||||
|
/**
|
||||||
|
* List of offered denominations.
|
||||||
|
*/
|
||||||
@Checkable.List(Checkable.Value(Denomination))
|
@Checkable.List(Checkable.Value(Denomination))
|
||||||
denoms: Denomination[];
|
denoms: Denomination[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The exchange's master public key.
|
||||||
|
*/
|
||||||
@Checkable.String
|
@Checkable.String
|
||||||
master_public_key: string;
|
master_public_key: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The list of auditors (partially) auditing the exchange.
|
||||||
|
*/
|
||||||
@Checkable.Any
|
@Checkable.Any
|
||||||
auditors: any[];
|
auditors: any[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Timestamp when this response was issued.
|
||||||
|
*/
|
||||||
@Checkable.String
|
@Checkable.String
|
||||||
list_issue_date: string;
|
list_issue_date: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of paybacks for compromised denominations.
|
||||||
|
*/
|
||||||
@Checkable.List(Checkable.Value(Payback))
|
@Checkable.List(Checkable.Value(Payback))
|
||||||
payback?: Payback[];
|
payback?: Payback[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Short-lived signing keys used to sign online
|
||||||
|
* responses.
|
||||||
|
*/
|
||||||
@Checkable.Any
|
@Checkable.Any
|
||||||
signkeys: any;
|
signkeys: any;
|
||||||
|
|
||||||
@Checkable.String
|
/**
|
||||||
eddsa_pub: string;
|
* Verify that a value matches the schema of this class and convert it into a
|
||||||
|
* member.
|
||||||
@Checkable.String
|
*/
|
||||||
eddsa_sig: string;
|
|
||||||
|
|
||||||
static checked: (obj: any) => KeysJson;
|
static checked: (obj: any) => KeysJson;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wire fees as anounced by the exchange.
|
||||||
|
*/
|
||||||
@Checkable.Class()
|
@Checkable.Class()
|
||||||
class WireFeesJson {
|
class WireFeesJson {
|
||||||
|
/**
|
||||||
|
* Cost of a wire transfer.
|
||||||
|
*/
|
||||||
@Checkable.Value(AmountJson)
|
@Checkable.Value(AmountJson)
|
||||||
wire_fee: AmountJson;
|
wire_fee: AmountJson;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cost of clising a reserve.
|
||||||
|
*/
|
||||||
@Checkable.Value(AmountJson)
|
@Checkable.Value(AmountJson)
|
||||||
closing_fee: AmountJson;
|
closing_fee: AmountJson;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signature made with the exchange's master key.
|
||||||
|
*/
|
||||||
@Checkable.String
|
@Checkable.String
|
||||||
sig: string;
|
sig: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date from which the fee applies.
|
||||||
|
*/
|
||||||
@Checkable.String
|
@Checkable.String
|
||||||
start_date: string;
|
start_date: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data after which the fee doesn't apply anymore.
|
||||||
|
*/
|
||||||
@Checkable.String
|
@Checkable.String
|
||||||
end_date: string;
|
end_date: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify that a value matches the schema of this class and convert it into a
|
||||||
|
* member.
|
||||||
|
*/
|
||||||
static checked: (obj: any) => WireFeesJson;
|
static checked: (obj: any) => WireFeesJson;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Information about wire transfer methods supported
|
||||||
|
* by the exchange.
|
||||||
|
*/
|
||||||
@Checkable.Class({extra: true})
|
@Checkable.Class({extra: true})
|
||||||
class WireDetailJson {
|
class WireDetailJson {
|
||||||
|
/**
|
||||||
|
* Name of the wire transfer method.
|
||||||
|
*/
|
||||||
@Checkable.String
|
@Checkable.String
|
||||||
type: string;
|
type: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fees associated with the wire transfer method.
|
||||||
|
*/
|
||||||
@Checkable.List(Checkable.Value(WireFeesJson))
|
@Checkable.List(Checkable.Value(WireFeesJson))
|
||||||
fees: WireFeesJson[];
|
fees: WireFeesJson[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify that a value matches the schema of this class and convert it into a
|
||||||
|
* member.
|
||||||
|
*/
|
||||||
static checked: (obj: any) => WireDetailJson;
|
static checked: (obj: any) => WireDetailJson;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request to mark a reserve as confirmed.
|
||||||
|
*/
|
||||||
@Checkable.Class()
|
@Checkable.Class()
|
||||||
export class CreateReserveRequest {
|
export class CreateReserveRequest {
|
||||||
/**
|
/**
|
||||||
@ -177,10 +243,17 @@ export class CreateReserveRequest {
|
|||||||
@Checkable.String
|
@Checkable.String
|
||||||
exchange: string;
|
exchange: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify that a value matches the schema of this class and convert it into a
|
||||||
|
* member.
|
||||||
|
*/
|
||||||
static checked: (obj: any) => CreateReserveRequest;
|
static checked: (obj: any) => CreateReserveRequest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request to mark a reserve as confirmed.
|
||||||
|
*/
|
||||||
@Checkable.Class()
|
@Checkable.Class()
|
||||||
export class ConfirmReserveRequest {
|
export class ConfirmReserveRequest {
|
||||||
/**
|
/**
|
||||||
@ -190,21 +263,40 @@ export class ConfirmReserveRequest {
|
|||||||
@Checkable.String
|
@Checkable.String
|
||||||
reservePub: string;
|
reservePub: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify that a value matches the schema of this class and convert it into a
|
||||||
|
* member.
|
||||||
|
*/
|
||||||
static checked: (obj: any) => ConfirmReserveRequest;
|
static checked: (obj: any) => ConfirmReserveRequest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Offer record, stored in the wallet's database.
|
||||||
|
*/
|
||||||
@Checkable.Class()
|
@Checkable.Class()
|
||||||
export class OfferRecord {
|
export class OfferRecord {
|
||||||
|
/**
|
||||||
|
* The contract that was offered by the merchant.
|
||||||
|
*/
|
||||||
@Checkable.Value(Contract)
|
@Checkable.Value(Contract)
|
||||||
contract: Contract;
|
contract: Contract;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signature by the merchant over the contract details.
|
||||||
|
*/
|
||||||
@Checkable.String
|
@Checkable.String
|
||||||
merchant_sig: string;
|
merchant_sig: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hash of the contract terms.
|
||||||
|
*/
|
||||||
@Checkable.String
|
@Checkable.String
|
||||||
H_contract: string;
|
H_contract: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Time when the offer was made.
|
||||||
|
*/
|
||||||
@Checkable.Number
|
@Checkable.Number
|
||||||
offer_time: number;
|
offer_time: number;
|
||||||
|
|
||||||
@ -214,14 +306,41 @@ export class OfferRecord {
|
|||||||
@Checkable.Optional(Checkable.Number)
|
@Checkable.Optional(Checkable.Number)
|
||||||
id?: number;
|
id?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify that a value matches the schema of this class and convert it into a
|
||||||
|
* member.
|
||||||
|
*/
|
||||||
static checked: (obj: any) => OfferRecord;
|
static checked: (obj: any) => OfferRecord;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Activity history record.
|
||||||
|
*/
|
||||||
export interface HistoryRecord {
|
export interface HistoryRecord {
|
||||||
|
/**
|
||||||
|
* Type of the history event.
|
||||||
|
*/
|
||||||
type: string;
|
type: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Time when the activity was recorded.
|
||||||
|
*/
|
||||||
timestamp: number;
|
timestamp: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subject of the entry. Used to group multiple history records together.
|
||||||
|
* Only the latest history record with the same subjectId will be shown.
|
||||||
|
*/
|
||||||
subjectId?: string;
|
subjectId?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Details used when rendering the history record.
|
||||||
|
*/
|
||||||
detail: any;
|
detail: any;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Level of detail of the history entry.
|
||||||
|
*/
|
||||||
level: HistoryLevel;
|
level: HistoryLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -246,6 +365,11 @@ interface TransactionRecord {
|
|||||||
finished: boolean;
|
finished: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Level of detail at which a history
|
||||||
|
* entry should be shown.
|
||||||
|
*/
|
||||||
export enum HistoryLevel {
|
export enum HistoryLevel {
|
||||||
Trace = 1,
|
Trace = 1,
|
||||||
Developer = 2,
|
Developer = 2,
|
||||||
@ -254,19 +378,34 @@ export enum HistoryLevel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Badge that shows activity for the wallet.
|
||||||
|
*/
|
||||||
export interface Badge {
|
export interface Badge {
|
||||||
setText(s: string): void;
|
/**
|
||||||
setColor(c: string): void;
|
* Start indicating background activity.
|
||||||
|
*/
|
||||||
startBusy(): void;
|
startBusy(): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop indicating background activity.
|
||||||
|
*/
|
||||||
stopBusy(): void;
|
stopBusy(): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nonce record as stored in the wallet's database.
|
||||||
|
*/
|
||||||
export interface NonceRecord {
|
export interface NonceRecord {
|
||||||
priv: string;
|
priv: string;
|
||||||
pub: string;
|
pub: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration key/value entries to configure
|
||||||
|
* the wallet.
|
||||||
|
*/
|
||||||
export interface ConfigRecord {
|
export interface ConfigRecord {
|
||||||
key: string;
|
key: string;
|
||||||
value: any;
|
value: any;
|
||||||
@ -328,9 +467,16 @@ function isWithdrawableDenom(d: DenominationRecord) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Result of selecting coins, contains the exchange, and selected
|
||||||
|
* coins with their denomination.
|
||||||
|
*/
|
||||||
export type CoinSelectionResult = {exchangeUrl: string, cds: CoinWithDenom[]}|undefined;
|
export type CoinSelectionResult = {exchangeUrl: string, cds: CoinWithDenom[]}|undefined;
|
||||||
|
|
||||||
export function selectCoins(cds: CoinWithDenom[], paymentAmount: AmountJson,
|
/**
|
||||||
|
* Select coins for a payment under the merchant's constraints.
|
||||||
|
*/
|
||||||
|
export function selectPayCoins(cds: CoinWithDenom[], paymentAmount: AmountJson,
|
||||||
depositFeeLimit: AmountJson): CoinWithDenom[]|undefined {
|
depositFeeLimit: AmountJson): CoinWithDenom[]|undefined {
|
||||||
if (cds.length === 0) {
|
if (cds.length === 0) {
|
||||||
return undefined;
|
return undefined;
|
||||||
@ -406,7 +552,11 @@ function getWithdrawDenomList(amountAvailable: AmountJson,
|
|||||||
return ds;
|
return ds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* tslint:disable:completed-docs */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The stores and indices for the wallet database.
|
||||||
|
*/
|
||||||
export namespace Stores {
|
export namespace Stores {
|
||||||
class ExchangeStore extends Store<ExchangeRecord> {
|
class ExchangeStore extends Store<ExchangeRecord> {
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -489,6 +639,7 @@ export namespace Stores {
|
|||||||
super("exchangeWireFees", {keyPath: "exchangeBaseUrl"});
|
super("exchangeWireFees", {keyPath: "exchangeBaseUrl"});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const exchanges = new ExchangeStore();
|
export const exchanges = new ExchangeStore();
|
||||||
export const exchangeWireFees = new ExchangeWireFeesStore();
|
export const exchangeWireFees = new ExchangeWireFeesStore();
|
||||||
export const nonces = new NonceStore();
|
export const nonces = new NonceStore();
|
||||||
@ -504,6 +655,8 @@ export namespace Stores {
|
|||||||
export const config = new ConfigStore();
|
export const config = new ConfigStore();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* tslint:enable:completed-docs */
|
||||||
|
|
||||||
|
|
||||||
interface CoinsForPaymentArgs {
|
interface CoinsForPaymentArgs {
|
||||||
allowedAuditors: Auditor[];
|
allowedAuditors: Auditor[];
|
||||||
@ -517,13 +670,15 @@ interface CoinsForPaymentArgs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The platform-independent wallet implementation.
|
||||||
|
*/
|
||||||
export class Wallet {
|
export class Wallet {
|
||||||
private db: IDBDatabase;
|
private db: IDBDatabase;
|
||||||
private http: HttpRequestLibrary;
|
private http: HttpRequestLibrary;
|
||||||
private badge: Badge;
|
private badge: Badge;
|
||||||
private notifier: Notifier;
|
private notifier: Notifier;
|
||||||
public cryptoApi: CryptoApi;
|
private cryptoApi: CryptoApi;
|
||||||
|
|
||||||
private processPreCoinConcurrent = 0;
|
private processPreCoinConcurrent = 0;
|
||||||
private processPreCoinThrottle: {[url: string]: number} = {};
|
private processPreCoinThrottle: {[url: string]: number} = {};
|
||||||
|
|
||||||
@ -748,7 +903,7 @@ export class Wallet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = selectCoins(cds, remainingAmount, depositFeeLimit);
|
const res = selectPayCoins(cds, remainingAmount, depositFeeLimit);
|
||||||
if (res) {
|
if (res) {
|
||||||
return {
|
return {
|
||||||
cds: res,
|
cds: res,
|
||||||
|
70
src/wxApi.ts
70
src/wxApi.ts
@ -14,6 +14,14 @@
|
|||||||
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface to the wallet through WebExtension messaging.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Imports.
|
||||||
|
*/
|
||||||
import {
|
import {
|
||||||
AmountJson,
|
AmountJson,
|
||||||
CoinRecord,
|
CoinRecord,
|
||||||
@ -25,12 +33,11 @@ import {
|
|||||||
ReserveRecord,
|
ReserveRecord,
|
||||||
} from "./types";
|
} from "./types";
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface to the wallet through WebExtension messaging.
|
* Query the wallet for the coins that would be used to withdraw
|
||||||
* @author Florian Dold
|
* from a given reserve.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
export function getReserveCreationInfo(baseUrl: string,
|
export function getReserveCreationInfo(baseUrl: string,
|
||||||
amount: AmountJson): Promise<ReserveCreationInfo> {
|
amount: AmountJson): Promise<ReserveCreationInfo> {
|
||||||
const m = { type: "reserve-creation-info", detail: { baseUrl, amount } };
|
const m = { type: "reserve-creation-info", detail: { baseUrl, amount } };
|
||||||
@ -48,7 +55,8 @@ export function getReserveCreationInfo(baseUrl: string,
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function callBackend(type: string, detail?: any): Promise<any> {
|
|
||||||
|
async function callBackend(type: string, detail?: any): Promise<any> {
|
||||||
return new Promise<any>((resolve, reject) => {
|
return new Promise<any>((resolve, reject) => {
|
||||||
chrome.runtime.sendMessage({ type, detail }, (resp) => {
|
chrome.runtime.sendMessage({ type, detail }, (resp) => {
|
||||||
if (resp && resp.error) {
|
if (resp && resp.error) {
|
||||||
@ -60,55 +68,107 @@ export async function callBackend(type: string, detail?: any): Promise<any> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all exchanges the wallet knows about.
|
||||||
|
*/
|
||||||
export async function getExchanges(): Promise<ExchangeRecord[]> {
|
export async function getExchanges(): Promise<ExchangeRecord[]> {
|
||||||
return await callBackend("get-exchanges");
|
return await callBackend("get-exchanges");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all currencies the exchange knows about.
|
||||||
|
*/
|
||||||
export async function getCurrencies(): Promise<CurrencyRecord[]> {
|
export async function getCurrencies(): Promise<CurrencyRecord[]> {
|
||||||
return await callBackend("get-currencies");
|
return await callBackend("get-currencies");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get information about a specific currency.
|
||||||
|
*/
|
||||||
export async function getCurrency(name: string): Promise<CurrencyRecord|null> {
|
export async function getCurrency(name: string): Promise<CurrencyRecord|null> {
|
||||||
return await callBackend("currency-info", {name});
|
return await callBackend("currency-info", {name});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get information about a specific exchange.
|
||||||
|
*/
|
||||||
export async function getExchangeInfo(baseUrl: string): Promise<ExchangeRecord> {
|
export async function getExchangeInfo(baseUrl: string): Promise<ExchangeRecord> {
|
||||||
return await callBackend("exchange-info", {baseUrl});
|
return await callBackend("exchange-info", {baseUrl});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replace an existing currency record with the one given. The currency to
|
||||||
|
* replace is specified inside the currency record.
|
||||||
|
*/
|
||||||
export async function updateCurrency(currencyRecord: CurrencyRecord): Promise<void> {
|
export async function updateCurrency(currencyRecord: CurrencyRecord): Promise<void> {
|
||||||
return await callBackend("update-currency", { currencyRecord });
|
return await callBackend("update-currency", { currencyRecord });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all reserves the wallet has at an exchange.
|
||||||
|
*/
|
||||||
export async function getReserves(exchangeBaseUrl: string): Promise<ReserveRecord[]> {
|
export async function getReserves(exchangeBaseUrl: string): Promise<ReserveRecord[]> {
|
||||||
return await callBackend("get-reserves", { exchangeBaseUrl });
|
return await callBackend("get-reserves", { exchangeBaseUrl });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all reserves for which a payback is available.
|
||||||
|
*/
|
||||||
export async function getPaybackReserves(): Promise<ReserveRecord[]> {
|
export async function getPaybackReserves(): Promise<ReserveRecord[]> {
|
||||||
return await callBackend("get-payback-reserves");
|
return await callBackend("get-payback-reserves");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Withdraw the payback that is available for a reserve.
|
||||||
|
*/
|
||||||
export async function withdrawPaybackReserve(reservePub: string): Promise<ReserveRecord[]> {
|
export async function withdrawPaybackReserve(reservePub: string): Promise<ReserveRecord[]> {
|
||||||
return await callBackend("withdraw-payback-reserve", { reservePub });
|
return await callBackend("withdraw-payback-reserve", { reservePub });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all coins withdrawn from the given exchange.
|
||||||
|
*/
|
||||||
export async function getCoins(exchangeBaseUrl: string): Promise<CoinRecord[]> {
|
export async function getCoins(exchangeBaseUrl: string): Promise<CoinRecord[]> {
|
||||||
return await callBackend("get-coins", { exchangeBaseUrl });
|
return await callBackend("get-coins", { exchangeBaseUrl });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all precoins withdrawn from the given exchange.
|
||||||
|
*/
|
||||||
export async function getPreCoins(exchangeBaseUrl: string): Promise<PreCoinRecord[]> {
|
export async function getPreCoins(exchangeBaseUrl: string): Promise<PreCoinRecord[]> {
|
||||||
return await callBackend("get-precoins", { exchangeBaseUrl });
|
return await callBackend("get-precoins", { exchangeBaseUrl });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all denoms offered by the given exchange.
|
||||||
|
*/
|
||||||
export async function getDenoms(exchangeBaseUrl: string): Promise<DenominationRecord[]> {
|
export async function getDenoms(exchangeBaseUrl: string): Promise<DenominationRecord[]> {
|
||||||
return await callBackend("get-denoms", { exchangeBaseUrl });
|
return await callBackend("get-denoms", { exchangeBaseUrl });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start refreshing a coin.
|
||||||
|
*/
|
||||||
export async function refresh(coinPub: string): Promise<void> {
|
export async function refresh(coinPub: string): Promise<void> {
|
||||||
return await callBackend("refresh-coin", { coinPub });
|
return await callBackend("refresh-coin", { coinPub });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request payback for a coin. Only works for non-refreshed coins.
|
||||||
|
*/
|
||||||
export async function payback(coinPub: string): Promise<void> {
|
export async function payback(coinPub: string): Promise<void> {
|
||||||
return await callBackend("payback-coin", { coinPub });
|
return await callBackend("payback-coin", { coinPub });
|
||||||
}
|
}
|
||||||
|
@ -340,8 +340,9 @@ async function dispatch(handlers: any, req: any, sender: any, sendResponse: any)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class ChromeNotifier implements Notifier {
|
class ChromeNotifier implements Notifier {
|
||||||
ports: Port[] = [];
|
private ports: Port[] = [];
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
chrome.runtime.onConnect.addListener((port) => {
|
chrome.runtime.onConnect.addListener((port) => {
|
||||||
@ -483,6 +484,11 @@ function clearRateLimitCache() {
|
|||||||
rateLimitCache = {};
|
rateLimitCache = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main function to run for the WebExtension backend.
|
||||||
|
*
|
||||||
|
* Sets up all event handlers and other machinery.
|
||||||
|
*/
|
||||||
export async function wxMain() {
|
export async function wxMain() {
|
||||||
window.onerror = (m, source, lineno, colno, error) => {
|
window.onerror = (m, source, lineno, colno, error) => {
|
||||||
logging.record("error", m + error, undefined, source || "(unknown)", lineno || 0, colno || 0);
|
logging.record("error", m + error, undefined, source || "(unknown)", lineno || 0, colno || 0);
|
||||||
|
30
tslint.json
30
tslint.json
@ -27,7 +27,35 @@
|
|||||||
"array-type": [true, "array-simple"],
|
"array-type": [true, "array-simple"],
|
||||||
"class-name": false,
|
"class-name": false,
|
||||||
"no-bitwise": false,
|
"no-bitwise": false,
|
||||||
"file-header": [true, "GNU General Public License"]
|
"file-header": [true, "GNU General Public License"],
|
||||||
|
"completed-docs": [true, {
|
||||||
|
"methods": {
|
||||||
|
"privacies": ["public"],
|
||||||
|
"locations": "all"
|
||||||
|
},
|
||||||
|
"properties": {
|
||||||
|
"privacies": ["public"],
|
||||||
|
"locations": ["all"]
|
||||||
|
},
|
||||||
|
"functions": {
|
||||||
|
"visibilities": ["exported"]
|
||||||
|
},
|
||||||
|
"interfaces": {
|
||||||
|
"visibilities": ["exported"]
|
||||||
|
},
|
||||||
|
"types": {
|
||||||
|
"visibilities": ["exported"]
|
||||||
|
},
|
||||||
|
"enums": {
|
||||||
|
"visibilities": ["exported"]
|
||||||
|
},
|
||||||
|
"classes": {
|
||||||
|
"visibilities": ["exported"]
|
||||||
|
},
|
||||||
|
"namespaces": {
|
||||||
|
"visibilities": ["exported"]
|
||||||
|
}
|
||||||
|
}]
|
||||||
},
|
},
|
||||||
"rulesDirectory": []
|
"rulesDirectory": []
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user