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

fixes: connectWith sdk #10863

Merged
merged 38 commits into from
Aug 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
74bff7c
fix: invalid icon url
abretonc7s Aug 19, 2024
86cadcc
docs: comments for sdk
abretonc7s Aug 19, 2024
7d32622
feat: improve connection management
abretonc7s Aug 19, 2024
3c386f1
feat: wip
abretonc7s Aug 19, 2024
f7381b9
feat: wip
abretonc7s Aug 19, 2024
7e070c9
feat: correct server url
abretonc7s Aug 19, 2024
92d1dcc
feat: cleanup
abretonc7s Aug 19, 2024
bda8389
feat: only redirect on deeplinks
abretonc7s Aug 19, 2024
0742cb8
feat: deeplink protocol into js
abretonc7s Aug 20, 2024
9861247
feat: wip
abretonc7s Aug 20, 2024
7fe0857
feat: wait for permissions to be loaded
abretonc7s Aug 20, 2024
0d18d66
Merge remote-tracking branch 'origin/main' into asynckeyexchange
abretonc7s Aug 21, 2024
44a6ae3
feat: update comm layer
abretonc7s Aug 21, 2024
09e3cd3
feat: cleanup
abretonc7s Aug 21, 2024
0266678
fix: unit tests
abretonc7s Aug 21, 2024
6cfe37a
fix: unit tests
abretonc7s Aug 21, 2024
a20b7ca
feat: update comm layer
abretonc7s Aug 21, 2024
c1f2e87
feat: update comm layer
abretonc7s Aug 21, 2024
e6fb190
feat: revert ui changes for separate PR
abretonc7s Aug 21, 2024
81fc3e7
fix: linting
abretonc7s Aug 21, 2024
b523e66
fix: unit tests
abretonc7s Aug 21, 2024
a567b40
fix: unit tests
abretonc7s Aug 21, 2024
258e355
feat: remove loading status
abretonc7s Aug 21, 2024
9ec2726
Merge remote-tracking branch 'origin/main' into asynckeyexchange
abretonc7s Aug 21, 2024
7bd210f
fix: unit tests
abretonc7s Aug 22, 2024
586c4b1
Merge remote-tracking branch 'origin/main' into asynckeyexchange
abretonc7s Aug 22, 2024
424200d
feat: make sure permittedaccounts have loaded
abretonc7s Aug 22, 2024
d2f6ce0
feat: add channelid to page meta
abretonc7s Aug 22, 2024
454dddf
feat: cleanup
abretonc7s Aug 22, 2024
243f81c
fix: invalid icon url
abretonc7s Aug 27, 2024
0e10cf2
Merge remote-tracking branch 'origin/main' into fix/favicon
abretonc7s Aug 27, 2024
c013c90
Merge branch 'fix/favicon' into dappurl
abretonc7s Aug 28, 2024
492edf7
feat: handle rpc param
abretonc7s Aug 28, 2024
90614b4
fix: unit tests
abretonc7s Aug 28, 2024
0eb1e1f
Merge remote-tracking branch 'origin/main' into dappurl
abretonc7s Aug 28, 2024
94b2713
feat: prevent double goback android
abretonc7s Aug 29, 2024
e09e097
Merge remote-tracking branch 'origin/main' into dappurl
abretonc7s Aug 29, 2024
c9bc743
feat: prevent goback with connectAndSign
abretonc7s Aug 29, 2024
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
7 changes: 6 additions & 1 deletion app/components/Views/AccountConnect/AccountConnect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -229,12 +229,17 @@ const AccountConnect = (props: AccountConnectProps) => {
);

const actualIcon = useMemo(() => {
// Priority to dappIconUrl
if (dappIconUrl) {
return { uri: dappIconUrl };
}

const favicon = faviconSource as ImageURISource;
if ('uri' in favicon) {
return faviconSource;
}

return { uri: dappIconUrl ?? '' };
return { uri: '' };
}, [dappIconUrl, faviconSource]);

const secureIcon = useMemo(
Expand Down
91 changes: 70 additions & 21 deletions app/core/SDKConnect/handlers/handleDeeplink.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,23 @@ import AppConstants from '../../AppConstants';
import SDKConnect from '../SDKConnect';
import { waitForCondition } from '../utils/wait.util';
import handleDeeplink from './handleDeeplink';
import handleConnectionMessage from './handleConnectionMessage';

jest.mock('../SDKConnect');
jest.mock('../../AppConstants');
jest.mock('../utils/DevLogger');
jest.mock('../utils/wait.util');
jest.mock('../../../util/Logger');
jest.mock('./handleConnectionMessage');

describe('handleDeeplink', () => {
let sdkConnect = {} as unknown as SDKConnect;
// TODO: Replace "any" with type
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let fakeConnections = {} as any;

const rpc = Buffer.from('{"jsonrpc":"2.0","method":"eth_accounts"}').toString(
'base64',
);
const mockWaitForCondition = waitForCondition as jest.MockedFunction<
typeof waitForCondition
>;
Expand All @@ -33,6 +37,11 @@ describe('handleDeeplink', () => {
const mockRevalidateChannel = jest.fn();
const mockReconnect = jest.fn();
const mockConnectToChannel = jest.fn();
const mockHandleConnectionMessage =
handleConnectionMessage as jest.MockedFunction<
typeof handleConnectionMessage
>;

const mockDecrypt = jest
.fn()
.mockReturnValue('{"jsonrpc":"2.0","method":"eth_accounts"}');
Expand All @@ -46,6 +55,8 @@ describe('handleDeeplink', () => {

beforeEach(() => {
jest.clearAllMocks();
jest.resetModules();

mockUpdateSDKLoadingState.mockResolvedValue(undefined);
fakeConnections = [
{
Expand All @@ -70,6 +81,11 @@ describe('handleDeeplink', () => {
mockGetConnections.mockReturnValue(fakeConnections);
});

afterEach(() => {
jest.clearAllMocks();
jest.restoreAllMocks();
});

it('should waits for SDKConnect to initialize if not already initialized', async () => {
mockHasInitialized.mockReturnValueOnce(false).mockReturnValueOnce(true);
mockWaitForCondition.mockResolvedValue();
Expand All @@ -83,7 +99,6 @@ describe('handleDeeplink', () => {
protocolVersion,
context,
});

expect(waitForCondition).toHaveBeenCalledWith(expect.any(Object));
expect(sdkConnect.hasInitialized).toHaveBeenCalledTimes(1);
});
Expand Down Expand Up @@ -184,18 +199,50 @@ describe('handleDeeplink', () => {
);
});

it('should handle rpc calls when rpc has values and connection is valid', async () => {
const rpc = Buffer.from(
it('should handle rpc calls for existing connections', async () => {
mockHasInitialized.mockReturnValue(true);
mockGetConnections.mockReturnValue({ [channelId]: {} });

await handleDeeplink({
sdkConnect,
channelId,
origin,
url,
otherPublicKey,
protocolVersion,
context,
rpc,
});

expect(mockDecrypt).toHaveBeenCalledWith(
'{"jsonrpc":"2.0","method":"eth_accounts"}',
).toString('base64');
const decodedRPC = '{"jsonrpc":"2.0","method":"eth_accounts"}';
);
expect(handleConnectionMessage).toHaveBeenCalledWith(
expect.objectContaining({
message: expect.any(Object),
connection: expect.any(Object),
engine: expect.any(Object),
}),
);
});

(sdkConnect.getConnections as jest.Mock).mockReturnValue({
[channelId]: {},
it('should handle rpc calls for new connections', async () => {
mockHasInitialized.mockReturnValue(true);
mockGetConnections.mockReturnValue({});
mockConnectToChannel.mockReturnValue({});
mockGetConnected.mockReturnValue({
[channelId]: {
remote: {
decrypt: mockDecrypt,
},
},
});

// Spy on JSON.parse
const jsonParseSpy = jest.spyOn(JSON, 'parse');

await handleDeeplink({
sdkConnect: sdkConnect as SDKConnect,
sdkConnect,
channelId,
origin,
url,
Expand All @@ -205,21 +252,21 @@ describe('handleDeeplink', () => {
rpc,
});

expect(mockGetConnected()[channelId].remote.decrypt).toHaveBeenCalledWith(
decodedRPC,
);
expect(mockConnectToChannel).toHaveBeenCalled();

// Verify that JSON.parse was called with the correct string
expect(jsonParseSpy).toHaveBeenCalled();

expect(mockHandleConnectionMessage).toHaveBeenCalled();
});

it('should not handle rpc calls when rpc has values and connection is not found', async () => {
const rpc = Buffer.from(
'{"jsonrpc":"2.0","method":"eth_accounts"}',
).toString('base64');
(sdkConnect.getConnections as jest.Mock).mockReturnValue({
[channelId]: undefined,
});
it('should not handle rpc calls when connection is not found', async () => {
mockHasInitialized.mockReturnValue(true);
mockGetConnections.mockReturnValue({});
mockGetConnected.mockReturnValue({});

await handleDeeplink({
sdkConnect: sdkConnect as SDKConnect,
sdkConnect,
channelId,
origin,
url,
Expand All @@ -229,6 +276,8 @@ describe('handleDeeplink', () => {
rpc,
});

expect(mockGetConnected()[channelId].remote.decrypt).not.toHaveBeenCalled();
expect(mockConnectToChannel).toHaveBeenCalled();
expect(mockDecrypt).not.toHaveBeenCalled();
expect(handleConnectionMessage).not.toHaveBeenCalled();
});
});
39 changes: 38 additions & 1 deletion app/core/SDKConnect/handlers/handleDeeplink.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import SDKConnect from '../SDKConnect';
import DevLogger from '../utils/DevLogger';
import { waitForCondition } from '../utils/wait.util';
import handleConnectionMessage from './handleConnectionMessage';
import { Platform } from 'react-native';

const QRCODE_PARAM_PATTERN = '&t=q';

Expand Down Expand Up @@ -119,15 +120,51 @@ const handleDeeplink = async ({
sdkConnect.updateSDKLoadingState({ channelId, loading: true });
}
} else {
const trigger =
rpc !== undefined && origin === AppConstants.DEEPLINKS.ORIGIN_DEEPLINK
? undefined // temporarily unset trigger on android to prevent goBack after connection approval
: 'deeplink';

DevLogger.log(
`handleDeeplink:: connectToChannel - trigger=${trigger} origin=${origin} platform=${Platform.OS} rpc=${rpc}`,
);
await sdkConnect.connectToChannel({
id: channelId,
origin,
originatorInfo,
initialConnection: true,
protocolVersion,
trigger: 'deeplink',
trigger,
otherPublicKey,
});

// When RPC is provided on new connection, it means connectWith.
if (rpc) {
const connection = sdkConnect.getConnected()[channelId];
if (!connection) {
DevLogger.log(`handleDeeplink:: connection not found`);
return;
}

if (!trigger) {
// set trigger back to deeplink on android
connection.trigger = 'deeplink';
}

// Decode rpc and directly process it - simulate network reception
const decodedRPC = Buffer.from(rpc, 'base64').toString('utf-8');

DevLogger.log(`decoded rpc`, decodedRPC);

const message = JSON.parse(decodedRPC) as CommunicationLayerMessage;
DevLogger.log(`handleDeeplink:: message`, message);

await handleConnectionMessage({
message,
connection,
engine: Engine,
});
}
}
} catch (error) {
Logger.error(error as Error, 'Failed to connect to channel');
Expand Down
Loading