implement payto URIs
This commit is contained in:
parent
3db38fbd0b
commit
6904c2759e
@ -34,7 +34,6 @@ import {
|
|||||||
MerchantRefundPermission,
|
MerchantRefundPermission,
|
||||||
PayReq,
|
PayReq,
|
||||||
TipResponse,
|
TipResponse,
|
||||||
WireDetail,
|
|
||||||
} from "./talerTypes";
|
} from "./talerTypes";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@ -114,10 +113,10 @@ export interface ReserveRecord {
|
|||||||
hasPayback: boolean;
|
hasPayback: boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wire information for the bank account that
|
* Wire information (as payto URI) for the bank account that
|
||||||
* transfered funds for this reserve.
|
* transfered funds for this reserve.
|
||||||
*/
|
*/
|
||||||
senderWire?: object;
|
senderWire?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -837,15 +836,7 @@ export interface PurchaseRecord {
|
|||||||
* Information about wire information for bank accounts we withdrew coins from.
|
* Information about wire information for bank accounts we withdrew coins from.
|
||||||
*/
|
*/
|
||||||
export interface SenderWireRecord {
|
export interface SenderWireRecord {
|
||||||
/**
|
paytoUri: string;
|
||||||
* Wire details.
|
|
||||||
*/
|
|
||||||
senderWire: WireDetail;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Identifier, hash code of canonicalized senderWire.
|
|
||||||
*/
|
|
||||||
id: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1001,7 +992,7 @@ export namespace Stores {
|
|||||||
|
|
||||||
class SenderWiresStore extends Store<SenderWireRecord> {
|
class SenderWiresStore extends Store<SenderWireRecord> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super("senderWires", { keyPath: "id" });
|
super("senderWires", { keyPath: "paytoUri" });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -235,7 +235,7 @@ msgstr ""
|
|||||||
|
|
||||||
#. #-#-#-#-# - (PACKAGE VERSION) #-#-#-#-#
|
#. #-#-#-#-# - (PACKAGE VERSION) #-#-#-#-#
|
||||||
#. TODO:generic error reporting function or component.
|
#. TODO:generic error reporting function or component.
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:511 src/webex/pages/tip.tsx:180
|
#: src/webex/pages/confirm-create-reserve.tsx:515 src/webex/pages/tip.tsx:180
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Fatal error: \"%1$s\"."
|
msgid "Fatal error: \"%1$s\"."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -235,7 +235,7 @@ msgstr ""
|
|||||||
|
|
||||||
#. #-#-#-#-# - (PACKAGE VERSION) #-#-#-#-#
|
#. #-#-#-#-# - (PACKAGE VERSION) #-#-#-#-#
|
||||||
#. TODO:generic error reporting function or component.
|
#. TODO:generic error reporting function or component.
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:511 src/webex/pages/tip.tsx:180
|
#: src/webex/pages/confirm-create-reserve.tsx:515 src/webex/pages/tip.tsx:180
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Fatal error: \"%1$s\"."
|
msgid "Fatal error: \"%1$s\"."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -235,7 +235,7 @@ msgstr ""
|
|||||||
|
|
||||||
#. #-#-#-#-# - (PACKAGE VERSION) #-#-#-#-#
|
#. #-#-#-#-# - (PACKAGE VERSION) #-#-#-#-#
|
||||||
#. TODO:generic error reporting function or component.
|
#. TODO:generic error reporting function or component.
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:511 src/webex/pages/tip.tsx:180
|
#: src/webex/pages/confirm-create-reserve.tsx:515 src/webex/pages/tip.tsx:180
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Fatal error: \"%1$s\"."
|
msgid "Fatal error: \"%1$s\"."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -235,7 +235,7 @@ msgstr ""
|
|||||||
|
|
||||||
#. #-#-#-#-# - (PACKAGE VERSION) #-#-#-#-#
|
#. #-#-#-#-# - (PACKAGE VERSION) #-#-#-#-#
|
||||||
#. TODO:generic error reporting function or component.
|
#. TODO:generic error reporting function or component.
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:511 src/webex/pages/tip.tsx:180
|
#: src/webex/pages/confirm-create-reserve.tsx:515 src/webex/pages/tip.tsx:180
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Fatal error: \"%1$s\"."
|
msgid "Fatal error: \"%1$s\"."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -239,7 +239,7 @@ msgstr ""
|
|||||||
|
|
||||||
#. #-#-#-#-# - (PACKAGE VERSION) #-#-#-#-#
|
#. #-#-#-#-# - (PACKAGE VERSION) #-#-#-#-#
|
||||||
#. TODO:generic error reporting function or component.
|
#. TODO:generic error reporting function or component.
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:511 src/webex/pages/tip.tsx:180
|
#: src/webex/pages/confirm-create-reserve.tsx:515 src/webex/pages/tip.tsx:180
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Fatal error: \"%1$s\"."
|
msgid "Fatal error: \"%1$s\"."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -235,7 +235,7 @@ msgstr ""
|
|||||||
|
|
||||||
#. #-#-#-#-# - (PACKAGE VERSION) #-#-#-#-#
|
#. #-#-#-#-# - (PACKAGE VERSION) #-#-#-#-#
|
||||||
#. TODO:generic error reporting function or component.
|
#. TODO:generic error reporting function or component.
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:511 src/webex/pages/tip.tsx:180
|
#: src/webex/pages/confirm-create-reserve.tsx:515 src/webex/pages/tip.tsx:180
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Fatal error: \"%1$s\"."
|
msgid "Fatal error: \"%1$s\"."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -852,29 +852,25 @@ export class WireFeesJson {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
@Checkable.Class()
|
||||||
* Information about wire transfer methods supported
|
export class AccountInfo {
|
||||||
* by the exchange.
|
|
||||||
*/
|
|
||||||
@Checkable.Class({extra: true})
|
|
||||||
export class WireDetailJson {
|
|
||||||
/**
|
|
||||||
* Name of the wire transfer method.
|
|
||||||
*/
|
|
||||||
@Checkable.String()
|
@Checkable.String()
|
||||||
type: string;
|
url: string;
|
||||||
|
|
||||||
/**
|
@Checkable.String()
|
||||||
* Fees associated with the wire transfer method.
|
master_sig: string;
|
||||||
*/
|
}
|
||||||
@Checkable.List(Checkable.Value(() => WireFeesJson))
|
|
||||||
fees: WireFeesJson[];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Verify that a value matches the schema of this class and convert it into a
|
@Checkable.Class({extra: true})
|
||||||
* member.
|
export class ExchangeWireJson {
|
||||||
*/
|
@Checkable.Map(Checkable.String(), Checkable.List(Checkable.Value(() => WireFeesJson)))
|
||||||
static checked: (obj: any) => WireDetailJson;
|
fees: { [methodName: string]: WireFeesJson[] };
|
||||||
|
|
||||||
|
@Checkable.List(Checkable.Value(() => AccountInfo))
|
||||||
|
accounts: AccountInfo[];
|
||||||
|
|
||||||
|
static checked: (obj: any) => ExchangeWireJson;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -884,12 +880,6 @@ export class WireDetailJson {
|
|||||||
*/
|
*/
|
||||||
export type WireDetail = object & { type: string };
|
export type WireDetail = object & { type: string };
|
||||||
|
|
||||||
/**
|
|
||||||
* Type guard for wire details.
|
|
||||||
*/
|
|
||||||
export function isWireDetail(x: any): x is WireDetail {
|
|
||||||
return x && typeof x === "object" && typeof x.type === "string";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Proposal returned from the contract URL.
|
* Proposal returned from the contract URL.
|
||||||
|
@ -28,7 +28,6 @@ import {
|
|||||||
canonicalJson,
|
canonicalJson,
|
||||||
canonicalizeBaseUrl,
|
canonicalizeBaseUrl,
|
||||||
getTalerStampSec,
|
getTalerStampSec,
|
||||||
hash,
|
|
||||||
strcmp,
|
strcmp,
|
||||||
} from "./helpers";
|
} from "./helpers";
|
||||||
import {
|
import {
|
||||||
@ -75,6 +74,7 @@ import {
|
|||||||
ContractTerms,
|
ContractTerms,
|
||||||
Denomination,
|
Denomination,
|
||||||
ExchangeHandle,
|
ExchangeHandle,
|
||||||
|
ExchangeWireJson,
|
||||||
KeysJson,
|
KeysJson,
|
||||||
MerchantRefundPermission,
|
MerchantRefundPermission,
|
||||||
MerchantRefundResponse,
|
MerchantRefundResponse,
|
||||||
@ -86,8 +86,6 @@ import {
|
|||||||
TipPlanchetDetail,
|
TipPlanchetDetail,
|
||||||
TipResponse,
|
TipResponse,
|
||||||
TipToken,
|
TipToken,
|
||||||
WireDetailJson,
|
|
||||||
isWireDetail,
|
|
||||||
} from "./talerTypes";
|
} from "./talerTypes";
|
||||||
import {
|
import {
|
||||||
Badge,
|
Badge,
|
||||||
@ -109,7 +107,6 @@ import {
|
|||||||
TipStatus,
|
TipStatus,
|
||||||
WalletBalance,
|
WalletBalance,
|
||||||
WalletBalanceEntry,
|
WalletBalanceEntry,
|
||||||
WireInfo,
|
|
||||||
} from "./walletTypes";
|
} from "./walletTypes";
|
||||||
|
|
||||||
|
|
||||||
@ -1133,10 +1130,9 @@ export class Wallet {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const senderWire = req.senderWire;
|
const senderWire = req.senderWire;
|
||||||
if (isWireDetail(senderWire)) {
|
if (senderWire) {
|
||||||
const rec = {
|
const rec = {
|
||||||
id: hash(senderWire),
|
paytoUri: senderWire,
|
||||||
senderWire,
|
|
||||||
};
|
};
|
||||||
await this.q().put(Stores.senderWires, rec).finish();
|
await this.q().put(Stores.senderWires, rec).finish();
|
||||||
}
|
}
|
||||||
@ -1327,7 +1323,7 @@ export class Wallet {
|
|||||||
/**
|
/**
|
||||||
* Get the wire information for the exchange with the given base URL.
|
* Get the wire information for the exchange with the given base URL.
|
||||||
*/
|
*/
|
||||||
async getWireInfo(exchangeBaseUrl: string): Promise<WireInfo> {
|
async getWireInfo(exchangeBaseUrl: string): Promise<ExchangeWireJson> {
|
||||||
exchangeBaseUrl = canonicalizeBaseUrl(exchangeBaseUrl);
|
exchangeBaseUrl = canonicalizeBaseUrl(exchangeBaseUrl);
|
||||||
const reqUrl = new URI("wire").absoluteTo(exchangeBaseUrl);
|
const reqUrl = new URI("wire").absoluteTo(exchangeBaseUrl);
|
||||||
const resp = await this.http.get(reqUrl.href());
|
const resp = await this.http.get(reqUrl.href());
|
||||||
@ -1340,7 +1336,7 @@ export class Wallet {
|
|||||||
if (!wiJson) {
|
if (!wiJson) {
|
||||||
throw Error("/wire response malformed");
|
throw Error("/wire response malformed");
|
||||||
}
|
}
|
||||||
return wiJson;
|
return ExchangeWireJson.checked(wiJson)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1500,6 +1496,11 @@ export class Wallet {
|
|||||||
throw Error(`no wire fees found for exchange ${baseUrl}`);
|
throw Error(`no wire fees found for exchange ${baseUrl}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const exchangeWireAccounts: string[] = [];
|
||||||
|
for (let account of wireInfo.accounts) {
|
||||||
|
exchangeWireAccounts.push(account.url);
|
||||||
|
}
|
||||||
|
|
||||||
const {isTrusted, isAudited} = await this.getExchangeTrust(exchangeInfo);
|
const {isTrusted, isAudited} = await this.getExchangeTrust(exchangeInfo);
|
||||||
|
|
||||||
let earliestDepositExpiration = Infinity;
|
let earliestDepositExpiration = Infinity;
|
||||||
@ -1534,10 +1535,10 @@ export class Wallet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const ret: ReserveCreationInfo = {
|
const ret: ReserveCreationInfo = {
|
||||||
earliestDepositExpiration,
|
earliestDepositExpiration,
|
||||||
exchangeInfo,
|
exchangeInfo,
|
||||||
|
exchangeWireAccounts,
|
||||||
exchangeVersion: exchangeInfo.protocolVersion || "unknown",
|
exchangeVersion: exchangeInfo.protocolVersion || "unknown",
|
||||||
isAudited,
|
isAudited,
|
||||||
isTrusted,
|
isTrusted,
|
||||||
@ -1548,7 +1549,6 @@ export class Wallet {
|
|||||||
versionMatch,
|
versionMatch,
|
||||||
walletVersion: WALLET_PROTOCOL_VERSION,
|
walletVersion: WALLET_PROTOCOL_VERSION,
|
||||||
wireFees,
|
wireFees,
|
||||||
wireInfo,
|
|
||||||
withdrawFee: acc,
|
withdrawFee: acc,
|
||||||
};
|
};
|
||||||
return ret;
|
return ret;
|
||||||
@ -1563,26 +1563,13 @@ export class Wallet {
|
|||||||
async updateExchangeFromUrl(baseUrl: string): Promise<ExchangeRecord> {
|
async updateExchangeFromUrl(baseUrl: string): Promise<ExchangeRecord> {
|
||||||
baseUrl = canonicalizeBaseUrl(baseUrl);
|
baseUrl = canonicalizeBaseUrl(baseUrl);
|
||||||
const keysUrl = new URI("keys").absoluteTo(baseUrl);
|
const keysUrl = new URI("keys").absoluteTo(baseUrl);
|
||||||
const wireUrl = new URI("wire").absoluteTo(baseUrl);
|
|
||||||
const keysResp = await this.http.get(keysUrl.href());
|
const keysResp = await this.http.get(keysUrl.href());
|
||||||
if (keysResp.status !== 200) {
|
if (keysResp.status !== 200) {
|
||||||
throw Error("/keys request failed");
|
throw Error("/keys request failed");
|
||||||
}
|
}
|
||||||
const wireResp = await this.http.get(wireUrl.href());
|
|
||||||
if (wireResp.status !== 200) {
|
|
||||||
throw Error("/wire request failed");
|
|
||||||
}
|
|
||||||
const exchangeKeysJson = KeysJson.checked(JSON.parse(keysResp.responseText));
|
const exchangeKeysJson = KeysJson.checked(JSON.parse(keysResp.responseText));
|
||||||
const wireRespJson = JSON.parse(wireResp.responseText);
|
const exchangeWire = await this.getWireInfo(baseUrl);
|
||||||
if (typeof wireRespJson !== "object") {
|
return this.updateExchangeFromJson(baseUrl, exchangeKeysJson, exchangeWire);
|
||||||
throw Error("/wire response is not an object");
|
|
||||||
}
|
|
||||||
console.log("exchange wire", wireRespJson);
|
|
||||||
const wireMethodDetails: WireDetailJson[] = [];
|
|
||||||
for (const methodName in wireRespJson) {
|
|
||||||
wireMethodDetails.push(WireDetailJson.checked(wireRespJson[methodName]));
|
|
||||||
}
|
|
||||||
return this.updateExchangeFromJson(baseUrl, exchangeKeysJson, wireMethodDetails);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1614,7 +1601,7 @@ export class Wallet {
|
|||||||
|
|
||||||
private async updateExchangeFromJson(baseUrl: string,
|
private async updateExchangeFromJson(baseUrl: string,
|
||||||
exchangeKeysJson: KeysJson,
|
exchangeKeysJson: KeysJson,
|
||||||
wireMethodDetails: WireDetailJson[]): Promise<ExchangeRecord> {
|
wireMethodDetails: ExchangeWireJson): Promise<ExchangeRecord> {
|
||||||
|
|
||||||
// FIXME: all this should probably be commited atomically
|
// FIXME: all this should probably be commited atomically
|
||||||
const updateTimeSec = getTalerStampSec(exchangeKeysJson.list_issue_date);
|
const updateTimeSec = getTalerStampSec(exchangeKeysJson.list_issue_date);
|
||||||
@ -1667,16 +1654,17 @@ export class Wallet {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const detail of wireMethodDetails) {
|
for (const paytoTargetType in wireMethodDetails.fees) {
|
||||||
let latestFeeStamp = 0;
|
let latestFeeStamp = 0;
|
||||||
const fees = oldWireFees.feesForType[detail.type] || [];
|
const newFeeDetails = wireMethodDetails.fees[paytoTargetType];
|
||||||
oldWireFees.feesForType[detail.type] = fees;
|
const oldFeeDetails = oldWireFees.feesForType[paytoTargetType] || [];
|
||||||
for (const oldFee of fees) {
|
oldWireFees.feesForType[paytoTargetType] = oldFeeDetails;
|
||||||
|
for (const oldFee of oldFeeDetails) {
|
||||||
if (oldFee.endStamp > latestFeeStamp) {
|
if (oldFee.endStamp > latestFeeStamp) {
|
||||||
latestFeeStamp = oldFee.endStamp;
|
latestFeeStamp = oldFee.endStamp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const fee of detail.fees) {
|
for (const fee of newFeeDetails) {
|
||||||
const start = getTalerStampSec(fee.start_date);
|
const start = getTalerStampSec(fee.start_date);
|
||||||
if (start === null) {
|
if (start === null) {
|
||||||
console.error("invalid start stamp in fee", fee);
|
console.error("invalid start stamp in fee", fee);
|
||||||
@ -1697,12 +1685,12 @@ export class Wallet {
|
|||||||
startStamp: start,
|
startStamp: start,
|
||||||
wireFee: Amounts.parseOrThrow(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(paytoTargetType, wf, exchangeInfo.masterPublicKey);
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
console.error("fee signature invalid", fee);
|
console.error("fee signature invalid", fee);
|
||||||
throw Error("fee signature invalid");
|
throw Error("fee signature invalid");
|
||||||
}
|
}
|
||||||
fees.push(wf);
|
oldFeeDetails.push(wf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2434,11 +2422,9 @@ export class Wallet {
|
|||||||
|
|
||||||
const senderWiresSet = new Set();
|
const senderWiresSet = new Set();
|
||||||
await this.q().iter(Stores.senderWires).map((x) => {
|
await this.q().iter(Stores.senderWires).map((x) => {
|
||||||
if (x.senderWire) {
|
senderWiresSet.add(x.paytoUri);
|
||||||
senderWiresSet.add(canonicalJson(x.senderWire));
|
|
||||||
}
|
|
||||||
}).run();
|
}).run();
|
||||||
const senderWires = Array.from(senderWiresSet).map((x) => JSON.parse(x));
|
const senderWires = Array.from(senderWiresSet);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
exchangeWireTypes,
|
exchangeWireTypes,
|
||||||
|
@ -70,19 +70,6 @@ export class CreateReserveResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wire info, sent to the bank when creating a reserve. Fee information will
|
|
||||||
* be filtered out. Only methods that the bank also supports should be sent.
|
|
||||||
*/
|
|
||||||
export interface WireInfo {
|
|
||||||
/**
|
|
||||||
* Mapping from wire method type to the exchange's wire info,
|
|
||||||
* excluding fees.
|
|
||||||
*/
|
|
||||||
[type: string]: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Information about what will happen when creating a reserve.
|
* Information about what will happen when creating a reserve.
|
||||||
*
|
*
|
||||||
@ -97,7 +84,7 @@ export interface ReserveCreationInfo {
|
|||||||
/**
|
/**
|
||||||
* Filtered wire info to send to the bank.
|
* Filtered wire info to send to the bank.
|
||||||
*/
|
*/
|
||||||
wireInfo: WireInfo;
|
exchangeWireAccounts: string[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Selected denominations for withdraw.
|
* Selected denominations for withdraw.
|
||||||
@ -139,6 +126,7 @@ export interface ReserveCreationInfo {
|
|||||||
* Number of currently offered denominations.
|
* Number of currently offered denominations.
|
||||||
*/
|
*/
|
||||||
numOfferedDenoms: number;
|
numOfferedDenoms: number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Public keys of trusted auditors for the currency we're withdrawing.
|
* Public keys of trusted auditors for the currency we're withdrawing.
|
||||||
*/
|
*/
|
||||||
@ -337,10 +325,11 @@ export class CreateReserveRequest {
|
|||||||
exchange: string;
|
exchange: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wire details for the bank account that sent the funds to the exchange.
|
* Wire details (as a payto URI) for the bank account that sent the funds to
|
||||||
|
* the exchange.
|
||||||
*/
|
*/
|
||||||
@Checkable.Optional(Checkable.Any())
|
@Checkable.Optional(Checkable.String())
|
||||||
senderWire?: object;
|
senderWire?: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify that a value matches the schema of this class and convert it into a
|
* Verify that a value matches the schema of this class and convert it into a
|
||||||
|
@ -92,7 +92,7 @@ interface ExchangeSelectionProps {
|
|||||||
callback_url: string;
|
callback_url: string;
|
||||||
wt_types: string[];
|
wt_types: string[];
|
||||||
currencyRecord: CurrencyRecord|null;
|
currencyRecord: CurrencyRecord|null;
|
||||||
sender_wire: object | undefined;
|
sender_wire: string | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ManualSelectionProps {
|
interface ManualSelectionProps {
|
||||||
@ -410,7 +410,7 @@ class ExchangeSelection extends ImplicitStateComponent<ExchangeSelectionProps> {
|
|||||||
exchange: string,
|
exchange: string,
|
||||||
amount: AmountJson,
|
amount: AmountJson,
|
||||||
callback_url: string,
|
callback_url: string,
|
||||||
sender_wire: object | undefined) {
|
sender_wire: string | undefined) {
|
||||||
const rawResp = await createReserve({
|
const rawResp = await createReserve({
|
||||||
amount,
|
amount,
|
||||||
exchange: canonicalizeBaseUrl(exchange),
|
exchange: canonicalizeBaseUrl(exchange),
|
||||||
@ -420,21 +420,25 @@ class ExchangeSelection extends ImplicitStateComponent<ExchangeSelectionProps> {
|
|||||||
throw Error("empty response");
|
throw Error("empty response");
|
||||||
}
|
}
|
||||||
// FIXME: filter out types that bank/exchange don't have in common
|
// FIXME: filter out types that bank/exchange don't have in common
|
||||||
const wireDetails = rci.wireInfo;
|
const exchangeWireAccounts = [];
|
||||||
const filteredWireDetails: any = {};
|
|
||||||
for (const wireType in wireDetails) {
|
for (let acct of rci.exchangeWireAccounts) {
|
||||||
if (this.props.wt_types.findIndex((x) => x.toLowerCase() === wireType.toLowerCase()) < 0) {
|
const payto = new URI(acct);
|
||||||
|
if (payto.scheme() != "payto") {
|
||||||
|
console.warn("unknown wire account URI scheme", acct);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const obj = Object.assign({}, wireDetails[wireType]);
|
if (this.props.wt_types.includes(payto.authority())) {
|
||||||
// The bank doesn't need to know about fees
|
exchangeWireAccounts.push(acct);
|
||||||
delete obj.fees;
|
|
||||||
// Consequently the bank can't verify signatures anyway, so
|
|
||||||
// we delete this extra data, to make the request URL shorter.
|
|
||||||
delete obj.salt;
|
|
||||||
delete obj.sig;
|
|
||||||
filteredWireDetails[wireType] = obj;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const chosenAcct = exchangeWireAccounts[0];
|
||||||
|
|
||||||
|
if (!chosenAcct) {
|
||||||
|
throw Error("no exchange account matches the bank's supported types");
|
||||||
|
}
|
||||||
|
|
||||||
if (!rawResp.error) {
|
if (!rawResp.error) {
|
||||||
const resp = CreateReserveResponse.checked(rawResp);
|
const resp = CreateReserveResponse.checked(rawResp);
|
||||||
const q: {[name: string]: string|number} = {
|
const q: {[name: string]: string|number} = {
|
||||||
@ -442,7 +446,7 @@ class ExchangeSelection extends ImplicitStateComponent<ExchangeSelectionProps> {
|
|||||||
amount_fraction: amount.fraction,
|
amount_fraction: amount.fraction,
|
||||||
amount_value: amount.value,
|
amount_value: amount.value,
|
||||||
exchange: resp.exchange,
|
exchange: resp.exchange,
|
||||||
exchange_wire_details: JSON.stringify(filteredWireDetails),
|
exchange_wire_details: chosenAcct,
|
||||||
reserve_pub: resp.reservePub,
|
reserve_pub: resp.reservePub,
|
||||||
};
|
};
|
||||||
const url = new URI(callback_url).addQuery(q);
|
const url = new URI(callback_url).addQuery(q);
|
||||||
@ -487,7 +491,11 @@ async function main() {
|
|||||||
|
|
||||||
let sender_wire;
|
let sender_wire;
|
||||||
if (query.sender_wire) {
|
if (query.sender_wire) {
|
||||||
sender_wire = JSON.parse(query.sender_wire);
|
let senderWireUri = new URI(query.sender_wire);
|
||||||
|
if (senderWireUri.scheme() != "payto") {
|
||||||
|
throw Error("sender wire info must be a payto URI");
|
||||||
|
}
|
||||||
|
sender_wire = query.sender_wire;
|
||||||
}
|
}
|
||||||
|
|
||||||
const suggestedExchangeUrl = query.suggested_exchange_url;
|
const suggestedExchangeUrl = query.suggested_exchange_url;
|
||||||
|
@ -273,7 +273,7 @@ export function checkUpgrade(): Promise<UpgradeResponse> {
|
|||||||
/**
|
/**
|
||||||
* Create a reserve.
|
* Create a reserve.
|
||||||
*/
|
*/
|
||||||
export function createReserve(args: { amount: AmountJson, exchange: string, senderWire?: object }): Promise<any> {
|
export function createReserve(args: { amount: AmountJson, exchange: string, senderWire?: string }): Promise<any> {
|
||||||
return callBackend("create-reserve", args);
|
return callBackend("create-reserve", args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ module.exports = function (env) {
|
|||||||
const base = {
|
const base = {
|
||||||
output: {
|
output: {
|
||||||
filename: '[name]-bundle.js',
|
filename: '[name]-bundle.js',
|
||||||
chunkFilename: "[id]-bundle.js",
|
chunkFilename: "[name]-bundle.js",
|
||||||
path: path.resolve(__dirname, "dist"),
|
path: path.resolve(__dirname, "dist"),
|
||||||
},
|
},
|
||||||
module: {
|
module: {
|
||||||
|
Loading…
Reference in New Issue
Block a user