@aptos-labs/wallet-adapter-core 2.6.0 → 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,5 +1,18 @@
1
- import { HexString, TxnBuilderTypes, Types } from "aptos";
2
- import { AptosConfig, InputGenerateTransactionData, generateTransactionPayload } from "@aptos-labs/ts-sdk";
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";
3
16
  import EventEmitter from "eventemitter3";
4
17
  import nacl from "tweetnacl";
5
18
  import { Buffer } from "buffer";
@@ -24,29 +37,33 @@ import {
24
37
  import {
25
38
  AccountInfo,
26
39
  NetworkInfo,
27
- WalletName,
28
40
  SignMessagePayload,
29
- SignMessageResponse,
30
41
  Wallet,
31
42
  WalletInfo,
32
43
  WalletCoreEvents,
33
- TransactionOptions,
44
+ SignMessageResponse,
34
45
  } from "./types";
35
46
  import {
36
47
  removeLocalStorage,
37
48
  setLocalStorage,
38
49
  scopePollingDetectionStrategy,
39
50
  isRedirectable,
51
+ generalizedErrorMessage,
40
52
  } from "./utils";
41
53
  import { getNameByAddress } from "./ans";
42
- import { AccountAuthenticator } from "@aptos-labs/ts-sdk";
43
- import { convertNetwork, convertToBCSPayload } from "./conversion";
54
+ import {
55
+ convertNetwork,
56
+ convertV2TransactionPayloadToV1BCSPayload,
57
+ convertV2PayloadToV1JSONPayload,
58
+ } from "./conversion";
59
+ import { WalletCoreV1 } from "./WalletCoreV1";
44
60
 
45
61
  export class WalletCore extends EventEmitter<WalletCoreEvents> {
46
62
  private _wallets: ReadonlyArray<Wallet> = [];
47
63
  private _wallet: Wallet | null = null;
48
64
  private _account: AccountInfo | null = null;
49
65
  private _network: NetworkInfo | null = null;
66
+ private readonly waletCoreV1: WalletCoreV1 = new WalletCoreV1();
50
67
 
51
68
  private _connecting: boolean = false;
52
69
  private _connected: boolean = false;
@@ -180,7 +197,7 @@ export class WalletCore extends EventEmitter<WalletCoreEvents> {
180
197
  * If all good, we connect the wallet by calling `this.connectWallet`
181
198
  * @param walletName. The wallet name we want to connect.
182
199
  */
183
- async connect(walletName: WalletName): Promise<void | string> {
200
+ async connect(walletName: string): Promise<void | string> {
184
201
  const selectedWallet = this._wallets?.find(
185
202
  (wallet: Wallet) => wallet.name === walletName
186
203
  );
@@ -239,8 +256,8 @@ export class WalletCore extends EventEmitter<WalletCoreEvents> {
239
256
  this.emit("connect", account);
240
257
  } catch (error: any) {
241
258
  this.clearData();
242
- const errMsg =
243
- typeof error == "object" && "message" in error ? error.message : error;
259
+
260
+ const errMsg = generalizedErrorMessage(error);
244
261
  throw new WalletConnectionError(errMsg).message;
245
262
  } finally {
246
263
  this._connecting = false;
@@ -260,95 +277,164 @@ export class WalletCore extends EventEmitter<WalletCoreEvents> {
260
277
  this.clearData();
261
278
  this.emit("disconnect");
262
279
  } catch (error: any) {
263
- const errMsg =
264
- typeof error == "object" && "message" in error ? error.message : error;
280
+ const errMsg = generalizedErrorMessage(error);
265
281
  throw new WalletDisconnectionError(errMsg).message;
266
282
  }
267
283
  }
268
284
 
269
285
  /**
270
- Sign and submit an entry (not bcs serialized) transaction type to chain.
271
- @param transaction a non-bcs serialized transaction
272
- @param options max_gas_amount and gas_unit_limit
273
- @return response from the wallet's signAndSubmitTransaction function
274
- @throws WalletSignAndSubmitMessageError
275
- */
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
+ */
276
292
  async signAndSubmitTransaction(
277
- transaction: Types.TransactionPayload,
278
- options?: TransactionOptions
279
- ): Promise<any> {
293
+ transactionInput: InputGenerateTransactionData,
294
+ options?: InputGenerateTransactionOptions
295
+ ): Promise<
296
+ { hash: Types.HexEncodedBytes; output?: any } | PendingTransactionResponse
297
+ > {
280
298
  try {
281
299
  this.doesWalletExist();
282
- const response = await this._wallet?.signAndSubmitTransaction(
283
- transaction,
284
- options
285
- );
286
- return response;
287
- } catch (error: any) {
288
- const errMsg =
289
- typeof error == "object" && "message" in error ? error.message : error;
290
- throw new WalletSignAndSubmitMessageError(errMsg).message;
291
- }
292
- }
293
300
 
294
- /**
295
- Sign and submit a bsc serialized transaction type to chain.
296
- @param transaction a bcs serialized transaction
297
- @param options max_gas_amount and gas_unit_limit
298
- @return response from the wallet's signAndSubmitBCSTransaction function
299
- @throws WalletSignAndSubmitMessageError
300
- */
301
- async signAndSubmitBCSTransaction(
302
- transaction: TxnBuilderTypes.TransactionPayload,
303
- options?: TransactionOptions
304
- ): Promise<any> {
305
- if (this._wallet && !("signAndSubmitBCSTransaction" in this._wallet)) {
306
- throw new WalletNotSupportedMethod(
307
- `Submit a BCS Transaction is not supported by ${this.wallet?.name}`
308
- ).message;
309
- }
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
310
 
311
- try {
312
- this.doesWalletExist();
313
- const response = await (this._wallet as any).signAndSubmitBCSTransaction(
314
- transaction,
315
- options
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
+ }
316
357
  );
317
- return response;
358
+ const { hash, ...output } = response;
359
+ return { hash, output };
318
360
  } catch (error: any) {
319
- const errMsg =
320
- typeof error == "object" && "message" in error ? error.message : error;
361
+ const errMsg = generalizedErrorMessage(error);
321
362
  throw new WalletSignAndSubmitMessageError(errMsg).message;
322
363
  }
323
364
  }
324
365
 
325
366
  /**
326
- Sign transaction (doesnt submit to chain).
327
- @param transaction
328
- @param options max_gas_amount and gas_unit_limit
329
- @return response from the wallet's signTransaction function
330
- @throws WalletSignTransactionError
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
331
375
  */
332
376
  async signTransaction(
333
- transaction: Types.TransactionPayload,
334
- options?: TransactionOptions
335
- ): Promise<Uint8Array | null> {
336
- if (this._wallet && !("signTransaction" in this._wallet)) {
337
- throw new WalletNotSupportedMethod(
338
- `Sign Transaction is not supported by ${this.wallet?.name}`
339
- ).message;
340
- }
341
-
377
+ transactionOrPayload: AnyRawTransaction | Types.TransactionPayload,
378
+ asFeePayer?: boolean,
379
+ options?: InputGenerateTransactionOptions
380
+ ): Promise<AccountAuthenticator> {
342
381
  try {
343
382
  this.doesWalletExist();
344
- const response = await (this._wallet as any).signTransaction(
345
- transaction,
346
- 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
+ }
347
416
  );
348
- 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;
349
436
  } catch (error: any) {
350
- const errMsg =
351
- typeof error == "object" && "message" in error ? error.message : error;
437
+ const errMsg = generalizedErrorMessage(error);
352
438
  throw new WalletSignTransactionError(errMsg).message;
353
439
  }
354
440
  }
@@ -359,61 +445,34 @@ export class WalletCore extends EventEmitter<WalletCoreEvents> {
359
445
  @return response from the wallet's signMessage function
360
446
  @throws WalletSignMessageError
361
447
  */
362
- async signMessage(
363
- message: SignMessagePayload
364
- ): Promise<SignMessageResponse | null> {
448
+ async signMessage(message: SignMessagePayload): Promise<SignMessageResponse> {
365
449
  try {
366
450
  this.doesWalletExist();
367
- if (!this._wallet) return null;
368
- const response = await this._wallet?.signMessage(message);
451
+ const response = await this._wallet!.signMessage(message);
369
452
  return response;
370
453
  } catch (error: any) {
371
- const errMsg =
372
- typeof error == "object" && "message" in error ? error.message : error;
454
+ const errMsg = generalizedErrorMessage(error);
373
455
  throw new WalletSignMessageError(errMsg).message;
374
456
  }
375
457
  }
376
458
 
377
- /**
378
- * This function is for signing and submitting a transaction using the `@aptos-labs/ts-sdk` (aka the v2 SDK)
379
- * input types. It's internally converting the input types to the old SDK input types and then calling
380
- * the v1 SDK's `signAndSubmitBCSTransaction` with it.
381
- *
382
- * @param transactionInput the transaction input
383
- * @param options max_gas_amount and gas_unit_limit
384
- * @returns the response from the wallet's signAndSubmitBCSTransaction function
385
- */
386
459
  async submitTransaction(
387
- transactionInput: InputGenerateTransactionData,
388
- options?: TransactionOptions,
389
- ): Promise<{ hash: string, output?: any }> {
390
- const payloadData = transactionInput.data;
391
- const aptosConfig = new AptosConfig({network: convertNetwork(this._network)});
392
- // TODO: Refactor this any, and remove the need for it by fixing the if ("bytecode" in data) stuff in `generateTransaction` in the v2 SDK
393
- const newPayload = await generateTransactionPayload({ ...payloadData as any, aptosConfig: aptosConfig });
394
- const oldTransactionPayload = convertToBCSPayload(newPayload);
395
- const response = await this.signAndSubmitBCSTransaction(oldTransactionPayload, options);
396
- const { hash, ...output } = response;
397
- return { hash, output };
398
- }
399
-
400
- async signMultiAgentTransaction(
401
- transaction: TxnBuilderTypes.MultiAgentRawTransaction | TxnBuilderTypes.FeePayerRawTransaction
402
- ): Promise<string | null> {
403
- if (this._wallet && !("signMultiAgentTransaction" in this._wallet)) {
460
+ transaction: InputSubmitTransactionData
461
+ ): Promise<PendingTransactionResponse> {
462
+ if (this._wallet && !("submitTransaction" in this._wallet)) {
404
463
  throw new WalletNotSupportedMethod(
405
- `Multi-agent & sponsored transactions are not supported by ${this.wallet?.name}`
464
+ `Submit Transaction is not supported by ${this.wallet?.name}`
406
465
  ).message;
407
466
  }
408
467
  try {
409
468
  this.doesWalletExist();
410
- const response = await (this._wallet as any).signMultiAgentTransaction(
469
+ const pendingTransaction = (this._wallet as any).submitTransaction(
411
470
  transaction
412
471
  );
413
- return response;
472
+
473
+ return pendingTransaction;
414
474
  } catch (error: any) {
415
- const errMsg =
416
- typeof error == "object" && "message" in error ? error.message : error;
475
+ const errMsg = generalizedErrorMessage(error);
417
476
  throw new WalletSignTransactionError(errMsg).message;
418
477
  }
419
478
  }
@@ -432,8 +491,7 @@ export class WalletCore extends EventEmitter<WalletCoreEvents> {
432
491
  this.emit("accountChange", this._account);
433
492
  });
434
493
  } catch (error: any) {
435
- const errMsg =
436
- typeof error == "object" && "message" in error ? error.message : error;
494
+ const errMsg = generalizedErrorMessage(error);
437
495
  throw new WalletAccountChangeError(errMsg).message;
438
496
  }
439
497
  }
@@ -452,12 +510,16 @@ export class WalletCore extends EventEmitter<WalletCoreEvents> {
452
510
  this.emit("networkChange", this._network);
453
511
  });
454
512
  } catch (error: any) {
455
- const errMsg =
456
- typeof error == "object" && "message" in error ? error.message : error;
513
+ const errMsg = generalizedErrorMessage(error);
457
514
  throw new WalletNetworkChangeError(errMsg).message;
458
515
  }
459
516
  }
460
517
 
518
+ /**
519
+ * Signs a message and verifies the signer
520
+ * @param message SignMessagePayload
521
+ * @returns boolean
522
+ */
461
523
  async signMessageAndVerify(message: SignMessagePayload): Promise<boolean> {
462
524
  try {
463
525
  this.doesWalletExist();
@@ -522,8 +584,7 @@ export class WalletCore extends EventEmitter<WalletCoreEvents> {
522
584
  }
523
585
  return verified;
524
586
  } catch (error: any) {
525
- const errMsg =
526
- typeof error == "object" && "message" in error ? error.message : error;
587
+ const errMsg = generalizedErrorMessage(error);
527
588
  throw new WalletSignMessageAndVerifyError(errMsg).message;
528
589
  }
529
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
+ }
package/src/conversion.ts CHANGED
@@ -1,24 +1,57 @@
1
- import { Network, AnyTransactionPayloadInstance } from "@aptos-labs/ts-sdk"
2
- import { BCS, TxnBuilderTypes } from "aptos"
1
+ import {
2
+ Network,
3
+ TransactionPayload,
4
+ InputGenerateTransactionPayloadData,
5
+ TypeTag,
6
+ } from "@aptos-labs/ts-sdk";
7
+ import { BCS, TxnBuilderTypes, Types } from "aptos";
3
8
  import { NetworkInfo } from "./types";
4
- import { NetworkName } from "./constants";
5
9
 
6
10
  // old => new
7
11
  export function convertNetwork(networkInfo: NetworkInfo | null): Network {
8
- switch(networkInfo?.name.toLowerCase()) {
9
- case "mainnet" as NetworkName:
10
- return Network.MAINNET;
11
- case "testnet" as NetworkName:
12
- return Network.TESTNET;
13
- case "devnet" as NetworkName:
14
- return Network.DEVNET;
15
- default:
16
- throw new Error("Invalid network name")
17
- }
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
+ }
18
22
  }
19
23
 
20
24
  // new => old
21
- export function convertToBCSPayload(payload: AnyTransactionPayloadInstance): TxnBuilderTypes.TransactionPayload {
22
- const deserializer = new BCS.Deserializer(payload.bcsToBytes());
23
- return TxnBuilderTypes.TransactionPayload.deserialize(deserializer);
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
+ }
24
57
  }