Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

research: refactor adapter/wallet initialize() #431

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/hdwallet-core/src/wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ export interface HDWallet extends HDWalletInfo {
/**
* Initialize a device session.
*/
initialize(): Promise<any>;
initialize(): Promise<boolean>;

/**
* Send a ping to the device.
Expand Down
41 changes: 19 additions & 22 deletions packages/hdwallet-keepkey/src/adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ export class Adapter<DelegateType extends AdapterDelegate<any>> {

private async handleConnect(device: DeviceType<DelegateType>): Promise<void> {
try {
await this.initialize([device]);
await this.initialize(device);
const { productName, serialNumber } = await this.inspectDevice(device);
await this.keyring.emit([productName, serialNumber, core.Events.CONNECT], serialNumber);
} catch (e) {
Expand All @@ -92,28 +92,25 @@ export class Adapter<DelegateType extends AdapterDelegate<any>> {
await this.keyring.emit([productName, serialNumber, core.Events.DISCONNECT], serialNumber);
}

async initialize(
devices?: Array<DeviceType<DelegateType>>,
private async initialize(
device: DeviceType<DelegateType>,
tryDebugLink?: boolean,
autoConnect?: boolean
): Promise<number> {
devices = devices ?? (await this.getDevices());
for (const device of devices) {
const { serialNumber } = await this.inspectDevice(device);
if (this.keyring.wallets[serialNumber]) await this.keyring.remove(serialNumber);

const delegate = await this.getTransportDelegate(device);
if (delegate === null) continue;

const transport = await Transport.create(this.keyring, delegate);
await transport.connect();
if (tryDebugLink) await transport.tryConnectDebugLink();

const wallet = await KeepKeyHDWallet.create(transport);
if (autoConnect) await wallet.initialize();
this.keyring.add(wallet, serialNumber);
}
return Object.keys(this.keyring.wallets).length;
): Promise<KeepKeyHDWallet | null> {
const { serialNumber } = await this.inspectDevice(device);
if (this.keyring.wallets[serialNumber]) await this.keyring.remove(serialNumber);

const delegate = await this.getTransportDelegate(device);
if (delegate === null) return null;

const transport = await Transport.create(this.keyring, delegate);
await transport.connect();
if (tryDebugLink) await transport.tryConnectDebugLink();

const wallet = await KeepKeyHDWallet.create(transport);
if (autoConnect) await wallet.initialize();
this.keyring.add(wallet, serialNumber);
return wallet;
}

async getDevice(serialNumber?: string): Promise<DeviceType<DelegateType>> {
Expand Down Expand Up @@ -154,7 +151,7 @@ export class Adapter<DelegateType extends AdapterDelegate<any>> {
}

async pairRawDevice(device: DeviceType<DelegateType>, tryDebugLink?: boolean): Promise<core.HDWallet> {
await this.initialize([device], tryDebugLink, true);
await this.initialize(device, tryDebugLink, true);
return core.mustBeDefined(this.keyring.get((await this.inspectDevice(device)).serialNumber));
}
}
4 changes: 2 additions & 2 deletions packages/hdwallet-keepkey/src/keepkey.ts
Original file line number Diff line number Diff line change
Expand Up @@ -999,7 +999,7 @@ export class KeepKeyHDWallet implements core.HDWallet, core.BTCWallet, core.ETHW
}

// Initialize assigns a hid connection to this KeepKey and send initialize message to device
public async initialize(): Promise<Messages.Features.AsObject> {
public async initialize(): Promise<boolean> {
const initialize = new Messages.Initialize();
const event = await this.transport.call(Messages.MessageType.MESSAGETYPE_INITIALIZE, initialize);
if (!event.message) throw event;
Expand All @@ -1024,7 +1024,7 @@ export class KeepKeyHDWallet implements core.HDWallet, core.BTCWallet, core.ETHW
// this._supportsThorchain = Semver.get(fwVersion, "v7.0.0");

this.cacheFeatures(out);
return out;
return await this.isInitialized();
}

// GetFeatures returns the features and other device information such as the version, label, and supported coins
Expand Down
28 changes: 11 additions & 17 deletions packages/hdwallet-ledger-webhid/src/adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,30 +64,24 @@ export class WebHIDLedgerAdapter {
return core.mustBeDefined(this.keyring.get(MOCK_SERIAL_NUMBER));
}

// without unique device identifiers, we should only ever have one HID ledger device on the keyring at a time
public async initialize(device?: HIDDevice): Promise<number> {
device = device ?? (await getFirstLedgerDevice()) ?? undefined;
// without unique device identifiers, we should only ever have one ledger device on the keyring at a time
private async initialize(device: HIDDevice): Promise<ledger.LedgerHDWallet> {
await this.keyring.remove(core.mustBeDefined(MOCK_SERIAL_NUMBER));

if (device) {
await this.keyring.remove(MOCK_SERIAL_NUMBER);
const ledgerTransport = await openTransport(device);

const ledgerTransport = await openTransport(device);
const wallet = ledger.create(new LedgerWebHIDTransport(device, ledgerTransport, this.keyring) as ledger.LedgerTransport);

const wallet = ledger.create(new LedgerWebHIDTransport(device, ledgerTransport, this.keyring));
await this.keyring.add(wallet, MOCK_SERIAL_NUMBER);

this.keyring.add(wallet, MOCK_SERIAL_NUMBER);
}

return Object.keys(this.keyring.wallets).length;
return wallet
}

public async pairDevice(): Promise<core.HDWallet> {
const ledgerTransport = await getTransport();
public async pairDevice(usbDevice?: HIDDevice): Promise<ledger.LedgerHDWallet> {
const device = usbDevice ?? (await getTransport()).device ?? (await getFirstLedgerDevice());

const device = ledgerTransport.device;
const wallet = await this.initialize(device);

await this.initialize(device);

return core.mustBeDefined(this.keyring.get(MOCK_SERIAL_NUMBER));
return core.mustBeDefined(wallet);
}
}
26 changes: 10 additions & 16 deletions packages/hdwallet-ledger-webusb/src/adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,29 +65,23 @@ export class WebUSBLedgerAdapter {
}

// without unique device identifiers, we should only ever have one ledger device on the keyring at a time
public async initialize(usbDevice?: USBDevice): Promise<number> {
const device = usbDevice ?? (await getFirstLedgerDevice());
private async initialize(device: USBDevice): Promise<ledger.LedgerHDWallet> {
await this.keyring.remove(core.mustBeDefined(device.serialNumber));

if (device) {
await this.keyring.remove(core.mustBeDefined(device.serialNumber));
const ledgerTransport = await openTransport(device);

const ledgerTransport = await openTransport(device);
const wallet = ledger.create(new LedgerWebUsbTransport(device, ledgerTransport, this.keyring) as ledger.LedgerTransport);

const wallet = ledger.create(new LedgerWebUsbTransport(device, ledgerTransport, this.keyring) as ledger.LedgerTransport);
await this.keyring.add(wallet, device.serialNumber);

this.keyring.add(wallet, device.serialNumber);
}

return Object.keys(this.keyring.wallets).length;
return wallet
}

public async pairDevice(): Promise<core.HDWallet> {
const ledgerTransport = await getTransport();
public async pairDevice(usbDevice?: USBDevice): Promise<ledger.LedgerHDWallet> {
const device = usbDevice ?? (await getTransport()).device ?? (await getFirstLedgerDevice());

const device = ledgerTransport.device;
const wallet = await this.initialize(device);

await this.initialize(device);

return core.mustBeDefined(this.keyring.get(device.serialNumber));
return core.mustBeDefined(wallet);
}
}
4 changes: 2 additions & 2 deletions packages/hdwallet-ledger/src/ledger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -301,8 +301,8 @@ export class LedgerHDWallet implements core.HDWallet, core.BTCWallet, core.ETHWa
this.info = new LedgerHDWalletInfo();
}

public async initialize(): Promise<any> {
return;
public async initialize(): Promise<boolean> {
return await this.isInitialized();
}

public async isInitialized(): Promise<boolean> {
Expand Down
4 changes: 0 additions & 4 deletions packages/hdwallet-metamask/src/adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,6 @@ export class MetaMaskAdapter {
return new MetaMaskAdapter(keyring);
}

public async initialize(): Promise<number> {
return Object.keys(this.keyring.wallets).length;
}

public async pairDevice(): Promise<core.HDWallet> {
const provider: any = await detectEthereumProvider({ mustBeMetaMask: true, silent: false, timeout: 3000 });
if (!provider) {
Expand Down
6 changes: 3 additions & 3 deletions packages/hdwallet-metamask/src/metamask.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,14 +77,14 @@ export class MetaMaskHDWallet implements core.HDWallet, core.ETHWallet {
return Promise.resolve("MetaMask");
}

public async initialize(): Promise<any> {
public async initialize(): Promise<boolean> {
try {
this.provider = await detectEthereumProvider({ mustBeMetaMask: true, silent: false, timeout: 3000 });
return true;
} catch (e) {
console.error(e);
return false;
}

return Promise.resolve();
}

public hasOnDevicePinEntry(): boolean {
Expand Down
1 change: 0 additions & 1 deletion packages/hdwallet-native/src/adapter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ describe("NativeAdapter", () => {
it("creates a unique wallet per deviceId", async () => {
const keyring = new core.Keyring();
const adapter = NativeAdapter.useKeyring(keyring);
expect(await adapter.initialize()).toBe(0);
const wallet = await adapter.pairDevice("foobar");
expect(wallet).toBeInstanceOf(NativeHDWallet);
expect(await adapter.pairDevice("foobar")).toBe(wallet);
Expand Down
4 changes: 0 additions & 4 deletions packages/hdwallet-native/src/adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,6 @@ export class NativeAdapter {
return new NativeAdapter(keyring);
}

async initialize(): Promise<number> {
return 0;
}

async pairDevice(deviceId: string): Promise<core.HDWallet | null> {
let wallet: core.HDWallet | null = this.keyring.get(deviceId);
if (!wallet && deviceId) {
Expand Down
4 changes: 2 additions & 2 deletions packages/hdwallet-native/src/native.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ describe("NativeHDWallet", () => {
});
wallet.events.addListener(native.NativeEvents.READY, readyMock);
wallet.events.addListener(native.NativeEvents.MNEMONIC_REQUIRED, mnemonicRequiredMock);
expect(await wallet.initialize()).toBe(null);
expect(await wallet.initialize()).toBe(false);
expect(mnemonicRequiredMock).toHaveBeenCalled();
expect(readyMock).not.toHaveBeenCalled();
});
Expand Down Expand Up @@ -267,7 +267,7 @@ describe("NativeHDWallet", () => {
expect(await wallet.initialize()).toBe(true);
await wallet.wipe();
expect(mock).not.toHaveBeenCalled();
expect(await wallet.initialize()).toBe(null);
expect(await wallet.initialize()).toBe(false);
expect(mock).toHaveBeenCalled();
});

Expand Down
7 changes: 3 additions & 4 deletions packages/hdwallet-native/src/native.ts
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ export class NativeHDWallet

async clearSession(): Promise<void> {}

async initialize(): Promise<boolean | null> {
async initialize(): Promise<boolean> {
return this.needsMnemonic(!!this.#masterKey, async () => {
const masterKey = await this.#masterKey!;
try {
Expand All @@ -309,9 +309,8 @@ export class NativeHDWallet
this.#initialized = false;
await this.wipe();
}

return this.#initialized;
});
return await this.isInitialized();
}) ?? false;
}

async ping(msg: core.Ping): Promise<core.Pong> {
Expand Down
12 changes: 4 additions & 8 deletions packages/hdwallet-portis/src/adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,9 @@ export class PortisAdapter {
return new PortisAdapter(keyring, args);
}

public async initialize(): Promise<number> {
return Object.keys(this.keyring.wallets).length;
}

public async pairDevice(): Promise<core.HDWallet> {
public async pairDevice(): Promise<PortisHDWallet> {
try {
const wallet = await this.pairPortisDevice();
const wallet = await this.initialize();
this.portis.onActiveWalletChanged(async (wallAddr: string) => {
// check if currentDeviceId has changed
const walletAddress = "portis:" + wallAddr;
Expand All @@ -40,7 +36,7 @@ export class PortisAdapter {
this.keyring.emit(["Portis", currentDeviceId, core.Events.DISCONNECT], currentDeviceId);
this.keyring.remove(currentDeviceId);
}
this.pairPortisDevice();
await this.initialize();
}
});
this.portis.onLogout(() => {
Expand All @@ -58,7 +54,7 @@ export class PortisAdapter {
}
}

private async pairPortisDevice(): Promise<core.HDWallet> {
private async initialize(): Promise<PortisHDWallet> {
const Portis = (await import("@portis/web3")).default;
this.portis = new Portis(this.portisAppId, "mainnet");
const wallet = new PortisHDWallet(this.portis);
Expand Down
4 changes: 2 additions & 2 deletions packages/hdwallet-portis/src/portis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,10 @@ export class PortisHDWallet implements core.HDWallet, core.ETHWallet, core.BTCWa
return "Portis";
}

public initialize(): Promise<any> {
public async initialize(): Promise<boolean> {
// no means to reset the state of the Portis widget
// while it's in the middle of execution
return Promise.resolve();
return await this.isInitialized();
}

public hasOnDevicePinEntry(): boolean {
Expand Down
38 changes: 15 additions & 23 deletions packages/hdwallet-trezor-connect/src/adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ export class TrezorAdapter {

public async addDevice(deviceID: string, path: string): Promise<void> {
this._deviceIDToPath.set(deviceID, path);
await this.initialize([{ path: path, deviceID: deviceID }]);
await this.initialize({ path: path, deviceID: deviceID });
}

public static useKeyring(keyring: core.Keyring, args: TrezorConnectArgs) {
Expand Down Expand Up @@ -143,26 +143,20 @@ export class TrezorAdapter {
this.connectCacheFeatures(event);
}

public async initialize(devices?: TrezorDevice[]): Promise<number> {
private async initialize(device: TrezorDevice): Promise<void> {
const init = await _initialization;
if (!init) throw new Error("Could not initialize TrezorAdapter: TrezorConnect not initialized");

const devicesToInitialize = devices || [];

for (let i = 0; i < devicesToInitialize.length; i++) {
const device = devicesToInitialize[i];
let wallet = this.keyring.get(device.deviceID);
if (wallet) {
if (device.path && !(wallet.transport as TrezorConnectTransport).device.path)
(wallet.transport as TrezorConnectTransport).device.path = device.path;
} else {
wallet = trezor.create(new TrezorConnectTransport(device, this.keyring));
}

await wallet.initialize();
this.keyring.add(wallet, device.deviceID);
let wallet = this.keyring.get(device.deviceID);
if (wallet) {
if (device.path && !(wallet.transport as TrezorConnectTransport).device.path)
(wallet.transport as TrezorConnectTransport).device.path = device.path;
} else {
wallet = trezor.create(new TrezorConnectTransport(device, this.keyring));
}
return Object.keys(this.keyring.wallets).length;

await wallet.initialize();
this.keyring.add(wallet, device.deviceID);
}

public async pairDevice(): Promise<core.HDWallet> {
Expand All @@ -178,12 +172,10 @@ export class TrezorAdapter {

let deviceID = payload.device_id;

await this.initialize([
{
path: this._deviceIDToPath.get(deviceID),
deviceID: deviceID,
},
]);
await this.initialize({
path: this._deviceIDToPath.get(deviceID),
deviceID: deviceID,
});

let wallet = this.keyring.get(deviceID) as trezor.TrezorHDWallet;

Expand Down
4 changes: 2 additions & 2 deletions packages/hdwallet-trezor/src/trezor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -275,8 +275,8 @@ export class TrezorHDWallet implements core.HDWallet, core.BTCWallet, core.ETHWa
this.info = new TrezorHDWalletInfo();
}

public async initialize(): Promise<any> {
return;
public async initialize(): Promise<boolean> {
return this.isInitialized();
}

public async isInitialized(): Promise<boolean> {
Expand Down
Loading