Skip to content

Commit 5652453

Browse files
authored
Merge pull request #3 from MobileWalletProtocol/felix/polish
Singleton Communicator
2 parents 293413c + 7209158 commit 5652453

15 files changed

Lines changed: 204 additions & 282 deletions

packages/client/.prettierignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,5 @@ coverage/**
55
**/build
66
**/dist
77
**/node_modules
8-
**/src/vendor-js
98
**/*-css.ts
109
**/*-svg.ts

packages/client/jest.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export default {
1616
coverageDirectory: 'coverage',
1717

1818
// An array of regexp pattern strings used to skip coverage collection
19-
coveragePathIgnorePatterns: ['/node_modules/', 'vendor-js/', 'assets/', 'walletlink/relay/'],
19+
coveragePathIgnorePatterns: ['/node_modules/'],
2020

2121
// A list of reporter names that Jest uses when writing coverage reports
2222
coverageReporters: ['json', 'text', 'text-summary', 'lcov'],

packages/client/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
"test": "jest",
2323
"test:coverage": "yarn test:unit && open coverage/lcov-report/index.html",
2424
"prebuild": "rm -rf ./build && node -p \"'export const LIB_VERSION = \\'' + require('./package.json').version + '\\';'\" > src/version.ts",
25-
"build": "tsc -p ./tsconfig.build.json && tsc-alias && cp -a src/vendor-js dist",
25+
"build": "tsc -p ./tsconfig.build.json && tsc-alias",
2626
"dev": "tsc --watch & nodemon --watch dist --delay 1 --exec tsc-alias",
2727
"typecheck": "tsc --noEmit",
2828
"lint": "eslint . --ext .ts,.tsx --fix"

packages/client/src/MWPClient.test.ts

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { WebBasedWalletCommunicator } from 'src/components/communicator/webBased/Communicator';
22

3-
import { CommunicatorInterface, getCommunicator } from './components/communicator';
43
import { KeyManager } from './components/key/KeyManager';
54
import { MWPClient } from './MWPClient';
65
import {
@@ -57,7 +56,6 @@ const mockWallet = Wallets.CoinbaseSmartWallet;
5756
describe('MWPClient', () => {
5857
let signer: MWPClient;
5958
let mockMetadata: AppMetadata;
60-
let mockCommunicator: CommunicatorInterface;
6159
let mockKeyManager: jest.Mocked<KeyManager>;
6260

6361
beforeEach(async () => {
@@ -67,10 +65,8 @@ describe('MWPClient', () => {
6765
appDeeplinkUrl: 'https://example.com',
6866
};
6967

70-
WebBasedWalletCommunicator.communicators.clear();
71-
mockCommunicator = getCommunicator(mockWallet);
7268
jest
73-
.spyOn(mockCommunicator, 'postRequestAndWaitForResponse')
69+
.spyOn(WebBasedWalletCommunicator, 'postRequestAndWaitForResponse')
7470
.mockResolvedValue(mockSuccessResponse);
7571

7672
mockKeyManager = new KeyManager({
@@ -126,7 +122,9 @@ describe('MWPClient', () => {
126122
content: { failure: mockError },
127123
timestamp: new Date(),
128124
};
129-
(mockCommunicator.postRequestAndWaitForResponse as jest.Mock).mockResolvedValue(mockResponse);
125+
(WebBasedWalletCommunicator.postRequestAndWaitForResponse as jest.Mock).mockResolvedValue(
126+
mockResponse
127+
);
130128

131129
await expect(signer.handshake()).rejects.toThrowError(mockError);
132130
});
@@ -165,11 +163,12 @@ describe('MWPClient', () => {
165163
const result = await signer.request(mockRequest);
166164

167165
expect(encryptContent).toHaveBeenCalled();
168-
expect(mockCommunicator.postRequestAndWaitForResponse).toHaveBeenCalledWith(
166+
expect(WebBasedWalletCommunicator.postRequestAndWaitForResponse).toHaveBeenCalledWith(
169167
expect.objectContaining({
170168
sender: '0xPublicKey',
171169
content: { encrypted: encryptedData },
172-
})
170+
}),
171+
mockWallet.scheme
173172
);
174173
expect(result).toEqual('0xSignature');
175174
});

packages/client/src/MWPClient.ts

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ const ACCOUNTS_KEY = 'accounts';
1616
const ACTIVE_CHAIN_STORAGE_KEY = 'activeChain';
1717
const AVAILABLE_CHAINS_STORAGE_KEY = 'availableChains';
1818
const WALLET_CAPABILITIES_STORAGE_KEY = 'walletCapabilities';
19-
import { CommunicatorInterface, getCommunicator } from './components/communicator';
19+
import * as Communicator from './components/communicator';
2020
import { LIB_VERSION } from './version';
2121
import {
2222
appendMWPResponsePath,
@@ -41,8 +41,6 @@ export class MWPClient {
4141
private readonly keyManager: KeyManager;
4242
private readonly storage: ScopedAsyncStorage;
4343

44-
private readonly communicator: CommunicatorInterface;
45-
4644
private accounts: AddressString[];
4745
private chain: Chain;
4846

@@ -57,8 +55,6 @@ export class MWPClient {
5755
this.keyManager = new KeyManager({ wallet: this.wallet });
5856
this.storage = new ScopedAsyncStorage(this.wallet.name, 'MWPClient');
5957

60-
this.communicator = getCommunicator(this.wallet);
61-
6258
// default values
6359
this.accounts = [];
6460
this.chain = {
@@ -67,8 +63,7 @@ export class MWPClient {
6763

6864
this.handshake = this.handshake.bind(this);
6965
this.request = this.request.bind(this);
70-
this.createRequestMessage = this.createRequestMessage.bind(this);
71-
this.decryptResponseMessage = this.decryptResponseMessage.bind(this);
66+
this.reset = this.reset.bind(this);
7267
}
7368

7469
private async initialize() {
@@ -96,8 +91,10 @@ export class MWPClient {
9691
params: this.metadata,
9792
},
9893
});
99-
const response: RPCResponseMessage =
100-
await this.communicator.postRequestAndWaitForResponse(handshakeMessage);
94+
const response: RPCResponseMessage = await Communicator.postRequestToWallet(
95+
handshakeMessage,
96+
this.wallet
97+
);
10198

10299
// store peer's public key
103100
if ('failure' in response.content) throw response.content.failure;
@@ -219,7 +216,7 @@ export class MWPClient {
219216
);
220217
const message = await this.createRequestMessage({ encrypted });
221218

222-
return this.communicator.postRequestAndWaitForResponse(message);
219+
return Communicator.postRequestToWallet(message, this.wallet);
223220
}
224221

225222
private async createRequestMessage(
@@ -232,7 +229,7 @@ export class MWPClient {
232229
content,
233230
sdkVersion: LIB_VERSION,
234231
timestamp: new Date(),
235-
...(this.metadata.appDeeplinkUrl && { callbackUrl: this.metadata.appDeeplinkUrl }),
232+
callbackUrl: this.metadata.appDeeplinkUrl,
236233
};
237234
}
238235

packages/client/src/components/communicator/getCommunicator.test.ts

Lines changed: 0 additions & 48 deletions
This file was deleted.

packages/client/src/components/communicator/getCommunicator.ts

Lines changed: 0 additions & 22 deletions
This file was deleted.
Lines changed: 36 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,62 @@
11
import { handleResponse } from './handleResponse';
22
import { WebBasedWalletCommunicator } from './webBased/Communicator';
33
import { MWP_RESPONSE_PATH } from ':core/constants';
4-
import { Wallet } from ':core/wallet';
54

6-
jest.mock('./webBased/Communicator');
7-
jest.mock('expo-web-browser', () => ({
8-
openBrowserAsync: jest.fn(),
9-
WebBrowserPresentationStyle: {
10-
FORM_SHEET: 'FORM_SHEET',
5+
jest.mock('./webBased/Communicator', () => ({
6+
WebBasedWalletCommunicator: {
7+
handleResponse: jest.fn(),
118
},
12-
dismissBrowser: jest.fn(),
139
}));
1410

1511
describe('handleResponse', () => {
16-
const mockWebBasedWallet = { type: 'webBased', scheme: 'https://example.com' } as Wallet;
17-
const mockNativeWallet = { type: 'native' } as Wallet;
18-
const mockOtherWallet = { type: 'other' as any } as Wallet;
19-
2012
beforeEach(() => {
2113
jest.clearAllMocks();
2214
});
2315

24-
test('returns false for non-MWP response URLs', () => {
25-
const url = 'https://example.com/some-path';
26-
expect(handleResponse(url, mockWebBasedWallet)).toBe(false);
16+
it('should return false if the pathname does not include MWP_RESPONSE_PATH', () => {
17+
const responseUrl = 'https://example.com/some-other-path';
18+
const result = handleResponse(responseUrl);
19+
expect(result).toBe(false);
20+
expect(WebBasedWalletCommunicator.handleResponse).not.toHaveBeenCalled();
2721
});
2822

29-
test('handles web-based wallet response correctly', () => {
30-
const url = `https://example.com/${MWP_RESPONSE_PATH}/some-params`;
31-
const mockHandleResponse = jest.fn().mockReturnValue(true);
32-
(WebBasedWalletCommunicator.getInstance as jest.Mock).mockReturnValue({
33-
handleResponse: mockHandleResponse,
34-
});
23+
it('should return true if WebBasedWalletCommunicator handles the response successfully', () => {
24+
const responseUrl = `https://example.com/${MWP_RESPONSE_PATH}/some-params`;
25+
(WebBasedWalletCommunicator.handleResponse as jest.Mock).mockReturnValue(true);
3526

36-
const result = handleResponse(url, mockWebBasedWallet);
27+
const result = handleResponse(responseUrl);
3728

38-
expect(WebBasedWalletCommunicator.getInstance).toHaveBeenCalledWith(mockWebBasedWallet.scheme);
39-
expect(mockHandleResponse).toHaveBeenCalledWith(url);
4029
expect(result).toBe(true);
30+
expect(WebBasedWalletCommunicator.handleResponse).toHaveBeenCalledWith(responseUrl);
4131
});
4232

43-
test('throws error for native wallet', () => {
44-
const url = `https://example.com/${MWP_RESPONSE_PATH}/some-params`;
45-
expect(() => handleResponse(url, mockNativeWallet)).toThrow('Native wallet not supported yet');
46-
});
33+
it('should return false if WebBasedWalletCommunicator does not handle the response', () => {
34+
const responseUrl = `https://example.com/${MWP_RESPONSE_PATH}/some-params`;
35+
(WebBasedWalletCommunicator.handleResponse as jest.Mock).mockReturnValue(false);
36+
37+
const result = handleResponse(responseUrl);
4738

48-
test('returns false for unsupported wallet types', () => {
49-
const url = `https://example.com/${MWP_RESPONSE_PATH}/some-params`;
50-
expect(handleResponse(url, mockOtherWallet)).toBe(false);
39+
expect(result).toBe(false);
40+
expect(WebBasedWalletCommunicator.handleResponse).toHaveBeenCalledWith(responseUrl);
5141
});
5242

53-
test('WebBasedWalletCommunicator.handleResponse returns false', () => {
54-
const url = `https://example.com/${MWP_RESPONSE_PATH}/some-params`;
55-
const mockHandleResponse = jest.fn().mockReturnValue(false);
56-
(WebBasedWalletCommunicator.getInstance as jest.Mock).mockReturnValue({
57-
handleResponse: mockHandleResponse,
43+
it('should handle different URL formats correctly', () => {
44+
const responseUrls = [
45+
`https://example.com/${MWP_RESPONSE_PATH}`,
46+
`https://example.com/${MWP_RESPONSE_PATH}/`,
47+
`https://example.com/${MWP_RESPONSE_PATH}?param=value`,
48+
`https://example.com/${MWP_RESPONSE_PATH}/?param=value`,
49+
];
50+
51+
responseUrls.forEach((url) => {
52+
(WebBasedWalletCommunicator.handleResponse as jest.Mock).mockReturnValue(true);
53+
expect(handleResponse(url)).toBe(true);
54+
expect(WebBasedWalletCommunicator.handleResponse).toHaveBeenCalledWith(url);
5855
});
56+
});
5957

60-
const result = handleResponse(url, mockWebBasedWallet);
61-
62-
expect(mockHandleResponse).toHaveBeenCalledWith(url);
63-
expect(result).toBe(false);
58+
it('should throw an error for invalid URLs', () => {
59+
const invalidUrl = 'not-a-valid-url';
60+
expect(() => handleResponse(invalidUrl)).toThrow('Invalid URL');
6461
});
6562
});
Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,24 @@
11
import { WebBasedWalletCommunicator } from './webBased/Communicator';
22
import { MWP_RESPONSE_PATH } from ':core/constants';
3-
import { Wallet } from ':core/wallet';
43

54
/**
65
* Handles the response from a deeplink.
76
*
87
* @param responseUrl - The URL of the response.
9-
* @param wallet - The wallet object.
108
* @returns A boolean indicating whether the response was handled successfully.
119
*/
12-
export function handleResponse(responseUrl: string, wallet: Wallet): boolean {
10+
export function handleResponse(responseUrl: string): boolean {
1311
const pathname = new URL(responseUrl).pathname;
1412

1513
if (!pathname.includes(MWP_RESPONSE_PATH)) {
1614
return false;
1715
}
1816

19-
if (wallet.type === 'webBased') {
20-
const communicator = WebBasedWalletCommunicator.getInstance(wallet.scheme);
21-
return communicator.handleResponse(responseUrl);
17+
if (WebBasedWalletCommunicator.handleResponse(responseUrl)) {
18+
return true;
2219
}
2320

24-
if (wallet.type === 'native') {
25-
throw new Error('Native wallet not supported yet');
26-
}
21+
// NativeWalletCommunicator.handleResponse
2722

2823
return false;
2924
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
export * from './getCommunicator';
21
export * from './handleResponse';
2+
export * from './postRequestToWallet';

0 commit comments

Comments
 (0)