@tonconnect/sdk 2.1.4 → 3.0.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/cjs/index.cjs CHANGED
@@ -329,6 +329,19 @@ function removeUrlLastSlash(url) {
329
329
  function addPathToUrl(url, path) {
330
330
  return removeUrlLastSlash(url) + '/' + path;
331
331
  }
332
+ function isTelegramUrl(link) {
333
+ const url = new URL(link);
334
+ return url.protocol === 'tg:' || url.hostname === 't.me';
335
+ }
336
+ function encodeTelegramUrlParameters(parameters) {
337
+ return parameters
338
+ .replaceAll('.', '%2E')
339
+ .replaceAll('-', '%2D')
340
+ .replaceAll('_', '%5F')
341
+ .replaceAll('&', '-')
342
+ .replaceAll('=', '__')
343
+ .replaceAll('%', '--');
344
+ }
332
345
 
333
346
  class BridgeGateway {
334
347
  constructor(storage, bridgeUrl, sessionId, listener, errorsListener) {
@@ -431,6 +444,10 @@ class BridgeGateway {
431
444
  }
432
445
  }
433
446
 
447
+ function isPendingConnectionHttp(connection) {
448
+ return !('connectEvent' in connection);
449
+ }
450
+
434
451
  class BridgeConnectionStorage {
435
452
  constructor(storage) {
436
453
  this.storage = storage;
@@ -441,17 +458,25 @@ class BridgeConnectionStorage {
441
458
  if (connection.type === 'injected') {
442
459
  return this.storage.setItem(this.storeKey, JSON.stringify(connection));
443
460
  }
444
- const rawSession = {
445
- sessionKeyPair: connection.session.sessionCrypto.stringifyKeypair(),
446
- walletPublicKey: connection.session.walletPublicKey,
447
- bridgeUrl: connection.session.bridgeUrl
448
- };
461
+ if (!isPendingConnectionHttp(connection)) {
462
+ const rawSession = {
463
+ sessionKeyPair: connection.session.sessionCrypto.stringifyKeypair(),
464
+ walletPublicKey: connection.session.walletPublicKey,
465
+ bridgeUrl: connection.session.bridgeUrl
466
+ };
467
+ const rawConnection = {
468
+ type: 'http',
469
+ connectEvent: connection.connectEvent,
470
+ session: rawSession,
471
+ lastWalletEventId: connection.lastWalletEventId,
472
+ nextRpcRequestId: connection.nextRpcRequestId
473
+ };
474
+ return this.storage.setItem(this.storeKey, JSON.stringify(rawConnection));
475
+ }
449
476
  const rawConnection = {
450
477
  type: 'http',
451
- connectEvent: connection.connectEvent,
452
- session: rawSession,
453
- lastWalletEventId: connection.lastWalletEventId,
454
- nextRpcRequestId: connection.nextRpcRequestId
478
+ connectionSource: connection.connectionSource,
479
+ sessionCrypto: connection.sessionCrypto.stringifyKeypair()
455
480
  };
456
481
  return this.storage.setItem(this.storeKey, JSON.stringify(rawConnection));
457
482
  });
@@ -471,17 +496,24 @@ class BridgeConnectionStorage {
471
496
  if (connection.type === 'injected') {
472
497
  return connection;
473
498
  }
474
- const sessionCrypto = new protocol.SessionCrypto(connection.session.sessionKeyPair);
499
+ if ('connectEvent' in connection) {
500
+ const sessionCrypto = new protocol.SessionCrypto(connection.session.sessionKeyPair);
501
+ return {
502
+ type: 'http',
503
+ connectEvent: connection.connectEvent,
504
+ lastWalletEventId: connection.lastWalletEventId,
505
+ nextRpcRequestId: connection.nextRpcRequestId,
506
+ session: {
507
+ sessionCrypto,
508
+ bridgeUrl: connection.session.bridgeUrl,
509
+ walletPublicKey: connection.session.walletPublicKey
510
+ }
511
+ };
512
+ }
475
513
  return {
476
514
  type: 'http',
477
- connectEvent: connection.connectEvent,
478
- lastWalletEventId: connection.lastWalletEventId,
479
- nextRpcRequestId: connection.nextRpcRequestId,
480
- session: {
481
- sessionCrypto,
482
- bridgeUrl: connection.session.bridgeUrl,
483
- walletPublicKey: connection.session.walletPublicKey
484
- }
515
+ sessionCrypto: new protocol.SessionCrypto(connection.sessionCrypto),
516
+ connectionSource: connection.connectionSource
485
517
  };
486
518
  });
487
519
  }
@@ -497,6 +529,21 @@ class BridgeConnectionStorage {
497
529
  return connection;
498
530
  });
499
531
  }
532
+ getHttpPendingConnection() {
533
+ return __awaiter(this, void 0, void 0, function* () {
534
+ const connection = yield this.getConnection();
535
+ if (!connection) {
536
+ throw new TonConnectError('Trying to read HTTP connection source while nothing is stored');
537
+ }
538
+ if (connection.type === 'injected') {
539
+ throw new TonConnectError('Trying to read HTTP connection source while injected connection is stored');
540
+ }
541
+ if (!isPendingConnectionHttp(connection)) {
542
+ throw new TonConnectError('Trying to read HTTP-pending connection while http connection is stored');
543
+ }
544
+ return connection;
545
+ });
546
+ }
500
547
  getInjectedConnection() {
501
548
  return __awaiter(this, void 0, void 0, function* () {
502
549
  const connection = yield this.getConnection();
@@ -522,7 +569,7 @@ class BridgeConnectionStorage {
522
569
  storeLastWalletEventId(id) {
523
570
  return __awaiter(this, void 0, void 0, function* () {
524
571
  const connection = yield this.getConnection();
525
- if (connection && connection.type === 'http') {
572
+ if (connection && connection.type === 'http' && !isPendingConnectionHttp(connection)) {
526
573
  connection.lastWalletEventId = id;
527
574
  return this.storeConnection(connection);
528
575
  }
@@ -540,7 +587,7 @@ class BridgeConnectionStorage {
540
587
  increaseNextRpcRequestId() {
541
588
  return __awaiter(this, void 0, void 0, function* () {
542
589
  const connection = yield this.getConnection();
543
- if (connection) {
590
+ if (connection && 'nextRpcRequestId' in connection) {
544
591
  const lastId = connection.nextRpcRequestId || 0;
545
592
  connection.nextRpcRequestId = lastId + 1;
546
593
  return this.storeConnection(connection);
@@ -550,7 +597,7 @@ class BridgeConnectionStorage {
550
597
  getNextRpcRequestId() {
551
598
  return __awaiter(this, void 0, void 0, function* () {
552
599
  const connection = yield this.getConnection();
553
- if (connection) {
600
+ if (connection && 'nextRpcRequestId' in connection) {
554
601
  return connection.nextRpcRequestId || 0;
555
602
  }
556
603
  return 0;
@@ -602,48 +649,53 @@ class BridgeProvider {
602
649
  return __awaiter(this, void 0, void 0, function* () {
603
650
  const bridgeConnectionStorage = new BridgeConnectionStorage(storage);
604
651
  const connection = yield bridgeConnectionStorage.getHttpConnection();
652
+ if (isPendingConnectionHttp(connection)) {
653
+ return new BridgeProvider(storage, connection.connectionSource);
654
+ }
605
655
  return new BridgeProvider(storage, { bridgeUrl: connection.session.bridgeUrl });
606
656
  });
607
657
  }
608
658
  connect(message) {
609
659
  this.closeGateways();
610
660
  const sessionCrypto = new protocol.SessionCrypto();
611
- let bridgeUrl = '';
612
- let universalLink = this.standardUniversalLink;
613
- if (Array.isArray(this.walletConnectionSource)) {
614
- this.pendingGateways = this.walletConnectionSource.map(source => {
615
- const gateway = new BridgeGateway(this.storage, source.bridgeUrl, sessionCrypto.sessionId, () => { }, e => {
616
- console.error(e);
617
- });
618
- gateway.setListener(message => this.pendingGatewaysListener(gateway, source.bridgeUrl, message));
619
- return gateway;
620
- });
621
- this.pendingGateways.forEach(bridge => bridge.registerSession());
622
- }
623
- else {
624
- bridgeUrl = this.walletConnectionSource.bridgeUrl;
625
- if (this.walletConnectionSource.universalLink) {
626
- universalLink = this.walletConnectionSource.universalLink;
627
- }
628
- this.gateway = new BridgeGateway(this.storage, this.walletConnectionSource.bridgeUrl, sessionCrypto.sessionId, this.gatewayListener.bind(this), this.gatewayErrorsListener.bind(this));
629
- this.gateway.registerSession();
630
- }
631
661
  this.session = {
632
662
  sessionCrypto,
633
- bridgeUrl
663
+ bridgeUrl: 'bridgeUrl' in this.walletConnectionSource
664
+ ? this.walletConnectionSource.bridgeUrl
665
+ : ''
634
666
  };
667
+ this.connectionStorage
668
+ .storeConnection({
669
+ type: 'http',
670
+ connectionSource: this.walletConnectionSource,
671
+ sessionCrypto
672
+ })
673
+ .then(() => this.openGateways(sessionCrypto));
674
+ const universalLink = 'universalLink' in this.walletConnectionSource &&
675
+ this.walletConnectionSource.universalLink
676
+ ? this.walletConnectionSource.universalLink
677
+ : this.standardUniversalLink;
635
678
  return this.generateUniversalLink(universalLink, message);
636
679
  }
637
680
  restoreConnection() {
638
681
  return __awaiter(this, void 0, void 0, function* () {
639
- if (Array.isArray(this.walletConnectionSource)) {
640
- throw new TonConnectError('Internal error. Connection source is array while WalletConnectionSourceHTTP was expected.');
641
- }
642
682
  this.closeGateways();
643
683
  const storedConnection = yield this.connectionStorage.getHttpConnection();
644
684
  if (!storedConnection) {
645
685
  return;
646
686
  }
687
+ if (isPendingConnectionHttp(storedConnection)) {
688
+ this.session = {
689
+ sessionCrypto: storedConnection.sessionCrypto,
690
+ bridgeUrl: 'bridgeUrl' in this.walletConnectionSource
691
+ ? this.walletConnectionSource.bridgeUrl
692
+ : ''
693
+ };
694
+ return this.openGateways(storedConnection.sessionCrypto);
695
+ }
696
+ if (Array.isArray(this.walletConnectionSource)) {
697
+ throw new TonConnectError('Internal error. Connection source is array while WalletConnectionSourceHTTP was expected.');
698
+ }
647
699
  this.session = storedConnection.session;
648
700
  this.gateway = new BridgeGateway(this.storage, this.walletConnectionSource.bridgeUrl, storedConnection.session.sessionCrypto.sessionId, this.gatewayListener.bind(this), this.gatewayErrorsListener.bind(this));
649
701
  yield this.gateway.registerSession();
@@ -786,12 +838,45 @@ class BridgeProvider {
786
838
  });
787
839
  }
788
840
  generateUniversalLink(universalLink, message) {
841
+ if (isTelegramUrl(universalLink)) {
842
+ return this.generateTGUniversalLink(universalLink, message);
843
+ }
844
+ return this.generateRegularUniversalLink(universalLink, message);
845
+ }
846
+ generateRegularUniversalLink(universalLink, message) {
789
847
  const url = new URL(universalLink);
790
848
  url.searchParams.append('v', PROTOCOL_VERSION.toString());
791
849
  url.searchParams.append('id', this.session.sessionCrypto.sessionId);
792
850
  url.searchParams.append('r', JSON.stringify(message));
793
851
  return url.toString();
794
852
  }
853
+ generateTGUniversalLink(universalLink, message) {
854
+ const urlToWrap = this.generateRegularUniversalLink('about:blank', message);
855
+ const linkParams = urlToWrap.split('?')[1];
856
+ const startattach = 'tonconnect-' + encodeTelegramUrlParameters(linkParams);
857
+ const url = new URL(universalLink);
858
+ url.searchParams.append('startattach', startattach);
859
+ return url.toString();
860
+ }
861
+ openGateways(sessionCrypto) {
862
+ return __awaiter(this, void 0, void 0, function* () {
863
+ if (Array.isArray(this.walletConnectionSource)) {
864
+ this.pendingGateways = this.walletConnectionSource.map(source => {
865
+ const gateway = new BridgeGateway(this.storage, source.bridgeUrl, sessionCrypto.sessionId, () => { }, e => {
866
+ console.error(e);
867
+ });
868
+ gateway.setListener(message => this.pendingGatewaysListener(gateway, source.bridgeUrl, message));
869
+ return gateway;
870
+ });
871
+ yield Promise.race(this.pendingGateways.map(bridge => bridge.registerSession()));
872
+ return;
873
+ }
874
+ else {
875
+ this.gateway = new BridgeGateway(this.storage, this.walletConnectionSource.bridgeUrl, sessionCrypto.sessionId, this.gatewayListener.bind(this), this.gatewayErrorsListener.bind(this));
876
+ return this.gateway.registerSession();
877
+ }
878
+ });
879
+ }
795
880
  closeGateways(options) {
796
881
  var _a;
797
882
  (_a = this.gateway) === null || _a === void 0 ? void 0 : _a.close();
@@ -819,6 +904,7 @@ function isJSBridgeWithMetadata(value) {
819
904
  }
820
905
  return hasProperties(value.tonconnect.walletInfo, [
821
906
  'name',
907
+ 'app_name',
822
908
  'image',
823
909
  'about_url',
824
910
  'platforms'
@@ -887,6 +973,7 @@ class InjectedProvider {
887
973
  const wallets = Object.entries(this.window).filter(([_, value]) => isJSBridgeWithMetadata(value));
888
974
  return wallets.map(([jsBridgeKey, wallet]) => ({
889
975
  name: wallet.tonconnect.walletInfo.name,
976
+ appName: wallet.tonconnect.walletInfo.app_name,
890
977
  aboutUrl: wallet.tonconnect.walletInfo.about_url,
891
978
  imageUrl: wallet.tonconnect.walletInfo.image,
892
979
  tondns: wallet.tonconnect.walletInfo.tondns,
@@ -1083,6 +1170,21 @@ function isWalletInfoInjected(value) {
1083
1170
 
1084
1171
  const FALLBACK_WALLETS_LIST = [
1085
1172
  {
1173
+ app_name: 'telegram-wallet',
1174
+ name: 'Wallet',
1175
+ image: 'https://wallet.tg/images/logo-288.png',
1176
+ about_url: 'https://wallet.tg/',
1177
+ universal_url: 'https://t.me/wallet?attach=wallet',
1178
+ bridge: [
1179
+ {
1180
+ type: 'sse',
1181
+ url: 'https://bridge.tonapi.io/bridge'
1182
+ }
1183
+ ],
1184
+ platforms: ['ios', 'android', 'macos', 'windows', 'linux']
1185
+ },
1186
+ {
1187
+ app_name: 'tonkeeper',
1086
1188
  name: 'Tonkeeper',
1087
1189
  image: 'https://tonkeeper.com/assets/tonconnect-icon.png',
1088
1190
  tondns: 'tonkeeper.ton',
@@ -1101,6 +1203,7 @@ const FALLBACK_WALLETS_LIST = [
1101
1203
  platforms: ['ios', 'android', 'chrome', 'firefox']
1102
1204
  },
1103
1205
  {
1206
+ app_name: 'openmask',
1104
1207
  name: 'OpenMask',
1105
1208
  image: 'https://raw.githubusercontent.com/OpenProduct/openmask-extension/main/public/openmask-logo-288.png',
1106
1209
  about_url: 'https://www.openmask.app/',
@@ -1113,6 +1216,7 @@ const FALLBACK_WALLETS_LIST = [
1113
1216
  platforms: ['chrome']
1114
1217
  },
1115
1218
  {
1219
+ app_name: 'mytonwallet',
1116
1220
  name: 'MyTonWallet',
1117
1221
  image: 'https://mytonwallet.io/icon-256.png',
1118
1222
  about_url: 'https://mytonwallet.io',
@@ -1130,6 +1234,7 @@ const FALLBACK_WALLETS_LIST = [
1130
1234
  platforms: ['chrome', 'windows', 'macos', 'linux']
1131
1235
  },
1132
1236
  {
1237
+ app_name: 'tonhub',
1133
1238
  name: 'Tonhub',
1134
1239
  image: 'https://tonhub.com/tonconnect_logo.png',
1135
1240
  about_url: 'https://tonhub.com',
@@ -1147,6 +1252,7 @@ const FALLBACK_WALLETS_LIST = [
1147
1252
  platforms: ['ios', 'android']
1148
1253
  },
1149
1254
  {
1255
+ app_name: 'tonflow',
1150
1256
  name: 'TonFlow',
1151
1257
  image: 'https://tonflow.net/assets/images/tonflow_ico_192.png',
1152
1258
  about_url: 'https://tonflow.net',
@@ -1159,6 +1265,7 @@ const FALLBACK_WALLETS_LIST = [
1159
1265
  platforms: ['chrome']
1160
1266
  },
1161
1267
  {
1268
+ app_name: 'dewallet',
1162
1269
  name: 'DeWallet',
1163
1270
  image: 'https://app.delabwallet.com/logo_black.png',
1164
1271
  about_url: 'https://delabwallet.com',
@@ -1171,6 +1278,7 @@ const FALLBACK_WALLETS_LIST = [
1171
1278
  platforms: ['chrome']
1172
1279
  },
1173
1280
  {
1281
+ app_name: 'xtonwallet',
1174
1282
  name: 'XTONWallet',
1175
1283
  image: 'https://xtonwallet.com/assets/img/icon-256-back.png',
1176
1284
  about_url: 'https://xtonwallet.com',
@@ -1183,6 +1291,7 @@ const FALLBACK_WALLETS_LIST = [
1183
1291
  platforms: ['chrome', 'firefox']
1184
1292
  },
1185
1293
  {
1294
+ app_name: 'tonwallet',
1186
1295
  name: 'TON Wallet',
1187
1296
  image: 'https://wallet.ton.org/assets/ui/qr-logo.png',
1188
1297
  about_url: 'https://chrome.google.com/webstore/detail/ton-wallet/nphplpgoakhhjchkkhmiggakijnkhfnd',
@@ -1200,7 +1309,7 @@ class WalletsListManager {
1200
1309
  constructor(options) {
1201
1310
  this.walletsListCache = null;
1202
1311
  this.walletsListCacheCreationTimestamp = null;
1203
- this.walletsListSource = 'https://raw.githubusercontent.com/ton-blockchain/wallets-list/main/wallets.json';
1312
+ this.walletsListSource = 'https://raw.githubusercontent.com/ton-blockchain/wallets-list/main/wallets-v2.json';
1204
1313
  if (options === null || options === void 0 ? void 0 : options.walletsListSource) {
1205
1314
  this.walletsListSource = options.walletsListSource;
1206
1315
  }
@@ -1272,13 +1381,15 @@ class WalletsListManager {
1272
1381
  }
1273
1382
  walletConfigDTOListToWalletConfigList(walletConfigDTO) {
1274
1383
  return walletConfigDTO.map(walletConfigDTO => {
1275
- const walletConfig = {
1384
+ const walletConfigBase = {
1276
1385
  name: walletConfigDTO.name,
1386
+ appName: walletConfigDTO.app_name,
1277
1387
  imageUrl: walletConfigDTO.image,
1278
1388
  aboutUrl: walletConfigDTO.about_url,
1279
1389
  tondns: walletConfigDTO.tondns,
1280
1390
  platforms: walletConfigDTO.platforms
1281
1391
  };
1392
+ const walletConfig = walletConfigBase;
1282
1393
  walletConfigDTO.bridge.forEach(bridge => {
1283
1394
  if (bridge.type === 'sse') {
1284
1395
  walletConfig.bridgeUrl = bridge.url;
@@ -1306,15 +1417,21 @@ class WalletsListManager {
1306
1417
  return Object.assign(Object.assign({}, (list1Item && Object.assign({}, list1Item))), (list2Item && Object.assign({}, list2Item)));
1307
1418
  });
1308
1419
  }
1420
+ // eslint-disable-next-line complexity
1309
1421
  isCorrectWalletConfigDTO(value) {
1310
1422
  if (!value || !(typeof value === 'object')) {
1311
1423
  return false;
1312
1424
  }
1313
1425
  const containsName = 'name' in value;
1426
+ const containsAppName = 'app_name' in value;
1314
1427
  const containsImage = 'image' in value;
1315
1428
  const containsAbout = 'about_url' in value;
1316
1429
  const containsPlatforms = 'platforms' in value;
1317
- if (!containsName || !containsImage || !containsAbout || !containsPlatforms) {
1430
+ if (!containsName ||
1431
+ !containsImage ||
1432
+ !containsAbout ||
1433
+ !containsPlatforms ||
1434
+ !containsAppName) {
1318
1435
  return false;
1319
1436
  }
1320
1437
  if (!value.platforms ||
@@ -1780,6 +1897,8 @@ exports.WalletNotInjectedError = WalletNotInjectedError;
1780
1897
  exports.WalletsListManager = WalletsListManager;
1781
1898
  exports.WrongAddressError = WrongAddressError;
1782
1899
  exports.default = TonConnect;
1900
+ exports.encodeTelegramUrlParameters = encodeTelegramUrlParameters;
1901
+ exports.isTelegramUrl = isTelegramUrl;
1783
1902
  exports.isWalletInfoCurrentlyEmbedded = isWalletInfoCurrentlyEmbedded;
1784
1903
  exports.isWalletInfoCurrentlyInjected = isWalletInfoCurrentlyInjected;
1785
1904
  exports.isWalletInfoInjectable = isWalletInfoInjectable;