///
import 'babel-polyfill';
import { Waves, IUserData } from './Waves';
import { default as TransportU2F } from '@ledgerhq/hw-transport-u2f';
declare const Buffer: any;
const ADDRES_PREFIX = '44\'/5741564\'/0\'/0\'/';
export class WavesLedger {
public ready: boolean;
private _wavesLibPromise: Promise | null;
private _initTransportPromise: Promise | null;
private _debug: boolean;
private _openTimeout: number | undefined;
private _listenTimeout: number | undefined;
private _exchangeTimeout: number | undefined;
private _networkCode: number;
private _error: any;
private _transport: any;
constructor(options: IWavesLedger) {
this.ready = false;
this._networkCode = options.networkCode == null ? 87 : options.networkCode;
this._wavesLibPromise = null;
this._initTransportPromise = null;
this._debug = options.debug == null ? false : options.debug;
this._openTimeout = options.openTimeout;
this._listenTimeout = options.listenTimeout;
this._exchangeTimeout = options.exchangeTimeout;
this._error = null;
this._transport = options.transport || TransportU2F;
this.tryConnect();
}
async tryConnect(): Promise {
const disconnectPromise = this.disconnect();
this._initU2FTransport();
this._setSettings();
this._initWavesLib();
await disconnectPromise;
await Promise.all([this._initTransportPromise, this._wavesLibPromise]);
}
async disconnect(): Promise {
const transportpromise = this._initTransportPromise;
this._initTransportPromise = null;
this._wavesLibPromise = null;
if (transportpromise) {
try {
const transport = await transportpromise;
transport.close();
} catch (e) {
}
}
}
async getTransport(): Promise {
try {
return await this._wavesLibPromise;
} catch (e) {
await this.tryConnect();
return await this._wavesLibPromise;
}
}
async getUserDataById(id: number): Promise {
try {
const waves = await this.getTransport();
const path = this.getPathById(id);
const userData = await waves.getWalletPublicKey(path, false);
return {
...userData, id, path
};
} catch (e) {
this.tryConnect();
this._error = e;
throw e;
}
}
async getVersion(): Promise> {
try {
const waves = await this.getTransport();
return await waves.getVersion();
} catch (e) {
this.tryConnect();
this._error = e;
throw e;
}
}
async getPaginationUsersData(from: number, limit: number): Promise> {
const usersData = [];
try {
for (let id = from; id <= from + limit; id++) {
const userData = await this.getUserDataById(id);
usersData.push(userData);
}
} catch (e) {
this.tryConnect();
this._error = e;
throw e;
}
return usersData;
}
async signTransaction(userId: number, asset: { precision: number }, txData: Uint8Array, version = 2) {
const path = this.getPathById(userId);
const msgData = new Buffer(txData);
try {
const waves = await this.getTransport();
return await waves.signTransaction(path, asset.precision, msgData, version);
} catch (e) {
this.tryConnect();
this._error = e;
throw e;
}
}
async signOrder(userId: number, asset: { precision: number }, txData: Uint8Array) {
const path = this.getPathById(userId);
const msgData = new Buffer(txData);
try {
const waves = await this.getTransport();
return await waves.signOrder(path, asset.precision, msgData);
} catch (e) {
this.tryConnect();
this._error = e;
throw e;
}
}
async signSomeData(userId: number, dataBuffer: Uint8Array) {
const path = this.getPathById(userId);
const msgData = new Buffer(dataBuffer);
try {
const waves = await this.getTransport();
return await waves.signSomeData(path, msgData);
} catch (e) {
this.tryConnect();
this._error = e;
throw e;
}
}
async signRequest(userId: number, dataBuffer: Uint8Array) {
const path = this.getPathById(userId);
const msgData = new Buffer(dataBuffer);
try {
const waves = await this.getTransport();
return await waves.signRequest(path, msgData);
} catch (e) {
this.tryConnect();
this._error = e;
throw e;
}
}
async signMessage(userId: number, message: string) {
const path = this.getPathById(userId);
const msgData = new Buffer(message, 'ascii');
try {
const waves = await this.getTransport();
return await waves.signMessage(path, msgData);
} catch (e) {
this.tryConnect();
this._error = e;
throw e;
}
}
getLastError() {
return this._error;
}
async probeDevice() {
if (!this.ready) {
await this.tryConnect();
}
this._error = null;
try {
await this.getUserDataById(1);
} catch (e) {
this._error = e;
return false;
}
return true;
}
getPathById(id: number) {
return `${ADDRES_PREFIX}${id}'`;
}
_setSettings() {
(this._initTransportPromise as Promise).then((transport) => {
transport.setDebugMode(this._debug);
transport.setExchangeTimeout(this._exchangeTimeout);
});
}
_initU2FTransport() {
this.ready = false;
this._initTransportPromise = this._transport.create(this._openTimeout, this._listenTimeout);
return this._initTransportPromise;
}
_initWavesLib() {
this._wavesLibPromise = (this._initTransportPromise as Promise).then(
(transport: any) => {
this.ready = true;
return new Waves(transport, this._networkCode);
});
return this._wavesLibPromise;
}
}
interface IWavesLedger {
debug?: boolean;
openTimeout?: number;
listenTimeout?: number;
exchangeTimeout?: number;
networkCode?: number,
transport?: any;
}
interface IUser extends IUserData {
id: number;
path: string;
}