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

Feat/required features #324

Open
wants to merge 8 commits into
base: feat/extra-currency
Choose a base branch
from
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
6 changes: 5 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,11 @@ module.exports = {
},
{
"sourceTag": "scope:ui",
"onlyDependOnLibsWithTags": ["scope:core"]
"onlyDependOnLibsWithTags": ["scope:sdk"]
},
{
"sourceTag": "scope:ui-react",
"onlyDependOnLibsWithTags": ["scope:ui"]
}
]
}
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
node_modules
dist
.idea
.vscode
.DS_Store
22 changes: 10 additions & 12 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export interface ConnectEventError {
payload: {
code: CONNECT_EVENT_ERROR_CODES;
message: string;
device?: DeviceInfo;
Copy link
Author

Choose a reason for hiding this comment

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

Remove changes in protocolo

};
}

Expand All @@ -28,7 +29,8 @@ export enum CONNECT_EVENT_ERROR_CODES {
MANIFEST_CONTENT_ERROR = 3,
UNKNOWN_APP_ERROR = 100,
USER_REJECTS_ERROR = 300,
METHOD_NOT_SUPPORTED = 400
METHOD_NOT_SUPPORTED = 400,
MISSING_REQUIRED_FEATURES = 430
}

export type ConnectItemReply = TonAddressItemReply | TonProofItemReply;
Expand Down
8 changes: 7 additions & 1 deletion packages/sdk/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
module.exports = {
extends: ["../../.eslintrc.js"],
extends: ['../../.eslintrc.js'],
overrides: [
{
files: './vite.config.ts',
Expand All @@ -9,6 +9,12 @@ module.exports = {
tsconfigRootDir: __dirname,
createDefaultProgram: true
},
'@nx/enforce-module-boundaries': [
'error',
{
allow: ['scope:protocol']
}
]
}
]
};
1 change: 1 addition & 0 deletions packages/sdk/src/errors/protocol/events/connect/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { UserRejectsError } from 'src/errors/protocol/events/connect/user-rejects.error';
export { MissingRequiredFeaturesError } from 'src/errors/protocol/events/connect/missing-required-features.error';
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { DeviceInfo } from '@tonconnect/protocol';
import { TonConnectError } from 'src/errors/ton-connect.error';

/**
* Thrown when wallet can't get manifest by passed manifestUrl.
*/
export class MissingRequiredFeaturesError extends TonConnectError {
Copy link
Author

Choose a reason for hiding this comment

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

Maybe need use generic for device

declare cause: {
device: DeviceInfo;
};

protected get info(): string {
return 'Missing required features. You need to update your wallet.';
}

constructor(...args: ConstructorParameters<typeof TonConnectError>) {
super(...args);

Object.setPrototypeOf(this, MissingRequiredFeaturesError.prototype);
}
}
4 changes: 4 additions & 0 deletions packages/sdk/src/models/ton-connect-options.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { Feature } from '@tonconnect/protocol';
import { IStorage } from 'src/storage/models/storage.interface';
import { EventDispatcher } from 'src/tracker/event-dispatcher';
import { SdkActionEvent } from 'src/tracker/types';
import { RequireFeature } from './wallet';

/**
* TonConnect constructor options
Expand Down Expand Up @@ -35,6 +37,8 @@ export interface TonConnectOptions {
*/
walletsListCacheTTLMs?: number;

walletsRequiredFeatures?: RequireFeature[] | ((features: Feature[]) => boolean);
Copy link
Author

Choose a reason for hiding this comment

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

Add descriptioins


/**
* Allows to disable auto pause/unpause SSE connection on 'document.visibilitychange' event. It is not recommended to change default behaviour.
*/
Expand Down
5 changes: 5 additions & 0 deletions packages/sdk/src/models/wallet/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,8 @@ export {
isWalletInfoRemote,
isWalletInfoInjected
} from './wallet-info';
export {
RequireFeature,
RequireSendTransactionFeature,
RequireSignDataFeature
} from './require-feature';
11 changes: 11 additions & 0 deletions packages/sdk/src/models/wallet/require-feature.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export type RequireFeature = RequireSendTransactionFeature | RequireSignDataFeature

export type RequireSendTransactionFeature = {
name: 'SendTransaction';
minMessages?: number;
extraCurrencyRequired?: boolean;
};

export type RequireSignDataFeature = {
Copy link
Author

Choose a reason for hiding this comment

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

Remove signData

name: 'SignData';
};
13 changes: 13 additions & 0 deletions packages/sdk/src/models/wallet/wallet-info.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { Feature } from "@tonconnect/protocol";

/**
* Common information for injectable and http-compatible wallets.
*/
Expand Down Expand Up @@ -27,6 +29,16 @@ export interface WalletInfoBase {
*/
aboutUrl: string;

/**
* List of features supported by the wallet.
*/
features?: Feature[];

/**
* Indicates if the wallet supports required features.
*/
isSupportRequiredFeatures: boolean;
Copy link
Author

Choose a reason for hiding this comment

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

Check in UIWalletList, for injected wallets


/**
* OS and browsers where the wallet could be installed
*/
Expand Down Expand Up @@ -119,6 +131,7 @@ export interface WalletInfoDTO {
tondns?: string;
about_url: string;
universal_url?: string;
features?: Feature[];
platforms: (
| 'ios'
| 'android'
Expand Down
13 changes: 6 additions & 7 deletions packages/sdk/src/parsers/connect-errors-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { ManifestNotFoundError } from 'src/errors/protocol/events/connect/manife
import { TonConnectError } from 'src/errors/ton-connect.error';
import { UnknownError } from 'src/errors/unknown.error';
import { CONNECT_EVENT_ERROR_CODES, ConnectEventError } from '@tonconnect/protocol';
import { MissingRequiredFeaturesError } from 'src/errors/protocol/events/connect/missing-required-features.error';

const connectEventErrorsCodes: Partial<Record<CONNECT_EVENT_ERROR_CODES, typeof TonConnectError>> =
{
Expand All @@ -12,18 +13,16 @@ const connectEventErrorsCodes: Partial<Record<CONNECT_EVENT_ERROR_CODES, typeof
[CONNECT_EVENT_ERROR_CODES.BAD_REQUEST_ERROR]: BadRequestError,
[CONNECT_EVENT_ERROR_CODES.UNKNOWN_APP_ERROR]: UnknownAppError,
[CONNECT_EVENT_ERROR_CODES.MANIFEST_NOT_FOUND_ERROR]: ManifestNotFoundError,
[CONNECT_EVENT_ERROR_CODES.MANIFEST_CONTENT_ERROR]: ManifestContentErrorError
[CONNECT_EVENT_ERROR_CODES.MANIFEST_CONTENT_ERROR]: ManifestContentErrorError,
[CONNECT_EVENT_ERROR_CODES.MISSING_REQUIRED_FEATURES]: MissingRequiredFeaturesError
};

class ConnectErrorsParser {
parseError(error: ConnectEventError['payload']): TonConnectError {
let ErrorConstructor: typeof TonConnectError = UnknownError;
Copy link
Author

Choose a reason for hiding this comment

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

Move to another function

const ErrorConstructor = connectEventErrorsCodes[error.code] ?? UnknownError;
const options = "device" in error ? { cause: { device: error.device } } : undefined;

if (error.code in connectEventErrorsCodes) {
ErrorConstructor = connectEventErrorsCodes[error.code] || UnknownError;
}

return new ErrorConstructor(error.message);
return new ErrorConstructor(error.message, options);
}
}

Expand Down
15 changes: 12 additions & 3 deletions packages/sdk/src/provider/injected/injected-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
AppRequest,
ConnectEventError,
ConnectRequest,
Feature,
RpcMethod,
WalletEvent,
WalletResponse
Expand Down Expand Up @@ -47,7 +48,9 @@ export class InjectedProvider<T extends string = string> implements InternalProv
return false;
}

public static getCurrentlyInjectedWallets(): WalletInfoCurrentlyInjected[] {
public static getCurrentlyInjectedWallets(
checkRequiredFeatures: (features: Feature[] | undefined) => boolean
): WalletInfoCurrentlyInjected[] {
if (!this.window) {
return [];
}
Expand All @@ -66,7 +69,11 @@ export class InjectedProvider<T extends string = string> implements InternalProv
jsBridgeKey,
injected: true,
embedded: wallet.tonconnect.isWalletBrowser,
platforms: wallet.tonconnect.walletInfo.platforms
platforms: wallet.tonconnect.walletInfo.platforms,
features: wallet.tonconnect.walletInfo.features,
isSupportRequiredFeatures: checkRequiredFeatures(
wallet.tonconnect.walletInfo.features
),
}));
}

Expand Down Expand Up @@ -184,7 +191,9 @@ export class InjectedProvider<T extends string = string> implements InternalProv
): Promise<WithoutId<WalletResponse<T>>>;
public async sendRequest<T extends RpcMethod>(
request: WithoutId<AppRequest<T>>,
optionsOrOnRequestSent?: (() => void) | { onRequestSent?: () => void; signal?: AbortSignal; attempts?: number }
optionsOrOnRequestSent?:
| (() => void)
| { onRequestSent?: () => void; signal?: AbortSignal; attempts?: number }
): Promise<WithoutId<WalletResponse<T>>> {
// TODO: remove deprecated method
const options: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export interface InjectedWalletApi {
deviceInfo: DeviceInfo;
walletInfo: Pick<
WalletInfoDTO,
'name' | 'app_name' | 'tondns' | 'image' | 'about_url' | 'platforms'
'name' | 'app_name' | 'tondns' | 'image' | 'about_url' | 'platforms' | 'features'
>;
protocolVersion: number;
isWalletBrowser: boolean;
Expand Down
33 changes: 31 additions & 2 deletions packages/sdk/src/ton-connect.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import {
CONNECT_EVENT_ERROR_CODES,
ConnectEventError,
ConnectEventSuccess,
ConnectItem,
ConnectRequest,
Feature,
SendTransactionRpcResponseSuccess,
TonAddressItemReply,
TonProofItemReply,
Expand All @@ -16,6 +18,7 @@ import { WalletAlreadyConnectedError } from 'src/errors/wallet/wallet-already-co
import { WalletNotConnectedError } from 'src/errors/wallet/wallet-not-connected.error';
import {
Account,
RequireFeature,
Wallet,
WalletConnectionSource,
WalletConnectionSourceHTTP,
Expand All @@ -39,7 +42,10 @@ import { ITonConnect } from 'src/ton-connect.interface';
import { getDocument, getWebPageManifest } from 'src/utils/web-api';
import { WalletsListManager } from 'src/wallets-list-manager';
import { WithoutIdDistributive } from 'src/utils/types';
import { checkSendTransactionSupport } from 'src/utils/feature-support';
import {
checkSendTransactionSupport,
checkRequiredWalletFeatures
} from 'src/utils/feature-support';
import { callForSuccess } from 'src/utils/call-for-success';
import { logDebug, logError } from 'src/utils/log';
import { createAbortController } from 'src/utils/create-abort-controller';
Expand Down Expand Up @@ -90,6 +96,11 @@ export class TonConnect implements ITonConnect {

private statusChangeErrorSubscriptions: ((err: TonConnectError) => void)[] = [];

private readonly walletsRequiredFeatures:
| RequireFeature[]
| ((features: Feature[]) => boolean)
| undefined;

private abortController?: AbortController;

/**
Expand Down Expand Up @@ -124,9 +135,12 @@ export class TonConnect implements ITonConnect {
storage: options?.storage || new DefaultStorage()
};

this.walletsRequiredFeatures = options?.walletsRequiredFeatures;

this.walletsList = new WalletsListManager({
walletsListSource: options?.walletsListSource,
cacheTTLMs: options?.walletsListCacheTTLMs
cacheTTLMs: options?.walletsListCacheTTLMs,
walletsRequiredFeatures: options?.walletsRequiredFeatures
});

this.tracker = new TonConnectTracker({
Expand Down Expand Up @@ -568,6 +582,21 @@ export class TonConnect implements ITonConnect {
throw new TonConnectError('ton_addr connection item was not found');
}

const hasRequiredFeatures = checkRequiredWalletFeatures(
connectEvent.device.features,
this.walletsRequiredFeatures ?? []
);

if (!hasRequiredFeatures) {
this.provider?.disconnect();
this.walletEventsListener({ event: 'connect_error', payload: {
code: CONNECT_EVENT_ERROR_CODES.MISSING_REQUIRED_FEATURES,
message: 'Wallet does not support required features',
device: connectEvent.device
} });
return;
}

const wallet: Wallet = {
device: connectEvent.device,
provider: this.provider!.type,
Expand Down
Loading