@aptos-labs/wallet-adapter-core 0.2.0 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # @aptos-labs/wallet-adapter-core
2
2
 
3
+ ## 0.2.2
4
+
5
+ ### Patch Changes
6
+
7
+ - d4e298f: Support Lodable wallet
8
+ Implement multi signature verification
9
+ Add a new optional property propertyName for multi-chain wallet
10
+ - 5fc6981: Throw wallet not found error when trying to connect to an uninstalled wallet
11
+ - d711f43: Import tweetnacl package via default export to support commonJS
12
+
13
+ ## 0.2.1
14
+
15
+ ### Patch Changes
16
+
17
+ - 1c3576e: Throw Sign Transaction is not supported error
18
+
3
19
  ## 0.2.0
4
20
 
5
21
  ### Minor Changes
package/dist/index.d.ts CHANGED
@@ -66,6 +66,7 @@ interface AdapterPluginProps<Name extends string = string> {
66
66
  name: WalletName<Name>;
67
67
  url: string;
68
68
  icon: `data:image/${"svg+xml" | "webp" | "png" | "gif"};base64,${string}`;
69
+ providerName?: string;
69
70
  provider: any;
70
71
  connect(): Promise<any>;
71
72
  disconnect: () => Promise<any>;
package/dist/index.js CHANGED
@@ -35,7 +35,7 @@ module.exports = __toCommonJS(src_exports);
35
35
  // src/WalletCore.ts
36
36
  var import_aptos = require("aptos");
37
37
  var import_eventemitter3 = __toESM(require("eventemitter3"));
38
- var import_tweetnacl = require("tweetnacl");
38
+ var import_tweetnacl = __toESM(require("tweetnacl"));
39
39
  var import_buffer = require("buffer");
40
40
 
41
41
  // src/constants.ts
@@ -138,6 +138,12 @@ var WalletSignTransactionError = class extends WalletError {
138
138
  this.name = "WalletSignTransactionError";
139
139
  }
140
140
  };
141
+ var WalletNotSupportedMethod = class extends WalletError {
142
+ constructor() {
143
+ super(...arguments);
144
+ this.name = "WalletNotSupportedMethod";
145
+ }
146
+ };
141
147
 
142
148
  // src/utils/scopePollingDetectionStrategy.ts
143
149
  function scopePollingDetectionStrategy(detect) {
@@ -194,12 +200,15 @@ var WalletCore = class extends import_eventemitter3.default {
194
200
  scopePollingDetectionStrategy() {
195
201
  var _a;
196
202
  (_a = this._wallets) == null ? void 0 : _a.forEach((wallet) => {
197
- wallet.readyState = typeof window === "undefined" || typeof document === "undefined" ? "Unsupported" /* Unsupported */ : "NotDetected" /* NotDetected */;
203
+ if (!wallet.readyState) {
204
+ wallet.readyState = typeof window === "undefined" || typeof document === "undefined" ? "Unsupported" /* Unsupported */ : "NotDetected" /* NotDetected */;
205
+ }
198
206
  if (typeof window !== "undefined") {
199
207
  scopePollingDetectionStrategy(() => {
200
- if (Object.keys(window).includes(wallet.name.toLowerCase())) {
208
+ const providerName = wallet.providerName || wallet.name.toLowerCase();
209
+ if (Object.keys(window).includes(providerName)) {
201
210
  wallet.readyState = "Installed" /* Installed */;
202
- wallet.provider = window[wallet.name.toLowerCase()];
211
+ wallet.provider = window[providerName];
203
212
  this.emit("readyStateChange", wallet);
204
213
  return true;
205
214
  }
@@ -270,10 +279,9 @@ var WalletCore = class extends import_eventemitter3.default {
270
279
  const selectedWallet = (_a = this._wallets) == null ? void 0 : _a.find(
271
280
  (wallet) => wallet.name === walletName
272
281
  );
273
- if (!selectedWallet)
274
- return;
275
- if (selectedWallet.readyState !== "Installed" /* Installed */)
276
- return;
282
+ if (!selectedWallet || selectedWallet.readyState !== "Installed" /* Installed */ && selectedWallet.readyState !== "Loadable" /* Loadable */) {
283
+ throw new WalletConnectionError(`${walletName} wallet not found`).message;
284
+ }
277
285
  if (this._connected) {
278
286
  await this.disconnect();
279
287
  }
@@ -318,9 +326,13 @@ var WalletCore = class extends import_eventemitter3.default {
318
326
  }
319
327
  }
320
328
  async signTransaction(transaction) {
329
+ var _a;
330
+ if (this._wallet && !("signTransaction" in this._wallet)) {
331
+ throw new WalletNotSupportedMethod(
332
+ `Sign Transaction is not supported by ${(_a = this.wallet) == null ? void 0 : _a.name}`
333
+ ).message;
334
+ }
321
335
  try {
322
- if (this._wallet && !("signTransaction" in this._wallet))
323
- return null;
324
336
  this.doesWalletExist();
325
337
  const response = await this._wallet.signTransaction(transaction);
326
338
  return response;
@@ -379,12 +391,42 @@ var WalletCore = class extends import_eventemitter3.default {
379
391
  throw new WalletSignMessageAndVerifyError("Failed to sign a message").message;
380
392
  let verified = false;
381
393
  if (Array.isArray(response.signature)) {
394
+ const { fullMessage, signature, bitmap } = response;
395
+ if (bitmap) {
396
+ const minKeysRequired = this._account.minKeysRequired;
397
+ if (signature.length < minKeysRequired) {
398
+ verified = false;
399
+ } else {
400
+ const bits = Array.from(bitmap).flatMap(
401
+ (n) => Array.from({ length: 8 }).map((_, i) => n >> i & 1)
402
+ );
403
+ const index = bits.map((_, i) => i).filter((i) => bits[i]);
404
+ const publicKeys = this._account.publicKey;
405
+ const matchedPublicKeys = publicKeys.filter(
406
+ (_, i) => index.includes(i)
407
+ );
408
+ verified = true;
409
+ for (let i = 0; i < signature.length; i++) {
410
+ const isSigVerified = import_tweetnacl.default.sign.detached.verify(
411
+ import_buffer.Buffer.from(fullMessage),
412
+ import_buffer.Buffer.from(signature[i], "hex"),
413
+ import_buffer.Buffer.from(matchedPublicKeys[i], "hex")
414
+ );
415
+ if (!isSigVerified) {
416
+ verified = false;
417
+ break;
418
+ }
419
+ }
420
+ }
421
+ } else {
422
+ throw new WalletSignMessageAndVerifyError("Failed to get a bitmap").message;
423
+ }
382
424
  } else {
383
425
  const currentAccountPublicKey = new import_aptos.HexString(
384
426
  this._account.publicKey
385
427
  );
386
428
  const signature = new import_aptos.HexString(response.signature);
387
- verified = import_tweetnacl.sign.detached.verify(
429
+ verified = import_tweetnacl.default.sign.detached.verify(
388
430
  import_buffer.Buffer.from(response.fullMessage),
389
431
  import_buffer.Buffer.from(signature.noPrefix(), "hex"),
390
432
  import_buffer.Buffer.from(currentAccountPublicKey.noPrefix(), "hex")
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  // src/WalletCore.ts
2
2
  import { HexString } from "aptos";
3
3
  import EventEmitter from "eventemitter3";
4
- import { sign } from "tweetnacl";
4
+ import nacl from "tweetnacl";
5
5
  import { Buffer } from "buffer";
6
6
 
7
7
  // src/constants.ts
@@ -104,6 +104,12 @@ var WalletSignTransactionError = class extends WalletError {
104
104
  this.name = "WalletSignTransactionError";
105
105
  }
106
106
  };
107
+ var WalletNotSupportedMethod = class extends WalletError {
108
+ constructor() {
109
+ super(...arguments);
110
+ this.name = "WalletNotSupportedMethod";
111
+ }
112
+ };
107
113
 
108
114
  // src/utils/scopePollingDetectionStrategy.ts
109
115
  function scopePollingDetectionStrategy(detect) {
@@ -160,12 +166,15 @@ var WalletCore = class extends EventEmitter {
160
166
  scopePollingDetectionStrategy() {
161
167
  var _a;
162
168
  (_a = this._wallets) == null ? void 0 : _a.forEach((wallet) => {
163
- wallet.readyState = typeof window === "undefined" || typeof document === "undefined" ? "Unsupported" /* Unsupported */ : "NotDetected" /* NotDetected */;
169
+ if (!wallet.readyState) {
170
+ wallet.readyState = typeof window === "undefined" || typeof document === "undefined" ? "Unsupported" /* Unsupported */ : "NotDetected" /* NotDetected */;
171
+ }
164
172
  if (typeof window !== "undefined") {
165
173
  scopePollingDetectionStrategy(() => {
166
- if (Object.keys(window).includes(wallet.name.toLowerCase())) {
174
+ const providerName = wallet.providerName || wallet.name.toLowerCase();
175
+ if (Object.keys(window).includes(providerName)) {
167
176
  wallet.readyState = "Installed" /* Installed */;
168
- wallet.provider = window[wallet.name.toLowerCase()];
177
+ wallet.provider = window[providerName];
169
178
  this.emit("readyStateChange", wallet);
170
179
  return true;
171
180
  }
@@ -236,10 +245,9 @@ var WalletCore = class extends EventEmitter {
236
245
  const selectedWallet = (_a = this._wallets) == null ? void 0 : _a.find(
237
246
  (wallet) => wallet.name === walletName
238
247
  );
239
- if (!selectedWallet)
240
- return;
241
- if (selectedWallet.readyState !== "Installed" /* Installed */)
242
- return;
248
+ if (!selectedWallet || selectedWallet.readyState !== "Installed" /* Installed */ && selectedWallet.readyState !== "Loadable" /* Loadable */) {
249
+ throw new WalletConnectionError(`${walletName} wallet not found`).message;
250
+ }
243
251
  if (this._connected) {
244
252
  await this.disconnect();
245
253
  }
@@ -284,9 +292,13 @@ var WalletCore = class extends EventEmitter {
284
292
  }
285
293
  }
286
294
  async signTransaction(transaction) {
295
+ var _a;
296
+ if (this._wallet && !("signTransaction" in this._wallet)) {
297
+ throw new WalletNotSupportedMethod(
298
+ `Sign Transaction is not supported by ${(_a = this.wallet) == null ? void 0 : _a.name}`
299
+ ).message;
300
+ }
287
301
  try {
288
- if (this._wallet && !("signTransaction" in this._wallet))
289
- return null;
290
302
  this.doesWalletExist();
291
303
  const response = await this._wallet.signTransaction(transaction);
292
304
  return response;
@@ -345,12 +357,42 @@ var WalletCore = class extends EventEmitter {
345
357
  throw new WalletSignMessageAndVerifyError("Failed to sign a message").message;
346
358
  let verified = false;
347
359
  if (Array.isArray(response.signature)) {
360
+ const { fullMessage, signature, bitmap } = response;
361
+ if (bitmap) {
362
+ const minKeysRequired = this._account.minKeysRequired;
363
+ if (signature.length < minKeysRequired) {
364
+ verified = false;
365
+ } else {
366
+ const bits = Array.from(bitmap).flatMap(
367
+ (n) => Array.from({ length: 8 }).map((_, i) => n >> i & 1)
368
+ );
369
+ const index = bits.map((_, i) => i).filter((i) => bits[i]);
370
+ const publicKeys = this._account.publicKey;
371
+ const matchedPublicKeys = publicKeys.filter(
372
+ (_, i) => index.includes(i)
373
+ );
374
+ verified = true;
375
+ for (let i = 0; i < signature.length; i++) {
376
+ const isSigVerified = nacl.sign.detached.verify(
377
+ Buffer.from(fullMessage),
378
+ Buffer.from(signature[i], "hex"),
379
+ Buffer.from(matchedPublicKeys[i], "hex")
380
+ );
381
+ if (!isSigVerified) {
382
+ verified = false;
383
+ break;
384
+ }
385
+ }
386
+ }
387
+ } else {
388
+ throw new WalletSignMessageAndVerifyError("Failed to get a bitmap").message;
389
+ }
348
390
  } else {
349
391
  const currentAccountPublicKey = new HexString(
350
392
  this._account.publicKey
351
393
  );
352
394
  const signature = new HexString(response.signature);
353
- verified = sign.detached.verify(
395
+ verified = nacl.sign.detached.verify(
354
396
  Buffer.from(response.fullMessage),
355
397
  Buffer.from(signature.noPrefix(), "hex"),
356
398
  Buffer.from(currentAccountPublicKey.noPrefix(), "hex")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aptos-labs/wallet-adapter-core",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "Aptos Wallet Adapter Core",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
package/src/WalletCore.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { HexString, Types } from "aptos";
2
2
  import EventEmitter from "eventemitter3";
3
- import { sign } from "tweetnacl";
3
+ import nacl from "tweetnacl";
4
4
  import { Buffer } from "buffer";
5
5
 
6
6
  import { WalletReadyState } from "./constants";
@@ -14,6 +14,7 @@ import {
14
14
  WalletNotConnectedError,
15
15
  WalletNotReadyError,
16
16
  WalletNotSelectedError,
17
+ WalletNotSupportedMethod,
17
18
  WalletSignAndSubmitMessageError,
18
19
  WalletSignMessageAndVerifyError,
19
20
  WalletSignMessageError,
@@ -52,15 +53,18 @@ export class WalletCore extends EventEmitter<WalletCoreEvents> {
52
53
 
53
54
  private scopePollingDetectionStrategy() {
54
55
  this._wallets?.forEach((wallet: Wallet) => {
55
- wallet.readyState =
56
- typeof window === "undefined" || typeof document === "undefined"
57
- ? WalletReadyState.Unsupported
58
- : WalletReadyState.NotDetected;
56
+ if (!wallet.readyState) {
57
+ wallet.readyState =
58
+ typeof window === "undefined" || typeof document === "undefined"
59
+ ? WalletReadyState.Unsupported
60
+ : WalletReadyState.NotDetected;
61
+ }
59
62
  if (typeof window !== "undefined") {
60
63
  scopePollingDetectionStrategy(() => {
61
- if (Object.keys(window).includes(wallet.name.toLowerCase())) {
64
+ const providerName = wallet.providerName || wallet.name.toLowerCase();
65
+ if (Object.keys(window).includes(providerName)) {
62
66
  wallet.readyState = WalletReadyState.Installed;
63
- wallet.provider = window[wallet.name.toLowerCase() as any];
67
+ wallet.provider = window[providerName as any];
64
68
  this.emit("readyStateChange", wallet);
65
69
  return true;
66
70
  }
@@ -170,8 +174,16 @@ export class WalletCore extends EventEmitter<WalletCoreEvents> {
170
174
  const selectedWallet = this._wallets?.find(
171
175
  (wallet: Wallet) => wallet.name === walletName
172
176
  );
173
- if (!selectedWallet) return;
174
- if (selectedWallet.readyState !== WalletReadyState.Installed) return;
177
+
178
+ if (
179
+ !selectedWallet ||
180
+ (selectedWallet.readyState !== WalletReadyState.Installed &&
181
+ selectedWallet.readyState !== WalletReadyState.Loadable)
182
+ ) {
183
+ throw new WalletConnectionError(`${walletName} wallet not found`)
184
+ .message;
185
+ }
186
+
175
187
  if (this._connected) {
176
188
  await this.disconnect();
177
189
  }
@@ -240,8 +252,13 @@ export class WalletCore extends EventEmitter<WalletCoreEvents> {
240
252
  async signTransaction(
241
253
  transaction: Types.TransactionPayload
242
254
  ): Promise<Uint8Array | null> {
255
+ if (this._wallet && !("signTransaction" in this._wallet)) {
256
+ throw new WalletNotSupportedMethod(
257
+ `Sign Transaction is not supported by ${this.wallet?.name}`
258
+ ).message;
259
+ }
260
+
243
261
  try {
244
- if (this._wallet && !("signTransaction" in this._wallet)) return null;
245
262
  this.doesWalletExist();
246
263
  const response = await (this._wallet as any).signTransaction(transaction);
247
264
  return response;
@@ -323,7 +340,42 @@ export class WalletCore extends EventEmitter<WalletCoreEvents> {
323
340
  let verified = false;
324
341
  if (Array.isArray(response.signature)) {
325
342
  // multi sig wallets
326
- // TODO - implement multi sig wallets
343
+ const { fullMessage, signature, bitmap } = response;
344
+ if (bitmap) {
345
+ const minKeysRequired = this._account.minKeysRequired as number;
346
+ if (signature.length < minKeysRequired) {
347
+ verified = false;
348
+ } else {
349
+ // Getting an array which marks the keys signing the message with 1, while marking 0 for the keys not being used.
350
+ const bits = Array.from(bitmap).flatMap((n) =>
351
+ Array.from({ length: 8 }).map((_, i) => (n >> i) & 1)
352
+ );
353
+ // Filter out indexes of the keys we need
354
+ const index = bits.map((_, i) => i).filter((i) => bits[i]);
355
+
356
+ const publicKeys = this._account.publicKey as string[];
357
+ const matchedPublicKeys = publicKeys.filter(
358
+ (_: string, i: number) => index.includes(i)
359
+ );
360
+
361
+ verified = true;
362
+ for (let i = 0; i < signature.length; i++) {
363
+ const isSigVerified = nacl.sign.detached.verify(
364
+ Buffer.from(fullMessage),
365
+ Buffer.from(signature[i], "hex"),
366
+ Buffer.from(matchedPublicKeys[i], "hex")
367
+ ); // `isSigVerified` should be `true` for every signature
368
+
369
+ if (!isSigVerified) {
370
+ verified = false;
371
+ break;
372
+ }
373
+ }
374
+ }
375
+ } else {
376
+ throw new WalletSignMessageAndVerifyError("Failed to get a bitmap")
377
+ .message;
378
+ }
327
379
  } else {
328
380
  // single sig wallets
329
381
  // support for when address doesnt have hex prefix (0x)
@@ -332,7 +384,7 @@ export class WalletCore extends EventEmitter<WalletCoreEvents> {
332
384
  );
333
385
  // support for when address doesnt have hex prefix (0x)
334
386
  const signature = new HexString(response.signature);
335
- verified = sign.detached.verify(
387
+ verified = nacl.sign.detached.verify(
336
388
  Buffer.from(response.fullMessage),
337
389
  Buffer.from(signature.noPrefix(), "hex"),
338
390
  Buffer.from(currentAccountPublicKey.noPrefix(), "hex")
@@ -98,3 +98,7 @@ export class WalletWindowClosedError extends WalletError {
98
98
  export class WalletResponseError extends WalletError {
99
99
  name = "WalletResponseError";
100
100
  }
101
+
102
+ export class WalletNotSupportedMethod extends WalletError {
103
+ name = "WalletNotSupportedMethod";
104
+ }
package/src/types.ts CHANGED
@@ -50,6 +50,7 @@ export interface AdapterPluginProps<Name extends string = string> {
50
50
  name: WalletName<Name>;
51
51
  url: string;
52
52
  icon: `data:image/${"svg+xml" | "webp" | "png" | "gif"};base64,${string}`;
53
+ providerName?: string
53
54
  provider: any;
54
55
  connect(): Promise<any>;
55
56
  disconnect: () => Promise<any>;