change protocol to string amount network format
This commit is contained in:
parent
9fe6dc5965
commit
97f6e68ce3
@ -38,19 +38,19 @@ export class AmountJson {
|
|||||||
/**
|
/**
|
||||||
* Value, must be an integer.
|
* Value, must be an integer.
|
||||||
*/
|
*/
|
||||||
@Checkable.Number
|
@Checkable.Number()
|
||||||
readonly value: number;
|
readonly value: number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fraction, must be an integer. Represent 1/1e8 of a unit.
|
* Fraction, must be an integer. Represent 1/1e8 of a unit.
|
||||||
*/
|
*/
|
||||||
@Checkable.Number
|
@Checkable.Number()
|
||||||
readonly fraction: number;
|
readonly fraction: number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Currency of the amount.
|
* Currency of the amount.
|
||||||
*/
|
*/
|
||||||
@Checkable.String
|
@Checkable.String()
|
||||||
readonly currency: string;
|
readonly currency: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -226,7 +226,7 @@ export function isNonZero(a: AmountJson): boolean {
|
|||||||
* Parse an amount like 'EUR:20.5' for 20 Euros and 50 ct.
|
* Parse an amount like 'EUR:20.5' for 20 Euros and 50 ct.
|
||||||
*/
|
*/
|
||||||
export function parse(s: string): AmountJson|undefined {
|
export function parse(s: string): AmountJson|undefined {
|
||||||
const res = s.match(/([a-zA-Z0-9_*-]+):([0-9])+([.][0-9]+)?/);
|
const res = s.match(/([a-zA-Z0-9_*-]+):([0-9]+)([.][0-9]+)?/);
|
||||||
if (!res) {
|
if (!res) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
@ -237,6 +237,14 @@ export function parse(s: string): AmountJson|undefined {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function parseOrThrow(s: string): AmountJson {
|
||||||
|
const res = parse(s);
|
||||||
|
if (!res) {
|
||||||
|
throw Error(`Can't parse amount: "${s}"`);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert the amount to a float.
|
* Convert the amount to a float.
|
||||||
*/
|
*/
|
||||||
@ -255,3 +263,23 @@ export function fromFloat(floatVal: number, currency: string) {
|
|||||||
value: Math.floor(floatVal),
|
value: Math.floor(floatVal),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert to standard human-readable string representation that's
|
||||||
|
* also used in JSON formats.
|
||||||
|
*/
|
||||||
|
export function toString(a: AmountJson) {
|
||||||
|
return `${a.currency}:${a.value + (a.fraction / fractionalBase)}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function check(a: any) {
|
||||||
|
if (typeof a !== "string") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const parsedAmount = parse(a);
|
||||||
|
return !!parsedAmount;
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -57,6 +57,7 @@ export namespace Checkable {
|
|||||||
elementChecker?: any;
|
elementChecker?: any;
|
||||||
elementProp?: any;
|
elementProp?: any;
|
||||||
keyProp?: any;
|
keyProp?: any;
|
||||||
|
stringChecker?: (s: string) => boolean;
|
||||||
valueProp?: any;
|
valueProp?: any;
|
||||||
optional?: boolean;
|
optional?: boolean;
|
||||||
extraAllowed?: boolean;
|
extraAllowed?: boolean;
|
||||||
@ -109,6 +110,9 @@ export namespace Checkable {
|
|||||||
if (typeof target !== "string") {
|
if (typeof target !== "string") {
|
||||||
throw new SchemaError(`expected string for ${path}, got ${typeof target} instead`);
|
throw new SchemaError(`expected string for ${path}, got ${typeof target} instead`);
|
||||||
}
|
}
|
||||||
|
if (prop.stringChecker && !prop.stringChecker(target)) {
|
||||||
|
throw new SchemaError(`string property ${path} malformed`);
|
||||||
|
}
|
||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -316,7 +320,7 @@ export namespace Checkable {
|
|||||||
/**
|
/**
|
||||||
* Makes another annotation optional, for example `@Checkable.Optional(Checkable.Number)`.
|
* Makes another annotation optional, for example `@Checkable.Optional(Checkable.Number)`.
|
||||||
*/
|
*/
|
||||||
export function Optional(type: any) {
|
export function Optional(type: (target: object, propertyKey: string | symbol) => void | any) {
|
||||||
const stub = {};
|
const stub = {};
|
||||||
type(stub, "(optional-element)");
|
type(stub, "(optional-element)");
|
||||||
const elementProp = getCheckableInfo(stub).props[0];
|
const elementProp = getCheckableInfo(stub).props[0];
|
||||||
@ -342,21 +346,27 @@ export namespace Checkable {
|
|||||||
/**
|
/**
|
||||||
* Target property must be a number.
|
* Target property must be a number.
|
||||||
*/
|
*/
|
||||||
export function Number(target: object, propertyKey: string | symbol): void {
|
export function Number(): (target: object, propertyKey: string | symbol) => void {
|
||||||
const chk = getCheckableInfo(target);
|
const deco = (target: object, propertyKey: string | symbol) => {
|
||||||
chk.props.push({checker: checkNumber, propertyKey});
|
const chk = getCheckableInfo(target);
|
||||||
|
chk.props.push({checker: checkNumber, propertyKey});
|
||||||
|
};
|
||||||
|
return deco;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Target property must be an arbitary object.
|
* Target property must be an arbitary object.
|
||||||
*/
|
*/
|
||||||
export function AnyObject(target: object, propertyKey: string | symbol): void {
|
export function AnyObject(): (target: object, propertyKey: string | symbol) => void {
|
||||||
const chk = getCheckableInfo(target);
|
const deco = (target: object, propertyKey: string | symbol) => {
|
||||||
chk.props.push({
|
const chk = getCheckableInfo(target);
|
||||||
checker: checkAnyObject,
|
chk.props.push({
|
||||||
propertyKey,
|
checker: checkAnyObject,
|
||||||
});
|
propertyKey,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
return deco;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -366,29 +376,40 @@ export namespace Checkable {
|
|||||||
* Not useful by itself, but in combination with higher-order annotations
|
* Not useful by itself, but in combination with higher-order annotations
|
||||||
* such as List or Map.
|
* such as List or Map.
|
||||||
*/
|
*/
|
||||||
export function Any(target: object, propertyKey: string | symbol): void {
|
export function Any(): (target: object, propertyKey: string | symbol) => void {
|
||||||
const chk = getCheckableInfo(target);
|
const deco = (target: object, propertyKey: string | symbol) => {
|
||||||
chk.props.push({
|
const chk = getCheckableInfo(target);
|
||||||
checker: checkAny,
|
chk.props.push({
|
||||||
optional: true,
|
checker: checkAny,
|
||||||
propertyKey,
|
optional: true,
|
||||||
});
|
propertyKey,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
return deco;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Target property must be a string.
|
* Target property must be a string.
|
||||||
*/
|
*/
|
||||||
export function String(target: object, propertyKey: string | symbol): void {
|
export function String(
|
||||||
const chk = getCheckableInfo(target);
|
stringChecker?: (s: string) => boolean): (target: object, propertyKey: string | symbol,
|
||||||
chk.props.push({ checker: checkString, propertyKey });
|
) => void {
|
||||||
|
const deco = (target: object, propertyKey: string | symbol) => {
|
||||||
|
const chk = getCheckableInfo(target);
|
||||||
|
chk.props.push({ checker: checkString, propertyKey, stringChecker });
|
||||||
|
};
|
||||||
|
return deco;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Target property must be a boolean value.
|
* Target property must be a boolean value.
|
||||||
*/
|
*/
|
||||||
export function Boolean(target: object, propertyKey: string | symbol): void {
|
export function Boolean(): (target: object, propertyKey: string | symbol) => void {
|
||||||
const chk = getCheckableInfo(target);
|
const deco = (target: object, propertyKey: string | symbol) => {
|
||||||
chk.props.push({ checker: checkBoolean, propertyKey });
|
const chk = getCheckableInfo(target);
|
||||||
|
chk.props.push({ checker: checkBoolean, propertyKey });
|
||||||
|
};
|
||||||
|
return deco;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -282,7 +282,7 @@ namespace RpcFunctions {
|
|||||||
const feeList: AmountJson[] = cds.map((x) => x.denom.feeDeposit);
|
const feeList: AmountJson[] = cds.map((x) => x.denom.feeDeposit);
|
||||||
let fees = Amounts.add(Amounts.getZero(feeList[0].currency), ...feeList).amount;
|
let fees = Amounts.add(Amounts.getZero(feeList[0].currency), ...feeList).amount;
|
||||||
// okay if saturates
|
// okay if saturates
|
||||||
fees = Amounts.sub(fees, contractTerms.max_fee).amount;
|
fees = Amounts.sub(fees, Amounts.parseOrThrow(contractTerms.max_fee)).amount;
|
||||||
const total = Amounts.add(fees, totalAmount).amount;
|
const total = Amounts.add(fees, totalAmount).amount;
|
||||||
|
|
||||||
const amountSpent = native.Amount.getZero(cds[0].coin.currentAmount.currency);
|
const amountSpent = native.Amount.getZero(cds[0].coin.currentAmount.currency);
|
||||||
@ -335,7 +335,7 @@ namespace RpcFunctions {
|
|||||||
const s: CoinPaySig = {
|
const s: CoinPaySig = {
|
||||||
coin_pub: cd.coin.coinPub,
|
coin_pub: cd.coin.coinPub,
|
||||||
coin_sig: coinSig,
|
coin_sig: coinSig,
|
||||||
contribution: coinSpend.toJson(),
|
contribution: Amounts.toString(coinSpend.toJson()),
|
||||||
denom_pub: cd.coin.denomPub,
|
denom_pub: cd.coin.denomPub,
|
||||||
exchange_url: cd.denom.exchangeBaseUrl,
|
exchange_url: cd.denom.exchangeBaseUrl,
|
||||||
ub_sig: cd.coin.denomSig,
|
ub_sig: cd.coin.denomSig,
|
||||||
|
@ -49,7 +49,7 @@ import {
|
|||||||
* In the future we might consider adding migration functions for
|
* In the future we might consider adding migration functions for
|
||||||
* each version increment.
|
* each version increment.
|
||||||
*/
|
*/
|
||||||
export const WALLET_DB_VERSION = 25;
|
export const WALLET_DB_VERSION = 26;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -212,14 +212,14 @@ export class DenominationRecord {
|
|||||||
/**
|
/**
|
||||||
* The denomination public key.
|
* The denomination public key.
|
||||||
*/
|
*/
|
||||||
@Checkable.String
|
@Checkable.String()
|
||||||
denomPub: string;
|
denomPub: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hash of the denomination public key.
|
* Hash of the denomination public key.
|
||||||
* Stored in the database for faster lookups.
|
* Stored in the database for faster lookups.
|
||||||
*/
|
*/
|
||||||
@Checkable.String
|
@Checkable.String()
|
||||||
denomPubHash: string;
|
denomPubHash: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -249,38 +249,38 @@ export class DenominationRecord {
|
|||||||
/**
|
/**
|
||||||
* Validity start date of the denomination.
|
* Validity start date of the denomination.
|
||||||
*/
|
*/
|
||||||
@Checkable.String
|
@Checkable.String()
|
||||||
stampStart: string;
|
stampStart: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Date after which the currency can't be withdrawn anymore.
|
* 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.
|
* 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.
|
* 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
|
* Signature by the exchange's master key over the denomination
|
||||||
* information.
|
* information.
|
||||||
*/
|
*/
|
||||||
@Checkable.String
|
@Checkable.String()
|
||||||
masterSig: string;
|
masterSig: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Did we verify the signature on the denomination?
|
* Did we verify the signature on the denomination?
|
||||||
*/
|
*/
|
||||||
@Checkable.Number
|
@Checkable.Number()
|
||||||
status: DenominationStatus;
|
status: DenominationStatus;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -288,13 +288,13 @@ export class DenominationRecord {
|
|||||||
* we checked?
|
* we checked?
|
||||||
* Only false when the exchange redacts a previously published denomination.
|
* Only false when the exchange redacts a previously published denomination.
|
||||||
*/
|
*/
|
||||||
@Checkable.Boolean
|
@Checkable.Boolean()
|
||||||
isOffered: boolean;
|
isOffered: boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base URL of the exchange.
|
* Base URL of the exchange.
|
||||||
*/
|
*/
|
||||||
@Checkable.String
|
@Checkable.String()
|
||||||
exchangeBaseUrl: string;
|
exchangeBaseUrl: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -500,7 +500,7 @@ export class ProposalDownloadRecord {
|
|||||||
/**
|
/**
|
||||||
* URL where the proposal was downloaded.
|
* URL where the proposal was downloaded.
|
||||||
*/
|
*/
|
||||||
@Checkable.String
|
@Checkable.String()
|
||||||
url: string;
|
url: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -512,32 +512,32 @@ export class ProposalDownloadRecord {
|
|||||||
/**
|
/**
|
||||||
* Signature by the merchant over the contract details.
|
* Signature by the merchant over the contract details.
|
||||||
*/
|
*/
|
||||||
@Checkable.String
|
@Checkable.String()
|
||||||
merchantSig: string;
|
merchantSig: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hash of the contract terms.
|
* Hash of the contract terms.
|
||||||
*/
|
*/
|
||||||
@Checkable.String
|
@Checkable.String()
|
||||||
contractTermsHash: string;
|
contractTermsHash: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Serial ID when the offer is stored in the wallet DB.
|
* Serial ID when the offer is stored in the wallet DB.
|
||||||
*/
|
*/
|
||||||
@Checkable.Optional(Checkable.Number)
|
@Checkable.Optional(Checkable.Number())
|
||||||
id?: number;
|
id?: number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Timestamp (in ms) of when the record
|
* Timestamp (in ms) of when the record
|
||||||
* was created.
|
* was created.
|
||||||
*/
|
*/
|
||||||
@Checkable.Number
|
@Checkable.Number()
|
||||||
timestamp: number;
|
timestamp: number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Private key for the nonce.
|
* Private key for the nonce.
|
||||||
*/
|
*/
|
||||||
@Checkable.String
|
@Checkable.String()
|
||||||
noncePriv: string;
|
noncePriv: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -119,12 +119,19 @@ export function flatMap<T, U>(xs: T[], f: (x: T) => U[]): U[] {
|
|||||||
*/
|
*/
|
||||||
export function getTalerStampSec(stamp: string): number | null {
|
export function getTalerStampSec(stamp: string): number | null {
|
||||||
const m = stamp.match(/\/?Date\(([0-9]*)\)\/?/);
|
const m = stamp.match(/\/?Date\(([0-9]*)\)\/?/);
|
||||||
if (!m) {
|
if (!m || !m[1]) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return parseInt(m[1], 10);
|
return parseInt(m[1], 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a timestamp is in the right format.
|
||||||
|
*/
|
||||||
|
export function timestampCheck(stamp: string): boolean {
|
||||||
|
return getTalerStampSec(stamp) !== null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a JavaScript Date object from a Taler date string.
|
* Get a JavaScript Date object from a Taler date string.
|
||||||
|
@ -26,9 +26,12 @@
|
|||||||
/**
|
/**
|
||||||
* Imports.
|
* Imports.
|
||||||
*/
|
*/
|
||||||
import { AmountJson } from "./amounts";
|
|
||||||
import { Checkable } from "./checkable";
|
import { Checkable } from "./checkable";
|
||||||
|
|
||||||
|
import * as Amounts from "./amounts";
|
||||||
|
|
||||||
|
import { timestampCheck } from "./helpers";
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Denomination as found in the /keys response from the exchange.
|
* Denomination as found in the /keys response from the exchange.
|
||||||
@ -38,70 +41,70 @@ export class Denomination {
|
|||||||
/**
|
/**
|
||||||
* Value of one coin of the denomination.
|
* Value of one coin of the denomination.
|
||||||
*/
|
*/
|
||||||
@Checkable.Value(() => AmountJson)
|
@Checkable.String(Amounts.check)
|
||||||
value: AmountJson;
|
value: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Public signing key of the denomination.
|
* Public signing key of the denomination.
|
||||||
*/
|
*/
|
||||||
@Checkable.String
|
@Checkable.String()
|
||||||
denom_pub: string;
|
denom_pub: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fee for withdrawing.
|
* Fee for withdrawing.
|
||||||
*/
|
*/
|
||||||
@Checkable.Value(() => AmountJson)
|
@Checkable.String(Amounts.check)
|
||||||
fee_withdraw: AmountJson;
|
fee_withdraw: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fee for depositing.
|
* Fee for depositing.
|
||||||
*/
|
*/
|
||||||
@Checkable.Value(() => AmountJson)
|
@Checkable.String(Amounts.check)
|
||||||
fee_deposit: AmountJson;
|
fee_deposit: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fee for refreshing.
|
* Fee for refreshing.
|
||||||
*/
|
*/
|
||||||
@Checkable.Value(() => AmountJson)
|
@Checkable.String(Amounts.check)
|
||||||
fee_refresh: AmountJson;
|
fee_refresh: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fee for refunding.
|
* Fee for refunding.
|
||||||
*/
|
*/
|
||||||
@Checkable.Value(() => AmountJson)
|
@Checkable.String(Amounts.check)
|
||||||
fee_refund: AmountJson;
|
fee_refund: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start date from which withdraw is allowed.
|
* Start date from which withdraw is allowed.
|
||||||
*/
|
*/
|
||||||
@Checkable.String
|
@Checkable.String(timestampCheck)
|
||||||
stamp_start: string;
|
stamp_start: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* End date for withdrawing.
|
* End date for withdrawing.
|
||||||
*/
|
*/
|
||||||
@Checkable.String
|
@Checkable.String(timestampCheck)
|
||||||
stamp_expire_withdraw: string;
|
stamp_expire_withdraw: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Expiration date after which the exchange can forget about
|
* Expiration date after which the exchange can forget about
|
||||||
* the currency.
|
* the currency.
|
||||||
*/
|
*/
|
||||||
@Checkable.String
|
@Checkable.String(timestampCheck)
|
||||||
stamp_expire_legal: string;
|
stamp_expire_legal: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Date after which the coins of this denomination can't be
|
* Date after which the coins of this denomination can't be
|
||||||
* deposited anymore.
|
* deposited anymore.
|
||||||
*/
|
*/
|
||||||
@Checkable.String
|
@Checkable.String(timestampCheck)
|
||||||
stamp_expire_deposit: string;
|
stamp_expire_deposit: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Signature over the denomination information by the exchange's master
|
* Signature over the denomination information by the exchange's master
|
||||||
* signing key.
|
* signing key.
|
||||||
*/
|
*/
|
||||||
@Checkable.String
|
@Checkable.String()
|
||||||
master_sig: string;
|
master_sig: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -120,13 +123,13 @@ export class AuditorDenomSig {
|
|||||||
/**
|
/**
|
||||||
* Denomination public key's hash.
|
* Denomination public key's hash.
|
||||||
*/
|
*/
|
||||||
@Checkable.String
|
@Checkable.String()
|
||||||
denom_pub_h: string;
|
denom_pub_h: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The signature.
|
* The signature.
|
||||||
*/
|
*/
|
||||||
@Checkable.String
|
@Checkable.String()
|
||||||
auditor_sig: string;
|
auditor_sig: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,13 +142,13 @@ export class Auditor {
|
|||||||
/**
|
/**
|
||||||
* Auditor's public key.
|
* Auditor's public key.
|
||||||
*/
|
*/
|
||||||
@Checkable.String
|
@Checkable.String()
|
||||||
auditor_pub: string;
|
auditor_pub: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base URL of the auditor.
|
* Base URL of the auditor.
|
||||||
*/
|
*/
|
||||||
@Checkable.String
|
@Checkable.String()
|
||||||
auditor_url: string;
|
auditor_url: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -197,20 +200,20 @@ export class PaybackConfirmation {
|
|||||||
/**
|
/**
|
||||||
* public key of the reserve that will receive the payback.
|
* public key of the reserve that will receive the payback.
|
||||||
*/
|
*/
|
||||||
@Checkable.String
|
@Checkable.String()
|
||||||
reserve_pub: string;
|
reserve_pub: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* How much will the exchange pay back (needed by wallet in
|
* How much will the exchange pay back (needed by wallet in
|
||||||
* case coin was partially spent and wallet got restored from backup)
|
* case coin was partially spent and wallet got restored from backup)
|
||||||
*/
|
*/
|
||||||
@Checkable.Value(() => AmountJson)
|
@Checkable.String()
|
||||||
amount: AmountJson;
|
amount: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Time by which the exchange received the /payback request.
|
* Time by which the exchange received the /payback request.
|
||||||
*/
|
*/
|
||||||
@Checkable.String
|
@Checkable.String()
|
||||||
timestamp: string;
|
timestamp: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -220,7 +223,7 @@ export class PaybackConfirmation {
|
|||||||
* by the date specified (this allows the exchange delaying the transfer
|
* by the date specified (this allows the exchange delaying the transfer
|
||||||
* a bit to aggregate additional payback requests into a larger one).
|
* a bit to aggregate additional payback requests into a larger one).
|
||||||
*/
|
*/
|
||||||
@Checkable.String
|
@Checkable.String()
|
||||||
exchange_sig: string;
|
exchange_sig: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -229,7 +232,7 @@ export class PaybackConfirmation {
|
|||||||
* explicitly as the client might otherwise be confused by clock skew as to
|
* explicitly as the client might otherwise be confused by clock skew as to
|
||||||
* which signing key was used.
|
* which signing key was used.
|
||||||
*/
|
*/
|
||||||
@Checkable.String
|
@Checkable.String()
|
||||||
exchange_pub: string;
|
exchange_pub: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -263,7 +266,7 @@ export interface CoinPaySig {
|
|||||||
/**
|
/**
|
||||||
* The amount that is subtracted from this coin with this payment.
|
* The amount that is subtracted from this coin with this payment.
|
||||||
*/
|
*/
|
||||||
contribution: AmountJson;
|
contribution: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* URL of the exchange this coin was withdrawn from.
|
* URL of the exchange this coin was withdrawn from.
|
||||||
@ -281,13 +284,13 @@ export class ExchangeHandle {
|
|||||||
/**
|
/**
|
||||||
* Master public signing key of the exchange.
|
* Master public signing key of the exchange.
|
||||||
*/
|
*/
|
||||||
@Checkable.String
|
@Checkable.String()
|
||||||
master_pub: string;
|
master_pub: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base URL of the exchange.
|
* Base URL of the exchange.
|
||||||
*/
|
*/
|
||||||
@Checkable.String
|
@Checkable.String()
|
||||||
url: string;
|
url: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -312,67 +315,67 @@ export class ContractTerms {
|
|||||||
/**
|
/**
|
||||||
* Hash of the merchant's wire details.
|
* Hash of the merchant's wire details.
|
||||||
*/
|
*/
|
||||||
@Checkable.String
|
@Checkable.String()
|
||||||
H_wire: string;
|
H_wire: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wire method the merchant wants to use.
|
* Wire method the merchant wants to use.
|
||||||
*/
|
*/
|
||||||
@Checkable.String
|
@Checkable.String()
|
||||||
wire_method: string;
|
wire_method: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Human-readable short summary of the contract.
|
* Human-readable short summary of the contract.
|
||||||
*/
|
*/
|
||||||
@Checkable.Optional(Checkable.String)
|
@Checkable.Optional(Checkable.String())
|
||||||
summary?: string;
|
summary?: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Nonce used to ensure freshness.
|
* Nonce used to ensure freshness.
|
||||||
*/
|
*/
|
||||||
@Checkable.Optional(Checkable.String)
|
@Checkable.Optional(Checkable.String())
|
||||||
nonce?: string;
|
nonce?: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Total amount payable.
|
* Total amount payable.
|
||||||
*/
|
*/
|
||||||
@Checkable.Value(() => AmountJson)
|
@Checkable.String(Amounts.check)
|
||||||
amount: AmountJson;
|
amount: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Auditors accepted by the merchant.
|
* Auditors accepted by the merchant.
|
||||||
*/
|
*/
|
||||||
@Checkable.List(Checkable.AnyObject)
|
@Checkable.List(Checkable.AnyObject())
|
||||||
auditors: any[];
|
auditors: any[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deadline to pay for the contract.
|
* Deadline to pay for the contract.
|
||||||
*/
|
*/
|
||||||
@Checkable.Optional(Checkable.String)
|
@Checkable.Optional(Checkable.String())
|
||||||
pay_deadline: string;
|
pay_deadline: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delivery locations.
|
* Delivery locations.
|
||||||
*/
|
*/
|
||||||
@Checkable.Any
|
@Checkable.Any()
|
||||||
locations: any;
|
locations: any;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maximum deposit fee covered by the merchant.
|
* Maximum deposit fee covered by the merchant.
|
||||||
*/
|
*/
|
||||||
@Checkable.Value(() => AmountJson)
|
@Checkable.String(Amounts.check)
|
||||||
max_fee: AmountJson;
|
max_fee: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Information about the merchant.
|
* Information about the merchant.
|
||||||
*/
|
*/
|
||||||
@Checkable.Any
|
@Checkable.Any()
|
||||||
merchant: any;
|
merchant: any;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Public key of the merchant.
|
* Public key of the merchant.
|
||||||
*/
|
*/
|
||||||
@Checkable.String
|
@Checkable.String()
|
||||||
merchant_pub: string;
|
merchant_pub: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -384,57 +387,57 @@ export class ContractTerms {
|
|||||||
/**
|
/**
|
||||||
* Products that are sold in this contract.
|
* Products that are sold in this contract.
|
||||||
*/
|
*/
|
||||||
@Checkable.List(Checkable.AnyObject)
|
@Checkable.List(Checkable.AnyObject())
|
||||||
products: any[];
|
products: any[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deadline for refunds.
|
* Deadline for refunds.
|
||||||
*/
|
*/
|
||||||
@Checkable.String
|
@Checkable.String(timestampCheck)
|
||||||
refund_deadline: string;
|
refund_deadline: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Time when the contract was generated by the merchant.
|
* Time when the contract was generated by the merchant.
|
||||||
*/
|
*/
|
||||||
@Checkable.String
|
@Checkable.String(timestampCheck)
|
||||||
timestamp: string;
|
timestamp: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Order id to uniquely identify the purchase within
|
* Order id to uniquely identify the purchase within
|
||||||
* one merchant instance.
|
* one merchant instance.
|
||||||
*/
|
*/
|
||||||
@Checkable.String
|
@Checkable.String()
|
||||||
order_id: string;
|
order_id: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* URL to post the payment to.
|
* URL to post the payment to.
|
||||||
*/
|
*/
|
||||||
@Checkable.String
|
@Checkable.String()
|
||||||
pay_url: string;
|
pay_url: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fulfillment URL to view the product or
|
* Fulfillment URL to view the product or
|
||||||
* delivery status.
|
* delivery status.
|
||||||
*/
|
*/
|
||||||
@Checkable.String
|
@Checkable.String()
|
||||||
fulfillment_url: string;
|
fulfillment_url: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Share of the wire fee that must be settled with one payment.
|
* 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.
|
* Maximum wire fee that the merchant agrees to pay for.
|
||||||
*/
|
*/
|
||||||
@Checkable.Optional(Checkable.Value(() => AmountJson))
|
@Checkable.Optional(Checkable.String())
|
||||||
max_wire_fee?: AmountJson;
|
max_wire_fee?: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extra data, interpreted by the mechant only.
|
* Extra data, interpreted by the mechant only.
|
||||||
*/
|
*/
|
||||||
@Checkable.Any
|
@Checkable.Any()
|
||||||
extra: any;
|
extra: any;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -480,31 +483,31 @@ export class MerchantRefundPermission {
|
|||||||
/**
|
/**
|
||||||
* Amount to be refunded.
|
* Amount to be refunded.
|
||||||
*/
|
*/
|
||||||
@Checkable.Value(() => AmountJson)
|
@Checkable.String(Amounts.check)
|
||||||
refund_amount: AmountJson;
|
refund_amount: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fee for the refund.
|
* Fee for the refund.
|
||||||
*/
|
*/
|
||||||
@Checkable.Value(() => AmountJson)
|
@Checkable.String(Amounts.check)
|
||||||
refund_fee: AmountJson;
|
refund_fee: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Public key of the coin being refunded.
|
* Public key of the coin being refunded.
|
||||||
*/
|
*/
|
||||||
@Checkable.String
|
@Checkable.String()
|
||||||
coin_pub: string;
|
coin_pub: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Refund transaction ID between merchant and exchange.
|
* Refund transaction ID between merchant and exchange.
|
||||||
*/
|
*/
|
||||||
@Checkable.Number
|
@Checkable.Number()
|
||||||
rtransaction_id: number;
|
rtransaction_id: number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Signature made by the merchant over the refund permission.
|
* Signature made by the merchant over the refund permission.
|
||||||
*/
|
*/
|
||||||
@Checkable.String
|
@Checkable.String()
|
||||||
merchant_sig: string;
|
merchant_sig: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -523,13 +526,13 @@ export interface RefundRequest {
|
|||||||
* coin's total deposit value (including deposit fee);
|
* coin's total deposit value (including deposit fee);
|
||||||
* must be larger than the refund fee.
|
* must be larger than the refund fee.
|
||||||
*/
|
*/
|
||||||
refund_amount: AmountJson;
|
refund_amount: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Refund fee associated with the given coin.
|
* Refund fee associated with the given coin.
|
||||||
* must be smaller than the refund amount.
|
* must be smaller than the refund amount.
|
||||||
*/
|
*/
|
||||||
refund_fee: AmountJson;
|
refund_fee: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SHA-512 hash of the contact of the merchant with the customer.
|
* SHA-512 hash of the contact of the merchant with the customer.
|
||||||
@ -566,14 +569,14 @@ export class MerchantRefundResponse {
|
|||||||
/**
|
/**
|
||||||
* Public key of the merchant
|
* Public key of the merchant
|
||||||
*/
|
*/
|
||||||
@Checkable.String
|
@Checkable.String()
|
||||||
merchant_pub: string;
|
merchant_pub: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contract terms hash of the contract that
|
* Contract terms hash of the contract that
|
||||||
* is being refunded.
|
* is being refunded.
|
||||||
*/
|
*/
|
||||||
@Checkable.String
|
@Checkable.String()
|
||||||
h_contract_terms: string;
|
h_contract_terms: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -629,7 +632,7 @@ export class ReserveSigSingleton {
|
|||||||
/**
|
/**
|
||||||
* Reserve signature.
|
* Reserve signature.
|
||||||
*/
|
*/
|
||||||
@Checkable.String
|
@Checkable.String()
|
||||||
reserve_sig: string;
|
reserve_sig: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -638,6 +641,30 @@ export class ReserveSigSingleton {
|
|||||||
static checked: (obj: any) => ReserveSigSingleton;
|
static checked: (obj: any) => ReserveSigSingleton;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Response to /reserve/status
|
||||||
|
*/
|
||||||
|
@Checkable.Class()
|
||||||
|
export class ReserveStatus {
|
||||||
|
/**
|
||||||
|
* Reserve signature.
|
||||||
|
*/
|
||||||
|
@Checkable.String()
|
||||||
|
balance: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reserve history, currently not used by the wallet.
|
||||||
|
*/
|
||||||
|
@Checkable.Any()
|
||||||
|
history: any;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a ReserveSigSingleton from untyped JSON.
|
||||||
|
*/
|
||||||
|
static checked: (obj: any) => ReserveStatus;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Response of the merchant
|
* Response of the merchant
|
||||||
* to the TipPickupRequest.
|
* to the TipPickupRequest.
|
||||||
@ -647,7 +674,7 @@ export class TipResponse {
|
|||||||
/**
|
/**
|
||||||
* Public key of the reserve
|
* Public key of the reserve
|
||||||
*/
|
*/
|
||||||
@Checkable.String
|
@Checkable.String()
|
||||||
reserve_pub: string;
|
reserve_pub: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -671,37 +698,37 @@ export class TipToken {
|
|||||||
/**
|
/**
|
||||||
* Expiration for the tip.
|
* Expiration for the tip.
|
||||||
*/
|
*/
|
||||||
@Checkable.String
|
@Checkable.String(timestampCheck)
|
||||||
expiration: string;
|
expiration: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* URL of the exchange that the tip can be withdrawn from.
|
* URL of the exchange that the tip can be withdrawn from.
|
||||||
*/
|
*/
|
||||||
@Checkable.String
|
@Checkable.String()
|
||||||
exchange_url: string;
|
exchange_url: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Merchant's URL to pick up the tip.
|
* Merchant's URL to pick up the tip.
|
||||||
*/
|
*/
|
||||||
@Checkable.String
|
@Checkable.String()
|
||||||
pickup_url: string;
|
pickup_url: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Merchant-chosen tip identifier.
|
* Merchant-chosen tip identifier.
|
||||||
*/
|
*/
|
||||||
@Checkable.String
|
@Checkable.String()
|
||||||
tip_id: string;
|
tip_id: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Amount of tip.
|
* Amount of tip.
|
||||||
*/
|
*/
|
||||||
@Checkable.Value(() => AmountJson)
|
@Checkable.String()
|
||||||
amount: AmountJson;
|
amount: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* URL to navigate after finishing tip processing.
|
* URL to navigate after finishing tip processing.
|
||||||
*/
|
*/
|
||||||
@Checkable.String
|
@Checkable.String()
|
||||||
next_url: string;
|
next_url: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -721,7 +748,7 @@ export class Payback {
|
|||||||
/**
|
/**
|
||||||
* The hash of the denomination public key for which the payback is offered.
|
* 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -740,7 +767,7 @@ export class KeysJson {
|
|||||||
/**
|
/**
|
||||||
* The exchange's master public key.
|
* The exchange's master public key.
|
||||||
*/
|
*/
|
||||||
@Checkable.String
|
@Checkable.String()
|
||||||
master_public_key: string;
|
master_public_key: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -752,7 +779,7 @@ export class KeysJson {
|
|||||||
/**
|
/**
|
||||||
* Timestamp when this response was issued.
|
* Timestamp when this response was issued.
|
||||||
*/
|
*/
|
||||||
@Checkable.String
|
@Checkable.String(timestampCheck)
|
||||||
list_issue_date: string;
|
list_issue_date: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -765,13 +792,13 @@ export class KeysJson {
|
|||||||
* Short-lived signing keys used to sign online
|
* Short-lived signing keys used to sign online
|
||||||
* responses.
|
* responses.
|
||||||
*/
|
*/
|
||||||
@Checkable.Any
|
@Checkable.Any()
|
||||||
signkeys: any;
|
signkeys: any;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Protocol version.
|
* Protocol version.
|
||||||
*/
|
*/
|
||||||
@Checkable.Optional(Checkable.String)
|
@Checkable.Optional(Checkable.String())
|
||||||
version?: string;
|
version?: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -790,31 +817,31 @@ export class WireFeesJson {
|
|||||||
/**
|
/**
|
||||||
* Cost of a wire transfer.
|
* Cost of a wire transfer.
|
||||||
*/
|
*/
|
||||||
@Checkable.Value(() => AmountJson)
|
@Checkable.String(Amounts.check)
|
||||||
wire_fee: AmountJson;
|
wire_fee: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cost of clising a reserve.
|
* Cost of clising a reserve.
|
||||||
*/
|
*/
|
||||||
@Checkable.Value(() => AmountJson)
|
@Checkable.String(Amounts.check)
|
||||||
closing_fee: AmountJson;
|
closing_fee: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Signature made with the exchange's master key.
|
* Signature made with the exchange's master key.
|
||||||
*/
|
*/
|
||||||
@Checkable.String
|
@Checkable.String()
|
||||||
sig: string;
|
sig: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Date from which the fee applies.
|
* Date from which the fee applies.
|
||||||
*/
|
*/
|
||||||
@Checkable.String
|
@Checkable.String(timestampCheck)
|
||||||
start_date: string;
|
start_date: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Data after which the fee doesn't apply anymore.
|
* Data after which the fee doesn't apply anymore.
|
||||||
*/
|
*/
|
||||||
@Checkable.String
|
@Checkable.String(timestampCheck)
|
||||||
end_date: string;
|
end_date: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -834,7 +861,7 @@ export class WireDetailJson {
|
|||||||
/**
|
/**
|
||||||
* Name of the wire transfer method.
|
* Name of the wire transfer method.
|
||||||
*/
|
*/
|
||||||
@Checkable.String
|
@Checkable.String()
|
||||||
type: string;
|
type: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -872,7 +899,7 @@ export class Proposal {
|
|||||||
@Checkable.Value(() => ContractTerms)
|
@Checkable.Value(() => ContractTerms)
|
||||||
contract_terms: ContractTerms;
|
contract_terms: ContractTerms;
|
||||||
|
|
||||||
@Checkable.String
|
@Checkable.String()
|
||||||
sig: string;
|
sig: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -54,14 +54,23 @@ test("amount subtraction (saturation)", (t) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
test("amount parsing", (t) => {
|
||||||
|
const a1 = Amounts.parseOrThrow("TESTKUDOS:10");
|
||||||
|
t.is(a1.currency, "TESTKUDOS");
|
||||||
|
t.is(a1.value, 10);
|
||||||
|
t.is(a1.fraction, 0);
|
||||||
|
t.pass();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
test("contract terms validation", (t) => {
|
test("contract terms validation", (t) => {
|
||||||
const c = {
|
const c = {
|
||||||
H_wire: "123",
|
H_wire: "123",
|
||||||
amount: amt(1, 2, "EUR"),
|
amount: "EUR:1.5",
|
||||||
auditors: [],
|
auditors: [],
|
||||||
exchanges: [{master_pub: "foo", url: "foo"}],
|
exchanges: [{master_pub: "foo", url: "foo"}],
|
||||||
fulfillment_url: "foo",
|
fulfillment_url: "foo",
|
||||||
max_fee: amt(1, 2, "EUR"),
|
max_fee: "EUR:1.5",
|
||||||
merchant_pub: "12345",
|
merchant_pub: "12345",
|
||||||
order_id: "test_order",
|
order_id: "test_order",
|
||||||
pay_deadline: "Date(12346)",
|
pay_deadline: "Date(12346)",
|
||||||
|
@ -82,6 +82,7 @@ import {
|
|||||||
PaybackConfirmation,
|
PaybackConfirmation,
|
||||||
Proposal,
|
Proposal,
|
||||||
RefundRequest,
|
RefundRequest,
|
||||||
|
ReserveStatus,
|
||||||
TipPlanchetDetail,
|
TipPlanchetDetail,
|
||||||
TipResponse,
|
TipResponse,
|
||||||
TipToken,
|
TipToken,
|
||||||
@ -825,13 +826,22 @@ export class Wallet {
|
|||||||
return this.submitPay(purchase.contractTermsHash, sessionId);
|
return this.submitPay(purchase.contractTermsHash, sessionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const contractAmount = Amounts.parseOrThrow(proposal.contractTerms.amount);
|
||||||
|
|
||||||
|
let wireFeeLimit;
|
||||||
|
if (!proposal.contractTerms.max_wire_fee) {
|
||||||
|
wireFeeLimit = Amounts.getZero(contractAmount.currency);
|
||||||
|
} else {
|
||||||
|
wireFeeLimit = Amounts.parseOrThrow(proposal.contractTerms.max_wire_fee);
|
||||||
|
}
|
||||||
|
|
||||||
const res = await this.getCoinsForPayment({
|
const res = await this.getCoinsForPayment({
|
||||||
allowedAuditors: proposal.contractTerms.auditors,
|
allowedAuditors: proposal.contractTerms.auditors,
|
||||||
allowedExchanges: proposal.contractTerms.exchanges,
|
allowedExchanges: proposal.contractTerms.exchanges,
|
||||||
depositFeeLimit: proposal.contractTerms.max_fee,
|
depositFeeLimit: Amounts.parseOrThrow(proposal.contractTerms.max_fee),
|
||||||
paymentAmount: proposal.contractTerms.amount,
|
paymentAmount: Amounts.parseOrThrow(proposal.contractTerms.amount),
|
||||||
wireFeeAmortization: proposal.contractTerms.wire_fee_amortization || 1,
|
wireFeeAmortization: proposal.contractTerms.wire_fee_amortization || 1,
|
||||||
wireFeeLimit: proposal.contractTerms.max_wire_fee || Amounts.getZero(proposal.contractTerms.amount.currency),
|
wireFeeLimit,
|
||||||
wireFeeTime: getTalerStampSec(proposal.contractTerms.timestamp) || 0,
|
wireFeeTime: getTalerStampSec(proposal.contractTerms.timestamp) || 0,
|
||||||
wireMethod: proposal.contractTerms.wire_method,
|
wireMethod: proposal.contractTerms.wire_method,
|
||||||
});
|
});
|
||||||
@ -907,14 +917,23 @@ export class Wallet {
|
|||||||
return { status: "paid" };
|
return { status: "paid" };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const paymentAmount = Amounts.parseOrThrow(proposal.contractTerms.amount);
|
||||||
|
|
||||||
|
let wireFeeLimit;
|
||||||
|
if (proposal.contractTerms.max_wire_fee) {
|
||||||
|
wireFeeLimit = Amounts.parseOrThrow(proposal.contractTerms.max_wire_fee);
|
||||||
|
} else {
|
||||||
|
wireFeeLimit = Amounts.getZero(paymentAmount.currency);
|
||||||
|
}
|
||||||
|
|
||||||
// If not already payed, check if we could pay for it.
|
// If not already payed, check if we could pay for it.
|
||||||
const res = await this.getCoinsForPayment({
|
const res = await this.getCoinsForPayment({
|
||||||
allowedAuditors: proposal.contractTerms.auditors,
|
allowedAuditors: proposal.contractTerms.auditors,
|
||||||
allowedExchanges: proposal.contractTerms.exchanges,
|
allowedExchanges: proposal.contractTerms.exchanges,
|
||||||
depositFeeLimit: proposal.contractTerms.max_fee,
|
depositFeeLimit: Amounts.parseOrThrow(proposal.contractTerms.max_fee),
|
||||||
paymentAmount: proposal.contractTerms.amount,
|
paymentAmount,
|
||||||
wireFeeAmortization: proposal.contractTerms.wire_fee_amortization || 1,
|
wireFeeAmortization: proposal.contractTerms.wire_fee_amortization || 1,
|
||||||
wireFeeLimit: proposal.contractTerms.max_wire_fee || Amounts.getZero(proposal.contractTerms.amount.currency),
|
wireFeeLimit,
|
||||||
wireFeeTime: getTalerStampSec(proposal.contractTerms.timestamp) || 0,
|
wireFeeTime: getTalerStampSec(proposal.contractTerms.timestamp) || 0,
|
||||||
wireMethod: proposal.contractTerms.wire_method,
|
wireMethod: proposal.contractTerms.wire_method,
|
||||||
});
|
});
|
||||||
@ -1243,8 +1262,8 @@ export class Wallet {
|
|||||||
denom.value,
|
denom.value,
|
||||||
denom.feeWithdraw).amount;
|
denom.feeWithdraw).amount;
|
||||||
const result = Amounts.sub(currentAmount,
|
const result = Amounts.sub(currentAmount,
|
||||||
denom.value,
|
denom.value,
|
||||||
denom.feeWithdraw);
|
denom.feeWithdraw);
|
||||||
if (result.saturated) {
|
if (result.saturated) {
|
||||||
console.error("can't create precoin, saturated");
|
console.error("can't create precoin, saturated");
|
||||||
throw AbortTransaction;
|
throw AbortTransaction;
|
||||||
@ -1290,11 +1309,11 @@ export class Wallet {
|
|||||||
if (resp.status !== 200) {
|
if (resp.status !== 200) {
|
||||||
throw Error();
|
throw Error();
|
||||||
}
|
}
|
||||||
const reserveInfo = JSON.parse(resp.responseText);
|
const reserveInfo = ReserveStatus.checked(JSON.parse(resp.responseText));
|
||||||
if (!reserveInfo) {
|
if (!reserveInfo) {
|
||||||
throw Error();
|
throw Error();
|
||||||
}
|
}
|
||||||
reserve.current_amount = reserveInfo.balance;
|
reserve.current_amount = Amounts.parseOrThrow(reserveInfo.balance);
|
||||||
await this.q()
|
await this.q()
|
||||||
.put(Stores.reserves, reserve)
|
.put(Stores.reserves, reserve)
|
||||||
.finish();
|
.finish();
|
||||||
@ -1613,7 +1632,7 @@ export class Wallet {
|
|||||||
exchangeInfo = {
|
exchangeInfo = {
|
||||||
auditors: exchangeKeysJson.auditors,
|
auditors: exchangeKeysJson.auditors,
|
||||||
baseUrl,
|
baseUrl,
|
||||||
currency: exchangeKeysJson.denoms[0].value.currency,
|
currency: Amounts.parseOrThrow(exchangeKeysJson.denoms[0].value).currency,
|
||||||
lastUpdateTime: updateTimeSec,
|
lastUpdateTime: updateTimeSec,
|
||||||
lastUsedTime: 0,
|
lastUsedTime: 0,
|
||||||
masterPublicKey: exchangeKeysJson.master_public_key,
|
masterPublicKey: exchangeKeysJson.master_public_key,
|
||||||
@ -1670,11 +1689,11 @@ export class Wallet {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const wf: WireFee = {
|
const wf: WireFee = {
|
||||||
closingFee: fee.closing_fee,
|
closingFee: Amounts.parseOrThrow(fee.closing_fee),
|
||||||
endStamp: end,
|
endStamp: end,
|
||||||
sig: fee.sig,
|
sig: fee.sig,
|
||||||
startStamp: start,
|
startStamp: start,
|
||||||
wireFee: fee.wire_fee,
|
wireFee: Amounts.parseOrThrow(fee.wire_fee),
|
||||||
};
|
};
|
||||||
const valid: boolean = await this.cryptoApi.isValidWireFee(detail.type, wf, exchangeInfo.masterPublicKey);
|
const valid: boolean = await this.cryptoApi.isValidWireFee(detail.type, wf, exchangeInfo.masterPublicKey);
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
@ -1829,7 +1848,7 @@ export class Wallet {
|
|||||||
return balance;
|
return balance;
|
||||||
}
|
}
|
||||||
for (const c of t.payReq.coins) {
|
for (const c of t.payReq.coins) {
|
||||||
addTo(balance, "pendingIncoming", c.contribution, c.exchange_url);
|
addTo(balance, "pendingIncoming", Amounts.parseOrThrow(c.contribution), c.exchange_url);
|
||||||
}
|
}
|
||||||
return balance;
|
return balance;
|
||||||
}
|
}
|
||||||
@ -2180,10 +2199,17 @@ export class Wallet {
|
|||||||
type: "pay",
|
type: "pay",
|
||||||
});
|
});
|
||||||
if (p.timestamp_refund) {
|
if (p.timestamp_refund) {
|
||||||
const amountsPending = Object.keys(p.refundsPending).map((x) => p.refundsPending[x].refund_amount);
|
const contractAmount = Amounts.parseOrThrow(p.contractTerms.amount);
|
||||||
const amountsDone = Object.keys(p.refundsDone).map((x) => p.refundsDone[x].refund_amount);
|
const amountsPending = (
|
||||||
|
Object.keys(p.refundsPending)
|
||||||
|
.map((x) => Amounts.parseOrThrow(p.refundsPending[x].refund_amount))
|
||||||
|
);
|
||||||
|
const amountsDone = (
|
||||||
|
Object.keys(p.refundsDone)
|
||||||
|
.map((x) => Amounts.parseOrThrow(p.refundsDone[x].refund_amount))
|
||||||
|
);
|
||||||
const amounts: AmountJson[] = amountsPending.concat(amountsDone);
|
const amounts: AmountJson[] = amountsPending.concat(amountsDone);
|
||||||
const amount = Amounts.add(Amounts.getZero(p.contractTerms.amount.currency), ...amounts).amount;
|
const amount = Amounts.add(Amounts.getZero(contractAmount.currency), ...amounts).amount;
|
||||||
|
|
||||||
history.push({
|
history.push({
|
||||||
detail: {
|
detail: {
|
||||||
@ -2357,10 +2383,10 @@ export class Wallet {
|
|||||||
denomPub: denomIn.denom_pub,
|
denomPub: denomIn.denom_pub,
|
||||||
denomPubHash,
|
denomPubHash,
|
||||||
exchangeBaseUrl,
|
exchangeBaseUrl,
|
||||||
feeDeposit: denomIn.fee_deposit,
|
feeDeposit: Amounts.parseOrThrow(denomIn.fee_deposit),
|
||||||
feeRefresh: denomIn.fee_refresh,
|
feeRefresh: Amounts.parseOrThrow(denomIn.fee_refresh),
|
||||||
feeRefund: denomIn.fee_refund,
|
feeRefund: Amounts.parseOrThrow(denomIn.fee_refund),
|
||||||
feeWithdraw: denomIn.fee_withdraw,
|
feeWithdraw: Amounts.parseOrThrow(denomIn.fee_withdraw),
|
||||||
isOffered: true,
|
isOffered: true,
|
||||||
masterSig: denomIn.master_sig,
|
masterSig: denomIn.master_sig,
|
||||||
stampExpireDeposit: denomIn.stamp_expire_deposit,
|
stampExpireDeposit: denomIn.stamp_expire_deposit,
|
||||||
@ -2368,7 +2394,7 @@ export class Wallet {
|
|||||||
stampExpireWithdraw: denomIn.stamp_expire_withdraw,
|
stampExpireWithdraw: denomIn.stamp_expire_withdraw,
|
||||||
stampStart: denomIn.stamp_start,
|
stampStart: denomIn.stamp_start,
|
||||||
status: DenominationStatus.Unverified,
|
status: DenominationStatus.Unverified,
|
||||||
value: denomIn.value,
|
value: Amounts.parseOrThrow(denomIn.value),
|
||||||
};
|
};
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
@ -2449,13 +2475,13 @@ export class Wallet {
|
|||||||
|
|
||||||
const contractTerms: ContractTerms = {
|
const contractTerms: ContractTerms = {
|
||||||
H_wire: wireHash,
|
H_wire: wireHash,
|
||||||
amount: req.amount,
|
amount: Amounts.toString(req.amount),
|
||||||
auditors: [],
|
auditors: [],
|
||||||
exchanges: [ { master_pub: exchange.masterPublicKey, url: exchange.baseUrl } ],
|
exchanges: [ { master_pub: exchange.masterPublicKey, url: exchange.baseUrl } ],
|
||||||
extra: {},
|
extra: {},
|
||||||
fulfillment_url: "",
|
fulfillment_url: "",
|
||||||
locations: [],
|
locations: [],
|
||||||
max_fee: req.amount,
|
max_fee: Amounts.toString(req.amount),
|
||||||
merchant: {},
|
merchant: {},
|
||||||
merchant_pub: pub,
|
merchant_pub: pub,
|
||||||
order_id: "none",
|
order_id: "none",
|
||||||
@ -2469,7 +2495,9 @@ export class Wallet {
|
|||||||
|
|
||||||
const contractTermsHash = await this.cryptoApi.hashString(canonicalJson(contractTerms));
|
const contractTermsHash = await this.cryptoApi.hashString(canonicalJson(contractTerms));
|
||||||
|
|
||||||
const payCoinInfo = await this.cryptoApi.signDeposit(contractTerms, cds, contractTerms.amount);
|
const payCoinInfo = await (
|
||||||
|
this.cryptoApi.signDeposit(contractTerms, cds, Amounts.parseOrThrow(contractTerms.amount))
|
||||||
|
);
|
||||||
|
|
||||||
console.log("pci", payCoinInfo);
|
console.log("pci", payCoinInfo);
|
||||||
|
|
||||||
@ -2660,9 +2688,11 @@ export class Wallet {
|
|||||||
console.warn("coin not found, can't apply refund");
|
console.warn("coin not found, can't apply refund");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const refundAmount = Amounts.parseOrThrow(perm.refund_amount);
|
||||||
|
const refundFee = Amounts.parseOrThrow(perm.refund_fee);
|
||||||
c.status = CoinStatus.Dirty;
|
c.status = CoinStatus.Dirty;
|
||||||
c.currentAmount = Amounts.add(c.currentAmount, perm.refund_amount).amount;
|
c.currentAmount = Amounts.add(c.currentAmount, refundAmount).amount;
|
||||||
c.currentAmount = Amounts.sub(c.currentAmount, perm.refund_fee).amount;
|
c.currentAmount = Amounts.sub(c.currentAmount, refundFee).amount;
|
||||||
|
|
||||||
return c;
|
return c;
|
||||||
};
|
};
|
||||||
@ -2690,7 +2720,7 @@ export class Wallet {
|
|||||||
if (!coin0) {
|
if (!coin0) {
|
||||||
throw Error("coin not found");
|
throw Error("coin not found");
|
||||||
}
|
}
|
||||||
let feeAcc = Amounts.getZero(refundPermissions[0].refund_amount.currency);
|
let feeAcc = Amounts.getZero(Amounts.parseOrThrow(refundPermissions[0].refund_amount).currency);
|
||||||
|
|
||||||
const denoms = await this.q().iterIndex(Stores.denominations.exchangeBaseUrlIndex, coin0.exchangeBaseUrl).toArray();
|
const denoms = await this.q().iterIndex(Stores.denominations.exchangeBaseUrlIndex, coin0.exchangeBaseUrl).toArray();
|
||||||
for (const rp of refundPermissions) {
|
for (const rp of refundPermissions) {
|
||||||
@ -2706,8 +2736,10 @@ export class Wallet {
|
|||||||
// When it hasn't, the refresh cost is inaccurate. To fix this,
|
// When it hasn't, the refresh cost is inaccurate. To fix this,
|
||||||
// we need introduce a flag to tell if a coin was refunded or
|
// we need introduce a flag to tell if a coin was refunded or
|
||||||
// refreshed normally (and what about incremental refunds?)
|
// refreshed normally (and what about incremental refunds?)
|
||||||
const refreshCost = getTotalRefreshCost(denoms, denom, Amounts.sub(rp.refund_amount, rp.refund_fee).amount);
|
const refundAmount = Amounts.parseOrThrow(rp.refund_amount);
|
||||||
feeAcc = Amounts.add(feeAcc, refreshCost, rp.refund_fee).amount;
|
const refundFee = Amounts.parseOrThrow(rp.refund_fee);
|
||||||
|
const refreshCost = getTotalRefreshCost(denoms, denom, Amounts.sub(refundAmount, refundFee).amount);
|
||||||
|
feeAcc = Amounts.add(feeAcc, refreshCost, refundFee).amount;
|
||||||
}
|
}
|
||||||
return feeAcc;
|
return feeAcc;
|
||||||
}
|
}
|
||||||
@ -2731,14 +2763,15 @@ export class Wallet {
|
|||||||
if (tipRecord && tipRecord.pickedUp) {
|
if (tipRecord && tipRecord.pickedUp) {
|
||||||
return tipRecord;
|
return tipRecord;
|
||||||
}
|
}
|
||||||
|
const tipAmount = Amounts.parseOrThrow(tipToken.amount);
|
||||||
await this.updateExchangeFromUrl(tipToken.exchange_url);
|
await this.updateExchangeFromUrl(tipToken.exchange_url);
|
||||||
const denomsForWithdraw = await this.getVerifiedWithdrawDenomList(tipToken.exchange_url, tipToken.amount);
|
const denomsForWithdraw = await this.getVerifiedWithdrawDenomList(tipToken.exchange_url, tipAmount);
|
||||||
const planchets = await Promise.all(denomsForWithdraw.map(d => this.cryptoApi.createTipPlanchet(d)));
|
const planchets = await Promise.all(denomsForWithdraw.map(d => this.cryptoApi.createTipPlanchet(d)));
|
||||||
const coinPubs: string[] = planchets.map(x => x.coinPub);
|
const coinPubs: string[] = planchets.map(x => x.coinPub);
|
||||||
const now = (new Date()).getTime();
|
const now = (new Date()).getTime();
|
||||||
tipRecord = {
|
tipRecord = {
|
||||||
accepted: false,
|
accepted: false,
|
||||||
amount: tipToken.amount,
|
amount: Amounts.parseOrThrow(tipToken.amount),
|
||||||
coinPubs,
|
coinPubs,
|
||||||
deadline: deadlineSec,
|
deadline: deadlineSec,
|
||||||
exchangeUrl: tipToken.exchange_url,
|
exchangeUrl: tipToken.exchange_url,
|
||||||
|
@ -53,13 +53,13 @@ export class CreateReserveResponse {
|
|||||||
* Exchange 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()
|
||||||
exchange: string;
|
exchange: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reserve public key of the newly created reserve.
|
* Reserve public key of the newly created reserve.
|
||||||
*/
|
*/
|
||||||
@Checkable.String
|
@Checkable.String()
|
||||||
reservePub: string;
|
reservePub: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -333,13 +333,13 @@ export class CreateReserveRequest {
|
|||||||
/**
|
/**
|
||||||
* Exchange URL where the bank should create the reserve.
|
* Exchange URL where the bank should create the reserve.
|
||||||
*/
|
*/
|
||||||
@Checkable.String
|
@Checkable.String()
|
||||||
exchange: string;
|
exchange: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wire details for the bank account that sent the funds to the exchange.
|
* Wire details for the bank account that sent the funds to the exchange.
|
||||||
*/
|
*/
|
||||||
@Checkable.Optional(Checkable.Any)
|
@Checkable.Optional(Checkable.Any())
|
||||||
senderWire?: object;
|
senderWire?: object;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -359,7 +359,7 @@ export class ConfirmReserveRequest {
|
|||||||
* Public key of then reserve that should be marked
|
* Public key of then reserve that should be marked
|
||||||
* as confirmed.
|
* as confirmed.
|
||||||
*/
|
*/
|
||||||
@Checkable.String
|
@Checkable.String()
|
||||||
reservePub: string;
|
reservePub: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -384,14 +384,14 @@ export class ReturnCoinsRequest {
|
|||||||
/**
|
/**
|
||||||
* The exchange to take the coins from.
|
* The exchange to take the coins from.
|
||||||
*/
|
*/
|
||||||
@Checkable.String
|
@Checkable.String()
|
||||||
exchange: string;
|
exchange: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wire details for the bank account of the customer that will
|
* Wire details for the bank account of the customer that will
|
||||||
* receive the funds.
|
* receive the funds.
|
||||||
*/
|
*/
|
||||||
@Checkable.Any
|
@Checkable.Any()
|
||||||
senderWire?: object;
|
senderWire?: object;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -42,6 +42,8 @@ import * as ReactDOM from "react-dom";
|
|||||||
import URI = require("urijs");
|
import URI = require("urijs");
|
||||||
import { WalletApiError } from "../wxApi";
|
import { WalletApiError } from "../wxApi";
|
||||||
|
|
||||||
|
import * as Amounts from "../../amounts";
|
||||||
|
|
||||||
|
|
||||||
interface DetailState {
|
interface DetailState {
|
||||||
collapsed: boolean;
|
collapsed: boolean;
|
||||||
@ -294,7 +296,7 @@ class ContractPrompt extends React.Component<ContractPromptProps, ContractPrompt
|
|||||||
} else {
|
} else {
|
||||||
merchantName = <strong>(pub: {c.merchant_pub})</strong>;
|
merchantName = <strong>(pub: {c.merchant_pub})</strong>;
|
||||||
}
|
}
|
||||||
const amount = <strong>{renderAmount(c.amount)}</strong>;
|
const amount = <strong>{renderAmount(Amounts.parseOrThrow(c.amount))}</strong>;
|
||||||
console.log("payStatus", this.state.payStatus);
|
console.log("payStatus", this.state.payStatus);
|
||||||
|
|
||||||
let products = null;
|
let products = null;
|
||||||
|
@ -38,11 +38,11 @@ import {
|
|||||||
|
|
||||||
import { ImplicitStateComponent, StateHolder } from "../components";
|
import { ImplicitStateComponent, StateHolder } from "../components";
|
||||||
import {
|
import {
|
||||||
|
WalletApiError,
|
||||||
createReserve,
|
createReserve,
|
||||||
getCurrency,
|
getCurrency,
|
||||||
getExchangeInfo,
|
getExchangeInfo,
|
||||||
getReserveCreationInfo,
|
getReserveCreationInfo,
|
||||||
WalletApiError,
|
|
||||||
} from "../wxApi";
|
} from "../wxApi";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
@ -59,18 +59,24 @@ const RefundDetail = ({purchase, fullRefundFees}: RefundDetailProps) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const firstRefundKey = [...pendingKeys, ...doneKeys][0];
|
const firstRefundKey = [...pendingKeys, ...doneKeys][0];
|
||||||
const currency = { ...purchase.refundsDone, ...purchase.refundsPending }[firstRefundKey].refund_amount.currency;
|
if (!firstRefundKey) {
|
||||||
|
return <p>Waiting for refunds ...</p>;
|
||||||
|
}
|
||||||
|
const allRefunds = { ...purchase.refundsDone, ...purchase.refundsPending };
|
||||||
|
const currency = Amounts.parseOrThrow(allRefunds[firstRefundKey].refund_amount).currency;
|
||||||
if (!currency) {
|
if (!currency) {
|
||||||
throw Error("invariant");
|
throw Error("invariant");
|
||||||
}
|
}
|
||||||
|
|
||||||
let amountPending = Amounts.getZero(currency);
|
let amountPending = Amounts.getZero(currency);
|
||||||
for (const k of pendingKeys) {
|
for (const k of pendingKeys) {
|
||||||
amountPending = Amounts.add(amountPending, purchase.refundsPending[k].refund_amount).amount;
|
const refundAmount = Amounts.parseOrThrow(purchase.refundsPending[k].refund_amount);
|
||||||
|
amountPending = Amounts.add(amountPending, refundAmount).amount;
|
||||||
}
|
}
|
||||||
let amountDone = Amounts.getZero(currency);
|
let amountDone = Amounts.getZero(currency);
|
||||||
for (const k of doneKeys) {
|
for (const k of doneKeys) {
|
||||||
amountDone = Amounts.add(amountDone, purchase.refundsDone[k].refund_amount).amount;
|
const refundAmount = Amounts.parseOrThrow(purchase.refundsDone[k].refund_amount);
|
||||||
|
amountDone = Amounts.add(amountDone, refundAmount).amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
const hasPending = amountPending.fraction !== 0 || amountPending.value !== 0;
|
const hasPending = amountPending.fraction !== 0 || amountPending.value !== 0;
|
||||||
@ -130,7 +136,7 @@ class RefundStatusView extends React.Component<RefundStatusViewProps, RefundStat
|
|||||||
Status of purchase <strong>{summary}</strong> from merchant <strong>{merchantName}</strong>{" "}
|
Status of purchase <strong>{summary}</strong> from merchant <strong>{merchantName}</strong>{" "}
|
||||||
(order id {purchase.contractTerms.order_id}).
|
(order id {purchase.contractTerms.order_id}).
|
||||||
</p>
|
</p>
|
||||||
<p>Total amount: <AmountDisplay amount={purchase.contractTerms.amount} /></p>
|
<p>Total amount: <AmountDisplay amount={Amounts.parseOrThrow(purchase.contractTerms.amount)} /></p>
|
||||||
{purchase.finished
|
{purchase.finished
|
||||||
? <RefundDetail purchase={purchase} fullRefundFees={this.state.refundFees!} />
|
? <RefundDetail purchase={purchase} fullRefundFees={this.state.refundFees!} />
|
||||||
: <p>Purchase not completed.</p>}
|
: <p>Purchase not completed.</p>}
|
||||||
@ -147,12 +153,15 @@ class RefundStatusView extends React.Component<RefundStatusViewProps, RefundStat
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
contractTermsHash = await wxApi.acceptRefund(refundUrl);
|
contractTermsHash = await wxApi.acceptRefund(refundUrl);
|
||||||
|
this.setState({ contractTermsHash });
|
||||||
}
|
}
|
||||||
const purchase = await wxApi.getPurchase(contractTermsHash);
|
const purchase = await wxApi.getPurchase(contractTermsHash);
|
||||||
console.log("got purchase", purchase);
|
console.log("got purchase", purchase);
|
||||||
const refundsDone = Object.keys(purchase.refundsDone).map((x) => purchase.refundsDone[x]);
|
const refundsDone = Object.keys(purchase.refundsDone).map((x) => purchase.refundsDone[x]);
|
||||||
const refundFees = await wxApi.getFullRefundFees( {refundPermissions: refundsDone });
|
if (refundsDone.length) {
|
||||||
this.setState({ purchase, gotResult: true, refundFees });
|
const refundFees = await wxApi.getFullRefundFees({ refundPermissions: refundsDone });
|
||||||
|
this.setState({ purchase, gotResult: true, refundFees });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,6 +54,7 @@
|
|||||||
"src/walletTypes.ts",
|
"src/walletTypes.ts",
|
||||||
"src/webex/background.ts",
|
"src/webex/background.ts",
|
||||||
"src/webex/chromeBadge.ts",
|
"src/webex/chromeBadge.ts",
|
||||||
|
"src/webex/compat.ts",
|
||||||
"src/webex/components.ts",
|
"src/webex/components.ts",
|
||||||
"src/webex/messages.ts",
|
"src/webex/messages.ts",
|
||||||
"src/webex/notify.ts",
|
"src/webex/notify.ts",
|
||||||
|
Loading…
Reference in New Issue
Block a user