Skip to content
Open
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
17 changes: 6 additions & 11 deletions packages/sdk/src/provider/bridge/bridge-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import { BridgeIncomingMessage } from 'src/provider/bridge/models/bridge-incommi
import { BridgePartialSession, BridgeSession } from 'src/provider/bridge/models/bridge-session';
import { HTTPProvider } from 'src/provider/provider';
import { BridgeConnectionStorage } from 'src/storage/bridge-connection-storage';
import { IStorage } from 'src/storage/models/storage.interface';
import { Optional, OptionalTraceable, Traceable, WithoutId } from 'src/utils/types';
import { PROTOCOL_VERSION } from 'src/resources/protocol';
import { logDebug, logError } from 'src/utils/log';
Expand All @@ -36,11 +35,10 @@ import { UUIDv7 } from 'src/utils/uuid';

export class BridgeProvider implements HTTPProvider {
public static async fromStorage(
storage: IStorage,
storage: BridgeConnectionStorage,
analyticsManager?: AnalyticsManager
): Promise<BridgeProvider> {
const bridgeConnectionStorage = new BridgeConnectionStorage(storage);
const connection = await bridgeConnectionStorage.getHttpConnection();
const connection = await storage.getHttpConnection();

if (isPendingConnectionHttp(connection)) {
return new BridgeProvider(storage, connection.connectionSource, analyticsManager);
Expand All @@ -56,8 +54,6 @@ export class BridgeProvider implements HTTPProvider {

private readonly standardUniversalLink = 'tc://';

private readonly connectionStorage: BridgeConnectionStorage;

private readonly pendingRequests = new Map<
string,
(response: TraceableWalletResponse<RpcMethod>) => void
Expand All @@ -80,13 +76,12 @@ export class BridgeProvider implements HTTPProvider {
private readonly analytics?: Analytics<BridgeClientEvent>;

constructor(
private readonly storage: IStorage,
private readonly connectionStorage: BridgeConnectionStorage,
private readonly walletConnectionSource:
| Optional<WalletConnectionSourceHTTP, 'universalLink'>
| Pick<WalletConnectionSourceHTTP, 'bridgeUrl'>[],
private readonly analyticsManager?: AnalyticsManager
) {
this.connectionStorage = new BridgeConnectionStorage(storage);
this.analytics = this.analyticsManager?.scoped();
}

Expand Down Expand Up @@ -208,7 +203,7 @@ export class BridgeProvider implements HTTPProvider {
}

this.gateway = new BridgeGateway(
this.storage,
this.connectionStorage.storage,
this.walletConnectionSource.bridgeUrl,
storedConnection.session.sessionCrypto.sessionId,
this.gatewayListener.bind(this),
Expand Down Expand Up @@ -603,7 +598,7 @@ export class BridgeProvider implements HTTPProvider {
// open new gateways
this.pendingGateways = this.walletConnectionSource.map(source => {
const gateway = new BridgeGateway(
this.storage,
this.connectionStorage.storage,
source.bridgeUrl,
sessionCrypto.sessionId,
() => {},
Expand Down Expand Up @@ -650,7 +645,7 @@ export class BridgeProvider implements HTTPProvider {
}

this.gateway = new BridgeGateway(
this.storage,
this.connectionStorage.storage,
this.walletConnectionSource.bridgeUrl,
sessionCrypto.sessionId,
this.gatewayListener.bind(this),
Expand Down
11 changes: 3 additions & 8 deletions packages/sdk/src/provider/injected/injected-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import {
} from 'src/provider/injected/models/injected-wallet-api';
import { InternalProvider } from 'src/provider/provider';
import { BridgeConnectionStorage } from 'src/storage/bridge-connection-storage';
import { IStorage } from 'src/storage/models/storage.interface';
import { OptionalTraceable, Traceable, WithoutId } from 'src/utils/types';
import { getWindow, getWindowEntries } from 'src/utils/web-api';
import { PROTOCOL_VERSION } from 'src/resources/protocol';
Expand All @@ -34,11 +33,10 @@ export class InjectedProvider<T extends string = string> implements InternalProv
private static window = getWindow();

public static async fromStorage(
storage: IStorage,
storage: BridgeConnectionStorage,
analyticsManager?: AnalyticsManager
): Promise<InjectedProvider> {
const bridgeConnectionStorage = new BridgeConnectionStorage(storage);
const connection = await bridgeConnectionStorage.getInjectedConnection();
const connection = await storage.getInjectedConnection();
return new InjectedProvider(storage, connection.jsBridgeKey, analyticsManager);
}

Expand Down Expand Up @@ -97,8 +95,6 @@ export class InjectedProvider<T extends string = string> implements InternalProv

private injectedWallet: InjectedWalletApi;

private readonly connectionStorage: BridgeConnectionStorage;

private listenSubscriptions = false;

private listeners: Array<(e: TraceableWalletEvent) => void> = [];
Expand All @@ -108,7 +104,7 @@ export class InjectedProvider<T extends string = string> implements InternalProv
>;

constructor(
storage: IStorage,
private readonly connectionStorage: BridgeConnectionStorage,
private readonly injectedWalletKey: T,
analyticsManager?: AnalyticsManager
) {
Expand All @@ -117,7 +113,6 @@ export class InjectedProvider<T extends string = string> implements InternalProv
throw new WalletNotInjectedError();
}

this.connectionStorage = new BridgeConnectionStorage(storage);
this.injectedWallet = window[injectedWalletKey]!.tonconnect!;

if (analyticsManager) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import { TraceableWalletEvent, TraceableWalletResponse } from 'src/models/wallet
import { OptionalTraceable, Traceable, WithoutId } from 'src/utils/types';
import { UUIDv7 } from 'src/utils/uuid';
import { InternalProvider } from 'src/provider/provider';
import { IStorage } from 'src/storage/models/storage.interface';
import { BridgeConnectionStorage } from 'src/storage/bridge-connection-storage';
import { TonConnectError } from 'src/errors';
import {
Expand Down Expand Up @@ -50,8 +49,6 @@ export class WalletConnectProvider implements InternalProvider {

private abortController?: AbortController;

private readonly connectionStorage: BridgeConnectionStorage;

private readonly config: {
projectId: string;
metadata: WalletConnectMetadata;
Expand All @@ -70,9 +67,7 @@ export class WalletConnectProvider implements InternalProvider {
}[];
};

constructor(storage: IStorage) {
this.connectionStorage = new BridgeConnectionStorage(storage);

constructor(private readonly connectionStorage: BridgeConnectionStorage) {
const { projectId, metadata } = getWalletConnectOptions();

this.config = {
Expand Down Expand Up @@ -106,7 +101,9 @@ export class WalletConnectProvider implements InternalProvider {
};
}

public static async fromStorage(storage: IStorage): Promise<WalletConnectProvider> {
public static async fromStorage(
storage: BridgeConnectionStorage
): Promise<WalletConnectProvider> {
return new WalletConnectProvider(storage);
}

Expand Down
39 changes: 36 additions & 3 deletions packages/sdk/src/storage/bridge-connection-storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,16 @@ import {
isPendingConnectionHttpRaw
} from 'src/provider/bridge/models/bridge-connection';
import { IStorage } from 'src/storage/models/storage.interface';
import { logDebug } from 'src/utils/log';
import { WalletsListManager } from 'src/wallets-list-manager';

export class BridgeConnectionStorage {
private readonly storeKey = 'ton-connect-storage_bridge-connection';

constructor(private readonly storage: IStorage) {}
constructor(
public readonly storage: IStorage,
private readonly walletsListManager: WalletsListManager
) {}

public async storeConnection(connection: BridgeConnection): Promise<void> {
if (connection.type === 'injected' || connection.type === 'wallet-connect') {
Expand Down Expand Up @@ -71,7 +76,7 @@ export class BridgeConnectionStorage {

if (!isPendingConnectionHttpRaw(connection)) {
const sessionCrypto = new SessionCrypto(connection.session.sessionKeyPair);
return {
return this.actualizeBridgeConnection({
type: 'http',
connectEvent: connection.connectEvent,
lastWalletEventId: connection.lastWalletEventId,
Expand All @@ -81,7 +86,7 @@ export class BridgeConnectionStorage {
bridgeUrl: connection.session.bridgeUrl,
walletPublicKey: connection.session.walletPublicKey
}
};
});
}

if (isExpiredPendingConnectionHttpRaw(connection)) {
Expand Down Expand Up @@ -214,4 +219,32 @@ export class BridgeConnectionStorage {

return 0;
}

private async actualizeBridgeConnection(
connection: BridgeConnectionHttp
): Promise<BridgeConnectionHttp> {
try {
const appName = connection.connectEvent.payload.device.appName;
const wallet = await this.walletsListManager.getRemoteWallet(appName);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If not found, we should use existing connection


if (wallet.bridgeUrl === connection.session.bridgeUrl) {
return connection;
}

const actualizedConnection = {
...connection,
session: {
...connection.session,
bridgeUrl: wallet.bridgeUrl
}
} satisfies BridgeConnectionHttp;

await this.storeConnection(connection);

return actualizedConnection;
} catch (error) {
logDebug('Failed to actualize bridge connection', error);
return connection;
}
}
}
21 changes: 13 additions & 8 deletions packages/sdk/src/ton-connect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ export class TonConnect implements ITonConnect {
*/
private readonly tracker: TonConnectTracker;

private readonly walletsList = new WalletsListManager();
private readonly walletsList: WalletsListManager;

private readonly analytics?: AnalyticsManager;

Expand Down Expand Up @@ -205,7 +205,10 @@ export class TonConnect implements ITonConnect {
);
}

this.bridgeConnectionStorage = new BridgeConnectionStorage(this.dappSettings.storage);
this.bridgeConnectionStorage = new BridgeConnectionStorage(
this.dappSettings.storage,
this.walletsList
);

if (!options?.disableAutoPauseConnection) {
this.addWindowFocusAndBlurSubscriptions();
Expand Down Expand Up @@ -408,18 +411,20 @@ export class TonConnect implements ITonConnect {
switch (bridgeConnectionType) {
case 'http':
provider = await BridgeProvider.fromStorage(
this.dappSettings.storage,
this.bridgeConnectionStorage,
this.analytics
);
break;
case 'injected':
provider = await InjectedProvider.fromStorage(
this.dappSettings.storage,
this.bridgeConnectionStorage,
this.analytics
);
break;
case 'wallet-connect':
provider = await WalletConnectProvider.fromStorage(this.dappSettings.storage);
provider = await WalletConnectProvider.fromStorage(
this.bridgeConnectionStorage
);
break;
default:
if (embeddedWallet) {
Expand Down Expand Up @@ -848,14 +853,14 @@ export class TonConnect implements ITonConnect {

if (!Array.isArray(wallet) && isWalletConnectionSourceJS(wallet)) {
provider = new InjectedProvider(
this.dappSettings.storage,
this.bridgeConnectionStorage,
wallet.jsBridgeKey,
this.analytics
);
} else if (!Array.isArray(wallet) && isWalletConnectionSourceWalletConnect(wallet)) {
provider = new WalletConnectProvider(this.dappSettings.storage);
provider = new WalletConnectProvider(this.bridgeConnectionStorage);
} else {
provider = new BridgeProvider(this.dappSettings.storage, wallet, this.analytics);
provider = new BridgeProvider(this.bridgeConnectionStorage, wallet, this.analytics);
}

provider.listen(this.walletEventsListener.bind(this));
Expand Down
17 changes: 17 additions & 0 deletions packages/sdk/src/wallets-list-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { InjectedProvider } from 'src/provider/injected/injected-provider';
import { logError } from 'src/utils/log';
import { FALLBACK_WALLETS_LIST } from 'src/resources/fallback-wallets-list';
import { isQaModeEnabled } from './utils/qa-mode';
import { TonConnectError } from 'src/errors';

export class WalletsListManager {
private walletsListDTOCache: Promise<WalletInfoDTO[]> | null = null;
Expand Down Expand Up @@ -77,6 +78,22 @@ export class WalletsListManager {
return this.walletsListDTOCache;
}

public async getRemoteWallet(appName: string): Promise<WalletInfoRemote> {
const walletsList = await this.getWallets();

const wallet = walletsList.find(wallet => wallet.appName === appName);

if (!wallet) {
throw new TonConnectError(`Wallet info not found for appName: "${appName}"`);
}

if (!('bridgeUrl' in wallet)) {
throw new TonConnectError(`Wallet "${appName}" is not remote`);
}

return wallet;
}

private async fetchWalletsListFromSource(): Promise<WalletInfoDTO[]> {
let walletsList: WalletInfoDTO[] = [];

Expand Down