@tezos-x/octez.connect-dapp 0.9.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.
Files changed (83) hide show
  1. package/LICENCE +19 -0
  2. package/README.md +16 -0
  3. package/dist/cjs/beacon-message-events.d.ts +9 -0
  4. package/dist/cjs/beacon-message-events.js +109 -0
  5. package/dist/cjs/beacon-message-events.js.map +1 -0
  6. package/dist/cjs/dapp-client/DAppClient.d.ts +282 -0
  7. package/dist/cjs/dapp-client/DAppClient.js +2073 -0
  8. package/dist/cjs/dapp-client/DAppClient.js.map +1 -0
  9. package/dist/cjs/dapp-client/DAppClientOptions.d.ts +117 -0
  10. package/dist/cjs/dapp-client/DAppClientOptions.js +3 -0
  11. package/dist/cjs/dapp-client/DAppClientOptions.js.map +1 -0
  12. package/dist/cjs/events.d.ts +209 -0
  13. package/dist/cjs/events.js +718 -0
  14. package/dist/cjs/events.js.map +1 -0
  15. package/dist/cjs/index.d.ts +15 -0
  16. package/dist/cjs/index.js +37 -0
  17. package/dist/cjs/index.js.map +1 -0
  18. package/dist/cjs/transports/DappP2PTransport.d.ts +14 -0
  19. package/dist/cjs/transports/DappP2PTransport.js +53 -0
  20. package/dist/cjs/transports/DappP2PTransport.js.map +1 -0
  21. package/dist/cjs/transports/DappPostMessageTransport.d.ts +14 -0
  22. package/dist/cjs/transports/DappPostMessageTransport.js +53 -0
  23. package/dist/cjs/transports/DappPostMessageTransport.js.map +1 -0
  24. package/dist/cjs/transports/DappWalletConnectTransport.d.ts +17 -0
  25. package/dist/cjs/transports/DappWalletConnectTransport.js +52 -0
  26. package/dist/cjs/transports/DappWalletConnectTransport.js.map +1 -0
  27. package/dist/cjs/utils/available-transports.d.ts +4 -0
  28. package/dist/cjs/utils/available-transports.js +12 -0
  29. package/dist/cjs/utils/available-transports.js.map +1 -0
  30. package/dist/cjs/utils/block-explorer.d.ts +24 -0
  31. package/dist/cjs/utils/block-explorer.js +24 -0
  32. package/dist/cjs/utils/block-explorer.js.map +1 -0
  33. package/dist/cjs/utils/get-instance.d.ts +4 -0
  34. package/dist/cjs/utils/get-instance.js +21 -0
  35. package/dist/cjs/utils/get-instance.js.map +1 -0
  36. package/dist/cjs/utils/shorten-string.d.ts +1 -0
  37. package/dist/cjs/utils/shorten-string.js +11 -0
  38. package/dist/cjs/utils/shorten-string.js.map +1 -0
  39. package/dist/cjs/utils/tzkt-blockexplorer.d.ts +12 -0
  40. package/dist/cjs/utils/tzkt-blockexplorer.js +59 -0
  41. package/dist/cjs/utils/tzkt-blockexplorer.js.map +1 -0
  42. package/dist/esm/beacon-message-events.d.ts +9 -0
  43. package/dist/esm/beacon-message-events.js +106 -0
  44. package/dist/esm/beacon-message-events.js.map +1 -0
  45. package/dist/esm/dapp-client/DAppClient.d.ts +282 -0
  46. package/dist/esm/dapp-client/DAppClient.js +2001 -0
  47. package/dist/esm/dapp-client/DAppClient.js.map +1 -0
  48. package/dist/esm/dapp-client/DAppClientOptions.d.ts +117 -0
  49. package/dist/esm/dapp-client/DAppClientOptions.js +2 -0
  50. package/dist/esm/dapp-client/DAppClientOptions.js.map +1 -0
  51. package/dist/esm/events.d.ts +209 -0
  52. package/dist/esm/events.js +702 -0
  53. package/dist/esm/events.js.map +1 -0
  54. package/dist/esm/index.d.ts +15 -0
  55. package/dist/esm/index.js +17 -0
  56. package/dist/esm/index.js.map +1 -0
  57. package/dist/esm/transports/DappP2PTransport.d.ts +14 -0
  58. package/dist/esm/transports/DappP2PTransport.js +34 -0
  59. package/dist/esm/transports/DappP2PTransport.js.map +1 -0
  60. package/dist/esm/transports/DappPostMessageTransport.d.ts +14 -0
  61. package/dist/esm/transports/DappPostMessageTransport.js +34 -0
  62. package/dist/esm/transports/DappPostMessageTransport.js.map +1 -0
  63. package/dist/esm/transports/DappWalletConnectTransport.d.ts +17 -0
  64. package/dist/esm/transports/DappWalletConnectTransport.js +35 -0
  65. package/dist/esm/transports/DappWalletConnectTransport.js.map +1 -0
  66. package/dist/esm/utils/available-transports.d.ts +4 -0
  67. package/dist/esm/utils/available-transports.js +9 -0
  68. package/dist/esm/utils/available-transports.js.map +1 -0
  69. package/dist/esm/utils/block-explorer.d.ts +24 -0
  70. package/dist/esm/utils/block-explorer.js +10 -0
  71. package/dist/esm/utils/block-explorer.js.map +1 -0
  72. package/dist/esm/utils/get-instance.d.ts +4 -0
  73. package/dist/esm/utils/get-instance.js +17 -0
  74. package/dist/esm/utils/get-instance.js.map +1 -0
  75. package/dist/esm/utils/shorten-string.d.ts +1 -0
  76. package/dist/esm/utils/shorten-string.js +7 -0
  77. package/dist/esm/utils/shorten-string.js.map +1 -0
  78. package/dist/esm/utils/tzkt-blockexplorer.d.ts +12 -0
  79. package/dist/esm/utils/tzkt-blockexplorer.js +43 -0
  80. package/dist/esm/utils/tzkt-blockexplorer.js.map +1 -0
  81. package/dist/octez.connect.dapp.min.js +1066 -0
  82. package/dist/walletbeacon.dapp.min.js +1066 -0
  83. package/package.json +45 -0
@@ -0,0 +1,2073 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.DAppClient = void 0;
13
+ const axios_1 = require("axios");
14
+ const bs58check_1 = require("bs58check");
15
+ const events_1 = require("../events");
16
+ const octez_connect_types_1 = require("@tezos-x/octez.connect-types");
17
+ const octez_connect_core_1 = require("@tezos-x/octez.connect-core");
18
+ const octez_connect_utils_1 = require("@tezos-x/octez.connect-utils");
19
+ const beacon_message_events_1 = require("../beacon-message-events");
20
+ const tzkt_blockexplorer_1 = require("../utils/tzkt-blockexplorer");
21
+ const octez_connect_dapp_1 = require("@tezos-x/octez.connect-dapp");
22
+ const DappPostMessageTransport_1 = require("../transports/DappPostMessageTransport");
23
+ const DappP2PTransport_1 = require("../transports/DappP2PTransport");
24
+ const DappWalletConnectTransport_1 = require("../transports/DappWalletConnectTransport");
25
+ const octez_connect_transport_postmessage_1 = require("@tezos-x/octez.connect-transport-postmessage");
26
+ const octez_connect_ui_1 = require("@tezos-x/octez.connect-ui");
27
+ const octez_connect_transport_walletconnect_1 = require("@tezos-x/octez.connect-transport-walletconnect");
28
+ const logger = new octez_connect_core_1.Logger('DAppClient');
29
+ /**
30
+ * @publicapi
31
+ *
32
+ * The DAppClient has to be used in decentralized applications. It handles all the logic related to connecting to beacon-compatible
33
+ * wallets and sending requests.
34
+ *
35
+ * @category DApp
36
+ */
37
+ class DAppClient extends octez_connect_core_1.Client {
38
+ constructor(config) {
39
+ var _a, _b, _c, _d, _e, _f, _g, _h;
40
+ super(Object.assign({ storage: config && config.storage ? config.storage : new octez_connect_core_1.LocalStorage() }, config));
41
+ this.events = new octez_connect_dapp_1.BeaconEventHandler();
42
+ this.isGetActiveAccountHandled = false;
43
+ this.openRequestsOtherTabs = new Set();
44
+ /**
45
+ * A map of requests that are currently "open", meaning we have sent them to a wallet and are still awaiting a response.
46
+ */
47
+ this.openRequests = new Map();
48
+ /**
49
+ * The currently active account. For all requests that are associated to a specific request (operation request, signing request),
50
+ * the active account is used to determine the network and destination wallet
51
+ */
52
+ this._activeAccount = new octez_connect_utils_1.ExposedPromise();
53
+ /**
54
+ * The currently active peer. This is used to address a peer in case the active account is not set. (Eg. for permission requests)
55
+ */
56
+ this._activePeer = new octez_connect_utils_1.ExposedPromise();
57
+ this.isInitPending = false;
58
+ this.beaconIDB = new octez_connect_core_1.IndexedDBStorage('beacon', ['bug_report', 'metrics']);
59
+ this.debounceSetActiveAccount = false;
60
+ this.multiTabChannel = new octez_connect_core_1.MultiTabChannel('octez.connect-sdk-channel', this.onBCMessageHandler.bind(this), this.onElectedLeaderhandler.bind(this));
61
+ this.blockchains = new Map();
62
+ this.description = config.description;
63
+ this.wcProjectId = ((_a = config.walletConnectOptions) === null || _a === void 0 ? void 0 : _a.projectId) || '24469fd0a06df227b6e5f7dc7de0ff4f';
64
+ this.wcRelayUrl = (_b = config.walletConnectOptions) === null || _b === void 0 ? void 0 : _b.relayUrl;
65
+ this.featuredWallets = config.featuredWallets;
66
+ this.events = new octez_connect_dapp_1.BeaconEventHandler(config.eventHandlers, (_c = config.disableDefaultEvents) !== null && _c !== void 0 ? _c : false);
67
+ this.blockExplorer = (_d = config.blockExplorer) !== null && _d !== void 0 ? _d : new tzkt_blockexplorer_1.TzktBlockExplorer();
68
+ this.network = (_e = config.network) !== null && _e !== void 0 ? _e : { type: (_f = config.preferredNetwork) !== null && _f !== void 0 ? _f : octez_connect_types_1.NetworkType.MAINNET };
69
+ (0, octez_connect_ui_1.setColorMode)((_g = config.colorMode) !== null && _g !== void 0 ? _g : octez_connect_types_1.ColorMode.LIGHT);
70
+ this.disclaimerText = config.disclaimerText;
71
+ this.errorMessages = (_h = config.errorMessages) !== null && _h !== void 0 ? _h : {};
72
+ this.appMetadataManager = new octez_connect_core_1.AppMetadataManager(this.storage);
73
+ this.storageValidator = new octez_connect_core_1.StorageValidator(this.storage);
74
+ this.enableAppSwitching =
75
+ config.enableAppSwitching === undefined ? true : !!config.enableAppSwitching;
76
+ this.enableMetrics = config.enableMetrics ? true : false;
77
+ // Subscribe to storage changes and update the active account if it changes on other tabs
78
+ this.storage.subscribeToStorageChanged((event) => __awaiter(this, void 0, void 0, function* () {
79
+ if (event.eventType === 'storageCleared') {
80
+ this.setActiveAccount(undefined);
81
+ return;
82
+ }
83
+ if (event.eventType === 'entryModified') {
84
+ if (event.key === this.storage.getPrefixedKey(octez_connect_types_1.StorageKey.ACTIVE_ACCOUNT)) {
85
+ const accountIdentifier = event.newValue;
86
+ if (!accountIdentifier || accountIdentifier === 'undefined') {
87
+ this.setActiveAccount(undefined);
88
+ }
89
+ else {
90
+ const account = yield this.getAccount(accountIdentifier);
91
+ this.setActiveAccount(account);
92
+ }
93
+ return;
94
+ }
95
+ if (event.key === this.storage.getPrefixedKey(octez_connect_types_1.StorageKey.ENABLE_METRICS)) {
96
+ this.enableMetrics = !!(yield this.storage.get(octez_connect_types_1.StorageKey.ENABLE_METRICS));
97
+ return;
98
+ }
99
+ if (event.key === this.storage.getPrefixedKey(octez_connect_types_1.StorageKey.BEACON_SDK_SECRET_SEED)) {
100
+ this._keyPair = new octez_connect_utils_1.ExposedPromise();
101
+ this._beaconId = new octez_connect_utils_1.ExposedPromise();
102
+ yield this.initSDK();
103
+ return;
104
+ }
105
+ }
106
+ }));
107
+ this.activeAccountLoaded = this.storage
108
+ .get(octez_connect_types_1.StorageKey.ACTIVE_ACCOUNT)
109
+ .then((activeAccountIdentifier) => __awaiter(this, void 0, void 0, function* () {
110
+ if (activeAccountIdentifier) {
111
+ const account = yield this.accountManager.getAccount(activeAccountIdentifier);
112
+ yield this.setActiveAccount(account);
113
+ return account;
114
+ }
115
+ else {
116
+ yield this.setActiveAccount(undefined);
117
+ return undefined;
118
+ }
119
+ }))
120
+ .catch((storageError) => __awaiter(this, void 0, void 0, function* () {
121
+ logger.error(storageError);
122
+ yield this.resetInvalidState(false);
123
+ this.events.emit(events_1.BeaconEvent.INVALID_ACCOUNT_DEACTIVATED);
124
+ return undefined;
125
+ }));
126
+ this.handleResponse = (message, connectionInfo) => __awaiter(this, void 0, void 0, function* () {
127
+ var _a;
128
+ const typedMessage = message.version === '3'
129
+ ? message.message
130
+ : message;
131
+ let appMetadata = message.version === '3'
132
+ ? (_a = typedMessage.blockchainData) === null || _a === void 0 ? void 0 : _a.appMetadata
133
+ : typedMessage.appMetadata;
134
+ if (!appMetadata && message.version === '3') {
135
+ const storedMetadata = yield Promise.all([
136
+ this.storage.get(octez_connect_types_1.StorageKey.TRANSPORT_P2P_PEERS_DAPP),
137
+ this.storage.get(octez_connect_types_1.StorageKey.TRANSPORT_WALLETCONNECT_PEERS_DAPP),
138
+ this.storage.get(octez_connect_types_1.StorageKey.TRANSPORT_POSTMESSAGE_PEERS_DAPP)
139
+ ]);
140
+ for (const peers of storedMetadata) {
141
+ const peer = peers.find((peer) => peer.senderId === message.senderId);
142
+ if (!peer) {
143
+ continue;
144
+ }
145
+ const wallet = yield this.getWalletInfo();
146
+ appMetadata = {
147
+ name: peer.name,
148
+ senderId: peer.senderId,
149
+ icon: wallet.icon
150
+ };
151
+ break;
152
+ }
153
+ }
154
+ if (this.openRequestsOtherTabs.has(message.id)) {
155
+ this.multiTabChannel.postMessage({
156
+ type: 'RESPONSE',
157
+ data: {
158
+ message,
159
+ connectionInfo
160
+ },
161
+ id: message.id
162
+ });
163
+ if (typedMessage.type !== octez_connect_types_1.BeaconMessageType.Acknowledge) {
164
+ this.openRequestsOtherTabs.delete(message.id);
165
+ }
166
+ return;
167
+ }
168
+ const openRequest = this.openRequests.get(message.id);
169
+ logger.log('### openRequest ###', openRequest);
170
+ logger.log('handleResponse', 'Received message', message, connectionInfo);
171
+ logger.log('### message ###', JSON.stringify(message));
172
+ logger.log('### connectionInfo ###', connectionInfo);
173
+ const handleDisconnect = () => __awaiter(this, void 0, void 0, function* () {
174
+ var _a;
175
+ this.analytics.track('event', 'DAppClient', 'Disconnect received from Wallet');
176
+ const relevantTransport = connectionInfo.origin === octez_connect_types_1.Origin.P2P
177
+ ? this.p2pTransport
178
+ : connectionInfo.origin === octez_connect_types_1.Origin.WALLETCONNECT
179
+ ? this.walletConnectTransport
180
+ : ((_a = this.postMessageTransport) !== null && _a !== void 0 ? _a : (yield this.transport));
181
+ if (relevantTransport) {
182
+ const peers = yield relevantTransport.getPeers();
183
+ const peer = peers.find((peerEl) => peerEl.senderId === message.senderId);
184
+ if (peer) {
185
+ yield relevantTransport.removePeer(peer);
186
+ }
187
+ }
188
+ yield this.removeAccountsForPeerIds([message.senderId]);
189
+ yield this.events.emit(events_1.BeaconEvent.CHANNEL_CLOSED);
190
+ });
191
+ if (openRequest && typedMessage.type === octez_connect_types_1.BeaconMessageType.Acknowledge) {
192
+ this.analytics.track('event', 'DAppClient', 'Acknowledge received from Wallet');
193
+ logger.log('handleResponse', `acknowledge message received for ${message.id}`);
194
+ this.events
195
+ .emit(events_1.BeaconEvent.ACKNOWLEDGE_RECEIVED, {
196
+ message: typedMessage,
197
+ extraInfo: {},
198
+ walletInfo: yield this.getWalletInfo()
199
+ })
200
+ .catch(console.error);
201
+ }
202
+ else if (openRequest) {
203
+ if (typedMessage.type === octez_connect_types_1.BeaconMessageType.PermissionResponse && appMetadata) {
204
+ yield this.appMetadataManager.addAppMetadata(appMetadata);
205
+ }
206
+ if (typedMessage.type === octez_connect_types_1.BeaconMessageType.Error) {
207
+ openRequest.reject(typedMessage);
208
+ }
209
+ else {
210
+ openRequest.resolve({ message, connectionInfo });
211
+ }
212
+ this.openRequests.delete(typedMessage.id);
213
+ }
214
+ else {
215
+ if (typedMessage.type === octez_connect_types_1.BeaconMessageType.Disconnect) {
216
+ yield handleDisconnect();
217
+ }
218
+ else if (typedMessage.type === octez_connect_types_1.BeaconMessageType.ChangeAccountRequest) {
219
+ yield this.onNewAccount(typedMessage, connectionInfo);
220
+ }
221
+ }
222
+ if (this._transport.isResolved()) {
223
+ const transport = yield this.transport;
224
+ if (transport instanceof octez_connect_transport_walletconnect_1.WalletConnectTransport &&
225
+ !this.openRequests.has('session_update')) {
226
+ this.openRequests.set('session_update', new octez_connect_utils_1.ExposedPromise());
227
+ }
228
+ }
229
+ });
230
+ this.storageValidator
231
+ .validate()
232
+ .then((isValid) => __awaiter(this, void 0, void 0, function* () {
233
+ var _a, _b;
234
+ const account = yield this.activeAccountLoaded;
235
+ if (!isValid) {
236
+ const info = yield this.getWalletInfo(undefined, account, false);
237
+ info.type =
238
+ info.type === 'extension' && (account === null || account === void 0 ? void 0 : account.origin.type) === octez_connect_types_1.Origin.P2P ? 'mobile' : info.type;
239
+ yield this.storage.set(octez_connect_types_1.StorageKey.LAST_SELECTED_WALLET, {
240
+ icon: (_a = info.icon) !== null && _a !== void 0 ? _a : '',
241
+ key: info.name,
242
+ type: (_b = info.type) !== null && _b !== void 0 ? _b : 'web',
243
+ name: info.name,
244
+ url: info.deeplink
245
+ });
246
+ const nowValid = yield this.storageValidator.validate();
247
+ if (!nowValid) {
248
+ this.resetInvalidState(false);
249
+ }
250
+ }
251
+ if (account && account.origin.type !== 'p2p') {
252
+ this.init();
253
+ }
254
+ }))
255
+ .catch((err) => logger.error(err.message));
256
+ this.sendMetrics('enable-metrics?' + this.addQueryParam('version', octez_connect_core_1.SDK_VERSION), undefined, (res) => {
257
+ if (!res.ok) {
258
+ res.status === 426
259
+ ? console.error('Metrics are no longer supported for this version, please upgrade.')
260
+ : console.warn('Network error encountered. Metrics sharing have been automatically disabled.');
261
+ }
262
+ this.enableMetrics = res.ok;
263
+ this.storage.set(octez_connect_types_1.StorageKey.ENABLE_METRICS, res.ok);
264
+ }, () => {
265
+ this.enableMetrics = false;
266
+ this.storage.set(octez_connect_types_1.StorageKey.ENABLE_METRICS, false);
267
+ });
268
+ this.initUserID().catch((err) => logger.error(err.message));
269
+ }
270
+ checkIfBCLeaderExists() {
271
+ return __awaiter(this, void 0, void 0, function* () {
272
+ // broadcast channel does not work on mobile
273
+ if ((0, octez_connect_ui_1.isMobileOS)(window)) {
274
+ return true;
275
+ }
276
+ const hasLeader = yield this.multiTabChannel.hasLeader();
277
+ if (hasLeader) {
278
+ return this.multiTabChannel.isLeader();
279
+ }
280
+ yield this.multiTabChannel.getLeadership();
281
+ return this.multiTabChannel.isLeader();
282
+ });
283
+ }
284
+ onElectedLeaderhandler() {
285
+ return __awaiter(this, void 0, void 0, function* () {
286
+ if (!this._transport.isResolved()) {
287
+ return;
288
+ }
289
+ const tranport = yield this.transport;
290
+ if (tranport.type !== octez_connect_types_1.TransportType.WALLETCONNECT) {
291
+ return;
292
+ }
293
+ if (tranport.connectionStatus === octez_connect_types_1.TransportStatus.CONNECTED) {
294
+ return;
295
+ }
296
+ yield tranport.connect();
297
+ });
298
+ }
299
+ onBCMessageHandler(message) {
300
+ return __awaiter(this, void 0, void 0, function* () {
301
+ switch (message.type) {
302
+ case octez_connect_types_1.BeaconMessageType.PermissionRequest:
303
+ case octez_connect_types_1.BeaconMessageType.OperationRequest:
304
+ case octez_connect_types_1.BeaconMessageType.SignPayloadRequest:
305
+ case octez_connect_types_1.BeaconMessageType.BroadcastRequest:
306
+ case octez_connect_types_1.BeaconMessageType.ProofOfEventChallengeRequest:
307
+ case octez_connect_types_1.BeaconMessageType.SimulatedProofOfEventChallengeRequest:
308
+ this.prepareRequest(message);
309
+ break;
310
+ case octez_connect_types_1.BeaconMessageType.BlockchainRequest:
311
+ this.prepareRequest(message, true);
312
+ break;
313
+ case 'RESPONSE':
314
+ this.handleResponse(message.data.message, message.data.connectionInfo);
315
+ break;
316
+ case 'DISCONNECT':
317
+ this._transport.isResolved() && this.disconnect();
318
+ break;
319
+ default:
320
+ logger.error('onBCMessageHandler', 'message type not recognized', message);
321
+ }
322
+ });
323
+ }
324
+ prepareRequest(message_1) {
325
+ return __awaiter(this, arguments, void 0, function* (message, isV3 = false) {
326
+ if (!this.multiTabChannel.isLeader()) {
327
+ return;
328
+ }
329
+ // block until the transport is ready
330
+ const transport = (yield this._transport.promise);
331
+ yield transport.waitForResolution();
332
+ this.openRequestsOtherTabs.add(message.id);
333
+ isV3
334
+ ? this.makeRequestV3(message.data, message.id)
335
+ : this.makeRequest(message.data, false, message.id);
336
+ });
337
+ }
338
+ createStateSnapshot() {
339
+ return __awaiter(this, void 0, void 0, function* () {
340
+ if (!localStorage || !this.enableMetrics) {
341
+ return;
342
+ }
343
+ const keys = Object.values(octez_connect_types_1.StorageKey).filter((key) => !key.includes('wc@2') && !key.includes('secret') && !key.includes('account'));
344
+ try {
345
+ for (const key of keys) {
346
+ yield this.beaconIDB.set(key, this.storage.getPrefixedKey(key));
347
+ }
348
+ }
349
+ catch (err) {
350
+ logger.error('createStateSnapshot', err.message);
351
+ }
352
+ });
353
+ }
354
+ initUserID() {
355
+ return __awaiter(this, void 0, void 0, function* () {
356
+ const id = yield this.storage.get(octez_connect_types_1.StorageKey.USER_ID);
357
+ if (id) {
358
+ this.userId = id;
359
+ return;
360
+ }
361
+ this.userId = yield (0, octez_connect_utils_1.generateGUID)();
362
+ this.storage.set(octez_connect_types_1.StorageKey.USER_ID, this.userId);
363
+ });
364
+ }
365
+ initInternalTransports() {
366
+ return __awaiter(this, void 0, void 0, function* () {
367
+ var _a, _b;
368
+ const seed = yield this.storage.get(octez_connect_types_1.StorageKey.BEACON_SDK_SECRET_SEED);
369
+ if (!seed) {
370
+ throw new Error('Secret seed not found');
371
+ }
372
+ const keyPair = yield (0, octez_connect_utils_1.getKeypairFromSeed)(seed);
373
+ if (this.postMessageTransport || this.p2pTransport || this.walletConnectTransport) {
374
+ return;
375
+ }
376
+ this.postMessageTransport = new DappPostMessageTransport_1.DappPostMessageTransport(this.name, keyPair, this.storage);
377
+ yield this.addListener(this.postMessageTransport);
378
+ this.p2pTransport = new DappP2PTransport_1.DappP2PTransport(this.name, keyPair, this.storage, this.matrixNodes, this.iconUrl, this.appUrl);
379
+ yield this.addListener(this.p2pTransport);
380
+ const wcOptions = {
381
+ projectId: this.wcProjectId,
382
+ relayUrl: this.wcRelayUrl,
383
+ metadata: {
384
+ name: this.name,
385
+ description: (_a = this.description) !== null && _a !== void 0 ? _a : '',
386
+ url: (_b = this.appUrl) !== null && _b !== void 0 ? _b : '',
387
+ icons: this.iconUrl ? [this.iconUrl] : []
388
+ }
389
+ };
390
+ this.walletConnectTransport = new DappWalletConnectTransport_1.DappWalletConnectTransport(this.name, keyPair, this.storage, {
391
+ network: this.network.type,
392
+ opts: wcOptions
393
+ }, this.checkIfBCLeaderExists.bind(this));
394
+ this.initEvents();
395
+ yield this.addListener(this.walletConnectTransport);
396
+ });
397
+ }
398
+ initEvents() {
399
+ if (!this.walletConnectTransport) {
400
+ return;
401
+ }
402
+ this.walletConnectTransport.setEventHandler("CLOSE_ALERT" /* ClientEvents.CLOSE_ALERT */, this.hideUI.bind(this, ['alert', 'toast']));
403
+ this.walletConnectTransport.setEventHandler("RESET_STATE" /* ClientEvents.RESET_STATE */, this.channelClosedHandler.bind(this));
404
+ this.walletConnectTransport.setEventHandler("WC_ACK_NOTIFICATION" /* ClientEvents.WC_ACK_NOTIFICATION */, this.wcToastHandler.bind(this));
405
+ this.walletConnectTransport.setEventHandler("ON_RELAYER_ERROR" /* ClientEvents.ON_RELAYER_ERROR */, this.onRelayerError.bind(this));
406
+ }
407
+ onRelayerError() {
408
+ return __awaiter(this, void 0, void 0, function* () {
409
+ yield this.resetInvalidState(false);
410
+ this.events.emit(events_1.BeaconEvent.RELAYER_ERROR);
411
+ });
412
+ }
413
+ wcToastHandler(status) {
414
+ return __awaiter(this, void 0, void 0, function* () {
415
+ const walletInfo = yield (() => __awaiter(this, void 0, void 0, function* () {
416
+ try {
417
+ return yield this.getWalletInfo();
418
+ }
419
+ catch (_a) {
420
+ return { name: 'wallet' };
421
+ }
422
+ }))();
423
+ yield this.events.emit(events_1.BeaconEvent.HIDE_UI, ['alert']);
424
+ if (status === 'pending') {
425
+ this.events.emit(events_1.BeaconEvent.ACKNOWLEDGE_RECEIVED, {
426
+ message: {},
427
+ extraInfo: {},
428
+ walletInfo
429
+ });
430
+ }
431
+ else {
432
+ this.events.emit(events_1.BeaconEvent.PERMISSION_REQUEST_ERROR, {
433
+ errorResponse: { errorType: octez_connect_types_1.BeaconErrorType.ABORTED_ERROR },
434
+ walletInfo
435
+ });
436
+ }
437
+ });
438
+ }
439
+ channelClosedHandler(type) {
440
+ return __awaiter(this, void 0, void 0, function* () {
441
+ const transport = yield this.transport;
442
+ if (transport.type !== type) {
443
+ return;
444
+ }
445
+ yield this.events.emit(events_1.BeaconEvent.CHANNEL_CLOSED);
446
+ this.setActiveAccount(undefined);
447
+ yield this.disconnect();
448
+ });
449
+ }
450
+ /**
451
+ * Destroy the instance.
452
+ *
453
+ * WARNING: Call `destroy` whenever you no longer need dAppClient
454
+ * as it frees internal subscriptions to the transport and therefore the instance may no longer work properly.
455
+ * If you wish to disconnect your dApp, use `disconnect` instead.
456
+ */
457
+ destroy() {
458
+ const _super = Object.create(null, {
459
+ destroy: { get: () => super.destroy }
460
+ });
461
+ return __awaiter(this, void 0, void 0, function* () {
462
+ yield this.createStateSnapshot();
463
+ yield _super.destroy.call(this);
464
+ });
465
+ }
466
+ init(transport, substratePairing) {
467
+ const _super = Object.create(null, {
468
+ init: { get: () => super.init }
469
+ });
470
+ return __awaiter(this, void 0, void 0, function* () {
471
+ if (this._initPromise) {
472
+ return this._initPromise;
473
+ }
474
+ try {
475
+ yield this.activeAccountLoaded;
476
+ }
477
+ catch (_a) {
478
+ //
479
+ }
480
+ this._initPromise = new Promise((resolve) => __awaiter(this, void 0, void 0, function* () {
481
+ if (transport) {
482
+ yield this.addListener(transport);
483
+ resolve(yield _super.init.call(this, transport));
484
+ }
485
+ else if (this._transport.isSettled()) {
486
+ yield (yield this.transport).connect();
487
+ resolve(yield _super.init.call(this, yield this.transport));
488
+ }
489
+ else {
490
+ const activeAccount = yield this.getActiveAccount();
491
+ const stopListening = () => {
492
+ if (this.postMessageTransport) {
493
+ this.postMessageTransport.stopListeningForNewPeers().catch(console.error);
494
+ }
495
+ if (this.p2pTransport) {
496
+ this.p2pTransport.stopListeningForNewPeers().catch(console.error);
497
+ }
498
+ if (this.walletConnectTransport) {
499
+ this.walletConnectTransport.stopListeningForNewPeers().catch(console.error);
500
+ }
501
+ };
502
+ yield this.initInternalTransports();
503
+ if (!this.postMessageTransport || !this.p2pTransport || !this.walletConnectTransport) {
504
+ return;
505
+ }
506
+ this.postMessageTransport.connect().then().catch(console.error);
507
+ if (activeAccount && activeAccount.origin) {
508
+ const origin = activeAccount.origin.type;
509
+ // Select the transport that matches the active account
510
+ if (origin === octez_connect_types_1.Origin.EXTENSION) {
511
+ resolve(yield _super.init.call(this, this.postMessageTransport));
512
+ }
513
+ else if (origin === octez_connect_types_1.Origin.P2P) {
514
+ resolve(yield _super.init.call(this, this.p2pTransport));
515
+ }
516
+ else if (origin === octez_connect_types_1.Origin.WALLETCONNECT) {
517
+ resolve(yield _super.init.call(this, this.walletConnectTransport));
518
+ }
519
+ }
520
+ else {
521
+ const p2pTransport = this.p2pTransport;
522
+ const postMessageTransport = this.postMessageTransport;
523
+ const walletConnectTransport = this.walletConnectTransport;
524
+ postMessageTransport
525
+ .listenForNewPeer((peer) => {
526
+ logger.log('init', 'postmessage transport peer connected', peer);
527
+ this.analytics.track('event', 'DAppClient', 'Extension connected', {
528
+ peerName: peer.name
529
+ });
530
+ this.events
531
+ .emit(events_1.BeaconEvent.PAIR_SUCCESS, peer)
532
+ .catch((emitError) => console.warn(emitError));
533
+ this.setActivePeer(peer).catch(console.error);
534
+ this.setTransport(this.postMessageTransport).catch(console.error);
535
+ stopListening();
536
+ resolve(octez_connect_types_1.TransportType.POST_MESSAGE);
537
+ })
538
+ .catch(console.error);
539
+ p2pTransport
540
+ .listenForNewPeer((peer) => {
541
+ logger.log('init', 'p2p transport peer connected', peer);
542
+ this.analytics.track('event', 'DAppClient', 'octez.connect Wallet connected', {
543
+ peerName: peer.name
544
+ });
545
+ this.events
546
+ .emit(events_1.BeaconEvent.PAIR_SUCCESS, peer)
547
+ .catch((emitError) => console.warn(emitError));
548
+ this.setActivePeer(peer).catch(console.error);
549
+ this.setTransport(this.p2pTransport).catch(console.error);
550
+ stopListening();
551
+ resolve(octez_connect_types_1.TransportType.P2P);
552
+ })
553
+ .catch(console.error);
554
+ walletConnectTransport
555
+ .listenForNewPeer((peer) => {
556
+ logger.log('init', 'walletconnect transport peer connected', peer);
557
+ this.analytics.track('event', 'DAppClient', 'WalletConnect Wallet connected', {
558
+ peerName: peer.name
559
+ });
560
+ this.events
561
+ .emit(events_1.BeaconEvent.PAIR_SUCCESS, peer)
562
+ .catch((emitError) => console.warn(emitError));
563
+ this.setActivePeer(peer).catch(console.error);
564
+ this.setTransport(this.walletConnectTransport).catch(console.error);
565
+ stopListening();
566
+ resolve(octez_connect_types_1.TransportType.WALLETCONNECT);
567
+ })
568
+ .catch(console.error);
569
+ octez_connect_transport_postmessage_1.PostMessageTransport.getAvailableExtensions()
570
+ .then((extensions) => __awaiter(this, void 0, void 0, function* () {
571
+ this.analytics.track('event', 'DAppClient', 'Extensions detected', { extensions });
572
+ }))
573
+ .catch((error) => {
574
+ this._initPromise = undefined;
575
+ console.error(error);
576
+ });
577
+ const abortHandler = () => __awaiter(this, void 0, void 0, function* () {
578
+ logger.log('init', 'ABORTED');
579
+ this.sendMetrics('performance-metrics/save', yield this.buildPayload('connect', 'abort'));
580
+ yield Promise.all([
581
+ postMessageTransport.disconnect(),
582
+ // p2pTransport.disconnect(), do not abort connection manually
583
+ walletConnectTransport.disconnect()
584
+ ]);
585
+ this.postMessageTransport = this.walletConnectTransport = this.p2pTransport = undefined;
586
+ this._activeAccount.isResolved() && this.clearActiveAccount();
587
+ this._initPromise = undefined;
588
+ });
589
+ const serializer = new octez_connect_core_1.Serializer();
590
+ const p2pPeerInfo = new Promise((resolve) => __awaiter(this, void 0, void 0, function* () {
591
+ try {
592
+ yield p2pTransport.connect();
593
+ }
594
+ catch (err) {
595
+ logger.error(err);
596
+ yield this.hideUI(['alert']); // hide pairing alert
597
+ setTimeout(() => this.events.emit(events_1.BeaconEvent.GENERIC_ERROR, err.message), 1000);
598
+ abortHandler();
599
+ resolve('');
600
+ return;
601
+ }
602
+ resolve(yield serializer.serialize(yield p2pTransport.getPairingRequestInfo()));
603
+ }));
604
+ const walletConnectPeerInfo = new Promise((resolve) => __awaiter(this, void 0, void 0, function* () {
605
+ resolve((yield walletConnectTransport.getPairingRequestInfo()).uri);
606
+ }));
607
+ const postmessagePeerInfo = new Promise((resolve) => __awaiter(this, void 0, void 0, function* () {
608
+ resolve(yield serializer.serialize(yield postMessageTransport.getPairingRequestInfo()));
609
+ }));
610
+ this.events
611
+ .emit(events_1.BeaconEvent.PAIR_INIT, {
612
+ p2pPeerInfo,
613
+ postmessagePeerInfo,
614
+ walletConnectPeerInfo,
615
+ networkType: this.network.type,
616
+ abortedHandler: abortHandler.bind(this),
617
+ disclaimerText: this.disclaimerText,
618
+ analytics: this.analytics,
619
+ featuredWallets: this.featuredWallets,
620
+ substratePairing
621
+ })
622
+ .catch((emitError) => console.warn(emitError));
623
+ }
624
+ }
625
+ }));
626
+ return this._initPromise;
627
+ });
628
+ }
629
+ /**
630
+ * Returns the active account
631
+ */
632
+ getActiveAccount() {
633
+ return __awaiter(this, void 0, void 0, function* () {
634
+ return this._activeAccount.promise;
635
+ });
636
+ }
637
+ isInvalidState(account) {
638
+ return __awaiter(this, void 0, void 0, function* () {
639
+ const activeAccount = yield this._activeAccount.promise;
640
+ return !activeAccount
641
+ ? false
642
+ : (activeAccount === null || activeAccount === void 0 ? void 0 : activeAccount.address) !== (account === null || account === void 0 ? void 0 : account.address) && !this.isGetActiveAccountHandled;
643
+ });
644
+ }
645
+ resetInvalidState() {
646
+ return __awaiter(this, arguments, void 0, function* (emit = true) {
647
+ var _a, _b;
648
+ this.accountManager.removeAllAccounts();
649
+ this._activeAccount = octez_connect_utils_1.ExposedPromise.resolve(undefined);
650
+ this.storage.set(octez_connect_types_1.StorageKey.ACTIVE_ACCOUNT, undefined);
651
+ emit && this.events.emit(events_1.BeaconEvent.INVALID_ACTIVE_ACCOUNT_STATE);
652
+ !emit && this.hideUI(['alert']);
653
+ yield Promise.all([
654
+ (_a = this.postMessageTransport) === null || _a === void 0 ? void 0 : _a.disconnect(),
655
+ (_b = this.walletConnectTransport) === null || _b === void 0 ? void 0 : _b.disconnect()
656
+ ]);
657
+ this.postMessageTransport = this.p2pTransport = this.walletConnectTransport = undefined;
658
+ yield this.setActivePeer(undefined);
659
+ yield this.setTransport(undefined);
660
+ this._initPromise = undefined;
661
+ });
662
+ }
663
+ /**
664
+ * Sets the active account
665
+ *
666
+ * @param account The account that will be set as the active account
667
+ */
668
+ setActiveAccount(account) {
669
+ return __awaiter(this, void 0, void 0, function* () {
670
+ var _a;
671
+ if (!this.isGetActiveAccountHandled) {
672
+ console.warn(`An active account has been received, but no active subscription was found for BeaconEvent.ACTIVE_ACCOUNT_SET.`);
673
+ }
674
+ if (account && this._activeAccount.isSettled() && (yield this.isInvalidState(account))) {
675
+ const tranport = yield this.transport;
676
+ if (tranport instanceof octez_connect_transport_walletconnect_1.WalletConnectTransport && tranport.wasDisconnectedByWallet()) {
677
+ yield this.resetInvalidState();
678
+ return;
679
+ }
680
+ }
681
+ // when I'm resetting the activeAccount
682
+ if (!account && this._activeAccount.isResolved() && (yield this.getActiveAccount())) {
683
+ const transport = yield this.transport;
684
+ const activeAccount = yield this.getActiveAccount();
685
+ if (!transport || !activeAccount) {
686
+ return;
687
+ }
688
+ if (!this.debounceSetActiveAccount && transport instanceof octez_connect_transport_walletconnect_1.WalletConnectTransport) {
689
+ this.debounceSetActiveAccount = true;
690
+ this._initPromise = undefined;
691
+ this.postMessageTransport = this.p2pTransport = this.walletConnectTransport = undefined;
692
+ if (this.multiTabChannel.isLeader() || (0, octez_connect_ui_1.isMobileOS)(window)) {
693
+ yield transport.disconnect();
694
+ this.openRequestsOtherTabs.clear();
695
+ }
696
+ else {
697
+ this.multiTabChannel.postMessage({
698
+ type: 'DISCONNECT'
699
+ });
700
+ }
701
+ Array.from(this.openRequests.entries())
702
+ .filter(([id, _promise]) => id !== 'session_update')
703
+ .forEach(([id, promise]) => {
704
+ promise.reject({
705
+ type: octez_connect_types_1.BeaconMessageType.Error,
706
+ errorType: octez_connect_types_1.BeaconErrorType.ABORTED_ERROR,
707
+ id,
708
+ senderId: '',
709
+ version: '2'
710
+ });
711
+ });
712
+ this.openRequests.clear();
713
+ this.debounceSetActiveAccount = false;
714
+ }
715
+ }
716
+ if (this._activeAccount.isSettled()) {
717
+ // If the promise has already been resolved we need to create a new one.
718
+ this._activeAccount = octez_connect_utils_1.ExposedPromise.resolve(account);
719
+ }
720
+ else {
721
+ this._activeAccount.resolve(account);
722
+ }
723
+ if (!this.isGetActiveAccountHandled && this._transport.isResolved()) {
724
+ const transport = yield this.transport;
725
+ if (transport instanceof octez_connect_transport_walletconnect_1.WalletConnectTransport && transport.wasDisconnectedByWallet()) {
726
+ yield this.resetInvalidState();
727
+ return;
728
+ }
729
+ }
730
+ if (account) {
731
+ const origin = account.origin.type;
732
+ yield this.initInternalTransports();
733
+ // Select the transport that matches the active account
734
+ if (origin === octez_connect_types_1.Origin.EXTENSION) {
735
+ yield this.setTransport(this.postMessageTransport);
736
+ }
737
+ else if (origin === octez_connect_types_1.Origin.P2P) {
738
+ yield this.setTransport(this.p2pTransport);
739
+ }
740
+ else if (origin === octez_connect_types_1.Origin.WALLETCONNECT) {
741
+ yield this.setTransport(this.walletConnectTransport);
742
+ (_a = this.walletConnectTransport) === null || _a === void 0 ? void 0 : _a.forceUpdate('INIT');
743
+ }
744
+ if (this._transport.isResolved()) {
745
+ const transport = yield this.transport;
746
+ if (transport.connectionStatus === octez_connect_types_1.TransportStatus.NOT_CONNECTED) {
747
+ yield transport.connect();
748
+ }
749
+ }
750
+ const peer = yield this.getPeer(account);
751
+ yield this.setActivePeer(peer);
752
+ }
753
+ else {
754
+ yield this.setActivePeer(undefined);
755
+ yield this.setTransport(undefined);
756
+ }
757
+ yield this.storage.set(octez_connect_types_1.StorageKey.ACTIVE_ACCOUNT, account ? account.accountIdentifier : undefined);
758
+ yield this.events.emit(events_1.BeaconEvent.ACTIVE_ACCOUNT_SET, account);
759
+ return;
760
+ });
761
+ }
762
+ /**
763
+ * Clear the active account
764
+ */
765
+ clearActiveAccount() {
766
+ return this.setActiveAccount();
767
+ }
768
+ setColorMode(colorMode) {
769
+ return __awaiter(this, void 0, void 0, function* () {
770
+ return (0, octez_connect_ui_1.setColorMode)(colorMode);
771
+ });
772
+ }
773
+ getColorMode() {
774
+ return __awaiter(this, void 0, void 0, function* () {
775
+ return (0, octez_connect_ui_1.getColorMode)();
776
+ });
777
+ }
778
+ /**
779
+ * @deprecated
780
+ *
781
+ * Use getOwnAppMetadata instead
782
+ */
783
+ getAppMetadata() {
784
+ return __awaiter(this, void 0, void 0, function* () {
785
+ return this.getOwnAppMetadata();
786
+ });
787
+ }
788
+ showPrepare() {
789
+ return __awaiter(this, void 0, void 0, function* () {
790
+ const walletInfo = yield (() => __awaiter(this, void 0, void 0, function* () {
791
+ try {
792
+ return yield this.getWalletInfo();
793
+ }
794
+ catch (_a) {
795
+ return undefined;
796
+ }
797
+ }))();
798
+ yield this.events.emit(events_1.BeaconEvent.SHOW_PREPARE, { walletInfo });
799
+ });
800
+ }
801
+ hideUI(elements) {
802
+ return __awaiter(this, void 0, void 0, function* () {
803
+ yield this.events.emit(events_1.BeaconEvent.HIDE_UI, elements);
804
+ });
805
+ }
806
+ tryToAppSwitch() {
807
+ return __awaiter(this, void 0, void 0, function* () {
808
+ if (!(0, octez_connect_ui_1.isMobileOS)(window) || !this.enableAppSwitching) {
809
+ return;
810
+ }
811
+ const wallet = yield this.getWalletInfo();
812
+ if (wallet.type !== 'mobile' || !wallet.deeplink) {
813
+ return;
814
+ }
815
+ const link = (0, octez_connect_ui_1.isIOS)(window) ? wallet.deeplink : `${wallet.deeplink}wc?uri=`;
816
+ if (!(link === null || link === void 0 ? void 0 : link.length)) {
817
+ return;
818
+ }
819
+ window.location = link;
820
+ });
821
+ }
822
+ addQueryParam(paramName, paramValue) {
823
+ return paramName + '=' + paramValue;
824
+ }
825
+ buildPayload(action, status) {
826
+ return __awaiter(this, void 0, void 0, function* () {
827
+ var _a, _b, _c, _d;
828
+ const wallet = yield this.storage.get(octez_connect_types_1.StorageKey.LAST_SELECTED_WALLET);
829
+ const transport = this._activeAccount.isResolved()
830
+ ? ((_b = (_a = (yield this.getActiveAccount())) === null || _a === void 0 ? void 0 : _a.origin.type) !== null && _b !== void 0 ? _b : 'UNKNOWN')
831
+ : 'UNKNOWN';
832
+ return {
833
+ method: 'POST',
834
+ headers: {
835
+ 'Content-Type': 'application/json'
836
+ },
837
+ body: JSON.stringify({
838
+ userId: this.userId,
839
+ os: (0, octez_connect_ui_1.currentOS)(),
840
+ walletName: (_c = wallet === null || wallet === void 0 ? void 0 : wallet.name) !== null && _c !== void 0 ? _c : 'init',
841
+ walletType: (_d = wallet === null || wallet === void 0 ? void 0 : wallet.type) !== null && _d !== void 0 ? _d : 'init',
842
+ sdkVersion: octez_connect_core_1.SDK_VERSION,
843
+ transport,
844
+ time: new Date(),
845
+ action,
846
+ status
847
+ })
848
+ };
849
+ });
850
+ }
851
+ updateMetricsStorage(payload) {
852
+ return __awaiter(this, void 0, void 0, function* () {
853
+ const queue = yield this.beaconIDB.getAllKeys('metrics');
854
+ if (queue.length >= 1000) {
855
+ const key = queue.shift();
856
+ this.beaconIDB.delete(key.toString(), 'metrics');
857
+ }
858
+ this.beaconIDB.set(String(Date.now()), payload, 'metrics');
859
+ });
860
+ }
861
+ sendMetrics(uri, options, thenHandler, catchHandler) {
862
+ if (!this.enableMetrics && uri === 'performance-metrics/save') {
863
+ options && this.updateMetricsStorage(options.body);
864
+ }
865
+ if (!this.enableMetrics) {
866
+ return;
867
+ }
868
+ fetch(`${octez_connect_core_1.BACKEND_URL}/${uri}`, options)
869
+ .then((res) => thenHandler && thenHandler(res))
870
+ .catch((err) => {
871
+ console.warn('Network error encountered. Metrics sharing have been automatically disabled.');
872
+ logger.error(err.message);
873
+ this.enableMetrics = false; // in the event of a network error, stop sending metrics
874
+ catchHandler && catchHandler(err);
875
+ });
876
+ }
877
+ checkMakeRequest() {
878
+ return __awaiter(this, void 0, void 0, function* () {
879
+ const isResolved = this._transport.isResolved();
880
+ const isWCInstance = isResolved && (yield this.transport) instanceof octez_connect_transport_walletconnect_1.WalletConnectTransport;
881
+ yield this.multiTabChannel.init();
882
+ const isLeader = this.multiTabChannel.isLeader();
883
+ return !isResolved || !isWCInstance || isLeader || (0, octez_connect_ui_1.isMobileOS)(window);
884
+ });
885
+ }
886
+ /**
887
+ * Will remove the account from the local storage and set a new active account if necessary.
888
+ *
889
+ * @param accountIdentifier ID of the account
890
+ */
891
+ removeAccount(accountIdentifier) {
892
+ const _super = Object.create(null, {
893
+ removeAccount: { get: () => super.removeAccount }
894
+ });
895
+ return __awaiter(this, void 0, void 0, function* () {
896
+ const removeAccountResult = _super.removeAccount.call(this, accountIdentifier);
897
+ const activeAccount = yield this.getActiveAccount();
898
+ if (activeAccount && activeAccount.accountIdentifier === accountIdentifier) {
899
+ yield this.setActiveAccount(undefined);
900
+ }
901
+ return removeAccountResult;
902
+ });
903
+ }
904
+ /**
905
+ * Remove all accounts and set active account to undefined
906
+ */
907
+ removeAllAccounts() {
908
+ const _super = Object.create(null, {
909
+ removeAllAccounts: { get: () => super.removeAllAccounts }
910
+ });
911
+ return __awaiter(this, void 0, void 0, function* () {
912
+ yield _super.removeAllAccounts.call(this);
913
+ yield this.setActiveAccount(undefined);
914
+ });
915
+ }
916
+ /**
917
+ * Removes a peer and all the accounts that have been connected through that peer
918
+ *
919
+ * @param peer Peer to be removed
920
+ */
921
+ removePeer(peer_1) {
922
+ return __awaiter(this, arguments, void 0, function* (peer, sendDisconnectToPeer = false) {
923
+ const transport = yield this.transport;
924
+ const removePeerResult = transport.removePeer(peer);
925
+ yield this.removeAccountsForPeers([peer]);
926
+ if (sendDisconnectToPeer) {
927
+ yield this.sendDisconnectToPeer(peer, transport);
928
+ }
929
+ return removePeerResult;
930
+ });
931
+ }
932
+ /**
933
+ * Remove all peers and all accounts that have been connected through those peers
934
+ */
935
+ removeAllPeers() {
936
+ return __awaiter(this, arguments, void 0, function* (sendDisconnectToPeers = false) {
937
+ const transport = yield this.transport;
938
+ const peers = yield transport.getPeers();
939
+ const removePeerResult = transport.removeAllPeers();
940
+ yield this.removeAccountsForPeers(peers);
941
+ if (sendDisconnectToPeers) {
942
+ const disconnectPromises = peers.map((peer) => this.sendDisconnectToPeer(peer, transport));
943
+ yield Promise.all(disconnectPromises);
944
+ }
945
+ return removePeerResult;
946
+ });
947
+ }
948
+ /**
949
+ * Allows the user to subscribe to specific events that are fired in the SDK
950
+ *
951
+ * @param internalEvent The event to subscribe to
952
+ * @param eventCallback The callback that will be called when the event occurs
953
+ */
954
+ subscribeToEvent(internalEvent, eventCallback) {
955
+ return __awaiter(this, void 0, void 0, function* () {
956
+ if (internalEvent === events_1.BeaconEvent.ACTIVE_ACCOUNT_SET) {
957
+ this.isGetActiveAccountHandled = true;
958
+ }
959
+ yield this.events.on(internalEvent, eventCallback);
960
+ });
961
+ }
962
+ /**
963
+ * Check if we have permissions to send the specific message type to the active account.
964
+ * If no active account is set, only permission requests are allowed.
965
+ *
966
+ * @param type The type of the message
967
+ */
968
+ checkPermissions(type) {
969
+ return __awaiter(this, void 0, void 0, function* () {
970
+ if ([
971
+ octez_connect_types_1.BeaconMessageType.PermissionRequest,
972
+ octez_connect_types_1.BeaconMessageType.ProofOfEventChallengeRequest,
973
+ octez_connect_types_1.BeaconMessageType.SimulatedProofOfEventChallengeRequest
974
+ ].includes(type)) {
975
+ return true;
976
+ }
977
+ const activeAccount = yield this.getActiveAccount();
978
+ if (!activeAccount) {
979
+ throw yield this.sendInternalError('No active account set!');
980
+ }
981
+ const permissions = activeAccount.scopes;
982
+ switch (type) {
983
+ case octez_connect_types_1.BeaconMessageType.OperationRequest:
984
+ return permissions.includes(octez_connect_types_1.PermissionScope.OPERATION_REQUEST);
985
+ case octez_connect_types_1.BeaconMessageType.SignPayloadRequest:
986
+ return permissions.includes(octez_connect_types_1.PermissionScope.SIGN);
987
+ // TODO: ENCRYPTION
988
+ // case BeaconMessageType.EncryptPayloadRequest:
989
+ // return permissions.includes(PermissionScope.ENCRYPT)
990
+ case octez_connect_types_1.BeaconMessageType.BroadcastRequest:
991
+ return true;
992
+ default:
993
+ return false;
994
+ }
995
+ });
996
+ }
997
+ sendNotification(title, message, payload, protocolIdentifier) {
998
+ return __awaiter(this, void 0, void 0, function* () {
999
+ var _a, _b, _c;
1000
+ const activeAccount = yield this.getActiveAccount();
1001
+ if (!activeAccount ||
1002
+ (activeAccount &&
1003
+ !activeAccount.scopes.includes(octez_connect_types_1.PermissionScope.NOTIFICATION) &&
1004
+ !activeAccount.notification)) {
1005
+ throw new Error('notification permissions not given');
1006
+ }
1007
+ if (!((_a = activeAccount.notification) === null || _a === void 0 ? void 0 : _a.token)) {
1008
+ throw new Error('No AccessToken');
1009
+ }
1010
+ const url = (_b = activeAccount.notification) === null || _b === void 0 ? void 0 : _b.apiUrl;
1011
+ if (!url) {
1012
+ throw new Error('No Push URL set');
1013
+ }
1014
+ return this.sendNotificationWithAccessToken({
1015
+ url,
1016
+ recipient: activeAccount.address,
1017
+ title,
1018
+ body: message,
1019
+ payload,
1020
+ protocolIdentifier,
1021
+ accessToken: (_c = activeAccount.notification) === null || _c === void 0 ? void 0 : _c.token
1022
+ });
1023
+ });
1024
+ }
1025
+ addBlockchain(chain) {
1026
+ this.blockchains.set(chain.identifier, chain);
1027
+ chain.getWalletLists().then((walletLists) => {
1028
+ (0, octez_connect_ui_1.setDesktopList)(walletLists.desktopList);
1029
+ (0, octez_connect_ui_1.setExtensionList)(walletLists.extensionList);
1030
+ (0, octez_connect_ui_1.setWebList)(walletLists.webList);
1031
+ (0, octez_connect_ui_1.setiOSList)(walletLists.iOSList);
1032
+ });
1033
+ }
1034
+ removeBlockchain(chainIdentifier) {
1035
+ this.blockchains.delete(chainIdentifier);
1036
+ }
1037
+ permissionRequest(input) {
1038
+ return __awaiter(this, void 0, void 0, function* () {
1039
+ logger.log('permissionRequest', input);
1040
+ const blockchain = this.blockchains.get(input.blockchainIdentifier);
1041
+ if (!blockchain) {
1042
+ throw new Error(`Blockchain "${input.blockchainIdentifier}" not supported by dAppClient`);
1043
+ }
1044
+ const request = Object.assign(Object.assign({}, input), { type: octez_connect_types_1.BeaconMessageType.PermissionRequest, blockchainData: Object.assign(Object.assign({}, input.blockchainData), { appMetadata: yield this.getOwnAppMetadata() }) });
1045
+ logger.log('REQUESTION PERMIMISSION V3', 'xxx', request);
1046
+ this.sendMetrics('performance-metrics/save', yield this.buildPayload('connect', 'start'));
1047
+ const logId = `makeRequestV3 ${Date.now()}`;
1048
+ logger.time(true, logId);
1049
+ const { message: response, connectionInfo } = yield this.makeRequestV3(request).catch((requestError) => __awaiter(this, void 0, void 0, function* () {
1050
+ requestError.errorType === octez_connect_types_1.BeaconErrorType.ABORTED_ERROR
1051
+ ? this.sendMetrics('performance-metrics/save', yield this.buildPayload('message', 'abort'))
1052
+ : this.sendMetrics('performance-metrics/save', yield this.buildPayload('message', 'error'));
1053
+ logger.time(false, logId);
1054
+ throw yield this.handleRequestError(request, requestError);
1055
+ }));
1056
+ logger.time(false, logId);
1057
+ this.sendMetrics('performance-metrics/save', yield this.buildPayload('connect', 'start'));
1058
+ logger.log('RESPONSE V3', response, connectionInfo);
1059
+ const partialAccountInfos = yield blockchain.getAccountInfosFromPermissionResponse(response.message);
1060
+ const accountInfo = {
1061
+ accountIdentifier: partialAccountInfos[0].accountId,
1062
+ senderId: response.senderId,
1063
+ origin: {
1064
+ type: connectionInfo.origin,
1065
+ id: connectionInfo.id
1066
+ },
1067
+ address: partialAccountInfos[0].address, // Store all addresses
1068
+ publicKey: partialAccountInfos[0].publicKey,
1069
+ scopes: response.message.blockchainData.scopes,
1070
+ connectedAt: new Date().getTime(),
1071
+ chainData: response.message.blockchainData
1072
+ };
1073
+ yield this.accountManager.addAccount(accountInfo);
1074
+ yield this.setActiveAccount(accountInfo);
1075
+ yield blockchain.handleResponse({
1076
+ request,
1077
+ account: accountInfo,
1078
+ output: response,
1079
+ blockExplorer: this.blockExplorer,
1080
+ connectionContext: connectionInfo,
1081
+ walletInfo: yield this.getWalletInfo()
1082
+ });
1083
+ yield this.notifySuccess(request, {
1084
+ account: accountInfo,
1085
+ output: {
1086
+ address: partialAccountInfos[0].address,
1087
+ network: { type: 'substrate' },
1088
+ scopes: []
1089
+ },
1090
+ blockExplorer: this.blockExplorer,
1091
+ connectionContext: connectionInfo,
1092
+ walletInfo: yield this.getWalletInfo()
1093
+ });
1094
+ // return output
1095
+ return response.message;
1096
+ });
1097
+ }
1098
+ request(input) {
1099
+ return __awaiter(this, void 0, void 0, function* () {
1100
+ logger.log('request', input);
1101
+ const blockchain = this.blockchains.get(input.blockchainIdentifier);
1102
+ if (!blockchain) {
1103
+ throw new Error(`Blockchain "${blockchain}" not supported by dAppClient`);
1104
+ }
1105
+ yield blockchain.validateRequest(input);
1106
+ const activeAccount = yield this.getActiveAccount();
1107
+ if (!activeAccount) {
1108
+ throw yield this.sendInternalError('No active account!');
1109
+ }
1110
+ const request = Object.assign(Object.assign({}, input), { type: octez_connect_types_1.BeaconMessageType.BlockchainRequest, accountId: activeAccount.accountIdentifier });
1111
+ this.sendMetrics('performance-metrics/save', yield this.buildPayload('message', 'start'));
1112
+ const logId = `makeRequestV3 ${Date.now()}`;
1113
+ logger.time(true, logId);
1114
+ const res = (yield this.checkMakeRequest())
1115
+ ? this.makeRequestV3(request)
1116
+ : this.makeRequestBC(request);
1117
+ res.catch((requestError) => __awaiter(this, void 0, void 0, function* () {
1118
+ requestError.errorType === octez_connect_types_1.BeaconErrorType.ABORTED_ERROR
1119
+ ? this.sendMetrics('performance-metrics/save', yield this.buildPayload('message', 'abort'))
1120
+ : this.sendMetrics('performance-metrics/save', yield this.buildPayload('message', 'error'));
1121
+ logger.time(false, logId);
1122
+ throw yield this.handleRequestError(request, requestError);
1123
+ }));
1124
+ const { message: response, connectionInfo } = (yield res);
1125
+ logger.time(false, logId);
1126
+ this.sendMetrics('performance-metrics/save', yield this.buildPayload('message', 'success'));
1127
+ yield blockchain.handleResponse({
1128
+ request,
1129
+ account: activeAccount,
1130
+ output: response,
1131
+ blockExplorer: this.blockExplorer,
1132
+ connectionContext: connectionInfo,
1133
+ walletInfo: yield this.getWalletInfo()
1134
+ });
1135
+ yield this.notifySuccess(request, {
1136
+ walletInfo: yield this.getWalletInfo()
1137
+ });
1138
+ return response.message;
1139
+ });
1140
+ }
1141
+ /**
1142
+ * Send a permission request to the DApp. This should be done as the first step. The wallet will respond
1143
+ * with an publicKey and permissions that were given. The account returned will be set as the "activeAccount"
1144
+ * and will be used for the following requests.
1145
+ *
1146
+ * @param input The message details we need to prepare the PermissionRequest message.
1147
+ */
1148
+ requestPermissions(input) {
1149
+ return __awaiter(this, void 0, void 0, function* () {
1150
+ if (input === null || input === void 0 ? void 0 : input.network) {
1151
+ throw new Error('[BEACON] the "network" property is no longer accepted in input. Please provide it when instantiating DAppClient.');
1152
+ }
1153
+ const request = {
1154
+ appMetadata: yield this.getOwnAppMetadata(),
1155
+ type: octez_connect_types_1.BeaconMessageType.PermissionRequest,
1156
+ network: this.network,
1157
+ scopes: input && input.scopes
1158
+ ? input.scopes
1159
+ : [octez_connect_types_1.PermissionScope.OPERATION_REQUEST, octez_connect_types_1.PermissionScope.SIGN]
1160
+ };
1161
+ this.analytics.track('event', 'DAppClient', 'Permission requested');
1162
+ this.sendMetrics('performance-metrics/save', yield this.buildPayload('connect', 'start'));
1163
+ const logId = `makeRequest ${Date.now()}`;
1164
+ logger.time(true, logId);
1165
+ const res = (yield this.checkMakeRequest()) || !(yield this.getActiveAccount())
1166
+ ? this.makeRequest(request, undefined, undefined)
1167
+ : this.makeRequestBC(request);
1168
+ res.catch((requestError) => __awaiter(this, void 0, void 0, function* () {
1169
+ requestError.errorType === octez_connect_types_1.BeaconErrorType.ABORTED_ERROR
1170
+ ? this.sendMetrics('performance-metrics/save', yield this.buildPayload('message', 'abort'))
1171
+ : this.sendMetrics('performance-metrics/save', yield this.buildPayload('message', 'error'));
1172
+ logger.time(false, logId);
1173
+ throw yield this.handleRequestError(request, requestError);
1174
+ }));
1175
+ const { message, connectionInfo } = (yield res);
1176
+ logger.time(false, logId);
1177
+ this.sendMetrics('performance-metrics/save', yield this.buildPayload('connect', 'success'));
1178
+ logger.log('requestPermissions', '######## MESSAGE #######');
1179
+ logger.log('requestPermissions', message);
1180
+ const accountInfo = yield this.onNewAccount(message, connectionInfo);
1181
+ logger.log('requestPermissions', '######## ACCOUNT INFO #######');
1182
+ logger.log('requestPermissions', JSON.stringify(accountInfo));
1183
+ yield this.accountManager.addAccount(accountInfo);
1184
+ const output = Object.assign(Object.assign({}, message), { walletKey: accountInfo.walletKey, address: accountInfo.address, accountInfo });
1185
+ yield this.notifySuccess(request, {
1186
+ account: accountInfo,
1187
+ output,
1188
+ blockExplorer: this.blockExplorer,
1189
+ connectionContext: connectionInfo,
1190
+ walletInfo: yield this.getWalletInfo()
1191
+ });
1192
+ this.analytics.track('event', 'DAppClient', 'Permission received', {
1193
+ address: accountInfo.address
1194
+ });
1195
+ return output;
1196
+ });
1197
+ }
1198
+ /**
1199
+ * Send a proof of event request to the wallet. The wallet will either accept or decline the challenge.
1200
+ * If it is accepted, the challenge will be stored, meaning that even if the user refresh the page, the DAppClient will keep checking if the challenge has been fulfilled.
1201
+ * Once the challenge is stored, a challenge stored message will be sent to the wallet.
1202
+ * It's **highly recommended** to run a proof of event challenge to check the identity of an abstracted account
1203
+ *
1204
+ * @param input The message details we need to prepare the ProofOfEventChallenge message.
1205
+ */
1206
+ requestProofOfEventChallenge(input) {
1207
+ return __awaiter(this, void 0, void 0, function* () {
1208
+ const activeAccount = yield this.getActiveAccount();
1209
+ if (!activeAccount)
1210
+ throw new Error('Please request permissions before doing a proof of event challenge');
1211
+ if (activeAccount.walletType !== 'abstracted_account' &&
1212
+ activeAccount.verificationType !== 'proof_of_event')
1213
+ throw new Error('This wallet is not an abstracted account and thus cannot perform proof of event');
1214
+ const request = {
1215
+ type: octez_connect_types_1.BeaconMessageType.ProofOfEventChallengeRequest,
1216
+ contractAddress: activeAccount.address,
1217
+ payload: input.payload
1218
+ };
1219
+ this.sendMetrics('performance-metrics/save', yield this.buildPayload('message', 'start'));
1220
+ const logId = `makeRequest ${Date.now()}`;
1221
+ logger.time(true, logId);
1222
+ const res = (yield this.checkMakeRequest())
1223
+ ? this.makeRequest(request)
1224
+ : this.makeRequestBC(request);
1225
+ res.catch((requestError) => __awaiter(this, void 0, void 0, function* () {
1226
+ requestError.errorType === octez_connect_types_1.BeaconErrorType.ABORTED_ERROR
1227
+ ? this.sendMetrics('performance-metrics/save', yield this.buildPayload('message', 'abort'))
1228
+ : this.sendMetrics('performance-metrics/save', yield this.buildPayload('message', 'error'));
1229
+ logger.time(false, logId);
1230
+ throw yield this.handleRequestError(request, requestError);
1231
+ }));
1232
+ const { message, connectionInfo } = (yield res);
1233
+ logger.time(false, logId);
1234
+ this.sendMetrics('performance-metrics/save', yield this.buildPayload('message', 'success'));
1235
+ this.analytics.track('event', 'DAppClient', `Proof of event challenge ${message.isAccepted ? 'accepted' : 'refused'}`, { address: activeAccount.address });
1236
+ yield this.notifySuccess(request, {
1237
+ account: activeAccount,
1238
+ output: message,
1239
+ blockExplorer: this.blockExplorer,
1240
+ connectionContext: connectionInfo,
1241
+ walletInfo: yield this.getWalletInfo()
1242
+ });
1243
+ return message;
1244
+ });
1245
+ }
1246
+ /**
1247
+ * Send a simulated proof of event request to the wallet. The wallet will either accept or decline the challenge.
1248
+ * It's the same than `requestProofOfEventChallenge` but rather than executing operations on the blockchain to prove the identity,
1249
+ * The wallet will return a list of operations that you'll be able to run on your side to verify the identity of the abstracted account
1250
+ * It's **highly recommended** to run a proof of event challenge to check the identity of an abstracted account
1251
+ *
1252
+ * @param input The message details we need to prepare the SimulatedProofOfEventChallenge message.
1253
+ */
1254
+ requestSimulatedProofOfEventChallenge(input) {
1255
+ return __awaiter(this, void 0, void 0, function* () {
1256
+ const activeAccount = yield this.getActiveAccount();
1257
+ if (!activeAccount)
1258
+ throw new Error('Please request permissions before doing a proof of event challenge');
1259
+ if (activeAccount.walletType !== 'abstracted_account' &&
1260
+ activeAccount.verificationType !== 'proof_of_event') {
1261
+ throw new Error('This wallet is not an abstracted account and thus cannot perform a simulated proof of event');
1262
+ }
1263
+ const request = Object.assign({ type: octez_connect_types_1.BeaconMessageType.SimulatedProofOfEventChallengeRequest, contractAddress: activeAccount.address }, input);
1264
+ const logId = `makeRequest ${Date.now()}`;
1265
+ logger.time(true, logId);
1266
+ const res = (yield this.checkMakeRequest())
1267
+ ? this.makeRequest(request)
1268
+ : this.makeRequestBC(request);
1269
+ res.catch((requestError) => __awaiter(this, void 0, void 0, function* () {
1270
+ requestError.errorType === octez_connect_types_1.BeaconErrorType.ABORTED_ERROR
1271
+ ? this.sendMetrics('performance-metrics/save', yield this.buildPayload('message', 'abort'))
1272
+ : this.sendMetrics('performance-metrics/save', yield this.buildPayload('message', 'error'));
1273
+ logger.time(false, logId);
1274
+ throw yield this.handleRequestError(request, requestError);
1275
+ }));
1276
+ const { message, connectionInfo } = (yield res);
1277
+ logger.time(false, logId);
1278
+ this.analytics.track('event', 'DAppClient', `Simulated proof of event challenge ${!message.errorMessage ? 'accepted' : 'refused'}`, { address: activeAccount.address });
1279
+ yield this.notifySuccess(request, {
1280
+ account: activeAccount,
1281
+ output: message,
1282
+ blockExplorer: this.blockExplorer,
1283
+ connectionContext: connectionInfo,
1284
+ walletInfo: yield this.getWalletInfo()
1285
+ });
1286
+ return message;
1287
+ });
1288
+ }
1289
+ /**
1290
+ * This method will send a "SignPayloadRequest" to the wallet. This method is meant to be used to sign
1291
+ * arbitrary data (eg. a string). It will return the signature in the format of "edsig..."
1292
+ *
1293
+ * @param input The message details we need to prepare the SignPayloadRequest message.
1294
+ */
1295
+ requestSignPayload(input) {
1296
+ return __awaiter(this, void 0, void 0, function* () {
1297
+ if (!input.payload) {
1298
+ throw yield this.sendInternalError('Payload must be provided');
1299
+ }
1300
+ const activeAccount = yield this.getActiveAccount();
1301
+ if (!activeAccount) {
1302
+ throw yield this.sendInternalError('No active account!');
1303
+ }
1304
+ const payload = input.payload;
1305
+ if (typeof payload !== 'string') {
1306
+ throw new Error('Payload must be a string');
1307
+ }
1308
+ const signingType = (() => {
1309
+ switch (input.signingType) {
1310
+ case octez_connect_types_1.SigningType.OPERATION:
1311
+ if (!payload.startsWith('03')) {
1312
+ throw new Error('When using signing type "OPERATION", the payload must start with prefix "03"');
1313
+ }
1314
+ return octez_connect_types_1.SigningType.OPERATION;
1315
+ case octez_connect_types_1.SigningType.MICHELINE:
1316
+ if (!payload.startsWith('05')) {
1317
+ throw new Error('When using signing type "MICHELINE", the payload must start with prefix "05"');
1318
+ }
1319
+ return octez_connect_types_1.SigningType.MICHELINE;
1320
+ case octez_connect_types_1.SigningType.RAW:
1321
+ default:
1322
+ return octez_connect_types_1.SigningType.RAW;
1323
+ }
1324
+ })();
1325
+ this.analytics.track('event', 'DAppClient', 'Signature requested');
1326
+ const request = {
1327
+ type: octez_connect_types_1.BeaconMessageType.SignPayloadRequest,
1328
+ signingType,
1329
+ payload,
1330
+ sourceAddress: input.sourceAddress || activeAccount.address
1331
+ };
1332
+ this.sendMetrics('performance-metrics/save', yield this.buildPayload('message', 'start'));
1333
+ const logId = `makeRequest ${Date.now()}`;
1334
+ logger.time(true, logId);
1335
+ const res = (yield this.checkMakeRequest())
1336
+ ? this.makeRequest(request)
1337
+ : this.makeRequestBC(request);
1338
+ res.catch((requestError) => __awaiter(this, void 0, void 0, function* () {
1339
+ requestError.errorType === octez_connect_types_1.BeaconErrorType.ABORTED_ERROR
1340
+ ? this.sendMetrics('performance-metrics/save', yield this.buildPayload('message', 'abort'))
1341
+ : this.sendMetrics('performance-metrics/save', yield this.buildPayload('message', 'error'));
1342
+ logger.time(false, logId);
1343
+ throw yield this.handleRequestError(request, requestError);
1344
+ }));
1345
+ const { message, connectionInfo } = (yield res);
1346
+ logger.time(false, logId);
1347
+ this.sendMetrics('performance-metrics/save', yield this.buildPayload('message', 'success'));
1348
+ yield this.notifySuccess(request, {
1349
+ account: activeAccount,
1350
+ output: message,
1351
+ connectionContext: connectionInfo,
1352
+ walletInfo: yield this.getWalletInfo()
1353
+ });
1354
+ this.analytics.track('event', 'DAppClient', 'Signature response');
1355
+ return message;
1356
+ });
1357
+ }
1358
+ /**
1359
+ * This method will send an "EncryptPayloadRequest" to the wallet. This method is meant to be used to encrypt or decrypt
1360
+ * arbitrary data (eg. a string). It will return the encrypted or decrypted payload
1361
+ *
1362
+ * @param input The message details we need to prepare the EncryptPayloadRequest message.
1363
+ */
1364
+ // TODO: ENCRYPTION
1365
+ // public async requestEncryptPayload(
1366
+ // input: RequestEncryptPayloadInput
1367
+ // ): Promise<EncryptPayloadResponseOutput> {
1368
+ // if (!input.payload) {
1369
+ // throw await this.sendInternalError('Payload must be provided')
1370
+ // }
1371
+ // const activeAccount: AccountInfo | undefined = await this.getActiveAccount()
1372
+ // if (!activeAccount) {
1373
+ // throw await this.sendInternalError('No active account!')
1374
+ // }
1375
+ // const payload = input.payload
1376
+ // if (typeof payload !== 'string') {
1377
+ // throw new Error('Payload must be a string')
1378
+ // }
1379
+ // if (typeof input.encryptionCryptoOperation === 'undefined') {
1380
+ // throw new Error('encryptionCryptoOperation must be defined')
1381
+ // }
1382
+ // if (typeof input.encryptionType === 'undefined') {
1383
+ // throw new Error('encryptionType must be defined')
1384
+ // }
1385
+ // const request: EncryptPayloadRequestInput = {
1386
+ // type: BeaconMessageType.EncryptPayloadRequest,
1387
+ // cryptoOperation: input.encryptionCryptoOperation,
1388
+ // encryptionType: input.encryptionType,
1389
+ // payload,
1390
+ // sourceAddress: input.sourceAddress || activeAccount.address
1391
+ // }
1392
+ // const { message, connectionInfo } = await this.makeRequest<
1393
+ // EncryptPayloadRequest,
1394
+ // EncryptPayloadResponse
1395
+ // >(request).catch(async (requestError: ErrorResponse) => {
1396
+ // throw await this.handleRequestError(request, requestError)
1397
+ // })
1398
+ // await this.notifySuccess(request, {
1399
+ // account: activeAccount,
1400
+ // output: message,
1401
+ // connectionContext: connectionInfo,
1402
+ // walletInfo: await this.getWalletInfo()
1403
+ // })
1404
+ // return message
1405
+ // }
1406
+ /**
1407
+ * This method sends an OperationRequest to the wallet. This method should be used for all kinds of operations,
1408
+ * eg. transaction or delegation. Not all properties have to be provided. Data like "counter" and fees will be
1409
+ * fetched and calculated by the wallet (but they can still be provided if required).
1410
+ *
1411
+ * @param input The message details we need to prepare the OperationRequest message.
1412
+ */
1413
+ requestOperation(input) {
1414
+ return __awaiter(this, void 0, void 0, function* () {
1415
+ if (!input.operationDetails) {
1416
+ throw yield this.sendInternalError('Operation details must be provided');
1417
+ }
1418
+ const activeAccount = yield this.getActiveAccount();
1419
+ if (!activeAccount) {
1420
+ throw yield this.sendInternalError('No active account!');
1421
+ }
1422
+ const request = {
1423
+ type: octez_connect_types_1.BeaconMessageType.OperationRequest,
1424
+ network: activeAccount.network || this.network,
1425
+ operationDetails: input.operationDetails,
1426
+ sourceAddress: activeAccount.address || ''
1427
+ };
1428
+ this.analytics.track('event', 'DAppClient', 'Operation requested');
1429
+ this.sendMetrics('performance-metrics/save', yield this.buildPayload('message', 'start'));
1430
+ const logId = `makeRequest ${Date.now()}`;
1431
+ logger.time(true, logId);
1432
+ const res = (yield this.checkMakeRequest())
1433
+ ? this.makeRequest(request)
1434
+ : this.makeRequestBC(request);
1435
+ res.catch((requestError) => __awaiter(this, void 0, void 0, function* () {
1436
+ requestError.errorType === octez_connect_types_1.BeaconErrorType.ABORTED_ERROR
1437
+ ? this.sendMetrics('performance-metrics/save', yield this.buildPayload('message', 'abort'))
1438
+ : this.sendMetrics('performance-metrics/save', yield this.buildPayload('message', 'error'));
1439
+ logger.time(false, logId);
1440
+ throw yield this.handleRequestError(request, requestError);
1441
+ }));
1442
+ const { message, connectionInfo } = (yield res);
1443
+ logger.time(false, logId);
1444
+ this.sendMetrics('performance-metrics/save', yield this.buildPayload('message', 'success'));
1445
+ yield this.notifySuccess(request, {
1446
+ account: activeAccount,
1447
+ output: message,
1448
+ blockExplorer: this.blockExplorer,
1449
+ connectionContext: connectionInfo,
1450
+ walletInfo: yield this.getWalletInfo()
1451
+ });
1452
+ this.analytics.track('event', 'DAppClient', 'Operation response');
1453
+ return message;
1454
+ });
1455
+ }
1456
+ /**
1457
+ * Sends a "BroadcastRequest" to the wallet. This method can be used to inject an already signed transaction
1458
+ * to the network.
1459
+ *
1460
+ * @param input The message details we need to prepare the BroadcastRequest message.
1461
+ */
1462
+ requestBroadcast(input) {
1463
+ return __awaiter(this, void 0, void 0, function* () {
1464
+ var _a;
1465
+ if (!input.signedTransaction) {
1466
+ throw yield this.sendInternalError('Signed transaction must be provided');
1467
+ }
1468
+ // Add error message for deprecation of network
1469
+ // TODO: Remove when we remove deprecated preferredNetwork
1470
+ if (input.network !== undefined && this.network.type !== ((_a = input.network) === null || _a === void 0 ? void 0 : _a.type)) {
1471
+ console.error('[BEACON] The network specified in the DAppClient constructor does not match the network set in the broadcast request. Please set the network in the constructor. Setting it during the Broadcast Request is deprecated.');
1472
+ }
1473
+ const request = {
1474
+ type: octez_connect_types_1.BeaconMessageType.BroadcastRequest,
1475
+ network: this.network,
1476
+ signedTransaction: input.signedTransaction
1477
+ };
1478
+ this.analytics.track('event', 'DAppClient', 'Broadcast requested');
1479
+ this.sendMetrics('performance-metrics/save', yield this.buildPayload('message', 'start'));
1480
+ const logId = `makeRequest ${Date.now()}`;
1481
+ logger.time(true, logId);
1482
+ const res = (yield this.checkMakeRequest())
1483
+ ? this.makeRequest(request)
1484
+ : this.makeRequestBC(request);
1485
+ res.catch((requestError) => __awaiter(this, void 0, void 0, function* () {
1486
+ requestError.errorType === octez_connect_types_1.BeaconErrorType.ABORTED_ERROR
1487
+ ? this.sendMetrics('performance-metrics/save', yield this.buildPayload('message', 'abort'))
1488
+ : this.sendMetrics('performance-metrics/save', yield this.buildPayload('message', 'error'));
1489
+ logger.time(false, logId);
1490
+ throw yield this.handleRequestError(request, requestError);
1491
+ }));
1492
+ const { message, connectionInfo } = (yield res);
1493
+ logger.time(false, logId);
1494
+ this.sendMetrics('performance-metrics/save', yield this.buildPayload('message', 'success'));
1495
+ yield this.notifySuccess(request, {
1496
+ network: this.network,
1497
+ output: message,
1498
+ blockExplorer: this.blockExplorer,
1499
+ connectionContext: connectionInfo,
1500
+ walletInfo: yield this.getWalletInfo()
1501
+ });
1502
+ this.analytics.track('event', 'DAppClient', 'Broadcast response');
1503
+ return message;
1504
+ });
1505
+ }
1506
+ setActivePeer(peer) {
1507
+ return __awaiter(this, void 0, void 0, function* () {
1508
+ if (this._activePeer.isSettled()) {
1509
+ // If the promise has already been resolved we need to create a new one.
1510
+ this._activePeer = octez_connect_utils_1.ExposedPromise.resolve(peer);
1511
+ }
1512
+ else {
1513
+ this._activePeer.resolve(peer);
1514
+ }
1515
+ if (!peer) {
1516
+ return;
1517
+ }
1518
+ yield this.initInternalTransports();
1519
+ if (peer.type === 'postmessage-pairing-response') {
1520
+ yield this.setTransport(this.postMessageTransport);
1521
+ }
1522
+ else if (peer.type === 'p2p-pairing-response') {
1523
+ yield this.setTransport(this.p2pTransport);
1524
+ }
1525
+ });
1526
+ }
1527
+ /**
1528
+ * A "setter" for when the transport needs to be changed.
1529
+ */
1530
+ setTransport(transport) {
1531
+ const _super = Object.create(null, {
1532
+ setTransport: { get: () => super.setTransport }
1533
+ });
1534
+ return __awaiter(this, void 0, void 0, function* () {
1535
+ if (!transport) {
1536
+ this._initPromise = undefined;
1537
+ }
1538
+ const result = _super.setTransport.call(this, transport);
1539
+ const event = transport ? Object.assign({}, transport) : undefined;
1540
+ // remove keyPair, to prevent dApps from accidentaly leaking the privateKey
1541
+ if (event) {
1542
+ event.client = Object.assign(Object.assign({}, event.client), { keyPair: undefined });
1543
+ }
1544
+ yield this.events.emit(events_1.BeaconEvent.ACTIVE_TRANSPORT_SET, event);
1545
+ return result;
1546
+ });
1547
+ }
1548
+ /**
1549
+ * This method will emit an internal error message.
1550
+ *
1551
+ * @param errorMessage The error message to send.
1552
+ */
1553
+ sendInternalError(errorMessage) {
1554
+ return __awaiter(this, void 0, void 0, function* () {
1555
+ yield this.events.emit(events_1.BeaconEvent.INTERNAL_ERROR, { text: errorMessage });
1556
+ throw new Error(errorMessage);
1557
+ });
1558
+ }
1559
+ /**
1560
+ * This method will remove all accounts associated with a specific peer.
1561
+ *
1562
+ * @param peersToRemove An array of peers for which accounts should be removed
1563
+ */
1564
+ removeAccountsForPeers(peersToRemove) {
1565
+ return __awaiter(this, void 0, void 0, function* () {
1566
+ const peerIdsToRemove = peersToRemove.map((peer) => peer.senderId);
1567
+ return this.removeAccountsForPeerIds(peerIdsToRemove);
1568
+ });
1569
+ }
1570
+ removeAccountsForPeerIds(peerIds) {
1571
+ return __awaiter(this, void 0, void 0, function* () {
1572
+ const accounts = yield this.accountManager.getAccounts();
1573
+ // Remove all accounts with origin of the specified peer
1574
+ const accountsToRemove = accounts.filter((account) => peerIds.includes(account.senderId));
1575
+ const accountIdentifiersToRemove = accountsToRemove.map((accountInfo) => accountInfo.accountIdentifier);
1576
+ yield this.accountManager.removeAccounts(accountIdentifiersToRemove);
1577
+ // Check if one of the accounts that was removed was the active account and if yes, set it to undefined
1578
+ const activeAccount = yield this.getActiveAccount();
1579
+ if (activeAccount) {
1580
+ if (accountIdentifiersToRemove.includes(activeAccount.accountIdentifier)) {
1581
+ yield this.setActiveAccount(undefined);
1582
+ }
1583
+ }
1584
+ });
1585
+ }
1586
+ /**
1587
+ * This message handles errors that we receive from the wallet.
1588
+ *
1589
+ * @param request The request we sent
1590
+ * @param beaconError The error we received
1591
+ */
1592
+ handleRequestError(request, beaconError) {
1593
+ return __awaiter(this, void 0, void 0, function* () {
1594
+ logger.error('handleRequestError', 'error response', beaconError);
1595
+ if (beaconError.errorType) {
1596
+ const buttons = [];
1597
+ if (beaconError.errorType === octez_connect_types_1.BeaconErrorType.NO_PRIVATE_KEY_FOUND_ERROR) {
1598
+ const actionCallback = () => __awaiter(this, void 0, void 0, function* () {
1599
+ const operationRequest = request;
1600
+ // if the account we requested is not available, we remove it locally
1601
+ let accountInfo;
1602
+ if (operationRequest.sourceAddress && operationRequest.network) {
1603
+ const accountIdentifier = yield (0, octez_connect_core_1.getAccountIdentifier)(operationRequest.sourceAddress, operationRequest.network);
1604
+ accountInfo = yield this.getAccount(accountIdentifier);
1605
+ if (accountInfo) {
1606
+ yield this.removeAccount(accountInfo.accountIdentifier);
1607
+ }
1608
+ }
1609
+ });
1610
+ buttons.push({ text: 'Remove account', actionCallback });
1611
+ }
1612
+ const peer = yield this.getPeer();
1613
+ const activeAccount = yield this.getActiveAccount();
1614
+ // If we sent a permission request, received an error and there is no active account, we need to reset the DAppClient.
1615
+ // This most likely means that the user rejected the first permission request after pairing a wallet, so we "forget" the paired wallet to allow the user to pair again.
1616
+ if (request.type === octez_connect_types_1.BeaconMessageType.PermissionRequest &&
1617
+ (yield this.getActiveAccount()) === undefined) {
1618
+ this._initPromise = undefined;
1619
+ this.postMessageTransport = undefined;
1620
+ this.p2pTransport = undefined;
1621
+ this.walletConnectTransport = undefined;
1622
+ yield this.setTransport();
1623
+ yield this.setActivePeer();
1624
+ }
1625
+ this.events
1626
+ .emit(beacon_message_events_1.messageEvents[request.type].error, {
1627
+ errorResponse: beaconError,
1628
+ walletInfo: yield this.getWalletInfo(peer, activeAccount),
1629
+ errorMessages: this.errorMessages
1630
+ }, buttons)
1631
+ .catch((emitError) => logger.error('handleRequestError', emitError));
1632
+ throw (0, octez_connect_core_1.getError)(beaconError.errorType, beaconError.errorData);
1633
+ }
1634
+ throw beaconError;
1635
+ });
1636
+ }
1637
+ /**
1638
+ * This message will send an event when we receive a successful response to one of the requests we sent.
1639
+ *
1640
+ * @param request The request we sent
1641
+ * @param response The response we received
1642
+ */
1643
+ notifySuccess(request, response) {
1644
+ return __awaiter(this, void 0, void 0, function* () {
1645
+ this.events
1646
+ .emit(beacon_message_events_1.messageEvents[request.type].success, response)
1647
+ .catch((emitError) => console.warn(emitError));
1648
+ });
1649
+ }
1650
+ getWalletInfoFromStorage() {
1651
+ return __awaiter(this, void 0, void 0, function* () {
1652
+ return yield this.storage.get(octez_connect_types_1.StorageKey.LAST_SELECTED_WALLET);
1653
+ });
1654
+ }
1655
+ updateStorageWallet(walletInfo) {
1656
+ return __awaiter(this, void 0, void 0, function* () {
1657
+ var _a;
1658
+ const wallet = yield this.storage.get(octez_connect_types_1.StorageKey.LAST_SELECTED_WALLET);
1659
+ if (!wallet) {
1660
+ return;
1661
+ }
1662
+ wallet.name = walletInfo.name;
1663
+ wallet.icon = (_a = walletInfo.icon) !== null && _a !== void 0 ? _a : wallet.icon;
1664
+ this.storage.set(octez_connect_types_1.StorageKey.LAST_SELECTED_WALLET, wallet);
1665
+ });
1666
+ }
1667
+ getWalletInfo(peer_1, account_1) {
1668
+ return __awaiter(this, arguments, void 0, function* (peer, account, readFromStorage = true) {
1669
+ var _a, _b, _c, _d, _e, _f;
1670
+ const selectedAccount = account ? account : yield this.getActiveAccount();
1671
+ const selectedPeer = peer ? peer : yield this.getPeer(selectedAccount);
1672
+ let walletInfo;
1673
+ if (selectedAccount) {
1674
+ walletInfo = yield this.appMetadataManager.getAppMetadata(selectedAccount.senderId);
1675
+ }
1676
+ let storageWallet;
1677
+ if (readFromStorage) {
1678
+ storageWallet = yield this.getWalletInfoFromStorage();
1679
+ }
1680
+ if (!walletInfo) {
1681
+ walletInfo = {
1682
+ name: (_b = (_a = selectedPeer === null || selectedPeer === void 0 ? void 0 : selectedPeer.name) !== null && _a !== void 0 ? _a : storageWallet === null || storageWallet === void 0 ? void 0 : storageWallet.key) !== null && _b !== void 0 ? _b : '',
1683
+ icon: (_c = selectedPeer === null || selectedPeer === void 0 ? void 0 : selectedPeer.icon) !== null && _c !== void 0 ? _c : storageWallet === null || storageWallet === void 0 ? void 0 : storageWallet.icon,
1684
+ type: storageWallet === null || storageWallet === void 0 ? void 0 : storageWallet.type
1685
+ };
1686
+ this.updateStorageWallet(walletInfo);
1687
+ }
1688
+ const lowerCaseCompare = (str1, str2) => {
1689
+ if (str1 && str2) {
1690
+ return str1.toLowerCase() === str2.toLowerCase();
1691
+ }
1692
+ return false;
1693
+ };
1694
+ const getOrgName = (name) => name.split(/[_\s]+/)[0];
1695
+ const apps = [
1696
+ ...(0, octez_connect_ui_1.getiOSList)(),
1697
+ ...(0, octez_connect_ui_1.getWebList)(),
1698
+ ...(0, octez_connect_ui_1.getDesktopList)(),
1699
+ ...(0, octez_connect_ui_1.getExtensionList)()
1700
+ ].filter((app) => { var _a; return lowerCaseCompare(getOrgName(app.key), getOrgName((_a = walletInfo === null || walletInfo === void 0 ? void 0 : walletInfo.name) !== null && _a !== void 0 ? _a : 'wallet')); });
1701
+ // TODO: Remove once all wallets send the icon?
1702
+ const mobile = apps.find((app) => app.universalLink || app.key.includes('ios') || app.key.includes('mobile'));
1703
+ const browser = apps.find((app) => app.links);
1704
+ const desktop = apps.find((app) => app.downloadLink);
1705
+ const extension = apps.find((app) => app.id);
1706
+ const appTypeMap = {
1707
+ extension: { app: extension, type: 'extension' },
1708
+ desktop: { app: desktop, type: 'desktop' },
1709
+ mobile: { app: mobile, type: 'mobile' },
1710
+ web: { app: browser, type: 'web' }
1711
+ };
1712
+ const defaultType = () => {
1713
+ if ((0, octez_connect_ui_1.isBrowser)(window) && browser)
1714
+ return { app: browser, type: 'web' };
1715
+ if ((0, octez_connect_ui_1.isDesktop)(window) && desktop)
1716
+ return { app: desktop, type: 'desktop' };
1717
+ if ((0, octez_connect_ui_1.isBrowser)(window) && extension)
1718
+ return { app: extension, type: 'extension' };
1719
+ if (mobile)
1720
+ return { app: mobile, type: 'mobile' };
1721
+ return { app: undefined, type: undefined };
1722
+ };
1723
+ const { app, type } = storageWallet ? appTypeMap[storageWallet.type] : defaultType();
1724
+ if (app) {
1725
+ let deeplink;
1726
+ if (app.hasOwnProperty('links')) {
1727
+ deeplink = app.links[(_d = selectedAccount === null || selectedAccount === void 0 ? void 0 : selectedAccount.network.type) !== null && _d !== void 0 ? _d : this.network.type];
1728
+ }
1729
+ else if (app.hasOwnProperty('deepLink')) {
1730
+ deeplink = app.deepLink;
1731
+ }
1732
+ return {
1733
+ name: (_e = app === null || app === void 0 ? void 0 : app.name) !== null && _e !== void 0 ? _e : walletInfo.name,
1734
+ icon: (_f = app === null || app === void 0 ? void 0 : app.logo) !== null && _f !== void 0 ? _f : walletInfo.icon,
1735
+ deeplink,
1736
+ type: type
1737
+ };
1738
+ }
1739
+ return walletInfo;
1740
+ });
1741
+ }
1742
+ getPeer(account) {
1743
+ return __awaiter(this, void 0, void 0, function* () {
1744
+ var _a, _b, _c, _d, _e, _f;
1745
+ let peer;
1746
+ if (account) {
1747
+ logger.log('getPeer', 'We have an account', account);
1748
+ const postMessagePeers = (_b = (yield ((_a = this.postMessageTransport) === null || _a === void 0 ? void 0 : _a.getPeers()))) !== null && _b !== void 0 ? _b : [];
1749
+ const p2pPeers = (_d = (yield ((_c = this.p2pTransport) === null || _c === void 0 ? void 0 : _c.getPeers()))) !== null && _d !== void 0 ? _d : [];
1750
+ const walletConnectPeers = (_f = (yield ((_e = this.walletConnectTransport) === null || _e === void 0 ? void 0 : _e.getPeers()))) !== null && _f !== void 0 ? _f : [];
1751
+ const peers = [...postMessagePeers, ...p2pPeers, ...walletConnectPeers];
1752
+ logger.log('getPeer', 'Found peers', peers, account);
1753
+ peer = peers.find((peerEl) => peerEl.senderId === account.senderId);
1754
+ if (!peer) {
1755
+ // We could not find an exact match for a sender, so we most likely received it over a relay
1756
+ peer = peers.find((peerEl) => peerEl.id === account.origin.id);
1757
+ }
1758
+ }
1759
+ else {
1760
+ peer = yield this._activePeer.promise;
1761
+ logger.log('getPeer', 'Active peer', peer);
1762
+ }
1763
+ return peer;
1764
+ });
1765
+ }
1766
+ makeRequest(requestInput, skipResponse, otherTabMessageId) {
1767
+ return __awaiter(this, void 0, void 0, function* () {
1768
+ var _a, _b, _c;
1769
+ const messageId = otherTabMessageId !== null && otherTabMessageId !== void 0 ? otherTabMessageId : (yield (0, octez_connect_utils_1.generateGUID)());
1770
+ if (this._initPromise && this.isInitPending) {
1771
+ yield Promise.all([
1772
+ (_a = this.postMessageTransport) === null || _a === void 0 ? void 0 : _a.disconnect(),
1773
+ (_b = this.walletConnectTransport) === null || _b === void 0 ? void 0 : _b.disconnect()
1774
+ ]);
1775
+ this._initPromise = undefined;
1776
+ this.hideUI(['toast']);
1777
+ }
1778
+ logger.log('makeRequest', 'starting');
1779
+ this.isInitPending = true;
1780
+ yield this.init();
1781
+ this.isInitPending = false;
1782
+ logger.log('makeRequest', 'after init');
1783
+ if (yield this.addRequestAndCheckIfRateLimited()) {
1784
+ this.events
1785
+ .emit(events_1.BeaconEvent.LOCAL_RATE_LIMIT_REACHED)
1786
+ .catch((emitError) => console.warn(emitError));
1787
+ throw new Error('rate limit reached');
1788
+ }
1789
+ if (!(yield this.checkPermissions(requestInput.type))) {
1790
+ this.events.emit(events_1.BeaconEvent.NO_PERMISSIONS).catch((emitError) => console.warn(emitError));
1791
+ throw new Error('No permissions to send this request to wallet!');
1792
+ }
1793
+ if (!this.beaconId) {
1794
+ throw yield this.sendInternalError('octez.connect ID not defined');
1795
+ }
1796
+ const request = Object.assign({ id: messageId, version: '2', senderId: yield (0, octez_connect_core_1.getSenderId)(yield this.beaconId) }, requestInput);
1797
+ let exposed;
1798
+ if (!skipResponse) {
1799
+ exposed = new octez_connect_utils_1.ExposedPromise();
1800
+ this.addOpenRequest(request.id, exposed);
1801
+ }
1802
+ const payload = yield new octez_connect_core_1.Serializer().serialize(request);
1803
+ const account = yield this.getActiveAccount();
1804
+ const peer = yield this.getPeer(account);
1805
+ const walletInfo = yield this.getWalletInfo(peer, account);
1806
+ logger.log('makeRequest', 'sending message', request);
1807
+ try {
1808
+ ;
1809
+ (yield this.transport).send(payload, peer);
1810
+ if (request.type !== octez_connect_types_1.BeaconMessageType.PermissionRequest ||
1811
+ (this._activeAccount.isResolved() && (yield this._activeAccount.promise))) {
1812
+ this.tryToAppSwitch();
1813
+ }
1814
+ }
1815
+ catch (sendError) {
1816
+ this.events.emit(events_1.BeaconEvent.INTERNAL_ERROR, {
1817
+ text: 'Unable to send message. If this problem persists, please reset the connection and pair your wallet again.',
1818
+ buttons: [
1819
+ {
1820
+ text: 'Reset Connection',
1821
+ actionCallback: () => __awaiter(this, void 0, void 0, function* () {
1822
+ (0, octez_connect_ui_1.closeToast)();
1823
+ this.disconnect();
1824
+ })
1825
+ }
1826
+ ]
1827
+ });
1828
+ throw sendError;
1829
+ }
1830
+ if (!otherTabMessageId) {
1831
+ this.events
1832
+ .emit(beacon_message_events_1.messageEvents[requestInput.type].sent, {
1833
+ walletInfo: Object.assign(Object.assign({}, walletInfo), { name: (_c = walletInfo.name) !== null && _c !== void 0 ? _c : 'Wallet' }),
1834
+ extraInfo: {
1835
+ resetCallback: () => __awaiter(this, void 0, void 0, function* () {
1836
+ this.disconnect();
1837
+ })
1838
+ }
1839
+ })
1840
+ .catch((emitError) => console.warn(emitError));
1841
+ }
1842
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1843
+ return exposed === null || exposed === void 0 ? void 0 : exposed.promise; // TODO: fix type
1844
+ });
1845
+ }
1846
+ /**
1847
+ * This method handles sending of requests to the DApp. It makes sure that the DAppClient is initialized and connected
1848
+ * to the transport. After that rate limits and permissions will be checked, an ID is attached and the request is sent
1849
+ * to the DApp over the transport.
1850
+ *
1851
+ * @param requestInput The BeaconMessage to be sent to the wallet
1852
+ * @param account The account that the message will be sent to
1853
+ */
1854
+ makeRequestV3(requestInput, otherTabMessageId) {
1855
+ return __awaiter(this, void 0, void 0, function* () {
1856
+ var _a, _b, _c;
1857
+ if (this._initPromise && this.isInitPending) {
1858
+ yield Promise.all([
1859
+ (_a = this.postMessageTransport) === null || _a === void 0 ? void 0 : _a.disconnect(),
1860
+ (_b = this.walletConnectTransport) === null || _b === void 0 ? void 0 : _b.disconnect()
1861
+ ]);
1862
+ this._initPromise = undefined;
1863
+ this.hideUI(['toast']);
1864
+ }
1865
+ const messageId = otherTabMessageId !== null && otherTabMessageId !== void 0 ? otherTabMessageId : (yield (0, octez_connect_utils_1.generateGUID)());
1866
+ logger.log('makeRequest', 'starting');
1867
+ this.isInitPending = true;
1868
+ yield this.init(undefined, true);
1869
+ this.isInitPending = false;
1870
+ logger.log('makeRequest', 'after init');
1871
+ if (yield this.addRequestAndCheckIfRateLimited()) {
1872
+ this.events
1873
+ .emit(events_1.BeaconEvent.LOCAL_RATE_LIMIT_REACHED)
1874
+ .catch((emitError) => console.warn(emitError));
1875
+ throw new Error('rate limit reached');
1876
+ }
1877
+ if (!this.beaconId) {
1878
+ throw yield this.sendInternalError('octez.connect ID not defined');
1879
+ }
1880
+ const request = {
1881
+ id: messageId,
1882
+ version: '3',
1883
+ senderId: yield (0, octez_connect_core_1.getSenderId)(yield this.beaconId),
1884
+ message: requestInput
1885
+ };
1886
+ const exposed = new octez_connect_utils_1.ExposedPromise();
1887
+ this.addOpenRequest(request.id, exposed);
1888
+ const payload = yield new octez_connect_core_1.Serializer().serialize(request);
1889
+ const account = yield this.getActiveAccount();
1890
+ const peer = yield this.getPeer(account);
1891
+ const walletInfo = yield this.getWalletInfo(peer, account);
1892
+ logger.log('makeRequest', 'sending message', request);
1893
+ try {
1894
+ ;
1895
+ (yield this.transport).send(payload, peer);
1896
+ if (request.message.type !== octez_connect_types_1.BeaconMessageType.PermissionRequest ||
1897
+ (this._activeAccount.isResolved() && (yield this._activeAccount.promise))) {
1898
+ this.tryToAppSwitch();
1899
+ }
1900
+ }
1901
+ catch (sendError) {
1902
+ this.events.emit(events_1.BeaconEvent.INTERNAL_ERROR, {
1903
+ text: 'Unable to send message. If this problem persists, please reset the connection and pair your wallet again.',
1904
+ buttons: [
1905
+ {
1906
+ text: 'Reset Connection',
1907
+ actionCallback: () => __awaiter(this, void 0, void 0, function* () {
1908
+ (0, octez_connect_ui_1.closeToast)();
1909
+ this.disconnect();
1910
+ })
1911
+ }
1912
+ ]
1913
+ });
1914
+ throw sendError;
1915
+ }
1916
+ const index = requestInput.type;
1917
+ this.events
1918
+ .emit(beacon_message_events_1.messageEvents[index].sent, {
1919
+ walletInfo: Object.assign(Object.assign({}, walletInfo), { name: (_c = walletInfo.name) !== null && _c !== void 0 ? _c : 'Wallet' }),
1920
+ extraInfo: {
1921
+ resetCallback: () => __awaiter(this, void 0, void 0, function* () {
1922
+ this.disconnect();
1923
+ })
1924
+ }
1925
+ })
1926
+ .catch((emitError) => console.warn(emitError));
1927
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1928
+ return exposed.promise; // TODO: fix type
1929
+ });
1930
+ }
1931
+ makeRequestBC(request) {
1932
+ return __awaiter(this, void 0, void 0, function* () {
1933
+ if (!this._transport.isResolved()) {
1934
+ return;
1935
+ }
1936
+ const transport = yield this.transport;
1937
+ if (transport.type !== octez_connect_types_1.TransportType.WALLETCONNECT) {
1938
+ return;
1939
+ }
1940
+ if (yield this.addRequestAndCheckIfRateLimited()) {
1941
+ this.events
1942
+ .emit(events_1.BeaconEvent.LOCAL_RATE_LIMIT_REACHED)
1943
+ .catch((emitError) => console.warn(emitError));
1944
+ throw new Error('rate limit reached');
1945
+ }
1946
+ const id = yield (0, octez_connect_utils_1.generateGUID)();
1947
+ this.multiTabChannel.postMessage({
1948
+ type: request.type,
1949
+ data: request,
1950
+ id
1951
+ });
1952
+ if (request.type !== octez_connect_types_1.BeaconMessageType.PermissionRequest ||
1953
+ (this._activeAccount.isResolved() && (yield this._activeAccount.promise))) {
1954
+ this.tryToAppSwitch();
1955
+ }
1956
+ this.events
1957
+ .emit(beacon_message_events_1.messageEvents[octez_connect_types_1.BeaconMessageType.PermissionRequest].sent, {
1958
+ walletInfo: yield this.getWalletInfo(),
1959
+ extraInfo: {
1960
+ resetCallback: () => this.disconnect()
1961
+ }
1962
+ })
1963
+ .catch((emitError) => console.warn(emitError));
1964
+ const exposed = new octez_connect_utils_1.ExposedPromise();
1965
+ this.addOpenRequest(id, exposed);
1966
+ return exposed.promise;
1967
+ });
1968
+ }
1969
+ disconnect() {
1970
+ return __awaiter(this, void 0, void 0, function* () {
1971
+ if (!this._transport.isResolved()) {
1972
+ throw new Error('No transport available.');
1973
+ }
1974
+ const transport = yield this.transport;
1975
+ if (transport.connectionStatus === octez_connect_types_1.TransportStatus.NOT_CONNECTED) {
1976
+ throw new Error('Not connected.');
1977
+ }
1978
+ yield this.createStateSnapshot();
1979
+ this.sendMetrics('performance-metrics/save', yield this.buildPayload('disconnect', 'start'));
1980
+ yield this.clearActiveAccount();
1981
+ if (!(transport instanceof octez_connect_transport_walletconnect_1.WalletConnectTransport)) {
1982
+ yield transport.disconnect();
1983
+ }
1984
+ this.postMessageTransport = undefined;
1985
+ this.p2pTransport = undefined;
1986
+ this.walletConnectTransport = undefined;
1987
+ this.sendMetrics('performance-metrics/save', yield this.buildPayload('disconnect', 'success'));
1988
+ });
1989
+ }
1990
+ /**
1991
+ * Adds a requests to the "openRequests" set so we know what messages have already been answered/handled.
1992
+ *
1993
+ * @param id The ID of the message
1994
+ * @param promise A promise that resolves once the response for that specific message is received
1995
+ */
1996
+ addOpenRequest(id, promise) {
1997
+ logger.log('addOpenRequest', this.name, `adding request ${id} and waiting for answer`);
1998
+ this.openRequests.set(id, promise);
1999
+ }
2000
+ sendNotificationWithAccessToken(notification) {
2001
+ return __awaiter(this, void 0, void 0, function* () {
2002
+ const { url, recipient, title, body, payload, protocolIdentifier, accessToken } = notification;
2003
+ const timestamp = new Date().toISOString();
2004
+ const keypair = yield this.keyPair;
2005
+ const rawPublicKey = keypair.publicKey;
2006
+ const prefix = Buffer.from(new Uint8Array([13, 15, 37, 217]));
2007
+ const publicKey = bs58check_1.default.encode(Buffer.concat([prefix, Buffer.from(rawPublicKey)]));
2008
+ const constructedString = [
2009
+ 'Tezos Signed Message: ',
2010
+ recipient,
2011
+ title,
2012
+ body,
2013
+ timestamp,
2014
+ payload
2015
+ ].join(' ');
2016
+ const bytes = (0, octez_connect_utils_1.toHex)(constructedString);
2017
+ const payloadBytes = '05' + '01' + bytes.length.toString(16).padStart(8, '0') + bytes;
2018
+ const signature = yield (0, octez_connect_utils_1.signMessage)(payloadBytes, {
2019
+ secretKey: Buffer.from(keypair.secretKey)
2020
+ });
2021
+ const notificationResponse = yield axios_1.default.post(`${url}/send`, {
2022
+ recipient,
2023
+ title,
2024
+ body,
2025
+ timestamp,
2026
+ payload,
2027
+ accessToken,
2028
+ protocolIdentifier,
2029
+ sender: {
2030
+ name: this.name,
2031
+ publicKey,
2032
+ signature
2033
+ }
2034
+ });
2035
+ return notificationResponse.data;
2036
+ });
2037
+ }
2038
+ onNewAccount(message, connectionInfo) {
2039
+ return __awaiter(this, void 0, void 0, function* () {
2040
+ var _a, _b, _c;
2041
+ // TODO: Migration code. Remove sometime after 1.0.0 release.
2042
+ const tempPK = message.publicKey || message.pubkey || message.pubKey;
2043
+ const publicKey = !!tempPK ? (0, octez_connect_utils_1.prefixPublicKey)(tempPK) : undefined;
2044
+ if (!publicKey && !message.address) {
2045
+ throw new Error('PublicKey or Address must be defined');
2046
+ }
2047
+ const address = (_a = message.address) !== null && _a !== void 0 ? _a : (yield (0, octez_connect_utils_1.getAddressFromPublicKey)(publicKey));
2048
+ if (!(0, octez_connect_utils_1.isValidAddress)(address)) {
2049
+ throw new Error(`Invalid address: "${address}"`);
2050
+ }
2051
+ if (message.walletType === 'abstracted_account' &&
2052
+ address.substring(0, 3) !== octez_connect_utils_1.CONTRACT_PREFIX) {
2053
+ throw new Error(`Invalid abstracted account address "${address}", it should be a ${octez_connect_utils_1.CONTRACT_PREFIX} address`);
2054
+ }
2055
+ logger.log('######## MESSAGE #######');
2056
+ logger.log('onNewAccount', message);
2057
+ const walletKey = (_b = (yield this.storage.get(octez_connect_types_1.StorageKey.LAST_SELECTED_WALLET))) === null || _b === void 0 ? void 0 : _b.key;
2058
+ const accountInfo = Object.assign({ accountIdentifier: yield (0, octez_connect_core_1.getAccountIdentifier)(address, message.network), senderId: message.senderId, origin: {
2059
+ type: connectionInfo.origin,
2060
+ id: connectionInfo.id
2061
+ }, walletKey,
2062
+ address,
2063
+ publicKey, network: message.network, scopes: message.scopes, threshold: message.threshold, notification: message.notification, connectedAt: new Date().getTime(), walletType: (_c = message.walletType) !== null && _c !== void 0 ? _c : 'implicit', verificationType: message.verificationType }, (message.verificationType === 'proof_of_event' ? { hasVerifiedChallenge: false } : {}));
2064
+ logger.log('accountInfo', '######## ACCOUNT INFO #######');
2065
+ logger.log('accountInfo', accountInfo);
2066
+ yield this.accountManager.addAccount(accountInfo);
2067
+ yield this.setActiveAccount(accountInfo);
2068
+ return accountInfo;
2069
+ });
2070
+ }
2071
+ }
2072
+ exports.DAppClient = DAppClient;
2073
+ //# sourceMappingURL=DAppClient.js.map