@aptos-labs/wallet-adapter-core 0.1.7 → 0.2.1
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 +19 -0
- package/dist/index.d.ts +12 -7
- package/dist/index.js +56 -9
- package/dist/index.mjs +56 -9
- package/jest.config.js +5 -0
- package/package.json +18 -12
- package/src/WalletCore.ts +53 -9
- package/src/__tests__/WalletCore.test.ts +106 -0
- package/src/error/index.ts +8 -0
- package/src/types.ts +10 -6
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# @aptos-labs/wallet-adapter-core
|
|
2
|
+
|
|
3
|
+
## 0.2.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 1c3576e: Throw Sign Transaction is not supported error
|
|
8
|
+
|
|
9
|
+
## 0.2.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- 576bb57: Add chainId and url propoerties to NetworkInfo type
|
|
14
|
+
- 6e53116: Add support to verify a signed message
|
|
15
|
+
|
|
16
|
+
### Patch Changes
|
|
17
|
+
|
|
18
|
+
- 18a0429: Add properties to SignMessageResponse interface
|
|
19
|
+
- 42e29f6: Add multisig support for AccountInfo
|
package/dist/index.d.ts
CHANGED
|
@@ -30,11 +30,14 @@ declare type WalletName<T extends string = string> = T & {
|
|
|
30
30
|
__brand__: "WalletName";
|
|
31
31
|
};
|
|
32
32
|
declare type NetworkInfo = {
|
|
33
|
-
name: NetworkName
|
|
33
|
+
name: NetworkName;
|
|
34
|
+
chainId?: string;
|
|
35
|
+
url?: string;
|
|
34
36
|
};
|
|
35
37
|
declare type AccountInfo = {
|
|
36
38
|
address: string;
|
|
37
|
-
publicKey: string;
|
|
39
|
+
publicKey: string | string[];
|
|
40
|
+
minKeysRequired?: number;
|
|
38
41
|
};
|
|
39
42
|
interface AptosWalletErrorResult {
|
|
40
43
|
code: number;
|
|
@@ -96,14 +99,15 @@ interface SignMessagePayload {
|
|
|
96
99
|
nonce: string;
|
|
97
100
|
}
|
|
98
101
|
interface SignMessageResponse {
|
|
99
|
-
address
|
|
100
|
-
application
|
|
101
|
-
chainId
|
|
102
|
+
address?: string;
|
|
103
|
+
application?: string;
|
|
104
|
+
chainId?: number;
|
|
102
105
|
fullMessage: string;
|
|
103
106
|
message: string;
|
|
104
107
|
nonce: string;
|
|
105
108
|
prefix: "APTOS";
|
|
106
|
-
signature: string;
|
|
109
|
+
signature: string | string[];
|
|
110
|
+
bitmap?: Uint8Array;
|
|
107
111
|
}
|
|
108
112
|
|
|
109
113
|
declare class WalletCore extends EventEmitter<WalletCoreEvents> {
|
|
@@ -115,7 +119,7 @@ declare class WalletCore extends EventEmitter<WalletCoreEvents> {
|
|
|
115
119
|
private _connected;
|
|
116
120
|
constructor(plugins: Wallet[]);
|
|
117
121
|
private scopePollingDetectionStrategy;
|
|
118
|
-
private
|
|
122
|
+
private doesWalletExist;
|
|
119
123
|
private clearData;
|
|
120
124
|
setWallet(wallet: Wallet | null): void;
|
|
121
125
|
setAccount(account: AccountInfo | null): void;
|
|
@@ -191,6 +195,7 @@ declare class WalletCore extends EventEmitter<WalletCoreEvents> {
|
|
|
191
195
|
@throws WalletNetworkChangeError
|
|
192
196
|
*/
|
|
193
197
|
onNetworkChange(): Promise<void>;
|
|
198
|
+
signMessageAndVerify(message: SignMessagePayload): Promise<boolean>;
|
|
194
199
|
}
|
|
195
200
|
|
|
196
201
|
export { AccountInfo, AdapterPlugin, AdapterPluginEvents, AdapterPluginProps, AptosWalletErrorResult, NetworkInfo, NetworkName, PluginProvider, SignMessagePayload, SignMessageResponse, Wallet, WalletCore, WalletCoreEvents, WalletInfo, WalletName, WalletReadyState };
|
package/dist/index.js
CHANGED
|
@@ -33,7 +33,10 @@ __export(src_exports, {
|
|
|
33
33
|
module.exports = __toCommonJS(src_exports);
|
|
34
34
|
|
|
35
35
|
// src/WalletCore.ts
|
|
36
|
+
var import_aptos = require("aptos");
|
|
36
37
|
var import_eventemitter3 = __toESM(require("eventemitter3"));
|
|
38
|
+
var import_tweetnacl = require("tweetnacl");
|
|
39
|
+
var import_buffer = require("buffer");
|
|
37
40
|
|
|
38
41
|
// src/constants.ts
|
|
39
42
|
var WalletReadyState = /* @__PURE__ */ ((WalletReadyState2) => {
|
|
@@ -117,6 +120,12 @@ var WalletSignMessageError = class extends WalletError {
|
|
|
117
120
|
this.name = "WalletSignMessageError";
|
|
118
121
|
}
|
|
119
122
|
};
|
|
123
|
+
var WalletSignMessageAndVerifyError = class extends WalletError {
|
|
124
|
+
constructor() {
|
|
125
|
+
super(...arguments);
|
|
126
|
+
this.name = "WalletSignMessageAndVerifyError";
|
|
127
|
+
}
|
|
128
|
+
};
|
|
120
129
|
var WalletSignAndSubmitMessageError = class extends WalletError {
|
|
121
130
|
constructor() {
|
|
122
131
|
super(...arguments);
|
|
@@ -129,6 +138,12 @@ var WalletSignTransactionError = class extends WalletError {
|
|
|
129
138
|
this.name = "WalletSignTransactionError";
|
|
130
139
|
}
|
|
131
140
|
};
|
|
141
|
+
var WalletNotSupportedMethod = class extends WalletError {
|
|
142
|
+
constructor() {
|
|
143
|
+
super(...arguments);
|
|
144
|
+
this.name = "WalletNotSupportedMethod";
|
|
145
|
+
}
|
|
146
|
+
};
|
|
132
147
|
|
|
133
148
|
// src/utils/scopePollingDetectionStrategy.ts
|
|
134
149
|
function scopePollingDetectionStrategy(detect) {
|
|
@@ -199,7 +214,7 @@ var WalletCore = class extends import_eventemitter3.default {
|
|
|
199
214
|
}
|
|
200
215
|
});
|
|
201
216
|
}
|
|
202
|
-
|
|
217
|
+
doesWalletExist() {
|
|
203
218
|
if (!this._connected || this._connecting || !this._wallet)
|
|
204
219
|
throw new WalletNotConnectedError().name;
|
|
205
220
|
if (!(this._wallet.readyState === "Loadable" /* Loadable */ || this._wallet.readyState === "Installed" /* Installed */))
|
|
@@ -287,7 +302,7 @@ var WalletCore = class extends import_eventemitter3.default {
|
|
|
287
302
|
async disconnect() {
|
|
288
303
|
var _a;
|
|
289
304
|
try {
|
|
290
|
-
this.
|
|
305
|
+
this.doesWalletExist();
|
|
291
306
|
await ((_a = this._wallet) == null ? void 0 : _a.disconnect());
|
|
292
307
|
this.clearData();
|
|
293
308
|
this.emit("disconnect");
|
|
@@ -298,7 +313,7 @@ var WalletCore = class extends import_eventemitter3.default {
|
|
|
298
313
|
async signAndSubmitTransaction(transaction) {
|
|
299
314
|
var _a;
|
|
300
315
|
try {
|
|
301
|
-
this.
|
|
316
|
+
this.doesWalletExist();
|
|
302
317
|
const response = await ((_a = this._wallet) == null ? void 0 : _a.signAndSubmitTransaction(
|
|
303
318
|
transaction
|
|
304
319
|
));
|
|
@@ -309,10 +324,14 @@ var WalletCore = class extends import_eventemitter3.default {
|
|
|
309
324
|
}
|
|
310
325
|
}
|
|
311
326
|
async signTransaction(transaction) {
|
|
327
|
+
var _a;
|
|
328
|
+
if (this._wallet && !("signTransaction" in this._wallet)) {
|
|
329
|
+
throw new WalletNotSupportedMethod(
|
|
330
|
+
`Sign Transaction is not supported by ${(_a = this.wallet) == null ? void 0 : _a.name}`
|
|
331
|
+
).message;
|
|
332
|
+
}
|
|
312
333
|
try {
|
|
313
|
-
|
|
314
|
-
return null;
|
|
315
|
-
this.isWalletExists();
|
|
334
|
+
this.doesWalletExist();
|
|
316
335
|
const response = await this._wallet.signTransaction(transaction);
|
|
317
336
|
return response;
|
|
318
337
|
} catch (error) {
|
|
@@ -323,7 +342,7 @@ var WalletCore = class extends import_eventemitter3.default {
|
|
|
323
342
|
async signMessage(message) {
|
|
324
343
|
var _a;
|
|
325
344
|
try {
|
|
326
|
-
this.
|
|
345
|
+
this.doesWalletExist();
|
|
327
346
|
if (!this._wallet)
|
|
328
347
|
return null;
|
|
329
348
|
const response = await ((_a = this._wallet) == null ? void 0 : _a.signMessage(message));
|
|
@@ -336,7 +355,7 @@ var WalletCore = class extends import_eventemitter3.default {
|
|
|
336
355
|
async onAccountChange() {
|
|
337
356
|
var _a;
|
|
338
357
|
try {
|
|
339
|
-
this.
|
|
358
|
+
this.doesWalletExist();
|
|
340
359
|
await ((_a = this._wallet) == null ? void 0 : _a.onAccountChange((data) => {
|
|
341
360
|
this.setAccount({ ...data });
|
|
342
361
|
this.emit("accountChange", this._account);
|
|
@@ -349,7 +368,7 @@ var WalletCore = class extends import_eventemitter3.default {
|
|
|
349
368
|
async onNetworkChange() {
|
|
350
369
|
var _a;
|
|
351
370
|
try {
|
|
352
|
-
this.
|
|
371
|
+
this.doesWalletExist();
|
|
353
372
|
await ((_a = this._wallet) == null ? void 0 : _a.onNetworkChange((data) => {
|
|
354
373
|
this.setNetwork({ ...data });
|
|
355
374
|
this.emit("networkChange", this._network);
|
|
@@ -359,6 +378,34 @@ var WalletCore = class extends import_eventemitter3.default {
|
|
|
359
378
|
throw new WalletNetworkChangeError(errMsg).message;
|
|
360
379
|
}
|
|
361
380
|
}
|
|
381
|
+
async signMessageAndVerify(message) {
|
|
382
|
+
var _a;
|
|
383
|
+
try {
|
|
384
|
+
this.doesWalletExist();
|
|
385
|
+
if (!this._account)
|
|
386
|
+
throw new Error("No account found!");
|
|
387
|
+
const response = await ((_a = this._wallet) == null ? void 0 : _a.signMessage(message));
|
|
388
|
+
if (!response)
|
|
389
|
+
throw new WalletSignMessageAndVerifyError("Failed to sign a message").message;
|
|
390
|
+
let verified = false;
|
|
391
|
+
if (Array.isArray(response.signature)) {
|
|
392
|
+
} else {
|
|
393
|
+
const currentAccountPublicKey = new import_aptos.HexString(
|
|
394
|
+
this._account.publicKey
|
|
395
|
+
);
|
|
396
|
+
const signature = new import_aptos.HexString(response.signature);
|
|
397
|
+
verified = import_tweetnacl.sign.detached.verify(
|
|
398
|
+
import_buffer.Buffer.from(response.fullMessage),
|
|
399
|
+
import_buffer.Buffer.from(signature.noPrefix(), "hex"),
|
|
400
|
+
import_buffer.Buffer.from(currentAccountPublicKey.noPrefix(), "hex")
|
|
401
|
+
);
|
|
402
|
+
}
|
|
403
|
+
return verified;
|
|
404
|
+
} catch (error) {
|
|
405
|
+
const errMsg = typeof error == "object" && "message" in error ? error.message : error;
|
|
406
|
+
throw new WalletSignMessageAndVerifyError(errMsg).message;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
362
409
|
};
|
|
363
410
|
// Annotate the CommonJS export names for ESM import in node:
|
|
364
411
|
0 && (module.exports = {
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
// src/WalletCore.ts
|
|
2
|
+
import { HexString } from "aptos";
|
|
2
3
|
import EventEmitter from "eventemitter3";
|
|
4
|
+
import { sign } from "tweetnacl";
|
|
5
|
+
import { Buffer } from "buffer";
|
|
3
6
|
|
|
4
7
|
// src/constants.ts
|
|
5
8
|
var WalletReadyState = /* @__PURE__ */ ((WalletReadyState2) => {
|
|
@@ -83,6 +86,12 @@ var WalletSignMessageError = class extends WalletError {
|
|
|
83
86
|
this.name = "WalletSignMessageError";
|
|
84
87
|
}
|
|
85
88
|
};
|
|
89
|
+
var WalletSignMessageAndVerifyError = class extends WalletError {
|
|
90
|
+
constructor() {
|
|
91
|
+
super(...arguments);
|
|
92
|
+
this.name = "WalletSignMessageAndVerifyError";
|
|
93
|
+
}
|
|
94
|
+
};
|
|
86
95
|
var WalletSignAndSubmitMessageError = class extends WalletError {
|
|
87
96
|
constructor() {
|
|
88
97
|
super(...arguments);
|
|
@@ -95,6 +104,12 @@ var WalletSignTransactionError = class extends WalletError {
|
|
|
95
104
|
this.name = "WalletSignTransactionError";
|
|
96
105
|
}
|
|
97
106
|
};
|
|
107
|
+
var WalletNotSupportedMethod = class extends WalletError {
|
|
108
|
+
constructor() {
|
|
109
|
+
super(...arguments);
|
|
110
|
+
this.name = "WalletNotSupportedMethod";
|
|
111
|
+
}
|
|
112
|
+
};
|
|
98
113
|
|
|
99
114
|
// src/utils/scopePollingDetectionStrategy.ts
|
|
100
115
|
function scopePollingDetectionStrategy(detect) {
|
|
@@ -165,7 +180,7 @@ var WalletCore = class extends EventEmitter {
|
|
|
165
180
|
}
|
|
166
181
|
});
|
|
167
182
|
}
|
|
168
|
-
|
|
183
|
+
doesWalletExist() {
|
|
169
184
|
if (!this._connected || this._connecting || !this._wallet)
|
|
170
185
|
throw new WalletNotConnectedError().name;
|
|
171
186
|
if (!(this._wallet.readyState === "Loadable" /* Loadable */ || this._wallet.readyState === "Installed" /* Installed */))
|
|
@@ -253,7 +268,7 @@ var WalletCore = class extends EventEmitter {
|
|
|
253
268
|
async disconnect() {
|
|
254
269
|
var _a;
|
|
255
270
|
try {
|
|
256
|
-
this.
|
|
271
|
+
this.doesWalletExist();
|
|
257
272
|
await ((_a = this._wallet) == null ? void 0 : _a.disconnect());
|
|
258
273
|
this.clearData();
|
|
259
274
|
this.emit("disconnect");
|
|
@@ -264,7 +279,7 @@ var WalletCore = class extends EventEmitter {
|
|
|
264
279
|
async signAndSubmitTransaction(transaction) {
|
|
265
280
|
var _a;
|
|
266
281
|
try {
|
|
267
|
-
this.
|
|
282
|
+
this.doesWalletExist();
|
|
268
283
|
const response = await ((_a = this._wallet) == null ? void 0 : _a.signAndSubmitTransaction(
|
|
269
284
|
transaction
|
|
270
285
|
));
|
|
@@ -275,10 +290,14 @@ var WalletCore = class extends EventEmitter {
|
|
|
275
290
|
}
|
|
276
291
|
}
|
|
277
292
|
async signTransaction(transaction) {
|
|
293
|
+
var _a;
|
|
294
|
+
if (this._wallet && !("signTransaction" in this._wallet)) {
|
|
295
|
+
throw new WalletNotSupportedMethod(
|
|
296
|
+
`Sign Transaction is not supported by ${(_a = this.wallet) == null ? void 0 : _a.name}`
|
|
297
|
+
).message;
|
|
298
|
+
}
|
|
278
299
|
try {
|
|
279
|
-
|
|
280
|
-
return null;
|
|
281
|
-
this.isWalletExists();
|
|
300
|
+
this.doesWalletExist();
|
|
282
301
|
const response = await this._wallet.signTransaction(transaction);
|
|
283
302
|
return response;
|
|
284
303
|
} catch (error) {
|
|
@@ -289,7 +308,7 @@ var WalletCore = class extends EventEmitter {
|
|
|
289
308
|
async signMessage(message) {
|
|
290
309
|
var _a;
|
|
291
310
|
try {
|
|
292
|
-
this.
|
|
311
|
+
this.doesWalletExist();
|
|
293
312
|
if (!this._wallet)
|
|
294
313
|
return null;
|
|
295
314
|
const response = await ((_a = this._wallet) == null ? void 0 : _a.signMessage(message));
|
|
@@ -302,7 +321,7 @@ var WalletCore = class extends EventEmitter {
|
|
|
302
321
|
async onAccountChange() {
|
|
303
322
|
var _a;
|
|
304
323
|
try {
|
|
305
|
-
this.
|
|
324
|
+
this.doesWalletExist();
|
|
306
325
|
await ((_a = this._wallet) == null ? void 0 : _a.onAccountChange((data) => {
|
|
307
326
|
this.setAccount({ ...data });
|
|
308
327
|
this.emit("accountChange", this._account);
|
|
@@ -315,7 +334,7 @@ var WalletCore = class extends EventEmitter {
|
|
|
315
334
|
async onNetworkChange() {
|
|
316
335
|
var _a;
|
|
317
336
|
try {
|
|
318
|
-
this.
|
|
337
|
+
this.doesWalletExist();
|
|
319
338
|
await ((_a = this._wallet) == null ? void 0 : _a.onNetworkChange((data) => {
|
|
320
339
|
this.setNetwork({ ...data });
|
|
321
340
|
this.emit("networkChange", this._network);
|
|
@@ -325,6 +344,34 @@ var WalletCore = class extends EventEmitter {
|
|
|
325
344
|
throw new WalletNetworkChangeError(errMsg).message;
|
|
326
345
|
}
|
|
327
346
|
}
|
|
347
|
+
async signMessageAndVerify(message) {
|
|
348
|
+
var _a;
|
|
349
|
+
try {
|
|
350
|
+
this.doesWalletExist();
|
|
351
|
+
if (!this._account)
|
|
352
|
+
throw new Error("No account found!");
|
|
353
|
+
const response = await ((_a = this._wallet) == null ? void 0 : _a.signMessage(message));
|
|
354
|
+
if (!response)
|
|
355
|
+
throw new WalletSignMessageAndVerifyError("Failed to sign a message").message;
|
|
356
|
+
let verified = false;
|
|
357
|
+
if (Array.isArray(response.signature)) {
|
|
358
|
+
} else {
|
|
359
|
+
const currentAccountPublicKey = new HexString(
|
|
360
|
+
this._account.publicKey
|
|
361
|
+
);
|
|
362
|
+
const signature = new HexString(response.signature);
|
|
363
|
+
verified = sign.detached.verify(
|
|
364
|
+
Buffer.from(response.fullMessage),
|
|
365
|
+
Buffer.from(signature.noPrefix(), "hex"),
|
|
366
|
+
Buffer.from(currentAccountPublicKey.noPrefix(), "hex")
|
|
367
|
+
);
|
|
368
|
+
}
|
|
369
|
+
return verified;
|
|
370
|
+
} catch (error) {
|
|
371
|
+
const errMsg = typeof error == "object" && "message" in error ? error.message : error;
|
|
372
|
+
throw new WalletSignMessageAndVerifyError(errMsg).message;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
328
375
|
};
|
|
329
376
|
export {
|
|
330
377
|
NetworkName,
|
package/jest.config.js
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aptos-labs/wallet-adapter-core",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Aptos Wallet Adapter Core",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -27,21 +27,27 @@
|
|
|
27
27
|
"Wallet Adapter",
|
|
28
28
|
"Aptos Wallet"
|
|
29
29
|
],
|
|
30
|
-
"scripts": {
|
|
31
|
-
"build": "tsup src/index.ts --format esm,cjs --dts",
|
|
32
|
-
"dev": "tsup src/index.ts --format esm,cjs --watch --dts",
|
|
33
|
-
"lint": "TIMING=1 eslint \"src/**/*.ts*\"",
|
|
34
|
-
"clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist"
|
|
35
|
-
},
|
|
36
30
|
"devDependencies": {
|
|
37
|
-
"@
|
|
31
|
+
"@types/jest": "^29.2.4",
|
|
38
32
|
"eslint": "^8.15.0",
|
|
39
|
-
"
|
|
33
|
+
"jest": "^29.3.1",
|
|
34
|
+
"ts-jest": "^29.0.3",
|
|
40
35
|
"tsup": "^5.10.1",
|
|
41
|
-
"typescript": "^4.5.3"
|
|
36
|
+
"typescript": "^4.5.3",
|
|
37
|
+
"@aptos-labs/eslint-config-adapter": "0.0.0",
|
|
38
|
+
"@aptos-labs/wallet-adapter-tsconfig": "0.0.0"
|
|
42
39
|
},
|
|
43
40
|
"dependencies": {
|
|
44
41
|
"aptos": "^1.3.17",
|
|
45
|
-
"
|
|
42
|
+
"buffer": "^6.0.3",
|
|
43
|
+
"eventemitter3": "^4.0.7",
|
|
44
|
+
"tweetnacl": "^1.0.3"
|
|
45
|
+
},
|
|
46
|
+
"scripts": {
|
|
47
|
+
"build": "tsup src/index.ts --format esm,cjs --dts",
|
|
48
|
+
"dev": "tsup src/index.ts --format esm,cjs --watch --dts",
|
|
49
|
+
"test": "jest",
|
|
50
|
+
"lint": "TIMING=1 eslint \"src/**/*.ts*\"",
|
|
51
|
+
"clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist"
|
|
46
52
|
}
|
|
47
|
-
}
|
|
53
|
+
}
|
package/src/WalletCore.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import { Types } from "aptos";
|
|
1
|
+
import { HexString, Types } from "aptos";
|
|
2
2
|
import EventEmitter from "eventemitter3";
|
|
3
|
+
import { sign } from "tweetnacl";
|
|
4
|
+
import { Buffer } from "buffer";
|
|
3
5
|
|
|
4
6
|
import { WalletReadyState } from "./constants";
|
|
5
7
|
import {
|
|
@@ -12,7 +14,9 @@ import {
|
|
|
12
14
|
WalletNotConnectedError,
|
|
13
15
|
WalletNotReadyError,
|
|
14
16
|
WalletNotSelectedError,
|
|
17
|
+
WalletNotSupportedMethod,
|
|
15
18
|
WalletSignAndSubmitMessageError,
|
|
19
|
+
WalletSignMessageAndVerifyError,
|
|
16
20
|
WalletSignMessageError,
|
|
17
21
|
WalletSignTransactionError,
|
|
18
22
|
} from "./error";
|
|
@@ -67,7 +71,7 @@ export class WalletCore extends EventEmitter<WalletCoreEvents> {
|
|
|
67
71
|
});
|
|
68
72
|
}
|
|
69
73
|
|
|
70
|
-
private
|
|
74
|
+
private doesWalletExist(): boolean | WalletNotConnectedError {
|
|
71
75
|
if (!this._connected || this._connecting || !this._wallet)
|
|
72
76
|
throw new WalletNotConnectedError().name;
|
|
73
77
|
if (
|
|
@@ -197,7 +201,7 @@ export class WalletCore extends EventEmitter<WalletCoreEvents> {
|
|
|
197
201
|
*/
|
|
198
202
|
async disconnect(): Promise<void> {
|
|
199
203
|
try {
|
|
200
|
-
this.
|
|
204
|
+
this.doesWalletExist();
|
|
201
205
|
await this._wallet?.disconnect();
|
|
202
206
|
this.clearData();
|
|
203
207
|
this.emit("disconnect");
|
|
@@ -216,7 +220,7 @@ export class WalletCore extends EventEmitter<WalletCoreEvents> {
|
|
|
216
220
|
transaction: Types.TransactionPayload
|
|
217
221
|
): Promise<any> {
|
|
218
222
|
try {
|
|
219
|
-
this.
|
|
223
|
+
this.doesWalletExist();
|
|
220
224
|
const response = await this._wallet?.signAndSubmitTransaction(
|
|
221
225
|
transaction
|
|
222
226
|
);
|
|
@@ -237,9 +241,14 @@ export class WalletCore extends EventEmitter<WalletCoreEvents> {
|
|
|
237
241
|
async signTransaction(
|
|
238
242
|
transaction: Types.TransactionPayload
|
|
239
243
|
): Promise<Uint8Array | null> {
|
|
244
|
+
if (this._wallet && !("signTransaction" in this._wallet)) {
|
|
245
|
+
throw new WalletNotSupportedMethod(
|
|
246
|
+
`Sign Transaction is not supported by ${this.wallet?.name}`
|
|
247
|
+
).message;
|
|
248
|
+
}
|
|
249
|
+
|
|
240
250
|
try {
|
|
241
|
-
|
|
242
|
-
this.isWalletExists();
|
|
251
|
+
this.doesWalletExist();
|
|
243
252
|
const response = await (this._wallet as any).signTransaction(transaction);
|
|
244
253
|
return response;
|
|
245
254
|
} catch (error: any) {
|
|
@@ -259,7 +268,7 @@ export class WalletCore extends EventEmitter<WalletCoreEvents> {
|
|
|
259
268
|
message: SignMessagePayload
|
|
260
269
|
): Promise<SignMessageResponse | null> {
|
|
261
270
|
try {
|
|
262
|
-
this.
|
|
271
|
+
this.doesWalletExist();
|
|
263
272
|
if (!this._wallet) return null;
|
|
264
273
|
const response = await this._wallet?.signMessage(message);
|
|
265
274
|
return response;
|
|
@@ -277,7 +286,7 @@ export class WalletCore extends EventEmitter<WalletCoreEvents> {
|
|
|
277
286
|
*/
|
|
278
287
|
async onAccountChange(): Promise<void> {
|
|
279
288
|
try {
|
|
280
|
-
this.
|
|
289
|
+
this.doesWalletExist();
|
|
281
290
|
await this._wallet?.onAccountChange((data: AccountInfo) => {
|
|
282
291
|
this.setAccount({ ...data });
|
|
283
292
|
this.emit("accountChange", this._account);
|
|
@@ -296,7 +305,7 @@ export class WalletCore extends EventEmitter<WalletCoreEvents> {
|
|
|
296
305
|
*/
|
|
297
306
|
async onNetworkChange(): Promise<void> {
|
|
298
307
|
try {
|
|
299
|
-
this.
|
|
308
|
+
this.doesWalletExist();
|
|
300
309
|
await this._wallet?.onNetworkChange((data: NetworkInfo) => {
|
|
301
310
|
this.setNetwork({ ...data });
|
|
302
311
|
this.emit("networkChange", this._network);
|
|
@@ -307,4 +316,39 @@ export class WalletCore extends EventEmitter<WalletCoreEvents> {
|
|
|
307
316
|
throw new WalletNetworkChangeError(errMsg).message;
|
|
308
317
|
}
|
|
309
318
|
}
|
|
319
|
+
|
|
320
|
+
async signMessageAndVerify(message: SignMessagePayload): Promise<boolean> {
|
|
321
|
+
try {
|
|
322
|
+
this.doesWalletExist();
|
|
323
|
+
if (!this._account) throw new Error("No account found!");
|
|
324
|
+
const response = await this._wallet?.signMessage(message);
|
|
325
|
+
if (!response)
|
|
326
|
+
throw new WalletSignMessageAndVerifyError("Failed to sign a message")
|
|
327
|
+
.message;
|
|
328
|
+
// Verify that the bytes were signed using the private key that matches the known public key
|
|
329
|
+
let verified = false;
|
|
330
|
+
if (Array.isArray(response.signature)) {
|
|
331
|
+
// multi sig wallets
|
|
332
|
+
// TODO - implement multi sig wallets
|
|
333
|
+
} else {
|
|
334
|
+
// single sig wallets
|
|
335
|
+
// support for when address doesnt have hex prefix (0x)
|
|
336
|
+
const currentAccountPublicKey = new HexString(
|
|
337
|
+
this._account.publicKey as string
|
|
338
|
+
);
|
|
339
|
+
// support for when address doesnt have hex prefix (0x)
|
|
340
|
+
const signature = new HexString(response.signature);
|
|
341
|
+
verified = sign.detached.verify(
|
|
342
|
+
Buffer.from(response.fullMessage),
|
|
343
|
+
Buffer.from(signature.noPrefix(), "hex"),
|
|
344
|
+
Buffer.from(currentAccountPublicKey.noPrefix(), "hex")
|
|
345
|
+
);
|
|
346
|
+
}
|
|
347
|
+
return verified;
|
|
348
|
+
} catch (error: any) {
|
|
349
|
+
const errMsg =
|
|
350
|
+
typeof error == "object" && "message" in error ? error.message : error;
|
|
351
|
+
throw new WalletSignMessageAndVerifyError(errMsg).message;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
310
354
|
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { AptosAccount } from "aptos";
|
|
2
|
+
import {
|
|
3
|
+
SignMessagePayload,
|
|
4
|
+
SignMessageResponse,
|
|
5
|
+
Wallet,
|
|
6
|
+
WalletName,
|
|
7
|
+
} from "../types";
|
|
8
|
+
import { WalletCore } from "../WalletCore";
|
|
9
|
+
|
|
10
|
+
const signMessageResponseMock: SignMessageResponse = {
|
|
11
|
+
fullMessage: "",
|
|
12
|
+
message: "message",
|
|
13
|
+
nonce: Date.now().toString(),
|
|
14
|
+
prefix: "APTOS",
|
|
15
|
+
signature: "",
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const mockSignMessagePayload: SignMessagePayload = {
|
|
19
|
+
message: "my-message",
|
|
20
|
+
nonce: Date.now().toString(),
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const connectMock = jest.fn(() => Promise.resolve(console.log("connect")));
|
|
24
|
+
const disconnectMock = jest.fn(() =>
|
|
25
|
+
Promise.resolve(console.log("disconnect"))
|
|
26
|
+
);
|
|
27
|
+
const networkMock = jest.fn(() => Promise.resolve(console.log("network")));
|
|
28
|
+
const signAndSubmitTransactionkMock = jest.fn((transaction, options?) =>
|
|
29
|
+
Promise.resolve({ hash: "signAndSubmitTransactionkMock" })
|
|
30
|
+
);
|
|
31
|
+
const signMessageMock = jest.fn((message) =>
|
|
32
|
+
Promise.resolve(signMessageResponseMock)
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
const onNetworkChangeeMock = jest.fn((callback: any) =>
|
|
36
|
+
Promise.resolve(console.log("onNetworkChange"))
|
|
37
|
+
);
|
|
38
|
+
const onAccountChangeMock = jest.fn((callback: any) =>
|
|
39
|
+
Promise.resolve(console.log("onAccountChangeMock"))
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
const walletMock: Wallet = {
|
|
43
|
+
name: "wallet-name" as WalletName<"wallet-name">,
|
|
44
|
+
url: "my-url",
|
|
45
|
+
icon: `data:image/png;base64,uri`,
|
|
46
|
+
provider: {},
|
|
47
|
+
connect: connectMock,
|
|
48
|
+
disconnect: disconnectMock,
|
|
49
|
+
network: networkMock,
|
|
50
|
+
signAndSubmitTransaction: signAndSubmitTransactionkMock,
|
|
51
|
+
signMessage: signMessageMock,
|
|
52
|
+
onNetworkChange: onNetworkChangeeMock,
|
|
53
|
+
onAccountChange: onAccountChangeMock,
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const pluginsMock: Wallet[] = [walletMock];
|
|
57
|
+
|
|
58
|
+
const walletCoreMock = new WalletCore(pluginsMock);
|
|
59
|
+
|
|
60
|
+
describe("signMessageAndVerify", () => {
|
|
61
|
+
walletCoreMock.setWallet(walletMock);
|
|
62
|
+
const account = new AptosAccount();
|
|
63
|
+
walletCoreMock.setAccount({
|
|
64
|
+
address: account.address().hex(),
|
|
65
|
+
publicKey: account.pubKey().hex(),
|
|
66
|
+
});
|
|
67
|
+
signMessageResponseMock.fullMessage = `\nmessage: ${signMessageResponseMock.message} \nnonce: ${signMessageResponseMock.nonce}`;
|
|
68
|
+
jest
|
|
69
|
+
.spyOn(walletCoreMock as any, "doesWalletExist")
|
|
70
|
+
.mockImplementation(() => true);
|
|
71
|
+
|
|
72
|
+
it("it should verify a signed message", async () => {
|
|
73
|
+
const encoder = new TextEncoder();
|
|
74
|
+
const messageBytes = encoder.encode(signMessageResponseMock.fullMessage);
|
|
75
|
+
const signature = account.signBuffer(messageBytes);
|
|
76
|
+
const signatureString = signature.noPrefix();
|
|
77
|
+
signMessageResponseMock.signature = signatureString;
|
|
78
|
+
|
|
79
|
+
jest
|
|
80
|
+
.spyOn((walletCoreMock as any)._wallet, "signMessage")
|
|
81
|
+
.mockResolvedValue(signMessageResponseMock);
|
|
82
|
+
|
|
83
|
+
const verified = await walletCoreMock.signMessageAndVerify(
|
|
84
|
+
mockSignMessagePayload
|
|
85
|
+
);
|
|
86
|
+
expect(verified).toBeTruthy();
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it("it should fails to verify signed message", async () => {
|
|
90
|
+
const account2 = new AptosAccount();
|
|
91
|
+
const encoder = new TextEncoder();
|
|
92
|
+
const messageBytes = encoder.encode(signMessageResponseMock.fullMessage);
|
|
93
|
+
const signature = account2.signBuffer(messageBytes);
|
|
94
|
+
const signatureString = signature.noPrefix();
|
|
95
|
+
signMessageResponseMock.signature = signatureString;
|
|
96
|
+
|
|
97
|
+
jest
|
|
98
|
+
.spyOn((walletCoreMock as any)._wallet, "signMessage")
|
|
99
|
+
.mockResolvedValue(signMessageResponseMock);
|
|
100
|
+
|
|
101
|
+
const verified = await walletCoreMock.signMessageAndVerify(
|
|
102
|
+
mockSignMessagePayload
|
|
103
|
+
);
|
|
104
|
+
expect(verified).toBeFalsy();
|
|
105
|
+
});
|
|
106
|
+
});
|
package/src/error/index.ts
CHANGED
|
@@ -71,6 +71,10 @@ export class WalletSignMessageError extends WalletError {
|
|
|
71
71
|
name = "WalletSignMessageError";
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
+
export class WalletSignMessageAndVerifyError extends WalletError {
|
|
75
|
+
name = "WalletSignMessageAndVerifyError";
|
|
76
|
+
}
|
|
77
|
+
|
|
74
78
|
export class WalletSignAndSubmitMessageError extends WalletError {
|
|
75
79
|
name = "WalletSignAndSubmitMessageError";
|
|
76
80
|
}
|
|
@@ -94,3 +98,7 @@ export class WalletWindowClosedError extends WalletError {
|
|
|
94
98
|
export class WalletResponseError extends WalletError {
|
|
95
99
|
name = "WalletResponseError";
|
|
96
100
|
}
|
|
101
|
+
|
|
102
|
+
export class WalletNotSupportedMethod extends WalletError {
|
|
103
|
+
name = "WalletNotSupportedMethod";
|
|
104
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -6,12 +6,15 @@ export type WalletName<T extends string = string> = T & {
|
|
|
6
6
|
__brand__: "WalletName";
|
|
7
7
|
};
|
|
8
8
|
export type NetworkInfo = {
|
|
9
|
-
name: NetworkName
|
|
9
|
+
name: NetworkName;
|
|
10
|
+
chainId?: string;
|
|
11
|
+
url?: string;
|
|
10
12
|
};
|
|
11
13
|
|
|
12
14
|
export type AccountInfo = {
|
|
13
15
|
address: string;
|
|
14
|
-
publicKey: string;
|
|
16
|
+
publicKey: string | string[];
|
|
17
|
+
minKeysRequired?: number
|
|
15
18
|
};
|
|
16
19
|
|
|
17
20
|
export interface AptosWalletErrorResult {
|
|
@@ -90,12 +93,13 @@ export interface SignMessagePayload {
|
|
|
90
93
|
}
|
|
91
94
|
|
|
92
95
|
export interface SignMessageResponse {
|
|
93
|
-
address
|
|
94
|
-
application
|
|
95
|
-
chainId
|
|
96
|
+
address?: string;
|
|
97
|
+
application?: string;
|
|
98
|
+
chainId?: number;
|
|
96
99
|
fullMessage: string; // The message that was generated to sign
|
|
97
100
|
message: string; // The message passed in by the user
|
|
98
101
|
nonce: string;
|
|
99
102
|
prefix: "APTOS"; // Should always be APTOS
|
|
100
|
-
signature: string; // The signed full message
|
|
103
|
+
signature: string | string[]; // The signed full message
|
|
104
|
+
bitmap?: Uint8Array; // a 4-byte (32 bits) bit-vector of length N
|
|
101
105
|
}
|