@aptos-labs/wallet-adapter-core 2.5.1 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/WalletCore.ts CHANGED
@@ -1,4 +1,18 @@
1
- import { HexString, TxnBuilderTypes, Types } from "aptos";
1
+ import { HexString, TxnBuilderTypes, Types, BCS } from "aptos";
2
+ import {
3
+ InputGenerateTransactionData,
4
+ AnyRawTransaction,
5
+ AccountAuthenticator,
6
+ AccountAuthenticatorEd25519,
7
+ Ed25519PublicKey,
8
+ InputGenerateTransactionOptions,
9
+ Ed25519Signature,
10
+ AptosConfig,
11
+ generateTransactionPayload,
12
+ InputSubmitTransactionData,
13
+ PendingTransactionResponse,
14
+ InputEntryFunctionDataWithRemoteABI,
15
+ } from "@aptos-labs/ts-sdk";
2
16
  import EventEmitter from "eventemitter3";
3
17
  import nacl from "tweetnacl";
4
18
  import { Buffer } from "buffer";
@@ -23,27 +37,33 @@ import {
23
37
  import {
24
38
  AccountInfo,
25
39
  NetworkInfo,
26
- WalletName,
27
40
  SignMessagePayload,
28
- SignMessageResponse,
29
41
  Wallet,
30
42
  WalletInfo,
31
43
  WalletCoreEvents,
32
- TransactionOptions,
44
+ SignMessageResponse,
33
45
  } from "./types";
34
46
  import {
35
47
  removeLocalStorage,
36
48
  setLocalStorage,
37
49
  scopePollingDetectionStrategy,
38
50
  isRedirectable,
51
+ generalizedErrorMessage,
39
52
  } from "./utils";
40
53
  import { getNameByAddress } from "./ans";
54
+ import {
55
+ convertNetwork,
56
+ convertV2TransactionPayloadToV1BCSPayload,
57
+ convertV2PayloadToV1JSONPayload,
58
+ } from "./conversion";
59
+ import { WalletCoreV1 } from "./WalletCoreV1";
41
60
 
42
61
  export class WalletCore extends EventEmitter<WalletCoreEvents> {
43
62
  private _wallets: ReadonlyArray<Wallet> = [];
44
63
  private _wallet: Wallet | null = null;
45
64
  private _account: AccountInfo | null = null;
46
65
  private _network: NetworkInfo | null = null;
66
+ private readonly waletCoreV1: WalletCoreV1 = new WalletCoreV1();
47
67
 
48
68
  private _connecting: boolean = false;
49
69
  private _connected: boolean = false;
@@ -177,7 +197,7 @@ export class WalletCore extends EventEmitter<WalletCoreEvents> {
177
197
  * If all good, we connect the wallet by calling `this.connectWallet`
178
198
  * @param walletName. The wallet name we want to connect.
179
199
  */
180
- async connect(walletName: WalletName): Promise<void | string> {
200
+ async connect(walletName: string): Promise<void | string> {
181
201
  const selectedWallet = this._wallets?.find(
182
202
  (wallet: Wallet) => wallet.name === walletName
183
203
  );
@@ -236,16 +256,16 @@ export class WalletCore extends EventEmitter<WalletCoreEvents> {
236
256
  this.emit("connect", account);
237
257
  } catch (error: any) {
238
258
  this.clearData();
239
- const errMsg =
240
- typeof error == "object" && "message" in error ? error.message : error;
259
+
260
+ const errMsg = generalizedErrorMessage(error);
241
261
  throw new WalletConnectionError(errMsg).message;
242
262
  } finally {
243
263
  this._connecting = false;
244
264
  }
245
265
  }
246
266
 
247
- /**
248
- Disconnect the exisitng wallet. On success, we clear the
267
+ /**
268
+ Disconnect the exisitng wallet. On success, we clear the
249
269
  current account, current network and LocalStorage data.
250
270
  @emit emits "disconnect" event
251
271
  @throws WalletDisconnectionError
@@ -257,121 +277,207 @@ export class WalletCore extends EventEmitter<WalletCoreEvents> {
257
277
  this.clearData();
258
278
  this.emit("disconnect");
259
279
  } catch (error: any) {
260
- const errMsg =
261
- typeof error == "object" && "message" in error ? error.message : error;
280
+ const errMsg = generalizedErrorMessage(error);
262
281
  throw new WalletDisconnectionError(errMsg).message;
263
282
  }
264
283
  }
265
284
 
266
- /**
267
- Sign and submit an entry (not bcs serialized) transaction type to chain.
268
- @param transaction a non-bcs serialized transaction
269
- @param options max_gas_amount and gas_unit_limit
270
- @return response from the wallet's signAndSubmitTransaction function
271
- @throws WalletSignAndSubmitMessageError
272
- */
285
+ /**
286
+ * Signs and submits a transaction to chain
287
+ *
288
+ * @param transactionInput InputGenerateTransactionData
289
+ * @param options optional. A configuration object to generate a transaction by
290
+ * @returns The pending transaction hash (V1 output) | PendingTransactionResponse (V2 output)
291
+ */
273
292
  async signAndSubmitTransaction(
274
- transaction: Types.TransactionPayload,
275
- options?: TransactionOptions
276
- ): Promise<any> {
293
+ transactionInput: InputGenerateTransactionData,
294
+ options?: InputGenerateTransactionOptions
295
+ ): Promise<
296
+ { hash: Types.HexEncodedBytes; output?: any } | PendingTransactionResponse
297
+ > {
277
298
  try {
278
299
  this.doesWalletExist();
279
- const response = await this._wallet?.signAndSubmitTransaction(
280
- transaction,
281
- options
300
+
301
+ // wallet supports sdk v2
302
+ if (this._wallet?.version === "v2") {
303
+ const response = await this._wallet.signAndSubmitTransaction(
304
+ transactionInput,
305
+ options
306
+ );
307
+ // response should be PendingTransactionResponse
308
+ return response;
309
+ }
310
+
311
+ // get the payload piece from the input
312
+ const payloadData = transactionInput.data;
313
+
314
+ // if first function arguments is an object (i.e a bcs serialized argument)
315
+ // we assume the transaction should be a bcs serialized transaction
316
+ if (typeof payloadData.functionArguments[0] === "object") {
317
+ const aptosConfig = new AptosConfig({
318
+ network: convertNetwork(this._network),
319
+ });
320
+ const newPayload = await generateTransactionPayload({
321
+ ...(payloadData as InputEntryFunctionDataWithRemoteABI),
322
+ aptosConfig: aptosConfig,
323
+ });
324
+ const oldTransactionPayload =
325
+ convertV2TransactionPayloadToV1BCSPayload(newPayload);
326
+ const response = await this.waletCoreV1.signAndSubmitBCSTransaction(
327
+ oldTransactionPayload,
328
+ this._wallet!,
329
+ {
330
+ max_gas_amount: options?.maxGasAmount
331
+ ? BigInt(options?.maxGasAmount)
332
+ : undefined,
333
+ gas_unit_price: options?.gasUnitPrice
334
+ ? BigInt(options?.gasUnitPrice)
335
+ : undefined,
336
+ }
337
+ );
338
+ const { hash, ...output } = response;
339
+ return { hash, output };
340
+ }
341
+
342
+ // if it is not a bcs serialized arguments transaction, convert to the old
343
+ // json format
344
+ const oldTransactionPayload =
345
+ convertV2PayloadToV1JSONPayload(payloadData);
346
+ const response = await this.waletCoreV1.signAndSubmitTransaction(
347
+ oldTransactionPayload,
348
+ this._wallet!,
349
+ {
350
+ max_gas_amount: options?.maxGasAmount
351
+ ? BigInt(options?.maxGasAmount)
352
+ : undefined,
353
+ gas_unit_price: options?.gasUnitPrice
354
+ ? BigInt(options?.gasUnitPrice)
355
+ : undefined,
356
+ }
282
357
  );
283
- return response;
358
+ const { hash, ...output } = response;
359
+ return { hash, output };
284
360
  } catch (error: any) {
285
- const errMsg =
286
- typeof error == "object" && "message" in error ? error.message : error;
361
+ const errMsg = generalizedErrorMessage(error);
287
362
  throw new WalletSignAndSubmitMessageError(errMsg).message;
288
363
  }
289
364
  }
290
365
 
291
- /**
292
- Sign and submit a bsc serialized transaction type to chain.
293
- @param transaction a bcs serialized transaction
294
- @param options max_gas_amount and gas_unit_limit
295
- @return response from the wallet's signAndSubmitBCSTransaction function
296
- @throws WalletSignAndSubmitMessageError
297
- */
298
- async signAndSubmitBCSTransaction(
299
- transaction: TxnBuilderTypes.TransactionPayload,
300
- options?: TransactionOptions
301
- ): Promise<any> {
302
- if (this._wallet && !("signAndSubmitBCSTransaction" in this._wallet)) {
303
- throw new WalletNotSupportedMethod(
304
- `Submit a BCS Transaction is not supported by ${this.wallet?.name}`
305
- ).message;
306
- }
307
-
366
+ /**
367
+ * Signs a transaction
368
+ *
369
+ * To support both existing wallet adapter V1 and V2, we support 2 input types
370
+ *
371
+ * @param transactionOrPayload AnyRawTransaction - V2 input | Types.TransactionPayload - V1 input
372
+ * @param options optional. V1 input
373
+ *
374
+ * @returns AccountAuthenticator
375
+ */
376
+ async signTransaction(
377
+ transactionOrPayload: AnyRawTransaction | Types.TransactionPayload,
378
+ asFeePayer?: boolean,
379
+ options?: InputGenerateTransactionOptions
380
+ ): Promise<AccountAuthenticator> {
308
381
  try {
309
382
  this.doesWalletExist();
310
- const response = await (this._wallet as any).signAndSubmitBCSTransaction(
311
- transaction,
312
- options
383
+ // if input is AnyRawTransaction, i.e V2
384
+ if ("rawTransaction" in transactionOrPayload) {
385
+ if (this._wallet?.version !== "v2") {
386
+ throw new WalletNotSupportedMethod(
387
+ `Sign Transaction V2 is not supported by ${this.wallet?.name}`
388
+ ).message;
389
+ }
390
+ const accountAuthenticator = (this._wallet as any).signTransaction(
391
+ transactionOrPayload,
392
+ asFeePayer
393
+ );
394
+
395
+ return accountAuthenticator;
396
+ }
397
+
398
+ // check current signTransaction function exists
399
+ if (this._wallet && !("signTransaction" in this._wallet)) {
400
+ throw new WalletNotSupportedMethod(
401
+ `Sign Transaction is not supported by ${this.wallet?.name}`
402
+ ).message;
403
+ }
404
+
405
+ const response = await this.waletCoreV1.signTransaction(
406
+ transactionOrPayload as Types.TransactionPayload,
407
+ this._wallet!,
408
+ {
409
+ max_gas_amount: options?.maxGasAmount
410
+ ? BigInt(options?.maxGasAmount)
411
+ : undefined,
412
+ gas_unit_price: options?.gasUnitPrice
413
+ ? BigInt(options?.gasUnitPrice)
414
+ : undefined,
415
+ }
313
416
  );
314
- return response;
417
+ if (!response) {
418
+ throw new Error("error");
419
+ }
420
+
421
+ // Convert retuned bcs serialized SignedTransaction into V2 AccountAuthenticator
422
+ const deserializer1 = new BCS.Deserializer(response);
423
+ const deserializedSignature =
424
+ TxnBuilderTypes.SignedTransaction.deserialize(deserializer1);
425
+ const transactionAuthenticator =
426
+ deserializedSignature.authenticator as TxnBuilderTypes.TransactionAuthenticatorEd25519;
427
+
428
+ const publicKey = transactionAuthenticator.public_key.value;
429
+ const signature = transactionAuthenticator.signature.value;
430
+
431
+ const accountAuthenticator = new AccountAuthenticatorEd25519(
432
+ new Ed25519PublicKey(publicKey),
433
+ new Ed25519Signature(signature)
434
+ );
435
+ return accountAuthenticator;
315
436
  } catch (error: any) {
316
- const errMsg =
317
- typeof error == "object" && "message" in error ? error.message : error;
318
- throw new WalletSignAndSubmitMessageError(errMsg).message;
437
+ const errMsg = generalizedErrorMessage(error);
438
+ throw new WalletSignTransactionError(errMsg).message;
319
439
  }
320
440
  }
321
441
 
322
- /**
323
- Sign transaction (doesnt submit to chain).
324
- @param transaction
325
- @param options max_gas_amount and gas_unit_limit
326
- @return response from the wallet's signTransaction function
327
- @throws WalletSignTransactionError
328
- */
329
- async signTransaction(
330
- transaction: Types.TransactionPayload,
331
- options?: TransactionOptions
332
- ): Promise<Uint8Array | null> {
333
- if (this._wallet && !("signTransaction" in this._wallet)) {
334
- throw new WalletNotSupportedMethod(
335
- `Sign Transaction is not supported by ${this.wallet?.name}`
336
- ).message;
337
- }
338
-
442
+ /**
443
+ Sign message (doesnt submit to chain).
444
+ @param message
445
+ @return response from the wallet's signMessage function
446
+ @throws WalletSignMessageError
447
+ */
448
+ async signMessage(message: SignMessagePayload): Promise<SignMessageResponse> {
339
449
  try {
340
450
  this.doesWalletExist();
341
- const response = await (this._wallet as any).signTransaction(
342
- transaction,
343
- options
344
- );
451
+ const response = await this._wallet!.signMessage(message);
345
452
  return response;
346
453
  } catch (error: any) {
347
- const errMsg =
348
- typeof error == "object" && "message" in error ? error.message : error;
349
- throw new WalletSignTransactionError(errMsg).message;
454
+ const errMsg = generalizedErrorMessage(error);
455
+ throw new WalletSignMessageError(errMsg).message;
350
456
  }
351
457
  }
352
458
 
353
- /**
354
- Sign message (doesnt submit to chain).
355
- @param message
356
- @return response from the wallet's signMessage function
357
- @throws WalletSignMessageError
358
- */
359
- async signMessage(
360
- message: SignMessagePayload
361
- ): Promise<SignMessageResponse | null> {
459
+ async submitTransaction(
460
+ transaction: InputSubmitTransactionData
461
+ ): Promise<PendingTransactionResponse> {
462
+ if (this._wallet && !("submitTransaction" in this._wallet)) {
463
+ throw new WalletNotSupportedMethod(
464
+ `Submit Transaction is not supported by ${this.wallet?.name}`
465
+ ).message;
466
+ }
362
467
  try {
363
468
  this.doesWalletExist();
364
- if (!this._wallet) return null;
365
- const response = await this._wallet?.signMessage(message);
366
- return response;
469
+ const pendingTransaction = (this._wallet as any).submitTransaction(
470
+ transaction
471
+ );
472
+
473
+ return pendingTransaction;
367
474
  } catch (error: any) {
368
- const errMsg =
369
- typeof error == "object" && "message" in error ? error.message : error;
370
- throw new WalletSignMessageError(errMsg).message;
475
+ const errMsg = generalizedErrorMessage(error);
476
+ throw new WalletSignTransactionError(errMsg).message;
371
477
  }
372
478
  }
373
479
 
374
- /**
480
+ /**
375
481
  Event for when account has changed on the wallet
376
482
  @return the new account info
377
483
  @throws WalletAccountChangeError
@@ -385,13 +491,12 @@ export class WalletCore extends EventEmitter<WalletCoreEvents> {
385
491
  this.emit("accountChange", this._account);
386
492
  });
387
493
  } catch (error: any) {
388
- const errMsg =
389
- typeof error == "object" && "message" in error ? error.message : error;
494
+ const errMsg = generalizedErrorMessage(error);
390
495
  throw new WalletAccountChangeError(errMsg).message;
391
496
  }
392
497
  }
393
498
 
394
- /**
499
+ /**
395
500
  Event for when network has changed on the wallet
396
501
  @return the new network info
397
502
  @throws WalletNetworkChangeError
@@ -405,12 +510,16 @@ export class WalletCore extends EventEmitter<WalletCoreEvents> {
405
510
  this.emit("networkChange", this._network);
406
511
  });
407
512
  } catch (error: any) {
408
- const errMsg =
409
- typeof error == "object" && "message" in error ? error.message : error;
513
+ const errMsg = generalizedErrorMessage(error);
410
514
  throw new WalletNetworkChangeError(errMsg).message;
411
515
  }
412
516
  }
413
517
 
518
+ /**
519
+ * Signs a message and verifies the signer
520
+ * @param message SignMessagePayload
521
+ * @returns boolean
522
+ */
414
523
  async signMessageAndVerify(message: SignMessagePayload): Promise<boolean> {
415
524
  try {
416
525
  this.doesWalletExist();
@@ -475,8 +584,7 @@ export class WalletCore extends EventEmitter<WalletCoreEvents> {
475
584
  }
476
585
  return verified;
477
586
  } catch (error: any) {
478
- const errMsg =
479
- typeof error == "object" && "message" in error ? error.message : error;
587
+ const errMsg = generalizedErrorMessage(error);
480
588
  throw new WalletSignMessageAndVerifyError(errMsg).message;
481
589
  }
482
590
  }
@@ -0,0 +1,85 @@
1
+ import { TxnBuilderTypes, Types } from "aptos";
2
+ import EventEmitter from "eventemitter3";
3
+
4
+ import {
5
+ WalletSignAndSubmitMessageError,
6
+ WalletSignTransactionError,
7
+ } from "./error";
8
+ import { Wallet, WalletCoreEvents, TransactionOptions } from "./types";
9
+
10
+ export class WalletCoreV1 extends EventEmitter<WalletCoreEvents> {
11
+ /**
12
+ Sign and submit an entry (not bcs serialized) transaction type to chain.
13
+ @param transaction a non-bcs serialized transaction
14
+ @param options max_gas_amount and gas_unit_limit
15
+ @return response from the wallet's signAndSubmitTransaction function
16
+ @throws WalletSignAndSubmitMessageError
17
+ */
18
+ async signAndSubmitTransaction(
19
+ transaction: Types.TransactionPayload,
20
+ wallet: Wallet,
21
+ options?: TransactionOptions
22
+ ): Promise<any> {
23
+ try {
24
+ const response = await (wallet as any).signAndSubmitTransaction(
25
+ transaction,
26
+ options
27
+ );
28
+ return response;
29
+ } catch (error: any) {
30
+ const errMsg =
31
+ typeof error == "object" && "message" in error ? error.message : error;
32
+ throw new WalletSignAndSubmitMessageError(errMsg).message;
33
+ }
34
+ }
35
+
36
+ /**
37
+ Sign and submit a bsc serialized transaction type to chain.
38
+ @param transaction a bcs serialized transaction
39
+ @param options max_gas_amount and gas_unit_limit
40
+ @return response from the wallet's signAndSubmitBCSTransaction function
41
+ @throws WalletSignAndSubmitMessageError
42
+ */
43
+ async signAndSubmitBCSTransaction(
44
+ transaction: TxnBuilderTypes.TransactionPayload,
45
+ wallet: Wallet,
46
+ options?: TransactionOptions
47
+ ): Promise<any> {
48
+ try {
49
+ const response = await (wallet as any).signAndSubmitBCSTransaction(
50
+ transaction,
51
+ options
52
+ );
53
+ return response;
54
+ } catch (error: any) {
55
+ const errMsg =
56
+ typeof error == "object" && "message" in error ? error.message : error;
57
+ throw new WalletSignAndSubmitMessageError(errMsg).message;
58
+ }
59
+ }
60
+
61
+ /**
62
+ Sign transaction (doesnt submit to chain).
63
+ @param transaction
64
+ @param options max_gas_amount and gas_unit_limit
65
+ @return response from the wallet's signTransaction function
66
+ @throws WalletSignTransactionError
67
+ */
68
+ async signTransaction(
69
+ transaction: Types.TransactionPayload,
70
+ wallet: Wallet,
71
+ options?: TransactionOptions
72
+ ): Promise<Uint8Array | null> {
73
+ try {
74
+ const response = await (wallet as any).signTransaction(
75
+ transaction,
76
+ options
77
+ );
78
+ return response;
79
+ } catch (error: any) {
80
+ const errMsg =
81
+ typeof error == "object" && "message" in error ? error.message : error;
82
+ throw new WalletSignTransactionError(errMsg).message;
83
+ }
84
+ }
85
+ }
@@ -0,0 +1,57 @@
1
+ import {
2
+ Network,
3
+ TransactionPayload,
4
+ InputGenerateTransactionPayloadData,
5
+ TypeTag,
6
+ } from "@aptos-labs/ts-sdk";
7
+ import { BCS, TxnBuilderTypes, Types } from "aptos";
8
+ import { NetworkInfo } from "./types";
9
+
10
+ // old => new
11
+ export function convertNetwork(networkInfo: NetworkInfo | null): Network {
12
+ switch (networkInfo?.name.toLowerCase()) {
13
+ case "mainnet" as Network:
14
+ return Network.MAINNET;
15
+ case "testnet" as Network:
16
+ return Network.TESTNET;
17
+ case "devnet" as Network:
18
+ return Network.DEVNET;
19
+ default:
20
+ throw new Error("Invalid network name");
21
+ }
22
+ }
23
+
24
+ // new => old
25
+ export function convertV2TransactionPayloadToV1BCSPayload(
26
+ payload: TransactionPayload
27
+ ): TxnBuilderTypes.TransactionPayload {
28
+ const deserializer = new BCS.Deserializer(payload.bcsToBytes());
29
+ return TxnBuilderTypes.TransactionPayload.deserialize(deserializer);
30
+ }
31
+
32
+ export function convertV2PayloadToV1JSONPayload(
33
+ payload: InputGenerateTransactionPayloadData
34
+ ): Types.TransactionPayload {
35
+ if ("bytecode" in payload) {
36
+ // is a script payload
37
+ throw new Error("script payload not supported");
38
+ } else {
39
+ // is entry function payload
40
+ const stringTypeTags: string[] | undefined = payload.typeArguments?.map(
41
+ (typeTag) => {
42
+ if (typeTag instanceof TypeTag) {
43
+ return typeTag.toString();
44
+ }
45
+ return typeTag;
46
+ }
47
+ );
48
+ const newPayload: Types.TransactionPayload = {
49
+ type: "entry_function_payload",
50
+ function: payload.function,
51
+ type_arguments: stringTypeTags || [],
52
+ arguments: payload.functionArguments,
53
+ };
54
+
55
+ return newPayload;
56
+ }
57
+ }