Skip to content

Commit 72edc58

Browse files
committed
feat: Add option to hide return modal
1 parent 13cd092 commit 72edc58

13 files changed

Lines changed: 231 additions & 2 deletions

File tree

packages/sdk/src/PostMessageStream/RemoteCommunicationPostMessageStream.test.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,22 @@ describe('RemoteCommunicationPostMessageStream', () => {
3636
);
3737
});
3838

39+
it('should initialize with hideReturnToAppModal option', () => {
40+
const instanceWithOption = new RemoteCommunicationPostMessageStream({
41+
name: ProviderConstants.PROVIDER,
42+
remote: mockRemoteCommunication,
43+
deeplinkProtocol: false,
44+
platformManager: mockPlatformManager,
45+
hideReturnToAppModal: true,
46+
});
47+
48+
expect(instanceWithOption.state.hideReturnToAppModal).toBe(true);
49+
});
50+
51+
it('should have hideReturnToAppModal as false by default', () => {
52+
expect(instance.state.hideReturnToAppModal).toBe(false);
53+
});
54+
3955
it('should call _write properly', async () => {
4056
const chunk = 'someData';
4157
const encoding = 'utf8';

packages/sdk/src/PostMessageStream/RemoteCommunicationPostMessageStream.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ interface RemoteCommunicationPostMessageStreamState {
1414
_name: any;
1515
remote: RemoteCommunication | null;
1616
deeplinkProtocol: boolean;
17+
hideReturnToAppModal?: boolean;
1718
platformManager: PlatformManager | null;
1819
}
1920

@@ -25,17 +26,20 @@ export class RemoteCommunicationPostMessageStream
2526
_name: null,
2627
remote: null,
2728
deeplinkProtocol: false,
29+
hideReturnToAppModal: false,
2830
platformManager: null,
2931
};
3032

3133
constructor({
3234
name,
3335
remote,
3436
deeplinkProtocol,
37+
hideReturnToAppModal,
3538
platformManager,
3639
}: {
3740
name: ProviderConstants;
3841
deeplinkProtocol: boolean;
42+
hideReturnToAppModal?: boolean;
3943
remote: RemoteCommunication;
4044
platformManager: PlatformManager;
4145
}) {
@@ -45,6 +49,8 @@ export class RemoteCommunicationPostMessageStream
4549
this.state._name = name;
4650
this.state.remote = remote;
4751
this.state.deeplinkProtocol = deeplinkProtocol;
52+
this.state.hideReturnToAppModal =
53+
hideReturnToAppModal ?? this.state.hideReturnToAppModal;
4854
this.state.platformManager = platformManager;
4955

5056
this._onMessage = this._onMessage.bind(this);

packages/sdk/src/PostMessageStream/getPostMessageStream.test.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,4 +59,38 @@ describe('getPostMessageStream', () => {
5959
platformManager: fakePlatformManager,
6060
});
6161
});
62+
63+
it('should pass hideReturnToAppModal from remoteConnection state', () => {
64+
const fakeConnector = {};
65+
const fakePlatformManager = {};
66+
const hideReturnToAppModal = true;
67+
mockRemoteConnection.mockImplementation(
68+
() =>
69+
({
70+
getConnector: jest.fn().mockReturnValue(fakeConnector),
71+
getPlatformManager: jest.fn().mockReturnValue(fakePlatformManager),
72+
state: {
73+
deeplinkProtocol: false,
74+
hideReturnToAppModal,
75+
},
76+
} as any),
77+
);
78+
79+
const result = getPostMessageStream({
80+
name: ProviderConstants.CONTENT_SCRIPT,
81+
remoteConnection: new RemoteConnection({
82+
getConnector: jest.fn().mockReturnValue(fakeConnector),
83+
} as any),
84+
debug: false,
85+
} as any);
86+
87+
expect(result).toBeInstanceOf(RemoteCommunicationPostMessageStream);
88+
expect(mockPostMessageStream).toHaveBeenCalledWith({
89+
name: ProviderConstants.CONTENT_SCRIPT,
90+
remote: fakeConnector,
91+
deeplinkProtocol: false,
92+
platformManager: fakePlatformManager,
93+
hideReturnToAppModal,
94+
});
95+
});
6296
});

packages/sdk/src/PostMessageStream/getPostMessageStream.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export const getPostMessageStream = ({
2525
name,
2626
remote: remoteConnection?.getConnector(),
2727
deeplinkProtocol: remoteConnection?.state.deeplinkProtocol,
28+
hideReturnToAppModal: remoteConnection?.state.hideReturnToAppModal,
2829
platformManager: remoteConnection?.getPlatformManager(),
2930
});
3031
};

packages/sdk/src/sdk.test.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,33 @@ describe('MetaMaskSDK', () => {
199199
expect(sdk.options).toMatchObject(options);
200200
});
201201

202+
it('should initialize with hideReturnToAppModal option', () => {
203+
const options: MetaMaskSDKOptions = {
204+
hideReturnToAppModal: true,
205+
dappMetadata: {
206+
name: 'Test DApp',
207+
url: 'http://test-dapp.com',
208+
},
209+
};
210+
211+
sdk = new MetaMaskSDK(options);
212+
213+
expect(sdk.options.hideReturnToAppModal).toBe(true);
214+
});
215+
216+
it('should have hideReturnToAppModal as undefined by default', () => {
217+
const options: MetaMaskSDKOptions = {
218+
dappMetadata: {
219+
name: 'Test DApp',
220+
url: 'http://test-dapp.com',
221+
},
222+
};
223+
224+
sdk = new MetaMaskSDK(options);
225+
226+
expect(sdk.options.hideReturnToAppModal).toBeUndefined();
227+
});
228+
202229
it('should set max listeners', () => {
203230
expect(sdk.getMaxListeners()).toBe(50);
204231
});

packages/sdk/src/sdk.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,12 @@ export interface MetaMaskSDKOptions {
9191
*/
9292
useDeeplink?: boolean;
9393

94+
/**
95+
* If true, MetaMask Mobile will hide the modal that invites the user to return to the app after performing an action on MetaMask Mobile.
96+
* This should be used when the app is loaded in an iframe inside the MetaMask Mobile browser.
97+
*/
98+
hideReturnToAppModal?: boolean;
99+
94100
/**
95101
* If true, the SDK will shim the window.web3 object with the provider returned by the SDK (useful for compatibility with older browser).
96102
*/
@@ -220,6 +226,7 @@ export class MetaMaskSDK extends EventEmitter2 {
220226
enableAnalytics: true,
221227
shouldShimWeb3: true,
222228
useDeeplink: true,
229+
hideReturnToAppModal: false,
223230
extensionOnly: true,
224231
headless: false,
225232
dappMetadata: {

packages/sdk/src/services/MetaMaskSDK/InitializerManager/performSDKInitialization.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ describe('performSDKInitialization', () => {
5757
injectProvider: true,
5858
shouldShimWeb3: true,
5959
useDeeplink: true,
60+
hideReturnToAppModal: false,
6061
storage: {
6162
enabled: true,
6263
},

packages/sdk/src/services/MetaMaskSDK/InitializerManager/performSDKInitialization.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ export async function performSDKInitialization(instance: MetaMaskSDK) {
5757
options.shouldShimWeb3 = options.shouldShimWeb3 ?? true;
5858
options.extensionOnly = options.extensionOnly ?? true;
5959
options.useDeeplink = options.useDeeplink ?? true;
60+
options.hideReturnToAppModal = options.hideReturnToAppModal ?? false;
6061
options.storage = options.storage ?? {
6162
enabled: true,
6263
};

packages/sdk/src/services/RemoteCommunicationPostMessageStream/write.test.ts

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,4 +317,83 @@ describe('write function', () => {
317317
expect(mockSendMessage).toHaveBeenCalled();
318318
});
319319
});
320+
321+
describe('hideReturnToAppModal URL parameter', () => {
322+
beforeEach(() => {
323+
mockIsReady.mockReturnValue(true);
324+
mockIsConnected.mockReturnValue(true);
325+
mockIsAuthorized.mockReturnValue(true);
326+
mockIsMobileWeb.mockReturnValue(false);
327+
mockIsSecure.mockReturnValue(true);
328+
mockGetChannelId.mockReturnValue('some_channel_id');
329+
mockIsMetaMaskInstalled.mockReturnValue(true);
330+
mockGetKeyInfo.mockReturnValue({ ecies: { public: 'test_public_key' } });
331+
mockHasDeeplinkProtocol.mockReturnValue(false);
332+
mockExtractMethod.mockReturnValue({
333+
method: Object.keys(METHODS_TO_REDIRECT)[0],
334+
data: {
335+
data: {
336+
jsonrpc: '2.0',
337+
method: Object.keys(METHODS_TO_REDIRECT)[0],
338+
params: [],
339+
},
340+
},
341+
triggeredInstaller: false,
342+
});
343+
});
344+
345+
it('should include hr=1 in URL when hideReturnToAppModal is true', async () => {
346+
mockRemoteCommunicationPostMessageStream.state.hideReturnToAppModal =
347+
true;
348+
349+
await write(
350+
mockRemoteCommunicationPostMessageStream,
351+
{ jsonrpc: '2.0', method: Object.keys(METHODS_TO_REDIRECT)[0] },
352+
'utf8',
353+
callback,
354+
);
355+
356+
expect(mockOpenDeeplink).toHaveBeenCalledWith(
357+
expect.stringContaining('hr=1'),
358+
expect.stringContaining('hr=1'),
359+
'_self',
360+
);
361+
});
362+
363+
it('should include hr=0 in URL when hideReturnToAppModal is false', async () => {
364+
mockRemoteCommunicationPostMessageStream.state.hideReturnToAppModal =
365+
false;
366+
367+
await write(
368+
mockRemoteCommunicationPostMessageStream,
369+
{ jsonrpc: '2.0', method: Object.keys(METHODS_TO_REDIRECT)[0] },
370+
'utf8',
371+
callback,
372+
);
373+
374+
expect(mockOpenDeeplink).toHaveBeenCalledWith(
375+
expect.stringContaining('hr=0'),
376+
expect.stringContaining('hr=0'),
377+
'_self',
378+
);
379+
});
380+
381+
it('should include hr=0 in URL when hideReturnToAppModal is undefined', async () => {
382+
mockRemoteCommunicationPostMessageStream.state.hideReturnToAppModal =
383+
undefined;
384+
385+
await write(
386+
mockRemoteCommunicationPostMessageStream,
387+
{ jsonrpc: '2.0', method: Object.keys(METHODS_TO_REDIRECT)[0] },
388+
'utf8',
389+
callback,
390+
);
391+
392+
expect(mockOpenDeeplink).toHaveBeenCalledWith(
393+
expect.stringContaining('hr=0'),
394+
expect.stringContaining('hr=0'),
395+
'_self',
396+
);
397+
});
398+
});
320399
});

packages/sdk/src/services/RemoteCommunicationPostMessageStream/write.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,9 @@ export async function write(
100100

101101
const pubKey = instance.state.remote?.getKeyInfo()?.ecies.public ?? '';
102102
let urlParams = encodeURI(
103-
`channelId=${channelId}&pubkey=${pubKey}&comm=socket&t=d&v=2`,
103+
`channelId=${channelId}&pubkey=${pubKey}&comm=socket&t=d&v=2&hr=${
104+
instance.state.hideReturnToAppModal ? 1 : 0
105+
}`,
104106
);
105107

106108
if (activeDeeplinkProtocol) {

0 commit comments

Comments
 (0)