@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 +16 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +53 -11
- package/dist/index.mjs +53 -11
- package/package.json +1 -1
- package/src/WalletCore.ts +64 -12
- package/src/error/index.ts +4 -0
- package/src/types.ts +1 -0
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
|
|
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
|
-
|
|
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[
|
|
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
|
-
|
|
275
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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[
|
|
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
|
-
|
|
241
|
-
|
|
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
package/src/WalletCore.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { HexString, Types } from "aptos";
|
|
2
2
|
import EventEmitter from "eventemitter3";
|
|
3
|
-
import
|
|
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
|
-
|
|
57
|
-
|
|
58
|
-
|
|
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
|
-
|
|
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[
|
|
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
|
-
|
|
174
|
-
if (
|
|
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
|
-
|
|
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")
|
package/src/error/index.ts
CHANGED
|
@@ -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>;
|